Maintain FNV checksums per PG to only write if config updated
This commit is contained in:
parent
9e894586b7
commit
fdd7990a29
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/crc.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "streambuf.h"
|
||||
|
@ -114,3 +116,17 @@ void crc8_xor_sbuf_append(sbuf_t *dst, uint8_t *start)
|
|||
sbufWriteU8(dst, crc);
|
||||
}
|
||||
|
||||
// Fowler–Noll–Vo hash function; see https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
|
||||
uint32_t fnv_update(uint32_t hash, const void *data, uint32_t length)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)data;
|
||||
const uint8_t *pend = p + length;
|
||||
|
||||
for (; p != pend; p++) {
|
||||
hash *= FNV_PRIME;
|
||||
hash ^= *p;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,3 +38,8 @@ void crc8_sbuf_append(struct sbuf_s *dst, uint8_t *start, uint8_t poly);
|
|||
|
||||
uint8_t crc8_xor_update(uint8_t crc, const void *data, uint32_t length);
|
||||
void crc8_xor_sbuf_append(struct sbuf_s *dst, uint8_t *start);
|
||||
|
||||
#define FNV_PRIME 16777619
|
||||
#define FNV_OFFSET_BASIS 2166136261
|
||||
|
||||
uint32_t fnv_update(uint32_t hash, const void *data, uint32_t length);
|
||||
|
|
|
@ -388,6 +388,7 @@ bool loadEEPROM(void)
|
|||
|
||||
success = false;
|
||||
}
|
||||
*reg->fnv_hash = fnv_update(FNV_OFFSET_BASIS, reg->address, pgSize(reg));
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -395,51 +396,63 @@ bool loadEEPROM(void)
|
|||
|
||||
static bool writeSettingsToEEPROM(void)
|
||||
{
|
||||
config_streamer_t streamer;
|
||||
config_streamer_init(&streamer);
|
||||
|
||||
config_streamer_start(&streamer, (uintptr_t)&__config_start, &__config_end - &__config_start);
|
||||
bool dirtyConfig = !isEEPROMVersionValid() || !isEEPROMStructureValid();
|
||||
|
||||
configHeader_t header = {
|
||||
.eepromConfigVersion = EEPROM_CONF_VERSION,
|
||||
.magic_be = 0xBE,
|
||||
};
|
||||
|
||||
config_streamer_write(&streamer, (uint8_t *)&header, sizeof(header));
|
||||
uint16_t crc = CRC_START_VALUE;
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&header, sizeof(header));
|
||||
PG_FOREACH(reg) {
|
||||
const uint16_t regSize = pgSize(reg);
|
||||
configRecord_t record = {
|
||||
.size = sizeof(configRecord_t) + regSize,
|
||||
.pgn = pgN(reg),
|
||||
.version = pgVersion(reg),
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
record.flags |= CR_CLASSICATION_SYSTEM;
|
||||
config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record));
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&record, sizeof(record));
|
||||
config_streamer_write(&streamer, reg->address, regSize);
|
||||
crc = crc16_ccitt_update(crc, reg->address, regSize);
|
||||
if (*reg->fnv_hash != fnv_update(FNV_OFFSET_BASIS, reg->address, pgSize(reg))) {
|
||||
dirtyConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
configFooter_t footer = {
|
||||
.terminator = 0,
|
||||
};
|
||||
// Only write the config if it has changed
|
||||
if (dirtyConfig) {
|
||||
config_streamer_t streamer;
|
||||
config_streamer_init(&streamer);
|
||||
|
||||
config_streamer_write(&streamer, (uint8_t *)&footer, sizeof(footer));
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&footer, sizeof(footer));
|
||||
config_streamer_start(&streamer, (uintptr_t)&__config_start, &__config_end - &__config_start);
|
||||
|
||||
// include inverted CRC in big endian format in the CRC
|
||||
const uint16_t invertedBigEndianCrc = ~(((crc & 0xFF) << 8) | (crc >> 8));
|
||||
config_streamer_write(&streamer, (uint8_t *)&invertedBigEndianCrc, sizeof(crc));
|
||||
config_streamer_write(&streamer, (uint8_t *)&header, sizeof(header));
|
||||
uint16_t crc = CRC_START_VALUE;
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&header, sizeof(header));
|
||||
PG_FOREACH(reg) {
|
||||
const uint16_t regSize = pgSize(reg);
|
||||
configRecord_t record = {
|
||||
.size = sizeof(configRecord_t) + regSize,
|
||||
.pgn = pgN(reg),
|
||||
.version = pgVersion(reg),
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
config_streamer_flush(&streamer);
|
||||
|
||||
const bool success = config_streamer_finish(&streamer) == 0;
|
||||
record.flags |= CR_CLASSICATION_SYSTEM;
|
||||
config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record));
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&record, sizeof(record));
|
||||
config_streamer_write(&streamer, reg->address, regSize);
|
||||
crc = crc16_ccitt_update(crc, reg->address, regSize);
|
||||
}
|
||||
|
||||
return success;
|
||||
configFooter_t footer = {
|
||||
.terminator = 0,
|
||||
};
|
||||
|
||||
config_streamer_write(&streamer, (uint8_t *)&footer, sizeof(footer));
|
||||
crc = crc16_ccitt_update(crc, (uint8_t *)&footer, sizeof(footer));
|
||||
|
||||
// include inverted CRC in big endian format in the CRC
|
||||
const uint16_t invertedBigEndianCrc = ~(((crc & 0xFF) << 8) | (crc >> 8));
|
||||
config_streamer_write(&streamer, (uint8_t *)&invertedBigEndianCrc, sizeof(crc));
|
||||
|
||||
config_streamer_flush(&streamer);
|
||||
|
||||
return (config_streamer_finish(&streamer) == 0);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void writeConfigToEEPROM(void)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "platform.h"
|
||||
|
||||
#include "common/crc.h"
|
||||
#include "common/maths.h"
|
||||
|
||||
#include "pg.h"
|
||||
|
@ -80,6 +81,8 @@ bool pgLoad(const pgRegistry_t* reg, const void *from, int size, int version)
|
|||
const int take = MIN(size, pgSize(reg));
|
||||
memcpy(pgOffset(reg), from, take);
|
||||
|
||||
*reg->fnv_hash = fnv_update(FNV_OFFSET_BASIS, from, take);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ typedef struct pgRegistry_s {
|
|||
void *ptr; // Pointer to init template
|
||||
pgResetFunc *fn; // Popinter to pgResetFunc
|
||||
} reset;
|
||||
uint32_t *fnv_hash; // Used to detect if config has changed prior to write
|
||||
} pgRegistry_t;
|
||||
|
||||
static inline uint16_t pgN(const pgRegistry_t* reg) {return reg->pgn & PGR_PGN_MASK;}
|
||||
|
@ -118,6 +119,7 @@ extern const uint8_t __pg_resetdata_end[];
|
|||
#define PG_REGISTER_I(_type, _name, _pgn, _version, _reset) \
|
||||
_type _name ## _System; \
|
||||
_type _name ## _Copy; \
|
||||
uint32_t _name ## _fnv_hash; \
|
||||
/* Force external linkage for g++. Catch multi registration */ \
|
||||
extern const pgRegistry_t _name ## _Registry; \
|
||||
const pgRegistry_t _name ##_Registry PG_REGISTER_ATTRIBUTES = { \
|
||||
|
@ -125,6 +127,7 @@ extern const uint8_t __pg_resetdata_end[];
|
|||
.length = 1, \
|
||||
.size = sizeof(_type) | PGR_SIZE_SYSTEM_FLAG, \
|
||||
.address = (uint8_t*)&_name ## _System, \
|
||||
.fnv_hash = &_name ## _fnv_hash, \
|
||||
.copy = (uint8_t*)&_name ## _Copy, \
|
||||
.ptr = 0, \
|
||||
_reset, \
|
||||
|
@ -149,12 +152,14 @@ extern const uint8_t __pg_resetdata_end[];
|
|||
#define PG_REGISTER_ARRAY_I(_type, _length, _name, _pgn, _version, _reset) \
|
||||
_type _name ## _SystemArray[_length]; \
|
||||
_type _name ## _CopyArray[_length]; \
|
||||
uint32_t _name ## _fnv_hash; \
|
||||
extern const pgRegistry_t _name ##_Registry; \
|
||||
const pgRegistry_t _name ## _Registry PG_REGISTER_ATTRIBUTES = { \
|
||||
.pgn = _pgn | (_version << 12), \
|
||||
.length = _length, \
|
||||
.size = (sizeof(_type) * _length) | PGR_SIZE_SYSTEM_FLAG, \
|
||||
.address = (uint8_t*)&_name ## _SystemArray, \
|
||||
.fnv_hash = &_name ## _fnv_hash, \
|
||||
.copy = (uint8_t*)&_name ## _CopyArray, \
|
||||
.ptr = 0, \
|
||||
_reset, \
|
||||
|
|
|
@ -106,7 +106,9 @@ blackbox_encoding_unittest_SRC := \
|
|||
|
||||
cli_unittest_SRC := \
|
||||
$(USER_DIR)/cli/cli.c \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/printf.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/config/feature.c \
|
||||
$(USER_DIR)/pg/pg.c \
|
||||
$(USER_DIR)/common/typeconversion.c
|
||||
|
@ -227,6 +229,8 @@ link_quality_unittest_DEFINES := \
|
|||
USE_RX_LINK_QUALITY_INFO=
|
||||
|
||||
pg_unittest_SRC := \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/pg/pg.c
|
||||
|
||||
|
||||
|
@ -234,7 +238,9 @@ rc_controls_unittest_SRC := \
|
|||
$(USER_DIR)/fc/rc_controls.c \
|
||||
$(USER_DIR)/pg/pg.c \
|
||||
$(USER_DIR)/common/bitarray.c \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/maths.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/fc/rc_adjustments.c \
|
||||
$(USER_DIR)/fc/rc_modes.c
|
||||
|
||||
|
@ -254,7 +260,9 @@ rx_ibus_unittest_SRC := \
|
|||
|
||||
rx_ranges_unittest_SRC := \
|
||||
$(USER_DIR)/common/bitarray.c \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/maths.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/fc/rc_modes.c \
|
||||
$(USER_DIR)/rx/rx.c \
|
||||
$(USER_DIR)/pg/pg.c \
|
||||
|
@ -287,7 +295,9 @@ sensor_gyro_unittest_SRC := \
|
|||
$(USER_DIR)/sensors/gyro_init.c \
|
||||
$(USER_DIR)/sensors/boardalignment.c \
|
||||
$(USER_DIR)/common/filter.c \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/maths.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/common/sensor_alignment.c \
|
||||
$(USER_DIR)/drivers/accgyro/accgyro_fake.c \
|
||||
$(USER_DIR)/drivers/accgyro/gyro_sync.c \
|
||||
|
@ -378,8 +388,10 @@ rcdevice_unittest_SRC := \
|
|||
$(USER_DIR)/pg/pg.c \
|
||||
|
||||
pid_unittest_SRC := \
|
||||
$(USER_DIR)/common/crc.c \
|
||||
$(USER_DIR)/common/filter.c \
|
||||
$(USER_DIR)/common/maths.c \
|
||||
$(USER_DIR)/common/streambuf.c \
|
||||
$(USER_DIR)/drivers/accgyro/gyro_sync.c \
|
||||
$(USER_DIR)/fc/controlrate_profile.c \
|
||||
$(USER_DIR)/fc/runtime_config.c \
|
||||
|
|
Loading…
Reference in New Issue