diff --git a/atest.c b/atest.c index 67b8ed9..91b5114 100644 --- a/atest.c +++ b/atest.c @@ -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].num_channels = format.nchannels; - my_audio_config.achan[0].valid = 1; - if (format.nchannels == 2) my_audio_config.achan[1].valid = 1; + my_audio_config.achan[0].medium = MEDIUM_RADIO; + if (format.nchannels == 2) { + my_audio_config.achan[1].medium = MEDIUM_RADIO; + } text_color_set(DW_COLOR_INFO); dw_printf ("%d samples per second. %d bits per sample. %d audio channels.\n", diff --git a/audio.h b/audio.h index 7bdf374..b427cfe 100644 --- a/audio.h +++ b/audio.h @@ -53,6 +53,13 @@ typedef enum retry_e { RETRY_INVERT_TWO_SEP=4, 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; @@ -102,19 +109,31 @@ struct audio_s { /* 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. */ + /* 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 { - 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. */ /* 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. */ /* Baseband signal. Not used yet. */ diff --git a/beacon.c b/beacon.c index 1959a02..e09c05c 100644 --- a/beacon.c +++ b/beacon.c @@ -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 (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 && strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 && diff --git a/cdigipeater.c b/cdigipeater.c index 9c40d95..3a4c8fe 100644 --- a/cdigipeater.c +++ b/cdigipeater.c @@ -129,8 +129,10 @@ void cdigipeater (int from_chan, packet_t pp) { 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); dw_printf ("cdigipeater: Did not expect to receive on invalid channel %d.\n", from_chan); return; diff --git a/config.c b/config.c index 12013da..348618e 100644 --- a/config.c +++ b/config.c @@ -757,8 +757,8 @@ void config_init (char *fname, struct audio_s *p_audio_config, for (channel=0; channelachan[channel].valid = 0; /* One or both channels will be */ - /* set to valid when corresponding */ + p_audio_config->achan[channel].medium = MEDIUM_NONE; /* One or both channels will be */ + /* set to radio when corresponding */ /* audio device is defined. */ p_audio_config->achan[channel].modem_type = MODEM_AFSK; 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. */ /* 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 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; /* 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_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; /* 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)); } @@ -1100,7 +1099,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_audio_config->adev[adevice].defined = 1; /* 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)); } @@ -1147,9 +1146,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, /* 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) { - p_audio_config->achan[ADEVFIRSTCHAN(adevice) + 1].valid = 1; + p_audio_config->achan[ADEVFIRSTCHAN(adevice) + 1].medium = MEDIUM_RADIO; } } else { @@ -1179,7 +1178,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, 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) { 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); 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); dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", line, from_chan); @@ -2222,7 +2225,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", line, to_chan); @@ -2341,7 +2346,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", line, from_chan); @@ -2361,7 +2369,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", line, to_chan); @@ -2400,10 +2408,17 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", line, from_chan); + dw_printf ("Only internal modems can be used for connected mode packet.\n"); continue; } @@ -2420,10 +2435,11 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", line, to_chan); + dw_printf ("Only internal modems can be used for connected mode packet.\n"); 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 * 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. * + * 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. * I'm not happy with this name because IG sounds like IGate * 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) { @@ -2497,12 +2526,19 @@ void config_init (char *fname, struct audio_s *p_audio_config, 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); dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", line, from_chan); 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); @@ -2522,12 +2558,19 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", line, to_chan); 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. */ @@ -2578,7 +2621,10 @@ void config_init (char *fname, struct audio_s *p_audio_config, 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); dw_printf ("Config file, line %d: FROM-channel %d is not valid.\n", line, from_chan); @@ -2599,7 +2645,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TO-channel %d is not valid.\n", line, to_chan); @@ -3756,7 +3802,11 @@ void config_init (char *fname, struct audio_s *p_audio_config, MAX_CHANS-1, line); 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); dw_printf ("Config file, line %d: TTOBJ DTMF receive channel %d is not valid.\n", 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); 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); dw_printf ("Config file, line %d: TTOBJ transmit channel %d is not valid.\n", line, x); 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) { 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. // This will handle eventual case of multiple transmit channels. - for (j=0; jachan[j].valid && strlen(p_igate_config->t2_login) > 0) { - if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) { - p_digi_config->filter_str[MAX_CHANS][j] = strdup("i/30"); + if (strlen(p_igate_config->t2_login) > 0) { + for (j=0; jachan[j].medium == MEDIUM_RADIO || p_audio_config->achan[j].medium == MEDIUM_NETTNC) { + if (p_digi_config->filter_str[MAX_CHANS][j] == NULL) { + 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') { 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); dw_printf ("Config file, line %d: Simulated receive on channel %d is not valid.\n", line, n); 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') { 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); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); continue; @@ -5106,7 +5162,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_ } else { int n = atoi(value); - if ( n < 0 || n >= MAX_CHANS || ! p_audio_config->achan[n].valid) { + if ( n < 0 || n >= MAX_CHANS || p_audio_config->achan[n].medium == MEDIUM_NONE) { text_color_set(DW_COLOR_ERROR); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, n); 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_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); dw_printf ("Config file, line %d: Send to channel %d is not valid.\n", line, b->sendto_chan); return (0); diff --git a/demod.c b/demod.c index c945b49..baa28db 100644 --- a/demod.c +++ b/demod.c @@ -108,7 +108,7 @@ int demod_init (struct audio_s *pa) 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 just_letters[16]; diff --git a/digipeater.c b/digipeater.c index 36970d7..a193222 100644 --- a/digipeater.c +++ b/digipeater.c @@ -149,11 +149,15 @@ void digipeater (int from_chan, packet_t pp) // 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); - 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); } diff --git a/direwolf.c b/direwolf.c index f02f624..73fc831 100644 --- a/direwolf.c +++ b/direwolf.c @@ -24,13 +24,14 @@ * * 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. * APRS data encoder / decoder. * APRS digipeater. * KISS TNC emulator. * APRStt (touch tone input) gateway * 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) { audio_config.adev[0].num_channels = n_opt; if (n_opt == 2) { - audio_config.achan[1].valid = 1; + audio_config.achan[1].medium = MEDIUM_RADIO; } } diff --git a/dtmf.c b/dtmf.c index 031946e..788be18 100644 --- a/dtmf.c +++ b/dtmf.c @@ -529,7 +529,7 @@ int main () memset (&my_audio_config, 0, sizeof(my_audio_config)); my_audio_config.adev[ACHAN2ADEV(c)].defined = 1; 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; dtmf_init(&my_audio_config, 50); diff --git a/gen_packets.c b/gen_packets.c index 1f4543e..1b34908 100644 --- a/gen_packets.c +++ b/gen_packets.c @@ -183,7 +183,7 @@ int main(int argc, char **argv) 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 */ modem.adev[0].num_channels = 2; - modem.achan[1].valid = 1; + modem.achan[1].medium = MEDIUM_RADIO; text_color_set(DW_COLOR_INFO); dw_printf("2 channels of sound rather than 1.\n"); break; diff --git a/gen_tone.c b/gen_tone.c index 26120f1..69d5b05 100644 --- a/gen_tone.c +++ b/gen_tone.c @@ -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++) { - if (audio_config_p->achan[chan].valid) { + if (audio_config_p->achan[chan].medium == MEDIUM_RADIO) { int a = ACHAN2ADEV(chan); @@ -291,8 +291,12 @@ void tone_gen_put_bit (int chan, int dat) int a = ACHAN2ADEV(chan); /* device for channel. */ 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) { /* Hack to test receive PLL recovery. */ diff --git a/hdlc_rec.c b/hdlc_rec.c index 15b72c2..56895c9 100644 --- a/hdlc_rec.c +++ b/hdlc_rec.c @@ -33,6 +33,7 @@ #include #include +//#include "tune.h" #include "demod.h" #include "hdlc_rec.h" #include "hdlc_rec2.h" @@ -47,7 +48,6 @@ //#define TEST 1 /* Define for unit testing. */ - //#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++) { - if (pa->achan[ch].valid) { + if (pa->achan[ch].medium == MEDIUM_RADIO) { 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); H->prev_descram = descram; - H->prev_raw = raw; } + H->prev_raw = raw; + } else { dbit = (raw == H->prev_raw); + H->prev_raw = raw; } + /* * Octets are sent LSB first. * 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 & 0xffffff00) == 0x7e7e7e00) { - //if ((H->flag4_det & 0xffff0000) == 0x7e7e0000) { - + if ((H->flag4_det & 0xffffff00) == 0x7e7e7e00) { // three seems good + //if ((H->flag4_det & 0xffff0000) == 0x7e7e0000) { // two in a row + //if ((H->flag4_det & 0xff000000) == 0x7e000000) { // single flag if ( ! H->data_detect) { H->data_detect = 1; dcd_change (chan, subchan, slice, 1); diff --git a/kiss_frame.c b/kiss_frame.c index 3ad295d..e485ae0 100644 --- a/kiss_frame.c +++ b/kiss_frame.c @@ -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. */ + /* 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); dw_printf ("Invalid transmit channel %d from KISS client app.\n", port); dw_printf ("\n"); diff --git a/morse.c b/morse.c index df0038d..8e709fd 100644 --- a/morse.c +++ b/morse.c @@ -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. - 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; @@ -360,7 +365,11 @@ static void morse_quiet (int chan, int tu, int wpm) { int nsamples; 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); @@ -395,7 +404,11 @@ static void morse_quiet_ms (int chan, int ms) { int nsamples; 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); diff --git a/multi_modem.c b/multi_modem.c index 5d96c79..9b891d0 100644 --- a/multi_modem.c +++ b/multi_modem.c @@ -152,7 +152,7 @@ void multi_modem_init (struct audio_s *pa) hdlc_rec_init (save_audio_config_p); for (chan=0; chanachan[chan].valid) { + if (save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) { if (save_audio_config_p->achan[chan].baud <= 0) { text_color_set(DW_COLOR_ERROR); dw_printf("Internal error, chan=%d, %s, %d\n", chan, __FILE__, __LINE__); diff --git a/ptt.c b/ptt.c index c070e5a..dd689cc 100644 --- a/ptt.c +++ b/ptt.c @@ -725,7 +725,7 @@ void ptt_init (struct audio_s *audio_config_p) 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { @@ -756,7 +756,7 @@ void ptt_init (struct audio_s *audio_config_p) int j, k; 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--) { 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]; @@ -839,7 +839,7 @@ void ptt_init (struct audio_s *audio_config_p) using_gpio = 0; for (ch=0; chachan[ch].valid) { + if (save_audio_config_p->achan[ch].medium == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { 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++) { - 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 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__) ) 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { 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; 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--) { 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]; @@ -963,7 +963,7 @@ void ptt_init (struct audio_s *audio_config_p) #ifdef USE_HAMLIB 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { 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++) { - if (audio_config_p->achan[ch].valid) { + if (audio_config_p->achan[ch].medium == MEDIUM_RADIO) { int ot; for (ot = 0; ot < NUM_OCTYPES; ot++) { 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. */ for (ch=0; chachan[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) { text_color_set(DW_COLOR_INFO); 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); - if ( ! 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 ("Internal error, ptt_set ( %s, %d, %d ), did not expect invalid channel.\n", otnames[ot], chan, ptt); return; @@ -1314,7 +1314,7 @@ int get_input (int it, int chan) assert (it >= 0 && it < NUM_ICTYPES); 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); dw_printf ("Internal error, get_input ( %d, %d ), did not expect invalid channel.\n", it, chan); return -1; @@ -1378,7 +1378,7 @@ void ptt_term (void) int 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { ptt_set (ot, n, 0); @@ -1387,7 +1387,7 @@ void ptt_term (void) } 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { if (ptt_fd[n][ot] != INVALID_HANDLE_VALUE) { @@ -1405,7 +1405,7 @@ void ptt_term (void) #ifdef USE_HAMLIB 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; for (ot = 0; ot < NUM_OCTYPES; ot++) { if (rig[n][ot] != NULL) { @@ -1444,14 +1444,14 @@ int main () 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; // 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, "/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[1].valid = 1; + my_audio_config.achan[1].medium = MEDIUM_RADIO; 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, "/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)); 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].out_gpio_num = 25; @@ -1556,10 +1556,10 @@ int main () #if 0 memset (&my_audio_config, 0, sizeof(my_audio_config)); 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_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_lpt_bit = 1; diff --git a/server.c b/server.c index 6e2c3c7..53fd592 100644 --- a/server.c +++ b/server.c @@ -1422,47 +1422,72 @@ static THREAD_F cmd_listen_thread (void *arg) // We can have gaps in the numbering. // I wonder what applications will think about that. -#if 1 // No other place cares about total number. count = 0; for (j=0; jachan[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++; } } snprintf (reply.info, sizeof(reply.info), "%d;", count); for (j=0; jachan[j].valid) { - char stemp[100]; - int a = ACHAN2ADEV(j); - // If I was really ambitious, some description could be provided. - static const char *names[8] = { "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth" }; - if (save_audio_config_p->adev[a].num_channels == 1) { - snprintf (stemp, sizeof(stemp), "Port%d %s soundcard mono;", j+1, names[a]); - strlcat (reply.info, stemp, sizeof(reply.info)); - } - else { - snprintf (stemp, sizeof(stemp), "Port%d %s soundcard %s;", j+1, names[a], j&1 ? "right" : "left"); - strlcat (reply.info, stemp, sizeof(reply.info)); - } - } - } + switch (save_audio_config_p->achan[j].medium) { + + case MEDIUM_RADIO: + { + char stemp[100]; + int a = ACHAN2ADEV(j); + // If I was really ambitious, some description could be provided. + static const char *names[8] = { "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth" }; + + if (save_audio_config_p->adev[a].num_channels == 1) { + snprintf (stemp, sizeof(stemp), "Port%d %s soundcard mono;", j+1, names[a]); + strlcat (reply.info, stemp, sizeof(reply.info)); + } + else { + snprintf (stemp, sizeof(stemp), "Port%d %s soundcard %s;", j+1, names[a], j&1 ? "right" : "left"); + strlcat (reply.info, stemp, sizeof(reply.info)); + } + } + break; + + case MEDIUM_IGATE: + { + char stemp[100]; + snprintf (stemp, sizeof(stemp), "Port%d Internet Gateway;", j+1); + strlcat (reply.info, stemp, sizeof(reply.info)); + } + break; + + 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)); + } + 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 -#else - if (num_channels == 1) { - snprintf (reply.info, sizeof(reply.info), "1;Port1 Single channel;"); - } - else { - snprintf (reply.info, sizeof(reply.info), "2;Port1 Left channel;Port2 Right Channel;"); - } -#endif reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1); send_to_client (client, &reply); - } break; @@ -1688,7 +1713,9 @@ static THREAD_F cmd_listen_thread (void *arg) 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; 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; - 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); } else { diff --git a/tq.c b/tq.c index a9bb960..0cc4bec 100644 --- a/tq.c +++ b/tq.c @@ -148,7 +148,7 @@ void tq_init (struct audio_s *audio_config_p) 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); @@ -167,7 +167,7 @@ void tq_init (struct audio_s *audio_config_p) 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); if (err != 0) { text_color_set(DW_COLOR_ERROR); @@ -247,11 +247,15 @@ void tq_append (int chan, int prio, packet_t pp) } #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); 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 ("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); return; } @@ -447,9 +451,13 @@ void lm_data_request (int chan, int prio, packet_t pp) } #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); 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); return; } @@ -600,9 +608,14 @@ void lm_seize_request (int chan) dw_printf ("lm_seize_request (chan=%d)\n", chan); #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); 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; } diff --git a/xmit.c b/xmit.c index 80ff58d..ca96f55 100644 --- a/xmit.c +++ b/xmit.c @@ -277,8 +277,7 @@ void xmit_init (struct audio_s *p_modem, int debug_xmit_packet) for (j=0; jachan[j].valid) { - + if (p_modem->achan[j].medium == MEDIUM_RADIO) { #if __WIN32__ xmit_th[j] = (HANDLE)_beginthreadex (NULL, 0, xmit_thread, (void*)(long)j, 0, NULL); if (xmit_th[j] == NULL) {