KISS Set Hardware commands TNC, TXBUF.

This commit is contained in:
wb2osz 2017-10-05 21:31:52 -04:00
parent cc84a610dd
commit c23ab04338
7 changed files with 135 additions and 53 deletions

View File

@ -1,7 +1,7 @@
# Revision History # # 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. 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. - "kissutil" for troubleshooting a KISS TNC or interfacing to an application via files.
- KISS "Set Hardware" command to report transmit queue length.
### Bugs Fixed: ### ### Bugs Fixed: ###

View File

@ -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->magic1 == MAGIC);
assert (this_p->magic2 == 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); 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 * Name: ax25_dedupe_crc

View File

@ -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_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_dedupe_crc (packet_t pp);
extern unsigned short ax25_m_m_crc (packet_t pp); extern unsigned short ax25_m_m_crc (packet_t pp);

View File

@ -25,7 +25,7 @@
* *
* Purpose: Common code used by Serial port and network versions of KISS protocol. * 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. * ( 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 ) * 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: * The first byte of the frame contains:
* *
* * port number in upper nybble. * * port number (radio channel) in upper nybble.
* * command in lower nybble. * * command in lower nybble.
* *
* *
* Commands from application recognized: * Commands from application tp TNC:
* *
* _0 Data Frame AX.25 frame in raw format. * _0 Data Frame AX.25 frame in raw format.
* *
@ -72,6 +72,9 @@
* *
* _0 Data Frame Received AX.25 frame in raw format. * _0 Data Frame Received AX.25 frame in raw format.
* *
* _6 SetHardware TNC specific.
* Usually a response to a query.
*
*---------------------------------------------------------------*/ *---------------------------------------------------------------*/
#include "direwolf.h" #include "direwolf.h"
@ -88,6 +91,8 @@
#include "kiss_frame.h" #include "kiss_frame.h"
#include "tq.h" #include "tq.h"
#include "xmit.h" #include "xmit.h"
#include "version.h"
/* In server.c. Should probably move to some misc. function file. */ /* In server.c. Should probably move to some misc. function file. */
void hex_dump (unsigned char *p, int len); 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 #endif
#if KISSUTIL //#if KISSUTIL
#define text_color_set(x) ; //#define text_color_set(x) ;
#define dw_printf printf //#define dw_printf printf
#endif //#endif
/*------------------------------------------------------------------- /*-------------------------------------------------------------------
@ -171,6 +176,7 @@ void kiss_frame_init (struct audio_s *pa)
* Inputs: in - Address of input block. * Inputs: in - Address of input block.
* First byte is the "type indicator" with type and * First byte is the "type indicator" with type and
* channel but we don't care about that here. * 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 * This seems cumbersome and confusing to have this
* one byte offset when encapsulating an AX.25 frame. * 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. * FEND - Magic frame separator.
* *
* Returns: Number of bytes in the output. * 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. * the escapes or FEND.
* First byte is the "type indicator" with type and * First byte is the "type indicator" with type and
* channel but we don't care about that here. * 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 * Note that this is "binary" data and can contain
* nul (0x00) values. Don't treat it like a text string! * 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. // Some functions are only for the TNC end.
// Other functions are suitble for both TNC and client app. // 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)) 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; int port;
@ -690,6 +700,7 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
* debug - debug level. * debug - debug level.
* *
* client - Client app number for TCP KISS. * 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. * Ignored for pseudo terminal and serial port.
* *
* sendfun - Function to send something to the client application. * 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 * be used for throttling of large transmissions and performing some action
* after the last frame has been sent. * 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: * like. I'm aware of only two, drastically different, implementations:
* *
* fldigi - http://www.w1hkj.com/FldigiHelp-3.22/kiss_command_page.html * fldigi - http://www.w1hkj.com/FldigiHelp-3.22/kiss_command_page.html
* *
* Everything is in human readable text in the form of: * Everything is in human readable in both directions:
* COMMAND : [ parameter [ , parameter ... ] ] *
* 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 * Used by applications, http://www.w1hkj.com/FldigiHelp/kiss_host_prgs_page.html
* - BPQ32 * - 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. * 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 #ifndef KISSUTIL
@ -754,39 +782,37 @@ static void kiss_set_hardware (int chan, char *command, int debug, int client, v
*param = '\0'; *param = '\0';
param++; 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) { if (strlen(param) > 0) {
text_color_set(DW_COLOR_ERROR); 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. snprintf (response, sizeof(response), "DIREWOLF %d.%d", MAJOR_VERSION, MINOR_VERSION);
// 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");
(*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), client); (*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, "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");
} }
else if (strcmp(command, "TRXS") == 0) {
; // TODO... BUSY 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 { else {
text_color_set(DW_COLOR_ERROR); 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 { else {
text_color_set(DW_COLOR_ERROR); 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; return;

View File

@ -1705,7 +1705,17 @@ static THREAD_F cmd_listen_thread (void *arg)
struct via_info { struct via_info {
unsigned char num_digi; /* Expect to be in range 1 to 7. Why not up to 8? */ unsigned char num_digi; /* Expect to be in range 1 to 7. Why not up to 8? */
char dcall[7][10]; 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]; char callsigns[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
int num_calls = 2; /* 2 plus any digipeaters. */ int num_calls = 2; /* 2 plus any digipeaters. */
@ -1866,7 +1876,7 @@ static THREAD_F cmd_listen_thread (void *arg)
int n = 0; int n = 0;
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) { 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); reply.data_NETLE = host2netle(n);
@ -1899,7 +1909,7 @@ static THREAD_F cmd_listen_thread (void *arg)
int n = 0; int n = 0;
if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) { 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); reply.data_NETLE = host2netle(n);

