decode_aprs can now process KISS or AX.25 frames as sequences of hexadecimal numbers.

This commit is contained in:
WB2OSZ 2017-05-24 19:25:08 -04:00
parent 3ce981c196
commit be7ee8211e
10 changed files with 278 additions and 48 deletions

View File

@ -14,6 +14,8 @@ This is a snapshot of ongoing development towards version of 1.5. Some features
- New document ***Bluetooth-KISS-TNC.pdf*** explaining how to use KISS over Bluetooth. - New document ***Bluetooth-KISS-TNC.pdf*** explaining how to use KISS over Bluetooth.
- decode_aprs utility can now accept KISS frames and AX.25 frames as series of two digit hexadecimal numbers.
### Bugs Fixed: ### ### Bugs Fixed: ###
- Little spelling errors in messages ???? - Little spelling errors in messages ????

View File

@ -2,6 +2,9 @@
# Makefile for Linux version of Dire Wolf. # Makefile for Linux version of Dire Wolf.
# #
APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc
all : $(APPS) direwolf.desktop direwolf.conf all : $(APPS) direwolf.desktop direwolf.conf
@ -259,6 +262,16 @@ endif
CFLAGS += -DUSE_ALSA CFLAGS += -DUSE_ALSA
LDFLAGS += -lasound LDFLAGS += -lasound
ifeq ($(wildcard /usr/include/pthread.h),)
$(error /usr/include/pthread.h does not exist. Install it with "sudo apt-get install libc6-dev" or "sudo yum install libc6-dev" )
endif
ifneq ($(USE_ALSA),)
ifeq ($(wildcard /usr/include/alsa/asoundlib.h),)
$(error /usr/include/alsa/asoundlib.h does not exist. Install it with "sudo apt-get install libasound2-dev" or "sudo yum install libasound2-dev" )
endif
endif
# Enable GPS if header file is present. # Enable GPS if header file is present.
# Finding libgps.so* is more difficult because it # Finding libgps.so* is more difficult because it
@ -355,7 +368,9 @@ tocalls-symbols :
# Separate application to decode raw data. # Separate application to decode raw data.
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o misc.a # First two use .c rather than .o because they depend on DECAMAIN definition.
decode_aprs : decode_aprs.c kiss_frame.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o misc.a
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ $(LDFLAGS) $(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ $(LDFLAGS)
@ -638,7 +653,8 @@ install-conf : direwolf.conf
cp -n telemetry-toolkit/telem-*.conf ~ cp -n telemetry-toolkit/telem-*.conf ~
ifneq ($(wildcard $(HOME)/Desktop),) ifneq ($(wildcard $(HOME)/Desktop),)
@echo " " @echo " "
@echo "This will add a desktop icon on some systems:" @echo "This will add a desktop icon on some systems."
@echo "This is known to work on Raspberry Pi but might not be compatible with other desktops."
@echo " " @echo " "
@echo " make install-rpi" @echo " make install-rpi"
@echo " " @echo " "

View File

@ -430,7 +430,9 @@ install-conf : direwolf.conf
# Separate application to decode raw data. # Separate application to decode raw data.
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o # First two use .c rather than .o because they depend on DECAMAIN definition.
decode_aprs : decode_aprs.c kiss_frame.c dwgpsnmea.o dwgps.o dwgpsd.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ -lm $(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ -lm
# Convert between text and touch tone representation. # Convert between text and touch tone representation.

View File

@ -159,7 +159,9 @@ tocalls-symbols :
# Separate application to decode raw data. # Separate application to decode raw data.
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.c regex.a misc.a geotranz.a # First two use .c rather than .o because they depend on DECAMAIN definition.
decode_aprs : decode_aprs.c kiss_frame.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o regex.a misc.a geotranz.a
$(CC) $(CFLAGS) -DDECAMAIN -o decode_aprs $^ $(CC) $(CFLAGS) -DDECAMAIN -o decode_aprs $^

View File

@ -760,12 +760,18 @@ int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, in
maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN-1); maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN-1);
p = in_addr; p = in_addr;
i = 0; i = 0;
for (p = in_addr; isalnum(*p); p++) { for (p = in_addr; *p != '\0' && *p != '-'; p++) {
if (i >= maxlen) { if (i >= maxlen) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen); dw_printf ("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen);
return 0; return 0;
} }
if ( ! isalnum(*p)) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p-in_addr)+1);
return 0;
}
out_addr[i++] = *p; out_addr[i++] = *p;
out_addr[i] = '\0'; out_addr[i] = '\0';
if (strict && islower(*p)) { if (strict && islower(*p)) {
@ -1257,13 +1263,22 @@ void ax25_get_addr_with_ssid (packet_t this_p, int n, char *station)
return; return;
} }
memset (station, 0, 7); // At one time this would stop at the first space, on the assumption we would have only trailing spaces.
for (i=0; i<6; i++) { // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space.
unsigned char ch; // In that case, we would have returned a zero length string here.
// Now we return exactly what is in the address field and trim trailing spaces.
// This will provide better information for troubleshooting.
ch = (this_p->frame_data[n*7+i] >> 1) & 0x7f; for (i=0; i<6; i++) {
if (ch <= ' ') break; station[i] = (this_p->frame_data[n*7+i] >> 1) & 0x7f;
station[i] = ch; }
station[6] = '\0';
for (i=5; i>=0; i--) {
if (station[i] == ' ')
station[i] = '\0';
else
break;
} }
ssid = ax25_get_ssid (this_p, n); ssid = ax25_get_ssid (this_p, n);
@ -1322,13 +1337,22 @@ void ax25_get_addr_no_ssid (packet_t this_p, int n, char *station)
return; return;
} }
memset (station, 0, 7); // At one time this would stop at the first space, on the assumption we would have only trailing spaces.
for (i=0; i<6; i++) { // Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space.
unsigned char ch; // In that case, we would have returned a zero length string here.
// Now we return exactly what is in the address field and trim trailing spaces.
// This will provide better information for troubleshooting.
ch = (this_p->frame_data[n*7+i] >> 1) & 0x7f; for (i=0; i<6; i++) {
if (ch <= ' ') break; station[i] = (this_p->frame_data[n*7+i] >> 1) & 0x7f;
station[i] = ch; }
station[6] = '\0';
for (i=5; i>=0; i--) {
if (station[i] == ' ')
station[i] = '\0';
else
break;
} }
} /* end ax25_get_addr_no_ssid */ } /* end ax25_get_addr_no_ssid */

