/************************************************************************** * * 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 #include "F021.h" #include "NVDataMgmt.h" #include "RTC.h" #include "system.h" #include "Utilities.h" #include "Timers.h" // Private defines #define QUEUE_MAX_SIZE 10U #define QUEUE_START_INDEX 0U // The clock frequency comes from HCLK_FREQ and it has to be rounded up to the // nearest number #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 0xF020C000 #define BANK7_SECTOR3_END_ADDRESS 0xF020FFFF #define LOG_DATA_MAX_SIZE_BYTES 32U #define LOG_DATA_START_INDEX 1U #define MAX_NUM_OF_SECTORS_FOR_LOG_DATA 3U #define MAX_LOG_DATA_PER_SECTOR (((BANK7_SECTOR1_END_ADDRESS + 1) - \ BANK7_SECTOR1_START_ADDRESS) / LOG_DATA_MAX_SIZE_BYTES) // RTC RAM defines #define BOOTLOADER_FLAG_START_ADDRESS 0x00000000 #define BOOTLOADER_FLAG_LENGTH_BYTES 4U #define LOG_RECORD_START_ADDRESS 0x00000010 // 16 #define MFG_RECORD_START_ADDRESS 0X00000020 // 32 #define HD_TREATMENT_TIME_START_ADDRESS 0X00000030 // 48 #define DG_CONSUMED_WATER_START_ADDRESS 0X00000040 // 64 #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_CRC_LENGTH_BYTES 2U #define MAX_EEPROM_WRITE_BUFFER_BYTES 16U //Assert 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_TO_EEPROM, NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM, NVDATAMGMT_EXEC_STATE_ERASE_EEPROM, NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC, NVDATAMGMT_EXEC_STATE_READ_FROM_RTC, NVDATAMGMT_EXEC_STATE_FAULT, NUM_OF_NVDATAMGMT_EXEC_STATES } NVDATAMGMT_EXEC_STATE_T; typedef enum NVDataMgmt_Operation { NVDATAMGMT_NONE = 0, NVDATAMGMT_WRITE, NVDATAMGMT_READ, NVDATAMGMT_ERASE, NUM_OF_NVDATAMGMT_OPS_STATES } NVDATAMGMT_OPERATION_STATE_T; typedef enum NVDataMgmt_Location { NVDATAMGMT_EEPROM = 0, NVDATAMGMT_RTC, NUM_OF_NVDATAMGMT_LOC_STATES } NVDATAMGMT_LOCATION_STATE_T; #pragma pack(push, 1) struct MEMORY_OPS_T { NVDATAMGMT_OPERATION_STATE_T memoryOperation; NVDATAMGMT_LOCATION_STATE_T memoryLocation; U32* startAddress; U08 buffer [ LOG_DATA_MAX_SIZE_BYTES ]; U32 length; }; typedef struct { U16 recordCount; 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; typedef struct { U32 epochTime; U32 eventCode; U32 subCode; F32 data1; F32 data2; F32 data3; F32 data4; F32 data5; } LOG_DATA_T; #pragma pack(pop) // 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 handleExecEraseState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecWriteToEEPROMState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecReadFromEEPROMState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecWriteToRAMState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecReadFromRAMState ( void ); // Queue functions static void setMemoryOpsStruct ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, U32 length ); static void enqueue ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, U32 length ); static void dequeue ( void ); static U32 prepareWriteLogJobAndGetStartAddress ( U08* data ); static U32 prepareReadLogJobAndGetStartAddress (); static BOOL isQueueEmpty ( void ); static BOOL isQueueFull ( void ); // Private variables struct MEMORY_OPS_T jobQueue [ QUEUE_MAX_SIZE ]; static U08 readBuffer [ LOG_DATA_MAX_SIZE_BYTES ]; static LOG_RECORD_T logRecord; static LOG_DATA_T logData; static MFG_RECORD_T mfgRecord; static U08 queueRearIndex = QUEUE_START_INDEX; static U08 queueFrontIndex = QUEUE_START_INDEX; static U08 queueCount = 0; 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; // REMOVE THIS CODE static U08 tempBufferForTest[5] = {'5', 'Y', 'I', 'D', 'P'}; //static U08 readBufferForTest [ 8 ]; // 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 = QUEUE_START_INDEX; queueFrontIndex = QUEUE_START_INDEX; 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 *************************************************************************/ static 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; } BOOL setSerialNumber ( char* buffer ) { BOOL status = TRUE; return status; } /************************************************************************* * @brief writeLogData * The writeLogData checks if the queue is not full and if it is not, it calls * enqueue to schedule a job for writing the log data * @details * Inputs : data * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL writeLogData ( U08* data ) { BOOL status = FALSE; if ( !isQueueFull() ) { enqueue ( NVDATAMGMT_WRITE, NVDATAMGMT_EEPROM, 0, data, sizeof( LOG_DATA_T ) ); status = TRUE; } return status; } /************************************************************************* * @brief readLogData * The readLogData checks if the queue is not full and if it is not, it calls * enqueue to schedule a job for writing the log data * @details * Inputs : data * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL readLogData ( U08* buffer ) { BOOL status = FALSE; if ( !isQueueFull() ) { enqueue( NVDATAMGMT_READ, NVDATAMGMT_EEPROM, 0, buffer, sizeof(buffer) ); status = TRUE; } return status; } /************************************************************************* * @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 *************************************************************************/ static 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 *************************************************************************/ static 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_RECORD_START_ADDRESS, sizeof ( LOG_RECORD_T ) ); isServiceOnEntry= FALSE; } if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE ) { U08 i; U08* logPtr = (U08*)&logRecord; getDataFromRAM ( readBuffer, sizeof ( LOG_RECORD_T ) ); for ( i = 0; i < sizeof ( LOG_RECORD_T ); i++ ) { *logPtr = ( readBuffer[ i ] & MASK_OFF_MSB ); logPtr++; } 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 *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadMfgRecord ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORDS; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_doMarginRead ( (U32*)BANK7_SECTOR0_START_ADDRESS, (U32*)readBuffer, sizeof( MFG_DATA_T ), Fapi_NormalRead ); isServiceOnEntry = FALSE; } else if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) { 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 *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_COMPLETE; U16 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_TO_EEPROM: NVDataMgmtExecState = handleExecWriteToEEPROMState(); break; case NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM: NVDataMgmtExecState = handleExecReadFromEEPROMState(); break; case NVDATAMGMT_EXEC_STATE_ERASE_EEPROM: NVDataMgmtExecState = handleExecEraseState(); break; case NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC: NVDataMgmtExecState = handleExecWriteToRAMState(); break; case NVDATAMGMT_EXEC_STATE_READ_FROM_RTC: NVDataMgmtExecState = handleExecReadFromRAMState(); 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; } } /************************************************************************* * @brief handleExecWaitForPostState * The handleExecWaitForPostState waits for POST to be completed * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static 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 logData.epochTime = 1582583436; logData.eventCode = NVDATAMGMT_DEVICE_TURNED_ON; logData.subCode = 14587; logData.data1 = 2.4; logData.data2 = 13; logData.data3 = 223.58; logData.data4 = 80.125; logData.data5 = 68; writeLogData ( (U08*)&logData ); readLogData ( (U08*)&tempBufferForTest ); //setSerialNumber( (char*)tempBufferForTest ); // TODO: REMOVE THIS CODE state = NVDATAMGMT_EXEC_STATE_IDLE; } else if ( NVDataMgmtSelfTestState == NVDATAMGMT_SELF_TEST_STATE_COMPLETE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } return state; } /************************************************************************* * @brief handleExecIdleState * The handleExecIdleState checks if the queue is empty and if it is not * empty, it sets the state of the job * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecIdleState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_IDLE; if ( !isQueueEmpty() ) { NVDATAMGMT_OPERATION_STATE_T ops = jobQueue [ queueFrontIndex ].memoryOperation; NVDATAMGMT_LOCATION_STATE_T location = jobQueue [ queueFrontIndex ].memoryLocation; if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM ) { state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; } else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_EEPROM ) { state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; } else if ( ops == NVDATAMGMT_ERASE ) { state = NVDATAMGMT_EXEC_STATE_ERASE_EEPROM; } else if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_RTC ) { state = NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC; } else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_RTC ) { state = NVDATAMGMT_EXEC_STATE_READ_FROM_RTC; } } return state; } /************************************************************************* * @brief handleExecWriteToEEPROMState * The handleExecWriteToEEPROMState issues a write command to EEPROM on entry * and if the write was successful, it sets the state to Idle * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecWriteToEEPROMState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_issueProgrammingCommand ( jobQueue [ queueFrontIndex ].startAddress, jobQueue [ queueFrontIndex ].buffer, jobQueue [ queueFrontIndex ].length, 0x00, 0, Fapi_DataOnly ); isServiceOnEntry = FALSE; } else if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleExecReadFromEEPROMState * The handleExecReadFromEEPROMState issues a read command to EEPROM on entry * and if the read was successful, it sets the state to Idle * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecReadFromEEPROMState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_doMarginRead ( jobQueue [ queueFrontIndex ].startAddress, (U32*)jobQueue [ queueFrontIndex ].buffer, jobQueue [ queueFrontIndex ].length, Fapi_NormalRead ); isServiceOnEntry = FALSE; } else if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleExecEraseState * The handleExecEraseState issues an erase command to EEPROM on entry * and if the erase was successful, it sets the state to Idle * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecEraseState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_ERASE_EEPROM; if ( isServiceOnEntry ) { EEPROMStatus = Fapi_issueAsyncCommandWithAddress ( Fapi_EraseSector, jobQueue [ queueFrontIndex ].startAddress ); isServiceOnEntry = FALSE; } else if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleExecWriteToRAMState * The handleExecWriteToRAMState issues a write command to RTC RAM if the * RAM was ready, and if the RAM got back to Idle after the write command, * it sets the state to Idle * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecWriteToRAMState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC; if ( isServiceOnEntry && getRTCRAMState() == RTC_RAM_STATE_READY ) { writeToRAM ( (U32)( jobQueue [ queueFrontIndex ].startAddress ), jobQueue [ queueFrontIndex ].buffer, jobQueue [ queueFrontIndex ].length ); isServiceOnEntry= FALSE; } if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief handleExecReadFromRAMState * The handleExecReadFromRAMState issues a read command to RTC RAM if the * RAM was ready, and if the RAM got back to Idle after the read command, * it calls another function to read the data back from RTC RAM and * it sets the state to Idle * @details * Inputs : none * Outputs : NVDATAMGMT_EXEC_STATE_T * @param none * @return NVDATAMGMT_EXEC_STATE_T *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecReadFromRAMState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_READ_FROM_RTC; if ( isServiceOnEntry && getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM( (U32)( jobQueue [ queueFrontIndex ].startAddress ), jobQueue [ queueFrontIndex ].length ); isServiceOnEntry= FALSE; } if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE ) { getDataFromRAM( jobQueue [ queueFrontIndex ].buffer, jobQueue [ queueFrontIndex ].length ); state = NVDATAMGMT_EXEC_STATE_IDLE; dequeue(); isServiceOnEntry = TRUE; } return state; } /************************************************************************* * @brief setMemoryOpsStruct * The setMemoryOpsStruct fills up the job struct * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void setMemoryOpsStruct ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, U32 length ) { jobQueue [ queueRearIndex ].memoryOperation = ops; jobQueue [ queueRearIndex ].memoryLocation = location; jobQueue [ queueRearIndex ].startAddress = (U32*)startAddress; jobQueue [ queueRearIndex ].length = length; memcpy ( jobQueue [ queueRearIndex ].buffer, data, length ); queueRearIndex++; // check the wrap } static U32 prepareWriteLogJobAndGetStartAddress ( U08* data ) { U32 modulus = 0; U32 opsStartAddress = 0; U16 readIndex = 0; // The write address is calculated using the next write index and is and offset from // the start of sector 1. Sectors 1,2, and 3 have been allocated for logging data opsStartAddress = ( logRecord.nextWriteIndex * LOG_DATA_MAX_SIZE_BYTES ) + BANK7_SECTOR1_START_ADDRESS; modulus = logRecord.nextWriteIndex % MAX_LOG_DATA_PER_SECTOR; if ( modulus == 0 ) { readIndex = logRecord.nextReadIndex; // define if ( logRecord.nextWriteIndex == MAX_LOG_DATA_PER_SECTOR * MAX_NUM_OF_SECTORS_FOR_LOG_DATA ) { opsStartAddress = BANK7_SECTOR1_START_ADDRESS; // It is at the end of sector 3, it needs to start over logRecord.nextWriteIndex = LOG_DATA_START_INDEX; // Sector 1 is being erased and the maximum number of logs that can be // stored in it is erased (in this case 512) logRecord.recordCount = logRecord.recordCount - MAX_LOG_DATA_PER_SECTOR; // If the read index is somewhere in sector 1, then it will be set to 0 if ( readIndex > ( MAX_NUM_OF_SECTORS_FOR_LOG_DATA - 1 ) * MAX_LOG_DATA_PER_SECTOR && readIndex < MAX_LOG_DATA_PER_SECTOR * MAX_NUM_OF_SECTORS_FOR_LOG_DATA ) { logRecord.nextReadIndex = 0; // sector 2, } } else { if ( logRecord.nextWriteIndex == MAX_LOG_DATA_PER_SECTOR ) { opsStartAddress = BANK7_SECTOR2_START_ADDRESS; if ( readIndex > 0 && readIndex < MAX_LOG_DATA_PER_SECTOR ) { logRecord.nextReadIndex = MAX_LOG_DATA_PER_SECTOR + 1; } } else if ( logRecord.nextWriteIndex == ( MAX_NUM_OF_SECTORS_FOR_LOG_DATA - 1 ) * MAX_LOG_DATA_PER_SECTOR ) { opsStartAddress = BANK7_SECTOR3_START_ADDRESS; if ( readIndex > ( MAX_NUM_OF_SECTORS_FOR_LOG_DATA - 1 ) * MAX_LOG_DATA_PER_SECTOR && readIndex < MAX_LOG_DATA_PER_SECTOR ) { logRecord.nextReadIndex = 0; } } if ( logRecord.recordCount > MAX_NUM_OF_SECTORS_FOR_LOG_DATA ) { logRecord.recordCount = logRecord.recordCount - MAX_NUM_OF_SECTORS_FOR_LOG_DATA; } else { logRecord.recordCount++; logRecord.nextWriteIndex++; } } // Erase does not need payload or length setMemoryOpsStruct ( NVDATAMGMT_ERASE, NVDATAMGMT_EEPROM, opsStartAddress, 0, 0 ); } else { logRecord.recordCount++; logRecord.nextWriteIndex++; } // Update the log record setMemoryOpsStruct ( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, LOG_RECORD_START_ADDRESS, (U08*)&logRecord, sizeof( LOG_RECORD_T ) ); return opsStartAddress; } static U32 prepareReadLogJobAndGetStartAddress() { // The write address is calculated using the next write index and is and offset from // the start of sector 1. Sectors 1,2, and 3 have been allocated for logging data U32 opsStartAddress = ( logRecord.nextReadIndex * LOG_DATA_MAX_SIZE_BYTES ) + BANK7_SECTOR1_START_ADDRESS; if ( logRecord.nextReadIndex == MAX_LOG_DATA_PER_SECTOR * MAX_NUM_OF_SECTORS_FOR_LOG_DATA ) { logRecord.nextReadIndex = LOG_DATA_START_INDEX; } else { logRecord.nextReadIndex++; } // Update the log record setMemoryOpsStruct ( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, LOG_RECORD_START_ADDRESS, (U08*)&logRecord, sizeof( LOG_RECORD_T ) ); return opsStartAddress; } /************************************************************************* * @brief enqueue * The enqueue prepares the jobs to be processed. It checks if the requested * job is read or write, or if it is RTC or EEPROM and sets the job struct. * It checks for the corner cases, for instance, if the next write log to EEPROM * is at the beginning of the next sector, it schedules and erase first and then * it schedules the write jobs. The function breaks the write to EEPROM jobs to * 16 bytes at the time * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void enqueue ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, U32 length ) { U32 quotient = 0; U32 modulus = 0; U32 maxBufferLength = 0; U32 opsStartAddress = startAddress; U08 i; // Remove if ( !isQueueFull() ) { queueRearIndex = QUEUE_START_INDEX; } // Setup EEPROM write log event if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM && startAddress == 0 ) { maxBufferLength = MAX_EEPROM_WRITE_BUFFER_BYTES; opsStartAddress = prepareWriteLogJobAndGetStartAddress ( data ); } // Setup EEPROM read log event else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_EEPROM && startAddress == 0 ) { maxBufferLength = LOG_DATA_MAX_SIZE_BYTES; opsStartAddress = prepareReadLogJobAndGetStartAddress(); } else if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM && startAddress == BANK7_SECTOR0_START_ADDRESS ) { // schedule this at the function for mfg data in sector 0 setMemoryOpsStruct ( NVDATAMGMT_ERASE, NVDATAMGMT_EEPROM, opsStartAddress, 0, 0 ); } // Comments if ( length > maxBufferLength ) { quotient = length / maxBufferLength; modulus = length % maxBufferLength; for ( i = 0; i < quotient; i++ ) { setMemoryOpsStruct ( ops, location, ( opsStartAddress + ( i * maxBufferLength ) ), data + ( i * maxBufferLength ), maxBufferLength ); } if ( modulus != 0 ) { setMemoryOpsStruct ( ops, location, ( opsStartAddress + ( quotient * maxBufferLength ) ), data + ( quotient * maxBufferLength ), modulus ); } } else { setMemoryOpsStruct ( ops, location, opsStartAddress, data, length ); } } /************************************************************************* * @brief dequeue * The dequeue increments the front index counter and if it is equal to * rear index, it sets it to -1, meaning that the queue is empty * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void dequeue ( void ) { if ( queueFrontIndex >= QUEUE_MAX_SIZE - 1 ) { queueFrontIndex = QUEUE_START_INDEX; } else { queueFrontIndex++; } if ( queueCount > 0 ) { queueCount--; } } /************************************************************************* * @brief isQueueEmpty * The isQueueEmpty checks whether the queue is empty and if it is empty, * it will return a false * @details * Inputs : none * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ static BOOL isQueueEmpty ( void ) { BOOL isEmpty = TRUE; if ( queueCount == 0 ) { isEmpty = FALSE; } return isEmpty; } /************************************************************************* * @brief isQueueFull * The isQueueFull checks whether the queue is full and if it is full, * it will return a true * @details * Inputs : none * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ static BOOL isQueueFull ( void ) { BOOL isFull = FALSE; if ( queueCount >= QUEUE_MAX_SIZE - 1 ) { isFull = TRUE; } return isFull; }