add audio channel option for ptt (Windows only)

This commit is contained in:
Andrew 2017-01-12 17:12:53 -08:00
parent 72cd5dbc26
commit 3b59838237
8 changed files with 348 additions and 6 deletions

View File

@ -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
View File

@ -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. */

20
audio_ptt.c Normal file
View File

@ -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/>.
//

11
audio_ptt.h Normal file
View File

@ -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

193
audio_ptt_win.c Normal file
View File

@ -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

View File

@ -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 {

View File

@ -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
View File

@ -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 */
/*-------------------------------------------------------------------