APRS settings can be saved in FLASH.

master
marcel 3 years ago
parent cc24f9d531
commit c67b9cde5e
  1. 10
      CHANGELOG.md
  2. 2
      build/src/CMakeFiles/main.dir/CXX.includecache
  3. BIN
      build/src/CMakeFiles/main.dir/main.cpp.obj
  4. BIN
      build/src/main.bin
  5. 50341
      build/src/main.dis
  6. BIN
      build/src/main.elf
  7. 1677
      build/src/main.elf.map
  8. 7974
      build/src/main.hex
  9. BIN
      build/src/main.uf2
  10. 48
      src/Config.h
  11. 335
      src/main.cpp

@ -9,10 +9,16 @@ All notable changes to this project will be documented in this file.
Fixed : for any bug fixes.
Security : in case of vulnerabilities.
## [1.0.0] - pre 2022-05-12
## [1.0.0] - pre 2022-05-10
First (more or less) working version.
## [1.0.1] - 2022-05-12
## [1.0.1] - 2022-05-10
### Added
- Support for saving settings to internal FLASH
## [1.0.2] - 2022-05-11
### Added
- APRS settings can now be saved in FLASH
- logging to serial USB is disabled when in KISS mode (but KISS mode still needs to be implemented)

@ -251,6 +251,8 @@ string.h
-
time.h
-
stdarg.h
-
pico/stdlib.h
/home/marcel/Documents/electronische_projecten/lora_aprs_node_pico/src/pico/stdlib.h
pico/binary_info.h

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.

@ -21,20 +21,13 @@
#define OFF 0
#define ON 1
#define CR 13
const long serialBaudRate = 38400;
const int rssiOffset = 292;
const int loraRxTurnaround = 50;
// Default LoRa settings
int loraSpreadingFactor = 12;
int loraPreamble = 8;
int loraCodingRate = 5;
int loraTxPower = 17;
int LoRaPaSelect = 1;
uint32_t loraBandwidth = 125E3;
uint32_t loraFrequency = 433775000;
uint8_t txBuffer[MTU];
uint8_t rxBuffer[MTU];
@ -60,18 +53,31 @@
const uint8_t SIG_SYNCED = 0x02;
const uint8_t RX_ONGOING = 0x04;
// The size of this struc should be a exactly 256 bytes, which is the FLASH_PAGE_SIZE of the RPi pico's flash memory
// The size of this struc should be a exactly 256 bytes (or a multiple), which is the FLASH_PAGE_SIZE of the RPi pico's flash memory
// Struct can not be bigger than 4kbyte
struct aprssettings {
uint8_t ValidFlashData = 0x5A; // Indicates flash contains valid data - 1 bytes
uint8_t MyCall[10] = { 'N','O','C','A','L','L','-','2', 0} ; // 10 bytes
uint8_t ServerCall[10] = { 'N','O','C','A','L','L','-','1', 0} ; // 10 bytes
uint8_t Destination[10] = { 'A','P','Z','M','D','M', 0} ; // 10 bytes
uint8_t Path1[10] = { 0,'I','D','E','1','-', '1', 0} ; // 10 bytes
uint8_t Path2[10] = { 0,'I','D','E','2','-', '2', 0} ; // 10 bytes
uint8_t FirmwareVersion[20] = { 'V','1',',','C','o','n','t','r', 'o','l','l','e','r',' ','0','1', 0} ; // 20 bytes
// 71 bytes total
uint8_t FillerData[256-71];
uint8_t MyCall[10] = { 'P','E','1','R','X','F','-','5', 0, 0} ; // 10 bytes
uint8_t ServerCall[10] = { 'P','E','1','R','X','F','-','3', 0, 0} ; // 10 bytes
uint8_t Destination[10] = { 'A','P','Z','M','D','M', 0, 0, 0 ,0} ; // 10 bytes
uint8_t Path1[10] = { 0,'I','D','E','1','-', '1', 0, 0, 0} ; // 10 bytes
uint8_t Path2[10] = { 0,'I','D','E','2','-', '2', 0, 0 ,0} ; // 10 bytes
uint8_t FirmwareVersion[20] = { 'V','1',',','C','o','n','t','r', 'o','l','l','e','r',' ','0','1', 0, 0, 0, 0} ;
// 20 bytes
// Default LoRa settings
uint16_t loraSpreadingFactor = 12; // 2 bytes
uint16_t loraPreamble = 8; // 2 bytes
uint16_t loraCodingRate = 5; // 2 bytes
uint16_t loraTxPower = 17; // 2 bytes
uint16_t loraPaSelect = 1; // 2 bytes
uint32_t loraBandwidth = 125E3; // 4 bytes
uint32_t loraFrequency = 433775000; // 4 bytes
// Total 89 bytes
uint8_t FillerData[163];
} AprsSettings;
struct status {
@ -81,6 +87,10 @@
bool ControlRelay;
uint8_t StatusString[6] = { '0','0','0','0','0',0};
uint8_t DescriptionString[20] ={ 'N','C',',','C','n','t','r',',','5','V',',','1','2','V',',','2','4','V',0,0};
uint8_t KissMode = OFF;
} Status;
#endif