49
tq.c
View File

@ -281,7 +281,7 @@ void tq_append (int chan, int prio, packet_t pp)
* Implementing the 6PACK protocol is probably the proper solution. * 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Transmit packet queue for channel %d is too long. Discarding packet.\n", chan); 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"); 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? * 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); text_color_set(DW_COLOR_ERROR);
dw_printf ("Warning: Transmit packet queue for channel %d is extremely long.\n", chan); 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"); 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 * 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. * This is used only for queries from KISS or AWG client applications.
* *
* Inputs: chan - Channel, 0 is first. * 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. * 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. * 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; int n;
if (prio == -1) { if (prio == -1) {
return (tq_count(chan, TQ_PRIO_0_HI, source, dest) return (tq_count(chan, TQ_PRIO_0_HI, source, dest, bytes)
+ tq_count(chan, TQ_PRIO_1_LO, source, dest)); + tq_count(chan, TQ_PRIO_1_LO, source, dest, bytes));
} }
// Array bounds check. FIXME: TODO: should have internal error instead of dying. // Array bounds check. FIXME: TODO: should have internal error instead of dying.
assert (chan >= 0 && chan < MAX_CHANS); if (chan < 0 || chan >= MAX_CHANS || prio < 0 || prio >= TQ_NUM_PRIO) {
assert (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. // Don't want lists being rearranged while we are traversing them.
dw_mutex_lock (&tq_mutex); dw_mutex_lock (&tq_mutex);
n = 0; n = 0;
p = queue_head[chan][prio]; pp = queue_head[chan][prio];
while (p != NULL) { while (pp != NULL) {
int count_it = 1; int count_it = 1;
if (source != NULL && *source != '\0') { if (source != NULL && *source != '\0') {
char frame_source[AX25_MAX_ADDR_LEN]; 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 (strcmp(source,frame_source) != 0) count_it = 0;
} }
if (count_it && dest != NULL && *dest != '\0') { if (count_it && dest != NULL && *dest != '\0') {
char frame_dest[AX25_MAX_ADDR_LEN]; 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 (strcmp(dest,frame_dest) != 0) count_it = 0;
} }
if (count_it) n++; if (count_it) {
p = ax25_get_nextp(p); if (bytes) {
n += ax25_get_frame_len(pp);
}
else {
n++;
}
}
pp = ax25_get_nextp(pp);
} }
dw_mutex_unlock (&tq_mutex); dw_mutex_unlock (&tq_mutex);
#if DEBUG #if DEBUG
text_color_set(DW_COLOR_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 #endif
return (n); return (n);

2
tq.h
View File

@ -34,7 +34,7 @@ packet_t tq_remove (int chan, int prio);
packet_t tq_peek (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 #endif