Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3b59838

Browse files
committedJan 13, 2017
add audio channel option for ptt (Windows only)
1 parent 72cd5db commit 3b59838

File tree

8 files changed

+348
-6
lines changed

8 files changed

+348
-6
lines changed
 

‎Makefile.win

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
7070
hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
7171
fcs_calc.o ax25_pad.o \
7272
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
73-
gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
73+
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 \
7474
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
7575
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
7676
dwgps.o dwgpsnmea.o dtime_now.o \

‎audio.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,16 @@ struct audio_s {
196196
int ptt_invert; /* Invert the output. */
197197
int ptt_invert2; /* Invert the secondary output. */
198198

199+
int ptt_channel; /* Channel number for audio PTT. */
200+
int ptt_frequency; /* Audio frequency for audio PTT. */
201+
#if __WIN32__
202+
HANDLE ptt_start; /* Handle for event that starts ptt tone. */
203+
HANDLE ptt_stop; /* Handle for event that stops ptt tone. */
204+
HANDLE ptt_close; /* Handle for event that closes ptt. */
205+
#else
206+
207+
#endif
208+
199209
#ifdef USE_HAMLIB
200210

201211
int ptt_model; /* HAMLIB model. -1 for AUTO. 2 for rigctld. Others are radio model. */

‎audio_ptt.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// This file is part of Dire Wolf, an amateur radio packet TNC.
3+
//
4+
// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ
5+
//
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 2 of the License, or
9+
// (at your option) any later version.
10+
//
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
//
19+
20+

‎audio_ptt.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
#ifndef AUDIO_PTT_H
3+
#define AUDIO_PTT_H 1
4+
5+
#if __WIN32__
6+
extern HANDLE start_ptt_thread ( struct audio_s *pa, int ch );
7+
#else
8+
extern int start_ptt_thread ( struct audio_s *pa, int ch );
9+
#endif
10+
11+
#endif

‎audio_ptt_win.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
2+
//
3+
// This file is part of Dire Wolf, an amateur radio packet TNC.
4+
//
5+
// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ
6+
//
7+
// This program is free software: you can redistribute it and/or modify
8+
// it under the terms of the GNU General Public License as published by
9+
// the Free Software Foundation, either version 2 of the License, or
10+
// (at your option) any later version.
11+
//
12+
// This program is distributed in the hope that it will be useful,
13+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
// GNU General Public License for more details.
16+
//
17+
// You should have received a copy of the GNU General Public License
18+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
//
20+
21+
22+
/*------------------------------------------------------------------
23+
*
24+
* Module: audio_ptt_win.c
25+
*
26+
* Purpose: Interface to audio device commonly called a "sound card" for
27+
* historical reasons.
28+
*
29+
* This version uses the native Windows sound interface.
30+
*
31+
*---------------------------------------------------------------*/
32+
33+
#if __WIN32__
34+
#include <stdio.h>
35+
#include <unistd.h>
36+
#include <sys/types.h>
37+
#include <stdlib.h>
38+
#include <assert.h>
39+
#include <ctype.h>
40+
#include <io.h>
41+
#include <fcntl.h>
42+
#include <math.h>
43+
44+
#include <windows.h>
45+
#include <mmsystem.h>
46+
47+
#ifndef WAVE_FORMAT_96M16
48+
#define WAVE_FORMAT_96M16 0x40000
49+
#define WAVE_FORMAT_96S16 0x80000
50+
#endif
51+
52+
#include "direwolf.h"
53+
#include "audio.h"
54+
#include "audio_stats.h"
55+
#include "textcolor.h"
56+
#include "ptt.h"
57+
#include "demod.h" /* for alevel_t & demod_get_audio_level() */
58+
#include "audio_ptt.h"
59+
60+
static struct audio_s *save_audio_config_p;
61+
62+
static unsigned __stdcall ptt_thread ( void *arg );
63+
64+
HANDLE start_ptt_thread (struct audio_s *pa , int ch)
65+
{
66+
save_audio_config_p = pa;
67+
68+
return (HANDLE)_beginthreadex (NULL, 0, ptt_thread, (void*)(long)ch, 0, NULL);
69+
}
70+
71+
unsigned __stdcall ptt_thread (void *arg)
72+
{
73+
WAVEFORMATEX wf;
74+
HWAVEOUT hWaveOut;
75+
int ch = (int)(long)arg; // channel number.
76+
int channel = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel;
77+
int freq = save_audio_config_p->achan[channel].octrl[OCTYPE_PTT].ptt_frequency;
78+
int a = ACHAN2ADEV( channel );
79+
int err;
80+
81+
if( save_audio_config_p->adev[a].defined ) {
82+
wf.wFormatTag = WAVE_FORMAT_PCM;
83+
wf.nChannels = save_audio_config_p->adev[a].num_channels;
84+
wf.nSamplesPerSec = save_audio_config_p->adev[a].samples_per_sec;
85+
wf.wBitsPerSample = save_audio_config_p->adev[a].bits_per_sample;
86+
wf.nBlockAlign = ( wf.wBitsPerSample / 8 ) * wf.nChannels;
87+
wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
88+
wf.cbSize = 0;
89+
90+
/*
91+
* Open the audio output device.
92+
* Soundcard is only possibility at this time.
93+
*/
94+
95+
err = waveOutOpen ( &hWaveOut, atoi( save_audio_config_p->adev[a].adevice_out ), &wf, (DWORD_PTR)NULL, 0, CALLBACK_NULL );
96+
if( err == MMSYSERR_NOERROR ) {
97+
WAVEHDR waveHeader;
98+
SHORT* pnData;
99+
SHORT sample;
100+
int nsamples = save_audio_config_p->adev[a].samples_per_sec / freq;
101+
int i;
102+
103+
if( save_audio_config_p->adev[a].num_channels == 1 ) {
104+
waveHeader.dwBufferLength = 1 * nsamples * sizeof( SHORT );
105+
}
106+
else {
107+
waveHeader.dwBufferLength = 2 * nsamples * sizeof( SHORT );
108+
}
109+
waveHeader.lpData = malloc( waveHeader.dwBufferLength );
110+
waveHeader.dwUser = 0;
111+
waveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
112+
waveHeader.dwLoops = 0xFFFF;
113+
114+
pnData = (SHORT*)waveHeader.lpData;
115+
116+
if( save_audio_config_p->adev[a].num_channels == 1 ) {
117+
for( i = 0; i < nsamples; i++ ) {
118+
sample = (SHORT)( 32000.0 * sin( ( (double)i / (double)nsamples ) * 2.0 * M_PI ) );
119+
pnData[i] = sample;
120+
}
121+
}
122+
else {
123+
for( i = 0; i < nsamples; i++ ) {
124+
sample = (SHORT)( 32000.0 * sin( ( (double)i / (double)nsamples ) * 2.0 * M_PI ) );
125+
if( channel == ADEVFIRSTCHAN( a ) ) {
126+
127+
// Stereo, left channel.
128+
129+
pnData[i*2 + 0] = sample;
130+
pnData[i*2 + 1] = 0;
131+
}
132+
else {
133+
134+
// Stereo, right channel.
135+
136+
pnData[i*2 + 0] = 0;
137+
pnData[i*2 + 1] = sample;
138+
}
139+
}
140+
}
141+
142+
err = waveOutPrepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
143+
if( err == MMSYSERR_NOERROR ) {
144+
HANDLE handles[3];
145+
DWORD dwWait;
146+
147+
handles[0] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_start;
148+
handles[1] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_stop;
149+
handles[2] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_close;
150+
151+
while( 1 )
152+
{
153+
dwWait = WaitForMultipleObjects ( 3, handles, FALSE, INFINITE );
154+
155+
if( dwWait == WAIT_OBJECT_0 + 0 )
156+
{
157+
//
158+
// ptt_set on
159+
//
160+
161+
waveOutWrite ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
162+
}
163+
else if( dwWait == WAIT_OBJECT_0 + 1 )
164+
{
165+
//
166+
// ptt_set off
167+
//
168+
169+
waveOutReset ( hWaveOut );
170+
}
171+
else if( dwWait == WAIT_OBJECT_0 + 2 )
172+
{
173+
//
174+
// close
175+
//
176+
177+
waveOutReset ( hWaveOut );
178+
waveOutUnprepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) );
179+
180+
break;
181+
}
182+
}
183+
}
184+
185+
waveOutClose ( hWaveOut );
186+
187+
free( waveHeader.lpData );
188+
}
189+
}
190+
191+
return 0;
192+
}
193+
#endif

