Index: NVDataMgmt.c =================================================================== diff -u -r54f132e07512bf9de8db4e16e028b11503787c83 -r4028a21bd9b05a212f4bb33db6631cd6012ff170 --- NVDataMgmt.c (.../NVDataMgmt.c) (revision 54f132e07512bf9de8db4e16e028b11503787c83) +++ NVDataMgmt.c (.../NVDataMgmt.c) (revision 4028a21bd9b05a212f4bb33db6631cd6012ff170) @@ -123,6 +123,7 @@ NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST = 0, ///< Exec state wait for POST. NVDATAMGMT_EXEC_STATE_IDLE, ///< Exec state Idle. NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM, ///< Exec state write to EEPROM. + NVDATAMGMT_EXEC_STATE_VERIFY_WRITE, ///< Exec state verify write (EEPROM and RTC RAM). NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM, ///< Exec state read from EEPROM. NVDATAMGMT_EXEC_STATE_ERASE_EEPROM, ///< Exec state erase EEPROM. NVDATAMGMT_EXEC_STATE_WRITE_TO_RTC, ///< Exec state write to RTC. @@ -175,6 +176,15 @@ NUM_OF_NVDATMGMT_RECORDS_JOBS ///< Number of NVDataMgmt records jobs. } RECORD_JOBS_STATE_T; +/// NVDataMgmt write record validity check states +typedef enum NVDataMgmt_Write_Record_Validity_Check +{ + NVDATAMGMT_RECORD_NOT_CHECKED = 0, ///< NVDataMgmt (written) record not checked. + NVDATAMGMT_RECORD_VALID, ///< NVDataMgmt record is valid. + NVDATAMGMT_RECORD_NOT_VALID, ///< NVDataMgmt record is not valid. + NUM_OF_NVDATAMGMT_RECORD_VALIDITY_CHECK ///< Number of NVDataMgmt validity check states. +} RECORD_VALIDITY_CHECK_T; + #pragma pack(push, 1) /// Process records specifications structure typedef struct @@ -316,19 +326,20 @@ DG_RO_PUMP_PAYLOAD_T roPump; ///< RO pump ratios (unknown for now) } DG_PUMPS_CAL_RECORD_T; +// TODO add more calibration data /// DG calibration records structure typedef struct { - DG_PRES_SENSORS_CAL_RECORD_T presSensorsCalRecord; ///< DG pressure sensors - DG_FLOW_SENSORS_CAL_RECORD_T flowSensorsCalRecord; ///< DG flow sensors - DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< DG load cells - DG_TEMP_SENSORS_CAL_RECORD_T tempSensorsCalRecord; ///< DG temperature sensors - DG_COND_SENSORS_CAL_RECORD_T condSensorsCalRecord; ///< DG conductivity sensors - //DG_PUMPS_CAL_RECORD_T pumpsCalRecord; ///< DG pumps + DG_PRES_SENSORS_CAL_RECORD_T presSensorsCalRecord; ///< DG pressure sensors. + DG_FLOW_SENSORS_CAL_RECORD_T flowSensorsCalRecord; ///< DG flow sensors. + DG_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< DG load cells. + DG_TEMP_SENSORS_CAL_RECORD_T tempSensorsCalRecord; ///< DG temperature sensors. + DG_COND_SENSORS_CAL_RECORD_T condSensorsCalRecord; ///< DG conductivity sensors. + //DG_PUMPS_CAL_RECORD_T pumpsCalRecord; ///< DG pumps. U08 padding[ 0x270 - ( sizeof(DG_PRES_SENSORS_CAL_RECORD_T) + sizeof(DG_FLOW_SENSORS_CAL_RECORD_T) + sizeof(DG_LOAD_CELLS_CAL_RECORD_T) + sizeof(DG_TEMP_SENSORS_CAL_RECORD_T) + - sizeof(DG_COND_SENSORS_CAL_RECORD_T) + sizeof(U16) ) ]; ///< DG calibration record padding - U16 crc; ///< CRC for the DG cal record structure + sizeof(DG_COND_SENSORS_CAL_RECORD_T) + sizeof(U16) ) ]; ///< DG calibration record padding. + U16 crc; ///< CRC for the DG cal record structure. } DG_CALIBRATION_RECORD_T; typedef struct @@ -368,28 +379,30 @@ static U08 recordQueueCount; ///< Record queue count. static PROCESS_RECORD_JOB_T recordCurrentJob; ///< Record queue current job. static U32 recordAddressOffset; ///< Record address offset. +static RECORD_VALIDITY_CHECK_T writtenRecordStatus; ///< Record data write validity check. +static U08 writtenRecordCheckBuffer[ MAX_EEPROM_WRITE_BUFFER_BYTES ]; ///< Written record validity check buffer. // Private variables -static MEMORY_LOG_OPS_T jobQueue [ QUEUE_MAX_SIZE ]; ///< Job queue buffer -static MEMORY_LOG_OPS_T currentJob; ///< Current job -static LOG_RECORD_T logRecord; ///< Log record variable -static TREATMENT_TIME_RECORD_T treatmentTimeRecord; ///< Treatment time record -static WATER_CONSUMPTION_RECORD_T waterConsumptionRecord; ///< Water consumption record -static MFG_RECORD_T mfgRecord; ///< Manufacturing record -static CALIBRATION_RECORD_T calibrationRecord; ///< Calibration record -static SERVICE_RECORD_T serviceRecord; ///< Service record -static LAST_DISINFECTION_RECORD_T lastDisinfectionRecord; ///< Disinfection record -static U08 queueRearIndex = QUEUE_START_INDEX; ///< Queue rear index -static U08 queueFrontIndex = QUEUE_START_INDEX; ///< Queue front index -static U08 queueCount = 0; ///< Queue count -static NVDATAMGMT_SELF_TEST_STATE_T NVDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_START; ///< NVDataMgmt self-test state variable -static NVDATAMGMT_EXEC_STATE_T NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; ///< NVDataMgmt exec state variable -static SELF_TEST_STATUS_T NVDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; ///< NVDataMgmt self-test result -static U32 bootloaderFlag = 0; ///< Bootloader flag -static BOOL hasCommandTimedout = FALSE; ///< Boolean flag for timeout of the commands -static U32 currentTime = 0; ///< Current time -static BOOL calRecordIsValid = FALSE; ///< Flag indicates whether stored calibration record was found to be valid -static volatile BOOL powerOffIsImminent = FALSE; ///< Power off warning has been signaled. Non-volatile memory operations should be completed ASAP and then ceased +static MEMORY_LOG_OPS_T jobQueue [ QUEUE_MAX_SIZE ]; ///< Job queue buffer. +static MEMORY_LOG_OPS_T currentJob; ///< Current job. +static LOG_RECORD_T logRecord; ///< Log record variable. +static TREATMENT_TIME_RECORD_T treatmentTimeRecord; ///< Treatment time record. +static WATER_CONSUMPTION_RECORD_T waterConsumptionRecord; ///< Water consumption record. +static MFG_RECORD_T mfgRecord; ///< Manufacturing record. +static CALIBRATION_RECORD_T calibrationRecord; ///< Calibration record. +static SERVICE_RECORD_T serviceRecord; ///< Service record. +static LAST_DISINFECTION_RECORD_T lastDisinfectionRecord; ///< Disinfection record. +static U08 queueRearIndex = QUEUE_START_INDEX; ///< Queue rear index. +static U08 queueFrontIndex = QUEUE_START_INDEX; ///< Queue front index. +static U08 queueCount = 0; ///< Queue count. +static NVDATAMGMT_SELF_TEST_STATE_T NVDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_START; ///< NVDataMgmt self-test state variable. +static NVDATAMGMT_EXEC_STATE_T NVDataMgmtExecState = NVDATAMGMT_EXEC_STATE_WAIT_FOR_POST; ///< NVDataMgmt exec state variable. +static SELF_TEST_STATUS_T NVDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; ///< NVDataMgmt self-test result. +static U32 bootloaderFlag = 0; ///< Bootloader flag. +static BOOL hasCommandTimedout = FALSE; ///< Boolean flag for timeout of the commands. +static U32 currentTime = 0; ///< Current time. +static BOOL calRecordIsValid = FALSE; ///< Flag indicates whether stored calibration record was found to be valid. +static volatile BOOL powerOffIsImminent = FALSE; ///< Power off warning has been signaled. Non-volatile memory operations should be completed ASAP and then ceased. // *** This declaration will cause a compiler error if CALIBRATION_DATA_T record size exceeds max message payload size. U08 calRecordSizeAssertion[ ( sizeof( CALIBRATION_DATA_T ) <= MAX_MSG_PAYLOAD_SIZE ? 1 : -1 ) ]; @@ -411,6 +424,7 @@ 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 handleExecVerifyWriteState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecReadFromEEPROMState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecWriteToRAMState ( void ); static NVDATAMGMT_EXEC_STATE_T handleExecReadFromRAMState ( void ); @@ -464,6 +478,7 @@ recordQueueFrontIndex = QUEUE_START_INDEX; recordQueueCount = 0; recordAddressOffset = 0; + writtenRecordStatus = NVDATAMGMT_RECORD_NOT_CHECKED; Fapi_initializeFlashBanks( ROUNDED_HCLK_FREQ ); Fapi_setActiveFlashBank( Fapi_FlashBank7 ); @@ -527,6 +542,11 @@ NVDataMgmtExecState = handleExecWriteToEEPROMState(); break; + case NVDATAMGMT_EXEC_STATE_VERIFY_WRITE: + + NVDataMgmtExecState = handleExecVerifyWriteState(); + break; + case NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM: NVDataMgmtExecState = handleExecReadFromEEPROMState(); @@ -1607,7 +1627,7 @@ U32 startAddress; U08* bufferAddress; U32 maxBufferLength; - BOOL isThereJob = FALSE; + BOOL areQueuesEmpty = FALSE; // If the record processing queue is not empty, process the queues if ( !isRecordQueueEmpty() ) @@ -1618,19 +1638,17 @@ PROCESS_RECORD_SPECS_T jobSpecs = RECORDS_SPECS [ job ]; // Set the record address offset to 0 since a job will just be started recordAddressOffset = 0; - isThereJob = TRUE; + areQueuesEmpty = TRUE; ops = recordCurrentJob.memoryOperation; location = recordCurrentJob.memoryLocation; currentTime = getMSTimerCount(); startAddress = jobSpecs.startAddress + recordAddressOffset; bufferAddress = (U08*)&dgCalibrationRecord + recordAddressOffset; maxBufferLength = jobSpecs.maxBufferSize; - // Current start address was updated. Update the offset - recordAddressOffset += jobSpecs.maxBufferSize; } // Check if a queue job is available - if ( isThereJob ) + if ( areQueuesEmpty ) { if ( ops == NVDATAMGMT_ERASE_SECTOR ) { @@ -1639,22 +1657,17 @@ } else if ( ops == NVDATAMGMT_WRITE && location == NVDATAMGMT_EEPROM ) { - // TODO remove - //U32* memoryPtr = (U32*)jobSpecs.startAddress + recordAddressOffset; - //U08* structPtr = (U08*)&dgCalibrationRecord + recordAddressOffset; - Fapi_issueProgrammingCommand ( (U32*)startAddress, (U08*)bufferAddress, maxBufferLength, 0x00, 0, Fapi_DataOnly ); state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; } else if ( ops == NVDATAMGMT_READ && location == NVDATAMGMT_EEPROM ) { - U08 test[100]; - memcpy(test, &dgCalibrationRecord, 100); Fapi_doMarginRead ( (U32*)startAddress, (U32*)bufferAddress, maxBufferLength, Fapi_NormalRead ); - BOOL test2 = FALSE; + state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; } } + // TODO clean up // Check if the queue is not empty and the calibration/service status is none // Processing calibration and service status have priority /*if ( !isQueueEmpty() ) @@ -1712,40 +1725,119 @@ /*********************************************************************//** * @brief - * 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 - * @details Outputs: none - * @return next state + * The handleExecWriteToEEPROMState issues a write command to EEPROM and + * if the write was successful, it sets the state to Idle. + * @details Inputs: recordAddressOffset, writtenRecordCheckBuffer, + * writtenRecordStatus + * @details Outputs: recordAddressOffset, writtenRecordCheckBuffer, + * writtenRecordStatus + * @return next state of the state machine *************************************************************************/ 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 ); + NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; + BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); RECORD_JOBS_STATE_T job = recordCurrentJob.recordJob; PROCESS_RECORD_SPECS_T jobSpecs = RECORDS_SPECS [ job ]; - if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady )//|| timeoutStatus == TRUE ) + // Check if the fapi has finished + if ( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) { - if ( jobSpecs.sizeofJob == recordAddressOffset ) + // Check the integrity of data (the 16 bytes that were written to EEPROM should be read and be checked for each byte) + if ( writtenRecordStatus == NVDATAMGMT_RECORD_NOT_CHECKED ) { - state = NVDATAMGMT_EXEC_STATE_IDLE; + currentTime = getMSTimerCount(); + U32 startAddress = jobSpecs.startAddress + recordAddressOffset; + + // Clear the buffer from the previous content + memset( writtenRecordCheckBuffer, 0, sizeof(writtenRecordCheckBuffer)); + + // Issue a FAPI read command + Fapi_doMarginRead ( (U32*)startAddress, (U32*)writtenRecordCheckBuffer, jobSpecs.maxBufferSize, Fapi_NormalRead ); + + state = NVDATAMGMT_EXEC_STATE_VERIFY_WRITE; } - /*else if ( timeoutStatus == TRUE ) + else if ( writtenRecordStatus == NVDATAMGMT_RECORD_VALID ) { - // TODO schedule another write - recordAddressOffset = 0; - state = NVDATAMGMT_EXEC_STATE_IDLE; - }*/ - else + // If the data is valid, and if it is at the end of the write, change to idle + if ( jobSpecs.sizeofJob == recordAddressOffset ) + { + state = NVDATAMGMT_EXEC_STATE_IDLE; + } + else + { + // Update the variables and issue the next write command + currentTime = getMSTimerCount(); + recordAddressOffset += jobSpecs.maxBufferSize; + U32 memoryPtr = jobSpecs.startAddress + recordAddressOffset; + U08* structPtr = (U08*)&dgCalibrationRecord + recordAddressOffset; + writtenRecordStatus = NVDATAMGMT_RECORD_NOT_CHECKED; + + Fapi_issueProgrammingCommand ( (U32*)memoryPtr, structPtr, jobSpecs.maxBufferSize, 0x00, 0, Fapi_DataOnly ); + } + } + } + // If timed out, get back to Idle + else if ( timeoutStatus == TRUE ) + { + // TODO schedule another write? + recordAddressOffset = 0; + state = NVDATAMGMT_EXEC_STATE_IDLE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleExecVerifyWriteState checks all the bytes that were written + * to either EEPROM or RTC RAM to ensure they match the data in the RAM. + * @details Inputs: recordAddressOffset + * @details Outputs: recordAddressOffset + * @return next state of the state machine + *************************************************************************/ +static NVDATAMGMT_EXEC_STATE_T handleExecVerifyWriteState ( void ) +{ + NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_VERIFY_WRITE; + BOOL timeoutStatus = didCommandTimeout ( ALARM_ID_NVDATA_EEPROM_OPS_FAILURE, (U08*)&state ); + RECORD_JOBS_STATE_T job = recordCurrentJob.recordJob; + PROCESS_RECORD_SPECS_T jobSpecs = RECORDS_SPECS [ job ]; + + // Check if the write job is EEPROM or RTC RAM + if ( recordCurrentJob.memoryLocation == NVDATAMGMT_EEPROM && FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmReady ) + { + // Check if the job is write calibration or system record + if ( job == NVDATAMGMT_WRITE_DG_CALIBRATION_RECORD ) { - currentTime = getMSTimerCount(); - U32 memoryPtr = jobSpecs.startAddress + recordAddressOffset; - U08* structPtr = (U08*)&dgCalibrationRecord; - structPtr += recordAddressOffset; + U32 i; + // Set the buffer pointer to beginning of the bytes that were written and needs to be checked + U08* bufferPtr = (U08*)&dgCalibrationRecord + recordAddressOffset; - Fapi_issueProgrammingCommand ( (U32*)memoryPtr, structPtr, jobSpecs.maxBufferSize, 0x00, 0, Fapi_DataOnly ); - recordAddressOffset += jobSpecs.maxBufferSize; + // Loop through the bytes in the buffer + for ( i = 0; i < jobSpecs.maxBufferSize; i++ ) + { + // Check if data in the buffer is not the same as the data in the structure + if ( writtenRecordCheckBuffer[ i ] != *bufferPtr ) + { + // Data is not valid. Schedule an erase and write of the calibration record since only a part of + // data cannot be written to EEPROM. + writtenRecordStatus = NVDATAMGMT_RECORD_NOT_VALID; + enqueueRecordJob( NVDATAMGMT_ERASE_SECTOR, NVDATAMGMT_EEPROM, NVDATAMGMT_WRITE_DG_CALIBRATION_RECORD ); + enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_EEPROM, NVDATAMGMT_WRITE_DG_CALIBRATION_RECORD ); + state = NVDATAMGMT_EXEC_STATE_IDLE; + // Exit the loop since there is no point to check the rest of data + break; + } + else + { + // Everything is good increment the pointer to check the next byte. + bufferPtr++; + // Record data is valid so far + writtenRecordStatus = NVDATAMGMT_RECORD_VALID; + // Go back write to EEPROM state to continue writing the record data + state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; + } + } } } @@ -2294,6 +2386,17 @@ return status; } +/*********************************************************************//** + * @brief + * 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: queueFrontIndex, queueCount + * @details Outputs: queueFrontIndex, queueCount + * @param ops: memory operation (i.e write, read) + * @param location: memory location which are either EEPROM or RTC RAM + * @param job: type of job (i.e write calibration data) + * @return none + *************************************************************************/ static void enqueueRecordJob( NVDATAMGMT_OPERATION_STATE_T ops, NVDATAMGMT_LOCATION_STATE_T location, RECORD_JOBS_STATE_T job ) { PROCESS_RECORD_JOB_T currentJob; @@ -2305,9 +2408,18 @@ recordJobQueue[ recordQueueRearIndex ] = currentJob; recordQueueCount++; - recordQueueRearIndex++; + recordQueueRearIndex = INC_WRAP( recordQueueRearIndex, 0, QUEUE_MAX_SIZE - 1 ); } +/*********************************************************************//** + * @brief + * The dequeueRecordJob 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: recordQueueFrontIndex, recordQueueCount, recordCurrentJob, + * recordJobQueue + * @details Outputs: recordQueueFrontIndex, recordQueueCount, recordCurrentJob + * @return none + *************************************************************************/ static void dequeueRecordJob( void ) { U32 tempIndex; @@ -2327,6 +2439,14 @@ _enable_IRQ(); } +/*********************************************************************//** + * @brief + * The isRecordQueueEmpty checks whether the queue is empty and if it is empty, + * it will return a false. + * @details Inputs: recordQueueCount + * @details Outputs: none + * @return TRUE if queue is not empty + *************************************************************************/ static BOOL isRecordQueueEmpty( void ) { BOOL isEmpty = TRUE;