@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/flash.h"
@ -34,36 +35,88 @@ const uint RelayOnControl = 3;
const uint8_t *flash_target_contents = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
uint8_t ReadSettingsFromFlash(void)
void log_out(const char *fmt, ...)
{
char buf[256];
va_list args;
// If byte zero of flash contains 0x5A we assume the data to be valid, otherwise we fill the flash with default values.
if (flash_target_contents[0] != 0x5A)
{
printf( "No valid data found in FLASH memory.\n" );
memset(AprsSettings.FillerData, 0, sizeof(AprsSettings.FillerData));
if (Status.KissMode == OFF) {
va_start(args, fmt);
vsnprintf(buf, sizeof buf, fmt, args);
va_end( args);
printf("%s", buf);
}
}
/*
* Saves settings in struct AprsSettings to FLASH memory
* Struct AprsSettings should be exactly a multiple of FLASH_PAGE_SIZE in size.
*
* Returns: 0 when successfull
* 1 when error
*/
uint8_t SaveSettingsToFlash(void)
{
uint32_t ints = save_and_disable_interrupts();
// First we erase the FLASH sector we need. After that we can store new values.
// Note that a whole number of sectors must be erased at a time.
// Sector size is 4kB, so this is way bigger than the needed 256 bytes for storing the settings.
printf("Erasing FLASH region...");
// Sector size is 4kB, so this is way bigger than the 256 bytes PAGE_SIZE for storing the settings.
// We can therefore store up to 16 blocks of 256 bytes per sector
log_out("Erasing FLASH region...");
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
printf("done\n");
printf("Writing default values to FLASH...");
flash_range_program(FLASH_TARGET_OFFSET, (uint8_t*)&AprsSettings, FLASH_PAGE_SIZE);
printf("done\n");
log_out("done\n");
log_out("Writing settings to FLASH...");
flash_range_program(FLASH_TARGET_OFFSET, (uint8_t*)&AprsSettings, sizeof(AprsSettings) );
log_out("done\n");
restore_interrupts (ints);
return(0);
}
void ShowSettings(void)
{
log_out("LoRa APRS remote switcher with build in KISS TNC.\n");
log_out(" Firmware version : %s\n",AprsSettings.FirmwareVersion);
log_out(" Size of struct : %u.\n\n", sizeof(AprsSettings));
log_out("APRS settings\n");
log_out(" My call : %s\n", AprsSettings.MyCall);
log_out(" Server call : %s\n", AprsSettings.ServerCall);
log_out(" Destination : %s\n", AprsSettings.Destination);
log_out(" Path 1 : %s\n", AprsSettings.Path1);
log_out(" Path 2 : %s\n\n", AprsSettings.Path2);
log_out("LoRa settings\n");
log_out(" Frequency : %u\n", AprsSettings.loraFrequency);
log_out(" SpreadingFactor : %i\n", AprsSettings.loraSpreadingFactor);
log_out(" Preamble : %i\n", AprsSettings.loraPreamble);
log_out(" CodingRate : %i\n", AprsSettings.loraCodingRate);
log_out(" TxPower : %i\n", AprsSettings.loraTxPower);
log_out(" PaSelect : %i\n", AprsSettings.loraPaSelect);
log_out(" Bandwidth : %u\n", AprsSettings.loraBandwidth);
}
uint8_t ReadSettingsFromFlash(void)
{
// If byte zero of flash contains 0x5A we assume the data to be valid, otherwise we fill the flash with default values.
if (flash_target_contents[0] != 0x5A)
{
log_out( "No valid data found in FLASH memory. Using default values.\n" );
memset(AprsSettings.FillerData, 0, sizeof(AprsSettings.FillerData));
SaveSettingsToFlash();
} else {
// Read settings stored in flash memory
printf("Found valid settings in FLASH memory.\n");
log_out("Found valid settings in FLASH memory.\n");
}
memcpy((uint8_t*)&AprsSettings, flash_target_contents, FLASH_PAGE_SIZE);
printf("APRS settings:\n");
printf("My call: %s\n", AprsSettings.MyCall);
printf("Server call: %s\n", AprsSettings.ServerCall);
printf("Firmware: %s\n",AprsSettings.FirmwareVersion);
memcpy((uint8_t*)&AprsSettings, flash_target_contents, sizeof(AprsSettings));
ShowSettings();
}
void setup(void)
@ -107,6 +160,191 @@ void setup(void)
startRadio();
}
void print_help(void)
{
log_out("Unknown command.\n\n");
log_out("kiss\n");
log_out(" Enter KISS mode.\n");
log_out("save\n");
log_out(" Save settings to flash.\n");
log_out("read <flash/ram>\n");
log_out(" Read settings from FLASH or RAM.\n");
log_out("mycall/servercall/destination/path1/path2\n");
log_out(" APRS settings.\n");
log_out("freq/spread/pre/rate/power/pa/band.\n");
log_out(" LoRa settings.\n");
}
void ProcessSerialInput(char string[])
{
uint8_t cnt;
uint8_t position=0;
char command[100];
char parameter[100];
//log_out("You wrote - %s (%u).\n", string, strlen(string));
// Command cannot be any shorter than 3 characters
if (strlen(string) > 2) {
// Extract command (part before space)
cnt = 0;
while( string[position] != 0 )
{
command[cnt++] = string[position];
if ( string[position] == ' ' ) {
command[cnt-1] = 0; // terminate command string
position++;
break;
}
position++;
}
// Extract parameter (part after space)
cnt = 0;
while( string[position] != 0 )
{
parameter[cnt++] = string[position++];
}
parameter[cnt] = 0; //terminate string
//log_out("Command - %s.\n", command);
//log_out("Parameter - %s.\n", parameter);
// Read settings
if (strcmp(command, "read") == 0) {
if (strcmp(parameter, "flash") == 0) {
ReadSettingsFromFlash();
}
else if (strcmp(parameter, "ram") == 0) {
ShowSettings();
}
}
// Save settings to FLASH
else if (strcmp(command, "save") == 0)
SaveSettingsToFlash();
// Enter KISS mode
else if (strcmp(command, "kiss") == 0) {
log_out("Entering KISS mode.\n");
log_out("You can exit KISS mode via KISS command <0xC0 0xFF 0xC0>\n");
Status.KissMode = ON;
}
// Set mycall (cannot be longer than 9 characters)
else if (strcmp(command, "mycall") == 0) {
if (sizeof(AprsSettings.MyCall) > strlen(parameter)) {
position = 0;
while( parameter[position] != 0 )
{
AprsSettings.MyCall[position] = parameter[position];
position++;
}
AprsSettings.MyCall[position] = 0;
log_out("MyCall set to %s.\n", AprsSettings.MyCall);
}
}
// Set servercall (cannot be longer than 9 characters)
else if (strcmp(command, "servercall") == 0) {
if (sizeof(AprsSettings.ServerCall) > strlen(parameter)) {
position = 0;
while( parameter[position] != 0 )
{
AprsSettings.ServerCall[position] = parameter[position];
position++;
}
AprsSettings.ServerCall[position] = 0;
log_out("ServerCall set to %s.\n", AprsSettings.ServerCall);
}
}
// Set path 1 (cannot be longer than 9 characters)
else if (strcmp(command, "path1") == 0) {
// Set path to nothing
if (parameter[0] == '0') {
AprsSettings.Path1[0] = 0;
log_out("Path1 cleared.\n");
}
else if (sizeof(AprsSettings.Path1) > strlen(parameter)) {
position = 0;
while( parameter[position] != 0 )
{
AprsSettings.Path1[position] = parameter[position];
position++;
}
AprsSettings.Path1[position] = 0;
log_out("Path1 set to %s.\n", AprsSettings.Path1);
}
}
// Set path 2 (cannot be longer than 9 characters)
else if (strcmp(command, "path2") == 0) {
// Set path to nothing
if (parameter[0] == '0') {
AprsSettings.Path2[0] = 0;
log_out("Path2 cleared.\n");
}
else if (sizeof(AprsSettings.Path2) > strlen(parameter)) {
position = 0;
while( parameter[position] != 0 )
{
AprsSettings.Path2[position] = parameter[position];
position++;
}
AprsSettings.Path2[position] = 0;
log_out("Path2 set to %s.\n", AprsSettings.Path2);
}
}
// Set destination (cannot be longer than 9 characters)
else if (strcmp(command, "dest") == 0) {
if (sizeof(AprsSettings.Destination) > strlen(parameter)) {
position = 0;
while( parameter[position] != 0 )
{
AprsSettings.Destination[position] = parameter[position];
position++;
}
AprsSettings.Destination[position] = 0;
log_out("Destination set to %s.\n", AprsSettings.Destination);
}
}
else {
print_help();
}
}
else
{
print_help();
}
}
void ReadUSBSerial(void)
{
static char strg[100];
int chr;
static int lp = 0;
// Read serial port (USB) - non-blocking!
chr = getchar_timeout_us(0);
while(chr != PICO_ERROR_TIMEOUT)
{
log_out("%c", chr);
strg[lp++] = chr;
if(chr == CR || lp == (sizeof(strg) - 1))
{
strg[lp-1] = 0; //terminate string by overwriting <CR> with NULL
//log_out("You wrote - %s\n", strg);
lp = 0; //reset string buffer pointer
ProcessSerialInput(strg);
break;
}
chr = getchar_timeout_us(0);
}
}
int main() {
uint16_t ServerCommand = 0;
@ -118,7 +356,7 @@ int main() {
int packetSize = LoRa.parsePacket();
if (packetSize) {
// received a packet
printf("Received packet (RSSI = %idBm)\n",LoRa.packetRssi());
log_out("Received packet (RSSI = %idBm)\n",LoRa.packetRssi());
getPacketData(packetSize);
@ -129,10 +367,10 @@ int main() {
rxBuffer[cnt-3] = rxBuffer[cnt];
}
rxBuffer[packetSize-3] = 0;
printf("%s\n", rxBuffer);
log_out("%s\n", rxBuffer);
ServerCommand = decode_packet();
} else {
printf("ERROR: No or corrupted APRS frame.\n");
log_out("ERROR: No or corrupted APRS frame.\n");
}
}
@ -169,6 +407,10 @@ int main() {
break;
// Send description digital outputs
case 7 :
ComposeAprsFrame(Status.DescriptionString);
// Switch off 24V power supply
case 30 :
gpio_put(PowerSupply24VControl, 0);
@ -235,6 +477,9 @@ int main() {
TransmitRequest = false;
}
}
// Read serial input and process it
ReadUSBSerial();
}
return 0;
@ -247,29 +492,19 @@ bool startRadio()
{
// override the default CS, reset, and IRQ pins (optional)
// LoRa.setPins(7, 6, 1); // set CS, reset, IRQ pin
printf("LoRa settings:\n");
printf("loraFrequency = %u\n", loraFrequency);
printf("loraSpreadingFactor = %i\n", loraSpreadingFactor);
printf("loraPreamble = %i\n", loraPreamble);
printf("loraCodingRate = %i\n", loraCodingRate);
printf("loraTxPower = %i\n", loraTxPower);
printf("LoRaPaSelect = %i\n", LoRaPaSelect);
printf("loraBandwidth = %u\n", loraBandwidth);
printf("Starting LoRa radio");
if (!LoRa.begin(loraFrequency)) {
printf(" [ FAILED ]\n");
log_out("Starting LoRa radio");
if (!LoRa.begin(AprsSettings.loraFrequency)) {
log_out(" [ FAILED ]\n");
while(1);
}
else {
LoRa.setPreambleLength(loraPreamble);
LoRa.setSignalBandwidth(loraBandwidth);
LoRa.setTxPower(loraTxPower,LoRaPaSelect);
LoRa.setSpreadingFactor(loraSpreadingFactor);
LoRa.setCodingRate4(loraCodingRate);
LoRa.setPreambleLength(AprsSettings.loraPreamble);
LoRa.setSignalBandwidth(AprsSettings.loraBandwidth);
LoRa.setTxPower(AprsSettings.loraTxPower,AprsSettings.loraPaSelect);
LoRa.setSpreadingFactor(AprsSettings.loraSpreadingFactor);
LoRa.setCodingRate4(AprsSettings.loraCodingRate);
LoRa.enableCrc();
printf(" [ DONE ]\n");
log_out(" [ DONE ]\n");
}
}
@ -318,13 +553,12 @@ uint16_t decode_packet ()
if ( rxBuffer[position] == '>' && position < 10 ) {
aprs_source_address[cnt-1] = 0;
valid_apsr_data = true;
position++;
break;
}
position++;
}
position++;
if (valid_apsr_data == true)
{
// Extract digi path
@ -336,6 +570,7 @@ uint16_t decode_packet ()
if ( rxBuffer[position] == ':' ) {
aprs_digi_path[cnt-1] = 0;
valid_apsr_data = true;
position++;
break;
}
position++;
@ -343,8 +578,6 @@ uint16_t decode_packet ()
}
position++;
if (valid_apsr_data == true)
{
// Extract data field
@ -372,8 +605,6 @@ uint16_t decode_packet ()
valid_apsr_data = false;
break;
}
//position++;
cnt = 0;
}
position++;
@ -424,20 +655,20 @@ uint16_t decode_packet ()
}
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);
log_out("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);
log_out("Message from server: %s (command %u)\n", aprs_message, aprs_server_command);
if (aprs_acknowledge_request) {
ComposeAprsFrame(aprs_acknowledge_number);
printf("Acknowledge request: %s\n", aprs_acknowledge_number);
log_out("Acknowledge request: %s\n", aprs_acknowledge_number);
}
}
}
else
printf("Error decoding APRS frame.");
log_out("Error decoding APRS frame.");
return (aprs_server_command);
}
@ -570,7 +801,7 @@ void ComposeAprsFrame(uint8_t payload[])
// Set variable to indicate a send request
TransmitRequest = true;
printf("%s\n", txBuffer);
log_out("%s\n", txBuffer);
}
void transmit() {

Loading…
Cancel
Save