1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-23 08:15:30 +03:00

Use CRC rather than simple checksum for EEPROM (#2517)

Use CRC rather than simple checksum for EEPROM
This commit is contained in:
Martin Budden 2017-03-08 17:50:45 +00:00 committed by GitHub
parent 9c03b32114
commit a77e424dec
3 changed files with 49 additions and 47 deletions

View file

@ -350,6 +350,17 @@ uint16_t crc16_ccitt(uint16_t crc, unsigned char a)
return crc;
}
uint16_t crc16_ccitt_update(uint16_t crc, const void *data, uint32_t length)
{
const uint8_t *p = (const uint8_t *)data;
const uint8_t *pend = p + length;
for (; p != pend; p++) {
crc = crc16_ccitt(crc, *p);
}
return crc;
}
uint8_t crc8_dvb_s2(uint8_t crc, unsigned char a)
{
crc ^= a;

View file

@ -140,5 +140,5 @@ static inline float constrainf(float amt, float low, float high)
return amt;
}
uint16_t crc16_ccitt(uint16_t crc, unsigned char a);
uint16_t crc16_ccitt_update(uint16_t crc, const void *data, uint32_t length);
uint8_t crc8_dvb_s2(uint8_t crc, unsigned char a);

View file

@ -35,15 +35,6 @@
#include "fc/config.h"
// declare a dummy PG, since scanEEPROM assumes there is at least one PG
// !!TODO remove once first PG has been created out of masterConfg
typedef struct dummpConfig_s {
uint8_t dummy;
} dummyConfig_t;
PG_DECLARE(dummyConfig_t, dummyConfig);
#define PG_DUMMY_CONFIG 1
PG_REGISTER(dummyConfig_t, dummyConfig, PG_DUMMY_CONFIG, 0);
extern uint8_t __config_start; // configured via linker script when building binaries.
extern uint8_t __config_end;
@ -57,11 +48,14 @@ typedef enum {
CR_CLASSICATION_PROFILE_LAST = CR_CLASSICATION_PROFILE3,
} configRecordFlags_e;
#define CR_CLASSIFICATION_MASK (0x3)
#define CR_CLASSIFICATION_MASK (0x3)
#define CRC_START_VALUE 0xFFFF
#define CRC_CHECK_VALUE 0x1D0F // pre-calculated value of CRC that includes the CRC itself
// Header for the saved copy.
typedef struct {
uint8_t eepromConfigVersion;
uint8_t magic_be; // magic number, should be 0xBE
char boardIdentifier[sizeof(TARGET_BOARD_IDENTIFIER)];
} PG_PACKED configHeader_t;
@ -97,42 +91,33 @@ void initEEPROM(void)
BUILD_BUG_ON(offsetof(packingTest_t, word) != 1);
BUILD_BUG_ON(sizeof(packingTest_t) != 5);
BUILD_BUG_ON(sizeof(configHeader_t) != 1 + sizeof(TARGET_BOARD_IDENTIFIER));
BUILD_BUG_ON(sizeof(configHeader_t) != 2 + sizeof(TARGET_BOARD_IDENTIFIER));
BUILD_BUG_ON(sizeof(configFooter_t) != 2);
BUILD_BUG_ON(sizeof(configRecord_t) != 6);
}
static uint8_t updateChecksum(uint8_t chk, const void *data, uint32_t length)
{
const uint8_t *p = (const uint8_t *)data;
const uint8_t *pend = p + length;
for (; p != pend; p++) {
chk ^= *p;
}
return chk;
}
// Scan the EEPROM config. Returns true if the config is valid.
bool isEEPROMContentValid(void)
{
uint8_t chk = 0;
const uint8_t *p = &__config_start;
const configHeader_t *header = (const configHeader_t *)p;
if (header->eepromConfigVersion != EEPROM_CONF_VERSION) {
return false;
}
if (header->magic_be != 0xBE) {
return false;
}
if (strncasecmp(header->boardIdentifier, TARGET_BOARD_IDENTIFIER, sizeof(TARGET_BOARD_IDENTIFIER))) {
return false;
}
chk = updateChecksum(chk, header, sizeof(*header));
uint16_t crc = CRC_START_VALUE;
crc = crc16_ccitt_update(crc, header, sizeof(*header));
p += sizeof(*header);
#ifndef USE_PARAMETER_GROUPS
// include the transitional masterConfig record
chk = updateChecksum(chk, p, sizeof(masterConfig));
crc = crc16_ccitt_update(crc, p, sizeof(masterConfig));
p += sizeof(masterConfig);
#endif
@ -149,19 +134,24 @@ bool isEEPROMContentValid(void)
return false;
}
chk = updateChecksum(chk, p, record->size);
crc = crc16_ccitt_update(crc, p, record->size);
p += record->size;
}
const configFooter_t *footer = (const configFooter_t *)p;
chk = updateChecksum(chk, footer, sizeof(*footer));
crc = crc16_ccitt_update(crc, footer, sizeof(*footer));
p += sizeof(*footer);
chk = ~chk;
const uint8_t checkSum = *p;
p += sizeof(checkSum);
// include stored CRC in the CRC calculation
const uint16_t *storedCrc = (const uint16_t *)p;
crc = crc16_ccitt_update(crc, storedCrc, sizeof(*storedCrc));
p += sizeof(storedCrc);
eepromConfigSize = p - &__config_start;
return chk == checkSum;
// CRC has the property that if the CRC itself is included in the calculation the resulting CRC will have constant value
return crc == CRC_CHECK_VALUE;
}
uint16_t getEEPROMConfigSize(void)
@ -235,19 +225,20 @@ static bool writeSettingsToEEPROM(void)
config_streamer_init(&streamer);
config_streamer_start(&streamer, (uintptr_t)&__config_start, &__config_end - &__config_start);
uint8_t chk = 0;
configHeader_t header = {
.eepromConfigVersion = EEPROM_CONF_VERSION,
.boardIdentifier = TARGET_BOARD_IDENTIFIER,
.eepromConfigVersion = EEPROM_CONF_VERSION,
.magic_be = 0xBE,
.boardIdentifier = TARGET_BOARD_IDENTIFIER,
};
config_streamer_write(&streamer, (uint8_t *)&header, sizeof(header));
chk = updateChecksum(chk, (uint8_t *)&header, sizeof(header));
uint16_t crc = CRC_START_VALUE;
crc = crc16_ccitt_update(crc, (uint8_t *)&header, sizeof(header));
#ifndef USE_PARAMETER_GROUPS
// write the transitional masterConfig record
config_streamer_write(&streamer, (uint8_t *)&masterConfig, sizeof(masterConfig));
chk = updateChecksum(chk, (uint8_t *)&masterConfig, sizeof(masterConfig));
crc = crc16_ccitt_update(crc, (uint8_t *)&masterConfig, sizeof(masterConfig));
#endif
PG_FOREACH(reg) {
const uint16_t regSize = pgSize(reg);
@ -262,9 +253,9 @@ static bool writeSettingsToEEPROM(void)
// write the only instance
record.flags |= CR_CLASSICATION_SYSTEM;
config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record));
chk = updateChecksum(chk, (uint8_t *)&record, sizeof(record));
crc = crc16_ccitt_update(crc, (uint8_t *)&record, sizeof(record));
config_streamer_write(&streamer, reg->address, regSize);
chk = updateChecksum(chk, reg->address, regSize);
crc = crc16_ccitt_update(crc, reg->address, regSize);
} else {
// write one instance for each profile
for (uint8_t profileIndex = 0; profileIndex < MAX_PROFILE_COUNT; profileIndex++) {
@ -272,10 +263,10 @@ static bool writeSettingsToEEPROM(void)
record.flags |= ((profileIndex + 1) & CR_CLASSIFICATION_MASK);
config_streamer_write(&streamer, (uint8_t *)&record, sizeof(record));
chk = updateChecksum(chk, (uint8_t *)&record, sizeof(record));
crc = crc16_ccitt_update(crc, (uint8_t *)&record, sizeof(record));
const uint8_t *address = reg->address + (regSize * profileIndex);
config_streamer_write(&streamer, address, regSize);
chk = updateChecksum(chk, address, regSize);
crc = crc16_ccitt_update(crc, address, regSize);
}
}
}
@ -285,15 +276,15 @@ static bool writeSettingsToEEPROM(void)
};
config_streamer_write(&streamer, (uint8_t *)&footer, sizeof(footer));
chk = updateChecksum(chk, (uint8_t *)&footer, sizeof(footer));
crc = crc16_ccitt_update(crc, (uint8_t *)&footer, sizeof(footer));
// append checksum now
chk = ~chk;
config_streamer_write(&streamer, &chk, sizeof(chk));
// 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);
bool success = config_streamer_finish(&streamer) == 0;
const bool success = config_streamer_finish(&streamer) == 0;
return success;
}