Skip to content

Commit f95c4e3

Browse files
committed
New SCHANNEL feature, like NCHANNEL but for serial TNCs
The SCHANNEL feature is essentially the same as the existing NCHANNEL feature but allowing for the mapping of a serial TNC to a channel, as opposed to the network TNC supported by NCHANNEL. Configuration uses the following form in the direwolf.conf file: SCHANNEL <channel> <device> [<baudrate>] The implementation is a close parallel to that for NCHANNEL, sharing some of the code, and makes use of existing serial port handling that hides OS differences. This results in fewer changes than might have been expected otherwise.
1 parent 11c4bdf commit f95c4e3

File tree

15 files changed

+658
-161
lines changed

15 files changed

+658
-161
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ list(APPEND direwolf_SOURCES
8585
morse.c
8686
multi_modem.c
8787
waypoint.c
88+
tnc_common.c
8889
nettnc.c
90+
sertnc.c
8991
serial_port.c
9092
pfilter.c
9193
ptt.c

src/audio.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ typedef enum retry_e {
6060
enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use.
6161
MEDIUM_RADIO, // Internal modem for radio.
6262
MEDIUM_IGATE, // Access IGate as ordinary channel.
63-
MEDIUM_NETTNC }; // Remote network TNC. (new in 1.8)
63+
MEDIUM_NETTNC, // Remote network TNC. (new in 1.8)
64+
MEDIUM_SERTNC }; // Local serial TNC. (new in 1.8)
6465

6566

