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 #
## 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: ###

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->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

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_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);

View File

@ -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;

View File

@ -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);

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.
*/
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);

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);
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