‎config.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
666666
p_audio_config->achan[channel].octrl[ot].ptt_lpt_bit = 0;
667667
p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
668668
p_audio_config->achan[channel].octrl[ot].ptt_invert2 = 0;
669-
}
669+
p_audio_config->achan[channel].octrl[ot].ptt_channel = 0;
670+
p_audio_config->achan[channel].octrl[ot].ptt_frequency = PTT_FREQ_DEFAULT;
671+
}
670672

671673
p_audio_config->achan[channel].dwait = DEFAULT_DWAIT;
672674
p_audio_config->achan[channel].slottime = DEFAULT_SLOTTIME;
@@ -1582,8 +1584,52 @@ void config_init (char *fname, struct audio_s *p_audio_config,
15821584
dw_printf ("Config file line %d: %s with RIG is only available when hamlib support is enabled.\n", line, otname);
15831585
#endif
15841586
}
1585-
else if (strcasecmp( t, "CHN") == 0) {
1587+
else if (strcasecmp( t, "CHANNEL") == 0) {
1588+
t = split(NULL, 0);
1589+
if (t == NULL) {
1590+
text_color_set( DW_COLOR_ERROR );
1591+
dw_printf ("Config file line %d: Missing channel number for %s.\n", line, otname);
1592+
continue;
1593+
}
1594+
1595+
int channel_ptt = atoi(t);
1596+
1597+
if (channel_ptt < 0 || channel_ptt >= MAX_CHANS) {
1598+
text_color_set( DW_COLOR_ERROR );
1599+
dw_printf ( "Config file line %d: Invalid PTT channel number for %s.\n", line, otname );
1600+
continue;
1601+
}
1602+
1603+
if (channel == channel_ptt) {
1604+
text_color_set( DW_COLOR_ERROR );
1605+
dw_printf ( "Config file line %d: PTT channel number must not be the same as the channel number itself.\n", line );
1606+
continue;
1607+
}
1608+
1609+
int freq_ptt = PTT_FREQ_DEFAULT;
1610+
1611+
t = split(NULL, 0);
1612+
if (t != NULL) {
1613+
freq_ptt = atoi(t);
1614+
1615+
if (freq_ptt < PTT_FREQ_MIN || freq_ptt > PTT_FREQ_MAX) {
1616+
text_color_set( DW_COLOR_ERROR );
1617+
dw_printf ("Config file line %d: Invalid value %d for PTT frequency. Using default of %d.\n",
1618+
line, freq_ptt, PTT_FREQ_DEFAULT );
1619+
1620+
freq_ptt = PTT_FREQ_DEFAULT;
1621+
}
1622+
}
1623+
15861624
p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_AUDIO;
1625+
p_audio_config->achan[channel].octrl[ot].ptt_channel = channel_ptt;
1626+
p_audio_config->achan[channel].octrl[ot].ptt_frequency = freq_ptt;
1627+
#ifdef __WIN32__
1628+
p_audio_config->achan[channel].octrl[ot].ptt_start = CreateEvent (NULL, FALSE, FALSE, NULL);
1629+
p_audio_config->achan[channel].octrl[ot].ptt_stop = CreateEvent (NULL, FALSE, FALSE, NULL);
1630+
p_audio_config->achan[channel].octrl[ot].ptt_close = CreateEvent (NULL, FALSE, FALSE, NULL);
1631+
#else
1632+
#endif
15871633
}
15881634
else {
15891635

‎direwolf.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@
3838
#define MAX_RIGS MAX_CHANS
3939
#endif
4040

41+
/*
42+
* PTT frequency settings
43+
*/
44+
45+
#define PTT_FREQ_MIN 50
46+
#define PTT_FREQ_MAX 20000
47+
#define PTT_FREQ_DEFAULT 1000
48+
4149
/*
4250
* Get audio device number for given channel.
4351
* and first channel for given device.

‎ptt.c

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ typedef int HANDLE;
126126
#include "textcolor.h"
127127
#include "audio.h"
128128
#include "ptt.h"
129+
#include "audio_ptt.h"
129130

130131

131132
#if __WIN32__
@@ -357,6 +358,13 @@ void ptt_init (struct audio_s *audio_config_p)
357358
{
358359
int ch;
359360
HANDLE fd = INVALID_HANDLE_VALUE;
361+
362+
#if __WIN32__
363+
HANDLE audio_ptt_th[MAX_CHANS];
364+
#else
365+
pthread_t audio_ptt_tid[MAX_CHANS];
366+
#endif
367+
360368
#if __WIN32__
361369
#else
362370
int using_gpio;
@@ -386,15 +394,17 @@ void ptt_init (struct audio_s *audio_config_p)
386394
if (ptt_debug_level >= 2) {
387395

388396
text_color_set(DW_COLOR_DEBUG);
389-
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
397+
dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d, channel=%d, freq=%d\n",
390398
ch,
391399
otnames[ot],
392400
audio_config_p->achan[ch].octrl[ot].ptt_method,
393401
audio_config_p->achan[ch].octrl[ot].ptt_device,
394402
audio_config_p->achan[ch].octrl[ot].ptt_line,
395403
audio_config_p->achan[ch].octrl[ot].ptt_gpio,
396404
audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
397-
audio_config_p->achan[ch].octrl[ot].ptt_invert);
405+
audio_config_p->achan[ch].octrl[ot].ptt_invert,
406+
audio_config_p->achan[ch].octrl[ot].ptt_channel,
407+
audio_config_p->achan[ch].octrl[ot].ptt_frequency );
398408
}
399409
}
400410
}
@@ -501,6 +511,7 @@ void ptt_init (struct audio_s *audio_config_p)
501511
ptt_set (ot, ch, 0);
502512

503513
} /* if serial method. */
514+
504515
} /* for each output type. */
505516
} /* if channel valid. */
506517
} /* For each channel. */
@@ -747,6 +758,35 @@ void ptt_init (struct audio_s *audio_config_p)
747758

