Implemented CRC of persistent data (settings and VFO state) in MDx devices
This commit is contained in:
parent
4b0326b1c8
commit
e2137eae23
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue