/************************************************************************** * * 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 // For memcpy #include "F021.h" #include "NVDataMgmt.h" #include "RTC.h" #include "system.h" #include "Utilities.h" #include "Timers.h" // Private defines #define QUEUE_MAX_SIZE 20U #define QUEUE_START_INDEX 0U #define MIN_QUEUE_COUNT_FOR_DATA_LOG 3U #define MIN_QUEUE_COUNT_FOR_SECTOR_0 4U // 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 MAX_EEPROM_WRITE_BUFFER_BYTES 16U //Assert #define MAX_JOB_DATA_SIZE_BYTES 32U #define LOG_DATA_START_INDEX 0U #define MAX_NUM_OF_SECTORS_FOR_LOG_DATA 3U #define MAX_LOG_DATA_PER_SECTOR (((BANK7_SECTOR1_END_ADDRESS + 1) - \ BANK7_SECTOR1_START_ADDRESS) / MAX_JOB_DATA_SIZE_BYTES) #define MAX_NUM_OF_DATA_LOGS_IN_SECTOR3 (MAX_NUM_OF_SECTORS_FOR_LOG_DATA * MAX_LOG_DATA_PER_SECTOR) #define MAX_NUM_OF_DATA_LOGS_IN_SECTOR2 ((MAX_NUM_OF_SECTORS_FOR_LOG_DATA - 1) * MAX_LOG_DATA_PER_SECTOR) #define MAX_NUM_OF_DATA_LOGS_IN_SECTOR1 ((MAX_NUM_OF_SECTORS_FOR_LOG_DATA - 2) * MAX_LOG_DATA_PER_SECTOR) // Data addresses and length in RTC RAM #define BOOTLOADER_FLAG_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_ADDRESS 0X00000030 // 48 #define DG_CONSUMED_WATER_ADDRESS 0X00000040 // 64 #define SERVICE_DATE_START_ADDRESS 0X00000050 // 80 // Data addresses in EEPROM #define CALIBRATION_RECORD_START_ADDRESS (BANK7_SECTOR0_START_ADDRESS + 0x100) #define COMMAND_TIME_OUT 500U // time in ms typedef enum NVDataMgmt_Self_Test_States { NVDATAMGMT_SELF_TEST_STATE_START = 0, NVDATAMGMT_SELF_TEST_STATE_ENABLE_EEPROM, NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG, NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD, NVDATAMGMT_SELF_TEST_STATE_READ_TREATMENT_TIME, NVDATAMGMT_SELF_TEST_STATE_READ_WATER_CONSUMPTION, NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORD, NVDATAMGMT_SELF_TEST_STATE_READ_CAL_RECORD, NVDATAMGMT_SELF_TEST_STATE_READ_SERVICE_RECORD, 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_SECTOR, 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) typedef struct { NVDATAMGMT_OPERATION_STATE_T memoryOperation; NVDATAMGMT_LOCATION_STATE_T memoryLocation; U32* startAddress; U08 buffer [ MAX_JOB_DATA_SIZE_BYTES ]; READ_DATA_T* externalAddress; U32 length; } MEMORY_OPS_T; typedef struct { U16 recordCount; U16 nextWriteIndex; U16 nextReadIndex; } LOG_HEADER_T; typedef struct { LOG_HEADER_T logHeader; U16 crc; } LOG_RECORD_T; typedef struct { U32 treatmentTime; U16 crc; } TREATMENT_TIME_RECORD_T; typedef struct { U32 waterConsumption; U16 crc; } WATER_CONSUMPTION_RECORD_T; typedef struct { MFG_DATA_T mfgData; U16 crc; } MFG_RECORD_T; typedef struct { SERVICE_DATA_T serviceData; U16 crc; } SERVICE_RECORD_T; typedef struct { CALIBRATION_DATA_T calData; U16 crc; } CALIBRATION_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 variables static MEMORY_OPS_T jobQueue [ QUEUE_MAX_SIZE ]; static MEMORY_OPS_T currentJob; static LOG_RECORD_T logRecord; static TREATMENT_TIME_RECORD_T treatmentTimeRecord; static WATER_CONSUMPTION_RECORD_T waterConsumptionRecord; static LOG_DATA_T logData; static MFG_RECORD_T mfgRecord; static CALIBRATION_RECORD_T calibrationRecord; static SERVICE_RECORD_T serviceRecord; static U08 queueRearIndex = QUEUE_START_INDEX; static U08 queueFrontIndex = QUEUE_START_INDEX; static U08 queueCount = 0; 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 U32 bootloaderFlag = 0; static BOOL hasLogRecordCRCFailed = FALSE; static BOOL hasCommandTimedout = FALSE; static U32 currentTime = 0; // Private functions static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestStart ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestEnableEEPROM ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadBootloaderFlag ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadHDTreatmentTime ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadDGWaterConsumption ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadLogRecord ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadMfgRecord ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadCalibrationRecord ( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadServiceRecord ( 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, READ_DATA_T* extAddress, U32 length ); static void enqueue ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, READ_DATA_T* extAddress, U32 length ); static void dequeue ( void ); static U32 prepareWriteLogJobAndGetStartAddress ( U08* data ); static U32 prepareReadLogJobAndGetStartAddress ( void ); static BOOL isQueueEmpty ( void ); static BOOL isQueueFull ( void ); static U32 getAvailableQueueCount ( void ); static BOOL enqueueBank7Sector0Records ( void ); // Helper functions static BOOL didCommandTimeout ( ALARM_ID_T alarm, U08* state ); // REMOVE THIS CODE //static U08 tempBufferForTest[5] = {'5', 'Y', 'I', 'D', 'P'}; static U08 readBufferForTest [ 36 ]; static READ_DATA_T mytest; static CALIBRATION_DATA_T calTest; static SERVICE_DATA_T service; // REMOVE THIS CODE /************************************************************************* * @brief initNVDataMgmt * The initNVDataMgmt initializes EEPROM * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ void initNVDataMgmt ( void ) { NVDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_START; NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; NVDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; hasLogRecordCRCFailed = FALSE; queueRearIndex = QUEUE_START_INDEX; queueFrontIndex = QUEUE_START_INDEX; Fapi_initializeFlashBanks( ROUNDED_HCLK_FREQ ); Fapi_setActiveFlashBank( Fapi_FlashBank7 ); } /************************************************************************* * @brief setMfgData * The setMfgData updates the struct that holds the manufacturing data, * calls another function to calculate the CRC for the provided data and * calls another function to erase sector 0 and write the new manufacturing * data. * @details * Inputs : MFG_DATA_T (data) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setMfgData ( MFG_DATA_T data ) { mfgRecord.mfgData = data; mfgRecord.crc = crc16 ( (U08*)&mfgRecord.mfgData, sizeof(MFG_DATA_T) ); BOOL status = enqueueBank7Sector0Records(); return status; } /************************************************************************* * @brief getMfgData * The getMfgData returns the data in the struct that hold manufacturing * record to buffer that the caller has provided * @details * Inputs : U08* (buffer) * Outputs : none * @param none * @return none *************************************************************************/ void getMfgData ( U08* buffer ) { memcpy ( buffer, (U08*)&mfgRecord.mfgData, sizeof(MFG_DATA_T) ); } /************************************************************************* * @brief setCalibrationData * The setCalibrationData updates the struct that holds the calibration data, * calls another function to calculate the CRC for the provided data and * calls another function to erase sector 0 and write the new manufacturing * data. * @details * Inputs : MFG_DATA_T (data) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setCalibrationData ( CALIBRATION_DATA_T data ) { calibrationRecord.calData = data; calibrationRecord.crc = crc16 ( (U08*)&calibrationRecord.calData, sizeof(CALIBRATION_DATA_T) ); // The entire sector 0 must be erased and re-written again BOOL status = enqueueBank7Sector0Records(); return status; } /************************************************************************* * @brief getCalibrationData * The getCalibrationData returns the data in the struct that hold calibration * record to buffer that the caller has provided * @details * Inputs : U08* (buffer) * Outputs : none * @param none * @return none *************************************************************************/ void getCalibrationData ( U08* buffer ) { memcpy ( buffer, (U08*)&calibrationRecord.calData, sizeof(CALIBRATION_DATA_T) ); } /************************************************************************* * @brief setServiceDate * The setServiceDate updates the struct that holds the calibration data, * calls another function to calculate the CRC for the provided data if * there is enough queues available, it schedules a write to RTC RAM * @details * Inputs : SERVICE_DATA_T (data) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setServiceDate ( SERVICE_DATA_T data ) { BOOL status = FALSE; serviceRecord.serviceData = data; serviceRecord.crc = crc16 ( (U08*)&serviceRecord.serviceData, sizeof(SERVICE_DATA_T) ); if ( !isQueueFull() ) { enqueue( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, SERVICE_DATE_START_ADDRESS, (U08*)&serviceRecord, 0, sizeof(SERVICE_RECORD_T) ); status = TRUE; } return status; } /************************************************************************* * @brief getServiceDate * The getServiceDate returns the data in the struct that holds service * date to buffer that the caller has provided * @details * Inputs : U08* (buffer) * Outputs : none * @param none * @return none *************************************************************************/ void getServiceDate ( U08* buffer ) { memcpy ( buffer, (U08*)&serviceRecord.serviceData, sizeof(SERVICE_DATA_T) ); } /************************************************************************* * @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 : U08* (data) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL writeLogData ( U08* data, U32 length ) { BOOL status = FALSE; if ( !isQueueFull() ) { enqueue ( NVDATAMGMT_WRITE, NVDATAMGMT_EEPROM, 0, data, 0, length ); 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 : READ_DATA_T* (buffer), U32 (length) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL readLogData ( READ_DATA_T* buffer, U32 length ) { BOOL status = FALSE; U32 availableQueue = getAvailableQueueCount(); if ( availableQueue >= MIN_QUEUE_COUNT_FOR_DATA_LOG ) { enqueue( NVDATAMGMT_READ, NVDATAMGMT_EEPROM, 0, 0, buffer, length ); status = TRUE; } return status; } /************************************************************************* * @brief setTreatmentTime * The setTreatmentTime sets a queue job to write the treatment time in * the specified RAM address * @details * Inputs : U32 (mins) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setTreatmentTime ( U32 mins ) { BOOL status = FALSE; treatmentTimeRecord.treatmentTime = mins; treatmentTimeRecord.crc = crc16 ( (U08*)&treatmentTimeRecord.treatmentTime, sizeof(U32) ); if ( !isQueueFull() ) { enqueue( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, HD_TREATMENT_TIME_ADDRESS, (U08*)&treatmentTimeRecord, 0, sizeof(TREATMENT_TIME_RECORD_T) ); status = TRUE; } return status; } /************************************************************************* * @brief setWaterConsumption * The setWaterConsumption sets a queue job to write the amount of water * that has been consumed in DG * @details * Inputs : U32 (liters) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setWaterConsumption ( U32 liters ) { BOOL status = FALSE; waterConsumptionRecord.waterConsumption = liters; waterConsumptionRecord.crc = crc16 ( (U08*)&waterConsumptionRecord.waterConsumption, sizeof(U32) ); if ( !isQueueFull() ) { enqueue( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, DG_CONSUMED_WATER_ADDRESS, (U08*)&waterConsumptionRecord, 0, sizeof(WATER_CONSUMPTION_RECORD_T) ); status = TRUE; } return status; } /************************************************************************* * @brief getWaterConsumption * The getWaterConsumption returns the amount of consumed water * @details * Inputs : none * Outputs : U32 * @param none * @return U32 *************************************************************************/ U32 getWaterConsumption ( void ) { return waterConsumptionRecord.waterConsumption; } /************************************************************************* * @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_ENABLE_EEPROM: NVDataMgmtSelfTestState = handleSelfTestEnableEEPROM(); 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_TREATMENT_TIME: NVDataMgmtSelfTestState = handleSelfTestReadHDTreatmentTime(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_WATER_CONSUMPTION: NVDataMgmtSelfTestState = handleSelfTestReadDGWaterConsumption(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORD: NVDataMgmtSelfTestState = handleSelfTestReadMfgRecord(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_CAL_RECORD: NVDataMgmtSelfTestState = handleSelfTestReadCalibrationRecord(); break; case NVDATAMGMT_SELF_TEST_STATE_READ_SERVICE_RECORD: NVDataMgmtSelfTestState = handleSelfTestReadServiceRecord(); 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 setBootloaderFlag * The setBootloaderFlag sets the bootloader flag to RTC RAM * @details * Inputs : U32 (flag) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ BOOL setBootloaderFlag ( U32 flag ) { BOOL status = FALSE; if ( !isQueueFull() ) { enqueue ( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, BOOTLOADER_FLAG_ADDRESS, (U08*)&flag, 0, BOOTLOADER_FLAG_LENGTH_BYTES ); status = TRUE; } return status; } /************************************************************************* * @brief getBootloaderFlag * The getBootloaderFlag gets the bootloader flag from RTC RAM * @details * Inputs : none * Outputs : U32 (flag value) * @param none * @return U32 (flag value) *************************************************************************/ U32 getBootloaderFlag( void ) { return bootloaderFlag; } /************************************************************************* * @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; } } // Private functions /************************************************************************* * @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_ENABLE_EEPROM; Fapi_enableEepromBankSectors( BANK7_SECTOR_0_31_ENABLE_BIT_MASK, BANK7_SECTOR_32_63_ENABLE_BIT_MASK ); // Get the time to check for timeout currentTime = getMSTimerCount(); return state; } /************************************************************************* * @brief handleSelfTestEnableEEPROM * The handleSelfTestEnableEEPROM waits for EEPROM to return with ready from * enabling the EEPROM command * @details * Inputs : none * Outputs : NVDATAMGMT_SELF_TEST_STATE_T * @param none * @return NVDATAMGMT_SELF_TEST_STATE_T *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestEnableEEPROM ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_ENABLE_EEPROM; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { // Enable was successful, Request a read for bootloader if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM( BOOTLOADER_FLAG_ADDRESS, BOOTLOADER_FLAG_LENGTH_BYTES ); // Get the time to check for timeout currentTime = getMSTimerCount(); } state = NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG; } 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 *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadBootloaderFlag ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_BOOTLOADER_FLAG; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); // If the read for bootloader is done, read it if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM( (U08*)&bootloaderFlag, BOOTLOADER_FLAG_LENGTH_BYTES ); // If the device is HD, read treatment time, // If the device is DG, read water consumption #ifdef _HD_ if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM ( HD_TREATMENT_TIME_ADDRESS, sizeof(TREATMENT_TIME_RECORD_T) ); currentTime = getMSTimerCount(); } state = NVDATAMGMT_SELF_TEST_STATE_READ_TREATMENT_TIME; #else if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM ( DG_CONSUMED_WATER_ADDRESS, sizeof(WATER_CONSUMPTION_RECORD_T) ); currentTime = getMSTimerCount(); } state = NVDATAMGMT_SELF_TEST_STATE_READ_WATER_CONSUMPTION; #endif } return state; } /************************************************************************* * @brief handleSelfTestReadHDTreatmentTime * The handleSelfTestReadHDTreatmentTime reads the HD treatment time * 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 handleSelfTestReadHDTreatmentTime ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_TREATMENT_TIME; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); // If the RTC RAM is ready, read the results if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM ( (U08*)&treatmentTimeRecord, sizeof(TREATMENT_TIME_RECORD_T) ); // If the RAM is ready, request a read for the log records (RAM) if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM ( LOG_RECORD_START_ADDRESS, sizeof(LOG_RECORD_T) ); currentTime = getMSTimerCount(); state = NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD; } } return state; } /************************************************************************* * @brief handleSelfTestReadDGWaterConsumption * The handleSelfTestReadDGWaterConsumption reads the DG water consumption * 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 handleSelfTestReadDGWaterConsumption ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_WATER_CONSUMPTION; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); // If the RAM is ready, request a read for water consumption if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM ( (U08*)&waterConsumptionRecord, sizeof(WATER_CONSUMPTION_RECORD_T) ); if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { readFromRAM ( LOG_RECORD_START_ADDRESS, sizeof(LOG_RECORD_T) ); currentTime = getMSTimerCount(); } state = NVDATAMGMT_SELF_TEST_STATE_READ_LOG_RECORD; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); // If the RAM is in Idle, read the log records if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM ( (U08*)&logRecord, sizeof(LOG_RECORD_T) ); currentTime = getMSTimerCount(); // Get ready for reading the manufacturing record Fapi_doMarginRead ( (U32*)BANK7_SECTOR0_START_ADDRESS, (U32*)&mfgRecord, sizeof(MFG_RECORD_T), Fapi_NormalRead ); state = NVDATAMGMT_SELF_TEST_STATE_READ_MFG_RECORD; } 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_RECORD; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); // Wait for the read from EEPROM to be successful if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { currentTime = getMSTimerCount(); // Send the read command for calibration record Fapi_doMarginRead ( (U32*)CALIBRATION_RECORD_START_ADDRESS, (U32*)&calibrationRecord, sizeof(CALIBRATION_RECORD_T), Fapi_NormalRead ); state = NVDATAMGMT_SELF_TEST_STATE_READ_CAL_RECORD; } return state; } /************************************************************************* * @brief handleSelfTestReadCalibrationRecord * The handleSelfTestReadCalibrationRecord reads the calibration 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 handleSelfTestReadCalibrationRecord ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_CAL_RECORD; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); // If the EEPROM read was successful, request a read from RAM to // read the service record if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { currentTime = getMSTimerCount(); readFromRAM( SERVICE_DATE_START_ADDRESS, sizeof(SERVICE_RECORD_T) ); state = NVDATAMGMT_SELF_TEST_STATE_READ_SERVICE_RECORD; } } return state; } /************************************************************************* * @brief handleSelfTestReadServiceRecord * The handleSelfTestReadServiceRecord reads the service dates 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 handleSelfTestReadServiceRecord ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_SERVICE_RECORD; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM ( (U08*)&serviceRecord, sizeof(SERVICE_RECORD_T) ); state = NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC; } 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; BOOL hasCRCPassed = TRUE; U16 calcCRC; U16 recordCRC; #ifdef _HD_ calcCRC = crc16 ( (U08*)&treatmentTimeRecord.treatmentTime, sizeof(U32) ); recordCRC = treatmentTimeRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_NVDATA_HW_USAGE_DATA_CRC_ERROR, recordCRC, calcCRC ); } #else calcCRC = crc16 ( (U08*)&waterConsumptionRecord.waterConsumption, sizeof(U32) ); recordCRC = waterConsumptionRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_NVDATA_HW_USAGE_DATA_CRC_ERROR, recordCRC, calcCRC ); } #endif // Check log header record calcCRC = crc16 ( (U08*)&logRecord.logHeader, sizeof(LOG_HEADER_T) ); recordCRC = logRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; // CRC for the log record has failed. The flag will be set to true // The log header will be set to full by having the record count be at // maximum number of counts (1536 in this case) and the read index be a 0 // of the beginning of the log sectors hasLogRecordCRCFailed = TRUE; logRecord.logHeader.recordCount = MAX_NUM_OF_DATA_LOGS_IN_SECTOR3; logRecord.logHeader.nextReadIndex = 0; logRecord.logHeader.nextReadIndex = 0; } // Check CRC for manufacturing record calcCRC = crc16 ( (U08*)&mfgRecord.mfgData, sizeof(MFG_DATA_T) ); recordCRC = mfgRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_NVDATA_MFG_RECORD_CRC_ERROR, recordCRC, calcCRC ); } // Check CRC for calibration record calcCRC = crc16 ( (U08*)&calibrationRecord.calData, sizeof(CALIBRATION_DATA_T) ); recordCRC = calibrationRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_NVDATA_CAL_RECORD_CRC_ERROR, recordCRC, calcCRC ); } // Check CRC for service record calcCRC = crc16 ( (U08*)&serviceRecord.serviceData, sizeof(SERVICE_DATA_T) ); recordCRC = serviceRecord.crc; if ( calcCRC != recordCRC ) { hasCRCPassed = FALSE; SET_ALARM_WITH_2_U32_DATA( ALARM_ID_NVDATA_SRVC_RECORD_CRC_ERROR, recordCRC, calcCRC ); } if ( hasCRCPassed || !hasCommandTimedout ) { NVDataMgmtSelfTestResult = SELF_TEST_STATUS_PASSED; } else { NVDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; } return state; } /************************************************************************* * @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 ) { // 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; mytest.status = NVDATAMGMT_READ_IDLE; mytest.externalBuffer = readBufferForTest; //writeLogData ( (U08*)&logData, 32 ); //readLogData ( &mytest, sizeof(readBufferForTest) ); //calTest.occSensorOffset = 3.4; //calTest.tempSensorOffset = 13.2; //setCalibrationData(calTest); char a[10] = {'0','3','-', '0','3','-','2','0','2','0'};; memcpy(service.currentServiceDate, a, 10); memcpy(service.nextServiceDate, a, 10); //setServiceDate(service); //setTreatmentTime(750); /*MFG_DATA_T test; char sys[7] = {'A', 'B', 'C', 'D', '3', '6', '7'}; char hw[5] = {'3', '4', '5', '6', '7'}; char date[10]={'2', '0', '2', '0','-', '0', '3','-', '0', '5'}; memcpy ( test.SYSSerialNumber, sys, 7 ); memcpy ( test.HWSerialNumber, hw, 5 ); memcpy ( test.mfgDate, date, 10 ); setMfgData(test);*/ // TODO: REMOVE THIS CODE 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() ) { dequeue(); NVDATAMGMT_OPERATION_STATE_T ops = currentJob.memoryOperation; NVDATAMGMT_LOCATION_STATE_T location = currentJob.memoryLocation; U32* startAddress = currentJob.startAddress; U32 length = currentJob.length; if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM ) { currentTime = getMSTimerCount(); Fapi_issueProgrammingCommand ( startAddress, currentJob.buffer, length, 0x00, 0, Fapi_DataOnly ); state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; } else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_EEPROM ) { currentTime = getMSTimerCount(); Fapi_doMarginRead ( startAddress, (U32*)( currentJob.externalAddress->externalBuffer ), length, Fapi_NormalRead ); // Change the status to in progress until the read operation is done currentJob.externalAddress->status = NVDATAMGMT_READ_IN_PROGRESS; state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; } else if ( ops == NVDATAMGMT_ERASE_SECTOR ) { currentTime = getMSTimerCount(); Fapi_issueAsyncCommandWithAddress ( Fapi_EraseSector, startAddress ); state = NVDATAMGMT_EXEC_STATE_ERASE_EEPROM; } else if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_RTC ) { if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { currentTime = getMSTimerCount(); writeToRAM ( (U32)startAddress, currentJob.buffer, length ); } state = NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC; } else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_RTC ) { if ( getRTCRAMState() == RTC_RAM_STATE_READY ) { currentTime = getMSTimerCount(); readFromRAM( (U32)startAddress, length ); currentJob.externalAddress->status = NVDATAMGMT_READ_IN_PROGRESS; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { currentJob.externalAddress->status = NVDATAMGMT_READ_COMPLETE; state = NVDATAMGMT_EXEC_STATE_IDLE; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady || timeoutStatus == TRUE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } 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; BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_RTC_RAM_OPS_ERROR, (U08*)&state ); if ( getRTCRAMStatus() == RTC_RAM_STATUS_IDLE || timeoutStatus == TRUE ) { getDataFromRAM( currentJob.externalAddress->externalBuffer, currentJob.length ); currentJob.externalAddress->status = NVDATAMGMT_READ_COMPLETE; state = NVDATAMGMT_EXEC_STATE_IDLE; } return state; } /************************************************************************* * @brief setMemoryOpsStruct * The setMemoryOpsStruct fills up the job struct * @details * Inputs : NVDATAMGMT_OPERATION_STATE_T (ops), NVDATAMGMT_LOCATION_STATE_T * (location), U32 (startAddress), U08* (data), READ_DATA_T* (extAddress) * U32 (length) * Outputs : none * @param none * @return none *************************************************************************/ static void setMemoryOpsStruct ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, READ_DATA_T* extAddress, U32 length ) { U32 myAddIndex; _disable_IRQ(); myAddIndex = queueRearIndex; if ( FALSE == isQueueFull() ) { queueCount++; queueRearIndex = INC_WRAP( queueRearIndex, 0, QUEUE_MAX_SIZE - 1 ); } _enable_IRQ(); jobQueue [ myAddIndex ].memoryOperation = ops; jobQueue [ myAddIndex ].memoryLocation = location; jobQueue [ myAddIndex ].startAddress = (U32*)startAddress; jobQueue [ myAddIndex ].length = length; jobQueue [ myAddIndex ].externalAddress = extAddress; if ( extAddress == 0 ) { memcpy ( jobQueue [ myAddIndex ].buffer, data, length ); } } /************************************************************************* * @brief prepareWriteLogJobAndGetStartAddress * The prepareWriteLogJobAndGetStartAddress checks whether the next write * is at edge of the any of the sectors and if yes, it will update the log * header accordingly. If the write is not at the edge, it will prepare a * normal write to EEPROM job. * @details * Inputs : U08* (data) * Outputs : U32 (opsStartAddress) * @param none * @return U32 (opsStartAddress) *************************************************************************/ static U32 prepareWriteLogJobAndGetStartAddress ( U08* data ) { U32 modulus = 0; U32 opsStartAddress = 0; U16 readIndexChange = 0; U16 writeIndexChange = 0; U16 recordCountChange = 1; // 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.logHeader.nextWriteIndex * MAX_JOB_DATA_SIZE_BYTES ) + BANK7_SECTOR1_START_ADDRESS; modulus = logRecord.logHeader.nextWriteIndex % MAX_LOG_DATA_PER_SECTOR; // Modulus is 0 so it is at any of the edges if ( modulus == 0 ) { // If full (1536) // 1. set readIndexChange = +512 // 2. set recordCountchange = -512 if ( logRecord.logHeader.recordCount >= MAX_NUM_OF_DATA_LOGS_IN_SECTOR3 - 1 ) { logRecord.logHeader.recordCount = logRecord.logHeader.recordCount - MAX_LOG_DATA_PER_SECTOR; readIndexChange = MAX_LOG_DATA_PER_SECTOR; } setMemoryOpsStruct ( NVDATAMGMT_ERASE_SECTOR, NVDATAMGMT_EEPROM, opsStartAddress, 0, 0, 0 ); } // Check for wrap in 1536 which is at the end of sector 3 writeIndexChange = INC_WRAP( logRecord.logHeader.nextWriteIndex, LOG_DATA_START_INDEX, MAX_NUM_OF_DATA_LOGS_IN_SECTOR3 - 1 ); logRecord.logHeader.nextWriteIndex = writeIndexChange; logRecord.logHeader.recordCount = logRecord.logHeader.recordCount + recordCountChange; logRecord.logHeader.nextReadIndex = logRecord.logHeader.nextReadIndex + readIndexChange; // Calculate the CRC for the new record logRecord.crc = crc16 ( (U08*)&logRecord.logHeader, sizeof(LOG_HEADER_T) ); // Update the log record setMemoryOpsStruct ( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, LOG_RECORD_START_ADDRESS, (U08*)&logRecord, 0, sizeof(LOG_RECORD_T) ); return opsStartAddress; } /************************************************************************* * @brief prepareReadLogJobAndGetStartAddress * The prepareReadLogJobAndGetStartAddress prepares a read from the specified * address of the EEPROM. * @details * Inputs : none * Outputs : U32 (opsStartAddress) * @param none * @return U32 (opsStartAddress) *************************************************************************/ static U32 prepareReadLogJobAndGetStartAddress ( void ) { // 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.logHeader.nextReadIndex * MAX_JOB_DATA_SIZE_BYTES ) + BANK7_SECTOR1_START_ADDRESS; U16 readIndexChange = INC_WRAP( logRecord.logHeader.nextReadIndex, LOG_DATA_START_INDEX, MAX_NUM_OF_DATA_LOGS_IN_SECTOR3 - 1 ); logRecord.logHeader.nextReadIndex = readIndexChange; logRecord.crc = crc16 ( (U08*)&logRecord.logHeader, sizeof(LOG_RECORD_T) ); // Update the log record setMemoryOpsStruct ( NVDATAMGMT_WRITE, NVDATAMGMT_RTC, LOG_RECORD_START_ADDRESS, (U08*)&logRecord, 0, 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 : NVDATAMGMT_OPERATION_STATE_T (ops), NVDATAMGMT_LOCATION_STATE_T * (location), U32 (startAddress), U08* (data), READ_DATA_T* (extAddress) * U32 (length) * Outputs : none * @param none * @return none *************************************************************************/ static void enqueue ( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, U32 startAddress, U08* data, READ_DATA_T* extAddress, U32 length ) { U32 quotient = 0; U32 modulus = 0; U32 maxBufferLength = length; U32 opsStartAddress = startAddress; U08 i; // Setup EEPROM write log event if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM ) { maxBufferLength = MAX_EEPROM_WRITE_BUFFER_BYTES; if ( startAddress == 0 ) { opsStartAddress = prepareWriteLogJobAndGetStartAddress ( data ); } } // Setup EEPROM read log event else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_EEPROM ) { if ( startAddress == 0 ) { opsStartAddress = prepareReadLogJobAndGetStartAddress(); } } // Maximum length for write is 16 bytes // Maximum length for read is 32 bytes // If the length is greater than the specified max lengths, // the operation will be broken into multiple pieces if ( length > maxBufferLength ) { quotient = length / maxBufferLength; modulus = length % maxBufferLength; for ( i = 0; i < quotient; i++ ) { setMemoryOpsStruct ( ops, location, ( opsStartAddress + ( i * maxBufferLength ) ), data + ( i * maxBufferLength ), extAddress, maxBufferLength ); } if ( modulus != 0 ) { setMemoryOpsStruct ( ops, location, ( opsStartAddress + ( quotient * maxBufferLength ) ), data + ( quotient * maxBufferLength ), extAddress, modulus ); } } // The length is less than maximum specified, normal operations else { setMemoryOpsStruct ( ops, location, opsStartAddress, data, extAddress, 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 ) { U32 tempIndex; _disable_IRQ(); tempIndex = queueFrontIndex; if ( FALSE == isQueueFull() ) { queueFrontIndex = INC_WRAP( queueFrontIndex, 0, QUEUE_MAX_SIZE - 1 ); } _enable_IRQ(); currentJob = jobQueue [ tempIndex ]; 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 : isEmpty (BOOL) * @param none * @return isEmpty (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 : isFull (BOOL) * @param none * @return isFull (BOOL) *************************************************************************/ static BOOL isQueueFull ( void ) { BOOL isFull = FALSE; if ( queueCount >= QUEUE_MAX_SIZE - 1 ) { isFull = TRUE; } return isFull; } /************************************************************************* * @brief getAvailableQueueCount * The getAvailableQueueCount returns the number of available queues left * @details * Inputs : none * Outputs : U32 * @param none * @return U32 *************************************************************************/ static U32 getAvailableQueueCount ( void ) { return QUEUE_MAX_SIZE - queueCount - 1; } /************************************************************************* * @brief enqueueBank7Sector0Records * The enqueueBank7Sector0Records checks whether there are enough number of * queues for erasing and setting the records. If there are enough queues, * it schedules an erase job and then schdules jobs to write all the records * back to Bank 7 Sector 0 * @details * Inputs : none * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ static BOOL enqueueBank7Sector0Records( void ) { BOOL status = FALSE; U32 currentQueueCount = getAvailableQueueCount(); if ( currentQueueCount >= MIN_QUEUE_COUNT_FOR_SECTOR_0 ) { // Sector 0 must be erased first enqueue ( NVDATAMGMT_ERASE_SECTOR, NVDATAMGMT_EEPROM, BANK7_SECTOR0_START_ADDRESS, 0, 0, 0 ); enqueue ( NVDATAMGMT_WRITE, NVDATAMGMT_EEPROM, BANK7_SECTOR0_START_ADDRESS, (U08*)&mfgRecord, 0, sizeof(MFG_RECORD_T) ); enqueue ( NVDATAMGMT_WRITE, NVDATAMGMT_EEPROM, CALIBRATION_RECORD_START_ADDRESS, (U08*)&calibrationRecord, 0, sizeof(CALIBRATION_RECORD_T) ); status = TRUE; } return status; } /************************************************************************* * @brief didCommandTimedout * The didCommandTimedout checks whether the a command whether RTC RAM or * EEPROM has timedout. If it has timedout, it sets the alarm and turns * flag to TRUE * @details * Inputs : ALARM_ID_T (alarm), U08* state (pointer to the state) * Outputs : BOOL * @param none * @return BOOL *************************************************************************/ static BOOL didCommandTimeout ( ALARM_ID_T alarm, U08* state ) { /* * NOTE: The state is a pointer so it can cover both the self test * states and exec states */ BOOL status = FALSE; if ( didTimeout( currentTime, COMMAND_TIME_OUT ) ) { SET_ALARM_WITH_2_U32_DATA( alarm, *state, 0 ); hasCommandTimedout = TRUE; status = TRUE; } return status; }