#include "plsr_persistence.h" #include "plsr_build_config.h" #include #include #define PLSR_HSD_BACKUP_MAGIC (0x504C4853UL) #define PLSR_HSD_BACKUP_VERSION (2U) #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) #define PLSR_SFD_DEFAULT_SPEED (1000UL) #define PLSR_SFD_DEFAULT_ACCEL_MS (100U) #define PLSR_SFD_DEFAULT_DECEL_MS (100U) #define PLSR_SFD_DEFAULT_FOLLOW (50U) #define PLSR_HSD_PARAMETER_SET_STRIDE (20U) #define PLSR_HSD_DEFAULT_BASE (460U) static const uint32_t PlsrPersistenceCrc32Nibble[16] = { 0x00000000UL, 0x1DB71064UL, 0x3B6E20C8UL, 0x26D930ACUL, 0x76DC4190UL, 0x6B6B51F4UL, 0x4DB26158UL, 0x5005713CUL, 0xEDB88320UL, 0xF00F9344UL, 0xD6D6A3E8UL, 0xCB61B38CUL, 0x9B64C2B0UL, 0x86D3D2D4UL, 0xA00AE278UL, 0xBDBDF21CUL }; typedef struct { uint32_t magic; uint16_t version; uint16_t payloadLength; uint32_t generation; PLSR_HSD_DATA data; 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; static uint32_t PlsrHostHsdSaveCount; #else #include "stm32f4xx.h" #include "stm32f4xx_hal.h" #include "stm32f4xx_hal_flash_ex.h" #endif static PLSR_PERSISTENCE_DIAGNOSTICS PlsrPersistenceDiagnostics; static uint8_t PlsrPersistenceDiagnosticsInitialized; static void PlsrPersistenceEnsureDiagnostics(void) { if (PlsrPersistenceDiagnosticsInitialized == 0U) { (void)memset(&PlsrPersistenceDiagnostics, 0, sizeof(PlsrPersistenceDiagnostics)); PlsrPersistenceDiagnostics.lastHsdLoadResult = PLSR_PERSISTENCE_NOT_IMPLEMENTED; PlsrPersistenceDiagnostics.lastSfdLoadResult = PLSR_PERSISTENCE_NOT_IMPLEMENTED; PlsrPersistenceDiagnostics.lastHsdSaveResult = PLSR_PERSISTENCE_NOT_IMPLEMENTED; PlsrPersistenceDiagnostics.lastSfdSaveResult = PLSR_PERSISTENCE_NOT_IMPLEMENTED; PlsrPersistenceDiagnostics.lastSfdEraseResult = PLSR_PERSISTENCE_NOT_IMPLEMENTED; #if PLSR_ENABLE_DESTRUCTIVE_PERSISTENCE_DIAG != 0U PlsrPersistenceDiagnostics.destructiveDiagnosticEnabled = 1U; #endif PlsrPersistenceDiagnosticsInitialized = 1U; } } static uint32_t PlsrPersistenceCrc32Update(uint32_t crc, const volatile uint8_t *data, uint32_t length) { uint32_t index; for (index = 0U; index < length; index++) { crc ^= data[index]; crc = (crc >> 4U) ^ PlsrPersistenceCrc32Nibble[crc & 0x0FUL]; crc = (crc >> 4U) ^ PlsrPersistenceCrc32Nibble[crc & 0x0FUL]; } 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( uint8_t slot) { #ifdef PLSR_HOST_TEST return &PlsrHostBackupSlots[slot]; #else uint32_t offset = PLSR_BACKUP_SLOT_A_OFFSET + (uint32_t)slot * PLSR_BACKUP_SLOT_STRIDE; return (volatile PLSR_HSD_BACKUP_RECORD *)(BKPSRAM_BASE + offset); #endif } static uint8_t PlsrPersistenceHsdRecordIsValid( const volatile PLSR_HSD_BACKUP_RECORD *record) { uint32_t expectedCrc; if ((record->magic != PLSR_HSD_BACKUP_MAGIC) || (record->version != PLSR_HSD_BACKUP_VERSION) || (record->payloadLength != sizeof(PLSR_HSD_DATA))) { return 0U; } expectedCrc = PlsrPersistenceCrc32( (const volatile uint8_t *)record, (uint32_t)offsetof(PLSR_HSD_BACKUP_RECORD, crc32)); return (expectedCrc == record->crc32) ? 1U : 0U; } static uint8_t PlsrPersistenceGenerationIsNewer(uint32_t left, uint32_t right) { 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 uint8_t PlsrPersistenceNewestMask(uint8_t validA, uint8_t validB, uint32_t generationA, uint32_t generationB) { if ((validA != 0U) && (validB != 0U)) { return (PlsrPersistenceGenerationIsNewer(generationB, generationA) != 0U) ? 2U : 1U; } if (validA != 0U) { return 1U; } return (validB != 0U) ? 2U : 0U; } static void PlsrPersistenceUpdateHsdDiagnostics( const volatile PLSR_HSD_BACKUP_RECORD *slotA, const volatile PLSR_HSD_BACKUP_RECORD *slotB, uint8_t validA, uint8_t validB) { uint8_t newestMask; PlsrPersistenceEnsureDiagnostics(); PlsrPersistenceDiagnostics.hsdValidMask = (uint8_t)((validA != 0U ? 1U : 0U) | (validB != 0U ? 2U : 0U)); PlsrPersistenceDiagnostics.hsdGeneration[0] = (validA != 0U) ? slotA->generation : 0UL; PlsrPersistenceDiagnostics.hsdGeneration[1] = (validB != 0U) ? slotB->generation : 0UL; newestMask = PlsrPersistenceNewestMask( validA, validB, PlsrPersistenceDiagnostics.hsdGeneration[0], PlsrPersistenceDiagnostics.hsdGeneration[1]); PlsrPersistenceDiagnostics.hsdNewestMask = newestMask; PlsrPersistenceDiagnostics.selectedHsdCrc32 = (newestMask == 1U) ? slotA->crc32 : (newestMask == 2U) ? slotB->crc32 : 0UL; } static void PlsrPersistenceUpdateSfdDiagnostics( const volatile PLSR_SFD_FLASH_RECORD *slotA, const volatile PLSR_SFD_FLASH_RECORD *slotB, uint8_t validA, uint8_t validB) { uint8_t newestMask; PlsrPersistenceEnsureDiagnostics(); PlsrPersistenceDiagnostics.sfdValidMask = (uint8_t)((validA != 0U ? 1U : 0U) | (validB != 0U ? 2U : 0U)); PlsrPersistenceDiagnostics.sfdGeneration[0] = (validA != 0U) ? slotA->generation : 0UL; PlsrPersistenceDiagnostics.sfdGeneration[1] = (validB != 0U) ? slotB->generation : 0UL; newestMask = PlsrPersistenceNewestMask( validA, validB, PlsrPersistenceDiagnostics.sfdGeneration[0], PlsrPersistenceDiagnostics.sfdGeneration[1]); PlsrPersistenceDiagnostics.sfdNewestMask = newestMask; PlsrPersistenceDiagnostics.selectedSfdCrc32 = (newestMask == 1U) ? slotA->crc32 : (newestMask == 2U) ? slotB->crc32 : 0UL; } static void PlsrPersistenceRefreshSfdDiagnostics(void) { volatile PLSR_SFD_FLASH_RECORD *slotA = PlsrPersistenceGetSfdSlot(0U); volatile PLSR_SFD_FLASH_RECORD *slotB = PlsrPersistenceGetSfdSlot(1U); PlsrPersistenceUpdateSfdDiagnostics( slotA, slotB, PlsrPersistenceSfdRecordIsValid(slotA), PlsrPersistenceSfdRecordIsValid(slotB)); } static PLSR_PERSISTENCE_RESULT PlsrPersistenceCompleteSfdSave( PLSR_PERSISTENCE_RESULT result) { PlsrPersistenceEnsureDiagnostics(); PlsrPersistenceDiagnostics.lastSfdSaveResult = result; PlsrPersistenceRefreshSfdDiagnostics(); if (result == PLSR_PERSISTENCE_OK) { PlsrPersistenceDiagnostics.sfdSaveCount++; } return result; } 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 PlsrPersistenceApplyParameterSetDefaults(uint16_t *config, uint16_t base) { /* 与信捷出厂默认一致:默认速度1000、加减速100ms、最大速度100000、 * 起始/终止速度0、FOLLOW 50、前馈0、1ms刷新。 */ config[base + 0U] = (uint16_t)(PLSR_SFD_DEFAULT_SPEED & 0xFFFFUL); config[base + 1U] = (uint16_t)(PLSR_SFD_DEFAULT_SPEED >> 16U); config[base + 2U] = (uint16_t)PLSR_SFD_DEFAULT_ACCEL_MS; config[base + 3U] = (uint16_t)PLSR_SFD_DEFAULT_DECEL_MS; config[base + 4U] = 0U; config[base + 5U] = 0U; config[base + 6U] = (uint16_t)(PLSR_SFD_DEFAULT_MAX_SPEED & 0xFFFFUL); config[base + 7U] = (uint16_t)(PLSR_SFD_DEFAULT_MAX_SPEED >> 16U); config[base + 8U] = 0U; config[base + 9U] = 0U; config[base + 10U] = 0U; config[base + 11U] = 0U; config[base + 12U] = (uint16_t)PLSR_SFD_DEFAULT_FOLLOW; config[base + 13U] = 0U; config[base + 14U] = 0U; config[base + 16U] = 0U; config[base + 17U] = 0U; config[base + 18U] = 0U; config[base + 19U] = 0U; } 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); /* 公共参数(与信捷出厂默认一致)。 */ data->config[axisOffset + 0U] = 0; /* SFD900 方向逻辑/单位等 */ data->config[axisOffset + 1U] = 0; /* SFD901 完成模式 */ data->config[axisOffset + 2U] = 1; /* SFD902 脉冲数/1转=1 */ data->config[axisOffset + 3U] = 0; data->config[axisOffset + 4U] = 1; /* SFD904 移动量/1转=1 */ data->config[axisOffset + 5U] = 0; data->config[axisOffset + 6U] = 0xFF; /* SFD906 方向端子:无 */ data->config[axisOffset + 7U] = 10; /* SFD907 方向延时10ms */ data->config[axisOffset + 8U] = 0; /* SFD908 正向齿隙 */ data->config[axisOffset + 9U] = 0; /* SFD909 负向齿隙 */ data->config[axisOffset + 12U] = 0; /* SFD912 端子开关状态 */ data->config[axisOffset + 13U] = 0xFF; /* SFD913 原点端子:无 */ data->config[axisOffset + 14U] = 0xFF; /* SFD914 Z相端子:无 */ data->config[axisOffset + 15U] = 0xFFFF; /* SFD915 极限端子:无 */ data->config[axisOffset + 17U] = 0xFF; /* SFD917 CLR端子:无 */ data->config[axisOffset + 18U] = 0; /* SFD918 VH */ data->config[axisOffset + 19U] = 0; data->config[axisOffset + 22U] = 0; /* SFD922 VC */ data->config[axisOffset + 23U] = 0; data->config[axisOffset + 24U] = 0; /* SFD924 机械原点位置 */ data->config[axisOffset + 25U] = 0; data->config[axisOffset + 26U] = 0; /* SFD926 Z相个数 */ data->config[axisOffset + 27U] = 20; /* SFD927 CLR延时20ms */ data->config[axisOffset + 30U] = 0; /* SFD930 软限位正 */ data->config[axisOffset + 31U] = 0; data->config[axisOffset + 32U] = 0; /* SFD932 软限位负 */ data->config[axisOffset + 33U] = 0; data->config[axisOffset + 43U] = 0x0201; /* SFD943 默认参数块 */ 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); PlsrPersistenceApplyParameterSetDefaults(data->config, parameterOffset); } } } static void PlsrPersistenceApplyHsdDefaults(PLSR_HSD_DATA *data) { uint8_t axis; (void)memset(data, 0, sizeof(*data)); for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { /* config 数组索引 = HSD地址 - PLSR_HSD_CONFIG_START。 */ PlsrPersistenceApplyParameterSetDefaults( data->config, (uint16_t)((uint16_t)axis * PLSR_HSD_PARAMETER_SET_STRIDE)); } } 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) { uint16_t index; destination->metadata = source->metadata; for (index = 0U; index < PLSR_HSD_RUNTIME_COUNT; index++) { destination->runtime[index] = source->runtime[index]; } for (index = 0U; index < PLSR_HSD_CONFIG_COUNT; index++) { destination->config[index] = source->config[index]; } } static void PlsrPersistenceWriteRecord( volatile PLSR_HSD_BACKUP_RECORD *destination, const PLSR_HSD_BACKUP_RECORD *source) { const uint32_t *sourceWords = (const uint32_t *)source; volatile uint32_t *destinationWords = (volatile uint32_t *)destination; uint32_t wordCount = (uint32_t)(sizeof(PLSR_HSD_BACKUP_RECORD) / sizeof(uint32_t)); uint32_t index; destination->magic = 0UL; #ifndef PLSR_HOST_TEST __DMB(); #endif for (index = 1U; index < wordCount; index++) { destinationWords[index] = sourceWords[index]; } #ifndef PLSR_HOST_TEST __DMB(); #endif destination->magic = PLSR_HSD_BACKUP_MAGIC; #ifndef PLSR_HOST_TEST __DMB(); #endif } PLSR_PERSISTENCE_RESULT PlsrPersistenceLoadHsd(PLSR_HSD_DATA *data) { volatile PLSR_HSD_BACKUP_RECORD *slotA; volatile PLSR_HSD_BACKUP_RECORD *slotB; const volatile PLSR_HSD_BACKUP_RECORD *selected; uint32_t generationA; uint32_t generationB; uint8_t validA; uint8_t validB; PlsrPersistenceEnsureDiagnostics(); if (data == NULL) { PlsrPersistenceDiagnostics.lastHsdLoadResult = PLSR_PERSISTENCE_INVALID_ARGUMENT; return PLSR_PERSISTENCE_INVALID_ARGUMENT; } slotA = PlsrPersistenceGetHsdSlot(0U); slotB = PlsrPersistenceGetHsdSlot(1U); validA = PlsrPersistenceHsdRecordIsValid(slotA); validB = PlsrPersistenceHsdRecordIsValid(slotB); PlsrPersistenceUpdateHsdDiagnostics(slotA, slotB, validA, validB); if ((validA == 0U) && (validB == 0U)) { PlsrPersistenceApplyHsdDefaults(data); PlsrPersistenceDiagnostics.lastHsdLoadResult = PLSR_PERSISTENCE_DEFAULTED; 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; } PlsrPersistenceCopyHsdFromVolatile(data, &selected->data); PlsrPersistenceDiagnostics.lastHsdLoadResult = PLSR_PERSISTENCE_OK; return PLSR_PERSISTENCE_OK; } PLSR_PERSISTENCE_RESULT PlsrPersistenceSaveHsd(const PLSR_HSD_DATA *data) { volatile PLSR_HSD_BACKUP_RECORD *slotA; volatile PLSR_HSD_BACKUP_RECORD *slotB; volatile PLSR_HSD_BACKUP_RECORD *target; PLSR_HSD_BACKUP_RECORD record; uint32_t newestGeneration = 0UL; uint32_t generationA; uint32_t generationB; uint8_t validA; uint8_t validB; uint8_t targetSlot; uint8_t targetValid; PlsrPersistenceEnsureDiagnostics(); if (data == NULL) { PlsrPersistenceDiagnostics.lastHsdSaveResult = PLSR_PERSISTENCE_INVALID_ARGUMENT; return PLSR_PERSISTENCE_INVALID_ARGUMENT; } #ifdef PLSR_HOST_TEST PlsrHostHsdSaveCount++; #endif if (sizeof(PLSR_HSD_BACKUP_RECORD) > PLSR_BACKUP_SLOT_STRIDE) { PlsrPersistenceDiagnostics.lastHsdSaveResult = PLSR_PERSISTENCE_VERIFY_FAILED; return PLSR_PERSISTENCE_VERIFY_FAILED; } slotA = PlsrPersistenceGetHsdSlot(0U); slotB = PlsrPersistenceGetHsdSlot(1U); validA = PlsrPersistenceHsdRecordIsValid(slotA); validB = PlsrPersistenceHsdRecordIsValid(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; } (void)memset(&record, 0, sizeof(record)); record.magic = PLSR_HSD_BACKUP_MAGIC; record.version = PLSR_HSD_BACKUP_VERSION; record.payloadLength = (uint16_t)sizeof(PLSR_HSD_DATA); record.generation = newestGeneration + 1UL; record.data = *data; record.crc32 = PlsrPersistenceCrc32( (const volatile uint8_t *)&record, (uint32_t)offsetof(PLSR_HSD_BACKUP_RECORD, crc32)); PlsrPersistenceWriteRecord(target, &record); targetValid = PlsrPersistenceHsdRecordIsValid(target); if (targetSlot == 0U) { validA = targetValid; } else { validB = targetValid; } PlsrPersistenceUpdateHsdDiagnostics(slotA, slotB, validA, validB); PlsrPersistenceDiagnostics.lastHsdSaveResult = (targetValid != 0U) ? PLSR_PERSISTENCE_OK : PLSR_PERSISTENCE_VERIFY_FAILED; if (targetValid != 0U) { PlsrPersistenceDiagnostics.hsdSaveCount++; } return PlsrPersistenceDiagnostics.lastHsdSaveResult; } void PlsrPersistenceResetHsd(void) { volatile PLSR_HSD_BACKUP_RECORD *slotA = PlsrPersistenceGetHsdSlot(0U); volatile PLSR_HSD_BACKUP_RECORD *slotB = PlsrPersistenceGetHsdSlot(1U); slotA->magic = 0UL; slotB->magic = 0UL; #ifndef PLSR_HOST_TEST __DMB(); #endif PlsrPersistenceUpdateHsdDiagnostics(slotA, slotB, 0U, 0U); } 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; PlsrPersistenceEnsureDiagnostics(); if (data == NULL) { PlsrPersistenceDiagnostics.lastSfdLoadResult = PLSR_PERSISTENCE_INVALID_ARGUMENT; return PLSR_PERSISTENCE_INVALID_ARGUMENT; } slotA = PlsrPersistenceGetSfdSlot(0U); slotB = PlsrPersistenceGetSfdSlot(1U); validA = PlsrPersistenceSfdRecordIsValid(slotA); validB = PlsrPersistenceSfdRecordIsValid(slotB); PlsrPersistenceUpdateSfdDiagnostics(slotA, slotB, validA, validB); if ((validA == 0U) && (validB == 0U)) { PlsrPersistenceApplySfdDefaults(data); PlsrPersistenceDiagnostics.lastSfdLoadResult = PLSR_PERSISTENCE_DEFAULTED; 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); PlsrPersistenceDiagnostics.lastSfdLoadResult = PLSR_PERSISTENCE_OK; 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; PlsrPersistenceEnsureDiagnostics(); if (data == NULL) { PlsrPersistenceDiagnostics.lastSfdSaveResult = PLSR_PERSISTENCE_INVALID_ARGUMENT; return PLSR_PERSISTENCE_INVALID_ARGUMENT; } if (sizeof(PLSR_SFD_FLASH_RECORD) > PLSR_SFD_FLASH_SECTOR_SIZE) { PlsrPersistenceDiagnostics.lastSfdSaveResult = PLSR_PERSISTENCE_VERIFY_FAILED; 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; } 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 PlsrPersistenceCompleteSfdSave(result); } result = PlsrPersistenceEraseSfdSlot(targetSlot); if (result != PLSR_PERSISTENCE_OK) { result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(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) { result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(result); } } for (index = 0U; index < dataWordCount; index++) { result = PlsrPersistenceProgramSfdWord( &targetWords[headerWordCount + index], dataWords[index]); if (result != PLSR_PERSISTENCE_OK) { result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(result); } } result = PlsrPersistenceProgramSfdWord( &targetWords[headerWordCount + dataWordCount], crc32); if (result != PLSR_PERSISTENCE_OK) { result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(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) { result = PlsrPersistenceEndSfdOperation( PLSR_PERSISTENCE_VERIFY_FAILED); return PlsrPersistenceCompleteSfdSave(result); } #ifdef PLSR_HOST_TEST if (PlsrHostSfdFault == PLSR_TEST_SFD_FAULT_BEFORE_COMMIT) { PlsrHostSfdFault = PLSR_TEST_SFD_FAULT_NONE; result = PlsrPersistenceEndSfdOperation( PLSR_PERSISTENCE_PROGRAM_FAILED); return PlsrPersistenceCompleteSfdSave(result); } #endif result = PlsrPersistenceProgramSfdWord(&targetWords[0], headerWords[0]); if (result != PLSR_PERSISTENCE_OK) { result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(result); } result = (PlsrPersistenceSfdRecordIsValid(target) != 0U) ? PLSR_PERSISTENCE_OK : PLSR_PERSISTENCE_VERIFY_FAILED; result = PlsrPersistenceEndSfdOperation(result); return PlsrPersistenceCompleteSfdSave(result); } PLSR_PERSISTENCE_RESULT PlsrPersistenceEraseSfd(void) { PLSR_PERSISTENCE_RESULT result; PlsrPersistenceEnsureDiagnostics(); result = PlsrPersistenceBeginSfdOperation(); if (result != PLSR_PERSISTENCE_OK) { PlsrPersistenceDiagnostics.lastSfdEraseResult = result; return result; } result = PlsrPersistenceEraseSfdSlot(0U); if (result == PLSR_PERSISTENCE_OK) { result = PlsrPersistenceEraseSfdSlot(1U); } result = PlsrPersistenceEndSfdOperation(result); PlsrPersistenceDiagnostics.lastSfdEraseResult = result; PlsrPersistenceRefreshSfdDiagnostics(); return result; } void PlsrPersistenceGetDiagnostics( PLSR_PERSISTENCE_DIAGNOSTICS *diagnostics) { if (diagnostics == NULL) { return; } PlsrPersistenceEnsureDiagnostics(); *diagnostics = PlsrPersistenceDiagnostics; } PLSR_PERSISTENCE_RESULT PlsrPersistenceDiagnosticInvalidateNewest( PLSR_PERSISTENCE_DIAG_TARGET target) { #if PLSR_ENABLE_DESTRUCTIVE_PERSISTENCE_DIAG != 0U uint32_t generationA; uint32_t generationB; uint8_t validA; uint8_t validB; PlsrPersistenceEnsureDiagnostics(); if (target == PLSR_PERSISTENCE_DIAG_TARGET_HSD) { volatile PLSR_HSD_BACKUP_RECORD *slotA = PlsrPersistenceGetHsdSlot(0U); volatile PLSR_HSD_BACKUP_RECORD *slotB = PlsrPersistenceGetHsdSlot(1U); volatile PLSR_HSD_BACKUP_RECORD *newest; validA = PlsrPersistenceHsdRecordIsValid(slotA); validB = PlsrPersistenceHsdRecordIsValid(slotB); PlsrPersistenceUpdateHsdDiagnostics(slotA, slotB, validA, validB); if ((validA == 0U) || (validB == 0U)) { return PLSR_PERSISTENCE_VERIFY_FAILED; } generationA = slotA->generation; generationB = slotB->generation; newest = (PlsrPersistenceGenerationIsNewer(generationB, generationA) != 0U) ? slotB : slotA; newest->magic = 0UL; #ifndef PLSR_HOST_TEST __DMB(); #endif PlsrPersistenceUpdateHsdDiagnostics( slotA, slotB, (newest == slotA) ? 0U : 1U, (newest == slotB) ? 0U : 1U); return PLSR_PERSISTENCE_OK; } if (target == PLSR_PERSISTENCE_DIAG_TARGET_SFD) { volatile PLSR_SFD_FLASH_RECORD *slotA = PlsrPersistenceGetSfdSlot(0U); volatile PLSR_SFD_FLASH_RECORD *slotB = PlsrPersistenceGetSfdSlot(1U); volatile PLSR_SFD_FLASH_RECORD *newest; PLSR_PERSISTENCE_RESULT result; validA = PlsrPersistenceSfdRecordIsValid(slotA); validB = PlsrPersistenceSfdRecordIsValid(slotB); PlsrPersistenceUpdateSfdDiagnostics(slotA, slotB, validA, validB); if ((validA == 0U) || (validB == 0U)) { return PLSR_PERSISTENCE_VERIFY_FAILED; } generationA = slotA->generation; generationB = slotB->generation; newest = (PlsrPersistenceGenerationIsNewer(generationB, generationA) != 0U) ? slotB : slotA; result = PlsrPersistenceBeginSfdOperation(); if (result == PLSR_PERSISTENCE_OK) { result = PlsrPersistenceProgramSfdWord( (volatile uint32_t *)&newest->magic, 0UL); result = PlsrPersistenceEndSfdOperation(result); } PlsrPersistenceRefreshSfdDiagnostics(); return result; } return PLSR_PERSISTENCE_INVALID_ARGUMENT; #else (void)target; return PLSR_PERSISTENCE_NOT_IMPLEMENTED; #endif } #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; PlsrHostHsdSaveCount = 0UL; PlsrPersistenceDiagnosticsInitialized = 0U; PlsrPersistenceEnsureDiagnostics(); PlsrPersistenceUpdateHsdDiagnostics( PlsrPersistenceGetHsdSlot(0U), PlsrPersistenceGetHsdSlot(1U), 0U, 0U); PlsrPersistenceRefreshSfdDiagnostics(); } uint32_t PlsrPersistenceTestGetHsdSaveCount(void) { return PlsrHostHsdSaveCount; } uint32_t PlsrPersistenceTestCrc32(const uint8_t *data, uint32_t length) { if ((data == NULL) && (length != 0UL)) { return 0UL; } return PlsrPersistenceCrc32(data, length); } void PlsrPersistenceTestCorruptNewestHsd(void) { volatile PLSR_HSD_BACKUP_RECORD *slotA = PlsrPersistenceGetHsdSlot(0U); volatile PLSR_HSD_BACKUP_RECORD *slotB = PlsrPersistenceGetHsdSlot(1U); uint8_t validA = PlsrPersistenceHsdRecordIsValid(slotA); uint8_t validB = PlsrPersistenceHsdRecordIsValid(slotB); volatile PLSR_HSD_BACKUP_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 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