6667
typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;
@@ -152,6 +153,7 @@ struct audio_s {
152153
// MEDIUM_RADIO for internal modem. (only possibility earlier)
153154
// MEDIUM_IGATE allows application access to IGate.
154155
// MEDIUM_NETTNC for external TNC via TCP.
156+
// MEDIUM_SERTNC for external TNC via serial port.
155157

156158
int igate_vchannel; /* Virtual channel mapped to APRS-IS. */
157159
/* -1 for none. */
@@ -164,6 +166,12 @@ struct audio_s {
164166

165167
int nettnc_port[MAX_TOTAL_CHANS]; // Network TNC TCP port.
166168

169+
// Applies only to serial TNC type channels.
170+
171+
char sertnc_device[MAX_TOTAL_CHANS][80]; // Serial TNC device name.
172+
173+
int sertnc_baud[MAX_TOTAL_CHANS]; // Serial TNC baud rate.
174+
167175

168176

169177
/* Properties for each radio channel, common to receive and transmit. */

src/beacon.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
165165
if (chan >= MAX_TOTAL_CHANS) chan = 0; // For ICHANNEL, use channel 0 call.
166166

167167
if (g_modem_config_p->chan_medium[chan] == MEDIUM_RADIO ||
168-
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) {
168+
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC ||
169+
g_modem_config_p->chan_medium[chan] == MEDIUM_SERTNC) {
169170

170171
if (strlen(g_modem_config_p->mycall[chan]) > 0 &&
171172
strcasecmp(g_modem_config_p->mycall[chan], "N0CALL") != 0 &&

src/cdigipeater.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ void cdigipeater (int from_chan, packet_t pp)
134134

135135
if ( from_chan < 0 || from_chan >= MAX_RADIO_CHANS ||
136136
(save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO &&
137-
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC) ) {
137+
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC &&
138+
save_audio_config_p->chan_medium[from_chan] != MEDIUM_SERTNC) ) {
138139
text_color_set(DW_COLOR_ERROR);
139140
dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
140141
return;

src/config.c

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,70 @@ void config_init (char *fname, struct audio_s *p_audio_config,
13811381
p_audio_config->nettnc_port[nchan] = atoi(t);
13821382
}
13831383

1384+
/*
1385+
* SCHANNEL chan device baudrate - Define Serial TNC virtual channel.
1386+
*
1387+
* This allows a client application to talk to to an external TNC over serial KISS
1388+
* by using a channel number outside the normal range for modems.
1389+
* This does not change the current channel number used by MODEM, PTT, etc.
1390+
*
1391+
* chan = direwolf channel.
1392+
* device = device (serial port) name of serial TNC.
1393+
* baudrate = baud rate for communicating with serial TNC.
1394+
*
1395+
* Future: Might allow selection of channel on the serial TNC.
1396+
* For now, ignore incoming and set to 0 for outgoing.
1397+
*
1398+
* FIXME: Can't set mycall for schannel.
1399+
*/
1400+
1401+
else if (strcasecmp(t, "SCHANNEL") == 0) {
1402+
t = split(NULL,0);
1403+
if (t == NULL) {
1404+
text_color_set(DW_COLOR_ERROR);
1405+
dw_printf ("Line %d: Missing virtual channel number for SCHANNEL command.\n", line);
1406+
continue;
1407+
}
1408+
int nchan = atoi(t);
1409+
if (nchan >= MAX_RADIO_CHANS && nchan < MAX_TOTAL_CHANS) {
1410+
1411+
if (p_audio_config->chan_medium[nchan] == MEDIUM_NONE) {
1412+
1413+
p_audio_config->chan_medium[nchan] = MEDIUM_SERTNC;
1414+
}
1415+
else {
1416+
text_color_set(DW_COLOR_ERROR);
1417+
dw_printf ("Line %d: SCHANNEL can't use channel %d because it is already in use.\n", line, nchan);
1418+
}
1419+
}
1420+
else {
1421+
text_color_set(DW_COLOR_ERROR);
1422+
dw_printf ("Line %d: SCHANNEL number must in range of %d to %d.\n", line, MAX_RADIO_CHANS, MAX_TOTAL_CHANS-1);
1423+
}
1424+
1425+
t = split(NULL,0);
1426+
if (t == NULL) {
1427+
text_color_set(DW_COLOR_ERROR);
1428+
dw_printf ("Line %d: Missing serial TNC device for SCHANNEL command.\n", line);
1429+
continue;
1430+
}
1431+
strlcpy (p_audio_config->sertnc_device[nchan], t, sizeof(p_audio_config->sertnc_device[nchan]));
1432+
int n;
1433+
t = split(NULL,0);
1434+
if (t != NULL) {
1435+
n = atoi(t);
1436+
if (n != 1200 && n != 2400 && n != 4800 && n != 9600 && n != 19200 && n != 38400 && n != 57600 && n != 115200) {
1437+
text_color_set(DW_COLOR_ERROR);
1438+
dw_printf ("Line %d: Warning: Unsupported data rate of %d bits per second. Using 9600.\n", line, n);
1439+
n = 9600;
1440+
}
1441+
p_audio_config->sertnc_baud[nchan] = n;
1442+
}
1443+
else {
1444+
p_audio_config->sertnc_baud[nchan] = 9600;
1445+
}
1446+
}
1447+
13841448
/*
13851449
* MYCALL station
13861450
*/
@@ -2749,7 +2813,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
27492813
// Channels specified must be radio channels or network TNCs.
27502814

27512815
if (p_audio_config->chan_medium[from_chan] != MEDIUM_RADIO &&
2752-
p_audio_config->chan_medium[from_chan] != MEDIUM_NETTNC) {
2816+
p_audio_config->chan_medium[from_chan] != MEDIUM_NETTNC &&
2817+
p_audio_config->chan_medium[from_chan] != MEDIUM_SERTNC) {
27532818
text_color_set(DW_COLOR_ERROR);
27542819
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
27552820
line, from_chan);
@@ -2777,7 +2842,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
27772842
}
27782843

27792844
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO &&
2780-
p_audio_config->chan_medium[to_chan] != MEDIUM_NETTNC) {
2845+
p_audio_config->chan_medium[to_chan] != MEDIUM_NETTNC &&
2846+
p_audio_config->chan_medium[to_chan] != MEDIUM_SERTNC) {
27812847
text_color_set(DW_COLOR_ERROR);
27822848
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
27832849
line, to_chan);
@@ -3111,7 +3177,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
31113177
}
31123178

31133179
if (p_audio_config->chan_medium[from_chan] != MEDIUM_RADIO &&
3114-
p_audio_config->chan_medium[from_chan] != MEDIUM_NETTNC) {
3180+
p_audio_config->chan_medium[from_chan] != MEDIUM_NETTNC &&
3181+
p_audio_config->chan_medium[from_chan] != MEDIUM_SERTNC) {
31153182
text_color_set(DW_COLOR_ERROR);
31163183
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
31173184
line, from_chan);
@@ -3149,7 +3216,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
31493216
continue;
31503217
}
31513218
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO &&
3152-
p_audio_config->chan_medium[to_chan] != MEDIUM_NETTNC) {
3219+
p_audio_config->chan_medium[to_chan] != MEDIUM_NETTNC &&
3220+
p_audio_config->chan_medium[to_chan] != MEDIUM_SERTNC) {
31533221
text_color_set(DW_COLOR_ERROR);
31543222
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
31553223
line, to_chan);
@@ -4429,7 +4497,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
44294497
x = -1;
44304498
}
44314499
else if (p_audio_config->chan_medium[x] != MEDIUM_RADIO &&
4432-
p_audio_config->chan_medium[x] != MEDIUM_NETTNC) {
4500+
p_audio_config->chan_medium[x] != MEDIUM_NETTNC &&
4501+
p_audio_config->chan_medium[x] != MEDIUM_SERTNC) {
44334502
text_color_set(DW_COLOR_ERROR);
44344503
dw_printf ("Config file, line %d: TTOBJ transmit channel %d is not valid.\n", line, x);
44354504
x = -1;
@@ -5784,7 +5853,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
57845853
/* When IGate is enabled, all radio channels must have a callsign associated. */
57855854

57865855
if (strlen(p_igate_config->t2_login) > 0 &&
5787-
(p_audio_config->chan_medium[i] == MEDIUM_RADIO || p_audio_config->chan_medium[i] == MEDIUM_NETTNC)) {
5856+
(p_audio_config->chan_medium[i] == MEDIUM_RADIO ||
5857+
p_audio_config->chan_medium[i] == MEDIUM_NETTNC ||
5858+
p_audio_config->chan_medium[i] == MEDIUM_SERTNC)) {
57885859

57895860
if (strcmp(p_audio_config->mycall[i], "NOCALL") == 0 || strcmp(p_audio_config->mycall[i], "N0CALL") == 0) {
57905861
text_color_set(DW_COLOR_ERROR);
@@ -5810,7 +5881,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
58105881

58115882
if (strlen(p_igate_config->t2_login) > 0) {
58125883
for (j=0; j<MAX_TOTAL_CHANS; j++) {
5813-
if (p_audio_config->chan_medium[j] == MEDIUM_RADIO || p_audio_config->chan_medium[j] == MEDIUM_NETTNC) {
5884+
if (p_audio_config->chan_medium[j] == MEDIUM_RADIO ||
5885+
p_audio_config->chan_medium[j] == MEDIUM_NETTNC ||
5886+
p_audio_config->chan_medium[j] == MEDIUM_SERTNC) {
58145887
if (p_digi_config->filter_str[MAX_TOTAL_CHANS][j] == NULL) {
58155888
p_digi_config->filter_str[MAX_TOTAL_CHANS][j] = strdup("i/180");
58165889
}

src/digipeater.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ void digipeater (int from_chan, packet_t pp)
156156

157157
if ( from_chan < 0 || from_chan >= MAX_TOTAL_CHANS ||
158158
(save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO &&
159-
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC)) {
159+
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC &&
160+
save_audio_config_p->chan_medium[from_chan] != MEDIUM_SERTNC)) {
160161
text_color_set(DW_COLOR_ERROR);
161162
dw_printf ("APRS digipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
162163
}

src/direwolf.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
#include "dlq.h" // for fec_type_t definition.
132132
#include "deviceid.h"
133133
#include "nettnc.h"
134+
#include "sertnc.h"
134135

135136

136137
//static int idx_decoded = 0;
@@ -1018,11 +1019,12 @@ int main (int argc, char *argv[])
10181019
il2p_init (d_2_opt);
10191020

10201021
/*
1021-
* New in 1.8 - Allow a channel to be mapped to a network TNC rather than
1022-
* an internal modem and radio.
1022+
* New in 1.8 - Allow a channel to be mapped to a network or serial TNC rather
1023+
* than an internal modem and radio.
10231024
* I put it here so channel properties would come out in right order.
10241025
*/
10251026
nettnc_init (&audio_config);
1027+
sertnc_init (&audio_config);
10261028

10271029
/*
10281030
* Initialize the touch tone decoder & APRStt gateway.
@@ -1191,6 +1193,7 @@ int main (int argc, char *argv[])
11911193
* -1 for DTMF decoder.
11921194
* -2 for channel mapped to APRS-IS.
11931195
* -3 for channel mapped to network TNC.
1196+
* -4 for channel mapped to serial TNC.
11941197
* slice - Slicer which caught it.
11951198
* pp - Packet handle.
11961199
* alevel - Audio level, range of 0 - 100.
@@ -1221,7 +1224,7 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
12211224
// Can indicate FX.25/IL2P or fix_bits.
12221225

12231226
assert (chan >= 0 && chan < MAX_TOTAL_CHANS); // TOTAL for virtual channels
1224-
assert (subchan >= -3 && subchan < MAX_SUBCHANS);
1227+
assert (subchan >= -4 && subchan < MAX_SUBCHANS);
12251228
assert (slice >= 0 && slice < MAX_SLICERS);
12261229
assert (pp != NULL); // 1.1J+
12271230

@@ -1342,7 +1345,7 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
13421345
dw_printf ("Setting audio input level so most stations are around 50 will provide good dyanmic range.\n");
13431346
}
13441347
// FIXME: rather than checking for ichannel, how about checking medium==radio
1345-
else if (alevel.rec < 5 && chan != audio_config.igate_vchannel && subchan != -3) {
1348+
else if (alevel.rec < 5 && chan != audio_config.igate_vchannel && subchan != SUBCHAN_NETTNC && subchan != SUBCHAN_SERTNC) {
13461349

13471350
text_color_set(DW_COLOR_ERROR);
13481351
dw_printf ("Audio input level is too low. Increase so most stations are around 50.\n");
@@ -1367,15 +1370,19 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
13671370
strlcpy (ts, "", sizeof(ts));
13681371
}
13691372

1370-
if (subchan == -1) { // dtmf
1373+
if (subchan == SUBCHAN_DTMF) {
13711374
text_color_set(DW_COLOR_REC);
13721375
dw_printf ("[%d.dtmf%s] ", chan, ts);
13731376
}
1374-
else if (subchan == -2) { // APRS-IS
1377+
else if (subchan == SUBCHAN_APRSIS) {
13751378
text_color_set(DW_COLOR_REC);
13761379
dw_printf ("[%d.is%s] ", chan, ts);
13771380
}
1378-
else if (subchan == -3) { // nettnc
1381+
else if (subchan == SUBCHAN_NETTNC) {
1382+
text_color_set(DW_COLOR_REC);
1383+
dw_printf ("[%d%s] ", chan, ts);
1384+
}
1385+
else if (subchan == SUBCHAN_SERTNC) {
13791386
text_color_set(DW_COLOR_REC);
13801387
dw_printf ("[%d%s] ", chan, ts);
13811388
}

src/dlq.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,13 @@ typedef struct dlq_item_s {
6262

6363
int subchan; /* Winning "subchannel" when using multiple */
6464
/* decoders on one channel. */
65-
/* Special case, -1 means DTMF decoder. */
6665
/* Maybe we should have a different type in this case? */
6766

67+
#define SUBCHAN_DTMF -1
68+
#define SUBCHAN_APRSIS -2
69+
#define SUBCHAN_NETTNC -3
70+
#define SUBCHAN_SERTNC -4
71+
6872
int slice; /* Winning slicer. */
6973

7074
packet_t pp; /* Pointer to frame structure. */

0 commit comments

Comments
 (0)