|
|
|
@@ -6,6 +6,16 @@ |
|
|
|
#define PLSR_HSD_BACKUP_VERSION (1U) |
|
|
|
#define PLSR_BACKUP_SLOT_A_OFFSET (0x0100UL) |
|
|
|
#define PLSR_BACKUP_SLOT_STRIDE (0x0200UL) |
|
|
|
#define PLSR_SFD_FLASH_MAGIC (0x504C5346UL) |
|
|
|
#define PLSR_SFD_FLASH_VERSION (1U) |
|
|
|
#define PLSR_SFD_FLASH_SLOT_A_ADDRESS (0x080C0000UL) |
|
|
|
#define PLSR_SFD_FLASH_SLOT_B_ADDRESS (0x080E0000UL) |
|
|
|
#define PLSR_SFD_FLASH_SECTOR_SIZE (0x00020000UL) |
|
|
|
#define PLSR_SFD_AXIS_STRIDE (130U) |
|
|
|
#define PLSR_SFD_PARAMETER_SET_COUNT (4U) |
|
|
|
#define PLSR_SFD_PARAMETER_SET_OFFSET (50U) |
|
|
|
#define PLSR_SFD_PARAMETER_SET_STRIDE (20U) |
|
|
|
#define PLSR_SFD_DEFAULT_MAX_SPEED (100000UL) |
|
|
|
|
|
|
|
typedef struct |
|
|
|
{ |
|
|
|
@@ -17,16 +27,38 @@ typedef struct |
|
|
|
uint32_t crc32; |
|
|
|
} PLSR_HSD_BACKUP_RECORD; |
|
|
|
|
|
|
|
typedef struct |
|
|
|
{ |
|
|
|
uint32_t magic; |
|
|
|
uint16_t version; |
|
|
|
uint16_t payloadLength; |
|
|
|
uint32_t generation; |
|
|
|
} PLSR_SFD_FLASH_HEADER; |
|
|
|
|
|
|
|
typedef struct |
|
|
|
{ |
|
|
|
uint32_t magic; |
|
|
|
uint16_t version; |
|
|
|
uint16_t payloadLength; |
|
|
|
uint32_t generation; |
|
|
|
PLSR_SFD_DATA data; |
|
|
|
uint32_t crc32; |
|
|
|
} PLSR_SFD_FLASH_RECORD; |
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
static PLSR_HSD_BACKUP_RECORD PlsrHostBackupSlots[2]; |
|
|
|
static PLSR_SFD_FLASH_RECORD PlsrHostSfdSlots[2]; |
|
|
|
static PLSR_TEST_SFD_FAULT PlsrHostSfdFault; |
|
|
|
#else |
|
|
|
#include "stm32f4xx.h" |
|
|
|
#include "stm32f4xx_hal.h" |
|
|
|
#include "stm32f4xx_hal_flash_ex.h" |
|
|
|
#endif |
|
|
|
|
|
|
|
static uint32_t PlsrPersistenceCrc32(const volatile uint8_t *data, |
|
|
|
uint32_t length) |
|
|
|
static uint32_t PlsrPersistenceCrc32Update(uint32_t crc, |
|
|
|
const volatile uint8_t *data, |
|
|
|
uint32_t length) |
|
|
|
{ |
|
|
|
uint32_t crc = 0xFFFFFFFFUL; |
|
|
|
uint32_t index; |
|
|
|
uint8_t bit; |
|
|
|
|
|
|
|
@@ -46,7 +78,13 @@ static uint32_t PlsrPersistenceCrc32(const volatile uint8_t *data, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return ~crc; |
|
|
|
return crc; |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t PlsrPersistenceCrc32(const volatile uint8_t *data, |
|
|
|
uint32_t length) |
|
|
|
{ |
|
|
|
return ~PlsrPersistenceCrc32Update(0xFFFFFFFFUL, data, length); |
|
|
|
} |
|
|
|
|
|
|
|
static volatile PLSR_HSD_BACKUP_RECORD *PlsrPersistenceGetHsdSlot( |
|
|
|
@@ -86,6 +124,200 @@ static uint8_t PlsrPersistenceGenerationIsNewer(uint32_t left, |
|
|
|
return (((int32_t)(left - right)) > 0) ? 1U : 0U; |
|
|
|
} |
|
|
|
|
|
|
|
static volatile PLSR_SFD_FLASH_RECORD *PlsrPersistenceGetSfdSlot( |
|
|
|
uint8_t slot) |
|
|
|
{ |
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
return &PlsrHostSfdSlots[slot]; |
|
|
|
#else |
|
|
|
uint32_t address = (slot == 0U) ? PLSR_SFD_FLASH_SLOT_A_ADDRESS |
|
|
|
: PLSR_SFD_FLASH_SLOT_B_ADDRESS; |
|
|
|
return (volatile PLSR_SFD_FLASH_RECORD *)address; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static uint8_t PlsrPersistenceSfdRecordIsValid( |
|
|
|
const volatile PLSR_SFD_FLASH_RECORD *record) |
|
|
|
{ |
|
|
|
uint32_t expectedCrc; |
|
|
|
|
|
|
|
if ((record->magic != PLSR_SFD_FLASH_MAGIC) |
|
|
|
|| (record->version != PLSR_SFD_FLASH_VERSION) |
|
|
|
|| (record->payloadLength != sizeof(PLSR_SFD_DATA))) |
|
|
|
{ |
|
|
|
return 0U; |
|
|
|
} |
|
|
|
|
|
|
|
expectedCrc = PlsrPersistenceCrc32( |
|
|
|
(const volatile uint8_t *)record, |
|
|
|
(uint32_t)offsetof(PLSR_SFD_FLASH_RECORD, crc32)); |
|
|
|
|
|
|
|
return (expectedCrc == record->crc32) ? 1U : 0U; |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrPersistenceCopySfdFromVolatile( |
|
|
|
PLSR_SFD_DATA *destination, |
|
|
|
const volatile PLSR_SFD_DATA *source) |
|
|
|
{ |
|
|
|
uint16_t index; |
|
|
|
|
|
|
|
for (index = 0U; index < PLSR_SFD_CONFIG_COUNT; index++) |
|
|
|
{ |
|
|
|
destination->config[index] = source->config[index]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrPersistenceApplySfdDefaults(PLSR_SFD_DATA *data) |
|
|
|
{ |
|
|
|
uint16_t axisOffset; |
|
|
|
uint16_t parameterOffset; |
|
|
|
uint8_t axis; |
|
|
|
uint8_t parameterSet; |
|
|
|
|
|
|
|
(void)memset(data, 0, sizeof(*data)); |
|
|
|
for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) |
|
|
|
{ |
|
|
|
axisOffset = (uint16_t)((uint16_t)axis * PLSR_SFD_AXIS_STRIDE); |
|
|
|
|
|
|
|
/* Explicit Xinje defaults from the SFD parameter table. */ |
|
|
|
data->config[axisOffset + 7U] = 10; |
|
|
|
data->config[axisOffset + 27U] = 20; |
|
|
|
data->config[axisOffset + 43U] = 0x0201; |
|
|
|
|
|
|
|
for (parameterSet = 0U; |
|
|
|
parameterSet < PLSR_SFD_PARAMETER_SET_COUNT; |
|
|
|
parameterSet++) |
|
|
|
{ |
|
|
|
parameterOffset = (uint16_t)( |
|
|
|
axisOffset + PLSR_SFD_PARAMETER_SET_OFFSET |
|
|
|
+ (uint16_t)parameterSet * PLSR_SFD_PARAMETER_SET_STRIDE); |
|
|
|
data->config[parameterOffset + 6U] = |
|
|
|
(int32_t)(PLSR_SFD_DEFAULT_MAX_SPEED & 0xFFFFUL); |
|
|
|
data->config[parameterOffset + 7U] = |
|
|
|
(int32_t)(PLSR_SFD_DEFAULT_MAX_SPEED >> 16U); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static PLSR_PERSISTENCE_RESULT PlsrPersistenceBeginSfdOperation(void) |
|
|
|
{ |
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
return PLSR_PERSISTENCE_OK; |
|
|
|
#else |
|
|
|
if (HAL_FLASH_Unlock() != HAL_OK) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_PROGRAM_FAILED; |
|
|
|
} |
|
|
|
|
|
|
|
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR |
|
|
|
| FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
|
|
|
| FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); |
|
|
|
return PLSR_PERSISTENCE_OK; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static PLSR_PERSISTENCE_RESULT PlsrPersistenceEndSfdOperation( |
|
|
|
PLSR_PERSISTENCE_RESULT result) |
|
|
|
{ |
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
return result; |
|
|
|
#else |
|
|
|
if ((HAL_FLASH_Lock() != HAL_OK) && (result == PLSR_PERSISTENCE_OK)) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_PROGRAM_FAILED; |
|
|
|
} |
|
|
|
return result; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static PLSR_PERSISTENCE_RESULT PlsrPersistenceEraseSfdSlot(uint8_t slot) |
|
|
|
{ |
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
if (PlsrHostSfdFault == PLSR_TEST_SFD_FAULT_ERASE) |
|
|
|
{ |
|
|
|
PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; |
|
|
|
return PLSR_PERSISTENCE_ERASE_FAILED; |
|
|
|
} |
|
|
|
(void)memset(&PlsrHostSfdSlots[slot], |
|
|
|
0xFF, |
|
|
|
sizeof(PlsrHostSfdSlots[slot])); |
|
|
|
return PLSR_PERSISTENCE_OK; |
|
|
|
#else |
|
|
|
FLASH_EraseInitTypeDef erase; |
|
|
|
uint32_t sectorError = 0xFFFFFFFFUL; |
|
|
|
|
|
|
|
erase.TypeErase = FLASH_TYPEERASE_SECTORS; |
|
|
|
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; |
|
|
|
erase.Sector = (slot == 0U) ? FLASH_SECTOR_10 : FLASH_SECTOR_11; |
|
|
|
erase.NbSectors = 1U; |
|
|
|
|
|
|
|
return (HAL_FLASHEx_Erase(&erase, §orError) == HAL_OK) |
|
|
|
? PLSR_PERSISTENCE_OK |
|
|
|
: PLSR_PERSISTENCE_ERASE_FAILED; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static PLSR_PERSISTENCE_RESULT PlsrPersistenceProgramSfdWord( |
|
|
|
volatile uint32_t *destination, |
|
|
|
uint32_t value) |
|
|
|
{ |
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
if (PlsrHostSfdFault == PLSR_TEST_SFD_FAULT_PROGRAM) |
|
|
|
{ |
|
|
|
PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; |
|
|
|
return PLSR_PERSISTENCE_PROGRAM_FAILED; |
|
|
|
} |
|
|
|
if ((*destination & value) != value) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_PROGRAM_FAILED; |
|
|
|
} |
|
|
|
*destination &= value; |
|
|
|
return PLSR_PERSISTENCE_OK; |
|
|
|
#else |
|
|
|
return (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, |
|
|
|
(uint32_t)destination, |
|
|
|
value) |
|
|
|
== HAL_OK) |
|
|
|
? PLSR_PERSISTENCE_OK |
|
|
|
: PLSR_PERSISTENCE_PROGRAM_FAILED; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static uint8_t PlsrPersistenceSfdBodyMatches( |
|
|
|
const volatile uint32_t *destination, |
|
|
|
const PLSR_SFD_FLASH_HEADER *header, |
|
|
|
const PLSR_SFD_DATA *data, |
|
|
|
uint32_t crc32) |
|
|
|
{ |
|
|
|
const uint32_t *headerWords = (const uint32_t *)header; |
|
|
|
const uint32_t *dataWords = (const uint32_t *)data; |
|
|
|
uint32_t headerWordCount = (uint32_t)(sizeof(*header) / sizeof(uint32_t)); |
|
|
|
uint32_t dataWordCount = (uint32_t)(sizeof(*data) / sizeof(uint32_t)); |
|
|
|
uint32_t index; |
|
|
|
|
|
|
|
for (index = 1U; index < headerWordCount; index++) |
|
|
|
{ |
|
|
|
if (destination[index] != headerWords[index]) |
|
|
|
{ |
|
|
|
return 0U; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (index = 0U; index < dataWordCount; index++) |
|
|
|
{ |
|
|
|
if (destination[headerWordCount + index] != dataWords[index]) |
|
|
|
{ |
|
|
|
return 0U; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (destination[headerWordCount + dataWordCount] != crc32) |
|
|
|
{ |
|
|
|
return 0U; |
|
|
|
} |
|
|
|
return 1U; |
|
|
|
} |
|
|
|
|
|
|
|
static void PlsrPersistenceCopyHsdFromVolatile( |
|
|
|
PLSR_HSD_DATA *destination, |
|
|
|
const volatile PLSR_HSD_DATA *source) |
|
|
|
@@ -261,29 +493,247 @@ void PlsrPersistenceResetHsd(void) |
|
|
|
|
|
|
|
PLSR_PERSISTENCE_RESULT PlsrPersistenceLoadSfd(PLSR_SFD_DATA *data) |
|
|
|
{ |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotA; |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotB; |
|
|
|
const volatile PLSR_SFD_FLASH_RECORD *selected; |
|
|
|
uint32_t generationA; |
|
|
|
uint32_t generationB; |
|
|
|
uint8_t validA; |
|
|
|
uint8_t validB; |
|
|
|
|
|
|
|
if (data == NULL) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_INVALID_ARGUMENT; |
|
|
|
} |
|
|
|
|
|
|
|
(void)memset(data, 0, sizeof(*data)); |
|
|
|
return PLSR_PERSISTENCE_NOT_IMPLEMENTED; |
|
|
|
slotA = PlsrPersistenceGetSfdSlot(0U); |
|
|
|
slotB = PlsrPersistenceGetSfdSlot(1U); |
|
|
|
validA = PlsrPersistenceSfdRecordIsValid(slotA); |
|
|
|
validB = PlsrPersistenceSfdRecordIsValid(slotB); |
|
|
|
|
|
|
|
if ((validA == 0U) && (validB == 0U)) |
|
|
|
{ |
|
|
|
PlsrPersistenceApplySfdDefaults(data); |
|
|
|
return PLSR_PERSISTENCE_DEFAULTED; |
|
|
|
} |
|
|
|
|
|
|
|
if ((validA != 0U) && (validB != 0U)) |
|
|
|
{ |
|
|
|
generationA = slotA->generation; |
|
|
|
generationB = slotB->generation; |
|
|
|
selected = (PlsrPersistenceGenerationIsNewer(generationB, |
|
|
|
generationA) |
|
|
|
!= 0U) |
|
|
|
? slotB |
|
|
|
: slotA; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
selected = (validA != 0U) ? slotA : slotB; |
|
|
|
} |
|
|
|
|
|
|
|
PlsrPersistenceCopySfdFromVolatile(data, &selected->data); |
|
|
|
return PLSR_PERSISTENCE_OK; |
|
|
|
} |
|
|
|
|
|
|
|
PLSR_PERSISTENCE_RESULT PlsrPersistenceSaveSfd(const PLSR_SFD_DATA *data) |
|
|
|
{ |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotA; |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotB; |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *target; |
|
|
|
volatile uint32_t *targetWords; |
|
|
|
const uint32_t *headerWords; |
|
|
|
const uint32_t *dataWords; |
|
|
|
PLSR_SFD_FLASH_HEADER header; |
|
|
|
PLSR_PERSISTENCE_RESULT result; |
|
|
|
uint32_t newestGeneration = 0UL; |
|
|
|
uint32_t generationA; |
|
|
|
uint32_t generationB; |
|
|
|
uint32_t headerWordCount; |
|
|
|
uint32_t dataWordCount; |
|
|
|
uint32_t crcState; |
|
|
|
uint32_t crc32; |
|
|
|
uint32_t index; |
|
|
|
uint8_t targetSlot; |
|
|
|
uint8_t validA; |
|
|
|
uint8_t validB; |
|
|
|
|
|
|
|
if (data == NULL) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_INVALID_ARGUMENT; |
|
|
|
} |
|
|
|
if (sizeof(PLSR_SFD_FLASH_RECORD) > PLSR_SFD_FLASH_SECTOR_SIZE) |
|
|
|
{ |
|
|
|
return PLSR_PERSISTENCE_VERIFY_FAILED; |
|
|
|
} |
|
|
|
|
|
|
|
slotA = PlsrPersistenceGetSfdSlot(0U); |
|
|
|
slotB = PlsrPersistenceGetSfdSlot(1U); |
|
|
|
validA = PlsrPersistenceSfdRecordIsValid(slotA); |
|
|
|
validB = PlsrPersistenceSfdRecordIsValid(slotB); |
|
|
|
|
|
|
|
if ((validA != 0U) && (validB != 0U)) |
|
|
|
{ |
|
|
|
generationA = slotA->generation; |
|
|
|
generationB = slotB->generation; |
|
|
|
if (PlsrPersistenceGenerationIsNewer(generationB, |
|
|
|
generationA) |
|
|
|
!= 0U) |
|
|
|
{ |
|
|
|
newestGeneration = generationB; |
|
|
|
target = slotA; |
|
|
|
targetSlot = 0U; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
newestGeneration = generationA; |
|
|
|
target = slotB; |
|
|
|
targetSlot = 1U; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (validA != 0U) |
|
|
|
{ |
|
|
|
newestGeneration = slotA->generation; |
|
|
|
target = slotB; |
|
|
|
targetSlot = 1U; |
|
|
|
} |
|
|
|
else if (validB != 0U) |
|
|
|
{ |
|
|
|
newestGeneration = slotB->generation; |
|
|
|
target = slotA; |
|
|
|
targetSlot = 0U; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
target = slotA; |
|
|
|
targetSlot = 0U; |
|
|
|
} |
|
|
|
|
|
|
|
return PLSR_PERSISTENCE_NOT_IMPLEMENTED; |
|
|
|
header.magic = PLSR_SFD_FLASH_MAGIC; |
|
|
|
header.version = PLSR_SFD_FLASH_VERSION; |
|
|
|
header.payloadLength = (uint16_t)sizeof(PLSR_SFD_DATA); |
|
|
|
header.generation = newestGeneration + 1UL; |
|
|
|
crcState = PlsrPersistenceCrc32Update( |
|
|
|
0xFFFFFFFFUL, |
|
|
|
(const volatile uint8_t *)&header, |
|
|
|
(uint32_t)sizeof(header)); |
|
|
|
crcState = PlsrPersistenceCrc32Update( |
|
|
|
crcState, |
|
|
|
(const volatile uint8_t *)data, |
|
|
|
(uint32_t)sizeof(*data)); |
|
|
|
crc32 = ~crcState; |
|
|
|
|
|
|
|
headerWordCount = (uint32_t)(sizeof(header) / sizeof(uint32_t)); |
|
|
|
dataWordCount = (uint32_t)(sizeof(*data) / sizeof(uint32_t)); |
|
|
|
headerWords = (const uint32_t *)&header; |
|
|
|
dataWords = (const uint32_t *)data; |
|
|
|
targetWords = (volatile uint32_t *)target; |
|
|
|
|
|
|
|
result = PlsrPersistenceBeginSfdOperation(); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
result = PlsrPersistenceEraseSfdSlot(targetSlot); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
|
|
|
|
/* The valid magic is committed last so an interrupted write stays invalid. */ |
|
|
|
for (index = 1U; index < headerWordCount; index++) |
|
|
|
{ |
|
|
|
result = PlsrPersistenceProgramSfdWord(&targetWords[index], |
|
|
|
headerWords[index]); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (index = 0U; index < dataWordCount; index++) |
|
|
|
{ |
|
|
|
result = PlsrPersistenceProgramSfdWord( |
|
|
|
&targetWords[headerWordCount + index], |
|
|
|
dataWords[index]); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
result = PlsrPersistenceProgramSfdWord( |
|
|
|
&targetWords[headerWordCount + dataWordCount], |
|
|
|
crc32); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
if (PlsrHostSfdFault == PLSR_TEST_SFD_FAULT_VERIFY) |
|
|
|
{ |
|
|
|
targetWords[1] ^= 1UL; |
|
|
|
PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; |
|
|
|
} |
|
|
|
#endif |
|
|
|
if (PlsrPersistenceSfdBodyMatches(targetWords, |
|
|
|
&header, |
|
|
|
data, |
|
|
|
crc32) |
|
|
|
== 0U) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation( |
|
|
|
PLSR_PERSISTENCE_VERIFY_FAILED); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
if (PlsrHostSfdFault == PLSR_TEST_SFD_FAULT_BEFORE_COMMIT) |
|
|
|
{ |
|
|
|
PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; |
|
|
|
return PlsrPersistenceEndSfdOperation( |
|
|
|
PLSR_PERSISTENCE_PROGRAM_FAILED); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
result = PlsrPersistenceProgramSfdWord(&targetWords[0], headerWords[0]); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
|
|
|
|
result = (PlsrPersistenceSfdRecordIsValid(target) != 0U) |
|
|
|
? PLSR_PERSISTENCE_OK |
|
|
|
: PLSR_PERSISTENCE_VERIFY_FAILED; |
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
|
|
|
|
PLSR_PERSISTENCE_RESULT PlsrPersistenceEraseSfd(void) |
|
|
|
{ |
|
|
|
PLSR_PERSISTENCE_RESULT result; |
|
|
|
|
|
|
|
result = PlsrPersistenceBeginSfdOperation(); |
|
|
|
if (result != PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
result = PlsrPersistenceEraseSfdSlot(0U); |
|
|
|
if (result == PLSR_PERSISTENCE_OK) |
|
|
|
{ |
|
|
|
result = PlsrPersistenceEraseSfdSlot(1U); |
|
|
|
} |
|
|
|
|
|
|
|
return PlsrPersistenceEndSfdOperation(result); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef PLSR_HOST_TEST |
|
|
|
void PlsrPersistenceTestResetStorage(void) |
|
|
|
{ |
|
|
|
(void)memset(PlsrHostBackupSlots, 0, sizeof(PlsrHostBackupSlots)); |
|
|
|
(void)memset(PlsrHostSfdSlots, 0xFF, sizeof(PlsrHostSfdSlots)); |
|
|
|
PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; |
|
|
|
} |
|
|
|
|
|
|
|
void PlsrPersistenceTestCorruptNewestHsd(void) |
|
|
|
@@ -313,4 +763,37 @@ void PlsrPersistenceTestCorruptNewestHsd(void) |
|
|
|
|
|
|
|
newest->crc32 ^= 1UL; |
|
|
|
} |
|
|
|
|
|
|
|
void PlsrPersistenceTestCorruptNewestSfd(void) |
|
|
|
{ |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotA = PlsrPersistenceGetSfdSlot(0U); |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *slotB = PlsrPersistenceGetSfdSlot(1U); |
|
|
|
uint8_t validA = PlsrPersistenceSfdRecordIsValid(slotA); |
|
|
|
uint8_t validB = PlsrPersistenceSfdRecordIsValid(slotB); |
|
|
|
volatile PLSR_SFD_FLASH_RECORD *newest; |
|
|
|
|
|
|
|
if ((validA == 0U) && (validB == 0U)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
if ((validA != 0U) && (validB != 0U)) |
|
|
|
{ |
|
|
|
newest = (PlsrPersistenceGenerationIsNewer(slotB->generation, |
|
|
|
slotA->generation) |
|
|
|
!= 0U) |
|
|
|
? slotB |
|
|
|
: slotA; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
newest = (validA != 0U) ? slotA : slotB; |
|
|
|
} |
|
|
|
|
|
|
|
newest->crc32 ^= 1UL; |
|
|
|
} |
|
|
|
|
|
|
|
void PlsrPersistenceTestSetSfdFault(PLSR_TEST_SFD_FAULT fault) |
|
|
|
{ |
|
|
|
PlsrHostSfdFault = fault; |
|
|
|
} |
|
|
|
#endif |