Fully functioning KISS TNC

master v1.0.4
marcel 2 years ago
parent fcaf1e7d1d
commit 043fdf6e54
  1. 6
      CHANGELOG.md
  2. BIN
      build/src/CMakeFiles/KISS.dir/kiss.cpp.obj
  3. BIN
      build/src/CMakeFiles/main.dir/main.cpp.obj
  4. BIN
      build/src/libKISS.a
  5. BIN
      build/src/main.bin
  6. 52859
      build/src/main.dis
  7. BIN
      build/src/main.elf
  8. 1470
      build/src/main.elf.map
  9. 8548
      build/src/main.hex
  10. BIN
      build/src/main.uf2
  11. 232
      src/kiss.cpp
  12. 14
      src/kiss.h
  13. 78
      src/main.cpp

@ -28,8 +28,12 @@ First (more or less) working version.
### Added
- All settings (LoRa and APRS) can now be saved to FLASH.
- Command added for restarting LoRa radio when settings are alterred: "restart lora"
- Received LoRa frames can now be converted to propper AX25 frames (needed for KISS TNC functionality)
- Received LoRa frames can now be converted to proper AX25 frames (needed for KISS TNC functionality)
- KISS mode works for receiving (LoRa -> USB port)
- KISS mode for transmitting in early phase of development
- Can enter KISS mode with command "kiss 1" and exit KISS mode with command "sudo kissparms -p ax0 -x"
## [1.0.4] - 2022-05-13
### Added
- Fully functioning KISS TNC, but repeater flag could not be tested because LoRa APRS software in general is a mess. It appears that nobody reads the AX.25 standard anymore. This software probably is also not up to spec. But at least I tried! You should too: [http://www.ax25.net/AX25.2.2-Jul%2098-2.pdf](http://www.ax25.net/AX25.2.2-Jul%2098-2.pdf)

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -4,7 +4,7 @@
* KISS encoder uses two steps:
*
* Step 1: encodes the LoRa APRS frame into an AX.25 frame. DONE
* Step 2: encapsulates the AX.25 frame into a KISS frame. TODO
* Step 2: encapsulates the AX.25 frame into a KISS frame. DONE
*
* struct aprs_frame {
* uint8_t source_address[10];
@ -27,6 +27,9 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
uint16_t cnt=0;
uint16_t position = 0;
uint8_t digi_cnt = 0;
uint8_t escaped_string_cnt=0;
//printf("Encode KISS");
// Destination call
//printf("Destination: ");
@ -35,7 +38,7 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
while (cnt < 7)
{
ax25frame->complete[position] = *(encoded_call+cnt);
////printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", ax25frame->complete[position]);
cnt++;
position++;
@ -49,7 +52,7 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
while (cnt < 7)
{
ax25frame->complete[position] = *(encoded_call+cnt);
////printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", ax25frame->complete[position]);
cnt++;
position++;
@ -73,7 +76,7 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
encoded_call = EncodeCall(aprsframe->digis[digi_cnt]);
while (cnt < 7) {
ax25frame->complete[position] = *(encoded_call+cnt);
////printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", *(encoded_call+cnt));
//printf("0x%X ", ax25frame->complete[position]);
cnt++;
position++;
@ -109,6 +112,9 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
// Encapsulate AX.25 frame in KISS frame (including escaping FEND codes)
putchar(FEND);
putchar(CMD_DATA);
escaped_string_cnt=0;
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = FEND;
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = CMD_DATA;
cnt=0;
position=ax25frame->lenght;
while (position-- != 0)
@ -117,15 +123,21 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
if (ax25frame->complete[cnt] == FEND) {
putchar(FESC);
putchar(TFEND);
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = FESC;
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = TFEND;
} else if (ax25frame->complete[cnt] == FESC) {
putchar(FESC);
putchar(TFESC);
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = FESC;
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = TFESC;
} else {
putchar(ax25frame->complete[cnt]);
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = ax25frame->complete[cnt];
}
cnt++;
}
putchar(FEND);
ax25frame->encoded_kiss_frame[escaped_string_cnt++] = FEND;
//printf("\n");
@ -136,13 +148,21 @@ uint16_t KissClass::EncodeFrame(struct aprs_frame *aprsframe, struct ax25_frame
* Decodes a KISS frame from the usb serial port
*
* Input : string starting with FEND and ending with FEND
* Output: ax25frame->decoded_kiss_frame terminated with NULL
* Output: filled struct AprsFrame
* Return: 0 = OK, 1 = ERROR, 2 = EXIT KISS MODE
*/
uint16_t KissClass::DecodeFrame(uint8_t string[], struct ax25_frame *ax25frame)
uint16_t KissClass::DecodeFrame(uint8_t string[], struct kiss_tx_frame *kisstxframe)
{
uint16_t position =0 ;
uint16_t loop_counter = 0;
uint16_t cnt =0 ;
uint16_t ssid = 0;
uint16_t last_digi = 0;
uint16_t digi_cnt = 0;
//printf("Decode KISS");
kisstxframe->valid_data = false;
// Not a valid frame
if (string[position] != FEND)
@ -182,6 +202,176 @@ uint16_t KissClass::DecodeFrame(uint8_t string[], struct ax25_frame *ax25frame)
}
// If we are here we have a valid AX.25 frame in 'string' which is decapsulated from its KISS frame
/*
0-5 destination
6 destination ssid
7-12 source
13 desitination sidd
vanaf byte 13 LAST FLAG zoeken
03
f0
payload tot aan NULL
*/
// Decode destination call
position = 0;
cnt = 0;
loop_counter = 0;
while (loop_counter < 6)
{
kisstxframe->digis[0][cnt] = string[position] >> 1;
// Remove space
if (kisstxframe->digis[0][cnt] == ' ')
cnt--;
position++;
loop_counter++;
cnt++;
//printf("%u ", position);
}
// Extract SSID
//printf("position: %u\n", position);
ssid = (string[position] & 0b00011110) >> 1;
//printf("DIGI SSID: %u (%u)\n", ssid, position);
// Place SSID behind call or not if it is zero
if (ssid != 0) {
kisstxframe->digis[0][cnt++] = '-';
if (ssid < 10)
{
kisstxframe->digis[0][cnt++] = ssid + 48;
}
else
{
kisstxframe->digis[0][cnt++] = '1';
kisstxframe->digis[0][cnt++] = (ssid%10)+48;
}
}
// Is has-been-repeated flag set?
if(string[position] & 0b10000000) {
kisstxframe->digis[0][cnt] = '*';
cnt++;
}
kisstxframe->digis[0][cnt] = 0; //terminate string
position++;
// Decode source call
cnt = 0;
loop_counter=0;
while (loop_counter < 6)
{
kisstxframe->source_address[cnt] = string[position] >> 1;
// Remove space
if (kisstxframe->source_address[cnt] == ' ')
cnt--;
position++;
loop_counter++;
cnt++;
//printf("%u ", position);
}
// Extract SSID
ssid = (string[position] & 0b00011110) >> 1;
//printf("sources SSID: %u (%u)\n", ssid, position);
// Place SSID behind call or not if it is zero
if (ssid != 0) {
kisstxframe->source_address[cnt++] = '-';
if (ssid < 10)
{
kisstxframe->source_address[cnt++] = ssid + 48;
}
else
{
kisstxframe->source_address[cnt++] = '1';
kisstxframe->source_address[cnt++] = (ssid%10)+48;
}
}
// Is has-been-repeated flag set?
if(string[position] & 0b10000000) {
kisstxframe->source_address[cnt] = '*';
cnt++;
}
kisstxframe->source_address[cnt] = 0; //terminate string
// Check LAST flag
if ( (string[position] & 0b00000001))
last_digi = 1;
position++;
// Decode digi path
digi_cnt=1;
while (last_digi == 0) {
cnt = 0;
loop_counter=0;
while (loop_counter < 6)
{
kisstxframe->digis[digi_cnt][cnt] = string[position] >> 1;
// Remove space
if (kisstxframe->digis[digi_cnt][cnt] == ' ')
cnt--;
position++;
loop_counter++;
cnt++;
//printf("%u ", position);
}
// Extract SSID
ssid = (string[position] & 0b00011110) >> 1;
//printf("DIGI SSID: %u (%u)\n", ssid, position);
// Place SSID behind call or not if it is zero
if (ssid != 0) {
kisstxframe->digis[digi_cnt][cnt++] = '-';
if (ssid < 10)
{
kisstxframe->digis[digi_cnt][cnt++] = ssid + 48;
}
else
{
kisstxframe->digis[digi_cnt][cnt++] = '1';
kisstxframe->digis[digi_cnt][cnt++] = (ssid%10) + 48;
}
}
// Is has-been-repeated flag set?
if(string[position] & 0b10000000) {
kisstxframe->digis[digi_cnt][cnt] = '*';
cnt++;
}
kisstxframe->digis[digi_cnt][cnt] = 0; //terminate string
// Check LAST flag (also ends when more than 10 digis)
if ( (string[position] & 0b00000001) || digi_cnt > 8)
last_digi = 1;
digi_cnt++;
position++;
}
kisstxframe->number_of_digipeaters = digi_cnt-1;
//printf("Digipeaters: %u \n",kisstxframe->number_of_digipeaters );
//Skip the two control fields
position++;
position++;
//Rest of string up to NULL is payload
cnt = 0;
kisstxframe->data_field[cnt++] = ':';
while (string[position] != 0 && position < 512)
{
kisstxframe->data_field[cnt] = string[position];
position++;
cnt++;
}
kisstxframe->data_field[cnt] = 0; //terminate string
kisstxframe->valid_data = true;
return 0;
}
@ -197,10 +387,26 @@ uint8_t * KissClass::EncodeCall(uint8_t string[])
{
uint8_t position = 0;
uint8_t cnt = 0;
uint8_t repeat_flag = 0;
static uint8_t call[7] = { 0,0,0,0,0,0,0} ;
uint8_t ssid = 0;
// if asterix is pressent in string, than the message has been repeated, so set the 'has been repeated' flag in the ssid register
// At the same time delete the asterix and place a NULL (string terminator) at its place. As the asterix should be the last character in the string, this should work.
position = 0;
while( string[position] != 0)
{
if (string[position] == '*') {
repeat_flag = 1;
string[position] == 0;
break;
}
position++;
}
position = 0;
// extract call
while( string[position] != 0 || cnt < 6)
{
@ -229,17 +435,11 @@ uint8_t * KissClass::EncodeCall(uint8_t string[])
}
}
// if asterix is pressent in string, than the message has been repeated, so set the 'has been repeated' flag in the ssid register
position = 0;
while( string[position] != 0)
{
if (string[position] == '*')
ssid = 0b10000000;
position++;
}
ssid = ssid << 1;
ssid |= 0b01100000;
ssid = (ssid << 1) | 0b01100000;
if (repeat_flag == 1)
ssid |= 0b10000000;
// add encoded ssid to encoded call array
call[6] = ssid;

@ -39,15 +39,27 @@
struct ax25_frame {
uint8_t complete[512];
uint16_t lenght = 0;
uint8_t encoded_kiss_frame[512];
uint8_t decoded_kiss_frame[512];
uint16_t kiss_length = 0;
};
struct kiss_tx_frame {
uint8_t source_address[10];
uint8_t data_field[512];
uint8_t digis[10][10];
uint16_t number_of_digipeaters = 0;
uint8_t lora_string[512];
uint8_t valid_data = false;
};
class KissClass
{
public:
uint16_t EncodeFrame(struct aprs_frame *frame, struct ax25_frame *ax25frame);
uint16_t DecodeFrame(uint8_t string[], struct ax25_frame *ax25frame);
uint16_t DecodeFrame(uint8_t string[], struct kiss_tx_frame *kisstxframe);
private:
uint8_t * EncodeCall(uint8_t string[]);
};

@ -11,7 +11,9 @@
#include "hardware/claim.h"
KissClass Kiss;
struct ax25_frame AX25Frame; //defined in kiss.h
struct ax25_frame AX25Frame; //defined in kiss.h
struct aprs_frame AprsFrame; //defined in kiss.h
struct kiss_tx_frame KissTxFrame; //defined in kiss.h
bool startRadio();
void getPacketData(int packetLength);
@ -23,6 +25,7 @@ uint16_t decode_packet ();
/* declaration for transmit functions */
void ComposeAprsFrame(uint8_t payload[]);
void ComposeAprsFrameFromKiss();
bool TransmitRequest = false;
void transmit();
@ -433,6 +436,7 @@ void ReadUSBSerial(void)
static char strg[512];
int chr;
static int lp = 0;
uint16_t tmp;
if (Status.KissMode == OFF) {
// Read serial port (USB) - non-blocking!
@ -472,15 +476,21 @@ void ReadUSBSerial(void)
// Received FEND (=begin or end frame)
if(chr == FEND)
{
// Valid FISS frame received
// Valid KISS frame received
if (strg[0] == FEND && lp > 1)
{
if (Kiss.DecodeFrame((uint8_t *) strg, &AX25Frame) == 2)
tmp = Kiss.DecodeFrame((uint8_t *) strg, &KissTxFrame);
if ( tmp == 2)
{
//exit KISS MODE
stdio_set_translate_crlf(&stdio_usb, true);
Status.KissMode = OFF;
}
// Valid KISS data frame, so lets send it
else if (tmp == 0)
{
ComposeAprsFrameFromKiss();
}
lp = 0; //reset string buffer pointer
}
// We received a FEND byte,so we are probably between two KISS frames. Let's assume the latest FEND is the beginning of a new frame
@ -682,8 +692,6 @@ uint16_t decode_packet ()
int position = 0;
int cnt = 0;
struct aprs_frame AprsFrame; //defined in kiss.h
memset(AprsFrame.source_address, 0, sizeof(AprsFrame.source_address));
memset(AprsFrame.digi_path, 0, sizeof(AprsFrame.digi_path));
memset(AprsFrame.data_field, 0, sizeof(AprsFrame.data_field));
@ -809,8 +817,11 @@ uint16_t decode_packet ()
log_out("Source address: %s\nDigipeaters (%u): %s %s %s %s\nData: %s\n", AprsFrame.source_address, AprsFrame.number_of_digipeaters+1, AprsFrame.digis[0], AprsFrame.digis[1], AprsFrame.digis[2], AprsFrame.digis[3], AprsFrame.data_field);
// If in KISS mode the struct AprsFrame is handed over to the KISS encoder
if (Status.KissMode == ON)
if (Status.KissMode == ON) {
Kiss.EncodeFrame(&AprsFrame, &AX25Frame);
//if (Kiss.DecodeFrame(AX25Frame.encoded_kiss_frame, &KissTxFrame) == 0)
//ComposeAprsFrameFromKiss();
}
if (AprsFrame.message[0])
{
@ -960,6 +971,61 @@ void ComposeAprsFrame(uint8_t payload[])
log_out("%s\n", txBuffer);
}
void ComposeAprsFrameFromKiss()
{
uint16_t BufferPosition = 0;
uint16_t cnt = 0;
uint8_t digi_cnt=0;
log_out( "Compose APRS from KISS frame");
memset(txBuffer, 0, sizeof(txBuffer));
// APRS header
txBuffer[BufferPosition++] = '<';
txBuffer[BufferPosition++] = 0xff;
txBuffer[BufferPosition++] = 0x01;
while ( KissTxFrame.source_address[cnt] != 0 && BufferPosition<MTU )
{
txBuffer[BufferPosition] = KissTxFrame.source_address[cnt];
BufferPosition++;
cnt++;
}
txBuffer[BufferPosition++] = '>';
digi_cnt=0;
while(digi_cnt <= KissTxFrame.number_of_digipeaters) {
cnt=0;
while ( KissTxFrame.digis[digi_cnt][cnt] != 0 && BufferPosition<MTU )
{
txBuffer[BufferPosition++] = KissTxFrame.digis[digi_cnt][cnt];
cnt++;
}
txBuffer[BufferPosition++] = ',';
digi_cnt++;
}
// Overwrite last command with colon
txBuffer[--BufferPosition] = ':';
cnt=0;
while ( KissTxFrame.data_field[cnt] != 0 && BufferPosition<MTU )
{
txBuffer[BufferPosition++] = KissTxFrame.data_field[cnt];
cnt++;
}
// Set variable to indicate a send request
TransmitRequest = true;
// Ready for next input KISS frame.
KissTxFrame.valid_data = false;
log_out("%s\n", txBuffer);
}
void transmit() {
uint16_t position = 0;

Loading…
Cancel
Save