|
|
|
@ -7,11 +7,19 @@ |
|
|
|
|
#include "KISS.h" |
|
|
|
|
|
|
|
|
|
bool startRadio(); |
|
|
|
|
bool LoadSettings(); |
|
|
|
|
void getPacketData(int packetLength); |
|
|
|
|
int compare_strings(uint8_t a[], uint8_t b[]); |
|
|
|
|
bool is_message_for_me (uint8_t data[], uint8_t mycall[]); |
|
|
|
|
|
|
|
|
|
void encode_kiss (); |
|
|
|
|
uint16_t decode_packet (); |
|
|
|
|
void ComposeAprsFrame(uint8_t payload[]); |
|
|
|
|
|
|
|
|
|
void transmit(); |
|
|
|
|
|
|
|
|
|
int main() { |
|
|
|
|
|
|
|
|
|
uint16_t ServerCommand = 0; |
|
|
|
|
|
|
|
|
|
/* Among others, this initializes the USB-serial port at 115200bps 8N1 */ |
|
|
|
|
stdio_init_all(); |
|
|
|
@ -21,6 +29,8 @@ int main() { |
|
|
|
|
memset(txBuffer, 0, sizeof(txBuffer)); |
|
|
|
|
|
|
|
|
|
sleep_ms(5000); |
|
|
|
|
|
|
|
|
|
LoadSettings(); |
|
|
|
|
|
|
|
|
|
startRadio(); |
|
|
|
|
|
|
|
|
@ -40,16 +50,43 @@ int main() { |
|
|
|
|
} |
|
|
|
|
rxBuffer[packetSize-3] = 0; |
|
|
|
|
printf("%s\n", rxBuffer); |
|
|
|
|
encode_kiss(); |
|
|
|
|
ServerCommand = decode_packet(); |
|
|
|
|
} else { |
|
|
|
|
printf("ERROR: No or corrupted APRS frame.\n"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ServerCommand) { |
|
|
|
|
|
|
|
|
|
if (ServerCommand == 1) { |
|
|
|
|
ComposeAprsFrame(AprsSettings.FirmwareVersion); |
|
|
|
|
// Wait for 100ms before responding
|
|
|
|
|
sleep_ms(5000); |
|
|
|
|
transmit(); |
|
|
|
|
sleep_ms(5000); |
|
|
|
|
transmit(); |
|
|
|
|
sleep_ms(5000); |
|
|
|
|
transmit(); |
|
|
|
|
sleep_ms(5000); |
|
|
|
|
transmit(); |
|
|
|
|
} |
|
|
|
|
ServerCommand = 0; |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Load settings from EEPROM |
|
|
|
|
*/ |
|
|
|
|
bool LoadSettings() |
|
|
|
|
{ |
|
|
|
|
printf("APRS settings:\n"); |
|
|
|
|
printf("My call: %s\n", AprsSettings.MyCall); |
|
|
|
|
printf("Server call: %s\n", AprsSettings.ServerCall); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
* Initializes the LoRa module with the parameters set in config.h |
|
|
|
|
*/ |
|
|
|
@ -95,8 +132,9 @@ void getPacketData(int packetLength) |
|
|
|
|
|
|
|
|
|
/* Encode LoRa APRS frame: extract source call, digipeater path and data field. At the same time, check for data corruption
|
|
|
|
|
*
|
|
|
|
|
* If frame is a message from the server it returns the command from this server
|
|
|
|
|
*/ |
|
|
|
|
void encode_kiss () |
|
|
|
|
uint16_t decode_packet () |
|
|
|
|
{ |
|
|
|
|
int position = 0; |
|
|
|
|
int cnt = 0; |
|
|
|
@ -105,13 +143,19 @@ void encode_kiss () |
|
|
|
|
|
|
|
|
|
uint8_t aprs_source_address[10]; |
|
|
|
|
uint8_t aprs_digi_path[255]; |
|
|
|
|
uint8_t aprs_data_field[255];
|
|
|
|
|
uint8_t aprs_data_field[255]; |
|
|
|
|
uint8_t aprs_message[255]; |
|
|
|
|
uint8_t aprs_digis[10][10]; |
|
|
|
|
uint8_t aprs_acknowledge_number[255]; |
|
|
|
|
bool aprs_acknowledge_request = false; |
|
|
|
|
uint16_t aprs_server_command = 0; |
|
|
|
|
|
|
|
|
|
memset(aprs_source_address, 0, sizeof(aprs_source_address)); |
|
|
|
|
memset(aprs_digi_path, 0, sizeof(aprs_digi_path)); |
|
|
|
|
memset(aprs_data_field, 0, sizeof(aprs_data_field)); |
|
|
|
|
memset(aprs_message, 0, sizeof(aprs_message)); |
|
|
|
|
memset(aprs_digis, 0, sizeof(aprs_digis)); |
|
|
|
|
memset(aprs_acknowledge_number, 0, sizeof(aprs_acknowledge_number)); |
|
|
|
|
|
|
|
|
|
// Extract from address
|
|
|
|
|
cnt = 0;
|
|
|
|
@ -184,8 +228,202 @@ void encode_kiss () |
|
|
|
|
aprs_digis[number_of_digipeaters][cnt] = 0;
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (valid_apsr_data) |
|
|
|
|
if (valid_apsr_data) { |
|
|
|
|
|
|
|
|
|
// Check if packet comes from our server and if so, check if it is a message for us.
|
|
|
|
|
if ( !compare_strings(aprs_source_address, AprsSettings.ServerCall) ) { |
|
|
|
|
|
|
|
|
|
if ( is_message_for_me(aprs_data_field, AprsSettings.MyCall) )
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
// Extract aprs message from data field
|
|
|
|
|
position=11; |
|
|
|
|
while( aprs_data_field[position] != 0 ) |
|
|
|
|
{ |
|
|
|
|
aprs_message[position-11] = aprs_data_field[position]; |
|
|
|
|
position++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Extract command and acknowledge number (if present)
|
|
|
|
|
cnt = 0; |
|
|
|
|
position = 0; |
|
|
|
|
while( aprs_message[position] != 0 ) |
|
|
|
|
{ |
|
|
|
|
if ( aprs_message[position] == '{' ) { |
|
|
|
|
aprs_acknowledge_number[cnt++] = ':'; |
|
|
|
|
|
|
|
|
|
while ( AprsSettings.ServerCall[cnt-1] != 0 ) |
|
|
|
|
{ |
|
|
|
|
aprs_acknowledge_number[cnt] = AprsSettings.ServerCall[cnt-1]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
//Fill with spaces
|
|
|
|
|
while ( cnt<10 ) |
|
|
|
|
{ |
|
|
|
|
aprs_acknowledge_number[cnt++] = ' '; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
aprs_acknowledge_number[cnt++] = ':';
|
|
|
|
|
aprs_acknowledge_number[cnt++] = 'a'; |
|
|
|
|
aprs_acknowledge_number[cnt++] = 'c'; |
|
|
|
|
aprs_acknowledge_number[cnt++] = 'k'; |
|
|
|
|
aprs_acknowledge_request = true; |
|
|
|
|
} |
|
|
|
|
// Calculate server command
|
|
|
|
|
if (!aprs_acknowledge_request) { |
|
|
|
|
aprs_server_command = 10*aprs_server_command + aprs_message[position]-48; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
position++; |
|
|
|
|
if (aprs_acknowledge_request) { |
|
|
|
|
aprs_acknowledge_number[cnt++] = aprs_message[position]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
aprs_acknowledge_number[cnt] = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("Source address: %s\nDigipeaters (%u): %s %s %s %s\nData: %s\n", aprs_source_address, number_of_digipeaters+1, aprs_digis[0], aprs_digis[1], aprs_digis[2], aprs_digis[3], aprs_data_field); |
|
|
|
|
if (aprs_message[0]) |
|
|
|
|
{ |
|
|
|
|
printf("Message from server: %s (command %u)\n", aprs_message, aprs_server_command); |
|
|
|
|
if (aprs_acknowledge_request) { |
|
|
|
|
ComposeAprsFrame(aprs_acknowledge_number); |
|
|
|
|
// Wait for 100ms before responding with acknowledge
|
|
|
|
|
sleep_ms(100); |
|
|
|
|
transmit(); |
|
|
|
|
printf("Acknowledge request: %s\n", aprs_acknowledge_number); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else |
|
|
|
|
printf("Error decoding APRS frame."); |
|
|
|
|
|
|
|
|
|
return (aprs_server_command); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Checks if aprs datafield contains message and if message is for us |
|
|
|
|
*
|
|
|
|
|
* Returns: 0 if datafield contains no message for us |
|
|
|
|
* 1 if datafield contains a message for us
|
|
|
|
|
*/ |
|
|
|
|
bool is_message_for_me (uint8_t data[], uint8_t mycall[]) |
|
|
|
|
{ |
|
|
|
|
// A variable to iterate through the strings
|
|
|
|
|
int i=0; |
|
|
|
|
|
|
|
|
|
if (data[0] == ':' && data[10] == ':') |
|
|
|
|
{ |
|
|
|
|
while( i<9 && mycall[i] != 0 ) { |
|
|
|
|
if (data[i+1] != mycall[i]) { |
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
return (1); |
|
|
|
|
}
|
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int compare_strings(uint8_t a[], uint8_t b[]) |
|
|
|
|
{ |
|
|
|
|
// A variable to iterate through the strings
|
|
|
|
|
int i = 0; |
|
|
|
|
|
|
|
|
|
while (a[i] == b[i])
|
|
|
|
|
{ |
|
|
|
|
// If either of the strings reaches the end
|
|
|
|
|
// we stop the loop
|
|
|
|
|
if (a[i] == '\0' || b[i] == '\0') |
|
|
|
|
break; |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// We check if both the strings have been compared
|
|
|
|
|
// till the end or not
|
|
|
|
|
// If the strings are compared till the end they are equal
|
|
|
|
|
if (a[i] == '\0' && b[i] == '\0') |
|
|
|
|
return 0; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if(a[i] == '\0')
|
|
|
|
|
return -1*(b[i]); |
|
|
|
|
else if(b[i] == '\0') |
|
|
|
|
return a[i]; |
|
|
|
|
else |
|
|
|
|
return (a[i]-b[i]);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ComposeAprsFrame(uint8_t payload[]) |
|
|
|
|
{ |
|
|
|
|
uint16_t BufferPosition = 0; |
|
|
|
|
uint16_t cnt = 0; |
|
|
|
|
|
|
|
|
|
// APRS header
|
|
|
|
|
txBuffer[BufferPosition++] = '<'; |
|
|
|
|
txBuffer[BufferPosition++] = 0xff; |
|
|
|
|
txBuffer[BufferPosition++] = 0x01; |
|
|
|
|
|
|
|
|
|
while ( AprsSettings.MyCall[cnt] != 0 && BufferPosition<MTU ) |
|
|
|
|
{ |
|
|
|
|
txBuffer[BufferPosition++] = AprsSettings.MyCall[cnt]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
txBuffer[BufferPosition++] = '>'; |
|
|
|
|
|
|
|
|
|
cnt=0; |
|
|
|
|
while ( AprsSettings.Destination[cnt] != 0 && BufferPosition<MTU ) |
|
|
|
|
{ |
|
|
|
|
txBuffer[BufferPosition++] = AprsSettings.Destination[cnt]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( AprsSettings.Path1[0] != 0) |
|
|
|
|
txBuffer[BufferPosition++] = ','; |
|
|
|
|
|
|
|
|
|
cnt=0; |
|
|
|
|
while ( AprsSettings.Path1[cnt] != 0 && BufferPosition<MTU ) |
|
|
|
|
{ |
|
|
|
|
txBuffer[BufferPosition++] = AprsSettings.Path1[cnt]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( AprsSettings.Path2[0] != 0) |
|
|
|
|
txBuffer[BufferPosition++] = ','; |
|
|
|
|
|
|
|
|
|
cnt=0; |
|
|
|
|
while ( AprsSettings.Path2[cnt] != 0 && BufferPosition<MTU ) |
|
|
|
|
{ |
|
|
|
|
txBuffer[BufferPosition++] = AprsSettings.Path2[cnt]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
txBuffer[BufferPosition++] = ':'; |
|
|
|
|
|
|
|
|
|
cnt=0; |
|
|
|
|
while ( payload[cnt] != 0 && BufferPosition<MTU ) |
|
|
|
|
{ |
|
|
|
|
txBuffer[BufferPosition++] = payload[cnt]; |
|
|
|
|
cnt++; |
|
|
|
|
} |
|
|
|
|
printf("%s\n", txBuffer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void transmit() { |
|
|
|
|
uint16_t position = 0; |
|
|
|
|
|
|
|
|
|
LoRa.beginPacket(); |
|
|
|
|
while( txBuffer[position] != 0 ) |
|
|
|
|
{ |
|
|
|
|
LoRa.write(txBuffer[position]); |
|
|
|
|
position++; |
|
|
|
|
} |
|
|
|
|
LoRa.endPacket(); |
|
|
|
|
|
|
|
|
|
LoRa.receive(); |
|
|
|
|
} |
|
|
|
|