Implemented CRC of persistent data (settings and VFO state) in MDx devices

This commit is contained in:
Silvano Seva 2022-08-11 17:02:04 +02:00
parent 4b0326b1c8
commit e2137eae23
12 changed files with 86 additions and 127 deletions

View File

@ -57,7 +57,7 @@ void nvm_readCalibData(void *buf);
* *
* @param info: destination data structure for hardware information data. * @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. * 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. * @param channel: pointer to the channel_t data structure to be populated.
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
*/ */
int nvm_readVFOChannelData(channel_t *channel); int nvm_readVfoChannelData(channel_t *channel);
/** /**
* Read OpenRTX settings from storage. * Read OpenRTX settings from storage.

View File

@ -26,7 +26,7 @@ channel_t cps_getDefaultChannel()
channel_t channel; channel_t channel;
channel.mode = OPMODE_FM; channel.mode = OPMODE_FM;
channel.bandwidth = BW_25; 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 // Set initial frequency based on supported bands
const hwInfo_t* hwinfo = platform_getHwInfo(); const hwInfo_t* hwinfo = platform_getHwInfo();

View File

@ -48,7 +48,7 @@ void state_init()
* Try loading VFO configuration from nonvolatile memory and default to sane * Try loading VFO configuration from nonvolatile memory and default to sane
* values in case of failure. * values in case of failure.
*/ */
if(nvm_readVFOChannelData(&state.channel) < 0) if(nvm_readVfoChannelData(&state.channel) < 0)
{ {
state.channel = cps_getDefaultChannel(); state.channel = cps_getDefaultChannel();
} }

View File

@ -40,8 +40,11 @@ static const uint32_t VHF_CAL_BASE = 0x6F070;
/** /**
* \internal Utility function for loading band-specific calibration data into * \internal Utility function for loading band-specific calibration data into
* the corresponding data structure. * 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 + 0x08, &(cal->modBias), 2);
W25Qx_readData(baseAddr + 0x0A, &(cal->mod2Offset), 1); W25Qx_readData(baseAddr + 0x0A, &(cal->mod2Offset), 1);
@ -87,6 +90,7 @@ void _loadBandCalData(uint32_t baseAddr, bandCalData_t *cal)
} }
} }
void nvm_init() void nvm_init()
{ {
W25Qx_init(); W25Qx_init();
@ -133,13 +137,13 @@ void nvm_readCalibData(void *buf)
calib->vhfCalPoints[7] = 172000000; 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. */ /* GDx devices does not have any hardware info in the external flash. */
(void) info; (void) info;
} }
int nvm_readVFOChannelData(channel_t *channel) int nvm_readVfoChannelData(channel_t *channel)
{ {
(void) channel; (void) channel;
return -1; return -1;

View File

@ -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 freqMin = 0;
uint16_t freqMax = 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 * TODO: functions temporarily implemented in "nvmem_settings_MDx.c"
* 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"
int nvm_readVFOChannelData(channel_t *channel) int nvm_readVFOChannelData(channel_t *channel)
{
(void) channel;
return -1;
}
*/
/*
TODO: temporarily implemented in "nvmem_settings_MDx.c"
int nvm_readSettings(settings_t *settings) int nvm_readSettings(settings_t *settings)
{
(void) settings;
return -1;
}
*/
int nvm_writeSettings(const settings_t *settings) int nvm_writeSettings(const settings_t *settings)
{
(void) settings; */
return -1;
}

View File

@ -42,36 +42,16 @@ void nvm_readCalibData(void *buf)
return; return;
} }
/* void nvm_readHwInfo(hwInfo_t *info)
TODO: temporarily implemented in "nvmem_settings_MDx.c" {
(void) info;
}
/**
* TODO: functions temporarily implemented in "nvmem_settings_MDx.c"
int nvm_readVFOChannelData(channel_t *channel) 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) 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) int nvm_writeSettings(const settings_t *settings)
{
// Disable settings write until DFU is implemented for flash backups */
(void) settings;
return -1;
}

View File

@ -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_freqMin = 0;
uint16_t vhf_freqMax = 0; uint16_t vhf_freqMax = 0;
@ -142,35 +142,11 @@ void nvm_loadHwInfo(hwInfo_t *info)
info->lcd_type = lcdInfo & 0x03; 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) 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) 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) int nvm_writeSettings(const settings_t *settings)
{
(void) settings; */
// Disable settings write until DFU is implemented for flash backups
return -1;
}

View File

