/************************************************************************** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file NVDataMgmt.c * * @date 11-FEB-2020 * @author D. Navaei * * @brief NVDataMgmt source file * **************************************************************************/ // Includes #include "F021.h" #include "NVDataMgmt.h" #include "RTC.h" #include "Utilities.h" #include "system.h" // Private defines #define MAX_QUEUE_SIZE 10U #define QUEUE_FRONT_INDEX 0U #define ROUNDED_HCLK_FREQ FLOAT_TO_INT_WITH_ROUND(HCLK_FREQ) #define BANK7_SECTOR_0_31_ENABLE_BIT_MASK 0x0000000F #define BANK7_SECTOR_32_63_ENABLE_BIT_MASK 0x00000000 #define BANK7_SECTOR0_START_ADDRESS 0xF0200000 #define BANK7_SECTOR0_END_ADDRESS 0xF0203FFF #define BANK7_SECTOR1_START_ADDRESS 0xF0204000 #define BANK7_SECTOR1_END_ADDRESS 0xF0207FFF #define BANK7_SECTOR2_START_ADDRESS 0xF0208000 #define BANK7_SECTOR2_END_ADDRESS 0xF020BFFF #define BANK7_SECTOR3_START_ADDRESS 0xF020FFFF #define BANK7_SECTOR3_END_ADDRESS 0xF020C000 // RTC RAM defines #define BOOTLOADER_FLAG_START_ADDRESS 0x0000 #define BOOTLOADER_FLAG_LENGTH_BYTES 4U // Address 20 in the RTC RAM #define LOG_RECORDS_START_ADDRESS 0x0014 #define LOG_RECORDS_LENGTH_BYTES 6U #define READ_BUFFER_SIZE 64U #define BUFFER_INDEX_0 0U #define BUFFER_INDEX_1 1U #define BUFFER_INDEX_2 2U #define BUFFER_INDEX_3 3U #define BUFFER_INDEX_4 4U #define BUFFER_INDEX_5 5U #define MAX_SYS_SERIAL_NUMBER_CHARACTERS 7U #define MAX_HW_SERIAL_NUMBER_CHARACTERS 5U #define MAX_MFG_DATE_CHARACTERS 10U #define MAX_CRC_LENGTH_BYTES 2U typedef enum NVDataMgmt_Self_Test_States { NVDATAMGMT_SELF_TEST_STATE_START = 0, NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG, NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD, NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORDS, NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC, NVDATAMGMT_SELF_TEST_STATE_COMPLETE, NUM_OF_NVDATAMGMT_SELF_TEST_STATES } NVDATAMGMT_SELF_TEST_STATE_T; typedef enum NVDataMgmt_Exec_State { NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST = 0, NVDATAMGMT_EXEC_STATE_IDLE, NVDATAMGMT_EXEC_STATE_WRITE, NVDATAMGMT_EXEC_STATE_READ, NVDATAMGMT_EXEC_STATE_ERASE, NVDATAMGMT_EXEC_STATE_FAULT, NUM_OF_NVDATAMGMT_EXEC_STATES } NVDATAMGMT_EXEC_STATE_T; typedef enum NVDataMgmt_Operation { NVDATAMGMT_WRITE = 0, NVDATAMGMT_READ, NVDATAMGMT_ERASE } NVDATAMGMT_OPERATION_STATE_T; typedef enum NVDataMgmt_Location { NVDATAMGMT_EEPROM = 0, NVDATAMGMT_RTC } NVDATAMGMT_LOCATION_STATE_T; // Private functions static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestStart( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadMfgRecord( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadBootloaderFlag( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadLogRecord( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC( void ); static NVDATAMGMT_EXEC_STATE_T handleExecWaitForPostState( void ); static NVDATAMGMT_EXEC_STATE_T handleExecIdleState( void ); static NVDATAMGMT_EXEC_STATE_T handleExecWriteState( void ); static NVDATAMGMT_EXEC_STATE_T handleExecReadState( void ); // Queue functions static void enqueue( void ); static void dequeue( void ); static BOOL isQueueEmpty ( void ); static U08 getQueueSize( void ); // Private variables #pragma pack(push,1) struct MEMORY_OPS_T { NVDATAMGMT_OPERATION_STATE_T memoryOperation; NVDATAMGMT_LOCATION_STATE_T memoryLocation; U32* startAddress; U08* buffer; U32 length; }; typedef struct { U16 recordsCount; U16 nextWriteIndex; U16 nextReadIndex; } LOG_RECORD_T; typedef struct mfg_Data { char SYSSerialNumber [ MAX_SYS_SERIAL_NUMBER_CHARACTERS ]; char HWSerialNumber [ MAX_HW_SERIAL_NUMBER_CHARACTERS ]; char mfgDate [ MAX_MFG_DATE_CHARACTERS ]; } MFG_DATA_T; typedef struct { MFG_DATA_T mfgData; U16 crc; } MFG_RECORD_T; #pragma pack(pop) struct MEMORY_OPS_T jobQueue[ MAX_QUEUE_SIZE ]; static S16 queueRearIndex = -1; static LOG_RECORD_T logRecord; static MFG_RECORD_T mfgRecord; static Fapi_StatusType EEPROMStatus = Fapi_Status_Success; static NVDATAMGMT_SELF_TEST_STATE_T NVDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_START; static NVDATAMGMT_EXEC_STATE_T NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; static SELF_TEST_STATUS_T NVDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; static BOOL isServiceOnEntry = TRUE; static U32 bootloaderFlag = 0; static U08 readBuffer[ READ_BUFFER_SIZE ]; // REMOVE THIS CODE static U08 tempBufferForTest[5] = {'A', 0x2, 0x45, 'X', 0x78}; // REMOVE THIS CODE /************************************************************************* * @brief initNVDataMgmt * The initNVDataMgmt initializes EEPROM * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ void initNVDataMgmt( void ) { // TODO: initialize all the necessary variables NVDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_START; EEPROMStatus = Fapi_Status_Success; NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; NVDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; isServiceOnEntry = TRUE; queueRearIndex = -1; EEPROMStatus = Fapi_initializeFlashBanks( ROUNDED_HCLK_FREQ ); EEPROMStatus = Fapi_setActiveFlashBank( Fapi_FlashBank7 ); } /************************************************************************* * @brief handleSelfTestStart * The handleSelfTestStart enables the EEPROM bank sectors * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestStart( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_START; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_enableEepromBankSectors( BANK7_SECTOR_0_31_ENABLE_BIT_MASK, BANK7_SECTOR_32_63_ENABLE_BIT_MASK ); isServiceOnEntry = FALSE; } else if ( EEPROMStatus == Fapi_Status_Success ) { state = NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG; isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleSelfTestReadBootloaderFlag * The handleSelfTestReadBootloaderFlag reads the bootloader flag * from RTC RAM * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadBootloaderFlag( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG; if ( isServiceOnEntry && getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM( BOOTLOADER_FLAG_START_ADDRESS, BOOTLOADER_FLAG_LENGTH_BYTES ); isServiceOnEntry= FALSE; } if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE ) { U08 i; U32 tempValue; getDataFromRAM( readBuffer, BOOTLOADER_FLAG_LENGTH_BYTES ); for ( i = 0; i < BOOTLOADER_FLAG_LENGTH_BYTES; i++ ) { tempValue = readBuffer [ i ] << i * SHIFT_8_BITS_FOR_BYTE_SHIFT; bootloaderFlag = bootloaderFlag + tempValue; } state = NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD; isServiceOnEntry= TRUE; } return state; } /************************************************************************* * @brief handleSelfTestReadLogRecord * The handleSelfTestReadLogRecord reads the log record from RTC RAM * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadLogRecord ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD; if ( isServiceOnEntry && getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM( LOG_RECORDS_START_ADDRESS, LOG_RECORDS_LENGTH_BYTES ); isServiceOnEntry= FALSE; } if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE ) { getDataFromRAM( readBuffer, LOG_RECORDS_LENGTH_BYTES ); logRecord.recordsCount = ( readBuffer [ BUFFER_INDEX_0 ] << SHIFT_8_BITS_FOR_BYTE_SHIFT ) + readBuffer [ BUFFER_INDEX_1 ]; logRecord.nextWriteIndex = ( readBuffer [ BUFFER_INDEX_2 ] << SHIFT_8_BITS_FOR_BYTE_SHIFT ) + readBuffer [ BUFFER_INDEX_3 ]; logRecord.nextReadIndex = ( readBuffer [ BUFFER_INDEX_4 ] << SHIFT_8_BITS_FOR_BYTE_SHIFT ) + readBuffer [ BUFFER_INDEX_5 ]; state = NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORDS; isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleSelfTestReadMfgRecords * The handleSelfTestReadMfgRecords reads the manufacturing record from * EEPROM * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadMfgRecord( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORDS; if ( isServiceOnEntry ) { U32 length = MAX_SYS_SERIAL_NUMBER_CHARACTERS + MAX_HW_SERIAL_NUMBER_CHARACTERS + MAX_MFG_DATE_CHARACTERS + MAX_CRC_LENGTH_BYTES; EEPROMStatus = Fapi_doMarginRead( (U32*)BANK7_SECTOR0_START_ADDRESS, (U32*)readBuffer, length, Fapi_NormalRead ); isServiceOnEntry = FALSE; } else if ( EEPROMStatus == Fapi_Status_Success ) { U08 i; for ( i = 0; i < MAX_SYS_SERIAL_NUMBER_CHARACTERS; i++ ) { mfgRecord.mfgData.SYSSerialNumber [ i ] = readBuffer [ i ]; } for ( i = 0; i < MAX_HW_SERIAL_NUMBER_CHARACTERS; i++ ) { mfgRecord.mfgData.HWSerialNumber [ i ] = readBuffer [ i + MAX_SYS_SERIAL_NUMBER_CHARACTERS ]; } for ( i = 0; i < MAX_MFG_DATE_CHARACTERS; i++ ) { mfgRecord.mfgData.mfgDate [ i ] = readBuffer [ i + MAX_SYS_SERIAL_NUMBER_CHARACTERS + MAX_HW_SERIAL_NUMBER_CHARACTERS ]; } mfgRecord.crc = ( readBuffer [ MAX_SYS_SERIAL_NUMBER_CHARACTERS + MAX_HW_SERIAL_NUMBER_CHARACTERS + MAX_MFG_DATE_CHARACTERS + 1 ] << SHIFT_8_BITS_FOR_BYTE_SHIFT ) + readBuffer [ MAX_SYS_SERIAL_NUMBER_CHARACTERS + MAX_HW_SERIAL_NUMBER_CHARACTERS + MAX_MFG_DATE_CHARACTERS ]; state = NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC; isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleSelfTestCheckCRC * The handleSelfTestCheckCRC calculates the CRC of the records and compares * them to the CRC that was read. If they don't match, it will fail POST * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_COMPLETE; U16 calculatedCRC; calculatedCRC = crc16( (U08*)&mfgRecord.mfgData, sizeof( MFG_DATA_T ) ); if ( calculatedCRC == mfgRecord.crc ) { NVDataMgmtSelfTestResult = SELF_TEST_STATUS_PASSED; } else { NVDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; } return state; } /************************************************************************* * @brief execNVDataMgmtSelfTest * The execNVDataMgmtSelfTest runs the NVDataMgmt POST during the self test * @details * Inputs : none * Outputs : SELF_TEST_STATUS_T * @param none * @return SELF_TEST_STATUS_T *************************************************************************/ SELF_TEST_STATUS_T execNVDataMgmtSelfTest ( void ) { switch( NVDataMgmtSelfTestState ) { case NVDATAMGMT_SELF_TEST_STATE_START: NVDataMgmtSelfTestState = handleSelfTestStart(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG: NVDataMgmtSelfTestState = handleSelfTestReadBootloaderFlag(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD: NVDataMgmtSelfTestState = handleSelfTestReadLogRecord(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORDS: NVDataMgmtSelfTestState = handleSelfTestReadMfgRecord(); break; case NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC: NVDataMgmtSelfTestState = handleSelfTestCheckCRC(); break; case NVDATAMGMT_SELF_TEST_STATE_COMPLETE: // Done with the state // TODO: If POST failed, set the proper alarm break; default: //TODO: Alarm NVDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; break; } return NVDataMgmtSelfTestResult; } /************************************************************************* * @brief execNVDataMgmt * The execNVDataMgmt runs the NVDataMgmt main tasks * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ void execNVDataMgmt( void ) { switch ( NVDataMgmtExecState ) { case NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST: NVDataMgmtExecState = handleExecWaitForPostState(); break; case NVDATAMGMT_EXEC_STATE_IDLE: NVDataMgmtExecState = handleExecIdleState(); break; case NVDATAMGMT_EXEC_STATE_WRITE: NVDataMgmtExecState = handleExecWriteState(); break; case NVDATAMGMT_EXEC_STATE_READ: NVDataMgmtExecState = handleExecReadState(); break; case NVDATAMGMT_EXEC_STATE_FAULT: // Something failed set the alarms // TODO: set the alarms and stuff break; default: NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_FAULT; break; } } NVDATAMGMT_EXEC_STATE_T handleExecWaitForPostState( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; if ( NVDataMgmtSelfTestState == NVDATAMGMT_SELF_TEST_STATE_COMPLETE && NVDataMgmtSelfTestResult == SELF_TEST_STATUS_PASSED ) { // TODO: REMOVE THIS CODE enqueue(); // TODO: REMOVE THIS CODE state = NVDATAMGMT_EXEC_STATE_IDLE; } else if ( NVDataMgmtSelfTestState == NVDATAMGMT_SELF_TEST_STATE_COMPLETE ) { // TODO: Check this state, do we have to go to FAULT if POST failed? state = NVDATAMGMT_EXEC_STATE_FAULT; } return state; } static NVDATAMGMT_EXEC_STATE_T handleExecIdleState( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_IDLE; if ( !isQueueEmpty() ) { NVDATAMGMT_OPERATION_STATE_T ops = jobQueue [ QUEUE_FRONT_INDEX ].memoryOperation; if ( ops == NVDATAMGMT_WRITE ) { state = NVDATAMGMT_EXEC_STATE_WRITE; } else if ( ops == NVDATAMGMT_READ ) { state = NVDATAMGMT_EXEC_STATE_READ; } } return state; } static NVDATAMGMT_EXEC_STATE_T handleExecWriteState( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_WRITE; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, jobQueue [ QUEUE_FRONT_INDEX ].startAddress); while ( EEPROMStatus != Fapi_Status_Success) {} // TODO: Convert the buffer to U08* EEPROMStatus = Fapi_issueProgrammingCommand ( jobQueue [ QUEUE_FRONT_INDEX ].startAddress, jobQueue [ QUEUE_FRONT_INDEX ].buffer, jobQueue [ QUEUE_FRONT_INDEX ].length, 0x00, 0, Fapi_DataOnly ); isServiceOnEntry = FALSE; } else if ( EEPROMStatus == Fapi_Status_Success ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } static NVDATAMGMT_EXEC_STATE_T handleExecReadState( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_READ; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_doMarginRead ( jobQueue [ QUEUE_FRONT_INDEX ].startAddress, (U32*)jobQueue [ QUEUE_FRONT_INDEX ].buffer, jobQueue [ QUEUE_FRONT_INDEX ].length, Fapi_NormalRead ); isServiceOnEntry = FALSE; } else if ( EEPROMStatus == Fapi_Status_Success ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } static void enqueue( void ) { // REMOVE THIS CODE. FOR TESTING ONLY queueRearIndex++; jobQueue[queueRearIndex].memoryOperation = NVDATAMGMT_WRITE; jobQueue[queueRearIndex].memoryLocation = NVDATAMGMT_EEPROM; jobQueue[queueRearIndex].startAddress = (U32*)BANK7_SECTOR1_START_ADDRESS; jobQueue[queueRearIndex].buffer = tempBufferForTest; jobQueue[queueRearIndex].length = sizeof(tempBufferForTest); queueRearIndex++; jobQueue[queueRearIndex].memoryOperation = NVDATAMGMT_READ; jobQueue[queueRearIndex].memoryLocation = NVDATAMGMT_EEPROM; jobQueue[queueRearIndex].startAddress = (U32*)BANK7_SECTOR1_START_ADDRESS; jobQueue[queueRearIndex].buffer = readBuffer; jobQueue[queueRearIndex].length = 8; // REMOVE THIS CODE. FOR TESTING ONLY } static void dequeue( void ) { U08 i; for ( i = 0; i < queueRearIndex; i++ ) { jobQueue [ i ] = jobQueue [ i + 1 ]; } queueRearIndex--; } static BOOL isQueueEmpty ( void ) { BOOL isEmpty = TRUE; if ( queueRearIndex >= QUEUE_FRONT_INDEX ) { isEmpty = FALSE; } return isEmpty; } static U08 getQueueSize( void ) { return queueRearIndex; }