View File

@ -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, 2013, 2014, 2015 John Langner, WB2OSZ // Copyright (C) 2011, 2012, 2013, 2014, 2015, 2017 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
@ -4583,6 +4583,14 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
* *
* WB2OSZ-1>APN383,qAR,N1EDU-2:!4237.14NS07120.83W#PHG7130Chelmsford, MA * WB2OSZ-1>APN383,qAR,N1EDU-2:!4237.14NS07120.83W#PHG7130Chelmsford, MA
* *
* New for 1.5:
*
* Also allow hexadecimal bytes for raw AX.25 or KISS. e.g.
*
* 00 82 a0 ae ae 62 60 e0 82 96 68 84 40 40 60 9c 68 b0 ae 86 40 e0 40 ae 92 88 8a 64 63 03 f0 3e 45 4d 36 34 6e 65 2f 23 20 45 63 68 6f 6c 69 6e 6b 20 31 34 35 2e 33 31 30 2f 31 30 30 68 7a 20 54 6f 6e 65
*
* If it begins with 00 or C0 (which would be impossible for AX.25 address) process as KISS.
* Also print these formats.
* *
* Outputs: stdout * Outputs: stdout
* *
@ -4614,11 +4622,16 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
* TODO: To make it more useful, * TODO: To make it more useful,
* - Remove any leading timestamp. * - Remove any leading timestamp.
* - Remove any "qA*" and following from the path. * - Remove any "qA*" and following from the path.
* - Handle non-APRS frames properly.
* *
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
#if DECAMAIN #if DECAMAIN
#include "kiss_frame.h"
/* Stub for stand-alone decoder. */ /* Stub for stand-alone decoder. */
void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab, char symbol, void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab, char symbol,
@ -4627,11 +4640,48 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
return; return;
} }
// TODO: hex_dump is currently in server.c and we don't want to drag that in.
// Someday put it in a more reasonable place, with other general utilities, and remove the private copy here.
static void hex_dump (unsigned char *p, int len)
{
int n, i, offset;
offset = 0;
while (len > 0) {
n = len < 16 ? len : 16;
dw_printf (" %03x: ", offset);
for (i=0; i<n; i++) {
dw_printf (" %02x", p[i]);
}
for (i=n; i<16; i++) {
dw_printf (" ");
}
dw_printf (" ");
for (i=0; i<n; i++) {
dw_printf ("%c", isprint(p[i]) ? p[i] : '.');
}
dw_printf ("\n");
p += 16;
offset += 16;
len -= 16;
}
}
// Do we have two hexadecimal digits followed by whitespace or end of line?
#define ISHEX2(x) (isxdigit(x[0]) && isxdigit(x[1]) && (x[2] == '\0' || isspace(x[2])))
#define MAXLINE 9000
#define MAXBYTES 3000
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
char stuff[300]; char stuff[MAXLINE];
unsigned char bytes[MAXBYTES];
int num_bytes;
char *p; char *p;
packet_t pp; packet_t pp;
@ -4687,37 +4737,149 @@ int main (int argc, char *argv[])
text_color_set(DW_COLOR_REC); text_color_set(DW_COLOR_REC);
dw_printf("\n%s\n", stuff); dw_printf("\n%s\n", stuff);
pp = ax25_from_text(stuff, 1); // Do we have monitor format, KISS, or AX.25 frame?
if (pp != NULL)
{
decode_aprs_t A;
// log directory option someday? p = stuff;
decode_aprs (&A, pp, 0); while (isspace(*p)) p++;
//Print it all out in human readable format. if (ISHEX2(p)) {
decode_aprs_print (&A); // Collect a bunch of hexadecimal numbers.
/* num_bytes = 0;
* Perform validity check on each address.
* This should print an error message if any issues.
*/
(void)ax25_check_addresses(pp);
// Send to log file? while (ISHEX2(p) && num_bytes < MAXBYTES) {
// if (logdir != NULL && *logdir != '\0') { bytes[num_bytes++] = strtoul(p, NULL, 16);
// log_write (&A, pp, logdir); p += 2;
// } while (isspace(*p)) p++;
}
ax25_delete (pp); if (num_bytes == 0 || *p != '\0') {
text_color_set(DW_COLOR_ERROR);
dw_printf("Parse error around column %d.\n", (int)(long)(p - stuff) + 1);
dw_printf("Was expecting only space separated 2 digit hexadecimal numbers.\n\n");
continue; // next line
}
// If we have 0xC0 at start, remove it and expect same at end.
if (bytes[0] == FEND) {
if (bytes[1] != 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf("Was expecting to find 00 after the initial C0.\n");
continue;
}
if (bytes[num_bytes-1] == FEND) {
text_color_set(DW_COLOR_INFO);
dw_printf("Removing KISS FEND characters at beginning and end.\n");
int n;
for (n = 0; n < num_bytes-1; n++) {
bytes[n] = bytes[n+1];
}
num_bytes -= 2;
}
else {
text_color_set(DW_COLOR_INFO);
dw_printf("Removing KISS FEND character at beginning. Was expecting another at end.\n");
int n;
for (n = 0; n < num_bytes-1; n++) {
bytes[n] = bytes[n+1];
}
num_bytes -= 1;
}
}
if (bytes[0] == 0) {
// Treat as KISS. Undo any KISS encoding.
unsigned char kiss_frame[MAXBYTES];
int kiss_len = num_bytes;
memcpy (kiss_frame, bytes, num_bytes);
text_color_set(DW_COLOR_DEBUG);
dw_printf ("--- KISS frame ---\n");
hex_dump (kiss_frame, kiss_len);
// Put FEND at end to keep kiss_unwrap happy.
// Having one at the begining is optional.
kiss_frame[kiss_len++] = FEND;
// In the more general case, we would need to include
// the command byte because it could be escaped.
// Here we know it is 0, so we take a short cut and
// remove it before, rather than after, the conversion.
num_bytes = kiss_unwrap (kiss_frame + 1, kiss_len - 1, bytes);
}
// Treat as AX.25.
alevel_t alevel;
memset (&alevel, 0, sizeof(alevel));
pp = ax25_from_frame(bytes, num_bytes, alevel);
if (pp != NULL) {
char addrs[120];
unsigned char *pinfo;
int info_len;
decode_aprs_t A;
text_color_set(DW_COLOR_DEBUG);
dw_printf ("--- AX.25 frame ---\n");
ax25_hex_dump (pp);
dw_printf ("-------------------\n");
ax25_format_addrs (pp, addrs);
text_color_set(DW_COLOR_DECODED);
dw_printf ("%s:", addrs);
info_len = ax25_get_info (pp, &pinfo);
ax25_safe_print ((char *)pinfo, info_len, 1); // Display non-ASCII to hexadecimal.
dw_printf ("\n");
decode_aprs (&A, pp, 0); // Extract information into structure.
decode_aprs_print (&A); // Now print it in human readable format.
(void)ax25_check_addresses(pp); // Errors for invalid addresses.
ax25_delete (pp);
}
else {
text_color_set(DW_COLOR_ERROR);
dw_printf("Could not construct AX.25 frame from bytes supplied!\n\n");
}
}
else {
// Normal monitoring format.
pp = ax25_from_text(stuff, 1);
if (pp != NULL) {
decode_aprs_t A;
decode_aprs (&A, pp, 0); // Extract information into structure.
decode_aprs_print (&A); // Now print it in human readable format.
(void)ax25_check_addresses(pp); // Errors for invalid addresses.
// Future? Add -d option to include hex dump and maybe KISS?
ax25_delete (pp);
}
else {
text_color_set(DW_COLOR_ERROR);
dw_printf("ERROR - Could not parse monitoring format input!\n\n");
}
} }
else
{
text_color_set(DW_COLOR_ERROR);
dw_printf("\n%s\n", "ERROR - Could not parse input!\n");
}
} }
} }
return (0); return (0);

