From e2137eae23080e9f038e18b838485a13eba46422 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Thu, 11 Aug 2022 17:02:04 +0200 Subject: [PATCH] Implemented CRC of persistent data (settings and VFO state) in MDx devices --- openrtx/include/interfaces/nvmem.h | 4 +- openrtx/src/core/cps.c | 2 +- openrtx/src/core/state.c | 2 +- platform/drivers/NVM/nvmem_GDx.c | 10 ++- platform/drivers/NVM/nvmem_MD3x0.c | 30 ++------- platform/drivers/NVM/nvmem_MD9600.c | 38 +++-------- platform/drivers/NVM/nvmem_MDUV3x0.c | 34 ++-------- platform/drivers/NVM/nvmem_Mod17.c | 4 +- platform/drivers/NVM/nvmem_linux.c | 4 +- platform/drivers/NVM/nvmem_settings_MDx.c | 81 ++++++++++++++--------- platform/targets/MD-3x0/platform.c | 2 +- platform/targets/MD-UV3x0/platform.c | 2 +- 12 files changed, 86 insertions(+), 127 deletions(-) diff --git a/openrtx/include/interfaces/nvmem.h b/openrtx/include/interfaces/nvmem.h index cf046d4c..e70f1637 100644 --- a/openrtx/include/interfaces/nvmem.h +++ b/openrtx/include/interfaces/nvmem.h @@ -57,7 +57,7 @@ void nvm_readCalibData(void *buf); * * @param info: destination data structure for hardware information data. */ -void nvm_loadHwInfo(hwInfo_t *info); +void nvm_readHwInfo(hwInfo_t *info); /** * Read from storage the channel data corresponding to the VFO channel A. @@ -65,7 +65,7 @@ void nvm_loadHwInfo(hwInfo_t *info); * @param channel: pointer to the channel_t data structure to be populated. * @return 0 on success, -1 on failure */ -int nvm_readVFOChannelData(channel_t *channel); +int nvm_readVfoChannelData(channel_t *channel); /** * Read OpenRTX settings from storage. diff --git a/openrtx/src/core/cps.c b/openrtx/src/core/cps.c index 497814aa..f1af29d0 100644 --- a/openrtx/src/core/cps.c +++ b/openrtx/src/core/cps.c @@ -26,7 +26,7 @@ channel_t cps_getDefaultChannel() channel_t channel; channel.mode = OPMODE_FM; channel.bandwidth = BW_25; - channel.power = 1.0; + channel.power = 100; // 1W, P = 10dBm + n*0.2dBm, we store n // Set initial frequency based on supported bands const hwInfo_t* hwinfo = platform_getHwInfo(); diff --git a/openrtx/src/core/state.c b/openrtx/src/core/state.c index 6998db47..16866bc0 100644 --- a/openrtx/src/core/state.c +++ b/openrtx/src/core/state.c @@ -48,7 +48,7 @@ void state_init() * Try loading VFO configuration from nonvolatile memory and default to sane * values in case of failure. */ - if(nvm_readVFOChannelData(&state.channel) < 0) + if(nvm_readVfoChannelData(&state.channel) < 0) { state.channel = cps_getDefaultChannel(); } diff --git a/platform/drivers/NVM/nvmem_GDx.c b/platform/drivers/NVM/nvmem_GDx.c index ca873066..d48067ab 100644 --- a/platform/drivers/NVM/nvmem_GDx.c +++ b/platform/drivers/NVM/nvmem_GDx.c @@ -40,8 +40,11 @@ static const uint32_t VHF_CAL_BASE = 0x6F070; /** * \internal Utility function for loading band-specific calibration data into * the corresponding data structure. + * + * @param baseAddr: start address of the data block; + * @param cal: pointer to calibration data structure to be filled. */ -void _loadBandCalData(uint32_t baseAddr, bandCalData_t *cal) +static void _loadBandCalData(uint32_t baseAddr, bandCalData_t *cal) { W25Qx_readData(baseAddr + 0x08, &(cal->modBias), 2); W25Qx_readData(baseAddr + 0x0A, &(cal->mod2Offset), 1); @@ -87,6 +90,7 @@ void _loadBandCalData(uint32_t baseAddr, bandCalData_t *cal) } } + void nvm_init() { W25Qx_init(); @@ -133,13 +137,13 @@ void nvm_readCalibData(void *buf) calib->vhfCalPoints[7] = 172000000; } -void nvm_loadHwInfo(hwInfo_t *info) +void nvm_readHwInfo(hwInfo_t *info) { /* GDx devices does not have any hardware info in the external flash. */ (void) info; } -int nvm_readVFOChannelData(channel_t *channel) +int nvm_readVfoChannelData(channel_t *channel) { (void) channel; return -1; diff --git a/platform/drivers/NVM/nvmem_MD3x0.c b/platform/drivers/NVM/nvmem_MD3x0.c index d074bba5..3cbb71ae 100644 --- a/platform/drivers/NVM/nvmem_MD3x0.c +++ b/platform/drivers/NVM/nvmem_MD3x0.c @@ -96,7 +96,7 @@ void nvm_readCalibData(void *buf) } } -void nvm_loadHwInfo(hwInfo_t *info) +void nvm_readHwInfo(hwInfo_t *info) { uint16_t freqMin = 0; uint16_t freqMax = 0; @@ -142,32 +142,10 @@ void nvm_loadHwInfo(hwInfo_t *info) } /** - * The MD380 stock CPS does not have a VFO channel slot - * because the stock firmware does not have a VFO - * To enable this functionality reserve a Flash portion for saving the VFO - * - * TODO: temporarily implemented in "nvmem_settings_MDx.c" + * TODO: functions temporarily implemented in "nvmem_settings_MDx.c" int nvm_readVFOChannelData(channel_t *channel) -{ - (void) channel; - return -1; -} -*/ - -/* - -TODO: temporarily implemented in "nvmem_settings_MDx.c" - int nvm_readSettings(settings_t *settings) -{ - (void) settings; - return -1; -} -*/ - int nvm_writeSettings(const settings_t *settings) -{ - (void) settings; - return -1; -} + +*/ diff --git a/platform/drivers/NVM/nvmem_MD9600.c b/platform/drivers/NVM/nvmem_MD9600.c index 5262644a..0d5535a1 100644 --- a/platform/drivers/NVM/nvmem_MD9600.c +++ b/platform/drivers/NVM/nvmem_MD9600.c @@ -42,36 +42,16 @@ void nvm_readCalibData(void *buf) return; } -/* -TODO: temporarily implemented in "nvmem_settings_MDx.c" +void nvm_readHwInfo(hwInfo_t *info) +{ + (void) info; +} + +/** + * TODO: functions temporarily implemented in "nvmem_settings_MDx.c" int nvm_readVFOChannelData(channel_t *channel) -{ - return _cps_readChannelAtAddress(channel, vfoChannelBaseAddr); -} -*/ - -/* - -TODO: temporarily implemented in "nvmem_settings_MDx.c" - int nvm_readSettings(settings_t *settings) -{ - settings_t newSettings; - W25Qx_wakeup(); - delayUs(5); - W25Qx_readData(settingsAddr, ((uint8_t *) &newSettings), sizeof(settings_t)); - W25Qx_sleep(); - if(memcmp(newSettings.valid, default_settings.valid, 6) != 0) - return -1; - memcpy(settings, &newSettings, sizeof(settings_t)); - return 0; -} -*/ - int nvm_writeSettings(const settings_t *settings) -{ - // Disable settings write until DFU is implemented for flash backups - (void) settings; - return -1; -} + +*/ diff --git a/platform/drivers/NVM/nvmem_MDUV3x0.c b/platform/drivers/NVM/nvmem_MDUV3x0.c index b321508c..c5fb2594 100644 --- a/platform/drivers/NVM/nvmem_MDUV3x0.c +++ b/platform/drivers/NVM/nvmem_MDUV3x0.c @@ -104,7 +104,7 @@ void nvm_readCalibData(void *buf) } } -void nvm_loadHwInfo(hwInfo_t *info) +void nvm_readHwInfo(hwInfo_t *info) { uint16_t vhf_freqMin = 0; uint16_t vhf_freqMax = 0; @@ -142,35 +142,11 @@ void nvm_loadHwInfo(hwInfo_t *info) info->lcd_type = lcdInfo & 0x03; } -/* -TODO: temporarily implemented in "nvmem_settings_MDx.c" +/** + * TODO: functions temporarily implemented in "nvmem_settings_MDx.c" int nvm_readVFOChannelData(channel_t *channel) -{ - return _cps_readChannelAtAddress(channel, vfoChannelBaseAddr); -} -*/ - -/* -TODO: temporarily implemented in "nvmem_settings_MDx.c" - int nvm_readSettings(settings_t *settings) -{ - settings_t newSettings; - W25Qx_wakeup(); - delayUs(5); - W25Qx_readData(settingsAddr, ((uint8_t *) &newSettings), sizeof(settings_t)); - W25Qx_sleep(); - if(memcmp(newSettings.valid, default_settings.valid, 6) != 0) - return -1; - memcpy(settings, &newSettings, sizeof(settings_t)); - return 0; -} -*/ - int nvm_writeSettings(const settings_t *settings) -{ - (void) settings; - // Disable settings write until DFU is implemented for flash backups - return -1; -} + +*/ diff --git a/platform/drivers/NVM/nvmem_Mod17.c b/platform/drivers/NVM/nvmem_Mod17.c index a4bed1bd..e3acce5a 100644 --- a/platform/drivers/NVM/nvmem_Mod17.c +++ b/platform/drivers/NVM/nvmem_Mod17.c @@ -35,12 +35,12 @@ void nvm_readCalibData(void *buf) (void) buf; } -void nvm_loadHwInfo(hwInfo_t *info) +void nvm_readHwInfo(hwInfo_t *info) { (void) info; } -int nvm_readVFOChannelData(channel_t *channel) +int nvm_readVfoChannelData(channel_t *channel) { // Module 17 has no channels: just load default values for it channel->mode = OPMODE_M17; diff --git a/platform/drivers/NVM/nvmem_linux.c b/platform/drivers/NVM/nvmem_linux.c index c9bad75c..e32ce7f1 100644 --- a/platform/drivers/NVM/nvmem_linux.c +++ b/platform/drivers/NVM/nvmem_linux.c @@ -223,13 +223,13 @@ void nvm_terminate() } } -void nvm_loadHwInfo(hwInfo_t *info) +void nvm_readHwInfo(hwInfo_t *info) { /* Linux devices does not have any hardware info in the external flash. */ (void) info; } -int nvm_readVFOChannelData(channel_t *channel) +int nvm_readVfoChannelData(channel_t *channel) { return _cps_read(memory_paths[P_VFO], channel, sizeof(channel_t)); } diff --git a/platform/drivers/NVM/nvmem_settings_MDx.c b/platform/drivers/NVM/nvmem_settings_MDx.c index 0715297d..7c35955f 100644 --- a/platform/drivers/NVM/nvmem_settings_MDx.c +++ b/platform/drivers/NVM/nvmem_settings_MDx.c @@ -18,29 +18,33 @@ * along with this program; if not, see * ***************************************************************************/ -#include #include +#include #include +#include #include "flash.h" /* - * Data structure defining the memory layout used for saving and restore + * Data structures defining the memory layout used for saving and restore * of user settings and VFO configuration. */ typedef struct { - uint32_t magic; - uint32_t flags[64]; - struct dataBlock - { - settings_t settings; - channel_t vfoData; - } - data[2048]; + uint16_t crc; + settings_t settings; + channel_t vfoData; +} +__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 validMagic = 0x584E504F; // "OPNX" +static const uint32_t MEM_MAGIC = 0x584E504F; // "OPNX" static const uint32_t baseAddress = 0x080E0000; memory_t *memory = ((memory_t *) baseAddress); @@ -53,15 +57,17 @@ memory_t *memory = ((memory_t *) baseAddress); * * @return number currently active data block or -1 if memory data is invalid. */ -int findActiveBlock() +static int findActiveBlock() { - if(memory->magic != validMagic) - { - return -1; // Invalid memory data - } + // Check for invalid memory data + if(memory->magic != MEM_MAGIC) + return -1; uint16_t block = 0; - for(; block < 64; block++) + uint16_t bit = 0; + + // Find the first 32-bit block not full of zeroes + for(; block < 32; block++) { if(memory->flags[block] != 0x00000000) { @@ -69,7 +75,7 @@ int findActiveBlock() } } - uint16_t bit = 0; + // Find the last zero within a block for(; bit < 32; bit++) { if((memory->flags[block] & (1 << bit)) != 0) @@ -79,12 +85,19 @@ int findActiveBlock() } block = (block * 32) + bit; - return block - 1; + block -= 1; + + // Check data validity + uint16_t crc = crc_ccitt(&(memory->data[block].settings), + sizeof(settings_t) + sizeof(channel_t)); + if(crc != memory->data[block].crc) + return -2; + + return block; } - -int nvm_readVFOChannelData(channel_t *channel) +int nvm_readVfoChannelData(channel_t *channel) { int block = findActiveBlock(); @@ -110,8 +123,9 @@ int nvm_readSettings(settings_t *settings) int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo) { - uint32_t addr = 0; - int block = findActiveBlock(); + uint32_t addr = 0; + int block = findActiveBlock(); + uint16_t prevCrc = 0; /* * Memory never initialised or save space finished: erase all the sector. @@ -122,21 +136,28 @@ int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo) { flash_eraseSector(11); addr = ((uint32_t) &(memory->magic)); - flash_write(addr, &validMagic, sizeof(validMagic)); + flash_write(addr, &MEM_MAGIC, sizeof(MEM_MAGIC)); block = 0; } else { + prevCrc = memory->data[block].crc; block += 1; } - // Save settings - addr = ((uint32_t) &(memory->data[block].settings)); - flash_write(addr, settings, sizeof(settings_t)); + dataBlock_t tmpBlock; + memcpy((&tmpBlock.settings), settings, sizeof(settings_t)); + memcpy((&tmpBlock.vfoData), vfo, sizeof(channel_t)); + tmpBlock.crc = crc_ccitt(&(tmpBlock.settings), + sizeof(settings_t) + sizeof(channel_t)); - // Save VFO configuration - addr = ((uint32_t) &(memory->data[block].vfoData)); - flash_write(addr, vfo, sizeof(channel_t)); + // 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)); diff --git a/platform/targets/MD-3x0/platform.c b/platform/targets/MD-3x0/platform.c index 40aded4d..a62f72d3 100644 --- a/platform/targets/MD-3x0/platform.c +++ b/platform/targets/MD-3x0/platform.c @@ -62,7 +62,7 @@ void platform_init() nvm_init(); /* Initialise non volatile memory manager */ nvm_readCalibData(&calibration); /* Load calibration data */ - nvm_loadHwInfo(&hwInfo); /* Load hardware information data */ + nvm_readHwInfo(&hwInfo); /* Load hardware information data */ toneGen_init(); /* Initialise tone generator */ rtc_init(); /* Initialise RTC */ backlight_init(); /* Initialise backlight driver */ diff --git a/platform/targets/MD-UV3x0/platform.c b/platform/targets/MD-UV3x0/platform.c index 25676ff3..0783dde5 100644 --- a/platform/targets/MD-UV3x0/platform.c +++ b/platform/targets/MD-UV3x0/platform.c @@ -61,7 +61,7 @@ void platform_init() nvm_init(); /* Initialise non volatile memory manager */ nvm_readCalibData(&calibration); /* Load calibration data */ - nvm_loadHwInfo(&hwInfo); /* Load hardware information data */ + nvm_readHwInfo(&hwInfo); /* Load hardware information data */ toneGen_init(); /* Initialise tone generator */ rtc_init(); /* Initialise RTC */ chSelector_init(); /* Initialise channel selector handler */