mirror of https://github.com/wb2osz/direwolf.git
Complete the new ICHANNEL feature.
This commit is contained in:
parent
031c937cdb
commit
04ecdbc6fc
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
### New Features: ###
|
### New Features: ###
|
||||||
|
|
||||||
|
- Additional documentation location to slow down growth of main repository. [https://github.com/wb2osz/direwolf-doc](https://github.com/wb2osz/direwolf-doc)
|
||||||
|
|
||||||
|
- New ICHANNEL configuration option to map a KISS client application channel to APRS-IS. Packets from APRS-IS will be presented to client applications as the specified channel. Packets sent, by client applications, to that channel will go to APRS-IS rather than a radio channel. Details in ***Internal-Packet-Routing.pdf***.
|
||||||
|
|
||||||
- New variable speed option for gen_packets. For example, "-v 5,0.1" would generate packets from 5% too slow to 5% too fast with increments of 0.1. Some implementations might have imprecise timing. Use this to test how well TNCs tolerate sloppy timing.
|
- New variable speed option for gen_packets. For example, "-v 5,0.1" would generate packets from 5% too slow to 5% too fast with increments of 0.1. Some implementations might have imprecise timing. Use this to test how well TNCs tolerate sloppy timing.
|
||||||
|
|
||||||
|
|
14
src/beacon.c
14
src/beacon.c
|
@ -162,6 +162,7 @@ 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 (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) {
|
||||||
|
@ -621,6 +622,7 @@ static void * beacon_thread (void *arg)
|
||||||
// On reboot, the time is in the past.
|
// On reboot, the time is in the past.
|
||||||
// After time gets set from GPS, all beacons from that interval are sent.
|
// After time gets set from GPS, all beacons from that interval are sent.
|
||||||
// FIXME: This will surely break time slotted scheduling.
|
// FIXME: This will surely break time slotted scheduling.
|
||||||
|
// TODO: The correct fix will be using monotonic, rather than clock, time.
|
||||||
|
|
||||||
/* craigerl: if next beacon is scheduled in the past, then set next beacon relative to now (happens when NTP pushes clock AHEAD) */
|
/* craigerl: if next beacon is scheduled in the past, then set next beacon relative to now (happens when NTP pushes clock AHEAD) */
|
||||||
/* fixme: if NTP sets clock BACK an hour, this thread will sleep for that hour */
|
/* fixme: if NTP sets clock BACK an hour, this thread will sleep for that hour */
|
||||||
|
@ -805,11 +807,17 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
|
|
||||||
assert (bp->sendto_chan >= 0);
|
assert (bp->sendto_chan >= 0);
|
||||||
|
|
||||||
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(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.
|
||||||
|
strlcpy (mycall, g_modem_config_p->achan[0].mycall, sizeof(mycall));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strlcpy (mycall, g_modem_config_p->achan[bp->sendto_chan].mycall, sizeof(mycall));
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("MYCALL not set for beacon in config file line %d.\n", bp->lineno);
|
dw_printf ("MYCALL not set for beacon to chan %d in config file line %d.\n", bp->sendto_chan, bp->lineno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,7 +1054,7 @@ static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[ig] %s\n", beacon_text);
|
dw_printf ("[ig] %s\n", beacon_text);
|
||||||
|
|
||||||
igate_send_rec_packet (0, pp);
|
igate_send_rec_packet (-1, pp); // Channel -1 to avoid RF>IS filtering.
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
36
src/config.c
36
src/config.c
|
@ -5594,7 +5594,8 @@ 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_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||||
|
&& 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);
|
||||||
continue;
|
continue;
|
||||||
|
@ -5604,7 +5605,8 @@ 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_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||||
|
&& 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);
|
||||||
continue;
|
continue;
|
||||||
|
@ -5615,7 +5617,8 @@ 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_CHANS || p_audio_config->chan_medium[n] == MEDIUM_NONE)
|
||||||
|
&& 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);
|
||||||
continue;
|
continue;
|
||||||
|
@ -5864,19 +5867,32 @@ 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_CHANS || p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_NONE)
|
||||||
|
&& p_audio_config->chan_medium[b->sendto_chan] != MEDIUM_IGATE) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 ||
|
if (p_audio_config->chan_medium[b->sendto_chan] == MEDIUM_IGATE) { // Prevent subscript out of bounds.
|
||||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 ||
|
// Will be using call from chan 0 later.
|
||||||
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) {
|
if ( strcmp(p_audio_config->achan[0].mycall, "") == 0 ||
|
||||||
|
strcmp(p_audio_config->achan[0].mycall, "NOCALL") == 0 ||
|
||||||
|
strcmp(p_audio_config->achan[0].mycall, "N0CALL") == 0 ) {
|
||||||
|
|
||||||
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", 0);
|
||||||
return (0);
|
return (0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ( strcmp(p_audio_config->achan[b->sendto_chan].mycall, "") == 0 ||
|
||||||
|
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "NOCALL") == 0 ||
|
||||||
|
strcmp(p_audio_config->achan[b->sendto_chan].mycall, "N0CALL") == 0 ) {
|
||||||
|
|
||||||
|
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);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
109
src/dtime_now.c
109
src/dtime_now.c
|
@ -25,9 +25,9 @@
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: dtime_now
|
* Name: dtime_realtime
|
||||||
*
|
*
|
||||||
* Purpose: Return current time as double precision.
|
* Purpose: Return current wall clock time as double precision.
|
||||||
*
|
*
|
||||||
* Input: none
|
* Input: none
|
||||||
*
|
*
|
||||||
|
@ -41,10 +41,23 @@
|
||||||
* simply use double precision floating point to make usage
|
* simply use double precision floating point to make usage
|
||||||
* easier.
|
* easier.
|
||||||
*
|
*
|
||||||
|
* NOTE: This is not a good way to calculate elapsed time because
|
||||||
|
* it can jump forward or backware via NTP or other manual setting.
|
||||||
|
*
|
||||||
|
* Use the monotonic version for measuring elapsed time.
|
||||||
|
*
|
||||||
|
* History: Originally I called this dtime_now. We ran into issues where
|
||||||
|
* we really cared about elapsed time, rather than wall clock time.
|
||||||
|
* The wall clock time could be wrong at start up time if there
|
||||||
|
* is no realtime clock or Internet access. It can then jump
|
||||||
|
* when GPS time or Internet access becomes available.
|
||||||
|
* All instances of dtime_now should be replaced by dtime_realtime
|
||||||
|
* if we want wall clock time, or dtime_monotonic if it is to be
|
||||||
|
* used for measuring elapsed time, such as between becons.
|
||||||
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double dtime_realtime (void)
|
||||||
double dtime_now (void)
|
|
||||||
{
|
{
|
||||||
double result;
|
double result;
|
||||||
|
|
||||||
|
@ -63,6 +76,10 @@ double dtime_now (void)
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
// Why didn't I use clock_gettime?
|
||||||
|
// Not available before Max OSX 10.12? https://github.com/gambit/gambit/issues/293
|
||||||
|
|
||||||
struct timeval tp;
|
struct timeval tp;
|
||||||
gettimeofday(&tp, NULL);
|
gettimeofday(&tp, NULL);
|
||||||
ts.tv_nsec = tp.tv_usec * 1000;
|
ts.tv_nsec = tp.tv_usec * 1000;
|
||||||
|
@ -75,6 +92,83 @@ double dtime_now (void)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("dtime_realtime() returns %.3f\n", result );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: dtime_monotonic
|
||||||
|
*
|
||||||
|
* Purpose: Return montonically increasing time, which is not influenced
|
||||||
|
* by the wall clock changing. e.g. leap seconds, NTP adjustments.
|
||||||
|
*
|
||||||
|
* Input: none
|
||||||
|
*
|
||||||
|
* Returns: Time as double precision, so we can get resolution
|
||||||
|
* finer than one second.
|
||||||
|
*
|
||||||
|
* Description: Use this when calculating elapsed time.
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double dtime_monotonic (void)
|
||||||
|
{
|
||||||
|
double result;
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// This is still returning wall clock time.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64
|
||||||
|
// GetTickCount64 would be ideal but it requires Vista or Server 2008.
|
||||||
|
// As far as I know, the current version of direwolf still works on XP.
|
||||||
|
//
|
||||||
|
// As a work-around, GetTickCount could be used if we add extra code to deal
|
||||||
|
// with the wrap around after about 49.7 days.
|
||||||
|
// Resolution is only about 10 or 16 milliseconds. Is that good enough?
|
||||||
|
|
||||||
|
/* 64 bit integer is number of 100 nanosecond intervals from Jan 1, 1601. */
|
||||||
|
|
||||||
|
FILETIME ft;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime (&ft);
|
||||||
|
|
||||||
|
result = ((( (double)ft.dwHighDateTime * (256. * 256. * 256. * 256.) +
|
||||||
|
(double)ft.dwLowDateTime ) / 10000000.) - 11644473600.);
|
||||||
|
#else
|
||||||
|
/* tv_sec is seconds from Jan 1, 1970. */
|
||||||
|
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
// FIXME: Does MacOS have a monotonically increasing time?
|
||||||
|
// https://stackoverflow.com/questions/41509505/clock-gettime-on-macos
|
||||||
|
|
||||||
|
struct timeval tp;
|
||||||
|
gettimeofday(&tp, NULL);
|
||||||
|
ts.tv_nsec = tp.tv_usec * 1000;
|
||||||
|
ts.tv_sec = tp.tv_sec;
|
||||||
|
#else
|
||||||
|
|
||||||
|
// This is the only case handled properly.
|
||||||
|
// Probably the only one that matters.
|
||||||
|
// It is common to have a Raspberry Pi, without Internet,
|
||||||
|
// starting up direwolf before GPS/NTP adjusts the time.
|
||||||
|
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &ts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
result = ((double)(ts.tv_sec) + (double)(ts.tv_nsec) * 0.000000001);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("dtime_now() returns %.3f\n", result );
|
dw_printf ("dtime_now() returns %.3f\n", result );
|
||||||
|
@ -84,6 +178,7 @@ double dtime_now (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: timestamp_now
|
* Name: timestamp_now
|
||||||
|
@ -104,7 +199,7 @@ double dtime_now (void)
|
||||||
|
|
||||||
void timestamp_now (char *result, int result_size, int show_ms)
|
void timestamp_now (char *result, int result_size, int show_ms)
|
||||||
{
|
{
|
||||||
double now = dtime_now();
|
double now = dtime_realtime();
|
||||||
time_t t = (int)now;
|
time_t t = (int)now;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
|
@ -150,7 +245,7 @@ void timestamp_now (char *result, int result_size, int show_ms)
|
||||||
|
|
||||||
void timestamp_user_format (char *result, int result_size, char *user_format)
|
void timestamp_user_format (char *result, int result_size, char *user_format)
|
||||||
{
|
{
|
||||||
double now = dtime_now();
|
double now = dtime_realtime();
|
||||||
time_t t = (int)now;
|
time_t t = (int)now;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
|
@ -191,7 +286,7 @@ void timestamp_user_format (char *result, int result_size, char *user_format)
|
||||||
|
|
||||||
void timestamp_filename (char *result, int result_size)
|
void timestamp_filename (char *result, int result_size)
|
||||||
{
|
{
|
||||||
double now = dtime_now();
|
double now = dtime_realtime();
|
||||||
time_t t = (int)now;
|
time_t t = (int)now;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
|
|
||||||
|
|
||||||
extern double dtime_now (void);
|
extern double dtime_realtime (void);
|
||||||
|
|
||||||
|
extern double dtime_monotonic (void);
|
||||||
|
|
||||||
|
|
||||||
void timestamp_now (char *result, int result_size, int show_ms);
|
void timestamp_now (char *result, int result_size, int show_ms);
|
||||||
|
|
||||||
void timestamp_user_format (char *result, int result_size, char *user_format);
|
void timestamp_user_format (char *result, int result_size, char *user_format);
|
||||||
|
|
||||||
void timestamp_filename (char *result, int result_size);
|
void timestamp_filename (char *result, int result_size);
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: remove temp workaround.
|
||||||
|
// Needs many scattered updates.
|
||||||
|
|
||||||
|
#define dtime_now dtime_realtime
|
||||||
|
|
71
src/igate.c
71
src/igate.c
|
@ -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) 2013, 2014, 2015, 2016 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014, 2015, 2016, 2023 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
|
||||||
|
@ -855,6 +855,9 @@ static void * connnect_thread (void *arg)
|
||||||
* Purpose: Send a packet to the IGate server
|
* Purpose: Send a packet to the IGate server
|
||||||
*
|
*
|
||||||
* Inputs: chan - Radio channel it was received on.
|
* Inputs: chan - Radio channel it was received on.
|
||||||
|
* This is required for the RF>IS filtering.
|
||||||
|
* Beaconing (sendto=ig, chan=-1) and a client app sending
|
||||||
|
* to ICHANNEL should bypass the filtering.
|
||||||
*
|
*
|
||||||
* recv_pp - Pointer to packet object.
|
* recv_pp - Pointer to packet object.
|
||||||
* *** CALLER IS RESPONSIBLE FOR DELETING IT! **
|
* *** CALLER IS RESPONSIBLE FOR DELETING IT! **
|
||||||
|
@ -902,7 +905,12 @@ void igate_send_rec_packet (int chan, packet_t recv_pp)
|
||||||
* In that case, the payload will have TCPIP in the path and it will be dropped.
|
* In that case, the payload will have TCPIP in the path and it will be dropped.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) {
|
// Apply RF>IS filtering only if it same from a radio channel.
|
||||||
|
// Beacon will be channel -1.
|
||||||
|
// Client app to ICHANNEL is outside of radio channel range.
|
||||||
|
|
||||||
|
if (chan >= 0 && chan < MAX_CHANS && // in radio channel range
|
||||||
|
save_digi_config_p->filter_str[chan][MAX_CHANS] != NULL) {
|
||||||
|
|
||||||
if (pfilter(chan, MAX_CHANS, save_digi_config_p->filter_str[chan][MAX_CHANS], recv_pp, 1) != 1) {
|
if (pfilter(chan, MAX_CHANS, save_digi_config_p->filter_str[chan][MAX_CHANS], recv_pp, 1) != 1) {
|
||||||
|
|
||||||
|
@ -1517,32 +1525,36 @@ static void * igate_recv_thread (void *arg)
|
||||||
|
|
||||||
int ichan = save_audio_config_p->igate_vchannel;
|
int ichan = save_audio_config_p->igate_vchannel;
|
||||||
|
|
||||||
// Try to parse it into a packet object.
|
// My original poorly thoughtout idea was to parse it into a packet object,
|
||||||
// This will contain "q constructs" and we might see an address
|
// using the non-strict option, and send to the client app.
|
||||||
// with two alphnumeric characters in the SSID so we must use
|
//
|
||||||
// the non-strict parsing.
|
// A lot of things can go wrong with that approach.
|
||||||
|
|
||||||
// Possible problem: Up to 8 digipeaters are allowed in radio format.
|
// (1) Up to 8 digipeaters are allowed in radio format.
|
||||||
// There is a potential of finding a larger number here.
|
// There is a potential of finding a larger number here.
|
||||||
|
//
|
||||||
|
// (2) The via path can have names that are not valid in the radio format.
|
||||||
|
// e.g. qAC, T2HAKATA, N5JXS-F1.
|
||||||
|
// Non-strict parsing would force uppercase, truncate names too long,
|
||||||
|
// and drop unacceptable SSIDs.
|
||||||
|
//
|
||||||
|
// (3) The source address could be invalid for the RF address format.
|
||||||
|
// e.g. WHO-IS>APJIW4,TCPIP*,qAC,AE5PL-JF::ZL1JSH-9 :Charles Beadfield/New Zealand{583
|
||||||
|
// That is essential information that we absolutely need to preserve.
|
||||||
|
//
|
||||||
|
// I think the only correct solution is to apply a third party header
|
||||||
|
// wrapper so the original contents are preserved. This will be a little
|
||||||
|
// more work for the application developer. Search for ":}" and use only
|
||||||
|
// the part after that. At this point, I don't see any value in encoding
|
||||||
|
// information in the source/destination so I will just use "X>X:}" as a prefix
|
||||||
|
|
||||||
packet_t pp3 = ax25_from_text((char*)message, 0); // 0 means not strict
|
char stemp[AX25_MAX_INFO_LEN];
|
||||||
|
strlcpy (stemp, "X>X:}", sizeof(stemp));
|
||||||
|
strlcat (stemp, (char*)message, sizeof(stemp));
|
||||||
|
|
||||||
|
packet_t pp3 = ax25_from_text(stemp, 0); // 0 means not strict
|
||||||
if (pp3 != NULL) {
|
if (pp3 != NULL) {
|
||||||
|
|
||||||
// Should we remove the VIA path?
|
|
||||||
|
|
||||||
// For example, we might get something like this from the server.
|
|
||||||
// Lower case 'q' and non-numeric SSID are not valid for AX.25 over the air.
|
|
||||||
// K1USN-1>APWW10,TCPIP*,qAC,N5JXS-F1:T#479,100,048,002,500,000,10000000
|
|
||||||
|
|
||||||
// Should we try to retain all information and pass that along, to the best of our ability,
|
|
||||||
// to the client app, or should we remove the via path so it looks like this?
|
|
||||||
// K1USN-1>APWW10:T#479,100,048,002,500,000,10000000
|
|
||||||
|
|
||||||
// For now, keep it intact and see if it causes problems. Easy to remove like this:
|
|
||||||
// while (ax25_get_num_repeaters(pp3) > 0) {
|
|
||||||
// ax25_remove_addr (pp3, AX25_REPEATER_1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
alevel_t alevel;
|
alevel_t alevel;
|
||||||
memset (&alevel, 0, sizeof(alevel));
|
memset (&alevel, 0, sizeof(alevel));
|
||||||
alevel.mark = -2; // FIXME: Do we want some other special case?
|
alevel.mark = -2; // FIXME: Do we want some other special case?
|
||||||
|
@ -1831,8 +1843,19 @@ static void maybe_xmit_packet_from_igate (char *message, int to_chan)
|
||||||
* If we recently transmitted a 'message' from some station,
|
* If we recently transmitted a 'message' from some station,
|
||||||
* send the position of the message sender when it comes along later.
|
* send the position of the message sender when it comes along later.
|
||||||
*
|
*
|
||||||
|
* Some refer to this as a courtesy posit report but I don't
|
||||||
|
* think that is an official term.
|
||||||
|
*
|
||||||
* If we have a position report, look up the sender and see if we should
|
* If we have a position report, look up the sender and see if we should
|
||||||
* bypass the normal filtering.
|
* bypass the normal filtering.
|
||||||
|
*
|
||||||
|
* Reference: https://www.aprs-is.net/IGating.aspx
|
||||||
|
*
|
||||||
|
* "Passing all message packets also includes passing the sending station's position
|
||||||
|
* along with the message. When APRS-IS was small, we did this using historical position
|
||||||
|
* packets. This has become problematic as it introduces historical data on to RF.
|
||||||
|
* The IGate should note the station(s) it has gated messages to RF for and pass
|
||||||
|
* the next position packet seen for that station(s) to RF."
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: Not quite this simple. Should have a function to check for position.
|
// TODO: Not quite this simple. Should have a function to check for position.
|
||||||
|
|
|
@ -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) 2013, 2014, 2017 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014, 2017, 2023 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
|
||||||
|
@ -611,7 +611,8 @@ 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_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE)
|
||||||
|
&& save_audio_config_p->chan_medium[chan] != MEDIUM_IGATE) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
47
src/tq.c
47
src/tq.c
|
@ -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, 2014, 2015, 2016 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2012, 2014, 2015, 2016, 2023 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
|
||||||
|
@ -50,7 +50,8 @@
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "tq.h"
|
#include "tq.h"
|
||||||
#include "dedupe.h"
|
#include "dedupe.h"
|
||||||
|
#include "igate.h"
|
||||||
|
#include "dtime_now.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,6 +196,9 @@ void tq_init (struct audio_s *audio_config_p)
|
||||||
*
|
*
|
||||||
* Inputs: chan - Channel, 0 is first.
|
* Inputs: chan - Channel, 0 is first.
|
||||||
*
|
*
|
||||||
|
* New in 1.7:
|
||||||
|
* Channel can be assigned to IGate rather than a radio.
|
||||||
|
*
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
|
@ -247,6 +251,43 @@ 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.
|
||||||
|
|
||||||
|
#ifndef DIGITEST // avoid dtest link error
|
||||||
|
|
||||||
|
if (save_audio_config_p->chan_medium[chan] == MEDIUM_IGATE) {
|
||||||
|
|
||||||
|
char ts[100]; // optional time stamp.
|
||||||
|
|
||||||
|
if (strlen(save_audio_config_p->timestamp_format) > 0) {
|
||||||
|
char tstmp[100];
|
||||||
|
timestamp_user_format (tstmp, sizeof(tstmp), save_audio_config_p->timestamp_format);
|
||||||
|
strlcpy (ts, " ", sizeof(ts)); // space after channel.
|
||||||
|
strlcat (ts, tstmp, sizeof(ts));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strlcpy (ts, "", sizeof(ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
char stemp[256]; // Formated addresses.
|
||||||
|
ax25_format_addrs (pp, stemp);
|
||||||
|
unsigned char *pinfo;
|
||||||
|
int info_len = ax25_get_info (pp, &pinfo);
|
||||||
|
text_color_set(DW_COLOR_XMIT);
|
||||||
|
dw_printf ("[%d>is%s] ", chan, ts);
|
||||||
|
dw_printf ("%s", stemp); /* stations followed by : */
|
||||||
|
ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
|
||||||
|
dw_printf ("\n");
|
||||||
|
|
||||||
|
igate_send_rec_packet (chan, pp);
|
||||||
|
ax25_delete(pp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Normal case - put in queue for radio transmission.
|
||||||
|
// Error if trying to transmit to a radio channel which was not configured.
|
||||||
|
|
||||||
if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->chan_medium[chan] == MEDIUM_NONE) {
|
if (chan < 0 || chan >= MAX_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);
|
||||||
|
@ -281,8 +322,6 @@ void tq_append (int chan, int prio, packet_t pp)
|
||||||
* The check would allow an unlimited number of other types.
|
* The check would allow an unlimited number of other types.
|
||||||
*
|
*
|
||||||
* Limit was 20. Changed to 100 in version 1.2 as a workaround.
|
* Limit was 20. Changed to 100 in version 1.2 as a workaround.
|
||||||
*
|
|
||||||
* Implementing the 6PACK protocol is probably the proper solution.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ax25_is_aprs(pp) && tq_count(chan,prio,"","",0) > 100) {
|
if (ax25_is_aprs(pp) && tq_count(chan,prio,"","",0) > 100) {
|
||||||
|
|
Loading…
Reference in New Issue