405 lines
16 KiB
C
405 lines
16 KiB
C
/*
|
|
* Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
|
|
* All rights reserved.
|
|
*
|
|
* Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
|
|
* exclusively with CVA's microcontroller products. This file can be freely
|
|
* distributed within development tools that are supporting such microcontroller
|
|
* products.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
|
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
|
* CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
|
* OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* the includes
|
|
******************************************************************************/
|
|
#include <string.h>
|
|
#include "nvm_block.h"
|
|
|
|
/*******************************************************************************
|
|
* the defines
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* the typedefs
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* the globals
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* the static
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* the functions
|
|
******************************************************************************/
|
|
void Nvm_Block_DataRepair(const Nvm_BlockType *obj, const Nvm_MethodType *method, uint16_t blockIdx, uint16_t datasetIdx)
|
|
{
|
|
bool writeFlag = false;
|
|
uint8_t *mainBuff;
|
|
uint8_t *backupBuff;
|
|
uint8_t *tempBuff;
|
|
uint8_t *romBuff;
|
|
uint32_t copySize;
|
|
uint32_t dataSize;
|
|
|
|
/* Obtain necessary data for performing block data validity checks. */
|
|
mainBuff = NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, datasetIdx);
|
|
tempBuff = NVM_BLOCK_GET_TEMP_RAM_BUFF_PTR(obj, blockIdx);
|
|
romBuff = NVM_BLOCK_GET_ROM_BUFF_PTR(obj, blockIdx, datasetIdx);
|
|
copySize = Nvm_Block_CalcUseSize(obj, blockIdx);
|
|
dataSize = NVM_BLOCK_GET_DATASIZE(obj, blockIdx);
|
|
|
|
/* Check if the block is configured with verification function. */
|
|
if(NVM_BLOCK_IS_CRC(obj, blockIdx))
|
|
{
|
|
/* Check if the block type is redundant. */
|
|
if(NVM_BLOCK_IS_REDUNDANT(obj, blockIdx))
|
|
{
|
|
/* Perform data checks on the main area. */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, NVM_BLOCK_MAIN_IDX, method);
|
|
/* Check whether the data validation result of the main area is invalid. */
|
|
if(NVM_BLOCK_CRC_FAIL_MASK == NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, NVM_BLOCK_MAIN_IDX))
|
|
{
|
|
/* Obtain the backup data address of the redundant type block. */
|
|
backupBuff = NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, NVM_BLOCK_BACKUP_IDX);
|
|
/* Perform data checks on the backup area */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, NVM_BLOCK_BACKUP_IDX, method);
|
|
/* Check whether the data validation result of the backup area is valid. */
|
|
if(NVM_BLOCK_CRC_OK_MASK == NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, NVM_BLOCK_BACKUP_IDX))
|
|
{
|
|
/* Restore the data in the backup area to the main area. */
|
|
memcpy(tempBuff, backupBuff, copySize);
|
|
writeFlag = true;
|
|
}
|
|
else
|
|
{
|
|
/* Restore data from the ROM region to the main region. */
|
|
memcpy(tempBuff, romBuff, dataSize);
|
|
writeFlag = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Perform data checks on the main area. */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, datasetIdx, method);
|
|
/* Check whether the data validation result of the main area is invalid. */
|
|
if(NVM_BLOCK_CRC_OK_MASK != NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, datasetIdx))
|
|
{
|
|
/* Restore data from the ROM region to the main region. */
|
|
memcpy((void *)tempBuff, (void *)romBuff, dataSize);
|
|
writeFlag = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Initialize tempbuff. */
|
|
memset((void *)tempBuff, NVM_BLOCK_RAMBUFF_DEFAULT_VALUE, ALIGN8BYTE(copySize));
|
|
/* Check if the data in the main area is uninitialized. */
|
|
if (0 == memcmp((void *)mainBuff, (void *)tempBuff, ALIGN8BYTE(copySize)))
|
|
{
|
|
/* Check if the block type is redundant. */
|
|
if(NVM_BLOCK_IS_REDUNDANT(obj, blockIdx))
|
|
{
|
|
/* Obtain the backup data address of the redundant type block. */
|
|
backupBuff = NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, NVM_BLOCK_BACKUP_IDX);
|
|
|
|
/* Check if the data in the backup area is uninitialized. */
|
|
if (0 == memcmp((void *)backupBuff, tempBuff, ALIGN8BYTE(copySize)))
|
|
{
|
|
/* Restore data from ROM area to main and backup areas. */
|
|
memcpy(tempBuff, romBuff, dataSize);
|
|
writeFlag = true;
|
|
}
|
|
else
|
|
{
|
|
/* Restore the data in the backup area to the main area. */
|
|
memcpy(tempBuff, backupBuff, copySize);
|
|
writeFlag = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Restore data from ROM area to main and backup areas. */
|
|
memcpy(tempBuff, romBuff, dataSize);
|
|
writeFlag = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Restore data from main area to block all area data. */
|
|
memcpy(tempBuff, mainBuff, dataSize);
|
|
writeFlag = true;
|
|
}
|
|
}
|
|
|
|
if(writeFlag)
|
|
{
|
|
/* Perform data recovery. */
|
|
Nvm_Block_WriteDataToRamBlock(obj, method, blockIdx, datasetIdx, tempBuff);
|
|
}
|
|
}
|
|
|
|
void Nvm_Block_SetDefaultVal(const Nvm_BlockType *obj, const Nvm_MethodType *method, uint16_t blockIdx, uint16_t datasetIdx)
|
|
{
|
|
uint8_t *buff;
|
|
/* Initialize all data regions of the block with data from non rom regions. */
|
|
buff = NVM_BLOCK_GET_TEMP_RAM_BUFF_PTR(obj, blockIdx);
|
|
Nvm_Block_GetRomData(obj, blockIdx, datasetIdx, buff);
|
|
Nvm_Block_WriteDataToRamBlock(obj, method, blockIdx, datasetIdx, buff);
|
|
}
|
|
|
|
void Nvm_Block_ClrRamBuff(const Nvm_BlockType *obj, uint16_t blockIdx, uint16_t datasetIdx)
|
|
{
|
|
uint8_t *mainRamBuff;
|
|
uint32_t dataSize;
|
|
|
|
/* Initialize all initializable data regions of the dataset in the block. */
|
|
dataSize = ALIGN8BYTE(Nvm_Block_CalcUseSize(obj, blockIdx));
|
|
mainRamBuff = NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, datasetIdx);
|
|
|
|
memset((void *)mainRamBuff, NVM_BLOCK_RAMBUFF_DEFAULT_VALUE, dataSize);
|
|
}
|
|
|
|
void Nvm_Block_ClrBlockRamBuff(const Nvm_BlockType *obj, uint16_t blockIdx, uint16_t datasetIdx)
|
|
{
|
|
/* Initialize all initializable data regions of the block. */
|
|
if(NVM_BLOCK_IS_REDUNDANT(obj, blockIdx))
|
|
{
|
|
Nvm_Block_ClrRamBuff(obj, blockIdx, NVM_BLOCK_MAIN_IDX);
|
|
Nvm_Block_ClrRamBuff(obj, blockIdx, NVM_BLOCK_BACKUP_IDX);
|
|
}
|
|
else
|
|
{
|
|
Nvm_Block_ClrRamBuff(obj, blockIdx, datasetIdx);
|
|
}
|
|
}
|
|
|
|
void Nvm_Block_SetState(const Nvm_BlockType *obj, uint16_t blockIdx, uint16_t datasetIdx, Nvm_BlockState state)
|
|
{
|
|
/* Set the status of the dataset in the block. */
|
|
obj->items[blockIdx].info[datasetIdx].state = state;
|
|
}
|
|
|
|
void Nvm_Block_SetInternalState(const Nvm_BlockType *obj, uint16_t blockIdx, uint16_t datasetIdx, Nvm_BlockState state)
|
|
{
|
|
/* Set the internal processing status of the NVM for the dataset in the block. */
|
|
obj->items[blockIdx].info[datasetIdx].internalState = state;
|
|
}
|
|
|
|
void Nvm_Block_SetTempRamBuffDefaultVal(const Nvm_BlockType *obj, uint16_t blockIdx, uint16_t datasetIdx)
|
|
{
|
|
/* Initialize the tempbuff of the block. */
|
|
memset((void *)obj->items[blockIdx].tempRamBuffPtr, NVM_BLOCK_RAMBUFF_DEFAULT_VALUE, ALIGN8BYTE(Nvm_Block_CalcUseSize(obj, blockIdx)));
|
|
}
|
|
|
|
uint32_t Nvm_Block_CalcUseSize(const Nvm_BlockType *obj, uint16_t blockIdx)
|
|
{
|
|
uint32_t ret;
|
|
|
|
/* Check if the block is configured with crc verification. */
|
|
if(NVM_CRC8 == obj->items[blockIdx].crc)
|
|
{
|
|
/* Calculate the size used to store valid data in BLCOK. */
|
|
ret = obj->items[blockIdx].dataSize + NVM_BLOCK_PLACEHOLDER_BYTES + NVM_BLOCK_CRC_BYTES;
|
|
}
|
|
else
|
|
{
|
|
/* Calculate the size used to store valid data in BLCOK. */
|
|
ret = obj->items[blockIdx].dataSize + NVM_BLOCK_PLACEHOLDER_BYTES;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void Nvm_Block_GetRomData(const Nvm_BlockType *obj, uint16_t blockIdx, uint8_t datasetIdx, uint8_t *data)
|
|
{
|
|
uint8_t *romBuff;
|
|
|
|
/* Obtain data from the rom area of the dataset in the block. */
|
|
romBuff = NVM_BLOCK_GET_ROM_BUFF_PTR(obj, blockIdx, datasetIdx);
|
|
memcpy((void *)data, (void *)romBuff, NVM_BLOCK_GET_DATASIZE(obj, blockIdx));
|
|
}
|
|
|
|
bool Nvm_Block_GetWriteData(const Nvm_BlockType *obj, uint16_t blockIdx, uint8_t datasetIdx, const Nvm_MethodType *method, uint8_t *data)
|
|
{
|
|
bool ret = true;
|
|
uint8_t integrity;
|
|
|
|
|
|
/* Check if the block type is redundant. */
|
|
if(NVM_BLOCK_IS_REDUNDANT(obj, blockIdx))
|
|
{
|
|
/* Perform data checks on the main area. */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, NVM_BLOCK_MAIN_IDX, method);
|
|
/* Perform data checks on the main area. */
|
|
integrity = NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, NVM_BLOCK_MAIN_IDX);
|
|
/* Check whether the data validation result of the main area is invalid. */
|
|
if(NVM_BLOCK_CRC_OK_MASK == integrity)
|
|
{
|
|
/* Copy valid data */
|
|
memcpy((void *)data, (void *)NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, NVM_BLOCK_MAIN_IDX), NVM_BLOCK_GET_DATASIZE(obj, blockIdx));
|
|
}
|
|
else
|
|
{
|
|
/* Perform data checks on the backup area. */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, datasetIdx, method);
|
|
/* Perform data checks on the backup area. */
|
|
integrity = NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, NVM_BLOCK_BACKUP_IDX);
|
|
/* Check whether the data validation result of the backup area is invalid. */
|
|
if(NVM_BLOCK_CRC_OK_MASK == integrity)
|
|
{
|
|
/* Copy valid data. */
|
|
memcpy((void *)data, (void *)NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, NVM_BLOCK_BACKUP_IDX), NVM_BLOCK_GET_DATASIZE(obj, blockIdx));
|
|
}
|
|
else
|
|
{
|
|
ret = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Perform data checks on the dataset area. */
|
|
Nvm_Block_IntegrityCheck(obj, blockIdx, datasetIdx, method);
|
|
/* Perform data checks on the dataset area. */
|
|
integrity = NVM_BLOCK_GET_INTEGRITY(obj, blockIdx, datasetIdx);
|
|
/* Check whether the data validation result of the dataset area is invalid. */
|
|
if(NVM_BLOCK_CRC_OK_MASK == integrity)
|
|
{
|
|
/* Copy valid data. */
|
|
memcpy((void *)data, (void *)NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, datasetIdx), NVM_BLOCK_GET_DATASIZE(obj, blockIdx));
|
|
}
|
|
else
|
|
{
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void Nvm_Block_IntegrityCheck(const Nvm_BlockType *obj, uint16_t blockIdx, uint8_t datasetIdx, const Nvm_MethodType *method)
|
|
{
|
|
uint8_t crc;
|
|
uint32_t crcLen;
|
|
uint8_t *mainRamBuff;
|
|
|
|
/* Set the data validity flag bit of the dataset in the block to error */
|
|
obj->items[blockIdx].info[datasetIdx].integrity = NVM_BLOCK_CRC_FAIL_MASK;
|
|
|
|
/* Check if the block is configured with crc verification */
|
|
if(NVM_BLOCK_IS_CRC(obj, blockIdx))
|
|
{
|
|
/* The required data length, starting address, and parity bits for obtaining verification data */
|
|
crcLen = NVM_BLOCK_GET_CRC_LEN(obj, blockIdx);
|
|
mainRamBuff = obj->items[blockIdx].buff[datasetIdx].ramBuffPtr;
|
|
crc = method->crc8(mainRamBuff, crcLen);
|
|
/* Compare check bits */
|
|
if(crc == mainRamBuff[crcLen])
|
|
{
|
|
/* Verification passed, configure the data validity flag as successful */
|
|
obj->items[blockIdx].info[datasetIdx].integrity = NVM_BLOCK_CRC_OK_MASK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Verification passed, configure the data validity flag as successful */
|
|
obj->items[blockIdx].info[datasetIdx].integrity = NVM_BLOCK_CRC_OK_MASK;
|
|
}
|
|
}
|
|
|
|
void Nvm_Block_WriteDataToBuff(const Nvm_BlockType *obj, const Nvm_MethodType *method, uint16_t blockIdx, uint16_t datasetIdx, uint8_t *data)
|
|
{
|
|
uint8_t * buff;
|
|
uint32_t dataSize;
|
|
uint32_t crcLen;
|
|
|
|
/* Write data to the corresponding RAM area based on blockid and dataset */
|
|
buff = NVM_BLOCK_GET_RAM_BUFF_PTR(obj, blockIdx, datasetIdx);
|
|
dataSize = ALIGN8BYTE(Nvm_Block_CalcUseSize(obj, blockIdx));
|
|
|
|
memset((void *)buff, NVM_BLOCK_RAMBUFF_DEFAULT_VALUE, ALIGN8BYTE(Nvm_Block_CalcUseSize(obj, blockIdx)));
|
|
memcpy((void *)buff, (void *)data, dataSize);
|
|
|
|
if(NVM_BLOCK_IS_CRC(obj, blockIdx))
|
|
{
|
|
crcLen = NVM_BLOCK_GET_CRC_LEN(obj, blockIdx);
|
|
buff[crcLen] = method->crc8(buff, crcLen);
|
|
}
|
|
}
|
|
|
|
void Nvm_Block_WriteDataToRamBlock(const Nvm_BlockType *obj, const Nvm_MethodType *method, uint16_t blockIdx, uint16_t datasetIdx, uint8_t *data)
|
|
{
|
|
/* If the type of the block is redundant, the data will be written to the main and backup areas. */
|
|
/* Otherwise, the data will be written to the dataset area. */
|
|
if(NVM_BLOCK_IS_REDUNDANT(obj, blockIdx))
|
|
{
|
|
Nvm_Block_WriteDataToBuff(obj, method, blockIdx, NVM_BLOCK_MAIN_IDX, data);
|
|
Nvm_Block_WriteDataToBuff(obj, method, blockIdx, NVM_BLOCK_BACKUP_IDX, data);
|
|
}
|
|
else
|
|
{
|
|
Nvm_Block_WriteDataToBuff(obj, method, blockIdx, datasetIdx, data);
|
|
}
|
|
}
|
|
|
|
uint16_t Nvm_Block_Search(const Nvm_BlockType *obj, uint16_t blockNumber)
|
|
{
|
|
uint16_t retBlock = NVM_BLOCK_INVALID_IDX;
|
|
uint16_t blockStartIdx = 0;
|
|
uint16_t blockMiddleIdx = (obj->itemsNum - 1) / 2;
|
|
uint16_t blockEndIdx = obj->itemsNum - 1;
|
|
bool retFlag = false;
|
|
|
|
while(false == retFlag)
|
|
{
|
|
/* If the current block and the input block are the same */
|
|
if(blockNumber == obj->items[blockMiddleIdx].number)
|
|
{
|
|
/* Returns the index of the block */
|
|
retBlock = blockMiddleIdx;
|
|
retFlag = true;
|
|
}
|
|
else
|
|
{
|
|
/* Currently, there are only two or fewer blocks left that are not found, then check the other block */
|
|
if((blockEndIdx - blockStartIdx) <= 1)
|
|
{
|
|
retFlag = true;
|
|
if(blockNumber == obj->items[blockEndIdx].number)
|
|
{
|
|
retBlock = blockEndIdx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* In descending order, first determine whether it is in the right range, */
|
|
/* and then check whether it is in the left range */
|
|
if(obj->items[blockMiddleIdx].number < blockNumber)
|
|
{
|
|
blockStartIdx = blockMiddleIdx + 1;
|
|
}
|
|
else
|
|
{
|
|
blockEndIdx = blockMiddleIdx - 1;
|
|
}
|
|
|
|
/* Calculate Median */
|
|
blockMiddleIdx = blockEndIdx + blockStartIdx;
|
|
blockMiddleIdx /= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retBlock;
|
|
}
|