diff --git a/CHANGES.md b/CHANGES.md index 0c68ad2..63653f7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,16 @@ ---------- +## Version 1.3 -- Development snapshot K -- January 2016 ## + +### New Feature: ### + +- SATgate mode for IGate. Packets heard directly are delayed before being sent +to the Internet Server. This favors digipeated packets because the original +arrives later and gets dropped if there are duplicates. + +---------- + ## Version 1.3 -- Development snapshot J -- January 2016 ## ### Bugs Fixed: ### @@ -10,7 +20,7 @@ - AGW network protocol now works properly for big-endian processors such as PowerPC or MIPS. - - The Mac OSX build procedure is now better about locating the SDK. +- The Mac OSX build procedure is now better about locating the SDK. ---------- diff --git a/audio.h b/audio.h index 18c7365..5957ae6 100644 --- a/audio.h +++ b/audio.h @@ -298,6 +298,12 @@ struct audio_s { #define DEFAULT_SPACE_FREQ 2200 #define DEFAULT_BAUD 1200 +/* Used for sanity checking in config file and command line options. */ +/* 9600 is known to work. */ +/* TODO: Is 19200 possible with a soundcard at 44100 samples/sec? */ + +#define MIN_BAUD 100 +#define MAX_BAUD 10000 /* diff --git a/ax25_pad.c b/ax25_pad.c index d20896b..37a9508 100644 --- a/ax25_pad.c +++ b/ax25_pad.c @@ -219,7 +219,7 @@ int ax25memdebug_seq (packet_t this_p) *------------------------------------------------------------------------------*/ -static packet_t ax25_new (void) +packet_t ax25_new (void) { struct packet_s *this_p; @@ -1630,11 +1630,50 @@ packet_t ax25_get_nextp (packet_t this_p) { assert (this_p->magic1 == MAGIC); assert (this_p->magic2 == MAGIC); - + return (this_p->nextp); } +/*------------------------------------------------------------------------------ + * + * Name: ax25_set_release_time + * + * Purpose: Set release time + * + * Inputs: this_p - Current packet object. + * + * release_time - Time as returned by dtime_now(). + * + *------------------------------------------------------------------------------*/ + +void ax25_set_release_time (packet_t this_p, double release_time) +{ + assert (this_p->magic1 == MAGIC); + assert (this_p->magic2 == MAGIC); + + this_p->release_time = release_time; +} + + + +/*------------------------------------------------------------------------------ + * + * Name: ax25_get_release_time + * + * Purpose: Get release time. + * + *------------------------------------------------------------------------------*/ + +double ax25_get_release_time (packet_t this_p) +{ + assert (this_p->magic1 == MAGIC); + assert (this_p->magic2 == MAGIC); + + return (this_p->release_time); +} + + /*------------------------------------------------------------------ * diff --git a/ax25_pad.h b/ax25_pad.h index 4200155..75ede36 100644 --- a/ax25_pad.h +++ b/ax25_pad.h @@ -73,8 +73,12 @@ struct packet_s { int magic1; /* for error checking. */ + int seq; /* unique sequence number for debugging. */ + double release_time; /* Time stamp in format returned by dtime_now(). */ + /* When to release from the SATgate mode delay queue. */ + #define MAGIC 0x41583235 struct packet_s *nextp; /* Pointer to next in queue. */ @@ -145,6 +149,8 @@ typedef struct packet_s *packet_t; #ifdef AX25_PAD_C /* Keep this hidden - implementation could change. */ +extern packet_t ax25_new (void); + /* * APRS always has one control octet of 0x03 but the more * general AX.25 case is one or two control bytes depending on @@ -273,8 +279,10 @@ typedef struct alevel_s { } alevel_t; +#ifndef AXTEST +// TODO: remove this? #define AX25MEMDEBUG 1 - +#endif #if AX25MEMDEBUG // to investigate a memory leak problem @@ -310,6 +318,8 @@ extern void ax25_delete (packet_t pp); #endif + + extern int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard); extern int ax25_check_addresses (packet_t pp); @@ -344,6 +354,9 @@ extern int ax25_get_dti (packet_t this_p); extern packet_t ax25_get_nextp (packet_t this_p); +extern void ax25_set_release_time (packet_t this_p, double release_time); +extern double ax25_get_release_time (packet_t this_p); + extern void ax25_format_addrs (packet_t pp, char *); extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]); diff --git a/config.c b/config.c index cb54011..860dc8d 100644 --- a/config.c +++ b/config.c @@ -1121,7 +1121,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, continue; } n = atoi(t); - if (n >= 100 && n <= 10000) { + if (n >= MIN_BAUD && n <= MAX_BAUD) { p_audio_config->achan[channel].baud = n; if (n != 300 && n != 1200 && n != 9600) { text_color_set(DW_COLOR_ERROR); @@ -3720,6 +3720,34 @@ void config_init (char *fname, struct audio_s *p_audio_config, } } +/* + * SATGATE - Special SATgate mode to delay packets heard directly. + * + * SATGATE [ n ] + */ + + else if (strcasecmp(t, "SATGATE") == 0) { + + t = split(NULL,0); + if (t != NULL) { + + int n = atoi(t); + if (n >= MIN_SATGATE_DELAY && n <= MAX_SATGATE_DELAY) { + p_igate_config->satgate_delay = n; + } + else { + p_igate_config->satgate_delay = DEFAULT_SATGATE_DELAY; + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Unreasonable SATgate delay. Using default.\n", line); + } + } + else { + p_igate_config->satgate_delay = DEFAULT_SATGATE_DELAY; + } + } + + + /* * ==================== All the left overs ==================== */ diff --git a/direwolf.c b/direwolf.c index 6e69f42..59a3cc0 100644 --- a/direwolf.c +++ b/direwolf.c @@ -1,7 +1,7 @@ // // This file is part of Dire Wolf, an amateur radio packet TNC. // -// Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ +// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -231,7 +231,7 @@ int main (int argc, char *argv[]) text_color_init(t_opt); text_color_set(DW_COLOR_INFO); //dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__); - dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "J", __DATE__); + dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "K", __DATE__); //dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION); #if defined(ENABLE_GPSD) || defined(USE_HAMLIB) diff --git a/doc/User-Guide.pdf b/doc/User-Guide.pdf index e49dc16..a8d6b7d 100644 Binary files a/doc/User-Guide.pdf and b/doc/User-Guide.pdf differ diff --git a/igate.c b/igate.c index 4373857..080c30e 100644 --- a/igate.c +++ b/igate.c @@ -1,7 +1,7 @@ // // This file is part of Dire Wolf, an amateur radio packet TNC. // -// Copyright (C) 2013, 2014, 2015 John Langner, WB2OSZ +// Copyright (C) 2013, 2014, 2015, 2016 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -33,6 +33,9 @@ * APRS iGate properties * http://wiki.ham.fi/APRS_iGate_properties * + * SATgate mode. + * http://www.tapr.org/pipermail/aprssig/2016-January/045283.html + * *---------------------------------------------------------------*/ /*------------------------------------------------------------------ @@ -97,16 +100,25 @@ #include "igate.h" #include "latlong.h" #include "pfilter.h" +#include "dtime_now.h" #if __WIN32__ static unsigned __stdcall connnect_thread (void *arg); static unsigned __stdcall igate_recv_thread (void *arg); +static unsigned __stdcall satgate_delay_thread (void *arg); #else static void * connnect_thread (void *arg); static void * igate_recv_thread (void *arg); +static void * satgate_delay_thread (void *arg); #endif + +static dw_mutex_t dp_mutex; /* Critical section for delayed packet queue. */ +static packet_t dp_queue_head; + +static void satgate_delay_packet (packet_t pp, int chan); +static void send_packet_to_server (packet_t pp, int chan); static void send_msg_to_server (const char *msg); static void xmit_packet (char *message, int chan); @@ -380,12 +392,15 @@ void igate_init (struct audio_s *p_audio_config, struct igate_config_s *p_igate_ #if __WIN32__ HANDLE connnect_th; HANDLE cmd_recv_th; + HANDLE satgate_delay_th; #else pthread_t connect_listen_tid; pthread_t cmd_listen_tid; + pthread_t satgate_delay_tid; int e; #endif s_debug = debug_level; + dp_queue_head = NULL; #if DEBUGx text_color_set(DW_COLOR_DEBUG); @@ -467,7 +482,31 @@ void igate_init (struct audio_s *p_audio_config, struct igate_config_s *p_igate_ return; } #endif -} + +/* + * This lets delayed packets continue after specified amount of time. + */ + + if (p_igate_config->satgate_delay > 0) { +#if __WIN32__ + satgate_delay_th = (HANDLE)_beginthreadex (NULL, 0, satgate_delay_thread, NULL, 0, NULL); + if (satgate_delay_th == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Internal error: Could not create SATgate delay thread\n"); + return; + } +#else + e = pthread_create (&satgate_delay_tid, NULL, satgate_delay_thread, NULL); + if (e != 0) { + text_color_set(DW_COLOR_ERROR); + perror("Internal error: Could not create SATgate delay thread"); + return; + } +#endif + dw_mutex_init(&dp_mutex); + } + +} /* end igate_init */ /*------------------------------------------------------------------- @@ -816,7 +855,6 @@ void igate_send_rec_packet (int chan, packet_t recv_pp) int n; unsigned char *pinfo; char *p; - char msg[IGATE_MAX_MSG]; int info_len; @@ -970,6 +1008,52 @@ void igate_send_rec_packet (int chan, packet_t recv_pp) // TODO: Should we drop raw touch tone data object type generated here? + +/* + * If the SATgate mode is enabled, see if it should be delayed. + * The rule is if we hear it directly and it has at least one + * digipeater so there is potential of being re-transmitted. + * (Digis are all unused if we are hearing it directly from source.) + */ + if (save_igate_config_p->satgate_delay > 0 && + ax25_get_heard(pp) == AX25_SOURCE && + ax25_get_num_repeaters(pp) > 0) { + + satgate_delay_packet (pp, chan); + } + else { + send_packet_to_server (pp, chan); + } + +} /* end igate_send_rec_packet */ + + + +/*------------------------------------------------------------------- + * + * Name: send_packet_to_server + * + * Purpose: Convert to text and send to the IGate server. + * + * Inputs: pp - Packet object. + * + * chan - Radio channel where it was received. + * + * Description: Duplicate detection is handled here. + * Suppress if same was sent recently. + * + *--------------------------------------------------------------------*/ + +static void send_packet_to_server (packet_t pp, int chan) +{ + unsigned char *pinfo; + int info_len; + char msg[IGATE_MAX_MSG]; + + + info_len = ax25_get_info (pp, &pinfo); + (void)(info_len); + /* * Do not relay if a duplicate of something sent recently. */ @@ -1004,9 +1088,7 @@ void igate_send_rec_packet (int chan, packet_t recv_pp) ax25_delete (pp); -} /* end igate_send_rec_packet */ - - +} /* end send_packet_to_server */ @@ -1259,6 +1341,126 @@ static void * igate_recv_thread (void *arg) } /* end igate_recv_thread */ + +/*------------------------------------------------------------------- + * + * Name: satgate_delay_packet + * + * Purpose: Put packet into holding area for a while rather than + * sending it immediately to the IS server. + * + * Inputs: pp - Packet object. + * + * chan - Radio channel where received. + * + * Outputs: Appended to queue. + * + * Description: If we hear a packet directly and the same one digipeated, + * we only send the first to the APRS IS due to duplicate removal. + * It may be desirable to favor the digipeated packet over the + * original. For this situation, we have an option which delays + * a packet if we hear it directly and the via path is not empty. + * We know we heard it directly if none of the digipeater + * addresses have been used. + * This way the digipeated packet will go first. + * The original is sent about 10 seconds later. + * Duplicate removal will drop the original if there is no + * corresponding digipeated version. + * + *--------------------------------------------------------------------*/ + +static void satgate_delay_packet (packet_t pp, int chan) +{ + packet_t pnext, plast; + + + //if (s_debug >= 1) { + text_color_set(DW_COLOR_INFO); + dw_printf ("Rx IGate: SATgate mode, delay packet heard directly.\n"); + //} + + ax25_set_release_time (pp, dtime_now() + save_igate_config_p->satgate_delay); +//TODO: save channel too. + + dw_mutex_lock (&dp_mutex); + + if (dp_queue_head == NULL) { + dp_queue_head = pp; + } + else { + plast = dp_queue_head; + while ((pnext = ax25_get_nextp(plast)) != NULL) { + plast = pnext; + } + ax25_set_nextp (plast, pp); + } + + dw_mutex_unlock (&dp_mutex); + +} /* end satgate_delay_packet */ + + + +/*------------------------------------------------------------------- + * + * Name: satgate_delay_thread + * + * Purpose: Release packet when specified release time has arrived. + * + * Inputs: dp_queue_head - Queue of packets. + * + * Outputs: Sent to APRS IS. + * + * Description: For simplicity we'll just poll each second. + * Release the packet when its time has arrived. + * + *--------------------------------------------------------------------*/ + +#if __WIN32__ +static unsigned __stdcall satgate_delay_thread (void *arg) +#else +static void * satgate_delay_thread (void *arg) +#endif +{ + double release_time; + int chan = 0; // TODO: get receive channel somehow. + // only matters if multi channel with different names. + + while (1) { + SLEEP_SEC (1); + +/* Don't need critical region just to peek */ + + if (dp_queue_head != NULL) { + + double now = dtime_now(); + + release_time = ax25_get_release_time (dp_queue_head); + +#if 0 + text_color_set(DW_COLOR_DEBUG); + dw_printf ("SATgate: %.1f sec remaining\n", release_time - now); +#endif + if (now > release_time) { + packet_t pp; + + dw_mutex_lock (&dp_mutex); + + pp = dp_queue_head; + dp_queue_head = ax25_get_nextp(pp); + + dw_mutex_unlock (&dp_mutex); + ax25_set_nextp (pp, NULL); + + send_packet_to_server (pp, chan); + } + } /* if something in queue */ + } /* while (1) */ + return (0); + +} /* end satgate_delay_thread */ + + /*------------------------------------------------------------------- * * Name: xmit_packet diff --git a/igate.h b/igate.h index 1736d04..3e2d003 100644 --- a/igate.h +++ b/igate.h @@ -20,6 +20,7 @@ #define DEFAULT_IGATE_PORT 14580 + struct igate_config_s { /* @@ -53,6 +54,10 @@ struct igate_config_s { int tx_limit_1; /* Max. packets to transmit in 1 minute. */ int tx_limit_5; /* Max. packets to transmit in 5 minutes. */ +/* + * Special SATgate mode to delay packets heard directly. + */ + int satgate_delay; /* seconds. 0 to disable. */ }; @@ -62,6 +67,10 @@ struct igate_config_s { #define IGATE_TX_LIMIT_5_DEFAULT 20 #define IGATE_TX_LIMIT_5_MAX 80 +#define DEFAULT_SATGATE_DELAY 10 +#define MIN_SATGATE_DELAY 5 +#define MAX_SATGATE_DELAY 30 + /* Call this once at startup */