/************************************************************************** * * 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 NVRecordsDD.c * * @author (original) Arpita Srivastava * @date (original) 31-Mar-2026 * ***************************************************************************/ #include // For memcpy #include "Common.h" #include "DDDefs.h" #include "NVMsgQ.h" #include "NVRecordsDD.h" #include "Timers.h" #include "Utilities.h" // For crc calculation /** * @addtogroup NVRecordsDD * @{ */ // ********** private definitions ********** #define RECORD_DEFAULT_TIME 0U ///< Record default time (calibration/set). #define RECORD_FOURTH_ORDER_COEFF 0.0F ///< Record fourth order coefficient. #define RECORD_THIRD_ORDER_COEFF 0.0F ///< Record third order coefficient. #define RECORD_SECOND_ORDER_COEFF 0.0F ///< Record second order coefficient. #define RECORD_DEFAULT_GAIN 1.0F ///< Record default gain. #define RECORD_DEFAULT_OFFSET 0.0F ///< Record default offset. #define RECORD_DEFAULT_CONST 0.0F ///< Record default constant. #define RECORD_DEFAULT_RATIO 1.0F ///< Record default ratio. #define RECORD_DEFAULT_SERVICE_INTERVAL_S 15768000U ///< Record default service interval in seconds (6 months). #define RECORD_DEFAULT_CHARACTER ' ' ///< Record default character. // DD specific defines #define DEFAULT_FLUSH_LINES_VOLUME_L 0.01F ///< Water volume to flush when starting re-circulate mode in liters. #define DEFAULT_BICARB_CONC_MIXING_RATIO ( 4.06812F / FRACTION_TO_PERCENT_FACTOR ) ///< Ratio between RO water and bicarbonate concentrate mixing ratio. #define DEFAULT_BICARB_BOTTLE_VOL_ML 3780.0F ///< Record default bicarb bottle volume in milliliters. #define DEFAULT_BICARB_COND_US_PER_CM 13734.88F ///< Record default acid conductivity in uS/cm. #define DEFAULT_BICARB_BOTTLE_TEMP_C 23.5F ///< Record default acid bottle temperature in C. #define DEFAULT_ACID_CONC_MIXING_RATIO ( 2.35618F / FRACTION_TO_PERCENT_FACTOR ) ///< Ratio between RO water and acid concentrate mixing ratio. #define DEFAULT_ACID_BOTTLE_VOL_ML 3430.0F ///< Record default acid bottle volume in milliliters. #define DEFAULT_ACID_COND_US_PER_CM 11645.05F ///< Record default acid conductivity in uS/cm. #define DEFAULT_ACID_BOTTLE_TEMP_C 23.5F ///< Record default acid bottle temperature in C. #define DEFAULT_RSRVR_TEMP_TAU_C_PER_MIN -0.25F ///< Reservoir temperature time constant C/min. #define DEFAULT_UF_TEMP_TAU_C_PER_MIN -0.6F ///< Ultrafilter temperature time constant C/min. #define DEFAULT_UF_VOLUME_ML 700 ///< Ultrafilter volume in milliliters. #define DEFAULT_FILL_1251_1_ACID_SNSR_US_PER_CM 0.0F ///< Fill acid 1251_1 acid sensor conductivity uS/cm. #define DEFAULT_FILL_1251_1_BIC_SNSR_US_PER_CM 13616.23F ///< Fill acid 1251_1 bicarb sensor conductivity uS/cm. #define DEFAULT_FILL_2251_0_ACID_SNSR_US_PER_CM 0.0F ///< Fill acid 2251_0 acid sensor conductivity uS/cm. #define DEFAULT_FILL_2251_0_BIC_SNSR_US_PER_CM 13734.88F ///< Fill acid 2251_0 bicarb sensor conductivity uS/cm. #define DEFAULT_FILL_3251_9_ACID_SNSR_US_PER_CM 0.0F ///< Fill acid 3251_9 acid sensor conductivity uS/cm. #define DEFAULT_FILL_3251_9_BIC_SNSR_US_PER_CM 13854.49F ///< Fill acid 3251_9 bicarb sensor conductivity uS/cm. #define DEFAULT_ACID_TEST_1251_1_US_PER_CM 13768.28F ///< Acid test acid 1251_1 acid conductivity uS/cm. #define DEFAULT_ACID_TEST_2251_0_US_PER_CM 13919.05F ///< Acid test acid 2251_0 acid conductivity uS/cm. #define DEFAULT_ACID_TEST_3251_9_US_PER_CM 14071.04F ///< Acid acid 3251_9 acid conductivity uS/cm. #define DEFAULT_BIC_TEST_ACID_SNSR_US_PER_CM 0.0F ///< Bicarb test acid sensor conductivity uS/cm. #define DEFAULT_BIC_TEST_BIC_SNSR_US_PER_CM 3890.0F ///< Bicarb test bicarb sensor conductivity uS/cm. #define MAX_NUM_OF_WRITE_TRIES 3U ///< Max number of write tries. #define RECORD_BYTE_SIZE(r) (sizeof(r) + sizeof(U16)) ///< Record byte size macro. // Padding length calculation: (DG struct size % bytes to write(16) == 0 ? 0 : ((DG struct size / bytes to write(16)) + 1) * bytes to write(16)) - DG struct size. // NOTE: assuming the macro is calculating the padding length for a non-volatile memory. For NV, 16 bytes is used and buffer and for the RTC RAM 64 bytes is used. // If the size of the structure + a 2-byte crc mod 16 is 0, then the size of the padding is 0 // Otherwise, the (((structure size + crc) / 16) + 1) * 16. In the calculations, a + 1 is added since the division has a decimal so + 1 is used // to round up. The result is then multiplied by 16 bytes to get the number of bytes needed and is subtracted from the size of the structure and CRC. #define RECORD_PADDING_LENGTH(rcrd, buf) (RECORD_BYTE_SIZE(rcrd) % buf == 0 ? 0 : \ ((((RECORD_BYTE_SIZE(rcrd) / buf) + 1)) * buf) \ - RECORD_BYTE_SIZE(rcrd)) ///< DG padding length macro. #pragma pack(push, 1) // ********** DD record structures ********** /// DD calibration groups structure typedef struct { DD_PRES_SENSORS_CAL_RECORD_T presSensorsCalRecord; ///< DG pressure sensors. DD_FLOW_SENSORS_CAL_RECORD_T flowSensorsCalRecord; ///< DG flow sensors. DD_LOAD_CELLS_CAL_RECORD_T loadCellsCalRecord; ///< DG load cells. DD_TEMP_SENSORS_CAL_RECORD_T tempSensorsCalRecord; ///< DG temperature sensors. DD_CONC_PUMPS_CAL_RECORD_T concentratePumpsRecord; ///< DG concentrate pumps. DD_DRAIN_PUMP_CAL_RECORD_T drainPumpRecord; ///< DG drain pump. DD_RO_PUMP_CAL_RECORD_T roPumpRecord; ///< DG RO pump. DD_DRAIN_LINE_VOLUME_T drainLineVolumeRecord; ///< DG drain line volume. DD_PRE_RO_PURGE_VOLUME_T preROPurgeVolumeRecord; ///< DG RO purge volume. DD_GENERIC_VOLUME_RECORD_T genericVolumeRecord; ///< DG generic volume (magic number because the value is unknown). DD_ACID_CONCENTRATES_RECORD_T acidConcentratesRecord; ///< DG acid concentrates. DD_BICARB_CONCENTRATES_RECORD_T bicarbConcentratesRecord; ///< DG bicarb concentrates. DD_FILTERS_CAL_RECORD_T filtersRecord; ///< DG filters. DD_FANS_CAL_RECORD_T fansRecord; ///< DG fans. DD_ACCEL_SENSOR_CAL_RECORD_T accelerometerSensorCalRecord; ///< DG accelerometer sensor. DD_HEATING_CAL_RECORD_T heatingCalRecord; ///< DG heating calibration record. DD_CHEMICALS_FILL_COND_CAL_RECORD_T fillCondCalRecord; ///< DG fill acid/bicarb target conductivities calibration record. } DD_CALIBRATION_GROUPS_T; /// DG calibration records structure typedef struct { DD_CALIBRATION_GROUPS_T ddCalibrationGroups; ///< DG calibration groups. U08 padding[ RECORD_PADDING_LENGTH(DD_CALIBRATION_GROUPS_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG calibration record padding byte array. U16 crc; ///< CRC for the DG calibration record structure. } DD_CALIBRATION_RECORD_T; /// DG system group structure typedef struct { DD_SYSTEM_RECORD_T ddSystemRecord; ///< DG system record. U08 padding[ RECORD_PADDING_LENGTH(DD_SYSTEM_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG system group padding byte array. U16 crc; ///< CRC for the DG system group structure. } DD_SYSTEM_GROUP_T; /// DG service record structure typedef struct { DD_SERVICE_RECORD_T ddServiceRecord; ///< DG service record. U08 padding[ RECORD_PADDING_LENGTH(DD_SERVICE_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG service group padding. U16 crc; ///< CRC for the DG service structure. } DD_SERVICE_GROUP_T; /// DG scheduler record structure typedef struct { DD_SCHEDULED_RUN_RECORD_T ddScheduledRun; ///< DG scheduled runs. U08 padding[ RECORD_PADDING_LENGTH(DD_SCHEDULED_RUN_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG scheduled run group padding. U16 crc; ///< CRC for the DG scheduled runs structure. } DD_SCHEDULED_RUNS_GROUP_T; /// DG usage record structure typedef struct { DD_USAGE_INFO_RECORD_T ddUsageInfo; ///< DG usage info record. U08 padding[ RECORD_PADDING_LENGTH(DD_USAGE_INFO_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG scheduled run group padding. U16 crc; ///< CRC for the DG usage info structure. } DD_USAGE_INFO_GROUP_T; /// DG heaters record typedef struct { DD_HEATERS_RECORD_T ddHeatersInfo; ///< DG heaters info record. U08 padding[ RECORD_PADDING_LENGTH(DD_HEATERS_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< DG heater info group padding. U16 crc; ///< CRC for the DG heaters info structure. } DD_HEATERS_INFO_GROUP_T; #ifndef _RELEASE_ /// DG software configurations group typedef struct { DD_SW_CONFIG_RECORD_T ddSWConfigsRecord; ///< Software configurations record. // Since the software configurations are one byte, Num_of was used for the length of the lists U08 padding[ RECORD_PADDING_LENGTH(DD_SW_CONFIG_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES) ]; ///< Software configurations group padding. U16 crc; ///< Software configurations CRC. } DD_SW_CONFIG_GROUP_T; #endif #pragma pack(pop) // ********** private data ********** // Calibration variables static DD_CALIBRATION_RECORD_T ddCalibrationRecord; ///< DG calibration record structure (including padding and final CRC). static DD_SYSTEM_GROUP_T ddSystemGroup; ///< DG system group structure (including padding and final CRC). static DD_SERVICE_GROUP_T ddServiceGroup; ///< DG service group structure (including padding and final CRC). static DD_SCHEDULED_RUNS_GROUP_T ddScheduledRunsGroup; ///< DG scheduled run structure (including padding and final CRC). static DD_USAGE_INFO_GROUP_T ddUsageInfoGroup; ///< DG usage info structure (including padding and final CRC). static DD_HEATERS_INFO_GROUP_T ddHeatersInfoGroup; ///< DG heaters info structure (including padding and final CRC). #ifndef _RELEASE_ static DD_SW_CONFIG_GROUP_T ddSWConfigGroup; ///< DG Software configurations structure(including padding and final CRC). #endif // Process records specifications const PROCESS_RECORD_SPECS_T RECORDS_SPECS[ NUM_OF_NVDATMGMT_RECORDS_JOBS ] = { // Start address Size of the job Max write bytes per job Max read bytes per job Record structure pointer Record CRC pointer Event calibration record update {CAL_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_CALIBRATION_RECORD_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_CALIBRATION_RECORD_T), (U08*)&ddCalibrationRecord, (U08*)&ddCalibrationRecord.crc, DD_EVENT_CAL_RECORD_UPDATE }, // NVDATAMGMT_CALIBRATION_RECORD {SYSTEM_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_SYSTEM_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_SYSTEM_GROUP_T), (U08*)&ddSystemGroup, (U08*)&ddSystemGroup.crc, DD_EVENT_SYSTEM_RECORD_UPDATE }, // NVDATAMGMT_SYSTEM_RECORD {SERVICE_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_SERVICE_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_SERVICE_GROUP_T), (U08*)&ddServiceGroup, (U08*)&ddServiceGroup.crc, DD_EVENT_SERVICE_UPDATE }, // NVDATAMGMT_SERVICE_RECORD {DD_SCHEDULED_RUNS_START_ADDRESS, sizeof(DD_SCHEDULED_RUNS_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_SCHEDULED_RUNS_GROUP_T),(U08*)&ddScheduledRunsGroup, (U08*)&ddScheduledRunsGroup.crc, DD_EVENT_SCHEDULED_RUNS_UPDATE }, // NVDATAMGMT_SCHEDULER_RECORD {DD_HEATERS_INFO_START_ADDRESS, sizeof(DD_HEATERS_INFO_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_HEATERS_INFO_GROUP_T), (U08*)&ddHeatersInfoGroup, (U08*)&ddHeatersInfoGroup.crc, DD_EVENT_HEATERS_INFO_UPDATE }, // NVDATAMGMT_HEATERS_INFO_RECORD {DD_USAGE_INFO_START_ADDRESS, sizeof(DD_USAGE_INFO_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_USAGE_INFO_GROUP_T), (U08*)&ddUsageInfoGroup, (U08*)&ddUsageInfoGroup.crc, DD_EVENT_USAGE_INFO_UPDATE }, // NVDATAMGMT_USAGE_INFO_RECORD #ifndef _RELEASE_ {SW_CONFIGS_START_ADDRESS, sizeof(DD_SW_CONFIG_GROUP_T), MAX_EEPROM_WRITE_BUFFER_BYTES, sizeof(DD_SW_CONFIG_GROUP_T), (U08*)&ddSWConfigGroup, (U08*)&ddSWConfigGroup.crc, DD_EVENT_SW_CONFIG_UPDATE } // NVDATAMGMT_SW_CONFIG_RECORD #endif }; static NVDATAMGMT_SELF_TEST_STATE_T nvDataMgmtSelfTestState; ///< NVDataMgmt self-test state variable. static SELF_TEST_STATUS_T nvDataMgmtSelfTestResult; ///< NVDataMgmt self-test result. static U32 usageWriteTries; ///< Usage write tries. static BOOL isSelfTestReadRecordsDone; ///< Set to true when all the records are read // ********** private function prototypes ********** // Self test functions static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadRecords( void ); static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC( void ); // Record check helper functions static BOOL isPolynomialRecordValid( POLYNOMIAL_CAL_PAYLOAD_T* record ); static BOOL isDDSystemRecordValid( void ); static BOOL isDDServiceRecordValid( void ); static BOOL isDDUsageRecordValid( void ); static BOOL isDDCalibrationRecordValid( void ); static BOOL isDDDrainPumpRecordValid( DD_DRAIN_PUMP_CAL_RECORD_T* record ); static BOOL isDDROPumpRecordValid( DD_RO_PUMP_CAL_RECORD_T* record ); static BOOL isDDPreROPurgeVolumeRecordValid( DD_PRE_RO_PURGE_VOLUME_T* record ); static BOOL isDDDrainLineVolRecordValid( DD_DRAIN_LINE_VOLUME_T* record ); static BOOL isDDGenericVolRecordValid( DD_GENERIC_VOLUME_DATA_T* record ); static BOOL isDDAcidConcentrateRecordValid( DD_ACID_CONCENTRATE_T* record ); static BOOL isDDBicarbConcentrateRecordValid( DD_BICARB_CONCENTRATE_T* record ); static BOOL isDDFilterRecordValid( DD_FILTER_CAL_RECORD_T* record ); static BOOL isDDFanRecordValid( DD_FAN_CAL_RECORD_T* record ); static BOOL isDDAccelerometerSensorRecordValid( DD_ACCEL_SENSOR_CAL_RECORD_T* record ); static BOOL isDDHeatingCalRecordValid( DD_HEATING_CAL_RECORD_T* record ); static BOOL isDDFillConductiviesRecordValid( DD_ACID_BICARB_FILL_COND_VALUES_T* record, DD_ACID_TYPES_T acidType, DD_FILL_COND_OPS_T operation ); #ifndef _RELEASE_ static BOOL isSWConfigRecordValid( void ); #endif void initNVRecordsDD( void ) { // Initialize the parameters nvDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS; nvDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; usageWriteTries = 0; } /*********************************************************************//** * @brief * The execNVDataMgmtSelfTest runs the NVDataMgmt POST during the self-test. * @details Inputs: nvDataMgmtSelfTestState, nvDataMgmtSelfTestResult * @details Outputs: nvDataMgmtSelfTestState * @return nvDataMgmtSelfTestResult the result of self-test *************************************************************************/ SELF_TEST_STATUS_T execNVDataMgmtSelfTest ( void ) { switch ( nvDataMgmtSelfTestState ) { case NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS: nvDataMgmtSelfTestState = handleSelfTestReadRecords(); break; case NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC: nvDataMgmtSelfTestState = handleSelfTestCheckCRC(); break; case NVDATAMGMT_SELF_TEST_STATE_COMPLETE: // Done with POST. Do nothing break; default: // SET_ALARM_WITH_2_U32_DATA ( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVDATAMGMT_INVALID_SELF_TEST_STATE, nvDataMgmtSelfTestState ); nvDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_COMPLETE; nvDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; break; } return nvDataMgmtSelfTestResult; } PROCESS_RECORD_SPECS_T getProcessRecord( RECORD_JOBS_STATE_T job ) { return RECORDS_SPECS[ job ]; } /*********************************************************************//** * @brief * The handleSelfTestReadRecords waits for the records to be read * @details Inputs: none * @details Outputs: none * @return next state *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadRecords( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS; // Check if the queues are empty and the exec state machine is in Idle meaning all the records have been read and the state machine // is back at Idle so even the last job in the queue has been processed if ( TRUE == isSelfTestReadRecordsDone ) { updateRecordReadStatus( NVDATAMGMT_RECORDS_READ ); state = NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC; } return state; } /*********************************************************************//** * @brief * 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: nvDataMgmtSelfTestResult * @details Outputs: none * @return next state *************************************************************************/ static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC ( void ) { NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_COMPLETE; BOOL haveCalGroupsPassed = TRUE; BOOL hasSystemRecordPassed = TRUE; BOOL hasServiceRecordPassed = TRUE; BOOL hasInstitutionalRecordPassed = TRUE; BOOL hasSWConfigRecordPassed = TRUE; BOOL hasUsageRecordPassed = TRUE; updateRecordReadStatus( NVDATAMGMT_RECORDS_CRC_CHECKED ); // Check all the calibration groups haveCalGroupsPassed = isDDCalibrationRecordValid(); hasSystemRecordPassed = isDDSystemRecordValid(); hasServiceRecordPassed = isDDServiceRecordValid(); hasUsageRecordPassed = isDDUsageRecordValid(); #ifndef _RELEASE_ hasSWConfigRecordPassed = isSWConfigRecordValid(); #endif // If any of the records did not pass, they should be filled // with benign values. After that, schedule a write to sector 0 // to re-write the records with the benign values if ( ( FALSE == hasServiceRecordPassed ) || ( FALSE == haveCalGroupsPassed ) || ( FALSE == hasSystemRecordPassed ) || ( FALSE == hasInstitutionalRecordPassed ) ) { enqueueSector0Records(); SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_CALIBRATION_RECORD ].nvEvent, 0, 0 ) SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_SYSTEM_RECORD ].nvEvent, 0, 0 ) SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_SERVICE_RECORD ].nvEvent, 0, 0 ) } #ifndef _RELEASE_ if ( FALSE == hasSWConfigRecordPassed ) { enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_SW_CONFIG_RECORD ); SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_SW_CONFIG_RECORD ].nvEvent, 0, 0 ) } #endif if ( FALSE == hasUsageRecordPassed ) { enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_USAGE_INFO_RECORD ); SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_USAGE_INFO_RECORD ].nvEvent, 0, 0 ) } // Check if the records' entire CRCs as well as the individual CRCs passed if ( ( TRUE == haveCalGroupsPassed ) && ( TRUE == hasSystemRecordPassed ) && ( TRUE == hasServiceRecordPassed ) && ( TRUE == hasInstitutionalRecordPassed ) ) { updateCalStartTimer( getMSTimerCount() ); updateNewCalAvailableFlag( TRUE ); nvDataMgmtSelfTestResult = SELF_TEST_STATUS_PASSED; } else { nvDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; } return state; } /*********************************************************************//** * @brief * The benignPolynomialCalRecord function benigns the provided polynomial * calibration record. * @details Inputs: none * @details Outputs: none * @return record which is a pointer to a polynomial calibration record * otherwise none *************************************************************************/ void benignPolynomialCalRecord( POLYNOMIAL_CAL_PAYLOAD_T* record ) { record->fourthOrderCoeff = RECORD_FOURTH_ORDER_COEFF; record->thirdOrderCoeff = RECORD_THIRD_ORDER_COEFF; record->secondOrderCoeff = RECORD_SECOND_ORDER_COEFF; record->gain = RECORD_DEFAULT_GAIN; record->offset = RECORD_DEFAULT_OFFSET; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) - sizeof( U16 ) ); } /*********************************************************************//** * @brief * The isPolynomialRecordValid function checks whether the records are * still valid by calculating the CRCs and comparing it to the strucutre's * CRC. * @details Inputs: none * @details Outputs: none * @param record: pointer to a polynomial payload. The actual calibration * data to be checked * @param isRecordNeeded: TRUE is the calibration record is need in the * firmware right now otherwise, FALSE * @return TRUE if the records' data is valid otherwise FALSE *************************************************************************/ static BOOL isPolynomialRecordValid( POLYNOMIAL_CAL_PAYLOAD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) - sizeof( U16 ) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { benignPolynomialCalRecord( record ); // Set status to FALSE since the record is not valid status = FALSE; } return status; } #ifndef _RELEASE_ /*********************************************************************//** * @brief * The isSWConfigRecordValid function checks the validity of the software * configuration record. * @details Inputs: ddSWConfigGroup, hdSWConfigGroup * @details Outputs: ddSWConfigGroup, hdSWConfigGroup * @return TRUE if the DG system record is valid otherwise FALSE *************************************************************************/ static BOOL isSWConfigRecordValid( void ) { BOOL status = TRUE; U16 calcCRC = crc16( (U08*)&ddSWConfigGroup, sizeof( DD_SW_CONFIG_GROUP_T ) - sizeof( U16 ) ); U16 recordCRC = ddSWConfigGroup.crc; if ( calcCRC != recordCRC ) { memset( (U08*)&ddSWConfigGroup, 0, sizeof( DD_SW_CONFIG_GROUP_T ) ); // Recalculate the CRC with the default values ddSWConfigGroup.crc = crc16( (U08*)&ddSWConfigGroup, sizeof( DD_SW_CONFIG_GROUP_T ) - sizeof( U16 ) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } #endif /*********************************************************************//** * @brief * The isDDSystemRecordValid function checks the validity of the DG system * record. * @details Inputs: ddSystemGroup.ddSystemRecord * @details Outputs: none * @return TRUE if the DG system record is valid otherwise FALSE *************************************************************************/ static BOOL isDDSystemRecordValid( void ) { BOOL status = TRUE; U16 calcCRC = crc16( (U08*)&ddSystemGroup.ddSystemRecord, sizeof( DD_SYSTEM_RECORD_T ) - sizeof( U16 ) ); U16 recordCRC = ddSystemGroup.ddSystemRecord.crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default ddSystemGroup.ddSystemRecord.mfgDate = 0; ddSystemGroup.ddSystemRecord.mfgLocation = 0; memset( ddSystemGroup.ddSystemRecord.topLevelPN, RECORD_DEFAULT_CHARACTER, sizeof( ddSystemGroup.ddSystemRecord.topLevelPN ) ); memset( ddSystemGroup.ddSystemRecord.topLevelSN, RECORD_DEFAULT_CHARACTER, sizeof( ddSystemGroup.ddSystemRecord.topLevelSN ) ); // Recalculate the CRC with the default values ddSystemGroup.ddSystemRecord.crc = crc16 ( (U08*)&ddSystemGroup.ddSystemRecord, sizeof( DD_SYSTEM_RECORD_T ) - sizeof( U16 ) ); ddSystemGroup.crc = crc16 ( (U08*)&ddSystemGroup, sizeof( DD_SYSTEM_GROUP_T ) - sizeof( U16 ) ); status = FALSE; // activateAlarmNoData( ALARM_ID_DD_INVALID_SYSTEM_RECORD_CRC ); } else { if ( RECORD_DEFAULT_CHARACTER == ddSystemGroup.ddSystemRecord.topLevelSN[ 0 ] ) { // activateAlarmNoData( ALARM_ID_DD_INVALID_SERIAL_NUMBER ); } } return status; } /*********************************************************************//** * @brief * The isDDServiceRecordValid function checks the validity of the DG service * record. * @details Inputs: ddServiceGroup.ddServiceRecord * @details Outputs: none * @return TRUE if the DG service record is valid otherwise FALSE *************************************************************************/ static BOOL isDDServiceRecordValid( void ) { BOOL status = TRUE; U16 calcCRC = crc16( (U08*)&ddServiceGroup.ddServiceRecord, sizeof( DD_SERVICE_RECORD_T ) - sizeof( U16 ) ); U16 recordCRC = ddServiceGroup.ddServiceRecord.crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default ddServiceGroup.ddServiceRecord.lastServiceEpochDate = 0; ddServiceGroup.ddServiceRecord.serviceIntervalSeconds = RECORD_DEFAULT_SERVICE_INTERVAL_S; // ddServiceGroup.ddServiceRecord.lastResetTimeEpoch = getRTCTimestamp(); ddServiceGroup.ddServiceRecord.crc = crc16 ( (U08*)&ddServiceGroup.ddServiceRecord, sizeof( DD_SERVICE_RECORD_T ) - sizeof( U16 ) ); ddServiceGroup.crc = crc16 ( (U08*)&ddServiceGroup, sizeof( DD_SERVICE_GROUP_T ) - sizeof( U16 ) ); status = FALSE; // Service record failure is also considered as RTC RAM failure // activateAlarmNoData( ALARM_ID_DD_INVALID_SERVICE_RECORD_CRC ); } return status; } /*********************************************************************//** * @brief * The isDDUsageRecordValid function checks whether the DG usage information * is valid or not. * @details Inputs: ddUsageInfoGroup * @details Outputs: ddUsageInfoGroup * @return TRUE if the DG usage record is valid otherwise FALSE *************************************************************************/ static BOOL isDDUsageRecordValid( void ) { BOOL status = TRUE; U16 calcCRC = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfo, sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); U16 recordCRC = ddUsageInfoGroup.ddUsageInfo.crc; if ( calcCRC != recordCRC ) { ddUsageInfoGroup.ddUsageInfo.lastChemDisCompleteDateEpoch = 0; ddUsageInfoGroup.ddUsageInfo.lastHeatDisCompleteDateEpoch = 0; ddUsageInfoGroup.ddUsageInfo.roWaterGenSinceLastServiceL = 0.0F; ddUsageInfoGroup.ddUsageInfo.roWaterGenTotalL = 0.0F; // ddUsageInfoGroup.ddUsageInfo.lastResetTimeEpoch = getRTCTimestamp(); ddUsageInfoGroup.ddUsageInfo.crc = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfo, sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); ddUsageInfoGroup.crc = crc16( (U08*)&ddUsageInfoGroup, sizeof( DD_USAGE_INFO_GROUP_T ) - sizeof( U16 ) ); status = FALSE; // activateAlarmNoData( ALARM_ID_DD_INVALID_USAGE_RECORD_CRC ); } return status; } /*********************************************************************//** * @brief * The isDDCalibrationRecordValid function calls other functions to check * the validity of DG calibration record. * @details Inputs: ddCalibrationRecord * @details Outputs: none * @return TRUE if the DG calibration record is valid otherwise FALSE *************************************************************************/ static BOOL isDDCalibrationRecordValid( void ) { U32 i; POLYNOMIAL_CAL_PAYLOAD_T* record; BOOL isHardwareRecordValid = TRUE; BOOL isCalRecordValid = TRUE; U16 recordCRC = crc16 ( (U08*)&ddCalibrationRecord, sizeof( DD_CALIBRATION_RECORD_T ) - sizeof( U16 ) ); // Create a benign polynomial calibration record. This record is used to // clear the reserved calibration record. The reserved spaces are not used // but this will prevent those records to be nan or a random number. POLYNOMIAL_CAL_PAYLOAD_T tempRecord; benignPolynomialCalRecord( &tempRecord ); // Get the calibration record of the hardware (i.e. pressure sensor) DD_PRES_SENSORS_CAL_RECORD_T* pressure = &ddCalibrationRecord.ddCalibrationGroups.presSensorsCalRecord; // The ones that are an array, are looped through for ( i = 0; i < NUM_OF_CAL_DATA_PRES_SENSORS; i++ ) { // Get calibration payload and assign it to a pointer record = (POLYNOMIAL_CAL_PAYLOAD_T*)&pressure->pressureSensors[ i ]; // Check in the validity of the calibration data // If the variable is already FALSE, let it be FALSE. Even if one record is not // valid, the values should be set to benign values. This variable is used to decide // whether a write should be scheduled or not so it should not be overwritten with a TRUE // once a record set it to FALSE isHardwareRecordValid = isPolynomialRecordValid( record ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } for ( i = 0; i < PRES_SENSORS_RESERVED_SPACE_COUNT; i++ ) { // Benign the pressures reserved spaces memcpy( (POLYNOMIAL_CAL_PAYLOAD_T*)&pressure->reservedSpace[ i ], &tempRecord, sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } DD_FLOW_SENSORS_CAL_RECORD_T* flow = &ddCalibrationRecord.ddCalibrationGroups.flowSensorsCalRecord; for ( i = 0; i < NUM_OF_CAL_DATA_FLOW_SENSORS; i++ ) { record = (POLYNOMIAL_CAL_PAYLOAD_T*)&flow->flowSensors[ i ]; isHardwareRecordValid = isPolynomialRecordValid( record ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } for ( i = 0; i < FLOW_SENSROS_RESERVED_SPACE_COUNT; i++ ) { // Benign the the flow sensors reserved spaces memcpy( (POLYNOMIAL_CAL_PAYLOAD_T*)&flow->reservedSpace[ i ], &tempRecord, sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } DD_LOAD_CELLS_CAL_RECORD_T* load = &ddCalibrationRecord.ddCalibrationGroups.loadCellsCalRecord; for ( i = 0; i < NUM_OF_CAL_DATA_LOAD_CELLS; i++ ) { record = (POLYNOMIAL_CAL_PAYLOAD_T*)&load->loadCells[ i ]; isHardwareRecordValid = isPolynomialRecordValid( record ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_TEMP_SENSORS_CAL_RECORD_T* temperature = &ddCalibrationRecord.ddCalibrationGroups.tempSensorsCalRecord; for ( i = 0; i < NUM_OF_CAL_DATA_TEMP_SENSORS; i++ ) { record = (POLYNOMIAL_CAL_PAYLOAD_T*)&temperature->tempSensors[ i ]; isHardwareRecordValid = isPolynomialRecordValid( record ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } for ( i = 0; i < TEMP_SENSORS_RESERVED_SPACE_COUNT; i++ ) { // Benign the temperature sensors reserved spaces memcpy( (POLYNOMIAL_CAL_PAYLOAD_T*)&temperature->reservedSpace[ i ], &tempRecord, sizeof( POLYNOMIAL_CAL_PAYLOAD_T ) ); } DD_CONC_PUMPS_CAL_RECORD_T* concPump = &ddCalibrationRecord.ddCalibrationGroups.concentratePumpsRecord; for ( i = 0; i < NUM_OF_CAL_DATA_DD_CONC_PUMPS; i++ ) { record = &concPump->concentratePumps[ i ]; isHardwareRecordValid = isPolynomialRecordValid( record ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_DRAIN_PUMP_CAL_RECORD_T* drainPump = &ddCalibrationRecord.ddCalibrationGroups.drainPumpRecord; isHardwareRecordValid = isDDDrainPumpRecordValid( drainPump ) != TRUE ? FALSE : isCalRecordValid; isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_RO_PUMP_CAL_RECORD_T* roPump = &ddCalibrationRecord.ddCalibrationGroups.roPumpRecord; isHardwareRecordValid = isDDROPumpRecordValid( roPump ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_PRE_RO_PURGE_VOLUME_T* preROPurgeVolume = &ddCalibrationRecord.ddCalibrationGroups.preROPurgeVolumeRecord; isHardwareRecordValid = isDDPreROPurgeVolumeRecordValid( preROPurgeVolume ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_DRAIN_LINE_VOLUME_T* drainLineVol = &ddCalibrationRecord.ddCalibrationGroups.drainLineVolumeRecord; isHardwareRecordValid = isDDDrainLineVolRecordValid( drainLineVol ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_GENERIC_VOLUME_RECORD_T* genericVol = &ddCalibrationRecord.ddCalibrationGroups.genericVolumeRecord; for ( i = 0; i < GENERIC_VOL_RESERVED_SPACE_COUNT; i++ ) { isHardwareRecordValid = isDDGenericVolRecordValid( &genericVol->genericVolume[ i ] ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_ACID_CONCENTRATES_RECORD_T* acidConc = &ddCalibrationRecord.ddCalibrationGroups.acidConcentratesRecord; for ( i = 0; i < NUM_OF_CAL_DATA_ACID_CONCENTRATES; i++ ) { isHardwareRecordValid = isDDAcidConcentrateRecordValid( &acidConc->acidConcentrate[ i ] ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_BICARB_CONCENTRATES_RECORD_T* bicarbConc = &ddCalibrationRecord.ddCalibrationGroups.bicarbConcentratesRecord; for ( i = 0; i < NUM_OF_CAL_DATA_BICARB_CONCENTRATES; i++ ) { isHardwareRecordValid = isDDBicarbConcentrateRecordValid( &bicarbConc->bicarbConcentrate[ i ] ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_FILTER_CAL_RECORD_T* roFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.roFilter; isHardwareRecordValid = isDDFilterRecordValid( roFilter ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FILTER_CAL_RECORD_T* ultraFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.ultraFilter; isHardwareRecordValid = isDDFilterRecordValid( ultraFilter ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FILTER_CAL_RECORD_T* sedimentFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.sedimentFilter; isHardwareRecordValid = isDDFilterRecordValid( sedimentFilter ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FILTER_CAL_RECORD_T* carbonFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.carbonFilter; isHardwareRecordValid = isDDFilterRecordValid( carbonFilter ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FILTER_CAL_RECORD_T* carbonPolishFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.carbonPolishFilter; isHardwareRecordValid = isDDFilterRecordValid( carbonPolishFilter ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FANS_CAL_RECORD_T* fan = &ddCalibrationRecord.ddCalibrationGroups.fansRecord; for ( i = 0; i < NUM_OF_CAL_DATA_FANS; i++ ) { isHardwareRecordValid = isDDFanRecordValid( &fan->fans[ i ] ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } DD_ACCEL_SENSOR_CAL_RECORD_T* accelerometer = &ddCalibrationRecord.ddCalibrationGroups.accelerometerSensorCalRecord; isHardwareRecordValid = isDDAccelerometerSensorRecordValid( accelerometer ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_HEATING_CAL_RECORD_T* heating = &ddCalibrationRecord.ddCalibrationGroups.heatingCalRecord; isHardwareRecordValid = isDDHeatingCalRecordValid( heating ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; DD_FILL_COND_OPS_T j; DD_CHEMICALS_FILL_COND_CAL_RECORD_T* acidBicarbTempRecord = &ddCalibrationRecord.ddCalibrationGroups.fillCondCalRecord; for ( i = 0; i < NUM_OF_ACID_TYPE; i++ ) { for ( j = FILL_COND_NORMAL_OP; j < NUM_OF_FILL_COND_TEST; j++ ) { isHardwareRecordValid = isDDFillConductiviesRecordValid( &acidBicarbTempRecord->fillCondValues[ i ][ j ], (DD_ACID_TYPES_T)i, (DD_FILL_COND_OPS_T)j ); isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; } } // If the sub groups failed, they are all updated to their benign values // so the main CRC of the calibration group is calculated again if ( ( FALSE == isCalRecordValid ) || ( recordCRC != ddCalibrationRecord.crc ) ) { isCalRecordValid = FALSE; ddCalibrationRecord.crc = crc16 ( (U08*)&ddCalibrationRecord, sizeof( DD_CALIBRATION_RECORD_T ) - sizeof( U16 ) ); // activateAlarmNoData( ALARM_ID_DD_NVDATAMGMT_CAL_GROUP_RECORD_CRC_INVALID ); } return isCalRecordValid; } /*********************************************************************//** * @brief * The isDDDrainPumpRecordValid function checks whether the calibration * record of drain pump is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_DRAIN_PUMP_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDDrainPumpRecordValid( DD_DRAIN_PUMP_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_DRAIN_PUMP_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->stepSpeed2FlowRatio = RECORD_DEFAULT_RATIO; record->voltage2SpeedRatio = RECORD_DEFAULT_RATIO; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_DRAIN_PUMP_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDROPumpRecordValid function checks whether the calibration * record of RO pump is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_RO_PUMP_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDROPumpRecordValid( DD_RO_PUMP_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_RO_PUMP_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->gain1Ratio = RECORD_DEFAULT_RATIO; record->gain2Ratio = RECORD_DEFAULT_RATIO; record->gain3Ratio = RECORD_DEFAULT_RATIO; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_RO_PUMP_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDPreROPurgeVolumeRecordValid function checks whether the * calibration record of pre RO purge is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_PRE_RO_PURGE_VOLUME_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDPreROPurgeVolumeRecordValid( DD_PRE_RO_PURGE_VOLUME_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_PRE_RO_PURGE_VOLUME_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->pressure2FlowRatio = RECORD_DEFAULT_RATIO; record->volume = RECORD_DEFAULT_CONST; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_PRE_RO_PURGE_VOLUME_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDDrainLineVolRecordValid function checks whether the calibration * record of drain line volume is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_DRAIN_LINE_VOLUME_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDDrainLineVolRecordValid( DD_DRAIN_LINE_VOLUME_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_DRAIN_LINE_VOLUME_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->volume = DEFAULT_FLUSH_LINES_VOLUME_L; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_DRAIN_LINE_VOLUME_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDGenericVolRecordValid function checks whether the calibration * record of generic volume is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_GENERIC_VOLUME_DATA_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDGenericVolRecordValid( DD_GENERIC_VOLUME_DATA_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_GENERIC_VOLUME_DATA_T ) - sizeof( U16 ) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->volume = RECORD_DEFAULT_CONST; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof( DD_GENERIC_VOLUME_DATA_T ) - sizeof( U16 ) ); status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDAcidConcentrateRecordValid function checks whether the calibration * record of acid concentrate is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_ACID_CONCENTRATE_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDAcidConcentrateRecordValid( DD_ACID_CONCENTRATE_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_ACID_CONCENTRATE_T ) - sizeof( U16 ) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->acidFullBottleVolumeML = DEFAULT_ACID_BOTTLE_VOL_ML; record->acidConductivityUSPerCM = DEFAULT_ACID_COND_US_PER_CM; record->acidBottleTemperature = DEFAULT_ACID_BOTTLE_TEMP_C; record->acidConcMixRatio = DEFAULT_ACID_CONC_MIXING_RATIO; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof( DD_ACID_CONCENTRATE_T ) - sizeof( U16 ) ); status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDBicarbConcentrateRecordValid function checks whether the * calibration record of bicarb concentrate is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_BICARB_CONCENTRATE_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDBicarbConcentrateRecordValid( DD_BICARB_CONCENTRATE_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_BICARB_CONCENTRATE_T ) - sizeof( U16 ) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->bicarbStartVolumeML = DEFAULT_BICARB_BOTTLE_VOL_ML; record->bicarbConductivityUSPerCM = DEFAULT_BICARB_COND_US_PER_CM; record->bicarbBottleTemperature = DEFAULT_BICARB_BOTTLE_TEMP_C; record->bicarbConcMixRatio = DEFAULT_BICARB_CONC_MIXING_RATIO; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof( DD_BICARB_CONCENTRATE_T ) - sizeof( U16 ) ); status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDFilterRecordValid function checks whether the calibration * record of filter is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_FILTER_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDFilterRecordValid( DD_FILTER_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_FILTER_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->reservedSpace1 = RECORD_DEFAULT_CONST; record->reservedSpace2 = RECORD_DEFAULT_CONST; record->reservedSpace3 = RECORD_DEFAULT_CONST; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_FILTER_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDFanRecordValid function checks whether the calibration record * of fan is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_FAN_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDFanRecordValid( DD_FAN_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_FAN_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->reservedSpace1 = RECORD_DEFAULT_CONST; record->reservedSpace2 = RECORD_DEFAULT_CONST; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_FAN_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDAccelerometerSensorRecordValid function checks whether the * calibration record of accelerometer sensor is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_ACCELEROMETER_SENSOR_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDAccelerometerSensorRecordValid( DD_ACCEL_SENSOR_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_ACCEL_SENSOR_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->accelXOffset = RECORD_DEFAULT_OFFSET; record->accelYOffset = RECORD_DEFAULT_OFFSET; record->accelZOffset = RECORD_DEFAULT_OFFSET; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_ACCEL_SENSOR_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDDHeatingCalRecordValid function checks whether the calibration record * of heating parameters is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DD_HEATING_CAL_RECORD_T pointer * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDHeatingCalRecordValid( DD_HEATING_CAL_RECORD_T* record ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_HEATING_CAL_RECORD_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { // CRC did not pass so set all values to default record->reservoirTempTauCPerMin = DEFAULT_RSRVR_TEMP_TAU_C_PER_MIN; record->ultrafilterTempTauCPerMin = DEFAULT_UF_TEMP_TAU_C_PER_MIN; record->ultrafilterVolmL = DEFAULT_UF_VOLUME_ML; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_HEATING_CAL_RECORD_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The isDGFillConductiviesRecordValid function checks whether fill conductivity * record is valid or not. * @details Inputs: none * @details Outputs: none * @param record: DG_ACID_BICARB_FILL_COND_VALUES_T pointer containing the * fill conductivities of acid and bicrab * @param operation which is the type fill operation that is check (e.g. normal ops) * @param acidType whcih is the type of acid that its values are checked (e.g. 0-1251-1) * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ static BOOL isDDFillConductiviesRecordValid( DD_ACID_BICARB_FILL_COND_VALUES_T* record, DD_ACID_TYPES_T acidType, DD_FILL_COND_OPS_T operation ) { BOOL status = TRUE; U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_ACID_BICARB_FILL_COND_VALUES_T) - sizeof(U16) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { F32 acidSensorCond = 0.0F; F32 bicarbSensorCond = 0.0F; switch ( operation ) { case FILL_COND_NORMAL_OP: switch ( acidType ) { case ACID_08_1251_1: acidSensorCond = DEFAULT_FILL_1251_1_ACID_SNSR_US_PER_CM; bicarbSensorCond = DEFAULT_FILL_1251_1_BIC_SNSR_US_PER_CM; break; case ACID_08_2251_0: acidSensorCond = DEFAULT_FILL_2251_0_ACID_SNSR_US_PER_CM; bicarbSensorCond = DEFAULT_FILL_2251_0_BIC_SNSR_US_PER_CM; break; case ACID_08_3251_9: acidSensorCond = DEFAULT_FILL_3251_9_ACID_SNSR_US_PER_CM; bicarbSensorCond = DEFAULT_FILL_3251_9_BIC_SNSR_US_PER_CM; break; default: // TODO software fault break; } break; case FILL_COND_ACID_TEST: switch ( acidType ) { case ACID_08_1251_1: acidSensorCond = DEFAULT_ACID_TEST_1251_1_US_PER_CM; bicarbSensorCond = DEFAULT_ACID_TEST_1251_1_US_PER_CM; break; case ACID_08_2251_0: acidSensorCond = DEFAULT_ACID_TEST_2251_0_US_PER_CM; bicarbSensorCond = DEFAULT_ACID_TEST_2251_0_US_PER_CM; break; case ACID_08_3251_9: acidSensorCond = DEFAULT_ACID_TEST_3251_9_US_PER_CM; bicarbSensorCond = DEFAULT_ACID_TEST_3251_9_US_PER_CM; break; default: // TODO software fault break; } break; case FILL_COND_BICARB_TEST: acidSensorCond = DEFAULT_BIC_TEST_ACID_SNSR_US_PER_CM; bicarbSensorCond = DEFAULT_BIC_TEST_BIC_SNSR_US_PER_CM; break; } // CRC did not pass so set all values to default record->acidConduSPerCM = acidSensorCond; record->bicarbConduSPerCM = bicarbSensorCond; record->calibrationTime = RECORD_DEFAULT_TIME; record->crc = crc16 ( (U08*)record, sizeof(DD_ACID_BICARB_FILL_COND_VALUES_T) - sizeof(U16) ); // Set the to FALSE since the record is not valid status = FALSE; } return status; } /*********************************************************************//** * @brief * The setLastDisinfectDate sets a queue job to write the last time that DG * was disinfected. * @details Inputs: dgUsageInfoGroup * @details Outputs: dgUsageInfoGroup * @param disinfect type (i.e chemical) * @param epochTime last disinfect time in epoch * @return TRUE if queue is not full *************************************************************************/ BOOL setLastDisinfectDate( DD_USAGE_INFO_ITEMS_T disinfect, U32 epochTime ) { BOOL status = FALSE; if ( FALSE == isRecordQueueFull() ) { switch ( disinfect ) { case USAGE_INFO_BASIC_FLUSH: ddUsageInfoGroup.ddUsageInfo.lastBasicFlushCompleteDateEpoch = epochTime; break; case USAGE_INFO_CHEM_DIS_START: ddUsageInfoGroup.ddUsageInfo.lastChemDisStartDateEpoch = epochTime; break; case USAGE_INFO_CHEM_DIS: ddUsageInfoGroup.ddUsageInfo.lastChemDisCompleteDateEpoch = epochTime; break; case USAGE_INFO_CHEM_FLUSH: ddUsageInfoGroup.ddUsageInfo.lastChemDisFlushCompleteDateEpoch = epochTime; break; case USAGE_INFO_HEAT_DIS: ddUsageInfoGroup.ddUsageInfo.lastHeatDisCompleteDateEpoch = epochTime; break; case USAGE_INFO_FILTER_FLUSH: ddUsageInfoGroup.ddUsageInfo.lastFilterFlushCompleteDateEpoch = epochTime; break; case USAGE_INFO_HEAT_DIS_ACTIVE_COOL: ddUsageInfoGroup.ddUsageInfo.lastHeatActiveCoolCompleteDateEpoch = epochTime; break; default: // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_USAGE_INFO_SELECTED, disinfect ); break; } ddUsageInfoGroup.ddUsageInfo.crc = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfo, sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); ddUsageInfoGroup.crc = crc16( (U08*)&ddUsageInfoGroup, sizeof( DD_USAGE_INFO_GROUP_T ) - sizeof( U16 ) ); usageWriteTries = 0; status = TRUE; enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_USAGE_INFO_RECORD ); SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_USAGE_INFO_RECORD ].nvEvent, 0, 0 ) } else if ( ++usageWriteTries > MAX_NUM_OF_WRITE_TRIES ) { // SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_WRITE_USAGE_INFO_TO_NV_FAILURE, disinfect ); } return status; } /*********************************************************************//** * @brief * The setServiceTime function sets the latest service time in epoch and updates * the usage information after the service. * @details Inputs: none * @details Outputs: hdServiceGroup, hdUsageInfoGroup * @return TRUE if the queue has sufficient space to enqueue all the changed * records *************************************************************************/ BOOL setServiceTime( void ) { BOOL status = FALSE; if ( getAvailableRecordQueueCount() >= ( MIN_JOBS_NEEDED_FOR_SECTOR_0 + 1 ) ) { // When the service record is changed, all the sector 0 must be re-written plus the stack's usage information must be updated. // Therefore, at least 4 queues are needed to be able to update all the records. The usage records are changed: // In HD the treatment time since last service is reset to 0 // In DG the RO water generation since the last service in reset to 0 // ddServiceGroup.ddServiceRecord.lastServiceEpochDate = getRTCTimestamp(); ddServiceGroup.ddServiceRecord.crc = crc16( (U08*)&ddServiceGroup.ddServiceRecord, sizeof( DD_SERVICE_RECORD_T ) - sizeof( U16 ) ); ddServiceGroup.crc = crc16( (U08*)&ddServiceGroup, sizeof( DD_SERVICE_GROUP_T ) - sizeof( U16 ) ); // Update the DG usage info ddUsageInfoGroup.ddUsageInfo.roWaterGenSinceLastServiceL = 0; ddUsageInfoGroup.ddUsageInfo.crc = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfo, sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); ddUsageInfoGroup.crc = crc16( (U08*)&ddUsageInfoGroup, sizeof( DD_USAGE_INFO_GROUP_T ) - sizeof( U16 ) ); // Service record has been touched so the entire sector 0 of the EEPROM must be rewritten enqueueSector0Records(); enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_USAGE_INFO_RECORD ); // Both the usage and service records have been updated SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_USAGE_INFO_RECORD ].nvEvent, 0, 0 ) SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_SERVICE_RECORD ].nvEvent, 0, 0 ) status = TRUE; } return status; } /*********************************************************************//** * @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_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: { DD_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 ); } /*********************************************************************//** * @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; } void updateNVSelfTestResult( SELF_TEST_STATUS_T result ) { nvDataMgmtSelfTestResult = result; } void updateNVSelfTestState( NVDATAMGMT_SELF_TEST_STATE_T state ) { nvDataMgmtSelfTestState = state; } void updateSelfTestReadRecordsFlag ( BOOL value ) { isSelfTestReadRecordsDone = value; } #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 /**@}*/