diff --git a/CHANGES.md b/CHANGES.md index b7e8d93..2f95bc4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@ # Revision History # -## Version 1.5 -- Development snapshot C -- September 2017 ## +## Version 1.5 -- Development snapshot C -- October 2017 ## This is a snapshot of ongoing development towards version of 1.5. Some features might be incomplete or broken or not documented properly. @@ -9,6 +9,8 @@ This is a snapshot of ongoing development towards version of 1.5. Some features - "kissutil" for troubleshooting a KISS TNC or interfacing to an application via files. +- KISS "Set Hardware" command to report transmit queue length. + ### Bugs Fixed: ### diff --git a/ax25_pad.c b/ax25_pad.c index 180085a..23e061b 100644 --- a/ax25_pad.c +++ b/ax25_pad.c @@ -2000,7 +2000,7 @@ int ax25_pack (packet_t this_p, unsigned char result[AX25_MAX_PACKET_LEN]) assert (this_p->magic1 == MAGIC); assert (this_p->magic2 == MAGIC); - assert (this_p->frame_len > 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); + assert (this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); memcpy (result, this_p->frame_data, this_p->frame_len); @@ -2503,6 +2503,33 @@ int ax25_get_pid (packet_t this_p) } + +/*------------------------------------------------------------------ + * + * Function: ax25_get_frame_len + * + * Purpose: Get length of frame. + * + * Inputs: this_p - pointer to packet object. + * + * Returns: Number of octets in the frame buffer. + * Does NOT include the extra 2 for FCS. + * + *------------------------------------------------------------------*/ + +int ax25_get_frame_len (packet_t this_p) +{ + assert (this_p->magic1 == MAGIC); + assert (this_p->magic2 == MAGIC); + + assert (this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN); + + return (this_p->frame_len); + +} /* end ax25_get_frame_len */ + + + /*------------------------------------------------------------------------------ * * Name: ax25_dedupe_crc diff --git a/ax25_pad.h b/ax25_pad.h index 6e859b1..72155b2 100644 --- a/ax25_pad.h +++ b/ax25_pad.h @@ -427,6 +427,8 @@ extern int ax25_get_c2 (packet_t this_p); extern int ax25_get_pid (packet_t this_p); +extern int ax25_get_frame_len (packet_t this_p); + extern unsigned short ax25_dedupe_crc (packet_t pp); extern unsigned short ax25_m_m_crc (packet_t pp); diff --git a/kiss_frame.c b/kiss_frame.c index 6129687..1db115c 100644 --- a/kiss_frame.c +++ b/kiss_frame.c @@ -25,7 +25,7 @@ * * Purpose: Common code used by Serial port and network versions of KISS protocol. * - * Description: The KISS TNS protocol is described in http://www.ka9q.net/papers/kiss.html + * Description: The KISS TNC protocol is described in http://www.ka9q.net/papers/kiss.html * * ( An extended form, to handle multiple TNCs on a single serial port. * Not applicable for our situation. http://he.fi/pub/oh7lzb/bpq/multi-kiss.pdf ) @@ -40,11 +40,11 @@ * * The first byte of the frame contains: * - * * port number in upper nybble. + * * port number (radio channel) in upper nybble. * * command in lower nybble. * * - * Commands from application recognized: + * Commands from application tp TNC: * * _0 Data Frame AX.25 frame in raw format. * @@ -72,6 +72,9 @@ * * _0 Data Frame Received AX.25 frame in raw format. * + * _6 SetHardware TNC specific. + * Usually a response to a query. + * *---------------------------------------------------------------*/ #include "direwolf.h" @@ -88,6 +91,8 @@ #include "kiss_frame.h" #include "tq.h" #include "xmit.h" +#include "version.h" + /* In server.c. Should probably move to some misc. function file. */ void hex_dump (unsigned char *p, int len); @@ -138,10 +143,10 @@ static void kiss_set_hardware (int chan, char *command, int debug, int client, v #endif -#if KISSUTIL -#define text_color_set(x) ; -#define dw_printf printf -#endif +//#if KISSUTIL +//#define text_color_set(x) ; +//#define dw_printf printf +//#endif /*------------------------------------------------------------------- @@ -171,6 +176,7 @@ void kiss_frame_init (struct audio_s *pa) * Inputs: in - Address of input block. * First byte is the "type indicator" with type and * channel but we don't care about that here. + * If it happens to be FEND or FESC, it is escaped, like any other byte. * * This seems cumbersome and confusing to have this * one byte offset when encapsulating an AX.25 frame. @@ -190,7 +196,7 @@ void kiss_frame_init (struct audio_s *pa) * FEND - Magic frame separator. * * Returns: Number of bytes in the output. - * Absolute max length will be twice input plus 2. + * Absolute max length (extremely unlikely) will be twice input plus 2. * *-----------------------------------------------------------------*/ @@ -242,6 +248,8 @@ int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out) * the escapes or FEND. * First byte is the "type indicator" with type and * channel but we don't care about that here. + * We treat it like any other byte with special handling + * if it happens to be FESC. * Note that this is "binary" data and can contain * nul (0x00) values. Don't treat it like a text string! * @@ -509,6 +517,8 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v // Some functions are only for the TNC end. // Other functions are suitble for both TNC and client app. +// This is used only by the TNC sided. + void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int)) { int port; @@ -690,6 +700,7 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli * debug - debug level. * * client - Client app number for TCP KISS. + * Needed so we can send any response to the right client app. * Ignored for pseudo terminal and serial port. * * sendfun - Function to send something to the client application. @@ -713,13 +724,17 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli * be used for throttling of large transmissions and performing some action * after the last frame has been sent. * - * The original KISS protocol spec offers no guidance on what this might look + * The original KISS protocol spec offers no guidance on what "Set Hardware" might look * like. I'm aware of only two, drastically different, implementations: * * fldigi - http://www.w1hkj.com/FldigiHelp-3.22/kiss_command_page.html * - * Everything is in human readable text in the form of: - * COMMAND : [ parameter [ , parameter ... ] ] + * Everything is in human readable in both directions: + * + * COMMAND: [ parameter [ , parameter ... ] ] + * + * Lack of a parameter, in the client to TNC direction, is a query + * which should generate a response in the same format. * * Used by applications, http://www.w1hkj.com/FldigiHelp/kiss_host_prgs_page.html * - BPQ32 @@ -740,6 +755,19 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli * * Let's start with the easy to understand human readable format. * + * Commands: (Client to TNC, with parameter(s) to set something.) + * + * none yet + * + * Queries: (Client to TNC, no parameters, generate a response.) + * + * Query Response Comment + * ----- -------- ------- + * + * TNC: TNC:DIREWOLF 9.9 9.9 represents current version. + * + * TXBUF: TXBUF:999 Number of bytes (not frames) in transmit queue. + * *--------------------------------------------------------------------*/ #ifndef KISSUTIL @@ -754,39 +782,37 @@ static void kiss_set_hardware (int chan, char *command, int debug, int client, v *param = '\0'; param++; - if (strcmp(command, "TXBUF") == 0) { /* Number of frames in transmit queue. */ + if (strcmp(command, "TNC") == 0) { /* TNC - Identify software version. */ if (strlen(param) > 0) { text_color_set(DW_COLOR_ERROR); - dw_printf ("KISS Set Hardware TXBUF: did not expect a parameter.\n"); + dw_printf ("KISS Set Hardware TNC: Did not expect a parameter.\n"); } - // See what we have in the transmit queue for specified channel. - // fldigi uses bytes but frames seems to make more sense in this situation. - // Do we add one if PTT is on? That information doesn't seem to be easily available. - -// TODO: FIXME: not implemented yet. - - // n = tq_count (chan, TQ_PRIO_0_HI) + tq_count (chan, TQ_PRIO_1_LO); - - snprintf (response, sizeof(response), "TXBUF:whatever"); - + snprintf (response, sizeof(response), "DIREWOLF %d.%d", MAJOR_VERSION, MINOR_VERSION); (*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), client); } - else if (strcmp(command, "TNC") == 0) { /* Identify software version. */ - ; // TODO... - } - else if (strcmp(command, "TRXS") == 0) { - ; // TODO... BUSY + + else if (strcmp(command, "TXBUF") == 0) { /* TXBUF - Number of bytes in transmit queue. */ + + if (strlen(param) > 0) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("KISS Set Hardware TXBUF: Did not expect a parameter.\n"); + } + + int n = tq_count (chan, -1, "", "", 1); + snprintf (response, sizeof(response), "TXBUF:%d", n); + (*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), client); } + else { text_color_set(DW_COLOR_ERROR); - dw_printf ("KISS Set Hardware invalid command.\n"); + dw_printf ("KISS Set Hardware unrecognized command: %s.\n", command); } } else { text_color_set(DW_COLOR_ERROR); - dw_printf ("KISS Set Hardware expected the form COMMAND:[parameter[,parameter...]]\n"); + dw_printf ("KISS Set Hardware \"%s\" expected the form COMMAND:[parameter[,parameter...]]\n", command); } return; diff --git a/server.c b/server.c index 0a35178..243b351 100644 --- a/server.c +++ b/server.c @@ -1705,7 +1705,17 @@ static THREAD_F cmd_listen_thread (void *arg) struct via_info { unsigned char num_digi; /* Expect to be in range 1 to 7. Why not up to 8? */ char dcall[7][10]; - } *v = (struct via_info *)cmd.data; + } +#if 1 + // October 2017. gcc ??? complained: + // warning: dereferencing pointer 'v' does break strict-aliasing rules + // Try adding this attribute to get rid of the warning. + // If this upsets your compiler, take it out. + // Let me know. Maybe we could put in a compiler version check here. + + __attribute__((__may_alias__)) +#endif + *v = (struct via_info *)cmd.data; char callsigns[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN]; int num_calls = 2; /* 2 plus any digipeaters. */ @@ -1866,7 +1876,7 @@ static THREAD_F cmd_listen_thread (void *arg) int n = 0; if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) { - n = tq_count (cmd.hdr.portx, -1, "", ""); + n = tq_count (cmd.hdr.portx, -1, "", "", 0); } reply.data_NETLE = host2netle(n); @@ -1899,7 +1909,7 @@ static THREAD_F cmd_listen_thread (void *arg) int n = 0; if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) { - n = tq_count (cmd.hdr.portx, -1, source, dest); + n = tq_count (cmd.hdr.portx, -1, source, dest, 0); } reply.data_NETLE = host2netle(n); diff --git a/tq.c b/tq.c index d805a74..79bdcf9 100644 --- a/tq.c +++ b/tq.c @@ -281,7 +281,7 @@ void tq_append (int chan, int prio, packet_t pp) * Implementing the 6PACK protocol is probably the proper solution. */ - if (ax25_is_aprs(pp) && tq_count(chan,prio,"","") > 100) { + if (ax25_is_aprs(pp) && tq_count(chan,prio,"","",0) > 100) { text_color_set(DW_COLOR_ERROR); dw_printf ("Transmit packet queue for channel %d is too long. Discarding packet.\n", chan); dw_printf ("Perhaps the channel is so busy there is no opportunity to send.\n"); @@ -458,7 +458,7 @@ void lm_data_request (int chan, int prio, packet_t pp) * Is transmit queue out of control? */ - if (tq_count(chan,prio,"","") > 250) { + if (tq_count(chan,prio,"","",0) > 250) { text_color_set(DW_COLOR_ERROR); dw_printf ("Warning: Transmit packet queue for channel %d is extremely long.\n", chan); dw_printf ("Perhaps the channel is so busy there is no opportunity to send.\n"); @@ -912,7 +912,7 @@ static int tq_is_empty (int chan) * * Name: tq_count * - * Purpose: Return count of the number of packets in the specified transmit queue. + * Purpose: Return count of the number of packets (or bytes) in the specified transmit queue. * This is used only for queries from KISS or AWG client applications. * * Inputs: chan - Channel, 0 is first. @@ -924,56 +924,71 @@ static int tq_is_empty (int chan) * * dest - If specified, count only those with this destination address. * + * bytes - If true, return number of bytes rather than packets. + * * Returns: Number of items in specified queue. * *--------------------------------------------------------------------*/ -int tq_count (int chan, int prio, char *source, char *dest) +int tq_count (int chan, int prio, char *source, char *dest, int bytes) { - packet_t p; + packet_t pp; int n; if (prio == -1) { - return (tq_count(chan, TQ_PRIO_0_HI, source, dest) - + tq_count(chan, TQ_PRIO_1_LO, source, dest)); + return (tq_count(chan, TQ_PRIO_0_HI, source, dest, bytes) + + tq_count(chan, TQ_PRIO_1_LO, source, dest, bytes)); } - // Array bounds check. FIXME: TODO: should have internal error instead of dying. - assert (chan >= 0 && chan < MAX_CHANS); - assert (prio >= 0 && prio < TQ_NUM_PRIO); + if (chan < 0 || chan >= MAX_CHANS || prio < 0 || prio >= TQ_NUM_PRIO) { + text_color_set(DW_COLOR_DEBUG); + dw_printf ("INTERNAL ERROR - tq_count(%d, %d, \"%s\", \"%s\", %d)\n", chan, prio, source, dest, bytes); + return (0); + } + + if (queue_head[chan][prio] == 0) { + return (0); + } // Don't want lists being rearranged while we are traversing them. dw_mutex_lock (&tq_mutex); n = 0; - p = queue_head[chan][prio]; - while (p != NULL) { + pp = queue_head[chan][prio]; + while (pp != NULL) { int count_it = 1; if (source != NULL && *source != '\0') { char frame_source[AX25_MAX_ADDR_LEN]; - ax25_get_addr_with_ssid (p, AX25_SOURCE, frame_source); + ax25_get_addr_with_ssid (pp, AX25_SOURCE, frame_source); if (strcmp(source,frame_source) != 0) count_it = 0; } if (count_it && dest != NULL && *dest != '\0') { char frame_dest[AX25_MAX_ADDR_LEN]; - ax25_get_addr_with_ssid (p, AX25_DESTINATION, frame_dest); + ax25_get_addr_with_ssid (pp, AX25_DESTINATION, frame_dest); if (strcmp(dest,frame_dest) != 0) count_it = 0; } - if (count_it) n++; - p = ax25_get_nextp(p); + if (count_it) { + if (bytes) { + n += ax25_get_frame_len(pp); + } + else { + n++; + } + } + pp = ax25_get_nextp(pp); } dw_mutex_unlock (&tq_mutex); #if DEBUG text_color_set(DW_COLOR_DEBUG); - dw_printf ("tq_count(%d, %d, \"%s\", \"%s\") returns %d\n", chan, prio, source, dest, n); + dw_printf ("tq_count(%d, %d, \"%s\", \"%s\", %d) returns %d\n", chan, prio, source, dest, bytes, n); #endif return (n); diff --git a/tq.h b/tq.h index 471fd5d..37599d5 100644 --- a/tq.h +++ b/tq.h @@ -34,7 +34,7 @@ packet_t tq_remove (int chan, int prio); packet_t tq_peek (int chan, int prio); -int tq_count (int chan, int prio, char *source, char *dest); +int tq_count (int chan, int prio, char *source, char *dest, int bytes); #endif