@ -35,12 +35,12 @@ void nvm_readCalibData(void *buf)
(void) buf; (void) buf;
} }
void nvm_loadHwInfo(hwInfo_t *info) void nvm_readHwInfo(hwInfo_t *info)
{ {
(void) 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 // Module 17 has no channels: just load default values for it
channel->mode = OPMODE_M17; channel->mode = OPMODE_M17;

View File

@ -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. */ /* Linux devices does not have any hardware info in the external flash. */
(void) info; (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)); return _cps_read(memory_paths[P_VFO], channel, sizeof(channel_t));
} }

View File

@ -18,29 +18,33 @@
* along with this program; if not, see <http://www.gnu.org/licenses/> * * along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/ ***************************************************************************/
#include <string.h>
#include <interfaces/nvmem.h> #include <interfaces/nvmem.h>
#include <string.h>
#include <cps.h> #include <cps.h>
#include <crc.h>
#include "flash.h" #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. * of user settings and VFO configuration.
*/ */
typedef struct typedef struct
{ {
uint32_t magic; uint16_t crc;
uint32_t flags[64];
struct dataBlock
{
settings_t settings; settings_t settings;
channel_t vfoData; channel_t vfoData;
} }
data[2048]; __attribute__((packed)) dataBlock_t;
typedef struct
{
uint32_t magic;
uint32_t flags[32];
dataBlock_t data[1024];
} }
__attribute__((packed)) memory_t; __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; static const uint32_t baseAddress = 0x080E0000;
memory_t *memory = ((memory_t *) baseAddress); 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. * @return number currently active data block or -1 if memory data is invalid.
*/ */
int findActiveBlock() static int findActiveBlock()
{ {
if(memory->magic != validMagic) // Check for invalid memory data
{ if(memory->magic != MEM_MAGIC)
return -1; // Invalid memory data return -1;
}
uint16_t block = 0; 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) 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++) for(; bit < 32; bit++)
{ {
if((memory->flags[block] & (1 << bit)) != 0) if((memory->flags[block] & (1 << bit)) != 0)
@ -79,12 +85,19 @@ int findActiveBlock()
} }
block = (block * 32) + bit; 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(); int block = findActiveBlock();
@ -112,6 +125,7 @@ int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo)
{ {
uint32_t addr = 0; uint32_t addr = 0;
int block = findActiveBlock(); int block = findActiveBlock();
uint16_t prevCrc = 0;
/* /*
* Memory never initialised or save space finished: erase all the sector. * 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); flash_eraseSector(11);
addr = ((uint32_t) &(memory->magic)); addr = ((uint32_t) &(memory->magic));
flash_write(addr, &validMagic, sizeof(validMagic)); flash_write(addr, &MEM_MAGIC, sizeof(MEM_MAGIC));
block = 0; block = 0;
} }
else else
{ {
prevCrc = memory->data[block].crc;
block += 1; block += 1;
} }
// Save settings dataBlock_t tmpBlock;
addr = ((uint32_t) &(memory->data[block].settings)); memcpy((&tmpBlock.settings), settings, sizeof(settings_t));
flash_write(addr, 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 // New data is equal to the old one, avoid saving
addr = ((uint32_t) &(memory->data[block].vfoData)); if((block != 0) && (tmpBlock.crc == prevCrc))
flash_write(addr, vfo, sizeof(channel_t)); return 0;
// Save data
addr = ((uint32_t) &(memory->data[block]));
flash_write(addr, &tmpBlock, sizeof(dataBlock_t));
// Update the flags marking used data blocks // Update the flags marking used data blocks
uint32_t flag = ~(1 << (block % 32)); uint32_t flag = ~(1 << (block % 32));

View File

@ -62,7 +62,7 @@ void platform_init()
nvm_init(); /* Initialise non volatile memory manager */ nvm_init(); /* Initialise non volatile memory manager */
nvm_readCalibData(&calibration); /* Load calibration data */ 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 */ toneGen_init(); /* Initialise tone generator */
rtc_init(); /* Initialise RTC */ rtc_init(); /* Initialise RTC */
backlight_init(); /* Initialise backlight driver */ backlight_init(); /* Initialise backlight driver */

View File

@ -61,7 +61,7 @@ void platform_init()
nvm_init(); /* Initialise non volatile memory manager */ nvm_init(); /* Initialise non volatile memory manager */
nvm_readCalibData(&calibration); /* Load calibration data */ 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 */ toneGen_init(); /* Initialise tone generator */
rtc_init(); /* Initialise RTC */ rtc_init(); /* Initialise RTC */
chSelector_init(); /* Initialise channel selector handler */ chSelector_init(); /* Initialise channel selector handler */