diff --git a/openrtx/include/ui/ui_mod17.h b/openrtx/include/ui/ui_mod17.h index 175cf3ed..e77c43d0 100644 --- a/openrtx/include/ui/ui_mod17.h +++ b/openrtx/include/ui/ui_mod17.h @@ -107,11 +107,13 @@ enum backupRestoreItems enum displayItems { - D_BRIGHTNESS = 0 #ifdef SCREEN_CONTRAST - ,D_CONTRAST -#endif + D_CONTRAST = 0 ,D_TIMER +#endif +#ifndef SCREEN_CONTRAST + D_TIMER = 0 +#endif }; #ifdef GPS_PRESENT diff --git a/openrtx/src/ui/module17/ui.c b/openrtx/src/ui/module17/ui.c index c1cb7423..9604a809 100644 --- a/openrtx/src/ui/module17/ui.c +++ b/openrtx/src/ui/module17/ui.c @@ -1221,7 +1221,10 @@ void ui_updateFSM(bool *sync_rtx) _ui_textInputReset(ui_state.new_callsign); } else if(msg.keys & KEY_ESC) + { + nvm_writeSettings(&state.settings); _ui_menuBack(MENU_SETTINGS); + } } break; case SETTINGS_RESET2DEFAULTS: @@ -1308,7 +1311,7 @@ void ui_updateFSM(bool *sync_rtx) ui_state.edit_mode = !ui_state.edit_mode; else if(msg.keys & KEY_ESC) { - // TODO save settings to non-volatile memory + nvm_writeSettings(&state.settings); _ui_menuBack(MENU_SETTINGS); } break; diff --git a/platform/drivers/NVM/nvmem_Mod17.c b/platform/drivers/NVM/nvmem_Mod17.c index a433b60e..37b5f19f 100644 --- a/platform/drivers/NVM/nvmem_Mod17.c +++ b/platform/drivers/NVM/nvmem_Mod17.c @@ -19,6 +19,83 @@ ***************************************************************************/ #include +#include +#include +#include +#include "flash.h" + +/* + * Data structures defining the memory layout used for saving and restore + * of user settings and VFO configuration. + */ +typedef struct +{ + uint16_t crc; + settings_t settings; + mod17Calib_t calibration; +} +__attribute__((packed)) dataBlock_t; + +typedef struct +{ + uint32_t magic; + uint32_t flags[32]; + dataBlock_t data[1024]; +} +__attribute__((packed)) memory_t; + +static const uint32_t MEM_MAGIC = 0x584E504F; // "OPNX" +static const uint32_t baseAddress = 0x080E0000; +memory_t *memory = ((memory_t *) baseAddress); + +extern mod17Calib_t mod17CalData; // Calibration data, to be saved and loaded + +/** + * \internal + * Utility function to find the currently active data block inside memory, that + * is the one containing the last saved settings. Blocks containing legacy data + * are marked with numbers starting from 4096. + * + * @return number currently active data block or -1 if memory data is invalid. + */ +static int findActiveBlock() +{ + // Check for invalid memory data + if(memory->magic != MEM_MAGIC) + return -1; + + uint16_t block = 0; + uint16_t bit = 0; + + // Find the first 32-bit block not full of zeroes + for(; block < 32; block++) + { + if(memory->flags[block] != 0x00000000) + { + break; + } + } + + // Find the last zero within a block + for(; bit < 32; bit++) + { + if((memory->flags[block] & (1 << bit)) != 0) + { + break; + } + } + + block = (block * 32) + bit; + block -= 1; + + // Check data validity + const size_t crcLen = sizeof(settings_t) + sizeof(mod17Calib_t); + uint16_t crc = crc_ccitt(&(memory->data[block].settings), crcLen); + if(crc != memory->data[block].crc) + return -2; + + return block; +} void nvm_init() { @@ -58,19 +135,66 @@ int nvm_readVfoChannelData(channel_t *channel) int nvm_readSettings(settings_t *settings) { - (void) settings; - return -1; + int block = findActiveBlock(); + + // Invalid data found + if(block < 0) return -1; + + memcpy(settings, &(memory->data[block].settings), sizeof(settings_t)); + memcpy(&mod17CalData, &(memory->data[block].calibration), sizeof(mod17Calib_t)); + + return 0; } int nvm_writeSettings(const settings_t *settings) { - (void) settings; - return -1; + uint32_t addr = 0; + int block = findActiveBlock(); + uint16_t prevCrc = 0; + + /* + * Memory never initialised or save space finished: erase all the sector. + * On STM32F405 the settings are saved in sector 11, starting at address + * 0x08060000. + */ + if((block < 0) || (block >= 2047)) + { + flash_eraseSector(11); + addr = ((uint32_t) &(memory->magic)); + flash_write(addr, &MEM_MAGIC, sizeof(MEM_MAGIC)); + block = 0; + } + else + { + prevCrc = memory->data[block].crc; + block += 1; + } + + dataBlock_t tmpBlock; + memcpy((&tmpBlock.settings), settings, sizeof(settings_t)); + memcpy((&tmpBlock.calibration), &mod17CalData, sizeof(mod17Calib_t)); + + const size_t crcLen = sizeof(settings_t) + sizeof(mod17Calib_t); + tmpBlock.crc = crc_ccitt(&(tmpBlock.settings), crcLen); + + // New data is equal to the old one, avoid saving + if((block != 0) && (tmpBlock.crc == prevCrc)) + return 0; + + // Save data + addr = ((uint32_t) &(memory->data[block])); + flash_write(addr, &tmpBlock, sizeof(dataBlock_t)); + + // Update the flags marking used data blocks + uint32_t flag = ~(1 << (block % 32)); + addr = ((uint32_t) &(memory->flags[block / 32])); + flash_write(addr, &flag, sizeof(uint32_t)); + + return 0; } int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo) { - (void) settings; (void) vfo; - return -1; + return nvm_writeSettings(settings); } diff --git a/platform/mcu/STM32F4xx/linker_script_Mod17.ld b/platform/mcu/STM32F4xx/linker_script_Mod17.ld index 7e229086..13473b0c 100644 --- a/platform/mcu/STM32F4xx/linker_script_Mod17.ld +++ b/platform/mcu/STM32F4xx/linker_script_Mod17.ld @@ -58,7 +58,7 @@ ENTRY(_Z13Reset_Handlerv) /* specify the memory areas */ MEMORY { - flash(rx) : ORIGIN = 0x08000000, LENGTH = 1M + flash(rx) : ORIGIN = 0x08000000, LENGTH = 1M - 128K /* * Note, the small ram starts at 0x10000000 but it is necessary to add the * size of the main stack, so it is 0x10000200.