Replace channel valid boolean with more versatile enum.

This commit is contained in:
wb2osz 2019-05-13 06:25:12 -04:00
parent d6ea439f98
commit ad12fa86d6
19 changed files with 262 additions and 115 deletions

View File

@ -564,8 +564,10 @@ int main (int argc, char *argv[])
my_audio_config.adev[0].bits_per_sample = format.wbitspersample; my_audio_config.adev[0].bits_per_sample = format.wbitspersample;
my_audio_config.adev[0].num_channels = format.nchannels; my_audio_config.adev[0].num_channels = format.nchannels;
my_audio_config.achan[0].valid = 1; my_audio_config.achan[0].medium = MEDIUM_RADIO;
if (format.nchannels == 2) my_audio_config.achan[1].valid = 1; if (format.nchannels == 2) {
my_audio_config.achan[1].medium = MEDIUM_RADIO;
}
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
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",

25
audio.h
View File

@ -53,6 +53,13 @@ typedef enum retry_e {
RETRY_INVERT_TWO_SEP=4, RETRY_INVERT_TWO_SEP=4,
RETRY_MAX = 5} retry_t; RETRY_MAX = 5} retry_t;
// Type of communication medium associated with the channel.
enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use.
MEDIUM_RADIO, // Internal modem for radio.
MEDIUM_IGATE, // Access IGate as ordinary channel.
MEDIUM_NETTNC }; // Remote network TNC. (possible future)
typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t; typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t;
@ -102,19 +109,31 @@ struct audio_s {
/* Command line option uses "strftime" format string. */ /* Command line option uses "strftime" format string. */
/* Properties for each audio channel, common to receive and transmit. */ /* Properties for each channel, common to receive and transmit. */
/* Can be different for each radio channel. */ /* Can be different for each radio channel. */
/* originally a "channel" was always connected to an internal modem. */
/* In version 1.6, this is generalized so that a channel (as seen by client application) */
/* can be connected to something else. Initially, this will allow application */
/* access to the IGate. Later we might have network TNCs or other internal functions. */
struct achan_param_s { struct achan_param_s {
int valid; /* Is this channel valid? */ // Originally there was a boolean, called "valid", to indicate that the
// channel is valid. This has been replaced with the new "medium" which
// will allow channels to correspond to things other than internal modems.
enum medium_e medium; // MEDIUM_NONE for invalid.
// MEDIUM_RADIO for internal modem. (only possibility earlier)
// MEDIUM_IGATE allows application access to IGate.
char mycall[AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */ char mycall[AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */
/* Could all be the same or different. */ /* Could all be the same or different. */
enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF } modem_type; enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF, MODEM_16_QAM, MODEM_64_QAM } modem_type;
/* Usual AFSK. */ /* Usual AFSK. */
/* Baseband signal. Not used yet. */ /* Baseband signal. Not used yet. */

View File

@ -183,7 +183,8 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */ if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
if (g_modem_config_p->achan[chan].valid) { if (g_modem_config_p->achan[chan].medium == MEDIUM_RADIO ||
g_modem_config_p->achan[chan].medium == MEDIUM_NETTNC) {
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 && if (strlen(g_modem_config_p->achan[chan].mycall) > 0 &&
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 && strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 &&

View File

@ -129,8 +129,10 @@ void cdigipeater (int from_chan, packet_t pp)
{ {
int to_chan; int to_chan;
// Connected mode is allowed only for channels with internal modem.
// It probably wouldn't matter for digipeating but let's keep that rule simple and consistent.
if ( from_chan < 0 || from_chan >= MAX_CHANS || ( ! save_audio_config_p->achan[from_chan].valid) ) { if ( from_chan < 0 || from_chan >= MAX_CHANS || save_audio_config_p->achan[from_chan].medium != MEDIUM_RADIO) {
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;

114
config.c
View File

@ -757,8 +757,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
for (channel=0; channel<MAX_CHANS; channel++) { for (channel=0; channel<MAX_CHANS; channel++) {
int ot, it; int ot, it;
p_audio_config->achan[channel].valid = 0; /* One or both channels will be */ p_audio_config->achan[channel].medium = MEDIUM_NONE; /* One or both channels will be */
/* set to valid when corresponding */ /* set to radio when corresponding */
/* audio device is defined. */ /* audio device is defined. */
p_audio_config->achan[channel].modem_type = MODEM_AFSK; p_audio_config->achan[channel].modem_type = MODEM_AFSK;
p_audio_config->achan[channel].mark_freq = DEFAULT_MARK_FREQ; /* -m option */ p_audio_config->achan[channel].mark_freq = DEFAULT_MARK_FREQ; /* -m option */
@ -803,8 +803,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
/* First channel should always be valid. */ /* First channel should always be valid. */
/* If there is no ADEVICE, it uses default device in mono. */ /* If there is no ADEVICE, it uses default device in mono. */
p_audio_config->achan[0].valid = 1; p_audio_config->achan[0].medium = MEDIUM_RADIO;
memset (p_digi_config, 0, sizeof(struct digi_config_s)); // APRS digipeater memset (p_digi_config, 0, sizeof(struct digi_config_s)); // APRS digipeater
p_digi_config->dedupe_time = DEFAULT_DEDUPE; p_digi_config->dedupe_time = DEFAULT_DEDUPE;
@ -1018,7 +1017,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->adev[adevice].defined = 1; p_audio_config->adev[adevice].defined = 1;
/* First channel of device is valid. */ /* First channel of device is valid. */
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1; p_audio_config->achan[ADEVFIRSTCHAN(adevice)].medium = MEDIUM_RADIO;
strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in)); strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out)); strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
@ -1073,7 +1072,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->adev[adevice].defined = 1; p_audio_config->adev[adevice].defined = 1;
/* First channel of device is valid. */ /* First channel of device is valid. */
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1; p_audio_config->achan[ADEVFIRSTCHAN(adevice)].medium = MEDIUM_RADIO;
strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in)); strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
} }
@ -1100,7 +1099,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
p_audio_config->adev[adevice].defined = 1; p_audio_config->adev[adevice].defined = 1;
/* First channel of device is valid. */ /* First channel of device is valid. */
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1; p_audio_config->achan[ADEVFIRSTCHAN(adevice)].medium = MEDIUM_RADIO;
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out)); strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
} }
@ -1147,9 +1146,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
/* Set valid channels depending on mono or stereo. */ /* Set valid channels depending on mono or stereo. */
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1; p_audio_config->achan[ADEVFIRSTCHAN(adevice)].medium = MEDIUM_RADIO;
if (n == 2) { if (n == 2) {
p_audio_config->achan[ADEVFIRSTCHAN(adevice) + 1].valid = 1; p_audio_config->achan[ADEVFIRSTCHAN(adevice) + 1].medium = MEDIUM_RADIO;
} }
} }
else { else {
@ -1179,7 +1178,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
channel = n; channel = n;
if ( ! p_audio_config->achan[n].valid) { if (p_audio_config->achan[n].medium != MEDIUM_RADIO) {
if ( ! p_audio_config->adev[ACHAN2ADEV(n)].defined) { if ( ! p_audio_config->adev[ACHAN2ADEV(n)].defined) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -2202,7 +2201,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[from_chan].valid) {
// Channels specified must be radio channels or network TNCs.
if (p_audio_config->achan[from_chan].medium != MEDIUM_RADIO &&
p_audio_config->achan[from_chan].medium != MEDIUM_NETTNC) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
line, from_chan); line, from_chan);
@ -2222,7 +2225,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[to_chan].valid) {
if (p_audio_config->achan[to_chan].medium != MEDIUM_RADIO &&
p_audio_config->achan[to_chan].medium != MEDIUM_NETTNC) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
line, to_chan); line, to_chan);
@ -2341,7 +2346,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[from_chan].valid) {
// Only radio channels are valid for regenerate.
if (p_audio_config->achan[from_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
line, from_chan); line, from_chan);
@ -2361,7 +2369,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[to_chan].valid) { if (p_audio_config->achan[to_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
line, to_chan); line, to_chan);
@ -2400,10 +2408,17 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[from_chan].valid) {
// For connected mode Link layer, only internal modems should be allowed.
// A network TNC probably would not provide information about channel status.
// There is discussion about this in the document called
// Why-is-9600-only-twice-as-fast-as-1200.pdf
if (p_audio_config->achan[from_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
line, from_chan); line, from_chan);
dw_printf ("Only internal modems can be used for connected mode packet.\n");
continue; continue;
} }
@ -2420,10 +2435,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[to_chan].valid) { if (p_audio_config->achan[to_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
line, to_chan); line, to_chan);
dw_printf ("Only internal modems can be used for connected mode packet.\n");
continue; continue;
} }
@ -2468,11 +2484,24 @@ void config_init (char *fname, struct audio_s *p_audio_config,
* to include IGate client side. Maybe it should be * to include IGate client side. Maybe it should be
* renamed AFILTER to make it clearer after adding CFILTER. * renamed AFILTER to make it clearer after adding CFILTER.
* *
* Both internal modem and NET TNC channels allowed here.
* "IG" should be used for the IGate, NOT a virtual channel
* assigned to it.
*
* CFILTER - Similar for connected moded digipeater. * CFILTER - Similar for connected moded digipeater.
* *
* Only internal modems can be used because they provide
* information about radio channel status.
* A remote network TNC might not provide the necessary
* status for correct operation.
* There is discussion about this in the document called
* Why-is-9600-only-twice-as-fast-as-1200.pdf
*
* IGFILTER - APRS-IS (IGate) server side - completely diffeent. * IGFILTER - APRS-IS (IGate) server side - completely diffeent.
* I'm not happy with this name because IG sounds like IGate * I'm not happy with this name because IG sounds like IGate
* which is really the client side. More comments later. * which is really the client side. More comments later.
* Maybe it should be called subscribe or something like that
* because the subscriptions are cummulative.
*/ */
else if (strcasecmp(t, "FILTER") == 0) { else if (strcasecmp(t, "FILTER") == 0) {
@ -2497,12 +2526,19 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
if ( ! p_audio_config->achan[from_chan].valid) { if (p_audio_config->achan[from_chan].medium != MEDIUM_RADIO &&
p_audio_config->achan[from_chan].medium != MEDIUM_NETTNC) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
line, from_chan); line, from_chan);
continue; continue;
} }
if (p_audio_config->achan[from_chan].medium == MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Use 'IG' rather than %d for FROM-channel.\n",
line, from_chan);
continue;
}
} }
t = split(NULL,0); t = split(NULL,0);
@ -2522,12 +2558,19 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[to_chan].valid) { if (p_audio_config->achan[to_chan].medium != MEDIUM_RADIO &&
p_audio_config->achan[to_chan].medium != MEDIUM_NETTNC) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
line, to_chan); line, to_chan);
continue; continue;
} }
if (p_audio_config->achan[to_chan].medium == MEDIUM_IGATE) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: Use 'IG' rather than %d for TO-channel.\n",
line, to_chan);
continue;
}
} }
t = split(NULL,1); /* Take rest of line including spaces. */ t = split(NULL,1); /* Take rest of line including spaces. */
@ -2578,7 +2621,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
if ( ! p_audio_config->achan[from_chan].valid) { // DO NOT allow a network TNC here.
// Must be internal modem to have necessary knowledge about channel status.
if (p_audio_config->achan[from_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n",
line, from_chan); line, from_chan);
@ -2599,7 +2645,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[to_chan].valid) { if (p_audio_config->achan[to_chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", dw_printf ("Config file, line %d: TO-channel %d is not valid.\n",
line, to_chan); line, to_chan);
@ -3756,7 +3802,11 @@ void config_init (char *fname, struct audio_s *p_audio_config,
MAX_CHANS-1, line); MAX_CHANS-1, line);
continue; continue;
} }
if ( ! p_audio_config->achan[r].valid) {
// I suppose we need internal modem channel here.
// otherwise a DTMF decoder would not be available.
if (p_audio_config->achan[r].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TTOBJ DTMF receive channel %d is not valid.\n", dw_printf ("Config file, line %d: TTOBJ DTMF receive channel %d is not valid.\n",
line, r); line, r);
@ -3782,7 +3832,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
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_CHANS-1, line);
x = -1; x = -1;
} }
else if ( ! p_audio_config->achan[x].valid) { else if (p_audio_config->achan[x].medium != MEDIUM_RADIO &&
p_audio_config->achan[x].medium != MEDIUM_NETTNC) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file, line %d: TTOBJ transmit channel %d is not valid.\n", line, x); dw_printf ("Config file, line %d: TTOBJ transmit channel %d is not valid.\n", line, x);
x = -1; x = -1;
@ -4970,7 +5021,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
} }
if (p_audio_config->achan[i].valid && strlen(p_igate_config->t2_login) > 0) { /* When IGate is enabled, all radio channels must have a callsign associated. */
if (strlen(p_igate_config->t2_login) > 0 &&
(p_audio_config->achan[i].medium == MEDIUM_RADIO || p_audio_config->achan[i].medium == 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->achan[i].mycall, "NOCALL") == 0 || strcmp(p_audio_config->achan[i].mycall, "N0CALL") == 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -4994,10 +5048,12 @@ void config_init (char *fname, struct audio_s *p_audio_config,
// Apply default IS>RF IGate filter if none specified. New in 1.4. // Apply default IS>RF IGate filter if none specified. New in 1.4.
// 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) {
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_CHANS; j++) {
if (p_audio_config->achan[j].valid && strlen(p_igate_config->t2_login) > 0) { if (p_audio_config->achan[j].medium == MEDIUM_RADIO || p_audio_config->achan[j].medium == MEDIUM_NETTNC) {
if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) { if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) {
p_digi_config->filter_str[MAX_CHANS][j] = strdup("i/30"); p_digi_config->filter_str[MAX_CHANS][j] = strdup("i/60");
}
} }
} }
} }
@ -5085,7 +5141,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->achan[n].valid) { if ( n < 0 || n >= MAX_CHANS || p_audio_config->achan[n].medium == MEDIUM_NONE) {
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);
continue; continue;
@ -5095,7 +5151,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->achan[n].valid) { if ( n < 0 || n >= MAX_CHANS || p_audio_config->achan[n].medium == MEDIUM_NONE) {
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);
continue; continue;
@ -5106,7 +5162,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->achan[n].valid) { if ( n < 0 || n >= MAX_CHANS || p_audio_config->achan[n].medium == MEDIUM_NONE) {
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);
continue; continue;
@ -5318,7 +5374,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->achan[b->sendto_chan].valid) { if ( b->sendto_chan < 0 || b->sendto_chan >= MAX_CHANS || p_audio_config->achan[b->sendto_chan].medium == MEDIUM_NONE) {
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);
return (0); return (0);

View File

@ -108,7 +108,7 @@ int demod_init (struct audio_s *pa)
for (chan = 0; chan < MAX_CHANS; chan++) { for (chan = 0; chan < MAX_CHANS; chan++) {
if (save_audio_config_p->achan[chan].valid) { if (save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
char *p; char *p;
char just_letters[16]; char just_letters[16];

View File

@ -149,11 +149,15 @@ void digipeater (int from_chan, packet_t pp)
// dw_printf ("digipeater()\n"); // dw_printf ("digipeater()\n");
assert (from_chan >= 0 && from_chan < MAX_CHANS);
if ( ! save_audio_config_p->achan[from_chan].valid) {
// Network TNC is OK for UI frames where we don't care about timing.
if ( from_chan < 0 || from_chan >= MAX_CHANS ||
(save_audio_config_p->achan[from_chan].medium != MEDIUM_RADIO &&
save_audio_config_p->achan[from_chan].medium != MEDIUM_NETTNC)) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("digipeater: Did not expect to receive on invalid channel %d.\n", from_chan); dw_printf ("APRS digipeater: Did not expect to receive on invalid channel %d.\n", from_chan);
} }

View File

@ -24,13 +24,14 @@
* *
* Purpose: Main program for "Dire Wolf" which includes: * Purpose: Main program for "Dire Wolf" which includes:
* *
* AFSK modem using the "sound card." * Various DSP modems using the "sound card."
* AX.25 encoder/decoder. * AX.25 encoder/decoder.
* APRS data encoder / decoder. * APRS data encoder / decoder.
* APRS digipeater. * APRS digipeater.
* KISS TNC emulator. * KISS TNC emulator.
* APRStt (touch tone input) gateway * APRStt (touch tone input) gateway
* Internet Gateway (IGate) * Internet Gateway (IGate)
* Ham Radio of Things - IoT with Ham Radio
* *
* *
*---------------------------------------------------------------*/ *---------------------------------------------------------------*/
@ -630,7 +631,7 @@ int main (int argc, char *argv[])
if (n_opt != 0) { if (n_opt != 0) {
audio_config.adev[0].num_channels = n_opt; audio_config.adev[0].num_channels = n_opt;
if (n_opt == 2) { if (n_opt == 2) {
audio_config.achan[1].valid = 1; audio_config.achan[1].medium = MEDIUM_RADIO;
} }
} }

2
dtmf.c
View File

@ -529,7 +529,7 @@ int main ()
memset (&my_audio_config, 0, sizeof(my_audio_config)); memset (&my_audio_config, 0, sizeof(my_audio_config));
my_audio_config.adev[ACHAN2ADEV(c)].defined = 1; my_audio_config.adev[ACHAN2ADEV(c)].defined = 1;
my_audio_config.adev[ACHAN2ADEV(c)].samples_per_sec = 44100; my_audio_config.adev[ACHAN2ADEV(c)].samples_per_sec = 44100;
my_audio_config.achan[c].valid = 1; my_audio_config.achan[c].medium = MEDIUM_RADIO;
my_audio_config.achan[c].dtmf_decode = DTMF_DECODE_ON; my_audio_config.achan[c].dtmf_decode = DTMF_DECODE_ON;
dtmf_init(&my_audio_config, 50); dtmf_init(&my_audio_config, 50);

View File

@ -183,7 +183,7 @@ int main(int argc, char **argv)
modem.achan[chan].baud = DEFAULT_BAUD; /* -b option */ modem.achan[chan].baud = DEFAULT_BAUD; /* -b option */
} }
modem.achan[0].valid = 1; modem.achan[0].medium = MEDIUM_RADIO;
/* /*
@ -402,7 +402,7 @@ int main(int argc, char **argv)
case '2': /* -2 for 2 channels of sound */ case '2': /* -2 for 2 channels of sound */
modem.adev[0].num_channels = 2; modem.adev[0].num_channels = 2;
modem.achan[1].valid = 1; modem.achan[1].medium = MEDIUM_RADIO;
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf("2 channels of sound rather than 1.\n"); dw_printf("2 channels of sound rather than 1.\n");
break; break;

View File

@ -164,7 +164,7 @@ int gen_tone_init (struct audio_s *audio_config_p, int amp, int gen_packets)
for (chan = 0; chan < MAX_CHANS; chan++) { for (chan = 0; chan < MAX_CHANS; chan++) {
if (audio_config_p->achan[chan].valid) { if (audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
int a = ACHAN2ADEV(chan); int a = ACHAN2ADEV(chan);
@ -291,8 +291,12 @@ void tone_gen_put_bit (int chan, int dat)
int a = ACHAN2ADEV(chan); /* device for channel. */ int a = ACHAN2ADEV(chan); /* device for channel. */
assert (save_audio_config_p != NULL); assert (save_audio_config_p != NULL);
assert (save_audio_config_p->achan[chan].valid);
if (save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel %d for tone generation.\n", chan);
return;
}
if (dat < 0) { if (dat < 0) {
/* Hack to test receive PLL recovery. */ /* Hack to test receive PLL recovery. */

View File

@ -33,6 +33,7 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
//#include "tune.h"
#include "demod.h" #include "demod.h"
#include "hdlc_rec.h" #include "hdlc_rec.h"
#include "hdlc_rec2.h" #include "hdlc_rec2.h"
@ -47,7 +48,6 @@
//#define TEST 1 /* Define for unit testing. */ //#define TEST 1 /* Define for unit testing. */
//#define DEBUG3 1 /* monitor the data detect signal. */ //#define DEBUG3 1 /* monitor the data detect signal. */
@ -142,7 +142,7 @@ void hdlc_rec_init (struct audio_s *pa)
for (ch = 0; ch < MAX_CHANS; ch++) for (ch = 0; ch < MAX_CHANS; ch++)
{ {
if (pa->achan[ch].valid) { if (pa->achan[ch].medium == MEDIUM_RADIO) {
num_subchan[ch] = pa->achan[ch].num_subchan; num_subchan[ch] = pa->achan[ch].num_subchan;
@ -230,13 +230,16 @@ void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled,
dbit = (descram == H->prev_descram); dbit = (descram == H->prev_descram);
H->prev_descram = descram; H->prev_descram = descram;
H->prev_raw = raw; } H->prev_raw = raw;
}
else { else {
dbit = (raw == H->prev_raw); dbit = (raw == H->prev_raw);
H->prev_raw = raw; H->prev_raw = raw;
} }
/* /*
* Octets are sent LSB first. * Octets are sent LSB first.
* Shift the most recent 8 bits thru the pattern detector. * Shift the most recent 8 bits thru the pattern detector.
@ -289,9 +292,9 @@ void hdlc_rec_bit (int chan, int subchan, int slice, int raw, int is_scrambled,
//if (H->flag4_det == 0x7e7e7e7e) { //if (H->flag4_det == 0x7e7e7e7e) {
if ((H->flag4_det & 0xffffff00) == 0x7e7e7e00) { if ((H->flag4_det & 0xffffff00) == 0x7e7e7e00) { // three seems good
//if ((H->flag4_det & 0xffff0000) == 0x7e7e0000) { //if ((H->flag4_det & 0xffff0000) == 0x7e7e0000) { // two in a row
//if ((H->flag4_det & 0xff000000) == 0x7e000000) { // single flag
if ( ! H->data_detect) { if ( ! H->data_detect) {
H->data_detect = 1; H->data_detect = 1;
dcd_change (chan, subchan, slice, 1); dcd_change (chan, subchan, slice, 1);

View File

@ -586,8 +586,9 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
/* Verify that the port (channel) number is valid. */ /* Verify that the port (channel) number is valid. */
/* Any sort of medium should be OK here. */
if (port < 0 || port >= MAX_CHANS || ! save_audio_config_p->achan[port].valid) { if (port < 0 || port >= MAX_CHANS || save_audio_config_p->achan[port].medium == MEDIUM_NONE) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid transmit channel %d from KISS client app.\n", port); dw_printf ("Invalid transmit channel %d from KISS client app.\n", port);
dw_printf ("\n"); dw_printf ("\n");

19
morse.c
View File

@ -312,7 +312,12 @@ static void morse_tone (int chan, int tu, int wpm) {
int f1_change_per_sample; // How much to advance phase for each audio sample. int f1_change_per_sample; // How much to advance phase for each audio sample.
assert (save_audio_config_p->achan[chan].valid);
if (save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel %d for sending Morse Code.\n", chan);
return;
}
tone_phase = 0; tone_phase = 0;
@ -360,7 +365,11 @@ static void morse_quiet (int chan, int tu, int wpm) {
int nsamples; int nsamples;
int j; int j;
assert (save_audio_config_p->achan[chan].valid); if (save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel %d for sending Morse Code.\n", chan);
return;
}
nsamples = (int) ((TIME_UNITS_TO_MS(tu,wpm) * (float)save_audio_config_p->adev[a].samples_per_sec / 1000.) + 0.5); nsamples = (int) ((TIME_UNITS_TO_MS(tu,wpm) * (float)save_audio_config_p->adev[a].samples_per_sec / 1000.) + 0.5);
@ -395,7 +404,11 @@ static void morse_quiet_ms (int chan, int ms) {
int nsamples; int nsamples;
int j; int j;
assert (save_audio_config_p->achan[chan].valid); if (save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Invalid channel %d for sending Morse Code.\n", chan);
return;
}
nsamples = (int) ((ms * (float)save_audio_config_p->adev[a].samples_per_sec / 1000.) + 0.5); nsamples = (int) ((ms * (float)save_audio_config_p->adev[a].samples_per_sec / 1000.) + 0.5);

View File

@ -152,7 +152,7 @@ void multi_modem_init (struct audio_s *pa)
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_CHANS; chan++) {
if (save_audio_config_p->achan[chan].valid) { if (save_audio_config_p->achan[chan].medium == 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);
dw_printf("Internal error, chan=%d, %s, %d\n", chan, __FILE__, __LINE__); dw_printf("Internal error, chan=%d, %s, %d\n", chan, __FILE__, __LINE__);

38
ptt.c
View File

@ -725,7 +725,7 @@ void ptt_init (struct audio_s *audio_config_p)
for (ch = 0; ch < MAX_CHANS; ch++) { for (ch = 0; ch < MAX_CHANS; ch++) {
if (audio_config_p->achan[ch].valid) { if (audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
@ -756,7 +756,7 @@ void ptt_init (struct audio_s *audio_config_p)
int j, k; int j, k;
for (j = ch; j >= 0; j--) { for (j = ch; j >= 0; j--) {
if (audio_config_p->achan[j].valid) { if (audio_config_p->achan[j].medium == MEDIUM_RADIO) {
for (k = ((j==ch) ? (ot - 1) : (NUM_OCTYPES-1)); k >= 0; k--) { for (k = ((j==ch) ? (ot - 1) : (NUM_OCTYPES-1)); k >= 0; k--) {
if (strcmp(audio_config_p->achan[ch].octrl[ot].ptt_device,audio_config_p->achan[j].octrl[k].ptt_device) == 0) { if (strcmp(audio_config_p->achan[ch].octrl[ot].ptt_device,audio_config_p->achan[j].octrl[k].ptt_device) == 0) {
fd = ptt_fd[j][k]; fd = ptt_fd[j][k];
@ -839,7 +839,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_CHANS; ch++) {
if (save_audio_config_p->achan[ch].valid) { if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIO) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_GPIO) {
@ -864,7 +864,7 @@ void ptt_init (struct audio_s *audio_config_p)
*/ */
for (ch = 0; ch < MAX_CHANS; ch++) { for (ch = 0; ch < MAX_CHANS; ch++) {
if (save_audio_config_p->achan[ch].valid) { if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; // output control type, PTT, DCD, CON, ... int ot; // output control type, PTT, DCD, CON, ...
int it; // input control type int it; // input control type
@ -896,7 +896,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_CHANS; ch++) {
if (save_audio_config_p->achan[ch].valid) { if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_LPT) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_LPT) {
@ -911,7 +911,7 @@ void ptt_init (struct audio_s *audio_config_p)
int j, k; int j, k;
for (j = ch; j >= 0; j--) { for (j = ch; j >= 0; j--) {
if (audio_config_p->achan[j].valid) { if (audio_config_p->achan[j].medium == MEDIUM_RADIO) {
for (k = ((j==ch) ? (ot - 1) : (NUM_OCTYPES-1)); k >= 0; k--) { for (k = ((j==ch) ? (ot - 1) : (NUM_OCTYPES-1)); k >= 0; k--) {
if (strcmp(audio_config_p->achan[ch].octrl[ot].ptt_device,audio_config_p->achan[j].octrl[k].ptt_device) == 0) { if (strcmp(audio_config_p->achan[ch].octrl[ot].ptt_device,audio_config_p->achan[j].octrl[k].ptt_device) == 0) {
fd = ptt_fd[j][k]; fd = ptt_fd[j][k];
@ -963,7 +963,7 @@ void ptt_init (struct audio_s *audio_config_p)
#ifdef USE_HAMLIB #ifdef USE_HAMLIB
for (ch = 0; ch < MAX_CHANS; ch++) { for (ch = 0; ch < MAX_CHANS; ch++) {
if (save_audio_config_p->achan[ch].valid) { if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_HAMLIB) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_HAMLIB) {
@ -1030,7 +1030,7 @@ void ptt_init (struct audio_s *audio_config_p)
for (ch = 0; ch < MAX_CHANS; ch++) { for (ch = 0; ch < MAX_CHANS; ch++) {
if (audio_config_p->achan[ch].valid) { if (audio_config_p->achan[ch].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_CM108) { if (audio_config_p->achan[ch].octrl[ot].ptt_method == PTT_METHOD_CM108) {
@ -1051,7 +1051,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_CHANS; ch++) {
if (audio_config_p->achan[ch].valid) { if (audio_config_p->achan[ch].medium == 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);
dw_printf ("Note: PTT not configured for channel %d. (Ignore this if using VOX.)\n", ch); dw_printf ("Note: PTT not configured for channel %d. (Ignore this if using VOX.)\n", ch);
@ -1103,7 +1103,7 @@ void ptt_set (int ot, int chan, int ptt_signal)
assert (chan >= 0 && chan < MAX_CHANS); assert (chan >= 0 && chan < MAX_CHANS);
if ( ! save_audio_config_p->achan[chan].valid) { if ( save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error, ptt_set ( %s, %d, %d ), did not expect invalid channel.\n", otnames[ot], chan, ptt); dw_printf ("Internal error, ptt_set ( %s, %d, %d ), did not expect invalid channel.\n", otnames[ot], chan, ptt);
return; return;
@ -1314,7 +1314,7 @@ 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_CHANS);
if ( ! save_audio_config_p->achan[chan].valid) { if ( save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error, get_input ( %d, %d ), did not expect invalid channel.\n", it, chan); dw_printf ("Internal error, get_input ( %d, %d ), did not expect invalid channel.\n", it, chan);
return -1; return -1;
@ -1378,7 +1378,7 @@ void ptt_term (void)
int n; int n;
for (n = 0; n < MAX_CHANS; n++) { for (n = 0; n < MAX_CHANS; n++) {
if (save_audio_config_p->achan[n].valid) { if (save_audio_config_p->achan[n].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
ptt_set (ot, n, 0); ptt_set (ot, n, 0);
@ -1387,7 +1387,7 @@ void ptt_term (void)
} }
for (n = 0; n < MAX_CHANS; n++) { for (n = 0; n < MAX_CHANS; n++) {
if (save_audio_config_p->achan[n].valid) { if (save_audio_config_p->achan[n].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (ptt_fd[n][ot] != INVALID_HANDLE_VALUE) { if (ptt_fd[n][ot] != INVALID_HANDLE_VALUE) {
@ -1405,7 +1405,7 @@ void ptt_term (void)
#ifdef USE_HAMLIB #ifdef USE_HAMLIB
for (n = 0; n < MAX_CHANS; n++) { for (n = 0; n < MAX_CHANS; n++) {
if (save_audio_config_p->achan[n].valid) { if (save_audio_config_p->achan[n].medium == MEDIUM_RADIO) {
int ot; int ot;
for (ot = 0; ot < NUM_OCTYPES; ot++) { for (ot = 0; ot < NUM_OCTYPES; ot++) {
if (rig[n][ot] != NULL) { if (rig[n][ot] != NULL) {
@ -1444,14 +1444,14 @@ int main ()
my_audio_config.adev[0].num_channels = 2; my_audio_config.adev[0].num_channels = 2;
my_audio_config.achan[0].valid = 1; my_audio_config.achan[0].medium = MEDIUM_RADIO;
my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL; my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
// TODO: device should be command line argument. // TODO: device should be command line argument.
strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device)); strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device));
//strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device)); //strlcpy (my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_device));
my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_RTS; my_audio_config.achan[0].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_RTS;
my_audio_config.achan[1].valid = 1; my_audio_config.achan[1].medium = MEDIUM_RADIO;
my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL; my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device)); strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "COM3", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device));
//strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device)); //strlcpy (my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.achan[1].octrl[OCTYPE_PTT].ptt_device));
@ -1525,7 +1525,7 @@ int main ()
memset (&my_audio_config, 0, sizeof(my_audio_config)); memset (&my_audio_config, 0, sizeof(my_audio_config));
my_audio_config.adev[0].num_channels = 1; my_audio_config.adev[0].num_channels = 1;
my_audio_config.valid[0] = 1; my_audio_config.achan[0].medium = MEDIUM_RADIO;
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_GPIO; my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_GPIO;
my_audio_config.adev[0].octrl[OCTYPE_PTT].out_gpio_num = 25; my_audio_config.adev[0].octrl[OCTYPE_PTT].out_gpio_num = 25;
@ -1556,10 +1556,10 @@ int main ()
#if 0 #if 0
memset (&my_audio_config, 0, sizeof(my_audio_config)); memset (&my_audio_config, 0, sizeof(my_audio_config));
my_audio_config.num_channels = 2; my_audio_config.num_channels = 2;
my_audio_config.valid[0] = 1; my_audio_config.achan[0].medium = MEDIUM_RADIO;
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_LPT; my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_LPT;
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_lpt_bit = 0; my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_lpt_bit = 0;
my_audio_config.valid[1] = 1; my_audio_config.achan[1].medium = MEDIUM_RADIO;
my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_LPT; my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_LPT;
my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_lpt_bit = 1; my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_lpt_bit = 1;

View File

@ -1422,19 +1422,24 @@ static THREAD_F cmd_listen_thread (void *arg)
// We can have gaps in the numbering. // We can have gaps in the numbering.
// I wonder what applications will think about that. // I wonder what applications will think about that.
#if 1
// 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_CHANS; j++) {
if (save_audio_config_p->achan[j].valid) { if (save_audio_config_p->achan[j].medium == MEDIUM_RADIO ||
save_audio_config_p->achan[j].medium == MEDIUM_IGATE ||
save_audio_config_p->achan[j].medium == MEDIUM_NETTNC) {
count++; count++;
} }
} }
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_CHANS; j++) {
if (save_audio_config_p->achan[j].valid) {
switch (save_audio_config_p->achan[j].medium) {
case MEDIUM_RADIO:
{
char stemp[100]; char stemp[100];
int a = ACHAN2ADEV(j); int a = ACHAN2ADEV(j);
// If I was really ambitious, some description could be provided. // If I was really ambitious, some description could be provided.
@ -1449,20 +1454,40 @@ static THREAD_F cmd_listen_thread (void *arg)
strlcat (reply.info, stemp, sizeof(reply.info)); strlcat (reply.info, stemp, sizeof(reply.info));
} }
} }
} break;
#else case MEDIUM_IGATE:
if (num_channels == 1) { {
snprintf (reply.info, sizeof(reply.info), "1;Port1 Single channel;"); char stemp[100];
snprintf (stemp, sizeof(stemp), "Port%d Internet Gateway;", j+1);
strlcat (reply.info, stemp, sizeof(reply.info));
} }
else { break;
snprintf (reply.info, sizeof(reply.info), "2;Port1 Left channel;Port2 Right Channel;");
case MEDIUM_NETTNC:
{
// could elaborate with hostname, etc.
char stemp[100];
snprintf (stemp, sizeof(stemp), "Port%d Network TNC;", j+1);
strlcat (reply.info, stemp, sizeof(reply.info));
} }
#endif break;
default:
{
// could elaborate with hostname, etc.
char stemp[100];
snprintf (stemp, sizeof(stemp), "Port%d INVALID CHANNEL;", j+1);
strlcat (reply.info, stemp, sizeof(reply.info));
}
break;
} // switch
} // for each channel
reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1); reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
send_to_client (client, &reply); send_to_client (client, &reply);
} }
break; break;
@ -1688,7 +1713,9 @@ static THREAD_F cmd_listen_thread (void *arg)
int chan = cmd.hdr.portx; int chan = cmd.hdr.portx;
if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].valid) { // Connected mode can only be used with internal modems.
if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
ok = 1; ok = 1;
dlq_register_callsign (cmd.hdr.call_from, chan, client); dlq_register_callsign (cmd.hdr.call_from, chan, client);
} }
@ -1715,7 +1742,9 @@ static THREAD_F cmd_listen_thread (void *arg)
int chan = cmd.hdr.portx; int chan = cmd.hdr.portx;
if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].valid) { // Connected mode can only be used with internal modems.
if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
dlq_unregister_callsign (cmd.hdr.call_from, chan, client); dlq_unregister_callsign (cmd.hdr.call_from, chan, client);
} }
else { else {

25
tq.c
View File

@ -148,7 +148,7 @@ void tq_init (struct audio_s *audio_config_p)
for (c = 0; c < MAX_CHANS; c++) { for (c = 0; c < MAX_CHANS; c++) {
if (audio_config_p->achan[c].valid) { if (audio_config_p->achan[c].medium == MEDIUM_RADIO) {
wake_up_event[c] = CreateEvent (NULL, 0, 0, NULL); wake_up_event[c] = CreateEvent (NULL, 0, 0, NULL);
@ -167,7 +167,7 @@ void tq_init (struct audio_s *audio_config_p)
xmit_thread_is_waiting[c] = 0; xmit_thread_is_waiting[c] = 0;
if (audio_config_p->achan[c].valid) { if (audio_config_p->achan[c].medium == MEDIUM_RADIO) {
err = pthread_cond_init (&(wake_up_cond[c]), NULL); err = pthread_cond_init (&(wake_up_cond[c]), NULL);
if (err != 0) { if (err != 0) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -247,11 +247,15 @@ void tq_append (int chan, int prio, packet_t pp)
} }
#endif #endif
if (chan < 0 || chan >= MAX_CHANS || ! save_audio_config_p->achan[chan].valid) { if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->achan[chan].medium == 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");
dw_printf ("AX.25 for Linux is known to transmit on channels 2 & 8 sometimes when it shouldn't.\n"); dw_printf ("Are you using AX.25 for Linux? It might be trying to use a modified\n");
dw_printf ("version of KISS which uses the port field differently than the\n");
dw_printf ("original KISS protocol specification. The solution might be to use\n");
dw_printf ("a command like \"kissparms -c 1 -p radio\" to set CRC none mode.\n");
dw_printf ("\n");
ax25_delete(pp); ax25_delete(pp);
return; return;
} }
@ -447,9 +451,13 @@ void lm_data_request (int chan, int prio, packet_t pp)
} }
#endif #endif
if (chan < 0 || chan >= MAX_CHANS || ! save_audio_config_p->achan[chan].valid) { if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
// 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);
dw_printf ("Connected packet mode is allowed only with internal modems.\n");
dw_printf ("Why aren't external KISS modems allowed? See\n");
dw_printf ("Why-is-9600-only-twice-as-fast-as-1200.pdf for explanation.\n");
ax25_delete(pp); ax25_delete(pp);
return; return;
} }
@ -600,9 +608,14 @@ void lm_seize_request (int chan)
dw_printf ("lm_seize_request (chan=%d)\n", chan); dw_printf ("lm_seize_request (chan=%d)\n", chan);
#endif #endif
if (chan < 0 || chan >= MAX_CHANS || ! save_audio_config_p->achan[chan].valid) {
if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->achan[chan].medium != MEDIUM_RADIO) {
// 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);
dw_printf ("Connected packet mode is allowed only with internal modems.\n");
dw_printf ("Why aren't external KISS modems allowed? See\n");
dw_printf ("Why-is-9600-only-twice-as-fast-as-1200.pdf for explanation.\n");
return; return;
} }

3
xmit.c
View File

@ -277,8 +277,7 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet)
for (j=0; j<MAX_CHANS; j++) { for (j=0; j<MAX_CHANS; j++) {
if (p_modem->achan[j].valid) { if (p_modem->achan[j].medium == MEDIUM_RADIO) {
#if __WIN32__ #if __WIN32__
xmit_th[j] = (HANDLE)_beginthreadex (NULL, 0, xmit_thread, (void*)(long)j, 0, NULL); xmit_th[j] = (HANDLE)_beginthreadex (NULL, 0, xmit_thread, (void*)(long)j, 0, NULL);
if (xmit_th[j] == NULL) { if (xmit_th[j] == NULL) {