Binary file not shown.

View File

@ -101,7 +101,9 @@ void text_color_set (dw_color_t c)
#else #else
#ifndef DECAMAIN
static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug); static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug);
#endif
#endif #endif
@ -212,7 +214,7 @@ int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out)
* *
*-----------------------------------------------------------------*/ *-----------------------------------------------------------------*/
static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out) int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
{ {
int olen; int olen;
int j; int j;
@ -278,6 +280,8 @@ static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
} /* end kiss_unwrap */ } /* end kiss_unwrap */
#ifndef DECAMAIN
#ifndef KISSTEST #ifndef KISSTEST
@ -687,6 +691,7 @@ void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int
#endif #endif
#endif /* DECAMAIN */
/* Quick unit test for encapsulate & unwrap */ /* Quick unit test for encapsulate & unwrap */
@ -730,7 +735,7 @@ int main ()
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
} }
#endif #endif /* KISSTEST */
#endif /* WALK96 */ #endif /* WALK96 */

View File

@ -45,6 +45,8 @@ void kiss_frame_init (struct audio_s *pa);
int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out); int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out);
int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out);
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,unsigned char*,int,int)); void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,unsigned char*,int,int));

View File

@ -9,7 +9,9 @@ decode_aprs \- Convert APRS raw data to human readable form.
[ \fItext-file\fR ] [ \fItext-file\fR ]
.RS .RS
.P .P
\fItext-file\fR should contain AX.25 packets in the standard monitoring format. \fItext-file\fR should contain AX.25 packets in the standard monitoring format or
as a series two digit hexadecimal numbers.
If the first number is 00 or c0, it will be treated as a KISS frame.
If no file specified, data will be read from stdin. If no file specified, data will be read from stdin.
.P .P
.RE .RE
@ -43,12 +45,14 @@ Pipe it into decode_aprs to find out.
http://www.findu.com/cgi-bin/errors.cgi has a never-ending collection of packets http://www.findu.com/cgi-bin/errors.cgi has a never-ending collection of packets
with errors. Sometimes it's not obvious what is wrong with them. with errors. Sometimes it's not obvious what is wrong with them.
Dire Wolf will usually tell you what is wrong. First, Dire Wolf will usually tell you what is wrong. First,
cut-n-paste the bad packets into a text file. Here a couple examples: cut-n-paste the bad packets into a text file. Here a few examples:
.P .P
.RS .RS
n2cma>APRS,TCPIP*,qAC,SEVENTH:@212127z43.2333n/77.1w_338/002g001t025P000h65b10208.wview_5_19_0 n2cma>APRS,TCPIP*,qAC,SEVENTH:@212127z43.2333n/77.1w_338/002g001t025P000h65b10208.wview_5_19_0
.P .P
K0YTH-10>APNU3B,NULL,qAR,K0DMF-10:!4601.5NS09255.52W#PHG6360/W2,MNn 444.575 K0YTH-10>APNU3B,NULL,qAR,K0DMF-10:!4601.5NS09255.52W#PHG6360/W2,MNn 444.575
.P
00 82 a0 ae ae 62 60 e0 82 96 68 84 40 40 60 9c 68 b0 ae 86 40 e0 40 ae 92 88 8a 64 63 03 f0 3e 45 4d 36 34 6e 65 2f 23 20 45 63 68 6f 6c 69 6e 6b 20 31 34 35 2e 33 31 30 2f 31 30 30 68 7a 20 54 6f 6e 65
.RE .RE
.P .P
If you simply fed this into decode_aprs, it would complain about the If you simply fed this into decode_aprs, it would complain about the
@ -67,7 +71,7 @@ Address has lower case letters. "n2cma" must be all upper case.
.P .P
After changing the source address to upper case, there are other issues. Identifying them is left as an exercise for the reader. After changing the source address to upper case, there are other issues. Identifying them is left as an exercise for the reader.
.P .P
And in the second example, In the second example,
.P .P
.RS .RS
.PD 0 .PD 0
@ -77,6 +81,17 @@ Invalid character in longitude. Found '9' when expecting 0 or 1 for hundreds of
.PD .PD
.RE .RE
.P
In the third example,
.P
.RS
.PD 0
Warning: Lower case letter in Maidenhead locator. Specification requires upper case.
.P
Digi2 Address, " WIDE2-1" contains character other than letter or digit in character position 1.
.PD
.RE
.SH SEE ALSO .SH SEE ALSO