/************************************************************************** * * Copyright (c) 2026-2027 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 NVMgmtDD.c * * @author (original) Arpita Srivastava * @date (original) 31-Mar-2026 * ***************************************************************************/ #include // For memcpy #include "NVDriver.h" #include "NVMgmtDD.h" #include "NVMsgQ.h" #include "NVRecordsDD.h" /// NVDataMgmt Exec states enumeration. typedef enum NVDataMgmt_Exec_State { NVDATAMGMT_EXEC_STATE_IDLE = 0, ///< Exec state Idle. NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM, ///< Exec state write to EEPROM. NVDATAMGMT_EXEC_STATE_VERIFY_EEPROM_WRITE, ///< Exec state verify EEPROM write. NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM, ///< Exec state read from EEPROM. NVDATAMGMT_EXEC_STATE_ERASE_EEPROM, ///< Exec state erase EEPROM. NUM_OF_NVDATAMGMT_EXEC_STATES ///< Total number of exec states. } NVDATAMGMT_EXEC_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; #define COMMAND_TIME_OUT (1 * MS_PER_SECOND) ///< Timeout for an EEPROM or RTC command in ms. static NVDATAMGMT_EXEC_STATE_T nvDataMgmtExecState; ///< NVDataMgmt exec state variable. static volatile BOOL powerOffIsImminent; ///< Power off warning has been signaled. Non-volatile memory operations should be completed ASAP and then ceased. static RECORD_VALIDITY_CHECK_T writtenRecordStatus; ///< Record data write validity check. static U08 writtenRecordCheckBuffer[ MAX_EEPROM_WRITE_BUFFER_BYTES ]; ///< Written record validity check buffer. static U32 currentTime; ///< Current time. // Exec functions 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 handleExecVerifyEEPROMWriteState( void ); // Helper functions static BOOL didCommandTimeout( NVDATAMGMT_EXEC_STATE_T state ); void initNVMgmtDD( void ) { nvDataMgmtExecState = NVDATAMGMT_EXEC_STATE_IDLE; powerOffIsImminent = FALSE; currentTime = 0; writtenRecordStatus = NVDATAMGMT_RECORD_NOT_CHECKED; initNVDriver(); initNVMsgQ(); enqueuePOSTReadRecords(); } /*********************************************************************//** * @brief * The signalPowerOffWarning signals this module that system power off is * imminent and any non-volatile data writes in progress should be wrapped * up quickly and any pending non-volatile data writes should not be started. * @details Inputs: powerOffIsImminent * @details Outputs: powerOffIsImminent * @return none *************************************************************************/ void signalPowerOffWarning( void ) { powerOffIsImminent = TRUE; } /*********************************************************************//** * @brief * The execNVDataMgmt runs the NVDataMgmt main tasks. * @details Inputs: nvDataMgmtExecState * @details Outputs: nvDataMgmtExecState * @return none *************************************************************************/ void execNVDataMgmt( void ) { switch ( nvDataMgmtExecState ) { case NVDATAMGMT_EXEC_STATE_IDLE: nvDataMgmtExecState = handleExecIdleState(); break; case NVDATAMGMT_EXEC_STATE_ERASE_EEPROM: nvDataMgmtExecState = handleExecEraseState(); 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_VERIFY_EEPROM_WRITE: nvDataMgmtExecState = handleExecVerifyEEPROMWriteState(); break; default: // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATAMGMT_EXEC_INVALID_STATE, nvDataMgmtExecState ); nvDataMgmtExecState = NVDATAMGMT_EXEC_STATE_IDLE; break; } } /*********************************************************************//** * @brief * The handleExecIdleState checks if the queue is empty and if it is not * empty, it sets the state of the job. * @details Inputs: powerOffIsImminent * @details Outputs: none * @return next state *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecIdleState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_IDLE; BOOL areQueuesNotEmpty = FALSE; NVDATAMGMT_OPERATION_STATE_T ops; U32 startAddress; U08* bufferAddress; // If power off command has been issued, do not process any new jobs if ( powerOffIsImminent != TRUE ) { // If the record processing queue is not empty, process the queues if ( ( FALSE == isRecordQueueEmpty() ) && ( TRUE == areResourcesAvailableForNextJob() ) ) { dequeueRecordJob(); RECORD_JOBS_STATE_T job = recordCurrentJob.recordJob; PROCESS_RECORD_SPECS_T jobSpecs = RECORDS_SPECS[ job ]; // Set the record address offset to 0 since a job will just be started recordAddressOffset = 0; areQueuesNotEmpty = TRUE; ops = recordCurrentJob.memoryOperation; currentTime = getMSTimerCount(); startAddress = jobSpecs.startAddress + recordAddressOffset; bufferAddress = jobSpecs.structAddressPtr + recordAddressOffset; } } // Check if a queue job is available if ( TRUE == areQueuesNotEmpty ) { switch ( ops ) { case NVDATAMGMT_ERASE_SECTOR: eraseSector( (U32*)startAddress ); state = NVDATAMGMT_EXEC_STATE_ERASE_EEPROM; break; case NVDATAMGMT_WRITE: writeSector( (U32*)startAddress, (U08*)bufferAddress, jobSpecs.maxWriteBufferSize ); currentTime = getMSTimerCount(); state = NVDATAMGMT_EXEC_STATE_WRITE_TO_EEPROM; break; case NVDATAMGMT_READ: readSector( (U32*)startAddress, (U32*)bufferAddress, ( jobSpecs.maxReadBufferSize / EEPROM_OPS_SIZE_OF_CONVERTER ) ); currentTime = getMSTimerCount(); state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; break; default: break; } } return state; } /*********************************************************************//** * @brief * 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 * @details Outputs: none * @return next state *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecEraseState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_ERASE_EEPROM; BOOL timeoutStatus = didCommandTimeout( state ); if ( TRUE == isFlashReady() || timeoutStatus == TRUE ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } return state; } /*********************************************************************//** * @brief * 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( state ); RECORD_JOBS_STATE_T job = recordCurrentJob.recordJob; PROCESS_RECORD_SPECS_T jobSpecs = RECORDS_SPECS [ job ]; // Check if the fapi has finished if ( TRUE == isFlashReady() ) { // 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 ) { currentTime = getMSTimerCount(); U32 startAddress = jobSpecs.startAddress + recordAddressOffset; U32 maxBufferLength = jobSpecs.maxWriteBufferSize / EEPROM_OPS_SIZE_OF_CONVERTER; // Clear the buffer from the previous content memset( writtenRecordCheckBuffer, 0, sizeof( writtenRecordCheckBuffer ) ); // Issue a FAPI read command but only the bytes that were written, so use maxWriteBufferSize readSector( (U32*)startAddress, (U32*)writtenRecordCheckBuffer, maxBufferLength ); state = NVDATAMGMT_EXEC_STATE_VERIFY_EEPROM_WRITE; } else if ( writtenRecordStatus == NVDATAMGMT_RECORD_VALID ) { // 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.maxWriteBufferSize; U32 memoryPtr = jobSpecs.startAddress + recordAddressOffset; U08* structPtr = jobSpecs.structAddressPtr + recordAddressOffset; writtenRecordStatus = NVDATAMGMT_RECORD_NOT_CHECKED; // Issue the write command writeSector( (U32*)memoryPtr, structPtr, jobSpecs.maxWriteBufferSize ); } } } // If timed out, get back to Idle else if ( timeoutStatus == TRUE ) { recordAddressOffset = 0; state = NVDATAMGMT_EXEC_STATE_IDLE; } return state; } /*********************************************************************//** * @brief * 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 * @details Outputs: None * @return next state *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecReadFromEEPROMState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_READ_FROM_EEPROM; BOOL timeoutStatus = didCommandTimeout( state ); if ( ( TRUE == isFlashReady() ) || ( TRUE == timeoutStatus ) ) { state = NVDATAMGMT_EXEC_STATE_IDLE; } return state; } /*********************************************************************//** * @brief * The handleExecVerifyEEPROMWriteState checks all the bytes that were * written to EEPROM to ensure they match the data in the NV memory. * @details Inputs: recordAddressOffset, writtenRecordCheckBuffer, * writtenRecordStatus * @details Outputs: recordAddressOffset, writtenRecordCheckBuffer, * writtenRecordStatus * @return next state of the state machine *************************************************************************/ static NVDATAMGMT_EXEC_STATE_T handleExecVerifyEEPROMWriteState ( void ) { NVDATAMGMT_EXEC_STATE_T state = NVDATAMGMT_EXEC_STATE_VERIFY_EEPROM_WRITE; BOOL timeoutStatus = didCommandTimeout( 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 ( TRUE == isFlashReady() ) { U32 i; U08* bufferPtr = jobSpecs.structAddressPtr + recordAddressOffset; // Loop through the bytes in the buffer for ( i = 0; i < jobSpecs.maxWriteBufferSize; 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_CALIBRATION_RECORD ); enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_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; } } } return state; } /*********************************************************************//** * @brief * The resetNVDataMgmtPOSTState function resets the NV data management POST * state and enqueues all the NV records to be read again from the NV memory. * @details Inputs: none * @details Outputs: nvDataMgmtSelfTestState, nvDataMgmtSelfTestResult * @return none *************************************************************************/ void resetNVDataMgmtPOSTState( void ) { nvDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; nvDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS; } /*********************************************************************//** * @brief * The getNVRecord2Driver function copies the requested non-volatile * data into the provided buffer by the caller. The function then checks if * the non-volatile data is valid. If the data is not valid, it raises the * provided alarm by the caller. * @details Inputs: ddCalibrationRecord * @details Outputs: ddCalibrationRecord * @param nvData the non-volatile data to be copied * @param bufferAddress the address of the provided buffer by the caller * @param bufferLength the length of the provided buffer by the caller * @param numOfSnsrs2Check the number of sensors to check in a array of sensors called * @param nvAlarm the corresponding alarm of the non-volatile data to be raised * if the data is not valid * @return TRUE if the non-volatile data is valid otherwise, FALSE *************************************************************************/ BOOL getNVRecord2Driver( NV_DATA_T nvData, U08* bufferAddress, U32 bufferLength, U08 numOfSnsrs2Check, ALARM_ID_T nvAlarm ) { U08 i; U08* nvDataStartPtr = 0; BOOL isNVDataInvalid = FALSE; U32 nvDataLength = 0; switch ( nvData ) { case GET_CAL_PRESSURE_SENOSRS: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.presSensorsCalRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.presSensorsCalRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.presSensorsCalRecord.pressureSensors[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_LOAD_CELL_SENSORS: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.loadCellsCalRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.loadCellsCalRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.loadCellsCalRecord.loadCells[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_FLOW_SENSORS: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.flowSensorsCalRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.flowSensorsCalRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.flowSensorsCalRecord.flowSensors[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_ACID_CONCENTREATES: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.acidConcentratesRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.acidConcentratesRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.acidConcentratesRecord.acidConcentrate[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_BICARB_CONCENTRATES: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.bicarbConcentratesRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.bicarbConcentratesRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.bicarbConcentratesRecord.bicarbConcentrate[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_ACCEL_SENSORS: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.accelerometerSensorCalRecord; isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.accelerometerSensorCalRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_TEMP_SENSORS: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.tempSensorsCalRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.tempSensorsCalRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.tempSensorsCalRecord.tempSensors[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_RSRVRS_VOL_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.reservoirVolumesRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.reservoirVolumesRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.reservoirVolumesRecord.reservoir[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_HEATING_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.heatingCalRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.heatingCalRecord ); isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.heatingCalRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_DRAIN_LINE_VOLUME_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.drainLineVolumeRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.drainLineVolumeRecord ); isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.drainLineVolumeRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_RO_PUMP_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.roPumpRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.roPumpRecord ); isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.roPumpRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_CONCENTRATE_PUMPS_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.concentratePumpsRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.concentratePumpsRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.concentratePumpsRecord.concentratePumps[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_DRAIN_PUMP_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.drainPumpRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.drainPumpRecord ); isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.drainPumpRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_FANS_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.fansRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.fansRecord ); for ( i = 0; i < numOfSnsrs2Check; i++ ) isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.fansRecord.fans[ i ].calibrationTime ? TRUE : FALSE ); break; case GET_CAL_PRE_RO_PURGE_VOLUME_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.preROPurgeVolumeRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.preROPurgeVolumeRecord ); isNVDataInvalid = ( 0 == ddCalibrationRecord.ddCalibrationGroups.preROPurgeVolumeRecord.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_FILTERS_RECORD: nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.filtersRecord; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.filtersRecord ); isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.filtersRecord.carbonFilter.calibrationTime ? TRUE : FALSE ); isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.filtersRecord.carbonPolishFilter.calibrationTime ? TRUE : FALSE ); isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.filtersRecord.roFilter.calibrationTime ? TRUE : FALSE ); isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.filtersRecord.sedimentFilter.calibrationTime ? TRUE : FALSE ); isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.filtersRecord.ultraFilter.calibrationTime ? TRUE : FALSE ); break; case GET_CAL_FILL_CONDUCTIVITIES_RECORD: { DG_FILL_COND_OPS_T fillOps; nvDataStartPtr = (U08*)&ddCalibrationRecord.ddCalibrationGroups.fillCondCalRecord.fillCondValues; nvDataLength = sizeof( ddCalibrationRecord.ddCalibrationGroups.fillCondCalRecord.fillCondValues ); for ( i = 0; i < numOfSnsrs2Check; i++ ) { for ( fillOps = FILL_COND_NORMAL_OP; fillOps < NUM_OF_FILL_COND_TEST; fillOps++ ) { isNVDataInvalid |= ( 0 == ddCalibrationRecord.ddCalibrationGroups.fillCondCalRecord.fillCondValues[ i ][ fillOps ].calibrationTime ? TRUE : FALSE ); } } } break; case GET_INF_HEATERS_RECORD: nvDataStartPtr = (U08*)&ddHeatersInfoGroup.ddHeatersInfo; nvDataLength = sizeof( ddHeatersInfoGroup.ddHeatersInfo ); break; case GET_SYS_RECORD: nvDataStartPtr = (U08*)&ddSystemGroup.ddSystemRecord; nvDataLength = sizeof( ddSystemGroup.ddSystemRecord ); break; case GET_SRV_RECORD: nvDataStartPtr = (U08*)&ddServiceGroup.ddServiceRecord; nvDataLength = sizeof( ddServiceGroup.ddServiceRecord ); break; case GET_SRR_RECORD: nvDataStartPtr = (U08*)&ddScheduledRunsGroup.ddScheduledRun; nvDataLength = sizeof( ddScheduledRunsGroup.ddScheduledRun ); break; case GET_USAGE_RECORD: nvDataStartPtr = (U08*)&ddUsageInfoGroup.ddUsageInfo; nvDataLength = sizeof( ddUsageInfoGroup.ddUsageInfo ); break; default: // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_NV_RECORD_SELECTED, nvData ); break; } // Make sure the provided buffer length is >= NV Data Length in the NV data management so the memory of the other variables is not // overridden. if ( ( bufferLength >= nvDataLength ) && ( nvDataStartPtr != 0 ) ) { // Copy the data into the provided buffer memcpy( bufferAddress, nvDataStartPtr, bufferLength ); } // Check if the non-volatile data is valid and if not raise the alarm if ( TRUE == isNVDataInvalid ) { // If no alarm has been provided to raise, just set the variable as TRUE if ( ALARM_ID_NO_ALARM == nvAlarm ) { isNVDataInvalid = FALSE; } else { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_CAL_CHECK ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( nvAlarm ); } #ifndef _RELEASE_ else { isNVDataInvalid = FALSE; } #endif } } // Reverse the polarity to signal the outside users that the calibration has passed. return ( FALSE == isNVDataInvalid ? TRUE : FALSE ); } #ifndef _RELEASE_ /*********************************************************************//** * @brief * The getSoftwareConfigStatus function returns the status of a software * configuration. * @details Inputs: swConfigsList * @details Outputs: none * @param config which is the configuration of the that its status is requested * @return status of the software configuration (0 or 1) *************************************************************************/ U08 getSoftwareConfigStatus( SOFTWARE_CONFIG_T config ) { U08 value = 0; // If the build is not a release, get the value from the software configurations list // If the build is a release, the configuration not matter what its value is kept in // the NV RAM, it returns a 0 which is the configuration is disabled value = ddSWConfigGroup.ddSWConfigsRecord.swConfigs[ config ]; return value; } #endif /*********************************************************************//** * @brief * 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: none * @details Outputs: alarm if command timed out * @param state the state that the command timed out * @return TRUE if a command timed out *************************************************************************/ static BOOL didCommandTimeout ( NVDATAMGMT_EXEC_STATE_T state ) { BOOL status = FALSE; if ( TRUE == didTimeout( currentTime, COMMAND_TIME_OUT ) ) { // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATA_MANAGEMENT_OPS_TIMEOUT, state ) status = TRUE; } return status; } /*********************************************************************//** * @brief * The testSetNVRecordCRCOverride overrides the non-volatile record CRC override. * @details Inputs: none * @details Outputs: none * @param job the job to override its CRC (i.e. calibration record) * @param crc the value its CRC to be overridden * @return TRUE if the job was scheduled successfully otherwise, FALSE *************************************************************************/ BOOL testSetNVRecordCRCOverride( U32 job, U16 crc ) { BOOL status = FALSE; RECORD_JOBS_STATE_T nvJob = (RECORD_JOBS_STATE_T)job; switch( nvJob ) { case NVDATAMGMT_CALIBRATION_RECORD: ddCalibrationRecord.crc = crc; status = enqueueSector0Records(); break; case NVDATAMGMT_SYSTEM_RECORD: ddSystemGroup.ddSystemRecord.crc = crc; status = enqueueSector0Records(); break; case NVDATAMGMT_SERVICE_RECORD: ddServiceGroup.ddServiceRecord.crc = crc; status = enqueueSector0Records(); break; case NVDATAMGMT_USAGE_INFO_RECORD: ddUsageInfoGroup.ddUsageInfo.crc = crc; if ( getAvailableRecordQueueCount() > 0 ) { enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_USAGE_INFO_RECORD ); status = TRUE; } break; } return status; }