748759
#endif
749760

761+
/*
762+
* Set up audio channel.
763+
*/
764+
765+
for (ch = 0; ch<MAX_CHANS; ch++) {
766+
if (audio_config_p->achan[ch].valid) {
767+
if (audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_AUDIO) {
768+
#if __WIN32__
769+
audio_ptt_th[ch] = start_ptt_thread (audio_config_p, ch);
770+
if (audio_ptt_th[ch] == NULL) {
771+
text_color_set(DW_COLOR_ERROR);
772+
dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n",
773+
audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch);
774+
return;
775+
}
776+
#else
777+
int e;
778+
779+
e = pthread_create (&(ptt_tid[j]), NULL, ptt_thread, (void *)(long)ch);
780+
if (e != 0) {
781+
text_color_set(DW_COLOR_ERROR);
782+
dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n",
783+
audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch );
784+
return;
785+
}
786+
#endif
787+
}
788+
}
789+
}
750790

751791
/* Why doesn't it transmit? Probably forgot to specify PTT option. */
752792

@@ -968,7 +1008,21 @@ void ptt_set (int ot, int chan, int ptt_signal)
9681008
}
9691009
#endif
9701010

971-
1011+
if( save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_AUDIO ) {
1012+
if( ptt_signal ) {
1013+
#ifdef __WIN32__
1014+
SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_start );
1015+
#else
1016+
#endif
1017+
}
1018+
else
1019+
{
1020+
#ifdef __WIN32__
1021+
SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_stop );
1022+
#else
1023+
#endif
1024+
}
1025+
}
9721026
} /* end ptt_set */
9731027

9741028
/*-------------------------------------------------------------------

0 commit comments

Comments
 (0)
Please sign in to comment.