mirror of https://github.com/wb2osz/direwolf.git
add audio channel option for ptt (Windows only)
This commit is contained in:
parent
72cd5dbc26
commit
3b59838237
|
@ -70,7 +70,7 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
|
|||
hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
|
||||
fcs_calc.o ax25_pad.o \
|
||||
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||
gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
|
||||
gen_tone.o morse.o audio_win.o audio_ptt_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
|
||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
|
||||
dwgps.o dwgpsnmea.o dtime_now.o \
|
||||
|
|
10
audio.h
10
audio.h
|
@ -196,6 +196,16 @@ struct audio_s {
|
|||
int ptt_invert; /* Invert the output. */
|
||||
int ptt_invert2; /* Invert the secondary output. */
|
||||
|
||||
int ptt_channel; /* Channel number for audio PTT. */
|
||||
int ptt_frequency; /* Audio frequency for audio PTT. */
|
||||
#if __WIN32__
|
||||
HANDLE ptt_start; /* Handle for event that starts ptt tone. */
|
||||
HANDLE ptt_stop; /* Handle for event that stops ptt tone. */
|
||||
HANDLE ptt_close; /* Handle for event that closes ptt. */
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_HAMLIB
|
||||
|
||||
int ptt_model; /* HAMLIB model. -1 for AUTO. 2 for rigctld. Others are radio model. */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#ifndef AUDIO_PTT_H
|
||||
#define AUDIO_PTT_H 1
|
||||
|
||||
#if __WIN32__
|
||||
extern HANDLE start_ptt_thread ( struct audio_s *pa, int ch );
|
||||
#else
|
||||
extern int start_ptt_thread ( struct audio_s *pa, int ch );
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,193 @@
|
|||
|
||||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Module: audio_ptt_win.c
|
||||
*
|
||||
* Purpose: Interface to audio device commonly called a "sound card" for
|
||||
* historical reasons.
|
||||
*
|
||||
* This version uses the native Windows sound interface.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
#if __WIN32__
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifndef WAVE_FORMAT_96M16
|
||||
#define WAVE_FORMAT_96M16 0x40000
|
||||
#define WAVE_FORMAT_96S16 0x80000
|
||||
#endif
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "audio.h"
|
||||
#include "audio_stats.h"
|
||||
#include "textcolor.h"
|
||||
#include "ptt.h"
|
||||
#include "demod.h" /* for alevel_t & demod_get_audio_level() */
|
||||
#include "audio_ptt.h"
|
||||
|
||||
static struct audio_s *save_audio_config_p;
|
||||
|
||||
static unsigned __stdcall ptt_thread ( void *arg );
|
||||
|
||||
HANDLE start_ptt_thread (struct audio_s *pa , int ch)
|
||||
{
|
||||
save_audio_config_p = pa;
|
||||
|
||||
return (HANDLE)_beginthreadex (NULL, 0, ptt_thread, (void*)(long)ch, 0, NULL);
|
||||
}
|
||||
|
||||
unsigned __stdcall ptt_thread (void *arg)
|
||||
{
|
||||
WAVEFORMATEX wf;
|
||||
HWAVEOUT hWaveOut;
|
||||
int ch = (int)(long)arg; // channel number.
|
||||
int channel = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel;
|
||||
int freq = save_audio_config_p->achan[channel].octrl[OCTYPE_PTT].ptt_frequency;
|
||||
int a = ACHAN2ADEV( channel );
|
||||
int err;
|
||||
|
||||
if( save_audio_config_p->adev[a].defined ) {
|
||||
wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wf.nChannels = save_audio_config_p->adev[a].num_channels;
|
||||
wf.nSamplesPerSec = save_audio_config_p->adev[a].samples_per_sec;
|
||||
wf.wBitsPerSample = save_audio_config_p->adev[a].bits_per_sample;
|
||||
wf.nBlockAlign = ( wf.wBitsPerSample / 8 ) * wf.nChannels;
|
||||
wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
|
||||
wf.cbSize = 0;
|
||||
|
||||
/*
|
||||
* Open the audio output device.
|
||||
* Soundcard is only possibility at this time.
|
||||
*/
|
||||
|
||||
err = waveOutOpen ( &hWaveOut, atoi( save_audio_config_p->adev[a].adevice_out ), &wf, (DWORD_PTR)NULL, 0, CALLBACK_NULL );
|
||||
if( err == MMSYSERR_NOERROR ) {
|
||||
WAVEHDR waveHeader;
|
||||
SHORT* pnData;
|
||||
SHORT sample;
|
||||
int nsamples = save_audio_config_p->adev[a].samples_per_sec / freq;
|
||||
int i;
|
||||
|
||||
if( save_audio_config_p->adev[a].num_channels == 1 ) {
|
||||
waveHeader.dwBufferLength = 1 * nsamples * sizeof( SHORT );
|
||||
}
|
||||
else {
|
||||
waveHeader.dwBufferLength = 2 * nsamples * sizeof( SHORT );
|
||||
}
|
||||
waveHeader.lpData = malloc( waveHeader.dwBufferLength );
|
||||
waveHeader.dwUser = 0;
|
||||
waveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
|
||||
waveHeader.dwLoops = 0xFFFF;
|
||||
|
||||
pnData = (SHORT*)waveHeader.lpData;
|
||||
|
||||
if( save_audio_config_p->adev[a].num_channels == 1 ) {
|
||||
for( i = 0; i < nsamples; i++ ) {
|
||||
sample = (SHORT)( 32000.0 * sin( ( (double)i / (double)nsamples ) * 2.0 * M_PI ) );
|
||||
pnData[i] = sample;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for( i = 0; i < nsamples; i++ ) {
|
||||
sample = (SHORT)( 32000.0 * sin( ( (double)i / (double)nsamples ) * 2.0 * M_PI ) );
|
||||
if( channel == ADEVFIRSTCHAN( a ) ) {
|
||||
|
||||
// Stereo, left channel.
|
||||
|
||||
pnData[i*2 + 0] = sample;
|
||||
pnData[i*2 + 1] = 0;
|
||||
}
|
||||
else {
|
||||
|
||||
// Stereo, right channel.
|
||||
|
||||
pnData[i*2 + 0] = 0;
|
||||
pnData[i*2 + 1] = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = waveOutPrepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
|
||||
if( err == MMSYSERR_NOERROR ) {
|
||||
HANDLE handles[3];
|
||||
DWORD dwWait;
|
||||
|
||||
handles[0] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_start;
|
||||
handles[1] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_stop;
|
||||
handles[2] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_close;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
dwWait = WaitForMultipleObjects ( 3, handles, FALSE, INFINITE );
|
||||
|
||||
if( dwWait == WAIT_OBJECT_0 + 0 )
|
||||
{
|
||||
//
|
||||
// ptt_set on
|
||||
//
|
||||
|
||||
waveOutWrite ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
|
||||
}
|
||||
else if( dwWait == WAIT_OBJECT_0 + 1 )
|
||||
{
|
||||
//
|
||||
// ptt_set off
|
||||
//
|
||||
|
||||
waveOutReset ( hWaveOut );
|
||||
}
|
||||
else if( dwWait == WAIT_OBJECT_0 + 2 )
|
||||
{
|
||||
//
|
||||
// close
|
||||
//
|
||||
|
||||
waveOutReset ( hWaveOut );
|
||||
waveOutUnprepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waveOutClose ( hWaveOut );
|
||||
|
||||
free( waveHeader.lpData );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
48
config.c
48
config.c
|
@ -666,6 +666,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
p_audio_config->achan[channel].octrl[ot].ptt_lpt_bit = 0;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_invert2 = 0;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_channel = 0;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_frequency = PTT_FREQ_DEFAULT;
|
||||
}
|
||||
|
||||
p_audio_config->achan[channel].dwait = DEFAULT_DWAIT;
|
||||
|
@ -1582,8 +1584,52 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
dw_printf ("Config file line %d: %s with RIG is only available when hamlib support is enabled.\n", line, otname);
|
||||
#endif
|
||||
}
|
||||
else if (strcasecmp( t, "CHN") == 0) {
|
||||
else if (strcasecmp( t, "CHANNEL") == 0) {
|
||||
t = split(NULL, 0);
|
||||
if (t == NULL) {
|
||||
text_color_set( DW_COLOR_ERROR );
|
||||
dw_printf ("Config file line %d: Missing channel number for %s.\n", line, otname);
|
||||
continue;
|
||||
}
|
||||
|
||||
int channel_ptt = atoi(t);
|
||||
|
||||
if (channel_ptt < 0 || channel_ptt >= MAX_CHANS) {
|
||||
text_color_set( DW_COLOR_ERROR );
|
||||
dw_printf ( "Config file line %d: Invalid PTT channel number for %s.\n", line, otname );
|
||||
continue;
|
||||
}
|
||||
|
||||
if (channel == channel_ptt) {
|
||||
text_color_set( DW_COLOR_ERROR );
|
||||
dw_printf ( "Config file line %d: PTT channel number must not be the same as the channel number itself.\n", line );
|
||||
continue;
|
||||
}
|
||||
|
||||
int freq_ptt = PTT_FREQ_DEFAULT;
|
||||
|
||||
t = split(NULL, 0);
|
||||
if (t != NULL) {
|
||||
freq_ptt = atoi(t);
|
||||
|
||||
if (freq_ptt < PTT_FREQ_MIN || freq_ptt > PTT_FREQ_MAX) {
|
||||
text_color_set( DW_COLOR_ERROR );
|
||||
dw_printf ("Config file line %d: Invalid value %d for PTT frequency. Using default of %d.\n",
|
||||
line, freq_ptt, PTT_FREQ_DEFAULT );
|
||||
|
||||
freq_ptt = PTT_FREQ_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_AUDIO;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_channel = channel_ptt;
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_frequency = freq_ptt;
|
||||
#ifdef __WIN32__
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_start = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_stop = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
p_audio_config->achan[channel].octrl[ot].ptt_close = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
||||
|
|
|
@ -38,6 +38,14 @@
|
|||
#define MAX_RIGS MAX_CHANS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PTT frequency settings
|
||||
*/
|
||||
|
||||
#define PTT_FREQ_MIN 50
|
||||
#define PTT_FREQ_MAX 20000
|
||||
#define PTT_FREQ_DEFAULT 1000
|
||||
|
||||
/*
|
||||
* Get audio device number for given channel.
|
||||
* and first channel for given device.
|
||||
|
|
60
ptt.c
60
ptt.c
|
@ -126,6 +126,7 @@ typedef int HANDLE;
|
|||
#include "textcolor.h"
|
||||
#include "audio.h"
|
||||
#include "ptt.h"
|
||||
#include "audio_ptt.h"
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
@ -357,6 +358,13 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
{
|
||||
int ch;
|
||||
HANDLE fd = INVALID_HANDLE_VALUE;
|
||||
|
||||
#if __WIN32__
|
||||
HANDLE audio_ptt_th[MAX_CHANS];
|
||||
#else
|
||||
pthread_t audio_ptt_tid[MAX_CHANS];
|
||||
#endif
|
||||
|
||||
#if __WIN32__
|
||||
#else
|
||||
int using_gpio;
|
||||
|
@ -386,7 +394,7 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
if (ptt_debug_level >= 2) {
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
|
||||
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d, channel=%d, freq=%d\n",
|
||||
ch,
|
||||
otnames[ot],
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_method,
|
||||
|
@ -394,7 +402,9 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
audio_config_p->achan[ch].octrl[ot].ptt_line,
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_gpio,
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_invert);
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_invert,
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_channel,
|
||||
audio_config_p->achan[ch].octrl[ot].ptt_frequency );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -501,6 +511,7 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
ptt_set (ot, ch, 0);
|
||||
|
||||
} /* if serial method. */
|
||||
|
||||
} /* for each output type. */
|
||||
} /* if channel valid. */
|
||||
} /* For each channel. */
|
||||
|
@ -747,6 +758,35 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up audio channel.
|
||||
*/
|
||||
|
||||
for (ch = 0; ch<MAX_CHANS; ch++) {
|
||||
if (audio_config_p->achan[ch].valid) {
|
||||
if (audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_AUDIO) {
|
||||
#if __WIN32__
|
||||
audio_ptt_th[ch] = start_ptt_thread (audio_config_p, ch);
|
||||
if (audio_ptt_th[ch] == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n",
|
||||
audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int e;
|
||||
|
||||
e = pthread_create (&(ptt_tid[j]), NULL, ptt_thread, (void *)(long)ch);
|
||||
if (e != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n",
|
||||
audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Why doesn't it transmit? Probably forgot to specify PTT option. */
|
||||
|
||||
|
@ -968,7 +1008,21 @@ void ptt_set (int ot, int chan, int ptt_signal)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
if( save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_AUDIO ) {
|
||||
if( ptt_signal ) {
|
||||
#ifdef __WIN32__
|
||||
SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_start );
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_stop );
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} /* end ptt_set */
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue