New NCHANNEL feature.

This commit is contained in:
wb2osz 2024-07-19 00:37:38 +01:00
parent c05669a82b
commit ae888b0a8d
56 changed files with 697 additions and 391 deletions

View File

@ -6,6 +6,9 @@
### New Features: ### ### 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. - [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 ## ## Version 1.7 -- October 2023 ##

View File

@ -274,7 +274,7 @@
%C%#DTMF %C%#DTMF
%C% %C%
%C%# Push to Talk (PTT) can be confusing because there are so many different cases. %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%# goes into detail about the various options.
%C% %C%
%L%# If using a C-Media CM108/CM119 or similar USB Audio Adapter, %L%# If using a C-Media CM108/CM119 or similar USB Audio Adapter,

View File

@ -79,6 +79,7 @@ list(APPEND direwolf_SOURCES
morse.c morse.c
multi_modem.c multi_modem.c
waypoint.c waypoint.c
nettnc.c
serial_port.c serial_port.c
pfilter.c pfilter.c
ptt.c ptt.c

View File

@ -357,7 +357,7 @@ static void * tnc_listen_thread (void *arg)
/* /*
* Take some precautions to guard against bad data which could cause problems later. * 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel number, %d, in command '%c', from network TNC.\n", dw_printf ("Invalid channel number, %d, in command '%c', from network TNC.\n",
cmd.hdr.portx, cmd.hdr.datakind); cmd.hdr.portx, cmd.hdr.datakind);

View File

@ -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])) { if (strncasecmp(p, "Port", 4) == 0 && isdigit(p[4])) {
int chan = atoi(p+4) - 1; // "Port1" is our channel 0. 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; char *desc = p + 4;
while (*desc != '\0' && (*desc == ' ' || isdigit(*desc))) { while (*desc != '\0' && (*desc == ' ' || isdigit(*desc))) {

View File

@ -95,8 +95,8 @@
#define MAX_MSG_LEN 100 #define MAX_MSG_LEN 100
static char msg_str[MAX_CHANS][MAX_MSG_LEN+1]; static char msg_str[MAX_RADIO_CHANS][MAX_MSG_LEN+1];
static int msg_len[MAX_CHANS]; static int msg_len[MAX_RADIO_CHANS];
static int parse_fields (char *msg); static int parse_fields (char *msg);
static int parse_callsign (char *e); 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. // TODO: Keep ptr instead of making a copy.
memcpy (&tt_config, p, sizeof(struct tt_config_s)); memcpy (&tt_config, p, sizeof(struct tt_config_s));
#endif #endif
for (c=0; c<MAX_CHANS; c++) { for (c=0; c<MAX_RADIO_CHANS; c++) {
msg_len[c] = 0; msg_len[c] = 0;
msg_str[c][0] = '\0'; msg_str[c][0] = '\0';
} }
@ -226,7 +226,7 @@ void aprs_tt_button (int chan, char button)
{ {
static int poll_period = 0; static int poll_period = 0;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
//if (button != '.') { //if (button != '.') {

View File

@ -231,7 +231,7 @@ int main (int argc, char *argv[])
my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; my_audio_config.adev[0].bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
for (channel=0; channel<MAX_CHANS; channel++) { for (channel=0; channel<MAX_RADIO_CHANS; channel++) {
my_audio_config.achan[channel].modem_type = MODEM_AFSK; my_audio_config.achan[channel].modem_type = MODEM_AFSK;
@ -628,9 +628,10 @@ int main (int argc, char *argv[])
dw_printf ("%d samples per second. %d bits per sample. %d audio channels.\n", dw_printf ("%d samples per second. %d bits per sample. %d audio channels.\n",
my_audio_config.adev[0].samples_per_sec, my_audio_config.adev[0].samples_per_sec,
my_audio_config.adev[0].bits_per_sample, my_audio_config.adev[0].bits_per_sample,
my_audio_config.adev[0].num_channels); (int)(my_audio_config.adev[0].num_channels));
// nnum_channels is known to be 1 or 2.
one_filetime = (double) wav_data.datasize / one_filetime = (double) wav_data.datasize /
((my_audio_config.adev[0].bits_per_sample / 8) * my_audio_config.adev[0].num_channels * my_audio_config.adev[0].samples_per_sec); ((my_audio_config.adev[0].bits_per_sample / 8) * (int)(my_audio_config.adev[0].num_channels) * my_audio_config.adev[0].samples_per_sec);
total_filetime += one_filetime; total_filetime += one_filetime;
dw_printf ("%d audio bytes in file. Duration = %.1f seconds.\n", dw_printf ("%d audio bytes in file. Duration = %.1f seconds.\n",
@ -654,7 +655,7 @@ int main (int argc, char *argv[])
int audio_sample; int audio_sample;
int c; int c;
for (c=0; c<my_audio_config.adev[0].num_channels; c++) for (c=0; c<(int)(my_audio_config.adev[0].num_channels); c++)
{ {
/* This reads either 1 or 2 bytes depending on */ /* This reads either 1 or 2 bytes depending on */
@ -921,7 +922,7 @@ void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alev
void ptt_set (int ot, int chan, int ptt_signal) void ptt_set (int ot, int chan, int ptt_signal)
{ {
// Should only get here for DCD output control. // Should only get here for DCD output control.
static double dcd_start_time[MAX_CHANS]; static double dcd_start_time[MAX_RADIO_CHANS];
if (d_o_opt) { if (d_o_opt) {
double t = (double)sample_number / my_audio_config.adev[0].samples_per_sec; double t = (double)sample_number / my_audio_config.adev[0].samples_per_sec;

View File

@ -257,7 +257,7 @@ int audio_open (struct audio_s *pa)
if (pa->adev[a].bits_per_sample == 0) if (pa->adev[a].bits_per_sample == 0)
pa->adev[a].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; 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) if (pa->achan[chan].mark_freq == 0)
pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ; pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ;

View File

@ -16,7 +16,7 @@
#include <hamlib/rig.h> #include <hamlib/rig.h>
#endif #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 "ax25_pad.h" /* for AX25_MAX_ADDR_LEN */
#include "version.h" #include "version.h"
@ -59,7 +59,7 @@ typedef enum retry_e {
enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use. enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use.
MEDIUM_RADIO, // Internal modem for radio. MEDIUM_RADIO, // Internal modem for radio.
MEDIUM_IGATE, // Access IGate as ordinary channel. 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; 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. */ /* 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) */ /* 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 */ /* 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. // 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]; enum medium_e chan_medium[MAX_TOTAL_CHANS];
// MEDIUM_NONE for invalid. // MEDIUM_NONE for invalid.
// MEDIUM_RADIO for internal modem. (only possibility earlier) // MEDIUM_RADIO for internal modem. (only possibility earlier)
@ -154,6 +163,14 @@ struct audio_s {
/* Redundant but it makes things quicker and simpler */ /* Redundant but it makes things quicker and simpler */
/* than always searching thru above. */ /* 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. */ /* Properties for each radio channel, common to receive and transmit. */
/* Can be different for each radio channel. */ /* 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] // 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. ??? // 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; 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. */ int fulldup; /* Full Duplex. */
} achan[MAX_CHANS]; } achan[MAX_RADIO_CHANS];
#ifdef USE_HAMLIB #ifdef USE_HAMLIB
int rigs; /* Total number of configured rigs */ int rigs; /* Total number of configured rigs */

View File

@ -578,7 +578,7 @@ int audio_open (struct audio_s *pa)
if (pa->adev[a].bits_per_sample == 0) if (pa->adev[a].bits_per_sample == 0)
pa->adev[a].bits_per_sample = DEFAULT_BITS_PER_SAMPLE; 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) if (pa->achan[chan].mark_freq == 0)
pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ; pa->achan[chan].mark_freq = DEFAULT_MARK_FREQ;

View File

@ -270,7 +270,7 @@ int audio_open (struct audio_s *pa)
A->g_audio_in_type = AUDIO_IN_TYPE_SOUNDCARD; A->g_audio_in_type = AUDIO_IN_TYPE_SOUNDCARD;
for (chan=0; chan<MAX_CHANS; chan++) { for (chan=0; chan<MAX_RADIO_CHANS; chan++) {
if (pa -> achan[chan].mark_freq == 0) if (pa -> achan[chan].mark_freq == 0)
pa -> achan[chan].mark_freq = DEFAULT_MARK_FREQ; pa -> achan[chan].mark_freq = DEFAULT_MARK_FREQ;
@ -660,7 +660,13 @@ int audio_open (struct audio_s *pa)
*/ */
case AUDIO_IN_TYPE_STDIN: 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_next= 0;
A->stream_len = 0; A->stream_len = 0;
@ -888,7 +894,7 @@ int audio_get (int a)
while (A->stream_next >= A->stream_len) { while (A->stream_next >= A->stream_len) {
int res; int res;
res = read(STDIN_FILENO, A->stream_data, 1024); res = read(STDIN_FILENO, A->stream_data, sizeof(A->stream_data));
if (res <= 0) { if (res <= 0) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf ("\nEnd of file on stdin. Exiting.\n"); dw_printf ("\nEnd of file on stdin. Exiting.\n");
@ -903,9 +909,13 @@ int audio_get (int a)
A->stream_len = res; A->stream_len = res;
A->stream_next = 0; 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; break;
}
} // end switch audio in type
return (-1); return (-1);

View File

@ -1,7 +1,7 @@
// //
// This file is part of Dire Wolf, an amateur radio packet TNC. // 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 // 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 // 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. * Inputs: pconfig - misc. configuration from config file or command line.
* Beacon stuff ended up here. * Beacon stuff ended up here.
* *
* debug - debug level.
*
* Outputs: Remember required information for future use. That's all. * 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; 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 */ } /* 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 dcd_status[MAX_RADIO_CHANS];
static int ptt_status[MAX_CHANS]; static int ptt_status[MAX_RADIO_CHANS];
void lm_channel_busy (dlq_item_t *E) void lm_channel_busy (dlq_item_t *E)
{ {
int busy; 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->activity == OCTYPE_PTT || E->activity == OCTYPE_DCD);
assert (E->status == 1 || E->status == 0); 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) 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; ax25_dlsm_t *S;

View File

@ -43,7 +43,7 @@
// Call once at startup time. // 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);

View File

@ -1,7 +1,7 @@
// //
// This file is part of Dire Wolf, an amateur radio packet TNC. // 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 // 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 // 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. * The SSID can be 2 alphanumeric characters, not just 1 to 15.
* *
* We can just truncate the name because we will only * 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. * Returns: Pointer to new packet object in the current implementation.
* *
* Outputs: Use the "get" functions to retrieve information in different ways. * 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 #if AX25MEMDEBUG

View File

@ -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; int chan = g_misc_config_p->beacon[j].sendto_chan;
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */ 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 || if (g_modem_config_p->chan_medium[chan] == MEDIUM_RADIO ||
g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) { g_modem_config_p->chan_medium[chan] == MEDIUM_NETTNC) {
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 && if (strlen(g_modem_config_p->mycall[chan]) > 0 &&
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 && strcasecmp(g_modem_config_p->mycall[chan], "N0CALL") != 0 &&
strcasecmp(g_modem_config_p->achan[chan].mycall, "NOCALL") != 0) { strcasecmp(g_modem_config_p->mycall[chan], "NOCALL") != 0) {
switch (g_misc_config_p->beacon[j].btype) { 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. 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. // 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 { 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) { 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: 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->symtab, bp->symbol,
bp->power, bp->height, bp->gain, bp->dir, bp->power, bp->height, bp->gain, bp->dir,
G_UNKNOWN, G_UNKNOWN, /* course, speed */ G_UNKNOWN, G_UNKNOWN, /* course, speed */

View File

@ -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. * 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) { int cdigipeater_get_count (int from_chan, int to_chan) {
return (cdigi_count[from_chan][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. // 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. // 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan); dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
return; return;
@ -145,13 +147,13 @@ void cdigipeater (int from_chan, packet_t pp)
* Might not have a benefit here. * Might not have a benefit here.
*/ */
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) { for (to_chan=0; to_chan<MAX_RADIO_CHANS; to_chan++) {
if (save_cdigi_config_p->enabled[from_chan][to_chan]) { if (save_cdigi_config_p->enabled[from_chan][to_chan]) {
if (to_chan == from_chan) { if (to_chan == from_chan) {
packet_t result; packet_t result;
result = cdigipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, result = cdigipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan],
save_audio_config_p->achan[to_chan].mycall, save_audio_config_p->mycall[to_chan],
save_cdigi_config_p->has_alias[from_chan][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->alias[from_chan][to_chan]), to_chan,
save_cdigi_config_p->cfilter_str[from_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. * Second pass: Look at packets being digipeated to different channel.
*/ */
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) { for (to_chan=0; to_chan<MAX_RADIO_CHANS; to_chan++) {
if (save_cdigi_config_p->enabled[from_chan][to_chan]) { if (save_cdigi_config_p->enabled[from_chan][to_chan]) {
if (to_chan != from_chan) { if (to_chan != from_chan) {
packet_t result; packet_t result;
result = cdigipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, result = cdigipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan],
save_audio_config_p->achan[to_chan].mycall, save_audio_config_p->mycall[to_chan],
save_cdigi_config_p->has_alias[from_chan][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->alias[from_chan][to_chan]), to_chan,
save_cdigi_config_p->cfilter_str[from_chan][to_chan]); save_cdigi_config_p->cfilter_str[from_chan][to_chan]);

View File

@ -5,7 +5,7 @@
#include "regex.h" #include "regex.h"
#include "direwolf.h" /* for MAX_CHANS */ #include "direwolf.h" /* for MAX_RADIO_CHANS */
#include "ax25_pad.h" /* for packet_t */ #include "ax25_pad.h" /* for packet_t */
#include "audio.h" /* for radio channel properties */ #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. * 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 // the structure below will not be set up
// properly and an attempt to use it could // properly and an attempt to use it could
// result in a crash. (fixed v1.5) // result in a crash. (fixed v1.5)
// Not needed for [APRS] DIGIPEAT because // Not needed for [APRS] DIGIPEAT because
// the alias is mandatory there. // 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". // NULL or optional Packet Filter strings such as "t/m".
}; };

View File

@ -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. p_audio_config->adev[0].defined = 2; // 2 means it was done by default and not the user's config file.
for (channel=0; channel<MAX_CHANS; channel++) { for (channel=0; channel<MAX_TOTAL_CHANS; channel++) {
int ot, it; int ot, it;
p_audio_config->chan_medium[channel] = MEDIUM_NONE; /* One or both channels will be */ p_audio_config->chan_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) { else if (strcasecmp(t, "CHANNEL") == 0) {
@ -1233,7 +1233,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
n = atoi(t); n = atoi(t);
if (n >= 0 && n < MAX_CHANS) { if (n >= 0 && n < MAX_RADIO_CHANS) {
channel = n; channel = n;
@ -1253,7 +1253,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
else { else {
text_color_set(DW_COLOR_ERROR); 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; continue;
} }
int ichan = atoi(t); 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) { 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 { else {
text_color_set(DW_COLOR_ERROR); 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 { else {
text_color_set(DW_COLOR_ERROR); 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 * MYCALL station
*/ */
@ -1330,14 +1388,14 @@ void config_init (char *fname, struct audio_s *p_audio_config,
int c; int c;
for (c = 0; c < MAX_CHANS; c++) { for (c = 0; c < MAX_TOTAL_CHANS; c++) {
if (c == channel || if (c == channel ||
strlen(p_audio_config->achan[c].mycall) == 0 || strlen(p_audio_config->mycall[c]) == 0 ||
strcasecmp(p_audio_config->achan[c].mycall, "NOCALL") == 0 || strcasecmp(p_audio_config->mycall[c], "NOCALL") == 0 ||
strcasecmp(p_audio_config->achan[c].mycall, "N0CALL") == 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; continue;
} }
from_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
@ -2582,10 +2640,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
to_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
@ -2713,10 +2771,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
from_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
@ -2742,10 +2800,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
to_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { 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; continue;
} }
from_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
@ -2820,10 +2878,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
to_chan = atoi(t); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { 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; continue;
} }
if (*t == 'i' || *t == 'I') { if (*t == 'i' || *t == 'I') {
from_chan = MAX_CHANS; from_chan = MAX_TOTAL_CHANS;
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: FILTER IG ... on line %d.\n", line); 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"); 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 { else {
from_chan = isdigit(*t) ? atoi(t) : -999; 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); 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", 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; continue;
} }
@ -2945,7 +3003,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
if (*t == 'i' || *t == 'I') { if (*t == 'i' || *t == 'I') {
to_chan = MAX_CHANS; to_chan = MAX_TOTAL_CHANS;
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: FILTER ... IG ... on line %d.\n", line); 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"); 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 { else {
to_chan = isdigit(*t) ? atoi(t) : -999; 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); 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", 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; continue;
} }
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO && 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; 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); 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", 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; continue;
} }
@ -3045,10 +3103,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
to_chan = isdigit(*t) ? atoi(t) : -999; 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); 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", 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; continue;
} }
if (p_audio_config->chan_medium[to_chan] != MEDIUM_RADIO) { 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); r = atoi(t);
if (r < 0 || r > MAX_CHANS-1) { if (r < 0 || r > MAX_RADIO_CHANS-1) {
text_color_set(DW_COLOR_ERROR); 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", 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; continue;
} }
@ -4236,9 +4294,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
if (isdigit(*p)) { if (isdigit(*p)) {
x = *p - '0'; x = *p - '0';
if (x < 0 || x > MAX_CHANS-1) { if (x < 0 || x > MAX_TOTAL_CHANS-1) {
text_color_set(DW_COLOR_ERROR); 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; x = -1;
} }
else if (p_audio_config->chan_medium[x] != MEDIUM_RADIO && 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); n = atoi(t);
if (n < 0 || n > MAX_CHANS-1) { if (n < 0 || n > MAX_TOTAL_CHANS-1) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Transmit channel must be in range of 0 to %d on line %d.\n", 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; continue;
} }
p_igate_config->tx_chan = n; 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); t = split(NULL,0);
if (t != NULL) { if (t != NULL) {
chan = atoi(t); chan = atoi(t);
if (chan < 0 || chan >= MAX_CHANS) { if (chan < 0 || chan >= MAX_TOTAL_CHANS) {
text_color_set(DW_COLOR_ERROR); 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; continue;
} }
} }
@ -5510,25 +5568,25 @@ void config_init (char *fname, struct audio_s *p_audio_config,
*/ */
int i, j, k, b; int i, j, k, b;
for (i=0; i<MAX_CHANS; i++) { for (i=0; i<MAX_TOTAL_CHANS; i++) {
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_TOTAL_CHANS; j++) {
/* APRS digipeating. */ /* APRS digipeating. */
if (p_digi_config->enabled[i][j]) { if (p_digi_config->enabled[i][j]) {
if ( strcmp(p_audio_config->achan[i].mycall, "") == 0 || if ( strcmp(p_audio_config->mycall[i], "") == 0 ||
strcmp(p_audio_config->achan[i].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[i], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) { strcmp(p_audio_config->mycall[i], "N0CALL") == 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: MYCALL must be set for receive channel %d before digipeating is allowed.\n", i); 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; p_digi_config->enabled[i][j] = 0;
} }
if ( strcmp(p_audio_config->achan[j].mycall, "") == 0 || if ( strcmp(p_audio_config->mycall[j], "") == 0 ||
strcmp(p_audio_config->achan[j].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[j], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[j].mycall, "N0CALL") == 0) { strcmp(p_audio_config->mycall[j], "N0CALL") == 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: MYCALL must be set for transmit channel %d before digipeating is allowed.\n", i); 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. */ /* 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 || if ( strcmp(p_audio_config->mycall[i], "") == 0 ||
strcmp(p_audio_config->achan[i].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[i], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) { strcmp(p_audio_config->mycall[i], "N0CALL") == 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: MYCALL must be set for receive channel %d before digipeating is allowed.\n", i); 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; p_cdigi_config->enabled[i][j] = 0;
} }
if ( strcmp(p_audio_config->achan[j].mycall, "") == 0 || if ( strcmp(p_audio_config->mycall[j], "") == 0 ||
strcmp(p_audio_config->achan[j].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[j], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[j].mycall, "N0CALL") == 0) { strcmp(p_audio_config->mycall[j], "N0CALL") == 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: MYCALL must be set for transmit channel %d before digipeating is allowed.\n", i); 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 && if (strlen(p_igate_config->t2_login) > 0 &&
(p_audio_config->chan_medium[i] == MEDIUM_RADIO || p_audio_config->chan_medium[i] == MEDIUM_NETTNC)) { (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); 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); 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)); 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. // Currently we can have only one transmit channel.
// This might be generalized someday to allow more. // This might be generalized someday to allow more.
if (p_igate_config->tx_chan >= 0 && if (p_igate_config->tx_chan >= 0 &&
( strcmp(p_audio_config->achan[p_igate_config->tx_chan].mycall, "") == 0 || ( strcmp(p_audio_config->mycall[p_igate_config->tx_chan], "") == 0 ||
strcmp(p_audio_config->achan[p_igate_config->tx_chan].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[p_igate_config->tx_chan], "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], "N0CALL") == 0)) {
text_color_set(DW_COLOR_ERROR); 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); 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. // This will handle eventual case of multiple transmit channels.
if (strlen(p_igate_config->t2_login) > 0) { if (strlen(p_igate_config->t2_login) > 0) {
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_TOTAL_CHANS; j++) {
if (p_audio_config->chan_medium[j] == MEDIUM_RADIO || p_audio_config->chan_medium[j] == MEDIUM_NETTNC) { if (p_audio_config->chan_medium[j] == MEDIUM_RADIO || p_audio_config->chan_medium[j] == MEDIUM_NETTNC) {
if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) { if (p_digi_config->filter_str[MAX_TOTAL_CHANS][j] == NULL) {
p_digi_config->filter_str[MAX_CHANS][j] = strdup("i/180"); 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') { else if (value[0] == 'r' || value[0] == 'R') {
int n = atoi(value+1); 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) { && p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n); 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') { else if (value[0] == 't' || value[0] == 'T' || value[0] == 'x' || value[0] == 'X') {
int n = atoi(value+1); 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) { && p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); 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 { else {
int n = atoi(value); 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) { && p_audio_config->chan_medium[n] != MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); 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_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) { && p_audio_config->chan_medium[b->sendto_chan] != MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan); 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. if (p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_IGATE) { // Prevent subscript out of bounds.
// Will be using call from chan 0 later. // Will be using call from chan 0 later.
if ( strcmp(p_audio_config->achan[0].mycall, "") == 0 || if ( strcmp(p_audio_config->mycall[0], "") == 0 ||
strcmp(p_audio_config->achan[0].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[0], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[0].mycall, "N0CALL") == 0 ) { strcmp(p_audio_config->mycall[0], "N0CALL") == 0 ) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", 0); dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", 0);
return (0); return (0);
} }
} else { } else {
if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 || if ( strcmp(p_audio_config->mycall[b->sendto_chan], "") == 0 ||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 || strcmp(p_audio_config->mycall[b->sendto_chan], "NOCALL") == 0 ||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) { strcmp(p_audio_config->mycall[b->sendto_chan], "N0CALL") == 0 ) {
text_color_set(DW_COLOR_ERROR); 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); dw_printf ("Config file: MYCALL must be set for channel %d before beaconing is allowed.\n", b->sendto_chan);

View File

@ -30,7 +30,7 @@ enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
#define MAX_BEACONS 30 #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 { struct misc_config_s {

View File

@ -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 "_ " // It is essential to keep trailing spaces. e.g. VX-8 suffix is "_ "
char mcomment[256]; 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') { if (mcomment[strlen(mcomment)-1] == '\r') {
mcomment[strlen(mcomment)-1] = '\0'; mcomment[strlen(mcomment)-1] = '\0';
} }

View File

@ -63,11 +63,11 @@ static struct audio_s *save_audio_config_p;
// Current state of all the decoders. // 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_sum[MAX_RADIO_CHANS][MAX_SUBCHANS];
static int sample_count[MAX_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; 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) { 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. // 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); // 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. // New in 1.7.
// A few people have a really bad audio cross talk situation where they receive their own transmissions. // 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) 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; 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; struct demodulator_state_s *D;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
if (mute_input[chan]) { if (mute_input[chan]) {
@ -1066,7 +1066,7 @@ alevel_t demod_get_audio_level (int chan, int subchan)
struct demodulator_state_s *D; struct demodulator_state_s *D;
alevel_t alevel; alevel_t alevel;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
/* We have to consider two different cases here. */ /* We have to consider two different cases here. */

View File

@ -395,7 +395,7 @@ void demod_9600_process_sample (int chan, int sam, int upsample, struct demodula
int subchan = 0; int subchan = 0;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
/* Scale to nice number for convenience. */ /* 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. */ /* 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); 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); 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) { 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) ); 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 { 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].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;
} }

View File

@ -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 */ static int seq = 0; /* for log file name */
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
/* /*

View File

@ -72,7 +72,10 @@
* V.26 has two variations, A and B. Initially I implemented the A alternative. * 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 * 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. * 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" #include "direwolf.h"
@ -94,7 +97,7 @@
#include "fsk_demod_state.h" // Values above override defaults. #include "fsk_demod_state.h" // Values above override defaults.
#include "audio.h" #include "audio.h"
#include "tune.h" //#include "tune.h" // obsolete. eventually remove all references.
#include "fsk_gen_filter.h" #include "fsk_gen_filter.h"
#include "hdlc_rec.h" #include "hdlc_rec.h"
#include "textcolor.h" #include "textcolor.h"
@ -102,7 +105,13 @@
#include "dsp.h" #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}; 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? D->num_slicers = 1; // Haven't thought about this yet. Is it even applicable?
#ifdef TUNE_PROFILE //#ifdef TUNE_PROFILE
profile = TUNE_PROFILE; // profile = TUNE_PROFILE;
#endif //#endif
TUNE("TUNE_PROFILE", profile, "profile", "%c")
if (modem_type == MODEM_QPSK) { 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 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.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.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 ); D->u.psk.soffs = (int) round( (13.f / 12.f) * (float)samples_per_sec / (float)correct_baud );
#endif
} }
else { 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 //#ifdef TUNE_PRE_BAUD
D->u.psk.prefilter_baud = TUNE_PRE_BAUD; // D->u.psk.prefilter_baud = TUNE_PRE_BAUD;
#endif //#endif
#ifdef TUNE_PRE_WINDOW TUNE("TUNE_PRE_BAUD", D->u.psk.prefilter_baud, "prefilter_baud", "%.3f")
D->u.psk.pre_window = TUNE_PRE_WINDOW;
#endif
#ifdef TUNE_LPF_BAUD //#ifdef TUNE_PRE_WINDOW
D->u.psk.lpf_baud = TUNE_LPF_BAUD; // D->u.psk.pre_window = TUNE_PRE_WINDOW;
#endif //#endif
#ifdef TUNE_LP_WINDOW TUNE("TUNE_PRE_WINDOW", D->u.psk.pre_window, "pre_window", "%d")
D->u.psk.lp_window = TUNE_LP_WINDOW;
#endif
#if defined(TUNE_PLL_SEARCHING) //#ifdef TUNE_LPF_BAUD
D->pll_searching_inertia = TUNE_PLL_SEARCHING; // D->u.psk.lpf_baud = TUNE_LPF_BAUD;
#endif //#endif
#if defined(TUNE_PLL_LOCKED) //#ifdef TUNE_LP_WINDOW
D->pll_locked_inertia = TUNE_PLL_LOCKED; // D->u.psk.lp_window = TUNE_LP_WINDOW;
#endif //#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 ); 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.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 ); 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 //#ifdef TUNE_PRE_FILTER_TAPS
D->u.psk.pre_filter_taps = TUNE_PRE_FILTER_TAPS; // D->u.psk.pre_filter_taps = TUNE_PRE_FILTER_TAPS;
#endif //#endif
TUNE("TUNE_PRE_FILTER_TAPS", D->u.psk.pre_filter_taps, "pre_filter_taps", "%d")
#ifdef TUNE_lp_filter_taps //#ifdef TUNE_lp_filter_taps
D->u.psk.lp_filter_taps = TUNE_lp_filter_taps; // D->u.psk.lp_filter_taps = TUNE_lp_filter_taps;
#endif //#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) { 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? 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); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
/* Scale to nice number for plotting during debug. */ /* 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; int gray = demod_bits;
hdlc_rec_bit (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1]); hdlc_rec_bit_new (chan, subchan, slice, (gray >> 1) & 1, 0, bit_quality[1],
hdlc_rec_bit (chan, subchan, slice, gray & 1, 0, bit_quality[0]); &(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 { else {
int gray = demod_bits; int gray = demod_bits;
hdlc_rec_bit (chan, subchan, slice, (gray >> 2) & 1, 0, bit_quality[2]); hdlc_rec_bit_new (chan, subchan, slice, (gray >> 2) & 1, 0, bit_quality[2],
hdlc_rec_bit (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 (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));
} }
D->slicer[slice].pll_symbol_count++;
pll_dcd_each_symbol2 (D, chan, subchan, slice); 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); 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) { 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); D->slicer[slice].data_clock_pll = (int)floorf((float)(D->slicer[slice].data_clock_pll) * D->pll_locked_inertia);
} }
else { else {
D->slicer[slice].data_clock_pll = (int)floorf((float)(D->slicer[slice].data_clock_pll) * D->pll_searching_inertia); 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;
} }
/* /*

View File

@ -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. * 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) { int digipeater_get_count (int from_chan, int to_chan) {
return (digi_count[from_chan][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. // 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_RADIO &&
save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC)) { save_audio_config_p->chan_medium[from_chan] != MEDIUM_NETTNC)) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -195,14 +195,14 @@ void digipeater (int from_chan, packet_t pp)
* *
*/ */
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) { for (to_chan=0; to_chan<MAX_TOTAL_CHANS; to_chan++) {
if (save_digi_config_p->enabled[from_chan][to_chan]) { if (save_digi_config_p->enabled[from_chan][to_chan]) {
if (to_chan == from_chan) { if (to_chan == from_chan) {
packet_t result; packet_t result;
result = digipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, result = digipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan],
save_audio_config_p->achan[to_chan].mycall, 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], &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], to_chan, save_digi_config_p->preempt[from_chan][to_chan],
save_digi_config_p->atgp[from_chan][to_chan], save_digi_config_p->atgp[from_chan][to_chan],
save_digi_config_p->filter_str[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 * These are lower priority
*/ */
for (to_chan=0; to_chan<MAX_CHANS; to_chan++) { for (to_chan=0; to_chan<MAX_TOTAL_CHANS; to_chan++) {
if (save_digi_config_p->enabled[from_chan][to_chan]) { if (save_digi_config_p->enabled[from_chan][to_chan]) {
if (to_chan != from_chan) { if (to_chan != from_chan) {
packet_t result; packet_t result;
result = digipeat_match (from_chan, pp, save_audio_config_p->achan[from_chan].mycall, result = digipeat_match (from_chan, pp, save_audio_config_p->mycall[from_chan],
save_audio_config_p->achan[to_chan].mycall, 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], &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], to_chan, save_digi_config_p->preempt[from_chan][to_chan],
save_digi_config_p->atgp[from_chan][to_chan], save_digi_config_p->atgp[from_chan][to_chan],
save_digi_config_p->filter_str[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"); // 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_chan<MAX_CHANS; to_chan++) { for (to_chan=0; to_chan<MAX_TOTAL_CHANS; to_chan++) {
if (save_digi_config_p->regen[from_chan][to_chan]) { if (save_digi_config_p->regen[from_chan][to_chan]) {
result = ax25_dup (pp); result = ax25_dup (pp);
if (result != NULL) { if (result != NULL) {

View File

@ -4,7 +4,7 @@
#include "regex.h" #include "regex.h"
#include "direwolf.h" /* for MAX_CHANS */ #include "direwolf.h" /* for MAX_TOTAL_CHANS */
#include "ax25_pad.h" /* for packet_t */ #include "ax25_pad.h" /* for packet_t */
#include "audio.h" /* for radio channel properties */ #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. * 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. // 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. // 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". // NULL or optional Packet Filter strings such as "t/m".
// Notice the size of arrays is one larger than normal. // Notice the size of arrays is one larger than normal.
// That extra position is for the IGate. // 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. // Sort of like digipeating but passed along unchanged.
}; };

View File

@ -1,7 +1,7 @@
// //
// This file is part of Dire Wolf, an amateur radio packet TNC. // 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 // 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 // it under the terms of the GNU General Public License as published by
@ -130,6 +130,7 @@
#include "dns_sd_dw.h" #include "dns_sd_dw.h"
#include "dlq.h" // for fec_type_t definition. #include "dlq.h" // for fec_type_t definition.
#include "deviceid.h" #include "deviceid.h"
#include "nettnc.h"
//static int idx_decoded = 0; //static int idx_decoded = 0;
@ -228,6 +229,7 @@ int main (int argc, char *argv[])
#endif #endif
int d_x_opt = 1; /* "-d x" option for FX.25. Default minimal. Repeat for more detail. -qx to silence. */ 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_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. */ 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_init(t_opt);
text_color_set(DW_COLOR_INFO); 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 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); //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); text_color_set(DW_COLOR_ERROR);
for (int n=0; n<15; n++) { for (int n=0; n<15; n++) {
dw_printf ("\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 ("Dire Wolf requires only privileges available to ordinary users.\n");
dw_printf ("Running this as root is an unnecessary security risk.\n"); dw_printf ("Running this as root is an unnecessary security risk.\n");
//SLEEP_SEC(1); //SLEEP_SEC(1);
@ -558,7 +561,7 @@ int main (int argc, char *argv[])
break; 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel %d for -x. \n", x_opt_chan); dw_printf ("Invalid channel %d for -x. \n", x_opt_chan);
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
@ -637,6 +640,7 @@ int main (int argc, char *argv[])
#if USE_HAMLIB #if USE_HAMLIB
case 'h': d_h_opt++; break; // Hamlib verbose level. case 'h': d_h_opt++; break; // Hamlib verbose level.
#endif #endif
case 'c': d_c_opt++; break; // Connected mode data link state machine
case 'x': d_x_opt++; break; // FX.25 case 'x': d_x_opt++; break; // FX.25
case '2': d_2_opt++; break; // IL2P case '2': d_2_opt++; break; // IL2P
case 'd': aprstt_debug++; break; // APRStt (mnemonic Dtmf) case 'd': aprstt_debug++; break; // APRStt (mnemonic Dtmf)
@ -1004,6 +1008,13 @@ int main (int argc, char *argv[])
fx25_init (d_x_opt); fx25_init (d_x_opt);
il2p_init (d_2_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. * 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); igate_init (&audio_config, &igate_config, &digi_config, d_i_opt);
cdigipeater_init (&audio_config, &cdigi_config); cdigipeater_init (&audio_config, &cdigi_config);
pfilter_init (&igate_config, d_f_opt); 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. * 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. * Inputs: chan - Audio channel number, 0 or 1.
* subchan - Which modem caught it. * 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. * slice - Slicer which caught it.
* pp - Packet handle. * pp - Packet handle.
* alevel - Audio level, range of 0 - 100. * 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. // Can indicate FX.25/IL2P or fix_bits.
assert (chan >= 0 && chan < MAX_TOTAL_CHANS); // TOTAL for virtual channels 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 (slice >= 0 && slice < MAX_SLICERS);
assert (pp != NULL); // 1.1J+ 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); 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) { 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 { 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"); 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 // 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Audio input level is too low. Increase so most stations are around 50.\n"); 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)); strlcpy (ts, "", sizeof(ts));
} }
if (subchan == -1) { if (subchan == -1) { // dtmf
text_color_set(DW_COLOR_REC); text_color_set(DW_COLOR_REC);
dw_printf ("[%d.dtmf%s] ", chan, ts); dw_printf ("[%d.dtmf%s] ", chan, ts);
} }
else if (subchan == -2) { else if (subchan == -2) { // APRS-IS
text_color_set(DW_COLOR_REC); text_color_set(DW_COLOR_REC);
dw_printf ("[%d.is%s] ", chan, ts); 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 { else {
if (ax25_is_aprs(pp)) { if (ax25_is_aprs(pp)) {
text_color_set(DW_COLOR_REC); 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 0, 0, 0, A.g_comment, // freq, tone, offset
ais_obj_info, sizeof(ais_obj_info)); 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); 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.) * Use only those with correct CRC (or using FEC.)
*/ */
if (retries == RETRY_NONE || fec_type == fec_type_fx25 || fec_type == fec_type_il2p) { if (chan < MAX_RADIO_CHANS) {
if (retries == RETRY_NONE || fec_type == fec_type_fx25 || fec_type == fec_type_il2p) {
cdigipeater (chan, pp); cdigipeater (chan, pp);
}
} }
} }
@ -1708,6 +1739,7 @@ static void usage (char **argv)
#if USE_HAMLIB #if USE_HAMLIB
dw_printf (" h h = hamlib increase verbose level.\n"); dw_printf (" h h = hamlib increase verbose level.\n");
#endif #endif
dw_printf (" c c = Connected mode data link state machine.\n");
dw_printf (" x x = FX.25 increase verbose level.\n"); dw_printf (" x x = FX.25 increase verbose level.\n");
dw_printf (" 2 2 = IL2P.\n"); dw_printf (" 2 2 = IL2P.\n");
dw_printf (" d d = APRStt (DTMF to APRS object translation).\n"); dw_printf (" d d = APRStt (DTMF to APRS object translation).\n");

View File

@ -56,15 +56,10 @@
* *
* ADevice 0: channel 0 * ADevice 0: channel 0
* ADevice 1: left = 2, right = 3 * ADevice 1: left = 2, right = 3
*
* TODO1.2: Look for any places that have
* for (ch=0; ch<MAX_CHANS; ch++) ...
* and make sure they handle undefined channels correctly.
*/ */
#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2) #define MAX_RADIO_CHANS ((MAX_ADEVS) * 2)
#define MAX_CHANS MAX_RADIO_CHANS // TODO: Replace all former with latter to avoid confusion with following.
#define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected #define MAX_TOTAL_CHANS 16 // v1.7 allows additional virtual channels which are connected
// to something other than radio modems. // to something other than radio modems.
@ -77,7 +72,7 @@
*/ */
#ifdef USE_HAMLIB #ifdef USE_HAMLIB
#define MAX_RIGS MAX_CHANS #define MAX_RIGS MAX_RADIO_CHANS
#endif #endif
/* /*

View File

@ -498,7 +498,7 @@ void dlq_connect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num
dw_printf ("dlq_connect_request (...)\n"); dw_printf ("dlq_connect_request (...)\n");
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* 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"); dw_printf ("dlq_disconnect_request (...)\n");
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* 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"); dw_printf ("dlq_outstanding_frames_request (...)\n");
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* 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"); dw_printf ("dlq_xmit_data_request (...)\n");
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* 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); dw_printf ("dlq_register_callsign (%s, chan=%d, client=%d)\n", addr, chan, client);
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* 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); dw_printf ("dlq_unregister_callsign (%s, chan=%d, client=%d)\n", addr, chan, client);
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
/* Allocate a new queue item. */ /* Allocate a new queue item. */

View File

@ -80,7 +80,7 @@ static struct dd_s { /* Separate for each audio channel. */
char prev_debounced; char prev_debounced;
int timeout; int timeout;
} dd[MAX_CHANS]; } dd[MAX_RADIO_CHANS];
static int s_amplitude = 100; // range of 0 .. 100 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. * Larger = narrower bandwidth, slower response.
*/ */
for (c=0; c<MAX_CHANS; c++) { for (c=0; c<MAX_RADIO_CHANS; c++) {
struct dd_s *D = &(dd[c]); struct dd_s *D = &(dd[c]);
int a = ACHAN2ADEV(c); int a = ACHAN2ADEV(c);
@ -167,7 +167,7 @@ void dtmf_init (struct audio_s *p_audio_config, int amp)
} }
} }
for (c=0; c<MAX_CHANS; c++) { for (c=0; c<MAX_RADIO_CHANS; c++) {
struct dd_s *D = &(dd[c]); struct dd_s *D = &(dd[c]);
D->n = 0; D->n = 0;
for (j=0; j<NUM_TONES; j++) { for (j=0; j<NUM_TONES; j++) {
@ -214,6 +214,11 @@ char dtmf_sample (int c, float input)
'7', '8', '9', 'C', '7', '8', '9', 'C',
'*', '0', '#', 'D' }; '*', '0', '#', 'D' };
// Only applies to radio channels. Should not be here.
if (c >= MAX_RADIO_CHANS) {
return ('$');
}
D = &(dd[c]); D = &(dd[c]);
for (i=0; i<NUM_TONES; i++) { for (i=0; i<NUM_TONES; i++) {

View File

@ -125,7 +125,7 @@ int dwsock_init(void)
/*------------------------------------------------------------------- /*-------------------------------------------------------------------
* *
* Name: sock_connect * Name: dwsock_connect
* *
* Purpose: Connect to given host / port. * Purpose: Connect to given host / port.
* *

View File

@ -596,14 +596,22 @@ int encode_position (int messaging, int compressed, double lat, double lon, int
presult[result_len] = '\0'; presult[result_len] = '\0';
/* Altitude. Can be anywhere in comment. */ /* Altitude. Can be anywhere in comment. */
// Officially, altitude must be six digits.
// What about all the places on the earth's surface that are below sea level?
// https://en.wikipedia.org/wiki/List_of_places_on_land_with_elevations_below_sea_level
// The MIC-E format allows negative altitudes; not allowing it for /A=123456 seems to be an oversight.
// Most modern applications recognize the form /A=-12345 with minus and five digits.
// This maintains the same total field width and the range is more than adequate.
if (alt_ft != G_UNKNOWN) { if (alt_ft != G_UNKNOWN) {
char salt[12]; char salt[12];
/* Not clear if altitude can be negative. */ /* Not clear if altitude can be negative. */
/* Be sure it will be converted to 6 digits. */ /* Be sure it will be converted to 6 digits. */
if (alt_ft < 0) alt_ft = 0; // if (alt_ft < 0) alt_ft = 0;
if (alt_ft < -99999) alt_ft = -99999;
if (alt_ft > 999999) alt_ft = 999999; if (alt_ft > 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); strlcat (presult, salt, result_size);
result_len += strlen(salt); result_len += strlen(salt);
} }

View File

@ -469,7 +469,7 @@ struct demodulator_state_s
* *
* Inputs: D Pointer to demodulator state. * 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 * subchan Which of multiple demodulators: 0 to MAX_SUBCHANS - 1
* *

View File

@ -59,7 +59,7 @@ struct fx_context_s {
unsigned char block[FX25_BLOCK_SIZE+1]; 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); 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]; struct fx_context_s *F = fx_context[chan][subchan][slice];
if (F == NULL) { if (F == NULL) {
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
assert (slice >= 0 && slice < MAX_SLICERS); assert (slice >= 0 && slice < MAX_SLICERS);
F = fx_context[chan][subchan][slice] = (struct fx_context_s *)malloc(sizeof (struct fx_context_s)); 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) 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 // This could be a little faster if we knew number of
// subchannels and slicers but it is probably insignificant. // subchannels and slicers but it is probably insignificant.

View File

@ -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 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 #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 void send_bit (int chan, int b)
{ {
static int output[MAX_CHANS]; static int output[MAX_RADIO_CHANS];
if (b == 0) { if (b == 0) {
output[chan] = ! output[chan]; output[chan] = ! output[chan];

View File

@ -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].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 */ 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].modem_type = MODEM_AFSK; /* change with -g */
modem.achan[chan].mark_freq = DEFAULT_MARK_FREQ; /* -m option */ modem.achan[chan].mark_freq = DEFAULT_MARK_FREQ; /* -m option */
modem.achan[chan].space_freq = DEFAULT_SPACE_FREQ; /* -s option */ modem.achan[chan].space_freq = DEFAULT_SPACE_FREQ; /* -s option */

View File

@ -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 ) #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 */ /* because they have same sample rate */
/* but less confusing to have for each channel. */ /* but less confusing to have for each channel. */
static int ticks_per_bit[MAX_CHANS]; static int ticks_per_bit[MAX_RADIO_CHANS];
static int f1_change_per_sample[MAX_CHANS]; static int f1_change_per_sample[MAX_RADIO_CHANS];
static int f2_change_per_sample[MAX_CHANS]; static int f2_change_per_sample[MAX_RADIO_CHANS];
static float samples_per_symbol[MAX_CHANS]; static float samples_per_symbol[MAX_RADIO_CHANS];
static short sine_table[256]; static short sine_table[256];
@ -78,7 +78,7 @@ static short sine_table[256];
/* Accumulators. */ /* 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. // Upper bits are used as index into sine table.
#define PHASE_SHIFT_180 ( 128u << 24 ) #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 ) #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. // on the channel. This is only used for QPSK.
// The LSB determines if we save the bit until // The LSB determines if we save the bit until
// next time, or send this one with the previously saved. // 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 // For 8PSK, it has a different meaning. It is the
// number of bits in 'save_bit' so we can accumulate // number of bits in 'save_bit' so we can accumulate
// three for each symbol. // 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); 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) { 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. // #define PSKIQ 1 // not ready for prime time yet.
#if PSKIQ #if PSKIQ
static int xmit_octant[MAX_CHANS]; // absolute phase in 45 degree units. static int xmit_octant[MAX_RADIO_CHANS]; // absolute phase in 45 degree units.
static int xmit_prev_octant[MAX_CHANS]; // from previous symbol. static int xmit_prev_octant[MAX_RADIO_CHANS]; // from previous symbol.
// For PSK, we generate the final signal by combining fixed frequency cosine and // For PSK, we generate the final signal by combining fixed frequency cosine and
// sine by the following weights. // sine by the following weights.

View File

@ -114,11 +114,11 @@ struct hdlc_state_s {
int eas_fields_after_plus; /* Number of "-" characters after the "+". */ 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)); 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) { 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) 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. */ int dbit; /* Data bit after undoing NRZI. */
/* Should be only 0 or 1. */ /* Should be only 0 or 1. */
struct hdlc_state_s *H;
assert (was_init == 1); assert (was_init == 1);
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
assert (slice >= 0 && slice < MAX_SLICERS); assert (slice >= 0 && slice < MAX_SLICERS);
// -e option can be used to artificially introduce the desired // -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. * 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); dw_printf ("\nfound flag, channel %d.%d, %d bits in frame\n", chan, subchan, rrbb_get_len(H->rrbb) - 1);
#endif #endif
if (rrbb_get_len(H->rrbb) >= MIN_FRAME_LEN * 8) { 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); alevel_t alevel = demod_get_audio_level (chan, subchan);
rrbb_set_audio_level (H->rrbb, alevel); rrbb_set_audio_level (H->rrbb, alevel);
hdlc_rec2_block (H->rrbb); hdlc_rec2_block (H->rrbb);
/* Now owned by someone else who will free it. */ /* 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. */ H->rrbb = rrbb_new (chan, subchan, slice, is_scrambled, H->lfsr, H->prev_descram); /* Allocate a new one. */
} }
else { 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); 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; int old, new;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan <= MAX_SUBCHANS); assert (subchan >= 0 && subchan <= MAX_SUBCHANS);
assert (slice >= 0 && slice < MAX_SLICERS); assert (slice >= 0 && slice < MAX_SLICERS);
assert (state == 0 || state == 1); assert (state == 0 || state == 1);
@ -791,7 +826,7 @@ int hdlc_rec_data_detect_any (int chan)
{ {
int sc; int sc;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
for (sc = 0; sc < num_subchan[chan]; sc++) { for (sc = 0; sc < num_subchan[chan]; sc++) {
if (composite_dcd[chan][sc] != 0) if (composite_dcd[chan][sc] != 0)

View File

@ -1,12 +1,22 @@
/* hdlc_rec.h */
#include <stdint.h> // int64_t
#include "audio.h" #include "audio.h"
void hdlc_rec_init (struct audio_s *pa); 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 (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. */ /* Provided elsewhere to process a complete frame. */
//void process_rec_frame (int chan, unsigned char *fbuf, int flen, int level); //void process_rec_frame (int chan, unsigned char *fbuf, int flen, int level);

View File

@ -216,6 +216,8 @@ void hdlc_rec2_init (struct audio_s *p_audio_config)
* Purpose: Extract HDLC frame from a stream of bits. * Purpose: Extract HDLC frame from a stream of bits.
* *
* Inputs: block - Handle for bit array. * 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 * Description: The other (original) hdlc decoder took one bit at a time
* right out of the demodulator. * 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 */ /* Let thru even with bad CRC. Of course, it still */
/* needs to be a minimum number of whole octets. */ /* needs to be a minimum number of whole octets. */
ok = try_decode (block, chan, subchan, slice, alevel, retry_cfg, 1); 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 */ } /* 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; retry_cfg.u_bits.sep.bit_idx_c = -1;
#ifdef DEBUG_LATER #ifdef DEBUG_LATER
tstart = dtime_now(); tstart = dtime_monotonic();
dw_printf ("*** Try flipping TWO SEPARATED BITS %d bits\n", len); dw_printf ("*** Try flipping TWO SEPARATED BITS %d bits\n", len);
#endif #endif
len = rrbb_get_len(block); len = rrbb_get_len(block);

View File

@ -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. // 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." // need to break up a long run by "bit stuffing."
// Needs to be array because we could be transmitting // Needs to be array because we could be transmitting
// on multiple channels at the same time. // 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 void send_bit_nrzi (int chan, int b)
{ {
static int output[MAX_CHANS]; static int output[MAX_RADIO_CHANS];
if (b == 0) { if (b == 0) {
output[chan] = ! output[chan]; output[chan] = ! output[chan];

View File

@ -216,8 +216,8 @@ int main (int argc, char *argv[])
memset (&audio_config, 0, sizeof(audio_config)); memset (&audio_config, 0, sizeof(audio_config));
audio_config.adev[0].num_channels = 2; audio_config.adev[0].num_channels = 2;
strlcpy (audio_config.achan[0].mycall, "WB2OSZ-1", sizeof(audio_config.achan[0].mycall)); strlcpy (audio_config.mycall[0], "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[1], "WB2OSZ-2", sizeof(audio_config.achan[0].mycall));
memset (&igate_config, 0, sizeof(igate_config)); 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. // Beacon will be channel -1.
// Client app to ICHANNEL is outside of radio channel range. // Client app to ICHANNEL is outside of radio channel range.
if (chan >= 0 && chan < MAX_CHANS && // in radio channel range if (chan >= 0 && chan < MAX_TOTAL_CHANS && // in radio channel range
save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) { 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? // 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. // 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) { if (s_debug >= 1) {
text_color_set(DW_COLOR_INFO); 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; 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, ",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)); strlcat (msg, ":", sizeof(msg));
@ -1781,7 +1781,7 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan)
{ {
int n; 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. * 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. * 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 ( ! 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. // 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. // 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. */ char dest[AX25_MAX_ADDR_LEN]; /* Destination field. */
ax25_get_addr_with_ssid (pp3, AX25_DESTINATION, dest); ax25_get_addr_with_ssid (pp3, AX25_DESTINATION, dest);
snprintf (payload, sizeof(payload), "%s>%s,TCPIP,%s*:%s", 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 #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)) { if (ig_to_tx_allow (pp3, to_chan)) {
char radio [2400]; char radio [2400];
snprintf (radio, sizeof(radio), "%s>%s%d%d%s:}%s", 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, APP_TOCALL, MAJOR_VERSION, MINOR_VERSION,
save_igate_config_p->tx_via, save_igate_config_p->tx_via,
payload); payload);

View File

@ -69,7 +69,7 @@ struct il2p_context_s {
int corrected; // Number of symbols corrected by RS FEC. 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]; struct il2p_context_s *F = il2p_context[chan][subchan][slice];
if (F == NULL) { if (F == NULL) {
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
assert (slice >= 0 && slice < MAX_SLICERS); assert (slice >= 0 && slice < MAX_SLICERS);
F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof (struct il2p_context_s)); 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) { if (pp != NULL) {
alevel_t alevel = demod_get_audio_level (chan, subchan); alevel_t alevel = demod_get_audio_level (chan, subchan);
retry_t retries = F->corrected; retry_t retries = F->corrected;
int is_fx25 = 1; // FIXME: distinguish fx.25 and IL2P. fec_type_t fec_type = fec_type_il2p;
// Currently this just means that a FEC mode was used.
// TODO: Could we put last 3 arguments in packet object rather than passing around separately? // 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. } // end block for local variables.

View File

@ -30,7 +30,7 @@
#include "gen_tone.h" #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_bytes (int chan, unsigned char *b, int count, int polarity);
static void send_bit (int chan, int b, int polarity); static void send_bit (int chan, int b, int polarity);

View File

@ -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. */ /* Verify that the radio channel number is valid. */
/* Any sort of medium should be OK here. */ /* 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) { && save_audio_config_p->chan_medium[chan] != MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan); 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); 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); 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Are you sure you want such an extreme value for TXDELAY?\n"); 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]); xmit_set_txdelay (chan, kiss_msg[1]);
break; 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) { if (kiss_msg[1] < 5 || kiss_msg[1] > 250) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Are you sure you want such an extreme value for PERSIST?\n"); 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]); xmit_set_persist (chan, kiss_msg[1]);
break; 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) { if (kiss_msg[1] < 2 || kiss_msg[1] > 50) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Are you sure you want such an extreme value for SLOTTIME?\n"); 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]); xmit_set_slottime (chan, kiss_msg[1]);
break; 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); 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); 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); 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 ("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]); xmit_set_txtail (chan, kiss_msg[1]);
break; break;

View File

@ -126,7 +126,7 @@ static struct {
int age; int age;
unsigned int crc; unsigned int crc;
int score; 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 #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); 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); demod_init (save_audio_config_p);
hdlc_rec_init (save_audio_config_p); hdlc_rec_init (save_audio_config_p);
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) { if (save_audio_config_p->chan_medium[chan] == MEDIUM_RADIO) {
if (save_audio_config_p->achan[chan].baud <= 0) { if (save_audio_config_p->achan[chan].baud <= 0) {
text_color_set(DW_COLOR_ERROR); 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) 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; packet_t pp;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
assert (slice >= 0 && slice < 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]; char nmea[256];
ais_to_nmea (fbuf, flen, nmea, sizeof(nmea)); 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]; 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); pp = ax25_from_text (monfmt, 1);
// alevel gets in there somehow making me question why it is passed thru here. // 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) { else if (save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
char monfmt[300]; // EAS SAME message max length is 268 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); pp = ax25_from_text (monfmt, 1);
// alevel gets in there somehow making me question why it is passed thru here. // alevel gets in there somehow making me question why it is passed thru here.

View File

@ -99,7 +99,7 @@ typedef enum token_type_e { TOKEN_AND, TOKEN_OR, TOKEN_NOT, TOKEN_LPAREN, TOKEN_
typedef struct pfstate_s { 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. */ 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. * Inputs: from_chan - Channel packet is coming from.
* to_chan - Channel packet is going to. * 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. * For debug/error messages only.
* *
* filter - String of filter specs and logical operators to combine them. * 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; char *p;
int result; int result;
assert (from_chan >= 0 && from_chan <= MAX_CHANS); assert (from_chan >= 0 && from_chan <= MAX_TOTAL_CHANS);
assert (to_chan >= 0 && to_chan <= MAX_CHANS); assert (to_chan >= 0 && to_chan <= MAX_TOTAL_CHANS);
memset (&pfstate, 0, sizeof(pfstate)); 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) { if (s_debug >= 1) {
text_color_set(DW_COLOR_DEBUG); 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)); 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)); dw_printf (" Packet filter from radio channel %d to IGate returns %s\n", from_chan, bool2text(result));
} }
else if (is_aprs) { else if (is_aprs) {
@ -1478,9 +1478,9 @@ static void print_error (pfstate_t *pf, char *msg)
{ {
char intro[50]; 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]: "); snprintf (intro, sizeof(intro), "filter[IG,IG]: ");
} }
else { else {
@ -1489,7 +1489,7 @@ static void print_error (pfstate_t *pf, char *msg)
} }
else { else {
if (pf->to_chan == MAX_CHANS) { if (pf->to_chan == MAX_TOTAL_CHANS) {
snprintf (intro, sizeof(intro), "filter[%d,IG]: ", pf->from_chan); snprintf (intro, sizeof(intro), "filter[%d,IG]: ", pf->from_chan);
} }
else { else {

View File

@ -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. */ /* Serial port handle or fd. */
/* Could be the same for two channels */ /* Could be the same for two channels */
/* if using both RTS and DTR. */ /* if using both RTS and DTR. */
#if USE_HAMLIB #if USE_HAMLIB
static RIG *rig[MAX_CHANS][NUM_OCTYPES]; static RIG *rig[MAX_RADIO_CHANS][NUM_OCTYPES];
#endif #endif
static char otnames[NUM_OCTYPES][8]; 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])); 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; int ot;
for (ot = 0; ot < NUM_OCTYPES; 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. * 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) { if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; int ot;
@ -906,7 +906,7 @@ void ptt_init (struct audio_s *audio_config_p)
*/ */
using_gpio = 0; using_gpio = 0;
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) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; 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) #if defined(USE_GPIOD)
// 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) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
for (int ot = 0; ot < NUM_OCTYPES; ot++) { for (int ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIOD) { 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. * 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) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; // output control type, PTT, DCD, CON, ... 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__) ) #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) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
@ -1051,7 +1051,7 @@ void ptt_init (struct audio_s *audio_config_p)
#endif /* x86 Linux */ #endif /* x86 Linux */
#ifdef USE_HAMLIB #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) { if (save_audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
@ -1163,7 +1163,7 @@ void ptt_init (struct audio_s *audio_config_p)
#if USE_CM108 #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) { if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
int ot; 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. */ /* Why doesn't it transmit? Probably forgot to specify PTT option. */
for (ch=0; ch<MAX_CHANS; ch++) { for (ch=0; ch<MAX_RADIO_CHANS; ch++) {
if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) { if (audio_config_p->chan_medium[ch] == MEDIUM_RADIO) {
if(audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_NONE) { if(audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_NONE) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
@ -1251,14 +1251,14 @@ void ptt_set (int ot, int chan, int ptt_signal)
int ptt2 = ptt_signal; int ptt2 = ptt_signal;
assert (ot >= 0 && ot < NUM_OCTYPES); assert (ot >= 0 && ot < NUM_OCTYPES);
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
if (ptt_debug_level >= 1) { if (ptt_debug_level >= 1) {
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("%s %d = %d\n", otnames[ot], chan, ptt_signal); 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) { if ( save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); 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) int get_input (int it, int chan)
{ {
assert (it >= 0 && it < NUM_ICTYPES); 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) { if ( save_audio_config_p->chan_medium[chan] != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -1559,7 +1559,7 @@ void ptt_term (void)
{ {
int n; 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) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; 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) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
@ -1586,7 +1586,7 @@ void ptt_term (void)
#ifdef USE_HAMLIB #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) { if (save_audio_config_p->chan_medium[n] == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {

View File

@ -108,6 +108,7 @@
#include "dtmf.h" #include "dtmf.h"
#include "aprs_tt.h" #include "aprs_tt.h"
#include "ax25_link.h" #include "ax25_link.h"
#include "ring.h"
#if __WIN32__ #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? // Try to re-init the audio device a couple times before giving up?
text_color_set(DW_COLOR_ERROR); 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); exit (1);
} }

View File

@ -83,7 +83,7 @@ rrbb_t rrbb_new (int chan, int subchan, int slice, int is_scrambled, int descram
{ {
rrbb_t result; rrbb_t result;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
assert (subchan >= 0 && subchan < MAX_SUBCHANS); assert (subchan >= 0 && subchan < MAX_SUBCHANS);
assert (slice >= 0 && slice < MAX_SLICERS); assert (slice >= 0 && slice < MAX_SLICERS);
@ -333,7 +333,7 @@ int rrbb_get_chan (rrbb_t b)
assert (b->magic1 == MAGIC1); assert (b->magic1 == MAGIC1);
assert (b->magic2 == MAGIC2); assert (b->magic2 == MAGIC2);
assert (b->chan >= 0 && b->chan < MAX_CHANS); assert (b->chan >= 0 && b->chan < MAX_RADIO_CHANS);
return (b->chan); return (b->chan);
} }

View File

@ -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. * 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("\nInvalid port number, %d, in command '%c', from AGW client application %d.\n", dw_printf ("\nInvalid port number, %d, in command '%c', from AGW client application %d.\n",
cmd.hdr.portx, cmd.hdr.datakind, client); 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. // No other place cares about total number.
count = 0; count = 0;
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_TOTAL_CHANS; j++) {
if (save_audio_config_p->chan_medium[j] == MEDIUM_RADIO || if (save_audio_config_p->chan_medium[j] == MEDIUM_RADIO ||
save_audio_config_p->chan_medium[j] == MEDIUM_IGATE || save_audio_config_p->chan_medium[j] == MEDIUM_IGATE ||
save_audio_config_p->chan_medium[j] == MEDIUM_NETTNC) { 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); snprintf (reply.info, sizeof(reply.info), "%d;", count);
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_TOTAL_CHANS; j++) {
switch (save_audio_config_p->chan_medium[j]) { switch (save_audio_config_p->chan_medium[j]) {
@ -1850,7 +1850,7 @@ static THREAD_F cmd_listen_thread (void *arg)
// Connected mode can only be used with internal modems. // 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; ok = 1;
dlq_register_callsign (cmd.hdr.call_from, chan, client); 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. // 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); dlq_unregister_callsign (cmd.hdr.call_from, chan, client);
} }
else { else {
@ -2066,7 +2066,7 @@ static THREAD_F cmd_listen_thread (void *arg)
reply.hdr.data_len_NETLE = host2netle(4); reply.hdr.data_len_NETLE = host2netle(4);
int n = 0; 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. // Count both normal and expedited in transmit queue for given channel.
n = tq_count (cmd.hdr.portx, -1, "", "", 0); n = tq_count (cmd.hdr.portx, -1, "", "", 0);
} }

View File

@ -71,7 +71,7 @@
#define T_NUM_ANALOG 5 /* Number of analog channels. */ #define T_NUM_ANALOG 5 /* Number of analog channels. */
#define T_NUM_DIGITAL 8 /* Number of digital 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. */ #define MAGIC1 0x5a1111a5 /* For checking storage allocation problems. */

View File

@ -285,7 +285,7 @@ int main (int argc, char *argv[])
setlinebuf (stdout); setlinebuf (stdout);
#endif #endif
start_dtime = dtime_now(); start_dtime = dtime_monotonic();
/* /*
* Extract command line args. * 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 * and sent to a common function to check that they
* all arrived in order. * 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 * Description: Perform any necessary configuration for the TNC then wait
* for responses and process them. * for responses and process them.
@ -859,7 +859,7 @@ static void * tnc_thread_net (void *arg)
* What did we get? * What did we get?
*/ */
dnow = dtime_now(); dnow = dtime_monotonic();
switch (mon_cmd.datakind) { 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 * and sent to a common function to check that they
* all arrived in order. * 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 * Description: Perform any necessary configuration for the TNC then wait
* for responses and process them. * for responses and process them.
@ -1038,12 +1038,12 @@ static void * tnc_thread_serial (void *arg)
done = 1; done = 1;
} }
else if (ch == XOFF) { else if (ch == XOFF) {
double dnow = dtime_now(); double dnow = dtime_monotonic();
printf("%*s[R %.3f] <XOFF>\n", my_index*column_width, "", dnow-start_dtime); printf("%*s[R %.3f] <XOFF>\n", my_index*column_width, "", dnow-start_dtime);
busy[my_index] = 1; busy[my_index] = 1;
} }
else if (ch == XON) { else if (ch == XON) {
double dnow = dtime_now(); double dnow = dtime_monotonic();
printf("%*s[R %.3f] <XON>\n", my_index*column_width, "", dnow-start_dtime); printf("%*s[R %.3f] <XON>\n", my_index*column_width, "", dnow-start_dtime);
busy[my_index] = 0; busy[my_index] = 0;
} }
@ -1070,7 +1070,7 @@ static void * tnc_thread_serial (void *arg)
if (len > 0) { 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); 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) 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); 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) 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); 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) 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); 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) 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); 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 { else {
// The assumption is that we are in CONVERS mode. // 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. int timeout = 600; // 60 sec. I've seen it take more than 20.
while (timeout > 0 && busy[from]) { while (timeout > 0 && busy[from]) {

View File

@ -52,10 +52,10 @@
#include "dedupe.h" #include "dedupe.h"
#include "igate.h" #include "igate.h"
#include "dtime_now.h" #include "dtime_now.h"
#include "nettnc.h"
static packet_t queue_head[MAX_RADIO_CHANS][TQ_NUM_PRIO]; /* Head of linked list for each queue. */
static packet_t queue_head[MAX_CHANS][TQ_NUM_PRIO]; /* Head of linked list for each queue. */
static dw_mutex_t tq_mutex; /* Critical section for updating queues. */ 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__ #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 #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 #endif
@ -128,7 +128,7 @@ void tq_init (struct audio_s *audio_config_p)
save_audio_config_p = audio_config_p; save_audio_config_p = audio_config_p;
for (c=0; c<MAX_CHANS; c++) { for (c=0; c<MAX_RADIO_CHANS; c++) {
for (p=0; p<TQ_NUM_PRIO; p++) { for (p=0; p<TQ_NUM_PRIO; p++) {
queue_head[c][p] = NULL; queue_head[c][p] = NULL;
} }
@ -147,7 +147,7 @@ void tq_init (struct audio_s *audio_config_p)
#if __WIN32__ #if __WIN32__
for (c = 0; c < MAX_CHANS; c++) { for (c = 0; c < MAX_RADIO_CHANS; c++) {
if (audio_config_p->chan_medium[c] == MEDIUM_RADIO) { if (audio_config_p->chan_medium[c] == MEDIUM_RADIO) {
@ -164,7 +164,7 @@ void tq_init (struct audio_s *audio_config_p)
#else #else
int err; int err;
for (c = 0; c < MAX_CHANS; c++) { for (c = 0; c < MAX_RADIO_CHANS; c++) {
xmit_thread_is_waiting[c] = 0; xmit_thread_is_waiting[c] = 0;
@ -199,6 +199,9 @@ void tq_init (struct audio_s *audio_config_p)
* New in 1.7: * New in 1.7:
* Channel can be assigned to IGate rather than a radio. * 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 * prio - Priority, use TQ_PRIO_0_HI for digipeated or
* TQ_PRIO_1_LO for normal. * TQ_PRIO_1_LO for normal.
* *
@ -252,10 +255,13 @@ void tq_append (int chan, int prio, packet_t pp)
#endif #endif
// New in 1.7 - A channel can be assigned to the IGate rather than a radio. // 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 #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. char ts[100]; // optional time stamp.
@ -274,21 +280,39 @@ void tq_append (int chan, int prio, packet_t pp)
unsigned char *pinfo; unsigned char *pinfo;
int info_len = ax25_get_info (pp, &pinfo); int info_len = ax25_get_info (pp, &pinfo);
text_color_set(DW_COLOR_XMIT); 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); ax25_delete(pp);
return; return;
} }
#endif #endif
// Normal case - put in queue for radio transmission. // Normal case - put in queue for radio transmission.
// Error if trying to transmit to a radio channel which was not configured. // 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); 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"); 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 #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. // Connected mode is allowed only with internal modems.
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan);
@ -648,7 +672,7 @@ void lm_seize_request (int chan)
#endif #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. // Connected mode is allowed only with internal modems.
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("ERROR - Request to transmit on invalid radio channel %d.\n", chan); 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); text_color_set(DW_COLOR_DEBUG);
dw_printf ("tq_wait_while_empty (%d) : enter critical section\n", chan); dw_printf ("tq_wait_while_empty (%d) : enter critical section\n", chan);
#endif #endif
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
dw_mutex_lock (&tq_mutex); dw_mutex_lock (&tq_mutex);
@ -944,7 +968,7 @@ static int tq_is_empty (int chan)
{ {
int p; int p;
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_RADIO_CHANS);
for (p=0; p<TQ_NUM_PRIO; p++) { for (p=0; p<TQ_NUM_PRIO; p++) {
@ -1001,7 +1025,7 @@ int tq_count (int chan, int prio, char *source, char *dest, int bytes)
// Array bounds check. FIXME: TODO: should have internal error instead of dying. // Array bounds check. FIXME: TODO: should have internal error instead of dying.
if (chan < 0 || chan >= 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); text_color_set(DW_COLOR_DEBUG);
dw_printf ("INTERNAL ERROR - tq_count(%d, %d, \"%s\", \"%s\", %d)\n", chan, prio, source, dest, bytes); dw_printf ("INTERNAL ERROR - tq_count(%d, %d, \"%s\", \"%s\", %d)\n", chan, prio, source, dest, bytes);
return (0); return (0);

View File

@ -819,10 +819,10 @@ static void xmit_object_report (int i, int first_time)
*/ */
if (save_tt_config_p->obj_xmit_chan >= 0) { 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 { 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, ">", sizeof(stemp));
strlcat (stemp, APP_TOCALL, 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)); 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. */ /* Fake TT gateway config. */

View File

@ -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 */ /* slot time delay. Transmit if a random number */
/* in range of 0 - 255 <= persist value. */ /* in range of 0 - 255 <= persist value. */
/* Otherwise wait another slot time and try again. */ /* 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. */ /* 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 */ /* are done sending the data. This is to avoid */
/* dropping PTT too soon and chopping off the end */ /* dropping PTT too soon and chopping off the end */
/* of the frame. Again 10 mS units. */ /* 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 */ /* Often called baud rate which is equivalent for */
/* 1200 & 9600 cases but could be different with other */ /* 1200 & 9600 cases but could be different with other */
/* modulation techniques. */ /* modulation techniques. */
@ -211,11 +211,11 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet)
int ad; int ad;
#if __WIN32__ #if __WIN32__
HANDLE xmit_th[MAX_CHANS]; HANDLE xmit_th[MAX_RADIO_CHANS];
#else #else
//pthread_attr_t attr; //pthread_attr_t attr;
//struct sched_param sp; //struct sched_param sp;
pthread_t xmit_tid[MAX_CHANS]; pthread_t xmit_tid[MAX_RADIO_CHANS];
#endif #endif
//int e; //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? * TODO1.2: Any reason to use global config rather than making a copy?
*/ */
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_RADIO_CHANS; j++) {
xmit_bits_per_sec[j] = p_modem->achan[j].baud; xmit_bits_per_sec[j] = p_modem->achan[j].baud;
xmit_slottime[j] = p_modem->achan[j].slottime; xmit_slottime[j] = p_modem->achan[j].slottime;
xmit_persist[j] = p_modem->achan[j].persist; 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. // underrun on the audio output device.
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_RADIO_CHANS; j++) {
if (p_modem->chan_medium[j] == MEDIUM_RADIO) { if (p_modem->chan_medium[j] == MEDIUM_RADIO) {
#if __WIN32__ #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) 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; xmit_txdelay[channel] = value;
} }
} }
void xmit_set_persist (int channel, int 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; xmit_persist[channel] = value;
} }
} }
void xmit_set_slottime (int channel, int 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; xmit_slottime[channel] = value;
} }
} }
void xmit_set_txtail (int channel, int 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; xmit_txtail[channel] = value;
} }
} }
void xmit_set_fulldup (int channel, int 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; xmit_fulldup[channel] = value;
} }
} }