From ae888b0a8d7261491017512fc06a0ba44cbbfc34 Mon Sep 17 00:00:00 2001 From: wb2osz Date: Fri, 19 Jul 2024 00:37:38 +0100 Subject: [PATCH] New NCHANNEL feature. --- CHANGES.md | 3 + conf/generic.conf | 2 +- src/CMakeLists.txt | 1 + src/agwlib.c | 2 +- src/appserver.c | 2 +- src/aprs_tt.c | 8 +- src/atest.c | 11 ++- src/audio.c | 2 +- src/audio.h | 27 ++++-- src/audio_portaudio.c | 2 +- src/audio_win.c | 20 +++- src/ax25_link.c | 39 ++++++-- src/ax25_link.h | 2 +- src/ax25_pad.c | 18 +++- src/beacon.c | 14 +-- src/cdigipeater.c | 18 ++-- src/cdigipeater.h | 14 ++- src/config.c | 206 +++++++++++++++++++++++++++--------------- src/config.h | 2 +- src/decode_aprs.c | 2 +- src/demod.c | 18 ++-- src/demod_9600.c | 9 +- src/demod_afsk.c | 2 +- src/demod_psk.c | 118 ++++++++++++++++-------- src/digipeater.c | 24 ++--- src/digipeater.h | 16 ++-- src/direwolf.c | 62 ++++++++++--- src/direwolf.h | 7 +- src/dlq.c | 12 +-- src/dtmf.c | 11 ++- src/dwsock.c | 2 +- src/encode_aprs.c | 12 ++- src/fsk_demod_state.h | 2 +- src/fx25_rec.c | 6 +- src/fx25_send.c | 4 +- src/gen_packets.c | 2 +- src/gen_tone.c | 28 +++--- src/hdlc_rec.c | 57 +++++++++--- src/hdlc_rec.h | 10 ++ src/hdlc_rec2.c | 10 +- src/hdlc_send.c | 6 +- src/igate.c | 26 +++--- src/il2p_rec.c | 9 +- src/il2p_send.c | 2 +- src/kiss_frame.c | 18 ++-- src/multi_modem.c | 21 +++-- src/pfilter.c | 18 ++-- src/ptt.c | 34 +++---- src/recv.c | 3 +- src/rrbb.c | 4 +- src/server.c | 12 +-- src/telemetry.c | 2 +- src/tnctest.c | 24 ++--- src/tq.c | 66 +++++++++----- src/tt_user.c | 6 +- src/xmit.c | 30 +++--- 56 files changed, 697 insertions(+), 391 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0903e9e..69a1a85 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,9 @@ ### New Features: ### + +- New NCHANNEL feature to map a channel number to an external network TCP KISS TNC. See xxx for example of a bridge to LoRa APRS. See [APRS-LoRa-VHF-APRS-Bridge.pdf](https://github.com/wb2osz/direwolf-doc/blob/main/APRS-LoRa-VHF-APRS-Bridge.pdf) for explanation. + - [http://www.aprs.org/aprs11/tocalls.txt](http://www.aprs.org/aprs11/tocalls.txt) has been abandoned since the end of 2021. [https://github.com/aprsorg/aprs-deviceid](https://github.com/aprsorg/aprs-deviceid) is now considered to be the authoritative source of truth for the vendor/model encoding. ## Version 1.7 -- October 2023 ## diff --git a/conf/generic.conf b/conf/generic.conf index 9a19d8a..4fb63f6 100644 --- a/conf/generic.conf +++ b/conf/generic.conf @@ -274,7 +274,7 @@ %C%#DTMF %C% %C%# Push to Talk (PTT) can be confusing because there are so many different cases. -%C%# Radio-Interface-Guide.pdf in https://github.com/wb2osz/direwolf-doc +%C%# https://github.com/wb2osz/direwolf-doc/blob/main/Radio-Interface-Guide.pdf %C%# goes into detail about the various options. %C% %L%# If using a C-Media CM108/CM119 or similar USB Audio Adapter, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19dada4..f376b7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ list(APPEND direwolf_SOURCES morse.c multi_modem.c waypoint.c + nettnc.c serial_port.c pfilter.c ptt.c diff --git a/src/agwlib.c b/src/agwlib.c index 2c03ada..cee4f99 100644 --- a/src/agwlib.c +++ b/src/agwlib.c @@ -357,7 +357,7 @@ static void * tnc_listen_thread (void *arg) /* * Take some precautions to guard against bad data which could cause problems later. */ - if (cmd.hdr.portx < 0 || cmd.hdr.portx >= MAX_CHANS) { + if (cmd.hdr.portx < 0 || cmd.hdr.portx >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Invalid channel number, %d, in command '%c', from network TNC.\n", cmd.hdr.portx, cmd.hdr.datakind); diff --git a/src/appserver.c b/src/appserver.c index b0ef7d8..bc2e281 100644 --- a/src/appserver.c +++ b/src/appserver.c @@ -597,7 +597,7 @@ void agw_cb_G_port_information (int num_chan_avail, char *chan_descriptions[]) if (strncasecmp(p, "Port", 4) == 0 && isdigit(p[4])) { int chan = atoi(p+4) - 1; // "Port1" is our channel 0. - if (chan >= 0 && chan < MAX_CHANS) { + if (chan >= 0 && chan < MAX_TOTAL_CHANS) { char *desc = p + 4; while (*desc != '\0' && (*desc == ' ' || isdigit(*desc))) { diff --git a/src/aprs_tt.c b/src/aprs_tt.c index 7b12575..a2d35ec 100644 --- a/src/aprs_tt.c +++ b/src/aprs_tt.c @@ -95,8 +95,8 @@ #define MAX_MSG_LEN 100 -static char msg_str[MAX_CHANS][MAX_MSG_LEN+1]; -static int msg_len[MAX_CHANS]; +static char msg_str[MAX_RADIO_CHANS][MAX_MSG_LEN+1]; +static int msg_len[MAX_RADIO_CHANS]; static int parse_fields (char *msg); static int parse_callsign (char *e); @@ -185,7 +185,7 @@ void aprs_tt_init (struct tt_config_s *p, int debug) // TODO: Keep ptr instead of making a copy. memcpy (&tt_config, p, sizeof(struct tt_config_s)); #endif - for (c=0; c= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); //if (button != '.') { diff --git a/src/atest.c b/src/atest.c index c5f4ec5..a24ed72 100644 --- a/src/atest.c +++ b/src/atest.c @@ -231,7 +231,7 @@ int main (int argc, char *argv[]) my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; - for (channel=0; channeladev[a].bits_per_sample == 0) pa->adev[a].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; - for (chan=0; chanachan[chan].mark_freq == 0) pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ; diff --git a/src/audio.h b/src/audio.h index 4fc0570..92fd944 100644 --- a/src/audio.h +++ b/src/audio.h @@ -16,7 +16,7 @@ #include #endif -#include "direwolf.h" /* for MAX_CHANS used throughout the application. */ +#include "direwolf.h" /* for MAX_RADIO_CHANS and MAX_TOTAL_CHANS used throughout the application. */ #include "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */ #include "version.h" @@ -59,7 +59,7 @@ typedef enum retry_e { enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use. MEDIUM_RADIO, // Internal modem for radio. MEDIUM_IGATE, // Access IGate as ordinary channel. - MEDIUM_NETTNC }; // Remote network TNC. (possible future) + MEDIUM_NETTNC }; // Remote network TNC. (new in 1.8) typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t; @@ -139,10 +139,19 @@ struct audio_s { /* originally a "channel" was always connected to an internal modem. */ /* In version 1.6, this is generalized so that a channel (as seen by client application) */ /* can be connected to something else. Initially, this will allow application */ - /* access to the IGate. Later we might have network TNCs or other internal functions. */ + /* access to the IGate. In version 1.8 we add network KISS TNC. */ + + // Watch out for maximum number of channels. + // MAX_CHANS - Originally, this was 6 for internal modem adio channels. Has been phased out. + // After adding virtual channels (IGate, network TNC), this is split into two different numbers: + // MAX_RADIO_CHANNELS - For internal modems. + // MAX_TOTAL_CHANNELS - limited by KISS channels/ports. Needed for digipeating, filtering, etc. // Properties for all channels. + char mycall[MAX_TOTAL_CHANS][AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */ + /* Could all be the same or different. */ + enum medium_e chan_medium[MAX_TOTAL_CHANS]; // MEDIUM_NONE for invalid. // MEDIUM_RADIO for internal modem. (only possibility earlier) @@ -154,6 +163,14 @@ struct audio_s { /* Redundant but it makes things quicker and simpler */ /* than always searching thru above. */ + // Applies only to network TNC type channels. + + char nettnc_addr[MAX_TOTAL_CHANS][80]; // Network TNC address: hostname or IP addr. + + int nettnc_port[MAX_TOTAL_CHANS]; // Network TNC TCP port. + + + /* Properties for each radio channel, common to receive and transmit. */ /* Can be different for each radio channel. */ @@ -171,8 +188,6 @@ struct audio_s { // int audio_source; // Default would be [0,1,2,3,4,5] // What else should be moved out of structure and enlarged when NETTNC is implemented. ??? - char mycall[AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */ - /* Could all be the same or different. */ enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF, MODEM_16_QAM, MODEM_64_QAM, MODEM_AIS, MODEM_EAS } modem_type; @@ -381,7 +396,7 @@ struct audio_s { int fulldup; /* Full Duplex. */ - } achan[MAX_CHANS]; + } achan[MAX_RADIO_CHANS]; #ifdef USE_HAMLIB int rigs; /* Total number of configured rigs */ diff --git a/src/audio_portaudio.c b/src/audio_portaudio.c index cb6ccf1..92ba2cb 100644 --- a/src/audio_portaudio.c +++ b/src/audio_portaudio.c @@ -578,7 +578,7 @@ int audio_open (struct audio_s *pa) if (pa->adev[a].bits_per_sample == 0) pa->adev[a].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; - for (chan = 0; chan < MAX_CHANS; chan++) { + for (chan = 0; chan < MAX_RADIO_CHANS; chan++) { if (pa->achan[chan].mark_freq == 0) pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ; diff --git a/src/audio_win.c b/src/audio_win.c index 85a1548..a133648 100644 --- a/src/audio_win.c +++ b/src/audio_win.c @@ -270,7 +270,7 @@ int audio_open (struct audio_s *pa) A->g_audio_in_type = AUDIO_IN_TYPE_SOUNDCARD; - for (chan=0; chan achan[chan].mark_freq == 0) pa -> achan[chan].mark_freq = DEFAULT_MARK_FREQ; @@ -660,7 +660,13 @@ int audio_open (struct audio_s *pa) */ case AUDIO_IN_TYPE_STDIN: - setmode (STDIN_FILENO, _O_BINARY); + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?view=msvc-170 + + int err = _setmode (_fileno(stdin), _O_BINARY); + if (err == -1) { + text_color_set (DW_COLOR_ERROR); + dw_printf ("Could not set stdin to binary mode. Unlikely to get desired result.\n"); + } A->stream_next= 0; A->stream_len = 0; @@ -888,7 +894,7 @@ int audio_get (int a) while (A->stream_next >= A->stream_len) { int res; - res = read(STDIN_FILENO, A->stream_data, 1024); + res = read(STDIN_FILENO, A->stream_data, sizeof(A->stream_data)); if (res <= 0) { text_color_set(DW_COLOR_INFO); dw_printf ("\nEnd of file on stdin. Exiting.\n"); @@ -903,9 +909,13 @@ int audio_get (int a) A->stream_len = res; A->stream_next = 0; } - return (A->stream_data[A->stream_next++] & 0xff); + sample = A->stream_data[A->stream_next] & 0xff; + A->stream_next++; + return (sample); + break; - } + + } // end switch audio in type return (-1); diff --git a/src/ax25_link.c b/src/ax25_link.c index 98d6c45..50495cd 100644 --- a/src/ax25_link.c +++ b/src/ax25_link.c @@ -1,7 +1,7 @@ // // This file is part of Dire Wolf, an amateur radio packet TNC. // -// Copyright (C) 2016, 2017, 2018, 2023 John Langner, WB2OSZ +// Copyright (C) 2016, 2017, 2018, 2023, 2024 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 @@ -679,11 +679,13 @@ static struct misc_config_s *g_misc_config_p; * Inputs: pconfig - misc. configuration from config file or command line. * Beacon stuff ended up here. * + * debug - debug level. + * * Outputs: Remember required information for future use. That's all. * *--------------------------------------------------------------------*/ -void ax25_link_init (struct misc_config_s *pconfig) +void ax25_link_init (struct misc_config_s *pconfig, int debug) { /* @@ -691,6 +693,31 @@ void ax25_link_init (struct misc_config_s *pconfig) */ g_misc_config_p = pconfig; + if (debug >= 1) { // Only single level so far. + + s_debug_protocol_errors = 1; // Less serious Protocol errors. + + s_debug_client_app = 1; // Interaction with client application. + // dl_connect_request, dl_data_request, dl_data_indication, etc. + + s_debug_radio = 1; // Received frames and channel busy status. + // lm_data_indication, lm_channel_busy + + s_debug_variables = 1; // Variables, state changes. + + s_debug_retry = 1; // Related to lost I frames, REJ, SREJ, timeout, resending. + + s_debug_link_handle = 1; // Create data link state machine or pick existing one, + // based on my address, peer address, client app index, and radio channel. + + s_debug_stats = 1; // Statistics when connection is closed. + + s_debug_misc = 1; // Anything left over that might be interesting. + + s_debug_timers = 1; // Timer details. + } + + } /* end ax25_link_init */ @@ -2013,14 +2040,14 @@ static void dl_data_indication (ax25_dlsm_t *S, int pid, char *data, int len) * *------------------------------------------------------------------------------*/ -static int dcd_status[MAX_CHANS]; -static int ptt_status[MAX_CHANS]; +static int dcd_status[MAX_RADIO_CHANS]; +static int ptt_status[MAX_RADIO_CHANS]; void lm_channel_busy (dlq_item_t *E) { int busy; - assert (E->chan >= 0 && E->chan < MAX_CHANS); + assert (E->chan >= 0 && E->chan < MAX_RADIO_CHANS); assert (E->activity == OCTYPE_PTT || E->activity == OCTYPE_DCD); assert (E->status == 1 || E->status == 0); @@ -2104,7 +2131,7 @@ void lm_channel_busy (dlq_item_t *E) void lm_seize_confirm (dlq_item_t *E) { - assert (E->chan >= 0 && E->chan < MAX_CHANS); + assert (E->chan >= 0 && E->chan < MAX_RADIO_CHANS); ax25_dlsm_t *S; diff --git a/src/ax25_link.h b/src/ax25_link.h index 40fa401..52cacee 100644 --- a/src/ax25_link.h +++ b/src/ax25_link.h @@ -43,7 +43,7 @@ // Call once at startup time. -void ax25_link_init (struct misc_config_s *pconfig); +void ax25_link_init (struct misc_config_s *pconfig, int debug); diff --git a/src/ax25_pad.c b/src/ax25_pad.c index 4a52638..57fd79d 100644 --- a/src/ax25_pad.c +++ b/src/ax25_pad.c @@ -1,7 +1,7 @@ // // This file is part of Dire Wolf, an amateur radio packet TNC. // -// Copyright (C) 2011 , 2013, 2014, 2015, 2019 John Langner, WB2OSZ +// Copyright (C) 2011 , 2013, 2014, 2015, 2019, 2024 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 @@ -355,12 +355,26 @@ void ax25_delete (packet_t this_p) * The SSID can be 2 alphanumeric characters, not just 1 to 15. * * We can just truncate the name because we will only - * end up discarding it. TODO: check on this. + * end up discarding it. TODO: check on this. WRONG! FIXME * * Returns: Pointer to new packet object in the current implementation. * * Outputs: Use the "get" functions to retrieve information in different ways. * + * Evolution: Originally this was written to handle only valid RF packets. + * There are other places where the rules are not as strict. + * Using decode_aprs with raw data seen on aprs.fi. e.g. + * EL-CA2JOT>RXTLM-1,TCPIP,qAR,CA2JOT::EL-CA2JOT:UNIT.... + * EA4YR>APBM1S,TCPIP*,qAS,BM2142POS:@162124z... + * * Source addr might not comply to RF format. + * * The q-construct has lower case. + * * Tier-2 server name might not comply to RF format. + * We have the same issue with the encapsulated part of a third-party packet. + * WB2OSZ-5>APDW17,WIDE1-1,WIDE2-1:}WHO-IS>APJIW4,TCPIP,WB2OSZ-5*::WB2OSZ-7 :ack0 + * + * We need a way to keep and retrieve the original name. + * This gets a little messy because the packet object is in the on air frame format. + * *------------------------------------------------------------------------------*/ #if AX25MEMDEBUG diff --git a/src/beacon.c b/src/beacon.c index 69a7270..b868f22 100644 --- a/src/beacon.c +++ b/src/beacon.c @@ -162,14 +162,14 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct int chan = g_misc_config_p->beacon[j].sendto_chan; if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */ - if (chan >= MAX_CHANS) chan = 0; // For ICHANNEL, use channel 0 call. + if (chan >= MAX_TOTAL_CHANS) chan = 0; // For ICHANNEL, use channel 0 call. if (g_modem_config_p->chan_medium[chan] == MEDIUM_RADIO || g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) { - if (strlen(g_modem_config_p->achan[chan].mycall) > 0 && - strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 && - strcasecmp(g_modem_config_p->achan[chan].mycall, "NOCALL") != 0) { + if (strlen(g_modem_config_p->mycall[chan]) > 0 && + strcasecmp(g_modem_config_p->mycall[chan], "N0CALL") != 0 && + strcasecmp(g_modem_config_p->mycall[chan], "NOCALL") != 0) { switch (g_misc_config_p->beacon[j].btype) { @@ -809,10 +809,10 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo) if (g_modem_config_p->chan_medium[bp->sendto_chan] == MEDIUM_IGATE) { // ICHANNEL uses chan 0 mycall. // TODO: Maybe it should be allowed to have own. - strlcpy (mycall, g_modem_config_p->achan[0].mycall, sizeof(mycall)); + strlcpy (mycall, g_modem_config_p->mycall[0], sizeof(mycall)); } else { - strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall)); + strlcpy (mycall, g_modem_config_p->mycall[bp->sendto_chan], sizeof(mycall)); } if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) { @@ -900,7 +900,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo) case BEACON_OBJECT: - encode_object (bp->objname, bp->compress, 0, bp->lat, bp->lon, bp->ambiguity, + encode_object (bp->objname, bp->compress, 1, bp->lat, bp->lon, bp->ambiguity, bp->symtab, bp->symbol, bp->power, bp->height, bp->gain, bp->dir, G_UNKNOWN, G_UNKNOWN, /* course, speed */ diff --git a/src/cdigipeater.c b/src/cdigipeater.c index 06128b2..844af47 100644 --- a/src/cdigipeater.c +++ b/src/cdigipeater.c @@ -76,7 +76,7 @@ static struct cdigi_config_s *save_cdigi_config_p; * Maintain count of packets digipeated for each combination of from/to channel. */ -static int cdigi_count[MAX_CHANS][MAX_CHANS]; +static int cdigi_count[MAX_RADIO_CHANS][MAX_RADIO_CHANS]; int cdigipeater_get_count (int from_chan, int to_chan) { return (cdigi_count[from_chan][to_chan]); @@ -132,7 +132,9 @@ void cdigipeater (int from_chan, packet_t pp) // Connected mode is allowed only for channels with internal modem. // It probably wouldn't matter for digipeating but let's keep that rule simple and consistent. - if ( from_chan < 0 || from_chan >= MAX_CHANS || save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO) { + if ( from_chan < 0 || from_chan >= MAX_RADIO_CHANS || + (save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO && + save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC) ) { text_color_set(DW_COLOR_ERROR); dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan); return; @@ -145,13 +147,13 @@ void cdigipeater (int from_chan, packet_t pp) * Might not have a benefit here. */ - for (to_chan=0; to_chanenabled[from_chan][to_chan]) { if (to_chan == from_chan) { packet_t result; - result = cdigipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, - save_audio_config_p->achan[to_chan].mycall, + result = cdigipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan], + save_audio_config_p->mycall[to_chan], save_cdigi_config_p->has_alias[from_chan][to_chan], &(save_cdigi_config_p->alias[from_chan][to_chan]), to_chan, save_cdigi_config_p->cfilter_str[from_chan][to_chan]); @@ -168,13 +170,13 @@ void cdigipeater (int from_chan, packet_t pp) * Second pass: Look at packets being digipeated to different channel. */ - for (to_chan=0; to_chanenabled[from_chan][to_chan]) { if (to_chan != from_chan) { packet_t result; - result = cdigipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, - save_audio_config_p->achan[to_chan].mycall, + result = cdigipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan], + save_audio_config_p->mycall[to_chan], save_cdigi_config_p->has_alias[from_chan][to_chan], &(save_cdigi_config_p->alias[from_chan][to_chan]), to_chan, save_cdigi_config_p->cfilter_str[from_chan][to_chan]); diff --git a/src/cdigipeater.h b/src/cdigipeater.h index 69a4b8c..89b0302 100644 --- a/src/cdigipeater.h +++ b/src/cdigipeater.h @@ -5,7 +5,7 @@ #include "regex.h" -#include "direwolf.h" /* for MAX_CHANS */ +#include "direwolf.h" /* for MAX_RADIO_CHANS */ #include "ax25_pad.h" /* for packet_t */ #include "audio.h" /* for radio channel properties */ @@ -23,17 +23,21 @@ struct cdigi_config_s { /* * Rules for each of the [from_chan][to_chan] combinations. */ - int enabled[MAX_CHANS][MAX_CHANS]; // Is it enabled for from/to pair? - int has_alias[MAX_CHANS][MAX_CHANS]; // If there was no alias in the config file, +// For APRS digipeater, we use MAX_TOTAL_CHANS because we use external TNCs. +// Connected mode packet must use internal modems we we use MAX_RADIO_CHANS. + + int enabled[MAX_RADIO_CHANS][MAX_RADIO_CHANS]; // Is it enabled for from/to pair? + + int has_alias[MAX_RADIO_CHANS][MAX_RADIO_CHANS]; // If there was no alias in the config file, // the structure below will not be set up // properly and an attempt to use it could // result in a crash. (fixed v1.5) // Not needed for [APRS] DIGIPEAT because // the alias is mandatory there. - regex_t alias[MAX_CHANS][MAX_CHANS]; + regex_t alias[MAX_RADIO_CHANS][MAX_RADIO_CHANS]; - char *cfilter_str[MAX_CHANS][MAX_CHANS]; + char *cfilter_str[MAX_RADIO_CHANS][MAX_RADIO_CHANS]; // NULL or optional Packet Filter strings such as "t/m". }; diff --git a/src/config.c b/src/config.c index de8d74d..69fa80e 100644 --- a/src/config.c +++ b/src/config.c @@ -763,7 +763,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_audio_config->adev[0].defined = 2; // 2 means it was done by default and not the user's config file. - for (channel=0; channelchan_medium[channel] = MEDIUM_NONE; /* One or both channels will be */ @@ -1221,7 +1221,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, */ /* - * CHANNEL n - Set channel for channel-specific commands. + * CHANNEL n - Set channel for channel-specific commands. Only for modem/radio channels. */ else if (strcasecmp(t, "CHANNEL") == 0) { @@ -1233,7 +1233,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } n = atoi(t); - if (n >= 0 && n < MAX_CHANS) { + if (n >= 0 && n < MAX_RADIO_CHANS) { channel = n; @@ -1253,7 +1253,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, } else { text_color_set(DW_COLOR_ERROR); - dw_printf ("Line %d: Channel number must in range of 0 to %d.\n", line, MAX_CHANS-1); + dw_printf ("Line %d: Channel number must in range of 0 to %d.\n", line, MAX_RADIO_CHANS-1); } } @@ -1274,7 +1274,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } int ichan = atoi(t); - if (ichan >= MAX_CHANS && ichan < MAX_TOTAL_CHANS) { + if (ichan >= MAX_RADIO_CHANS && ichan < MAX_TOTAL_CHANS) { if (p_audio_config->chan_medium[ichan] == MEDIUM_NONE) { @@ -1286,15 +1286,73 @@ void config_init (char *fname, struct audio_s *p_audio_config, } else { text_color_set(DW_COLOR_ERROR); - dw_printf ("Line %d: ICHANNEL can't use %d because it is already in use.\n", line, ichan); + dw_printf ("Line %d: ICHANNEL can't use channel %d because it is already in use.\n", line, ichan); } } else { text_color_set(DW_COLOR_ERROR); - dw_printf ("Line %d: ICHANNEL number must in range of %d to %d.\n", line, MAX_CHANS, MAX_TOTAL_CHANS-1); + dw_printf ("Line %d: ICHANNEL number must in range of %d to %d.\n", line, MAX_RADIO_CHANS, MAX_TOTAL_CHANS-1); } } +/* + * NCHANNEL chan addr port - Define Network TNC virtual channel. + * + * This allows a client application to talk to to an external TNC over TCP KISS + * by using a channel number outside the normal range for modems. + * This does not change the current channel number used by MODEM, PTT, etc. + * + * chan = direwolf channel. + * addr = hostname or IP address of network TNC. + * port = KISS TCP port on network TNC. + * + * Future: Might allow selection of channel on the network TNC. + * For now, ignore incoming and set to 0 for outgoing. + * + * FIXME: Can't set mycall for nchannel. + */ + + else if (strcasecmp(t, "NCHANNEL") == 0) { + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Missing virtual channel number for NCHANNEL command.\n", line); + continue; + } + int nchan = atoi(t); + if (nchan >= MAX_RADIO_CHANS && nchan < MAX_TOTAL_CHANS) { + + if (p_audio_config->chan_medium[nchan] == MEDIUM_NONE) { + + p_audio_config->chan_medium[nchan] = MEDIUM_NETTNC; + } + else { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: NCHANNEL can't use channel %d because it is already in use.\n", line, nchan); + } + } + else { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: NCHANNEL number must in range of %d to %d.\n", line, MAX_RADIO_CHANS, MAX_TOTAL_CHANS-1); + } + + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Missing network TNC address for NCHANNEL command.\n", line); + continue; + } + strlcpy (p_audio_config->nettnc_addr[nchan], t, sizeof(p_audio_config->nettnc_addr[nchan])); + + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Missing network TNC TCP port for NCHANNEL command.\n", line); + continue; + } + p_audio_config->nettnc_port[nchan] = atoi(t); + } + /* * MYCALL station */ @@ -1330,14 +1388,14 @@ void config_init (char *fname, struct audio_s *p_audio_config, int c; - for (c = 0; c < MAX_CHANS; c++) { + for (c = 0; c < MAX_TOTAL_CHANS; c++) { if (c == channel || - strlen(p_audio_config->achan[c].mycall) == 0 || - strcasecmp(p_audio_config->achan[c].mycall, "NOCALL") == 0 || - strcasecmp(p_audio_config->achan[c].mycall, "N0CALL") == 0) { + strlen(p_audio_config->mycall[c]) == 0 || + strcasecmp(p_audio_config->mycall[c], "NOCALL") == 0 || + strcasecmp(p_audio_config->mycall[c], "N0CALL") == 0) { - strlcpy (p_audio_config->achan[c].mycall, t, sizeof(p_audio_config->achan[c].mycall)); + strlcpy (p_audio_config->mycall[c], t, sizeof(p_audio_config->mycall[c])); } } } @@ -2552,10 +2610,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } from_chan = atoi(t); - if (from_chan < 0 || from_chan >= MAX_CHANS) { + if (from_chan < 0 || from_chan >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_TOTAL_CHANS-1, line); continue; } @@ -2582,10 +2640,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } to_chan = atoi(t); - if (to_chan < 0 || to_chan >= MAX_CHANS) { + if (to_chan < 0 || to_chan >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_TOTAL_CHANS-1, line); continue; } @@ -2713,10 +2771,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } from_chan = atoi(t); - if (from_chan < 0 || from_chan >= MAX_CHANS) { + if (from_chan < 0 || from_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } @@ -2742,10 +2800,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } to_chan = atoi(t); - if (to_chan < 0 || to_chan >= MAX_CHANS) { + if (to_chan < 0 || to_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { @@ -2787,10 +2845,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } from_chan = atoi(t); - if (from_chan < 0 || from_chan >= MAX_CHANS) { + if (from_chan < 0 || from_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } @@ -2820,10 +2878,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } to_chan = atoi(t); - if (to_chan < 0 || to_chan >= MAX_CHANS) { + if (to_chan < 0 || to_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { @@ -2906,7 +2964,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } if (*t == 'i' || *t == 'I') { - from_chan = MAX_CHANS; + from_chan = MAX_TOTAL_CHANS; text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: FILTER IG ... on line %d.\n", line); dw_printf ("Warning! Don't mess with IS>RF filtering unless you are an expert and have an unusual situation.\n"); @@ -2916,10 +2974,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } else { from_chan = isdigit(*t) ? atoi(t) : -999; - if (from_chan < 0 || from_chan >= MAX_CHANS) { + if (from_chan < 0 || from_chan >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: Filter FROM-channel must be in range of 0 to %d or \"IG\" on line %d.\n", - MAX_CHANS-1, line); + MAX_TOTAL_CHANS-1, line); continue; } @@ -2945,7 +3003,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } if (*t == 'i' || *t == 'I') { - to_chan = MAX_CHANS; + to_chan = MAX_TOTAL_CHANS; text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: FILTER ... IG ... on line %d.\n", line); dw_printf ("Warning! Don't mess with RF>IS filtering unless you are an expert and have an unusual situation.\n"); @@ -2955,10 +3013,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } else { to_chan = isdigit(*t) ? atoi(t) : -999; - if (to_chan < 0 || to_chan >= MAX_CHANS) { + if (to_chan < 0 || to_chan >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: Filter TO-channel must be in range of 0 to %d or \"IG\" on line %d.\n", - MAX_CHANS-1, line); + MAX_TOTAL_CHANS-1, line); continue; } if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO && @@ -3020,10 +3078,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } from_chan = isdigit(*t) ? atoi(t) : -999; - if (from_chan < 0 || from_chan >= MAX_CHANS) { + if (from_chan < 0 || from_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: Filter FROM-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } @@ -3045,10 +3103,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } to_chan = isdigit(*t) ? atoi(t) : -999; - if (to_chan < 0 || to_chan >= MAX_CHANS) { + if (to_chan < 0 || to_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: Filter TO-channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { @@ -4205,10 +4263,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } r = atoi(t); - if (r < 0 || r > MAX_CHANS-1) { + if (r < 0 || r > MAX_RADIO_CHANS-1) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: DTMF receive channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_RADIO_CHANS-1, line); continue; } @@ -4236,9 +4294,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, if (isdigit(*p)) { x = *p - '0'; - if (x < 0 || x > MAX_CHANS-1) { + if (x < 0 || x > MAX_TOTAL_CHANS-1) { text_color_set(DW_COLOR_ERROR); - dw_printf ("Config file: Transmit channel must be in range of 0 to %d on line %d.\n", MAX_CHANS-1, line); + dw_printf ("Config file: Transmit channel must be in range of 0 to %d on line %d.\n", MAX_TOTAL_CHANS-1, line); x = -1; } else if (p_audio_config->chan_medium[x] != MEDIUM_RADIO && @@ -4528,10 +4586,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, } n = atoi(t); - if (n < 0 || n > MAX_CHANS-1) { + if (n < 0 || n > MAX_TOTAL_CHANS-1) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: Transmit channel must be in range of 0 to %d on line %d.\n", - MAX_CHANS-1, line); + MAX_TOTAL_CHANS-1, line); continue; } p_igate_config->tx_chan = n; @@ -4797,9 +4855,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, t = split(NULL,0); if (t != NULL) { chan = atoi(t); - if (chan < 0 || chan >= MAX_CHANS) { + if (chan < 0 || chan >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); - dw_printf ("Line %d: Invalid channel %d for KISSPORT command. Must be in range 0 thru %d.\n", line, chan, MAX_CHANS-1); + dw_printf ("Line %d: Invalid channel %d for KISSPORT command. Must be in range 0 thru %d.\n", line, chan, MAX_TOTAL_CHANS-1); continue; } } @@ -5510,25 +5568,25 @@ void config_init (char *fname, struct audio_s *p_audio_config, */ int i, j, k, b; - for (i=0; ienabled[i][j]) { - if ( strcmp(p_audio_config->achan[i].mycall, "") == 0 || - strcmp(p_audio_config->achan[i].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) { + if ( strcmp(p_audio_config->mycall[i], "") == 0 || + strcmp(p_audio_config->mycall[i], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[i], "N0CALL") == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for receive channel %d before digipeating is allowed.\n", i); p_digi_config->enabled[i][j] = 0; } - if ( strcmp(p_audio_config->achan[j].mycall, "") == 0 || - strcmp(p_audio_config->achan[j].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[j].mycall, "N0CALL") == 0) { + if ( strcmp(p_audio_config->mycall[j], "") == 0 || + strcmp(p_audio_config->mycall[j], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[j], "N0CALL") == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for transmit channel %d before digipeating is allowed.\n", i); @@ -5550,20 +5608,20 @@ void config_init (char *fname, struct audio_s *p_audio_config, /* Connected mode digipeating. */ - if (p_cdigi_config->enabled[i][j]) { + if (i < MAX_RADIO_CHANS && j < MAX_RADIO_CHANS && p_cdigi_config->enabled[i][j]) { - if ( strcmp(p_audio_config->achan[i].mycall, "") == 0 || - strcmp(p_audio_config->achan[i].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) { + if ( strcmp(p_audio_config->mycall[i], "") == 0 || + strcmp(p_audio_config->mycall[i], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[i], "N0CALL") == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for receive channel %d before digipeating is allowed.\n", i); p_cdigi_config->enabled[i][j] = 0; } - if ( strcmp(p_audio_config->achan[j].mycall, "") == 0 || - strcmp(p_audio_config->achan[j].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[j].mycall, "N0CALL") == 0) { + if ( strcmp(p_audio_config->mycall[j], "") == 0 || + strcmp(p_audio_config->mycall[j], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[j], "N0CALL") == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for transmit channel %d before digipeating is allowed.\n", i); @@ -5587,7 +5645,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, if (strlen(p_igate_config->t2_login) > 0 && (p_audio_config->chan_medium[i] == MEDIUM_RADIO || p_audio_config->chan_medium[i] == MEDIUM_NETTNC)) { - if (strcmp(p_audio_config->achan[i].mycall, "NOCALL") == 0 || strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) { + if (strcmp(p_audio_config->mycall[i], "NOCALL") == 0 || strcmp(p_audio_config->mycall[i], "N0CALL") == 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for receive channel %d before Rx IGate is allowed.\n", i); strlcpy (p_igate_config->t2_login, "", sizeof(p_igate_config->t2_login)); @@ -5595,9 +5653,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, // Currently we can have only one transmit channel. // This might be generalized someday to allow more. if (p_igate_config->tx_chan >= 0 && - ( strcmp(p_audio_config->achan[p_igate_config->tx_chan].mycall, "") == 0 || - strcmp(p_audio_config->achan[p_igate_config->tx_chan].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[p_igate_config->tx_chan].mycall, "N0CALL") == 0)) { + ( strcmp(p_audio_config->mycall[p_igate_config->tx_chan], "") == 0 || + strcmp(p_audio_config->mycall[p_igate_config->tx_chan], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[p_igate_config->tx_chan], "N0CALL") == 0)) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for transmit channel %d before Tx IGate is allowed.\n", i); @@ -5610,10 +5668,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, // This will handle eventual case of multiple transmit channels. if (strlen(p_igate_config->t2_login) > 0) { - for (j=0; jchan_medium[j] == MEDIUM_RADIO || p_audio_config->chan_medium[j] == MEDIUM_NETTNC) { - if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) { - p_digi_config->filter_str[MAX_CHANS][j] = strdup("i/180"); + if (p_digi_config->filter_str[MAX_TOTAL_CHANS][j] == NULL) { + p_digi_config->filter_str[MAX_TOTAL_CHANS][j] = strdup("i/180"); } } } @@ -5746,7 +5804,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ } else if (value[0] == 'r' || value[0] == 'R') { int n = atoi(value+1); - if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) + if (( n < 0 || n >= MAX_TOTAL_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) && p_audio_config->chan_medium[n] != MEDIUM_IGATE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n); @@ -5757,7 +5815,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ } else if (value[0] == 't' || value[0] == 'T' || value[0] == 'x' || value[0] == 'X') { int n = atoi(value+1); - if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) + if (( n < 0 || n >= MAX_TOTAL_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) && p_audio_config->chan_medium[n] != MEDIUM_IGATE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); @@ -5769,7 +5827,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ } else { int n = atoi(value); - if (( n < 0 || n >= MAX_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) + if (( n < 0 || n >= MAX_TOTAL_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE) && p_audio_config->chan_medium[n] != MEDIUM_IGATE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); @@ -6020,7 +6078,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ if (b->sendto_type == SENDTO_XMIT) { - if (( b->sendto_chan < 0 || b->sendto_chan >= MAX_CHANS || p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_NONE) + if (( b->sendto_chan < 0 || b->sendto_chan >= MAX_TOTAL_CHANS || p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_NONE) && p_audio_config->chan_medium[b->sendto_chan] != MEDIUM_IGATE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan); @@ -6029,18 +6087,18 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ if (p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_IGATE) { // Prevent subscript out of bounds. // Will be using call from chan 0 later. - if ( strcmp(p_audio_config->achan[0].mycall, "") == 0 || - strcmp(p_audio_config->achan[0].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[0].mycall, "N0CALL") == 0 ) { + if ( strcmp(p_audio_config->mycall[0], "") == 0 || + strcmp(p_audio_config->mycall[0], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[0], "N0CALL") == 0 ) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", 0); return (0); } } else { - if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 || - strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 || - strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) { + if ( strcmp(p_audio_config->mycall[b->sendto_chan], "") == 0 || + strcmp(p_audio_config->mycall[b->sendto_chan], "NOCALL") == 0 || + strcmp(p_audio_config->mycall[b->sendto_chan], "N0CALL") == 0 ) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", b->sendto_chan); diff --git a/src/config.h b/src/config.h index 360ac49..e467523 100644 --- a/src/config.h +++ b/src/config.h @@ -30,7 +30,7 @@ enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV }; #define MAX_BEACONS 30 -#define MAX_KISS_TCP_PORTS (MAX_CHANS+1) +#define MAX_KISS_TCP_PORTS (MAX_RADIO_CHANS+1) struct misc_config_s { diff --git a/src/decode_aprs.c b/src/decode_aprs.c index 71eb946..ce658eb 100644 --- a/src/decode_aprs.c +++ b/src/decode_aprs.c @@ -1652,7 +1652,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int // It is essential to keep trailing spaces. e.g. VX-8 suffix is "_ " char mcomment[256]; - strlcpy (mcomment, info + sizeof(struct aprs_mic_e_s), sizeof(mcomment)); + strlcpy (mcomment, ((char*)info) + sizeof(struct aprs_mic_e_s), sizeof(mcomment)); if (mcomment[strlen(mcomment)-1] == '\r') { mcomment[strlen(mcomment)-1] = '\0'; } diff --git a/src/demod.c b/src/demod.c index cc52227..efcfde7 100644 --- a/src/demod.c +++ b/src/demod.c @@ -63,11 +63,11 @@ static struct audio_s *save_audio_config_p; // Current state of all the decoders. -static struct demodulator_state_s demodulator_state[MAX_CHANS][MAX_SUBCHANS]; +static struct demodulator_state_s demodulator_state[MAX_RADIO_CHANS][MAX_SUBCHANS]; -static int sample_sum[MAX_CHANS][MAX_SUBCHANS]; -static int sample_count[MAX_CHANS][MAX_SUBCHANS]; +static int sample_sum[MAX_RADIO_CHANS][MAX_SUBCHANS]; +static int sample_count[MAX_RADIO_CHANS][MAX_SUBCHANS]; /*------------------------------------------------------------------ @@ -100,7 +100,7 @@ int demod_init (struct audio_s *pa) save_audio_config_p = pa; - for (chan = 0; chan < MAX_CHANS; chan++) { + for (chan = 0; chan < MAX_RADIO_CHANS; chan++) { if (save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { @@ -812,7 +812,7 @@ int demod_init (struct audio_s *pa) // Now the virtual channels. FIXME: could be single loop. - for (chan = MAX_CHANS; chan < MAX_TOTAL_CHANS; chan++) { + for (chan = MAX_RADIO_CHANS; chan < MAX_TOTAL_CHANS; chan++) { // FIXME dw_printf ("-------- virtual channel loop %d \n", chan); @@ -927,7 +927,7 @@ int demod_get_sample (int a) * *--------------------------------------------------------------------*/ -static volatile int mute_input[MAX_CHANS]; +static volatile int mute_input[MAX_RADIO_CHANS]; // New in 1.7. // A few people have a really bad audio cross talk situation where they receive their own transmissions. @@ -939,7 +939,7 @@ static volatile int mute_input[MAX_CHANS]; void demod_mute_input (int chan, int mute_during_xmit) { - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); mute_input[chan] = mute_during_xmit; } @@ -952,7 +952,7 @@ void demod_process_sample (int chan, int subchan, int sam) struct demodulator_state_s *D; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); if (mute_input[chan]) { @@ -1066,7 +1066,7 @@ alevel_t demod_get_audio_level (int chan, int subchan) struct demodulator_state_s *D; alevel_t alevel; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); /* We have to consider two different cases here. */ diff --git a/src/demod_9600.c b/src/demod_9600.c index 705d1fa..99432bf 100644 --- a/src/demod_9600.c +++ b/src/demod_9600.c @@ -395,7 +395,7 @@ void demod_9600_process_sample (int chan, int sam, int upsample, struct demodula int subchan = 0; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); /* Scale to nice number for convenience. */ @@ -611,7 +611,10 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_ /* Overflow. Was large positive, wrapped around, now large negative. */ - hdlc_rec_bit (chan, subchan, slice, demod_out_f > 0, D->modem_type == MODEM_SCRAMBLE, D->slicer[slice].lfsr); + hdlc_rec_bit_new (chan, subchan, slice, demod_out_f > 0, D->modem_type == MODEM_SCRAMBLE, D->slicer[slice].lfsr, + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); + D->slicer[slice].pll_symbol_count++; + pll_dcd_each_symbol2 (D, chan, subchan, slice); } @@ -627,12 +630,14 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_ float target = D->pll_step_per_sample * demod_out_f / (demod_out_f - D->slicer[slice].prev_demod_out_f); + signed int before = (signed int)(D->slicer[slice].data_clock_pll); // Treat as signed. if (D->slicer[slice].data_detect) { D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_locked_inertia + target * (1.0f - D->pll_locked_inertia) ); } else { D->slicer[slice].data_clock_pll = (int)(D->slicer[slice].data_clock_pll * D->pll_searching_inertia + target * (1.0f - D->pll_searching_inertia) ); } + D->slicer[slice].pll_nudge_total += (int64_t)((signed int)(D->slicer[slice].data_clock_pll)) - (int64_t)before; } diff --git a/src/demod_afsk.c b/src/demod_afsk.c index b4d6c29..3e5d03e 100644 --- a/src/demod_afsk.c +++ b/src/demod_afsk.c @@ -609,7 +609,7 @@ void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulat static int seq = 0; /* for log file name */ #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); /* diff --git a/src/demod_psk.c b/src/demod_psk.c index bc05818..3d06c91 100644 --- a/src/demod_psk.c +++ b/src/demod_psk.c @@ -72,7 +72,10 @@ * V.26 has two variations, A and B. Initially I implemented the A alternative. * It later turned out that the MFJ-2400 used the B alternative. In version 1.6 you have a * choice between compatibility with MFJ (and probably the others) or the original implementation. - * + * The B alternative works a little more reliably, perhaps because there is never a + * zero phase difference between adjacent symbols. + * Eventually the A alternative might disappear to reduce confusion. + * *---------------------------------------------------------------*/ #include "direwolf.h" @@ -94,7 +97,7 @@ #include "fsk_demod_state.h" // Values above override defaults. #include "audio.h" -#include "tune.h" +//#include "tune.h" // obsolete. eventually remove all references. #include "fsk_gen_filter.h" #include "hdlc_rec.h" #include "textcolor.h" @@ -102,7 +105,13 @@ #include "dsp.h" - +#define TUNE(envvar,param,name,fmt) { \ + char *e = getenv(envvar); \ + if (e != NULL) { \ + param = atof(e); \ + text_color_set (DW_COLOR_ERROR); \ + dw_printf ("TUNE: " name " = " fmt "\n", param); \ + } } static const int phase_to_gray_v26[4] = {0, 1, 3, 2}; @@ -202,9 +211,10 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe D->num_slicers = 1; // Haven't thought about this yet. Is it even applicable? -#ifdef TUNE_PROFILE - profile = TUNE_PROFILE; -#endif +//#ifdef TUNE_PROFILE +// profile = TUNE_PROFILE; +//#endif + TUNE("TUNE_PROFILE", profile, "profile", "%c") if (modem_type == MODEM_QPSK) { @@ -290,9 +300,16 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe D->u.psk.delay_line_width_sym = 1.25; // Delay line > 13/12 * symbol period +// JWL experiment 11-7. Should delay be based on audio freq rather than baud? +#if 0 // experiment made things much worse. 55 went down to 21. + D->u.psk.coffs = (int) round( (11.f / 12.f) * (float)samples_per_sec / (float)carrier_freq ); + D->u.psk.boffs = (int) round( (float)samples_per_sec / (float)carrier_freq ); + D->u.psk.soffs = (int) round( (13.f / 12.f) * (float)samples_per_sec / (float)carrier_freq ); +#else D->u.psk.coffs = (int) round( (11.f / 12.f) * (float)samples_per_sec / (float)correct_baud ); D->u.psk.boffs = (int) round( (float)samples_per_sec / (float)correct_baud ); D->u.psk.soffs = (int) round( (13.f / 12.f) * (float)samples_per_sec / (float)correct_baud ); +#endif } else { @@ -393,26 +410,40 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe } } -#ifdef TUNE_PRE_BAUD - D->u.psk.prefilter_baud = TUNE_PRE_BAUD; -#endif -#ifdef TUNE_PRE_WINDOW - D->u.psk.pre_window = TUNE_PRE_WINDOW; -#endif +//#ifdef TUNE_PRE_BAUD +// D->u.psk.prefilter_baud = TUNE_PRE_BAUD; +//#endif + TUNE("TUNE_PRE_BAUD", D->u.psk.prefilter_baud, "prefilter_baud", "%.3f") -#ifdef TUNE_LPF_BAUD - D->u.psk.lpf_baud = TUNE_LPF_BAUD; -#endif -#ifdef TUNE_LP_WINDOW - D->u.psk.lp_window = TUNE_LP_WINDOW; -#endif +//#ifdef TUNE_PRE_WINDOW +// D->u.psk.pre_window = TUNE_PRE_WINDOW; +//#endif + TUNE("TUNE_PRE_WINDOW", D->u.psk.pre_window, "pre_window", "%d") -#if defined(TUNE_PLL_SEARCHING) - D->pll_searching_inertia = TUNE_PLL_SEARCHING; -#endif -#if defined(TUNE_PLL_LOCKED) - D->pll_locked_inertia = TUNE_PLL_LOCKED; -#endif +//#ifdef TUNE_LPF_BAUD +// D->u.psk.lpf_baud = TUNE_LPF_BAUD; +//#endif +//#ifdef TUNE_LP_WINDOW +// D->u.psk.lp_window = TUNE_LP_WINDOW; +//#endif + TUNE("TUNE_LPF_BAUD", D->u.psk.lpf_baud, "lpf_baud", "%.3f") + TUNE("TUNE_LP_WINDOW", D->u.psk.lp_window, "lp_window", "%d") + + + TUNE("TUNE_LP_FILTER_WIDTH_SYM", D->u.psk.lp_filter_width_sym, "lp_filter_width_sym", "%.3f") + + + + + +//#if defined(TUNE_PLL_SEARCHING) +// D->pll_searching_inertia = TUNE_PLL_SEARCHING; +//#endif +//#if defined(TUNE_PLL_LOCKED) +// D->pll_locked_inertia = TUNE_PLL_LOCKED; +//#endif + TUNE("TUNE_PLL_LOCKED", D->pll_locked_inertia, "pll_locked_inertia", "%.2f") + TUNE("TUNE_PLL_SEARCHING", D->pll_searching_inertia, "pll_searching_inertia", "%.2f") /* @@ -427,17 +458,24 @@ void demod_psk_init (enum modem_t modem_type, enum v26_e v26_alt, int samples_pe */ D->u.psk.pre_filter_taps = (int) round( D->u.psk.pre_filter_width_sym * (float)samples_per_sec / (float)correct_baud ); + +// JWL experiment 11/7 - Should delay line be based on audio frequency? D->u.psk.delay_line_taps = (int) round( D->u.psk.delay_line_width_sym * (float)samples_per_sec / (float)correct_baud ); + D->u.psk.delay_line_taps = (int) round( D->u.psk.delay_line_width_sym * (float)samples_per_sec / (float)correct_baud ); + + D->u.psk.lp_filter_taps = (int) round( D->u.psk.lp_filter_width_sym * (float)samples_per_sec / (float)correct_baud ); -#ifdef TUNE_PRE_FILTER_TAPS - D->u.psk.pre_filter_taps = TUNE_PRE_FILTER_TAPS; -#endif +//#ifdef TUNE_PRE_FILTER_TAPS +// D->u.psk.pre_filter_taps = TUNE_PRE_FILTER_TAPS; +//#endif + TUNE("TUNE_PRE_FILTER_TAPS", D->u.psk.pre_filter_taps, "pre_filter_taps", "%d") -#ifdef TUNE_lp_filter_taps - D->u.psk.lp_filter_taps = TUNE_lp_filter_taps; -#endif +//#ifdef TUNE_lp_filter_taps +// D->u.psk.lp_filter_taps = TUNE_lp_filter_taps; +//#endif + TUNE("TUNE_LP_FILTER_TAPS", D->u.psk.lp_filter_taps, "lp_filter_taps (FIR)", "%d") if (D->u.psk.pre_filter_taps > MAX_FILTER_SIZE) { @@ -665,7 +703,7 @@ void demod_psk_process_sample (int chan, int subchan, int sam, struct demodulato { int slice = 0; // Would it make sense to have more than one? - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); /* Scale to nice number for plotting during debug. */ @@ -800,16 +838,22 @@ static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct int gray = demod_bits; - hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1]); - hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, bit_quality[0]); + hdlc_rec_bit_new (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1], + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); + hdlc_rec_bit_new (chan, subchan, slice, gray & 1, 0, bit_quality[0], + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); } else { int gray = demod_bits; - hdlc_rec_bit (chan, subchan, slice, (gray >> 2) & 1, 0, bit_quality[2]); - hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1]); - hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, bit_quality[0]); + hdlc_rec_bit_new (chan, subchan, slice, (gray >> 2) & 1, 0, bit_quality[2], + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); + hdlc_rec_bit_new (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1], + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); + hdlc_rec_bit_new (chan, subchan, slice, gray & 1, 0, bit_quality[0], + &(D->slicer[slice].pll_nudge_total), &(D->slicer[slice].pll_symbol_count)); } + D->slicer[slice].pll_symbol_count++; pll_dcd_each_symbol2 (D, chan, subchan, slice); } @@ -826,12 +870,14 @@ static void nudge_pll (int chan, int subchan, int slice, int demod_bits, struct pll_dcd_signal_transition2 (D, slice, D->slicer[slice].data_clock_pll); + signed int before = (signed int)(D->slicer[slice].data_clock_pll); // Treat as signed. if (D->slicer[slice].data_detect) { D->slicer[slice].data_clock_pll = (int)floorf((float)(D->slicer[slice].data_clock_pll) * D->pll_locked_inertia); } else { D->slicer[slice].data_clock_pll = (int)floorf((float)(D->slicer[slice].data_clock_pll) * D->pll_searching_inertia); } + D->slicer[slice].pll_nudge_total += (int64_t)((signed int)(D->slicer[slice].data_clock_pll)) - (int64_t)before; } /* diff --git a/src/digipeater.c b/src/digipeater.c index fbe8937..fcf5956 100644 --- a/src/digipeater.c +++ b/src/digipeater.c @@ -91,7 +91,7 @@ static struct digi_config_s *save_digi_config_p; * Maintain count of packets digipeated for each combination of from/to channel. */ -static int digi_count[MAX_CHANS][MAX_CHANS]; +static int digi_count[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; int digipeater_get_count (int from_chan, int to_chan) { return (digi_count[from_chan][to_chan]); @@ -154,7 +154,7 @@ void digipeater (int from_chan, packet_t pp) // Network TNC is OK for UI frames where we don't care about timing. - if ( from_chan < 0 || from_chan >= MAX_CHANS || + if ( from_chan < 0 || from_chan >= MAX_TOTAL_CHANS || (save_audio_config_p->chan_medium[from_chan] != MEDIUM_RADIO && save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC)) { text_color_set(DW_COLOR_ERROR); @@ -195,14 +195,14 @@ void digipeater (int from_chan, packet_t pp) * */ - for (to_chan=0; to_chanenabled[from_chan][to_chan]) { if (to_chan == from_chan) { packet_t result; - result = digipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, - save_audio_config_p->achan[to_chan].mycall, - &save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan], + result = digipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan], + save_audio_config_p->mycall[to_chan], + &save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan], to_chan, save_digi_config_p->preempt[from_chan][to_chan], save_digi_config_p->atgp[from_chan][to_chan], save_digi_config_p->filter_str[from_chan][to_chan]); @@ -222,14 +222,14 @@ void digipeater (int from_chan, packet_t pp) * These are lower priority */ - for (to_chan=0; to_chanenabled[from_chan][to_chan]) { if (to_chan != from_chan) { packet_t result; - result = digipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, - save_audio_config_p->achan[to_chan].mycall, - &save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan], + result = digipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan], + save_audio_config_p->mycall[to_chan], + &save_digi_config_p->alias[from_chan][to_chan], &save_digi_config_p->wide[from_chan][to_chan], to_chan, save_digi_config_p->preempt[from_chan][to_chan], save_digi_config_p->atgp[from_chan][to_chan], save_digi_config_p->filter_str[from_chan][to_chan]); @@ -641,9 +641,9 @@ void digi_regen (int from_chan, packet_t pp) // dw_printf ("digi_regen()\n"); - assert (from_chan >= 0 && from_chan < MAX_CHANS); + assert (from_chan >= 0 && from_chan < MAX_TOTAL_CHANS); - for (to_chan=0; to_chanregen[from_chan][to_chan]) { result = ax25_dup (pp); if (result != NULL) { diff --git a/src/digipeater.h b/src/digipeater.h index 5c84976..46d955d 100644 --- a/src/digipeater.h +++ b/src/digipeater.h @@ -4,7 +4,7 @@ #include "regex.h" -#include "direwolf.h" /* for MAX_CHANS */ +#include "direwolf.h" /* for MAX_TOTAL_CHANS */ #include "ax25_pad.h" /* for packet_t */ #include "audio.h" /* for radio channel properties */ @@ -29,25 +29,25 @@ struct digi_config_s { * Rules for each of the [from_chan][to_chan] combinations. */ - regex_t alias[MAX_CHANS][MAX_CHANS]; + regex_t alias[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; - regex_t wide[MAX_CHANS][MAX_CHANS]; + regex_t wide[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; - int enabled[MAX_CHANS][MAX_CHANS]; + int enabled[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; - enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS]; + enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; // ATGP is an ugly hack for the specific need of ATGP which needs more that 8 digipeaters. // DO NOT put this in the User Guide. On a need to know basis. - char atgp[MAX_CHANS][MAX_CHANS][AX25_MAX_ADDR_LEN]; + char atgp[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS][AX25_MAX_ADDR_LEN]; - char *filter_str[MAX_CHANS+1][MAX_CHANS+1]; + char *filter_str[MAX_TOTAL_CHANS+1][MAX_TOTAL_CHANS+1]; // NULL or optional Packet Filter strings such as "t/m". // Notice the size of arrays is one larger than normal. // That extra position is for the IGate. - int regen[MAX_CHANS][MAX_CHANS]; // Regenerate packet. + int regen[MAX_TOTAL_CHANS][MAX_TOTAL_CHANS]; // Regenerate packet. // Sort of like digipeating but passed along unchanged. }; diff --git a/src/direwolf.c b/src/direwolf.c index 2dfa58d..2bffcc2 100644 --- a/src/direwolf.c +++ b/src/direwolf.c @@ -1,7 +1,7 @@ // // This file is part of Dire Wolf, an amateur radio packet TNC. // -// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2023 John Langner, WB2OSZ +// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2023, 2024 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 @@ -130,6 +130,7 @@ #include "dns_sd_dw.h" #include "dlq.h" // for fec_type_t definition. #include "deviceid.h" +#include "nettnc.h" //static int idx_decoded = 0; @@ -228,6 +229,7 @@ int main (int argc, char *argv[]) #endif int d_x_opt = 1; /* "-d x" option for FX.25. Default minimal. Repeat for more detail. -qx to silence. */ int d_2_opt = 0; /* "-d 2" option for IL2P. Default minimal. Repeat for more detail. */ + int d_c_opt = 0; /* "-d c" option for connected mode data link state machine. */ int aprstt_debug = 0; /* "-d d" option for APRStt (think Dtmf) debug. */ @@ -303,7 +305,7 @@ int main (int argc, char *argv[]) text_color_init(t_opt); text_color_set(DW_COLOR_INFO); //dw_printf ("Dire Wolf version %d.%d (%s) BETA TEST 7\n", MAJOR_VERSION, MINOR_VERSION, __DATE__); - dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "A", __DATE__); + dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "D", __DATE__); //dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION); @@ -390,6 +392,7 @@ int main (int argc, char *argv[]) text_color_set(DW_COLOR_ERROR); for (int n=0; n<15; n++) { dw_printf ("\n"); + dw_printf ("Why are you running this as root user?.\n"); dw_printf ("Dire Wolf requires only privileges available to ordinary users.\n"); dw_printf ("Running this as root is an unnecessary security risk.\n"); //SLEEP_SEC(1); @@ -558,7 +561,7 @@ int main (int argc, char *argv[]) break; } } - if (x_opt_chan < 0 || x_opt_chan >= MAX_CHANS) { + if (x_opt_chan < 0 || x_opt_chan >= MAX_RADIO_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("Invalid channel %d for -x. \n", x_opt_chan); text_color_set(DW_COLOR_INFO); @@ -637,6 +640,7 @@ int main (int argc, char *argv[]) #if USE_HAMLIB case 'h': d_h_opt++; break; // Hamlib verbose level. #endif + case 'c': d_c_opt++; break; // Connected mode data link state machine case 'x': d_x_opt++; break; // FX.25 case '2': d_2_opt++; break; // IL2P case 'd': aprstt_debug++; break; // APRStt (mnemonic Dtmf) @@ -1004,6 +1008,13 @@ int main (int argc, char *argv[]) fx25_init (d_x_opt); il2p_init (d_2_opt); +/* + * New in 1.8 - Allow a channel to be mapped to a network TNC rather than + * an internal modem and radio. + * I put it here so channel properties would come out in right order. + */ + nettnc_init (&audio_config); + /* * Initialize the touch tone decoder & APRStt gateway. */ @@ -1108,7 +1119,7 @@ int main (int argc, char *argv[]) igate_init (&audio_config, &igate_config, &digi_config, d_i_opt); cdigipeater_init (&audio_config, &cdigi_config); pfilter_init (&igate_config, d_f_opt); - ax25_link_init (&misc_config); + ax25_link_init (&misc_config, d_c_opt); /* * Provide the AGW & KISS socket interfaces for use by a client application. @@ -1167,7 +1178,10 @@ int main (int argc, char *argv[]) * * Inputs: chan - Audio channel number, 0 or 1. * subchan - Which modem caught it. - * Special case -1 for DTMF decoder. + * Special cases: + * -1 for DTMF decoder. + * -2 for channel mapped to APRS-IS. + * -3 for channel mapped to network TNC. * slice - Slicer which caught it. * pp - Packet handle. * alevel - Audio level, range of 0 - 100. @@ -1198,7 +1212,7 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev // Can indicate FX.25/IL2P or fix_bits. assert (chan >= 0 && chan < MAX_TOTAL_CHANS); // TOTAL for virtual channels - assert (subchan >= -2 && subchan < MAX_SUBCHANS); + assert (subchan >= -3 && subchan < MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SLICERS); assert (pp != NULL); // 1.1J+ @@ -1279,7 +1293,13 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev ax25_get_addr_with_ssid(pp, h-1, probably_really); - dw_printf ("%s (probably %s) audio level = %s %s %s\n", heard, probably_really, alevel_text, display_retries, spectrum); + // audio level applies only for internal modem channels. + if (subchan >=0) { + dw_printf ("%s (probably %s) audio level = %s %s %s\n", heard, probably_really, alevel_text, display_retries, spectrum); + } + else { + dw_printf ("%s (probably %s)\n", heard, probably_really); + } } else if (strcmp(heard, "DTMF") == 0) { @@ -1288,7 +1308,13 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev } else { - dw_printf ("%s audio level = %s %s %s\n", heard, alevel_text, display_retries, spectrum); + // audio level applies only for internal modem channels. + if (subchan >= 0) { + dw_printf ("%s audio level = %s %s %s\n", heard, alevel_text, display_retries, spectrum); + } + else { + dw_printf ("%s\n", heard); + } } } } @@ -1305,7 +1331,7 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev dw_printf ("Audio input level is too high. Reduce so most stations are around 50.\n"); } // FIXME: rather than checking for ichannel, how about checking medium==radio - else if (alevel.rec < 5 && chan != audio_config.igate_vchannel) { + else if (alevel.rec < 5 && chan != audio_config.igate_vchannel && subchan != -3) { text_color_set(DW_COLOR_ERROR); dw_printf ("Audio input level is too low. Increase so most stations are around 50.\n"); @@ -1330,14 +1356,18 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev strlcpy (ts, "", sizeof(ts)); } - if (subchan == -1) { + if (subchan == -1) { // dtmf text_color_set(DW_COLOR_REC); dw_printf ("[%d.dtmf%s] ", chan, ts); } - else if (subchan == -2) { + else if (subchan == -2) { // APRS-IS text_color_set(DW_COLOR_REC); dw_printf ("[%d.is%s] ", chan, ts); } + else if (subchan == -3) { // nettnc + text_color_set(DW_COLOR_REC); + dw_printf ("[%d%s] ", chan, ts); + } else { if (ax25_is_aprs(pp)) { text_color_set(DW_COLOR_REC); @@ -1498,7 +1528,7 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev 0, 0, 0, A.g_comment, // freq, tone, offset ais_obj_info, sizeof(ais_obj_info)); - snprintf (ais_obj_packet, sizeof(ais_obj_packet), "%s>%s%1d%1d:%s", A.g_src, APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, ais_obj_info); + snprintf (ais_obj_packet, sizeof(ais_obj_packet), "%s>%s%1d%1d,NOGATE:%s", A.g_src, APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, ais_obj_info); dw_printf ("[%d.AIS] %s\n", chan, ais_obj_packet); @@ -1614,9 +1644,10 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev * Use only those with correct CRC (or using FEC.) */ - if (retries == RETRY_NONE || fec_type == fec_type_fx25 || fec_type == fec_type_il2p) { - - cdigipeater (chan, pp); + if (chan < MAX_RADIO_CHANS) { + if (retries == RETRY_NONE || fec_type == fec_type_fx25 || fec_type == fec_type_il2p) { + cdigipeater (chan, pp); + } } } @@ -1708,6 +1739,7 @@ static void usage (char **argv) #if USE_HAMLIB dw_printf (" h h = hamlib increase verbose level.\n"); #endif + dw_printf (" c c = Connected mode data link state machine.\n"); dw_printf (" x x = FX.25 increase verbose level.\n"); dw_printf (" 2 2 = IL2P.\n"); dw_printf (" d d = APRStt (DTMF to APRS object translation).\n"); diff --git a/src/direwolf.h b/src/direwolf.h index 69b0952..a6db322 100644 --- a/src/direwolf.h +++ b/src/direwolf.h @@ -56,15 +56,10 @@ * * ADevice 0: channel 0 * ADevice 1: left = 2, right = 3 - * - * TODO1.2: Look for any places that have - * for (ch=0; ch= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ @@ -556,7 +556,7 @@ void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int dw_printf ("dlq_disconnect_request (...)\n"); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ @@ -619,7 +619,7 @@ void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LE dw_printf ("dlq_outstanding_frames_request (...)\n"); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ @@ -691,7 +691,7 @@ void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int n dw_printf ("dlq_xmit_data_request (...)\n"); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ @@ -758,7 +758,7 @@ void dlq_register_callsign (char *addr, int chan, int client) dw_printf ("dlq_register_callsign (%s, chan=%d, client=%d)\n", addr, chan, client); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ @@ -793,7 +793,7 @@ void dlq_unregister_callsign (char *addr, int chan, int client) dw_printf ("dlq_unregister_callsign (%s, chan=%d, client=%d)\n", addr, chan, client); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); /* Allocate a new queue item. */ diff --git a/src/dtmf.c b/src/dtmf.c index 953b0f7..447366f 100644 --- a/src/dtmf.c +++ b/src/dtmf.c @@ -80,7 +80,7 @@ static struct dd_s { /* Separate for each audio channel. */ char prev_debounced; int timeout; -} dd[MAX_CHANS]; +} dd[MAX_RADIO_CHANS]; static int s_amplitude = 100; // range of 0 .. 100 @@ -129,7 +129,7 @@ void dtmf_init (struct audio_s *p_audio_config, int amp) * Larger = narrower bandwidth, slower response. */ - for (c=0; cn = 0; for (j=0; j= MAX_RADIO_CHANS) { + return ('$'); + } + D = &(dd[c]); for (i=0; i 999999) alt_ft = 999999; - snprintf (salt, sizeof(salt), "/A=%06d", alt_ft); + snprintf (salt, sizeof(salt), "/A=%06d", alt_ft); // /A=123456 ot /A=-12345 strlcat (presult, salt, result_size); result_len += strlen(salt); } diff --git a/src/fsk_demod_state.h b/src/fsk_demod_state.h index c9b26c2..e094bb4 100644 --- a/src/fsk_demod_state.h +++ b/src/fsk_demod_state.h @@ -469,7 +469,7 @@ struct demodulator_state_s * * Inputs: D Pointer to demodulator state. * - * chan Radio channel: 0 to MAX_CHANS - 1 + * chan Radio channel: 0 to MAX_RADIO_CHANS - 1 * * subchan Which of multiple demodulators: 0 to MAX_SUBCHANS - 1 * diff --git a/src/fx25_rec.c b/src/fx25_rec.c index 9cb5c4d..8e6d422 100644 --- a/src/fx25_rec.c +++ b/src/fx25_rec.c @@ -59,7 +59,7 @@ struct fx_context_s { unsigned char block[FX25_BLOCK_SIZE+1]; }; -static struct fx_context_s *fx_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; +static struct fx_context_s *fx_context[MAX_RADIO_CHANS][MAX_SUBCHANS][MAX_SLICERS]; static void process_rs_block (int chan, int subchan, int slice, struct fx_context_s *F); @@ -157,7 +157,7 @@ void fx25_rec_bit (int chan, int subchan, int slice, int dbit) struct fx_context_s *F = fx_context[chan][subchan][slice]; if (F == NULL) { - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SLICERS); F = fx_context[chan][subchan][slice] = (struct fx_context_s *)malloc(sizeof (struct fx_context_s)); @@ -256,7 +256,7 @@ void fx25_rec_bit (int chan, int subchan, int slice, int dbit) int fx25_rec_busy (int chan) { - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); // This could be a little faster if we knew number of // subchannels and slicers but it is probably insignificant. diff --git a/src/fx25_send.c b/src/fx25_send.c index 7435be9..0841a3f 100644 --- a/src/fx25_send.c +++ b/src/fx25_send.c @@ -41,7 +41,7 @@ static void send_bit (int chan, int b); static int stuff_it (unsigned char *in, int ilen, unsigned char *out, int osize); -static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "fx25_send_frame" or "???" +static int number_of_bits_sent[MAX_RADIO_CHANS]; // Count number of bits sent by "fx25_send_frame" or "???" #if FXTEST @@ -249,7 +249,7 @@ static void send_bytes (int chan, unsigned char *b, int count) */ static void send_bit (int chan, int b) { - static int output[MAX_CHANS]; + static int output[MAX_RADIO_CHANS]; if (b == 0) { output[chan] = ! output[chan]; diff --git a/src/gen_packets.c b/src/gen_packets.c index 57b2741..e98e774 100644 --- a/src/gen_packets.c +++ b/src/gen_packets.c @@ -242,7 +242,7 @@ int main(int argc, char **argv) modem.adev[0].samples_per_sec = DEFAULT_SAMPLES_PER_SEC; /* -r option */ modem.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; /* -8 for 8 instead of 16 bits */ - for (chan = 0; chan < MAX_CHANS; chan++) { + for (chan = 0; chan < MAX_RADIO_CHANS; chan++) { modem.achan[chan].modem_type = MODEM_AFSK; /* change with -g */ modem.achan[chan].mark_freq = DEFAULT_MARK_FREQ; /* -m option */ modem.achan[chan].space_freq = DEFAULT_SPACE_FREQ; /* -s option */ diff --git a/src/gen_tone.c b/src/gen_tone.c index 6a81655..400c292 100644 --- a/src/gen_tone.c +++ b/src/gen_tone.c @@ -63,14 +63,14 @@ static struct audio_s *save_audio_config_p = NULL; #define TICKS_PER_CYCLE ( 256.0 * 256.0 * 256.0 * 256.0 ) -static int ticks_per_sample[MAX_CHANS]; /* Same for both channels of same soundcard */ +static int ticks_per_sample[MAX_RADIO_CHANS]; /* Same for both channels of same soundcard */ /* because they have same sample rate */ /* but less confusing to have for each channel. */ -static int ticks_per_bit[MAX_CHANS]; -static int f1_change_per_sample[MAX_CHANS]; -static int f2_change_per_sample[MAX_CHANS]; -static float samples_per_symbol[MAX_CHANS]; +static int ticks_per_bit[MAX_RADIO_CHANS]; +static int f1_change_per_sample[MAX_RADIO_CHANS]; +static int f2_change_per_sample[MAX_RADIO_CHANS]; +static float samples_per_symbol[MAX_RADIO_CHANS]; static short sine_table[256]; @@ -78,7 +78,7 @@ static short sine_table[256]; /* Accumulators. */ -static unsigned int tone_phase[MAX_CHANS]; // Phase accumulator for tone generation. +static unsigned int tone_phase[MAX_RADIO_CHANS]; // Phase accumulator for tone generation. // Upper bits are used as index into sine table. #define PHASE_SHIFT_180 ( 128u << 24 ) @@ -86,11 +86,11 @@ static unsigned int tone_phase[MAX_CHANS]; // Phase accumulator for tone generat #define PHASE_SHIFT_45 ( 32u << 24 ) -static int bit_len_acc[MAX_CHANS]; // To accumulate fractional samples per bit. +static int bit_len_acc[MAX_RADIO_CHANS]; // To accumulate fractional samples per bit. -static int lfsr[MAX_CHANS]; // Shift register for scrambler. +static int lfsr[MAX_RADIO_CHANS]; // Shift register for scrambler. -static int bit_count[MAX_CHANS]; // Counter incremented for each bit transmitted +static int bit_count[MAX_RADIO_CHANS]; // Counter incremented for each bit transmitted // on the channel. This is only used for QPSK. // The LSB determines if we save the bit until // next time, or send this one with the previously saved. @@ -101,10 +101,10 @@ static int bit_count[MAX_CHANS]; // Counter incremented for each bit transmitted // For 8PSK, it has a different meaning. It is the // number of bits in 'save_bit' so we can accumulate // three for each symbol. -static int save_bit[MAX_CHANS]; +static int save_bit[MAX_RADIO_CHANS]; -static int prev_dat[MAX_CHANS]; // Previous data bit. Used for G3RUH style. +static int prev_dat[MAX_RADIO_CHANS]; // Previous data bit. Used for G3RUH style. @@ -163,7 +163,7 @@ int gen_tone_init (struct audio_s *audio_config_p, int amp, int gen_packets) amp16bit = (int)((32767 * amp) / 100); - for (chan = 0; chan < MAX_CHANS; chan++) { + for (chan = 0; chan < MAX_RADIO_CHANS; chan++) { if (audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { @@ -352,8 +352,8 @@ static const int gray2phase_v27[8] = {1, 0, 2, 3, 6, 7, 5, 4}; // #define PSKIQ 1 // not ready for prime time yet. #if PSKIQ -static int xmit_octant[MAX_CHANS]; // absolute phase in 45 degree units. -static int xmit_prev_octant[MAX_CHANS]; // from previous symbol. +static int xmit_octant[MAX_RADIO_CHANS]; // absolute phase in 45 degree units. +static int xmit_prev_octant[MAX_RADIO_CHANS]; // from previous symbol. // For PSK, we generate the final signal by combining fixed frequency cosine and // sine by the following weights. diff --git a/src/hdlc_rec.c b/src/hdlc_rec.c index d87a1b5..cfae77a 100644 --- a/src/hdlc_rec.c +++ b/src/hdlc_rec.c @@ -114,11 +114,11 @@ struct hdlc_state_s { int eas_fields_after_plus; /* Number of "-" characters after the "+". */ }; -static struct hdlc_state_s hdlc_state[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; +static struct hdlc_state_s hdlc_state[MAX_RADIO_CHANS][MAX_SUBCHANS][MAX_SLICERS]; -static int num_subchan[MAX_CHANS]; //TODO1.2 use ptr rather than copy. +static int num_subchan[MAX_RADIO_CHANS]; //TODO1.2 use ptr rather than copy. -static int composite_dcd[MAX_CHANS][MAX_SUBCHANS+1]; +static int composite_dcd[MAX_RADIO_CHANS][MAX_SUBCHANS+1]; /*********************************************************************************** @@ -149,7 +149,7 @@ void hdlc_rec_init (struct audio_s *pa) memset (composite_dcd, 0, sizeof(composite_dcd)); - for (ch = 0; ch < MAX_CHANS; ch++) + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (pa->chan_medium[ch] == MEDIUM_RADIO) { @@ -429,17 +429,24 @@ a good modem here and providing a result when it is received. ***********************************************************************************/ void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled, int not_used_remove) +{ + static int64_t dummyll = 0; + static int dummy = 0; + hdlc_rec_bit_new (chan, subchan, slice, raw, is_scrambled, not_used_remove, + &dummyll, &dummy); +} + +void hdlc_rec_bit_new (int chan, int subchan, int slice, int raw, int is_scrambled, int not_used_remove, + int64_t *pll_nudge_total, int *pll_symbol_count) { int dbit; /* Data bit after undoing NRZI. */ /* Should be only 0 or 1. */ - struct hdlc_state_s *H; assert (was_init == 1); - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); - assert (slice >= 0 && slice < MAX_SLICERS); // -e option can be used to artificially introduce the desired @@ -467,7 +474,7 @@ void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled, /* * Different state information for each channel / subchannel / slice. */ - H = &hdlc_state[chan][subchan][slice]; + struct hdlc_state_s *H = &hdlc_state[chan][subchan][slice]; /* @@ -589,16 +596,44 @@ void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled, dw_printf ("\nfound flag, channel %d.%d, %d bits in frame\n", chan, subchan, rrbb_get_len(H->rrbb) - 1); #endif if (rrbb_get_len(H->rrbb) >= MIN_FRAME_LEN * 8) { - + +//JWL - end of frame + + float speed_error; // in percentage. + if (*pll_symbol_count > 0) { // avoid divde by 0. + + // TODO: + // Fudged to get +-2.0 with gen_packets -b 1224 & 1176. + // Also initialized the symbol counter to -1. + + speed_error = (float)((double)(*pll_nudge_total) * 100. / (256. * 256. * 256. * 256.) / (double)(*pll_symbol_count) + 0.02); + + text_color_set(DW_COLOR_DEBUG); + +// std dw_printf ("DEBUG: total %lld, count %d\n", *pll_nudge_total, *pll_symbol_count); +// mingw +// dw_printf ("DEBUG: total %I64d, count %d\n", *pll_nudge_total, *pll_symbol_count); +// dw_printf ("DEBUG: speed error %+0.2f%% -> %+0.1f%% \n", speed_error, speed_error); + } + else { + speed_error = 0; + } + rrbb_set_speed_error (H->rrbb, speed_error); + alevel_t alevel = demod_get_audio_level (chan, subchan); rrbb_set_audio_level (H->rrbb, alevel); hdlc_rec2_block (H->rrbb); /* Now owned by someone else who will free it. */ + H->rrbb = NULL; H->rrbb = rrbb_new (chan, subchan, slice, is_scrambled, H->lfsr, H->prev_descram); /* Allocate a new one. */ } else { + +//JWL - start of frame + *pll_nudge_total = 0; + *pll_symbol_count = -1; // comes out better than using 0. rrbb_clear (H->rrbb, is_scrambled, H->lfsr, H->prev_descram); } @@ -730,7 +765,7 @@ void dcd_change (int chan, int subchan, int slice, int state) { int old, new; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan <= MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SLICERS); assert (state == 0 || state == 1); @@ -791,7 +826,7 @@ int hdlc_rec_data_detect_any (int chan) { int sc; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); for (sc = 0; sc < num_subchan[chan]; sc++) { if (composite_dcd[chan][sc] != 0) diff --git a/src/hdlc_rec.h b/src/hdlc_rec.h index 69b60a9..21cbf6c 100644 --- a/src/hdlc_rec.h +++ b/src/hdlc_rec.h @@ -1,12 +1,22 @@ +/* hdlc_rec.h */ + + + + +#include // int64_t #include "audio.h" void hdlc_rec_init (struct audio_s *pa); +// TODO: change all to _new. void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled, int descram_state); +void hdlc_rec_bit_new (int chan, int subchan, int slice, int raw, int is_scrambled, int descram_state, + int64_t *pll_nudge_total, int *pll_nudge_count); + /* Provided elsewhere to process a complete frame. */ //void process_rec_frame (int chan, unsigned char *fbuf, int flen, int level); diff --git a/src/hdlc_rec2.c b/src/hdlc_rec2.c index b817018..ebaac6c 100644 --- a/src/hdlc_rec2.c +++ b/src/hdlc_rec2.c @@ -216,6 +216,8 @@ void hdlc_rec2_init (struct audio_s *p_audio_config) * Purpose: Extract HDLC frame from a stream of bits. * * Inputs: block - Handle for bit array. + * This will be deallocated so the caller + * must not hold on to the address. * * Description: The other (original) hdlc decoder took one bit at a time * right out of the demodulator. @@ -287,12 +289,10 @@ void hdlc_rec2_block (rrbb_t block) /* Let thru even with bad CRC. Of course, it still */ /* needs to be a minimum number of whole octets. */ ok = try_decode (block, chan, subchan, slice, alevel, retry_cfg, 1); - rrbb_delete (block); - } - else { - rrbb_delete (block); } + rrbb_delete (block); + } /* end hdlc_rec2_block */ @@ -438,7 +438,7 @@ static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int slice, retry_cfg.u_bits.sep.bit_idx_c = -1; #ifdef DEBUG_LATER - tstart = dtime_now(); + tstart = dtime_monotonic(); dw_printf ("*** Try flipping TWO SEPARATED BITS %d bits\n", len); #endif len = rrbb_get_len(block); diff --git a/src/hdlc_send.c b/src/hdlc_send.c index 8a1cdc6..5b2008d 100644 --- a/src/hdlc_send.c +++ b/src/hdlc_send.c @@ -39,7 +39,7 @@ static void send_bit_nrzi (int, int); -static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "hdlc_send_frame" or "hdlc_send_flags" +static int number_of_bits_sent[MAX_RADIO_CHANS]; // Count number of bits sent by "hdlc_send_frame" or "hdlc_send_flags" @@ -240,7 +240,7 @@ static void send_byte_msb_first (int chan, int x, int polarity) // Data (non flags) use bit stuffing. -static int stuff[MAX_CHANS]; // Count number of "1" bits to keep track of when we +static int stuff[MAX_RADIO_CHANS]; // Count number of "1" bits to keep track of when we // need to break up a long run by "bit stuffing." // Needs to be array because we could be transmitting // on multiple channels at the same time. @@ -284,7 +284,7 @@ static void send_data_nrzi (int chan, int x) static void send_bit_nrzi (int chan, int b) { - static int output[MAX_CHANS]; + static int output[MAX_RADIO_CHANS]; if (b == 0) { output[chan] = ! output[chan]; diff --git a/src/igate.c b/src/igate.c index 7f84228..1e5d56e 100644 --- a/src/igate.c +++ b/src/igate.c @@ -216,8 +216,8 @@ int main (int argc, char *argv[]) memset (&audio_config, 0, sizeof(audio_config)); audio_config.adev[0].num_channels = 2; - strlcpy (audio_config.achan[0].mycall, "WB2OSZ-1", sizeof(audio_config.achan[0].mycall)); - strlcpy (audio_config.achan[1].mycall, "WB2OSZ-2", sizeof(audio_config.achan[0].mycall)); + strlcpy (audio_config.mycall[0], "WB2OSZ-1", sizeof(audio_config.achan[0].mycall)); + strlcpy (audio_config.mycall[1], "WB2OSZ-2", sizeof(audio_config.achan[0].mycall)); memset (&igate_config, 0, sizeof(igate_config)); @@ -909,10 +909,10 @@ void igate_send_rec_packet (int chan, packet_t recv_pp) // Beacon will be channel -1. // Client app to ICHANNEL is outside of radio channel range. - if (chan >= 0 && chan < MAX_CHANS && // in radio channel range - save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) { + if (chan >= 0 && chan < MAX_TOTAL_CHANS && // in radio channel range + save_digi_config_p->filter_str[chan][MAX_TOTAL_CHANS] != NULL) { - if (pfilter(chan, MAX_CHANS, save_digi_config_p->filter_str[chan][MAX_CHANS], recv_pp, 1) != 1) { + if (pfilter(chan, MAX_TOTAL_CHANS, save_digi_config_p->filter_str[chan][MAX_TOTAL_CHANS], recv_pp, 1) != 1) { // Is this useful troubleshooting information or just distracting noise? // Originally this was always printed but there was a request to add a "quiet" option to suppress this. @@ -920,7 +920,7 @@ void igate_send_rec_packet (int chan, packet_t recv_pp) if (s_debug >= 1) { text_color_set(DW_COLOR_INFO); - dw_printf ("Packet from channel %d to IGate was rejected by filter: %s\n", chan, save_digi_config_p->filter_str[chan][MAX_CHANS]); + dw_printf ("Packet from channel %d to IGate was rejected by filter: %s\n", chan, save_digi_config_p->filter_str[chan][MAX_TOTAL_CHANS]); } return; } @@ -1141,7 +1141,7 @@ static void send_packet_to_server (packet_t pp, int chan) strlcat (msg, ",qAO,", sizeof(msg)); // new for version 1.4. } - strlcat (msg, save_audio_config_p->achan[chan].mycall, sizeof(msg)); + strlcat (msg, save_audio_config_p->mycall[chan], sizeof(msg)); strlcat (msg, ":", sizeof(msg)); @@ -1781,7 +1781,7 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan) { int n; - assert (to_chan >= 0 && to_chan < MAX_CHANS); + assert (to_chan >= 0 && to_chan < MAX_TOTAL_CHANS); /* * Try to parse it into a packet object; we need this for the packet filtering. @@ -1856,7 +1856,7 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan) * filtering by stations along the way or the q construct. */ - assert (to_chan >= 0 && to_chan < MAX_CHANS); + assert (to_chan >= 0 && to_chan < MAX_TOTAL_CHANS); /* @@ -1906,9 +1906,9 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan) if ( ! msp_special_case) { - if (save_digi_config_p->filter_str[MAX_CHANS][to_chan] != NULL) { + if (save_digi_config_p->filter_str[MAX_TOTAL_CHANS][to_chan] != NULL) { - if (pfilter(MAX_CHANS, to_chan, save_digi_config_p->filter_str[MAX_CHANS][to_chan], pp3, 1) != 1) { + if (pfilter(MAX_TOTAL_CHANS, to_chan, save_digi_config_p->filter_str[MAX_TOTAL_CHANS][to_chan], pp3, 1) != 1) { // Previously there was a debug message here about the packet being dropped by filtering. // This is now handled better by the "-df" command line option for filtering details. @@ -1965,7 +1965,7 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan) char dest[AX25_MAX_ADDR_LEN]; /* Destination field. */ ax25_get_addr_with_ssid (pp3, AX25_DESTINATION, dest); snprintf (payload, sizeof(payload), "%s>%s,TCPIP,%s*:%s", - src, dest, save_audio_config_p->achan[to_chan].mycall, pinfo); + src, dest, save_audio_config_p->mycall[to_chan], pinfo); #if DEBUGx @@ -1991,7 +1991,7 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan) if (ig_to_tx_allow (pp3, to_chan)) { char radio [2400]; snprintf (radio, sizeof(radio), "%s>%s%d%d%s:}%s", - save_audio_config_p->achan[to_chan].mycall, + save_audio_config_p->mycall[to_chan], APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, save_igate_config_p->tx_via, payload); diff --git a/src/il2p_rec.c b/src/il2p_rec.c index 5ad457a..a1e2726 100644 --- a/src/il2p_rec.c +++ b/src/il2p_rec.c @@ -69,7 +69,7 @@ struct il2p_context_s { int corrected; // Number of symbols corrected by RS FEC. }; -static struct il2p_context_s *il2p_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; +static struct il2p_context_s *il2p_context[MAX_RADIO_CHANS][MAX_SUBCHANS][MAX_SLICERS]; @@ -101,7 +101,7 @@ void il2p_rec_bit (int chan, int subchan, int slice, int dbit) struct il2p_context_s *F = il2p_context[chan][subchan][slice]; if (F == NULL) { - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SLICERS); F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof (struct il2p_context_s)); @@ -251,12 +251,11 @@ void il2p_rec_bit (int chan, int subchan, int slice, int dbit) if (pp != NULL) { alevel_t alevel = demod_get_audio_level (chan, subchan); retry_t retries = F->corrected; - int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. - // Currently this just means that a FEC mode was used. + fec_type_t fec_type = fec_type_il2p; // TODO: Could we put last 3 arguments in packet object rather than passing around separately? - multi_modem_process_rec_packet (chan, subchan, slice, pp, alevel, retries, is_fx25); + multi_modem_process_rec_packet (chan, subchan, slice, pp, alevel, retries, fec_type); } } // end block for local variables. diff --git a/src/il2p_send.c b/src/il2p_send.c index 3c4554e..2894876 100644 --- a/src/il2p_send.c +++ b/src/il2p_send.c @@ -30,7 +30,7 @@ #include "gen_tone.h" -static int number_of_bits_sent[MAX_CHANS]; // Count number of bits sent by "il2p_send_frame" +static int number_of_bits_sent[MAX_RADIO_CHANS]; // Count number of bits sent by "il2p_send_frame" static void send_bytes (int chan, unsigned char *b, int count, int polarity); static void send_bit (int chan, int b, int polarity); diff --git a/src/kiss_frame.c b/src/kiss_frame.c index aa581dd..65a0942 100644 --- a/src/kiss_frame.c +++ b/src/kiss_frame.c @@ -612,7 +612,7 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct /* Verify that the radio channel number is valid. */ /* Any sort of medium should be OK here. */ - if ((chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) + if ((chan < 0 || chan >= MAX_TOTAL_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) && save_audio_config_p->chan_medium[chan] != MEDIUM_IGATE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan); @@ -663,10 +663,11 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct } text_color_set(DW_COLOR_INFO); dw_printf ("KISS protocol set TXDELAY = %d (*10mS units = %d mS), chan %d\n", kiss_msg[1], kiss_msg[1] * 10, chan); - if (kiss_msg[1] < 4 || kiss_msg[1] > 100) { + if (kiss_msg[1] < 10 || kiss_msg[1] >= 100) { text_color_set(DW_COLOR_ERROR); dw_printf ("Are you sure you want such an extreme value for TXDELAY?\n"); - dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n"); + dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n"); + dw_printf ("section, to understand what this means.\n"); } xmit_set_txdelay (chan, kiss_msg[1]); break; @@ -683,7 +684,8 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct if (kiss_msg[1] < 5 || kiss_msg[1] > 250) { text_color_set(DW_COLOR_ERROR); dw_printf ("Are you sure you want such an extreme value for PERSIST?\n"); - dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n"); + dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n"); + dw_printf ("section, to understand what this means.\n"); } xmit_set_persist (chan, kiss_msg[1]); break; @@ -700,7 +702,8 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct if (kiss_msg[1] < 2 || kiss_msg[1] > 50) { text_color_set(DW_COLOR_ERROR); dw_printf ("Are you sure you want such an extreme value for SLOTTIME?\n"); - dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n"); + dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n"); + dw_printf ("section, to understand what this means.\n"); } xmit_set_slottime (chan, kiss_msg[1]); break; @@ -714,10 +717,11 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct } text_color_set(DW_COLOR_INFO); dw_printf ("KISS protocol set TXtail = %d (*10mS units = %d mS), chan %d\n", kiss_msg[1], kiss_msg[1] * 10, chan); - if (kiss_msg[1] < 2) { + if (kiss_msg[1] < 5) { text_color_set(DW_COLOR_ERROR); dw_printf ("Setting TXTAIL so low is asking for trouble. You probably don't want to do this.\n"); - dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n"); + dw_printf ("Read the Dire Wolf User Guide, \"Radio Channel - Transmit Timing\"\n"); + dw_printf ("section, to understand what this means.\n"); } xmit_set_txtail (chan, kiss_msg[1]); break; diff --git a/src/multi_modem.c b/src/multi_modem.c index d2382f1..7770a19 100644 --- a/src/multi_modem.c +++ b/src/multi_modem.c @@ -126,7 +126,7 @@ static struct { int age; unsigned int crc; int score; -} candidate[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS]; +} candidate[MAX_RADIO_CHANS][MAX_SUBCHANS][MAX_SLICERS]; @@ -135,7 +135,7 @@ static struct { #define PROCESS_AFTER_BITS 3 -static int process_age[MAX_CHANS]; +static int process_age[MAX_RADIO_CHANS]; static void pick_best_candidate (int chan); @@ -172,7 +172,7 @@ void multi_modem_init (struct audio_s *pa) demod_init (save_audio_config_p); hdlc_rec_init (save_audio_config_p); - for (chan=0; chanchan_medium[chan] == MEDIUM_RADIO) { if (save_audio_config_p->achan[chan].baud <= 0) { text_color_set(DW_COLOR_ERROR); @@ -222,7 +222,7 @@ void multi_modem_init (struct audio_s *pa) * *------------------------------------------------------------------------------*/ -static float dc_average[MAX_CHANS]; +static float dc_average[MAX_RADIO_CHANS]; int multi_modem_get_dc_average (int chan) { @@ -319,7 +319,7 @@ void multi_modem_process_rec_frame (int chan, int subchan, int slice, unsigned c packet_t pp; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SUBCHANS); @@ -329,8 +329,15 @@ void multi_modem_process_rec_frame (int chan, int subchan, int slice, unsigned c char nmea[256]; ais_to_nmea (fbuf, flen, nmea, sizeof(nmea)); + // The intention is for the AIS sentences to go only to attached applications. + // e.g. SARTrack knows how to parse the AIS sentences. + + // Put NOGATE in path so RF>IS IGates will block this. + // TODO: Use station callsign, rather than "AIS," so we know where it is coming from, + // if it happens to get onto RF somehow. + char monfmt[276]; - snprintf (monfmt, sizeof(monfmt), "AIS>%s%1d%1d:{%c%c%s", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, USER_DEF_USER_ID, USER_DEF_TYPE_AIS, nmea); + snprintf (monfmt, sizeof(monfmt), "AIS>%s%1d%1d,NOGATE:{%c%c%s", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, USER_DEF_USER_ID, USER_DEF_TYPE_AIS, nmea); pp = ax25_from_text (monfmt, 1); // alevel gets in there somehow making me question why it is passed thru here. @@ -338,7 +345,7 @@ void multi_modem_process_rec_frame (int chan, int subchan, int slice, unsigned c else if (save_audio_config_p->achan[chan].modem_type == MODEM_EAS) { char monfmt[300]; // EAS SAME message max length is 268 - snprintf (monfmt, sizeof(monfmt), "EAS>%s%1d%1d:{%c%c%s", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, USER_DEF_USER_ID, USER_DEF_TYPE_EAS, fbuf); + snprintf (monfmt, sizeof(monfmt), "EAS>%s%1d%1d,NOGATE:{%c%c%s", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION, USER_DEF_USER_ID, USER_DEF_TYPE_EAS, fbuf); pp = ax25_from_text (monfmt, 1); // alevel gets in there somehow making me question why it is passed thru here. diff --git a/src/pfilter.c b/src/pfilter.c index 35767a6..cc51519 100644 --- a/src/pfilter.c +++ b/src/pfilter.c @@ -99,7 +99,7 @@ typedef enum token_type_e { TOKEN_AND, TOKEN_OR, TOKEN_NOT, TOKEN_LPAREN, TOKEN_ typedef struct pfstate_s { - int from_chan; /* From and to channels. MAX_CHANS is used for IGate. */ + int from_chan; /* From and to channels. MAX_TOTAL_CHANS is used for IGate. */ int to_chan; /* Used only for debug and error messages. */ /* @@ -175,7 +175,7 @@ static char *bool2text (int val) * * Inputs: from_chan - Channel packet is coming from. * to_chan - Channel packet is going to. - * Both are 0 .. MAX_CHANS-1 or MAX_CHANS for IGate. + * Both are 0 .. MAX_TOTAL_CHANS-1 or MAX_TOTAL_CHANS for IGate. * For debug/error messages only. * * filter - String of filter specs and logical operators to combine them. @@ -201,8 +201,8 @@ int pfilter (int from_chan, int to_chan, char *filter, packet_t pp, int is_aprs) char *p; int result; - assert (from_chan >= 0 && from_chan <= MAX_CHANS); - assert (to_chan >= 0 && to_chan <= MAX_CHANS); + assert (from_chan >= 0 && from_chan <= MAX_TOTAL_CHANS); + assert (to_chan >= 0 && to_chan <= MAX_TOTAL_CHANS); memset (&pfstate, 0, sizeof(pfstate)); @@ -258,10 +258,10 @@ int pfilter (int from_chan, int to_chan, char *filter, packet_t pp, int is_aprs) if (s_debug >= 1) { text_color_set(DW_COLOR_DEBUG); - if (from_chan == MAX_CHANS) { + if (from_chan == MAX_TOTAL_CHANS) { dw_printf (" Packet filter from IGate to radio channel %d returns %s\n", to_chan, bool2text(result)); } - else if (to_chan == MAX_CHANS) { + else if (to_chan == MAX_TOTAL_CHANS) { dw_printf (" Packet filter from radio channel %d to IGate returns %s\n", from_chan, bool2text(result)); } else if (is_aprs) { @@ -1478,9 +1478,9 @@ static void print_error (pfstate_t *pf, char *msg) { char intro[50]; - if (pf->from_chan == MAX_CHANS) { + if (pf->from_chan == MAX_TOTAL_CHANS) { - if (pf->to_chan == MAX_CHANS) { + if (pf->to_chan == MAX_TOTAL_CHANS) { snprintf (intro, sizeof(intro), "filter[IG,IG]: "); } else { @@ -1489,7 +1489,7 @@ static void print_error (pfstate_t *pf, char *msg) } else { - if (pf->to_chan == MAX_CHANS) { + if (pf->to_chan == MAX_TOTAL_CHANS) { snprintf (intro, sizeof(intro), "filter[%d,IG]: ", pf->from_chan); } else { diff --git a/src/ptt.c b/src/ptt.c index af74662..ec09387 100644 --- a/src/ptt.c +++ b/src/ptt.c @@ -730,12 +730,12 @@ int gpiod_probe(const char *chip_name, int line_number) -static HANDLE ptt_fd[MAX_CHANS][NUM_OCTYPES]; +static HANDLE ptt_fd[MAX_RADIO_CHANS][NUM_OCTYPES]; /* Serial port handle or fd. */ /* Could be the same for two channels */ /* if using both RTS and DTR. */ #if USE_HAMLIB -static RIG *rig[MAX_CHANS][NUM_OCTYPES]; +static RIG *rig[MAX_RADIO_CHANS][NUM_OCTYPES]; #endif static char otnames[NUM_OCTYPES][8]; @@ -761,7 +761,7 @@ void ptt_init (struct audio_s *audio_config_p) strlcpy (otnames[OCTYPE_CON], "CON", sizeof(otnames[OCTYPE_CON])); - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -791,7 +791,7 @@ void ptt_init (struct audio_s *audio_config_p) * Set up serial ports. */ - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { int ot; @@ -906,7 +906,7 @@ void ptt_init (struct audio_s *audio_config_p) */ using_gpio = 0; - for (ch=0; chchan_medium[ch] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -927,7 +927,7 @@ void ptt_init (struct audio_s *audio_config_p) } #if defined(USE_GPIOD) // GPIOD - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { for (int ot = 0; ot < NUM_OCTYPES; ot++) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) { @@ -952,7 +952,7 @@ void ptt_init (struct audio_s *audio_config_p) * the pins we want to use. */ - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { int ot; // output control type, PTT, DCD, CON, ... @@ -984,7 +984,7 @@ void ptt_init (struct audio_s *audio_config_p) #if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) ) - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -1051,7 +1051,7 @@ void ptt_init (struct audio_s *audio_config_p) #endif /* x86 Linux */ #ifdef USE_HAMLIB - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -1163,7 +1163,7 @@ void ptt_init (struct audio_s *audio_config_p) #if USE_CM108 - for (ch = 0; ch < MAX_CHANS; ch++) { + for (ch = 0; ch < MAX_RADIO_CHANS; ch++) { if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { int ot; @@ -1185,7 +1185,7 @@ void ptt_init (struct audio_s *audio_config_p) /* Why doesn't it transmit? Probably forgot to specify PTT option. */ - for (ch=0; chchan_medium[ch] == MEDIUM_RADIO) { if(audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_NONE) { text_color_set(DW_COLOR_INFO); @@ -1251,14 +1251,14 @@ void ptt_set (int ot, int chan, int ptt_signal) int ptt2 = ptt_signal; assert (ot >= 0 && ot < NUM_OCTYPES); - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); if (ptt_debug_level >= 1) { text_color_set(DW_COLOR_DEBUG); dw_printf ("%s %d = %d\n", otnames[ot], chan, ptt_signal); } - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); if ( save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { text_color_set(DW_COLOR_ERROR); @@ -1494,7 +1494,7 @@ void ptt_set (int ot, int chan, int ptt_signal) int get_input (int it, int chan) { assert (it >= 0 && it < NUM_ICTYPES); - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); if ( save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { text_color_set(DW_COLOR_ERROR); @@ -1559,7 +1559,7 @@ void ptt_term (void) { int n; - for (n = 0; n < MAX_CHANS; n++) { + for (n = 0; n < MAX_RADIO_CHANS; n++) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -1568,7 +1568,7 @@ void ptt_term (void) } } - for (n = 0; n < MAX_CHANS; n++) { + for (n = 0; n < MAX_RADIO_CHANS; n++) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -1586,7 +1586,7 @@ void ptt_term (void) #ifdef USE_HAMLIB - for (n = 0; n < MAX_CHANS; n++) { + for (n = 0; n < MAX_RADIO_CHANS; n++) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { diff --git a/src/recv.c b/src/recv.c index 49040e5..51f2f01 100644 --- a/src/recv.c +++ b/src/recv.c @@ -108,6 +108,7 @@ #include "dtmf.h" #include "aprs_tt.h" #include "ax25_link.h" +#include "ring.h" #if __WIN32__ @@ -278,7 +279,7 @@ static void * recv_adev_thread (void *arg) // Try to re-init the audio device a couple times before giving up? text_color_set(DW_COLOR_ERROR); - dw_printf ("Terminating after audio input failure.\n"); + dw_printf ("Terminating after audio device %d input failure.\n", a); exit (1); } diff --git a/src/rrbb.c b/src/rrbb.c index e787dae..0666d42 100644 --- a/src/rrbb.c +++ b/src/rrbb.c @@ -83,7 +83,7 @@ rrbb_t rrbb_new (int chan, int subchan, int slice, int is_scrambled, int descram { rrbb_t result; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (slice >= 0 && slice < MAX_SLICERS); @@ -333,7 +333,7 @@ int rrbb_get_chan (rrbb_t b) assert (b->magic1 == MAGIC1); assert (b->magic2 == MAGIC2); - assert (b->chan >= 0 && b->chan < MAX_CHANS); + assert (b->chan >= 0 && b->chan < MAX_RADIO_CHANS); return (b->chan); } diff --git a/src/server.c b/src/server.c index 2cc108b..7814d9c 100644 --- a/src/server.c +++ b/src/server.c @@ -1413,7 +1413,7 @@ static THREAD_F cmd_listen_thread (void *arg) /* * Take some precautions to guard against bad data which could cause problems later. */ - if (cmd.hdr.portx < 0 || cmd.hdr.portx >= MAX_CHANS) { + if (cmd.hdr.portx < 0 || cmd.hdr.portx >= MAX_TOTAL_CHANS) { text_color_set(DW_COLOR_ERROR); dw_printf ("\nInvalid port number, %d, in command '%c', from AGW client application %d.\n", cmd.hdr.portx, cmd.hdr.datakind, client); @@ -1544,7 +1544,7 @@ static THREAD_F cmd_listen_thread (void *arg) // No other place cares about total number. count = 0; - for (j=0; jchan_medium[j] == MEDIUM_RADIO || save_audio_config_p->chan_medium[j] == MEDIUM_IGATE || save_audio_config_p->chan_medium[j] == MEDIUM_NETTNC) { @@ -1553,7 +1553,7 @@ static THREAD_F cmd_listen_thread (void *arg) } snprintf (reply.info, sizeof(reply.info), "%d;", count); - for (j=0; jchan_medium[j]) { @@ -1850,7 +1850,7 @@ static THREAD_F cmd_listen_thread (void *arg) // Connected mode can only be used with internal modems. - if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { + if (chan >= 0 && chan < MAX_RADIO_CHANS && save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { ok = 1; dlq_register_callsign (cmd.hdr.call_from, chan, client); } @@ -1879,7 +1879,7 @@ static THREAD_F cmd_listen_thread (void *arg) // Connected mode can only be used with internal modems. - if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { + if (chan >= 0 && chan < MAX_RADIO_CHANS && save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) { dlq_unregister_callsign (cmd.hdr.call_from, chan, client); } else { @@ -2066,7 +2066,7 @@ static THREAD_F cmd_listen_thread (void *arg) reply.hdr.data_len_NETLE = host2netle(4); int n = 0; - if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) { + if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_RADIO_CHANS) { // Count both normal and expedited in transmit queue for given channel. n = tq_count (cmd.hdr.portx, -1, "", "", 0); } diff --git a/src/telemetry.c b/src/telemetry.c index 2a6c690..d796cf1 100644 --- a/src/telemetry.c +++ b/src/telemetry.c @@ -71,7 +71,7 @@ #define T_NUM_ANALOG 5 /* Number of analog channels. */ #define T_NUM_DIGITAL 8 /* Number of digital channels. */ -#define T_STR_LEN 16 /* Max len for labels and units. */ +#define T_STR_LEN 32 /* Max len for labels and units. */ #define MAGIC1 0x5a1111a5 /* For checking storage allocation problems. */ diff --git a/src/tnctest.c b/src/tnctest.c index 0d4c26b..f5fb861 100644 --- a/src/tnctest.c +++ b/src/tnctest.c @@ -285,7 +285,7 @@ int main (int argc, char *argv[]) setlinebuf (stdout); #endif - start_dtime = dtime_now(); + start_dtime = dtime_monotonic(); /* * Extract command line args. @@ -615,7 +615,7 @@ void process_rec_data (int my_index, char *data) * and sent to a common function to check that they * all arrived in order. * - * Global Out: is_connected - Updated when connected/disconnected notifications are received. + * Global Out: is_connected - Updated when connected/disconnected notfications are received. * * Description: Perform any necessary configuration for the TNC then wait * for responses and process them. @@ -859,7 +859,7 @@ static void * tnc_thread_net (void *arg) * What did we get? */ - dnow = dtime_now(); + dnow = dtime_monotonic(); switch (mon_cmd.datakind) { @@ -943,7 +943,7 @@ static void * tnc_thread_net (void *arg) * and sent to a common function to check that they * all arrived in order. * - * Global Out: is_connected - Updated when connected/disconnected notifications are received. + * Global Out: is_connected - Updated when connected/disconnected notfications are received. * * Description: Perform any necessary configuration for the TNC then wait * for responses and process them. @@ -1038,12 +1038,12 @@ static void * tnc_thread_serial (void *arg) done = 1; } else if (ch == XOFF) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[R %.3f] \n", my_index*column_width, "", dnow-start_dtime); busy[my_index] = 1; } else if (ch == XON) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[R %.3f] \n", my_index*column_width, "", dnow-start_dtime); busy[my_index] = 0; } @@ -1070,7 +1070,7 @@ static void * tnc_thread_serial (void *arg) if (len > 0) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[R %.3f] %s\n", my_index*column_width, "", dnow-start_dtime, result); @@ -1109,7 +1109,7 @@ static void * tnc_thread_serial (void *arg) static void tnc_connect (int from, int to) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[T %.3f] *** Send connect request ***\n", from*column_width, "", dnow-start_dtime); @@ -1160,7 +1160,7 @@ static void tnc_connect (int from, int to) static void tnc_disconnect (int from, int to) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[T %.3f] *** Send disconnect request ***\n", from*column_width, "", dnow-start_dtime); @@ -1201,7 +1201,7 @@ static void tnc_disconnect (int from, int to) static void tnc_reset (int from, int to) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[T %.3f] *** Send reset ***\n", from*column_width, "", dnow-start_dtime); @@ -1232,7 +1232,7 @@ static void tnc_reset (int from, int to) static void tnc_send_data (int from, int to, char * data) { - double dnow = dtime_now(); + double dnow = dtime_monotonic(); printf("%*s[T %.3f] %s\n", from*column_width, "", dnow-start_dtime, data); @@ -1257,7 +1257,7 @@ static void tnc_send_data (int from, int to, char * data) else { // The assumption is that we are in CONVERS mode. - // The data should be terminated by carriage return. + // The data sould be terminated by carriage return. int timeout = 600; // 60 sec. I've seen it take more than 20. while (timeout > 0 && busy[from]) { diff --git a/src/tq.c b/src/tq.c index c656af5..0738eca 100644 --- a/src/tq.c +++ b/src/tq.c @@ -52,10 +52,10 @@ #include "dedupe.h" #include "igate.h" #include "dtime_now.h" +#include "nettnc.h" - -static packet_t queue_head[MAX_CHANS][TQ_NUM_PRIO]; /* Head of linked list for each queue. */ +static packet_t queue_head[MAX_RADIO_CHANS][TQ_NUM_PRIO]; /* Head of linked list for each queue. */ static dw_mutex_t tq_mutex; /* Critical section for updating queues. */ @@ -63,15 +63,15 @@ static dw_mutex_t tq_mutex; /* Critical section for updating queues. */ #if __WIN32__ -static HANDLE wake_up_event[MAX_CHANS]; /* Notify transmit thread when queue not empty. */ +static HANDLE wake_up_event[MAX_RADIO_CHANS]; /* Notify transmit thread when queue not empty. */ #else -static pthread_cond_t wake_up_cond[MAX_CHANS]; /* Notify transmit thread when queue not empty. */ +static pthread_cond_t wake_up_cond[MAX_RADIO_CHANS]; /* Notify transmit thread when queue not empty. */ -static pthread_mutex_t wake_up_mutex[MAX_CHANS]; /* Required by cond_wait. */ +static pthread_mutex_t wake_up_mutex[MAX_RADIO_CHANS]; /* Required by cond_wait. */ -static int xmit_thread_is_waiting[MAX_CHANS]; +static int xmit_thread_is_waiting[MAX_RADIO_CHANS]; #endif @@ -128,7 +128,7 @@ void tq_init (struct audio_s *audio_config_p) save_audio_config_p = audio_config_p; - for (c=0; cchan_medium[c] == MEDIUM_RADIO) { @@ -164,7 +164,7 @@ void tq_init (struct audio_s *audio_config_p) #else int err; - for (c = 0; c < MAX_CHANS; c++) { + for (c = 0; c < MAX_RADIO_CHANS; c++) { xmit_thread_is_waiting[c] = 0; @@ -199,6 +199,9 @@ void tq_init (struct audio_s *audio_config_p) * New in 1.7: * Channel can be assigned to IGate rather than a radio. * + * New in 1.8: + * Channel can be assigned to a network TNC. + * * prio - Priority, use TQ_PRIO_0_HI for digipeated or * TQ_PRIO_1_LO for normal. * @@ -252,10 +255,13 @@ void tq_append (int chan, int prio, packet_t pp) #endif // New in 1.7 - A channel can be assigned to the IGate rather than a radio. +// New in 1.8: Assign a channel to external network TNC. +// Send somewhere else, rather than the transmit queue. #ifndef DIGITEST // avoid dtest link error - if (save_audio_config_p->chan_medium[chan] == MEDIUM_IGATE) { + if (save_audio_config_p->chan_medium[chan] == MEDIUM_IGATE || + save_audio_config_p->chan_medium[chan] == MEDIUM_NETTNC) { char ts[100]; // optional time stamp. @@ -274,21 +280,39 @@ void tq_append (int chan, int prio, packet_t pp) unsigned char *pinfo; int info_len = ax25_get_info (pp, &pinfo); text_color_set(DW_COLOR_XMIT); - dw_printf ("[%d>is%s] ", chan, ts); - dw_printf ("%s", stemp); /* stations followed by : */ - ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp)); - dw_printf ("\n"); - igate_send_rec_packet (chan, pp); + if (save_audio_config_p->chan_medium[chan] == MEDIUM_IGATE) { + + dw_printf ("[%d>is%s] ", chan, ts); + dw_printf ("%s", stemp); /* stations followed by : */ + ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp)); + dw_printf ("\n"); + + igate_send_rec_packet (chan, pp); + } + else { // network TNC + dw_printf ("[%d>nt%s] ", chan, ts); + dw_printf ("%s", stemp); /* stations followed by : */ + ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp)); + dw_printf ("\n"); + + nettnc_send_packet (chan, pp); + + } + ax25_delete(pp); return; } #endif + + + + // Normal case - put in queue for radio transmission. // Error if trying to transmit to a radio channel which was not configured. - if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) { + if (chan < 0 || chan >= MAX_RADIO_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) { text_color_set(DW_COLOR_ERROR); dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); dw_printf ("This is probably a client application error, not a problem with direwolf.\n"); @@ -490,7 +514,7 @@ void lm_data_request (int chan, int prio, packet_t pp) } #endif - if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { + if (chan < 0 || chan >= MAX_RADIO_CHANS || save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { // Connected mode is allowed only with internal modems. text_color_set(DW_COLOR_ERROR); dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); @@ -648,7 +672,7 @@ void lm_seize_request (int chan) #endif - if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { + if (chan < 0 || chan >= MAX_RADIO_CHANS || save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) { // Connected mode is allowed only with internal modems. text_color_set(DW_COLOR_ERROR); dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); @@ -748,7 +772,7 @@ void tq_wait_while_empty (int chan) text_color_set(DW_COLOR_DEBUG); dw_printf ("tq_wait_while_empty (%d) : enter critical section\n", chan); #endif - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); dw_mutex_lock (&tq_mutex); @@ -944,7 +968,7 @@ static int tq_is_empty (int chan) { int p; - assert (chan >= 0 && chan < MAX_CHANS); + assert (chan >= 0 && chan < MAX_RADIO_CHANS); for (p=0; p= MAX_CHANS || prio < 0 || prio >= TQ_NUM_PRIO) { + if (chan < 0 || chan >= MAX_RADIO_CHANS || prio < 0 || prio >= TQ_NUM_PRIO) { text_color_set(DW_COLOR_DEBUG); dw_printf ("INTERNAL ERROR - tq_count(%d, %d, \"%s\", \"%s\", %d)\n", chan, prio, source, dest, bytes); return (0); diff --git a/src/tt_user.c b/src/tt_user.c index a73d6a4..63043b2 100644 --- a/src/tt_user.c +++ b/src/tt_user.c @@ -819,10 +819,10 @@ static void xmit_object_report (int i, int first_time) */ if (save_tt_config_p->obj_xmit_chan >= 0) { - strlcpy (stemp, save_audio_config_p->achan[save_tt_config_p->obj_xmit_chan].mycall, sizeof(stemp)); + strlcpy (stemp, save_audio_config_p->mycall[save_tt_config_p->obj_xmit_chan], sizeof(stemp)); } else { - strlcpy (stemp, save_audio_config_p->achan[save_tt_config_p->obj_recv_chan].mycall, sizeof(stemp)); + strlcpy (stemp, save_audio_config_p->mycall[save_tt_config_p->obj_recv_chan], sizeof(stemp)); } strlcat (stemp, ">", sizeof(stemp)); strlcat (stemp, APP_TOCALL, sizeof(stemp)); @@ -1134,7 +1134,7 @@ int main (int argc, char *argv[]) memset (&my_audio_config, 0, sizeof(my_audio_config)); - strlcpy (my_audio_config.achan[0].mycall, "WB2OSZ-15", sizeof(my_audio_config.achan[0].mycall)); + strlcpy (my_audio_config.mycall[0], "WB2OSZ-15", sizeof(my_audio_config.mycall[0])); /* Fake TT gateway config. */ diff --git a/src/xmit.c b/src/xmit.c index 13bbaec..0d938ef 100644 --- a/src/xmit.c +++ b/src/xmit.c @@ -88,24 +88,24 @@ */ -static int xmit_slottime[MAX_CHANS]; /* Slot time in 10 mS units for persistence algorithm. */ +static int xmit_slottime[MAX_RADIO_CHANS]; /* Slot time in 10 mS units for persistence algorithm. */ -static int xmit_persist[MAX_CHANS]; /* Sets probability for transmitting after each */ +static int xmit_persist[MAX_RADIO_CHANS]; /* Sets probability for transmitting after each */ /* slot time delay. Transmit if a random number */ /* in range of 0 - 255 <= persist value. */ /* Otherwise wait another slot time and try again. */ -static int xmit_txdelay[MAX_CHANS]; /* After turning on the transmitter, */ +static int xmit_txdelay[MAX_RADIO_CHANS]; /* After turning on the transmitter, */ /* send "flags" for txdelay * 10 mS. */ -static int xmit_txtail[MAX_CHANS]; /* Amount of time to keep transmitting after we */ +static int xmit_txtail[MAX_RADIO_CHANS]; /* Amount of time to keep transmitting after we */ /* are done sending the data. This is to avoid */ /* dropping PTT too soon and chopping off the end */ /* of the frame. Again 10 mS units. */ -static int xmit_fulldup[MAX_CHANS]; /* Full duplex if non-zero. */ +static int xmit_fulldup[MAX_RADIO_CHANS]; /* Full duplex if non-zero. */ -static int xmit_bits_per_sec[MAX_CHANS]; /* Data transmission rate. */ +static int xmit_bits_per_sec[MAX_RADIO_CHANS]; /* Data transmission rate. */ /* Often called baud rate which is equivalent for */ /* 1200 & 9600 cases but could be different with other */ /* modulation techniques. */ @@ -211,11 +211,11 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet) int ad; #if __WIN32__ - HANDLE xmit_th[MAX_CHANS]; + HANDLE xmit_th[MAX_RADIO_CHANS]; #else //pthread_attr_t attr; //struct sched_param sp; - pthread_t xmit_tid[MAX_CHANS]; + pthread_t xmit_tid[MAX_RADIO_CHANS]; #endif //int e; @@ -247,7 +247,7 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet) * TODO1.2: Any reason to use global config rather than making a copy? */ - for (j=0; jachan[j].baud; xmit_slottime[j] = p_modem->achan[j].slottime; xmit_persist[j] = p_modem->achan[j].persist; @@ -276,7 +276,7 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet) // underrun on the audio output device. - for (j=0; jchan_medium[j] == MEDIUM_RADIO) { #if __WIN32__ @@ -365,35 +365,35 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet) void xmit_set_txdelay (int channel, int value) { - if (channel >= 0 && channel < MAX_CHANS) { + if (channel >= 0 && channel < MAX_RADIO_CHANS) { xmit_txdelay[channel] = value; } } void xmit_set_persist (int channel, int value) { - if (channel >= 0 && channel < MAX_CHANS) { + if (channel >= 0 && channel < MAX_RADIO_CHANS) { xmit_persist[channel] = value; } } void xmit_set_slottime (int channel, int value) { - if (channel >= 0 && channel < MAX_CHANS) { + if (channel >= 0 && channel < MAX_RADIO_CHANS) { xmit_slottime[channel] = value; } } void xmit_set_txtail (int channel, int value) { - if (channel >= 0 && channel < MAX_CHANS) { + if (channel >= 0 && channel < MAX_RADIO_CHANS) { xmit_txtail[channel] = value; } } void xmit_set_fulldup (int channel, int value) { - if (channel >= 0 && channel < MAX_CHANS) { + if (channel >= 0 && channel < MAX_RADIO_CHANS) { xmit_fulldup[channel] = value; } }