Index: firmware/App/Services/NVRecordsDD.c =================================================================== diff -u -r1e809a81cb8831f5aa5938bd333cc374920d5b87 -r1e1a8756efda753c29d6a5dcfb8410451132a43a --- firmware/App/Services/NVRecordsDD.c (.../NVRecordsDD.c) (revision 1e809a81cb8831f5aa5938bd333cc374920d5b87) +++ firmware/App/Services/NVRecordsDD.c (.../NVRecordsDD.c) (revision 1e1a8756efda753c29d6a5dcfb8410451132a43a) @@ -1,360 +1,436 @@ /************************************************************************** * -* Copyright (c) 2026-2027 Diality Inc. - All Rights Reserved. +* Copyright (c) 2026-2026 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 (last) Arpita Srivastava +* @date (last) 27-Jul-2026 +* * @author (original) Arpita Srivastava -* @date (original) 31-Mar-2026 +* @date (original) 06-Apr-2026 * ***************************************************************************/ #include // For memcpy -#include "NVMsgQ.h" +#include "DDDefs.h" +#include "Messaging.h" +#include "NVJobQ.h" +#include "NVMessagingDD.h" #include "NVRecordsDD.h" +#include "Timers.h" #include "Utilities.h" // For crc calculation -// Data addresses and length in RTC RAM +/** + * @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. +#define NV_RECORD_SLOT_SIZE 4096 ///< Size of each NV record slot (4KB) -// 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 SYSTEM_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of system record within sector +#define SERVICE_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of service record within sector +#define CAL_RECORD_OFFSET (1U * NV_RECORD_SLOT_SIZE) ///< Offset of calibration record within sector +#define INSTIT_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of institutional record within sector +#define USAGE_RECORD_OFFSET (0U * NV_RECORD_SLOT_SIZE) ///< Offset of usage record within sector -#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 SYSTEM_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR0_START_ADDRESS + SYSTEM_RECORD_OFFSET ) ///< Start address of system record in NV memory +#define SERVICE_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR1_START_ADDRESS + SERVICE_RECORD_OFFSET ) ///< Start address of service record in NV memory +#define CAL_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR1_START_ADDRESS + CAL_RECORD_OFFSET ) ///< Start address of calibration record in NV memory +#define INSTIT_RECORD_NV_MEM_START_ADDRESS ( BANK7_SECTOR2_START_ADDRESS + INSTIT_RECORD_OFFSET ) ///< Start address of institutional record in NV memory +#define USAGE_INFO_START_ADDRESS ( BANK7_SECTOR3_START_ADDRESS + USAGE_RECORD_OFFSET ) ///< Start address of usage info record in NV memory -#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 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. -#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. +// DD specific defines +#define DEFAULT_D12_PUMP_TARGET_SPEED 0 ///< Default D12 dailysate pump target speed. +#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_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_BLOOD_LEAK_SET_POINT 20 ///< Blood leak default set point. -#define MAX_NUM_OF_WRITE_TRIES 3U ///< Max number of write tries. +// Default Values for Institutional Records +#define DEFAULT_MIN_DIALYSATE_FLOW_MLPM 50 ///< Default value of min dialysate flow in mL/min +#define DEFAULT_MAX_DIALYSATE_FLOW_MLPM 600 ///< Default value of max dialysate flow in mL/min +#define DEFAULT_MIN_DIALYSATE_TEMP_C 35.0F ///< Default value of min dialysate temp in °C +#define DEFAULT_MAX_DIALYSATE_TEMP_C 38.0F ///< Default value of max dialysate temp in °C +#define DEFAULT_MIN_ACID_CONCENTRATE 0 ///< Default value of min acid concentrate +#define DEFAULT_MAX_ACID_CONCENTRATE 2 ///< Default value of max acid concentrate +#define DEFAULT_MIN_BICARB_CARTRIDGE_SIZE_G 0 ///< Default value of min bicarb cartridge size in grams +#define DEFAULT_MAX_BICARB_CARTRIDGE_SIZE_G 5 ///< Default value of max bicarb cartridge size in grams +#define DEFAULT_MIN_SODIUM_MEQL 130 ///< Default value of min sodium in mEq/L +#define DEFAULT_MAX_SODIUM_MEQL 155 ///< Default value of max sodium in mEq/L +#define DEFAULT_MIN_BICARBONATE_MEQL 20 ///< Default value of min bicarbonate in mEq/L +#define DEFAULT_MAX_BICARBONATE_MEQL 40 ///< Default value of max bicarbonate in mEq/L +#define DEFAULT_MAX_RO_REJECTION_RATIO_PCT 90 ///< Max RO rejection ratio in percent. +#define DEFAULT_NUM_OF_DISINFECTION_FREQUENCY 3 ///< Number of Days between each disinfection cycle +#define DEFAULT_NUM_OF_DISINFECTION_CYCLE_TIME 30 ///< Time period of which disinfection is done +#define DEFAULT_MIN_INLET_WATER_COND_ALARM_US_P_CM 200.0F ///< Min inlet water conductivity alarm limit in uS/cm. +#define DEFAULT_MAX_INLET_WATER_COND_ALARM_US_P_CM 50.0F ///< Max inlet water conductivity alarm limit in uS/cm. +#define DEFAULT_ACID_CONCENTRATE_JUG_SIZE 3.43F ///< Acid Concentrate jug size in litres +#define DEFAULT_MIN_ACID_ALARM_US_P_CM 0 ///< Min acid alarm limit in percent. +#define DEFAULT_MIN_BICARB_ALARM_US_P_CM 0 ///< Min bicarb alarm limit in percent. +#define DEFAULT_POST_TREATMENT_DRAIN_OPTION 0 ///< Default Post Treatment Drain Option +#define DEFAULT_POST_TREATMENT_DRY_BICARB_OPTION 0 ///< Default Post Treatment Dry Bicarb Option -#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. +#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: (DD struct size % bytes to write(16) == 0 ? 0 : ((DD struct size / bytes to write(16)) + 1) * bytes to write(16)) - DD struct size. +// NOTE: assuming the macro is calculating the padding length for a non-volatile memory. For NV, 16 bytes is used for buffer. // 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. +#define RECORD_PADDING_LENGTH(rcrd, buf) ( RECORD_BYTE_SIZE( rcrd ) % buf == 0 ? 0 : \ + ( ( ( ( RECORD_BYTE_SIZE( rcrd ) / buf) + 1 ) ) * buf ) \ + - RECORD_BYTE_SIZE( rcrd ) ) ///< DD padding length macro. +#define SYSTEM_RECORD_PADDING_LENGTH ( RECORD_PADDING_LENGTH( DD_SYSTEM_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES ) ) +#define SERVICE_RECORD_PADDING_LENGTH ( RECORD_PADDING_LENGTH( DD_SERVICE_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES ) ) +#define CALIBRATION_RECORD_PADDING_LENGTH ( RECORD_PADDING_LENGTH( DD_CALIBRATION_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES ) ) +#define INSTITUTIONAL_RECORD_PADDING_LENGTH ( RECORD_PADDING_LENGTH( DD_INSTITUTIONAL_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES ) ) +#define USAGE_INFO_RECORD_PADDING_LENGTH ( RECORD_PADDING_LENGTH( DD_USAGE_INFO_RECORD_T, MAX_EEPROM_WRITE_BUFFER_BYTES ) ) - - -/// NVDataMgmt self-test states enumeration. -typedef enum NVDataMgmt_Self_Test_States -{ - NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS = 0, ///< Self test read records. - NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC, ///< Self test check CRC. - NVDATAMGMT_SELF_TEST_STATE_COMPLETE, ///< Self test complete. - NUM_OF_NVDATAMGMT_SELF_TEST_STATES ///< Total number of self-test states. -} NVDATAMGMT_SELF_TEST_STATE_T; - #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_RESERVOIR_VOLUME_RECORD_T reservoirVolumesRecord; ///< DG reservoir volumes. - 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; + DD_PRES_SENSORS_CAL_RECORD_T presSensorsCalRecord; ///< DD pressure sensors calibration record + DD_TEMP_SENSORS_CAL_RECORD_T tempSensorsCalRecord; ///< DD temperature sensors calibration record + DD_CONC_PUMPS_CAL_RECORD_T concentratePumpsRecord; ///< DD concentrate pumps calibration record + DD_D12_DIALYSATE_PUMP_RECORD_T d12DialysatePumpRecord; ///< DD dialysate pump d12 calibration data. + DD_D48_DIALYSATE_PUMP_RECORD_T d48DialysatePumpRecord; ///< DD dialysate pumps calibration record + DD_ACID_CONCENTRATES_RECORD_T acidConcentratesRecord; ///< DD acid concentrates calibration record + DD_BICARB_CONCENTRATES_RECORD_T bicarbConcentratesRecord; ///< DD bicarb concentrates calibration record + DD_ACCEL_SENSOR_CAL_RECORD_T accelerometerSensorCalRecord; ///< DD accelerometer sensor. + DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T bloodLeakSensorCalRecord; ///< DD blood leak detector calibration record +} DD_CALIBRATION_RECORD_T; -/// DG calibration records structure +/// DD 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; + DD_CALIBRATION_RECORD_T ddCalibrationRecord; ///< DD calibration groups. + U08 padding[ CALIBRATION_RECORD_PADDING_LENGTH ]; ///< DD calibration record padding byte array. + U16 crc; ///< CRC for the DG calibration record structure. +} DD_CALIBRATION_GROUP_T; -/// DG system group structure +/// DD 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_RECORD_T ddSystemRecord; ///< DD system record. + U08 padding[ SYSTEM_RECORD_PADDING_LENGTH ]; ///< DD system group padding byte array. + U16 crc; ///< CRC for the DG system group structure. } DD_SYSTEM_GROUP_T; -/// DG service record structure +/// DD service record structure typedef struct { - DD_SERVICE_RECORD_T ddServiceRecord; ///< DG service record. - U08 padding[ RECORD_PADDING_LENGTH(DD_SERVICE_RECORD_T, MAX_RTC_RAM_OPS_BUFFER_BYTES) ]; ///< DG service group padding. - U16 crc; ///< CRC for the DG service structure. + DD_SERVICE_RECORD_T ddServiceRecord; ///< DD service record. + U08 padding[ SERVICE_RECORD_PADDING_LENGTH ]; ///< DD service group padding. + U16 crc; ///< CRC for the DG service structure. } DD_SERVICE_GROUP_T; -/// DG scheduler record structure +/// DD institutional record structure typedef struct { - DD_SCHEDULED_RUN_RECORD_T ddScheduledRun; ///< DG scheduled runs. - U08 padding[ RECORD_PADDING_LENGTH(DD_SCHEDULED_RUN_RECORD_T, MAX_RTC_RAM_OPS_BUFFER_BYTES) ]; ///< DG scheduled run group padding. - U16 crc; ///< CRC for the DG scheduled runs structure. -} DD_SCHEDULED_RUNS_GROUP_T; + DD_INSTITUTIONAL_RECORD_T ddInstitutionalRecord; ///< DD institutional record. + U08 padding[ INSTITUTIONAL_RECORD_PADDING_LENGTH ]; ///< DD institutional group padding. + U16 crc; ///< CRC for the HD institutional structure. +} DD_INSTITUTIONAL_GROUP_T; -/// DG usage record structure +/// DD 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_RTC_RAM_OPS_BUFFER_BYTES) ]; ///< DG scheduled run group padding. - U16 crc; ///< CRC for the DG usage info structure. + DD_USAGE_INFO_RECORD_T ddUsageInfoRecord; ///< DD usage info record. + U08 padding[ USAGE_INFO_RECORD_PADDING_LENGTH ]; ///< DD 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_RTC_RAM_OPS_BUFFER_BYTES) ]; ///< DG heater info group padding. - U16 crc; ///< CRC for the DG heaters info structure. -} DD_HEATERS_INFO_GROUP_T; +#pragma pack(pop) -#ifndef _RELEASE_ -/// DG software configurations group -typedef struct -{ - DD_SW_CONFIG_RECORD_T ddSWConfigsRecord; ///< Software configurations record. +// ********** private data ********** - // 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_RTC_RAM_OPS_BUFFER_BYTES) ]; ///< Software configurations group padding. - U16 crc; ///< Software configurations CRC. -} DD_SW_CONFIG_GROUP_T; -#endif +/// Main NVM Record variables +static DD_SYSTEM_GROUP_T ddSystemGroup; ///< DD system group structure (including padding and final CRC). +static DD_SERVICE_GROUP_T ddServiceGroup; ///< DD service group structure (including padding and final CRC). +static DD_CALIBRATION_GROUP_T ddCalibrationGroup; ///< DD calibration record structure (including padding and final CRC). +static DD_INSTITUTIONAL_GROUP_T ddInstitutionalGroup; ///< DD institutional group structure (including padding and final CRC). +static DD_USAGE_INFO_GROUP_T ddUsageInfoGroup; ///< DD usage info structure (including padding and final CRC). -#pragma pack(pop) +/// Main Process records specifications +const PROCESS_RECORD_SPECS_T RECORDS_SPECS[ NUM_OF_NVM_RECORD_TYPES ] = { + // Start address Size of the job Record structure pointer Record CRC pointer Event calibration record update + {SYSTEM_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_SYSTEM_GROUP_T), (U08*)&ddSystemGroup, (U08*)&ddSystemGroup.crc, DD_EVENT_SYSTEM_RECORD_UPDATE }, // NVM_SYSTEM_RECORD + {SERVICE_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_SERVICE_GROUP_T), (U08*)&ddServiceGroup, (U08*)&ddServiceGroup.crc, DD_EVENT_SERVICE_RECORD_UPDATE }, // NVM_SERVICE_RECORD + {CAL_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_CALIBRATION_GROUP_T), (U08*)&ddCalibrationGroup, (U08*)&ddCalibrationGroup.crc, DD_EVENT_CALIBRATION_RECORD_UPDATE }, // NVM_CALIBRATION_RECORD + {INSTIT_RECORD_NV_MEM_START_ADDRESS, sizeof(DD_INSTITUTIONAL_GROUP_T), (U08*)&ddInstitutionalGroup, (U08*)&ddInstitutionalGroup.crc, DD_EVENT_INSTITUTIONAL_RECORD_UPDATE }, // NVM_INSTITUTIONAL_RECORD + {USAGE_INFO_START_ADDRESS, sizeof(DD_USAGE_INFO_GROUP_T), (U08*)&ddUsageInfoGroup, (U08*)&ddUsageInfoGroup.crc, DD_EVENT_USAGE_INFO_RECORD_UPDATE }, // NVM_USAGE_INFO_RECORD +}; -// 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 +/// Table showing data type of each institutional record component +const CRITICAL_DATA_TYPES_T institRecDataTypeTable[ NUM_OF_DD_INSTIT_RECORD_TYPE ] = +{ + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_DIALYSATE_FLOW_MLPM + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MAX_DIALYSATE_FLOW_MLPM + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MIN_DIALYSATE_TEMP_C + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MAX_DIALYSATE_TEMP_C + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_ACID_CONCENTRATE + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MAX_ACID_CONCENTRATE + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_BICARB_CARTRIDGE_SIZE_G + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MAX_BICARB_CARTRIDGE_SIZE_G + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_SODIUM_MEQL + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MAX_SODIUM_MEQL + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_BICARBONATE_MEQL + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MAX_BICARBONATE_MEQL + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_MIN_RO_REJECTION_RATIO_PCT + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_DISINFECTION_FREQUENCY + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_DISINFECTION_CYCLE_TIME + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MIN_INLET_WATER_COND_ALARM_LIMIT_USPCM + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MAX_INLET_WATER_COND_ALARM_LIMIT_USPCM + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_ACID_CONCENTRATE_JUG_SIZE_L + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MIN_ACID_ALARM_LIMIT_PCT + CRITICAL_DATA_TYPE_F32, // DD_INSTIT_MIN_BICARB_ALARM_LIMIT_PCT + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_POST_TREAT_DRAIN_OPTION + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_POST_TREAT_DRY_BICARB_OPTION + CRITICAL_DATA_TYPE_U32, // DD_INSTIT_CALIBRATION_TIME + CRITICAL_DATA_TYPE_U32 // DD_INSTIT_CRC +}; -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 NVM_SELF_TEST_STATE_T nvmSelfTestState; ///< NVM self-test state variable. +static SELF_TEST_STATUS_T nvmSelfTestResult; ///< NVM 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 ); +static NVM_SELF_TEST_STATE_T handleSelfTestReadRecords( void ); +static NVM_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 isDDInstitutionalRecordValid( 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 isDDReservoirVolRecordValid( DD_RESERVOIR_VOLUME_DATA_T* record ); -static BOOL isDDGenericVolRecordValid( DD_GENERIC_VOLUME_DATA_T* record ); +static BOOL isDDPumpD12RecordValid( DD_D12_DIALYSATE_PUMP_RECORD_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 ); -#ifndef _RELEASE_ -static BOOL isSWConfigRecordValid( void ); -#endif +static BOOL isDDBloodLeakSensorValid( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T* record ); +static void initDDSystemRecord( void ); +static void initDDServiceRecord( void ); +static void initDDInstitutionalRecord( void ); +static void initDDUsageRecord( void ); + +static void updateRecordPadding( NVM_RECORD_TYPE_T recType ); + +/*********************************************************************//** + * @brief + * The initNVRecordsDD function initializes the NV records data management + * state and resets related control variables. It sets the self-test + * process to start reading records. + * @details \b Inputs: none + * @details \b Outputs: nvmSelfTestState, + * nvmSelfTestResult, usageWriteTries + * @return none + *************************************************************************/ void initNVRecordsDD( void ) { // Initialize the parameters - nvDataMgmtSelfTestState = NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS; - nvDataMgmtSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; - usageWriteTries = 0; + nvmSelfTestState = NVM_SELF_TEST_STATE_READ_RECORDS; + nvmSelfTestResult = 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 + * The execNVMRecordsSelfTest function runs the NV data management + * self-test state machine. It processes states and updates the result + * based on self-test execution. + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT + * @details \b Inputs: nvmSelfTestState, + * nvmSelfTestResult + * @details \b Outputs: nvmSelfTestState, + * nvmSelfTestResult + * @return nvmSelfTestResult the result of self-test *************************************************************************/ -SELF_TEST_STATUS_T execNVDataMgmtSelfTest ( void ) +SELF_TEST_STATUS_T execNVMRecordsSelfTest ( void ) { - switch ( nvDataMgmtSelfTestState ) + switch ( nvmSelfTestState ) { - case NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS: - nvDataMgmtSelfTestState = handleSelfTestReadRecords(); + case NVM_SELF_TEST_STATE_READ_RECORDS: + nvmSelfTestState = handleSelfTestReadRecords(); break; - case NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC: - nvDataMgmtSelfTestState = handleSelfTestCheckCRC(); + case NVM_SELF_TEST_STATE_CHECK_CRC: + nvmSelfTestState = handleSelfTestCheckCRC(); break; - case NVDATAMGMT_SELF_TEST_STATE_COMPLETE: + case NVM_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; + SET_ALARM_WITH_2_U32_DATA ( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVM_INVALID_SELF_TEST_STATE, ( U32 )nvmSelfTestState ); + nvmSelfTestState = NVM_SELF_TEST_STATE_COMPLETE; + nvmSelfTestResult = SELF_TEST_STATUS_FAILED; break; } - return nvDataMgmtSelfTestResult; + return nvmSelfTestResult; } /*********************************************************************//** * @brief - * The handleSelfTestReadRecords waits for the records to be read - * @details Inputs: none - * @details Outputs: none - * @return next state + * The getProcessRecord function gets the process record + * specification for the given job. + * @details \b Inputs: RECORDS_SPECS + * @details \b Outputs: none + * @param job Record job identifier used to select the process record + * @return RECORDS_SPECS[job] corresponding process record specification *************************************************************************/ -static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestReadRecords( void ) +PROCESS_RECORD_SPECS_T getProcessRecord( NVM_RECORD_TYPE_T job ) { - NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_READ_RECORDS; + return RECORDS_SPECS[ job ]; +} - // 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 +/*********************************************************************//** + * @brief + * The handleSelfTestReadRecords function waits for the records to be + * read and updates the state when reading is complete. + * @details \b Inputs: isSelfTestReadRecordsDone + * @details \b Outputs: none + * @return state next self-test state + *************************************************************************/ +static NVM_SELF_TEST_STATE_T handleSelfTestReadRecords( void ) +{ + NVM_SELF_TEST_STATE_T state = NVM_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 == isRecordQueueEmpty() ) && ( NVDATAMGMT_EXEC_STATE_IDLE == nvDataMgmtExecState ) ) + if ( TRUE == isSelfTestReadRecordsDone ) { - recordsReadStatus = NVDATAMGMT_RECORDS_READ; - state = NVDATAMGMT_SELF_TEST_STATE_CHECK_CRC; + updateRecordReadStatus( NVM_RECORDS_READ ); + state = NVM_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 + * The handleSelfTestCheckCRC function checks the CRC of records and + * compares them with stored CRC values. If they don't match, it will fail POST. + * It updates the self-test result + * and schedules rewrite for invalid records. + * @details \b Inputs: nvmSelfTestResult + * @details \b Outputs: nvmSelfTestResult + * @return state next self-test state *************************************************************************/ -static NVDATAMGMT_SELF_TEST_STATE_T handleSelfTestCheckCRC ( void ) +static NVM_SELF_TEST_STATE_T handleSelfTestCheckCRC ( void ) { - NVDATAMGMT_SELF_TEST_STATE_T state = NVDATAMGMT_SELF_TEST_STATE_COMPLETE; - BOOL haveCalGroupsPassed = TRUE; + NVM_SELF_TEST_STATE_T state = NVM_SELF_TEST_STATE_COMPLETE; BOOL hasSystemRecordPassed = TRUE; BOOL hasServiceRecordPassed = TRUE; + BOOL haveCalGroupsPassed = TRUE; BOOL hasInstitutionalRecordPassed = TRUE; - BOOL hasSWConfigRecordPassed = TRUE; BOOL hasUsageRecordPassed = TRUE; - recordsReadStatus = NVDATAMGMT_RECORDS_CRC_CHECKED; + updateRecordReadStatus( NVM_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 + // with benign values. After that, schedule a write to sector // to re-write the records with the benign values - if ( ( FALSE == hasServiceRecordPassed ) || ( FALSE == haveCalGroupsPassed ) || ( FALSE == hasSystemRecordPassed ) || ( FALSE == hasInstitutionalRecordPassed ) ) + + // Validate system record + hasSystemRecordPassed = isDDSystemRecordValid(); + if ( FALSE == hasSystemRecordPassed ) { - 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 ) + enqueueEraseAndWriteSector ( NVM_SYSTEM_RECORD ); + sendNVEvent( NVM_SYSTEM_RECORD, 0, 0 ); } -#ifndef _RELEASE_ - if ( FALSE == hasSWConfigRecordPassed ) + // Validate service and calibration records + hasServiceRecordPassed = isDDServiceRecordValid(); + haveCalGroupsPassed = isDDCalibrationRecordValid(); + if ( ( FALSE == hasServiceRecordPassed ) || ( FALSE == haveCalGroupsPassed ) ) { - enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_SW_CONFIG_RECORD ); - SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_SW_CONFIG_RECORD ].nvEvent, 0, 0 ) + enqueueEraseAndWriteSector ( NVM_SERVICE_RECORD ); + sendNVEvent( NVM_SERVICE_RECORD, 0, 0 ); + sendNVEvent( NVM_CALIBRATION_RECORD, 0, 0 ); + + startNewCalRecordAvailableTimer(); + setNewCalibrationRecordAvailable( TRUE ); } -#endif + // Validate institutional record + hasInstitutionalRecordPassed = isDDInstitutionalRecordValid(); + if ( FALSE == hasInstitutionalRecordPassed ) + { + enqueueEraseAndWriteSector ( NVM_INSTITUTIONAL_RECORD ); + sendNVEvent( NVM_INSTITUTIONAL_RECORD, 0, 0 ); + } + + // Validate usage info record + hasUsageRecordPassed = isDDUsageRecordValid(); 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 ) + enqueueEraseAndWriteSector ( NVM_USAGE_INFO_RECORD ); + sendNVEvent( NVM_USAGE_INFO_RECORD, 0, 0 ); } // Check if the records' entire CRCs as well as the individual CRCs passed - if ( ( TRUE == haveCalGroupsPassed ) && ( TRUE == hasSystemRecordPassed ) && ( TRUE == hasServiceRecordPassed ) && ( TRUE == hasInstitutionalRecordPassed ) ) + if ( ( TRUE == hasSystemRecordPassed ) && ( TRUE == hasServiceRecordPassed ) && + ( TRUE == haveCalGroupsPassed ) && ( TRUE == hasInstitutionalRecordPassed ) && + ( TRUE == hasUsageRecordPassed ) ) { - newCalStartTimer = getMSTimerCount(); - isNewCalAvailable = TRUE; - nvDataMgmtSelfTestResult = SELF_TEST_STATUS_PASSED; - + nvmSelfTestResult = SELF_TEST_STATUS_PASSED; } else { - nvDataMgmtSelfTestResult = SELF_TEST_STATUS_FAILED; + nvmSelfTestResult = 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 + * The benignPolynomialCalRecord function fills the provided polynomial + * calibration record with benign default values and updates its CRC. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to the polynomial calibration record to update + * @return none *************************************************************************/ void benignPolynomialCalRecord( POLYNOMIAL_CAL_PAYLOAD_T* record ) { @@ -369,15 +445,12 @@ /*********************************************************************//** * @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 + * The isPolynomialRecordValid function checks if the polynomial record + * is valid by comparing calculated CRC with stored CRC. If invalid, + * it updates the record with benign values. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to the polynomial calibration record to check * @return TRUE if the records' data is valid otherwise FALSE *************************************************************************/ static BOOL isPolynomialRecordValid( POLYNOMIAL_CAL_PAYLOAD_T* record ) @@ -397,154 +470,179 @@ 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 + * The isDDSystemRecordValid function checks the validity of the DD + * system record. It verifies CRC and updates the record with default + * values if invalid. + * @details \b Alarms: ALARM_ID_DD_NVM_INVALID_SYSTEM_RECORD_CRC if CRC + * check fails, ALARM_ID_DD_NVM_INVALID_SERIAL_NUMBER if serial number + * is not initialized + * @details \b Inputs: ddSystemGroup.ddSystemRecord + * @details \b Outputs: ddSystemGroup.ddSystemRecord, ddSystemGroup.crc + * @return TRUE if the DD system record is valid otherwise FALSE *************************************************************************/ -static BOOL isSWConfigRecordValid( void ) +static BOOL isDDSystemRecordValid( void ) { - BOOL status = TRUE; + BOOL status = TRUE; + U16 calcCRC = crc16( (U08*)&ddSystemGroup.ddSystemRecord, sizeof( DD_SYSTEM_RECORD_T ) - sizeof( U16 ) ); + U16 recordCRC = ddSystemGroup.ddSystemRecord.crc; - 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 ) ); + // CRC did not pass so set all values to default + initDDSystemRecord(); + // Initialize the padding + updateRecordPadding( NVM_SYSTEM_RECORD ); + // Recalculate the CRC with the default values - ddSWConfigGroup.crc = crc16( (U08*)&ddSWConfigGroup, sizeof( DD_SW_CONFIG_GROUP_T ) - sizeof( U16 ) ); + updateRecordCRC( NVM_SYSTEM_RECORD ); - // Set the to FALSE since the record is not valid status = FALSE; + + activateAlarmNoData( ALARM_ID_DD_NVM_INVALID_SYSTEM_RECORD_CRC ); } + else + { + // Verify the serial number from the system record + if ( RECORD_DEFAULT_CHARACTER == ddSystemGroup.ddSystemRecord.topLevelSN[ 0 ] ) + { + activateAlarmNoData( ALARM_ID_DD_NVM_INVALID_SERIAL_NUMBER ); + } + } 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 + * The isDDServiceRecordValid function checks the validity of the DD + * service record. It verifies CRC and updates the record with default + * values if invalid. + * @details \b Alarms: ALARM_ID_DD_NVM_INVALID_SERVICE_RECORD_CRC if CRC + * check fails + * @details \b Inputs: ddServiceGroup.ddServiceRecord + * @details \b Outputs: ddServiceGroup.ddServiceRecord, + * ddServiceGroup.crc + * @return TRUE if the DD service record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDSystemRecordValid( void ) +static BOOL isDDServiceRecordValid( void ) { BOOL status = TRUE; - U16 calcCRC = crc16( (U08*)&ddSystemGroup.ddSystemRecord, sizeof( DD_SYSTEM_RECORD_T ) - sizeof( U16 ) ); - U16 recordCRC = ddSystemGroup.ddSystemRecord.crc; + 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 - 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 ) ); + initDDServiceRecord(); + // Initialize the padding + updateRecordPadding( NVM_SERVICE_RECORD ); + // 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; + updateRecordCRC( NVM_SERVICE_RECORD ); -// activateAlarmNoData( ALARM_ID_DD_INVALID_SYSTEM_RECORD_CRC ); + status = FALSE; + + // Service record failure + activateAlarmNoData( ALARM_ID_DD_NVM_INVALID_SERVICE_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 + * The isDDInstitutionalRecordValid function checks the validity of the DD + * institutional record. It verifies CRC and updates the record + * with default values if invalid. + * @details \b Alarms: ALARM_ID_DD_NVM_INVALID_INSTITUTIONAL_RECORD_CRC if CRC + * check fails + * @details \b Inputs: ddInstitutionalGroup + * @details \b Outputs: ddInstitutionalGroup + * @return TRUE if the DD Institutional record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDServiceRecordValid( void ) +static BOOL isDDInstitutionalRecordValid( void ) { BOOL status = TRUE; - U16 calcCRC = crc16( (U08*)&ddServiceGroup.ddServiceRecord, sizeof( DD_SERVICE_RECORD_T ) - sizeof( U16 ) ); - U16 recordCRC = ddServiceGroup.ddServiceRecord.crc; + U16 calcCRC = crc16( (U08*)&ddInstitutionalGroup.ddInstitutionalRecord, sizeof( DD_INSTITUTIONAL_RECORD_T ) - sizeof( U16 ) ); + U16 recordCRC = ddInstitutionalGroup.ddInstitutionalRecord.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; + initDDInstitutionalRecord(); - // Service record failure is also considered as RTC RAM failure -// activateAlarmNoData( ALARM_ID_DD_INVALID_SERVICE_RECORD_CRC ); + // Initialize the padding + updateRecordPadding( NVM_INSTITUTIONAL_RECORD ); + + // Recalculate the CRC with the default values + updateRecordCRC( NVM_INSTITUTIONAL_RECORD ); + + status = FALSE; + + // Institutional record failure is also considered as RTC RAM failure + activateAlarmNoData( ALARM_ID_DD_NVM_INVALID_INSTITUTIONAL_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 + * The isDDUsageRecordValid function checks the validity of the DD + * usage information record. It verifies CRC and updates the record + * with default values if invalid. + * @details \b Alarms: ALARM_ID_DD_NVM_INVALID_USAGE_RECORD_CRC if CRC + * check fails + * @details \b Inputs: ddUsageInfoGroup + * @details \b Outputs: ddUsageInfoGroup + * @return TRUE if the DD 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; + U16 calcCRC = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfoRecord, sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); + U16 recordCRC = ddUsageInfoGroup.ddUsageInfoRecord.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; + // CRC did not pass so set all values to default + initDDUsageRecord(); -// activateAlarmNoData( ALARM_ID_DD_INVALID_USAGE_RECORD_CRC ); + // Initialize the padding + updateRecordPadding( NVM_USAGE_INFO_RECORD ); + + // Recalculate the CRC with the default values + updateRecordCRC( NVM_USAGE_INFO_RECORD ); + status = FALSE; + + activateAlarmNoData( ALARM_ID_DD_NVM_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 + * The isDDCalibrationRecordValid function checks the validity of the DD + * calibration record. It verifies all calibration sub-records and + * updates them with benign values if invalid. + * @details \b Alarms: ALARM_ID_DD_NVM_INVALID_CALIBRATION_RECORD_CRC if + * CRC check fails or any sub-record is invalid + * @details \b Inputs: ddCalibrationGroup + * @details \b Outputs: ddCalibrationGroup + * @return TRUE if the DD 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 ) ); + U16 recordCRC = crc16 ( (U08*)&ddCalibrationGroup, sizeof( DD_CALIBRATION_GROUP_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 @@ -554,9 +652,9 @@ benignPolynomialCalRecord( &tempRecord ); // Get the calibration record of the hardware (i.e. pressure sensor) - DD_PRES_SENSORS_CAL_RECORD_T* pressure = &ddCalibrationRecord.ddCalibrationGroups.presSensorsCalRecord; + DD_PRES_SENSORS_CAL_RECORD_T* pressure = &ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord; // The ones that are an array, are looped through - for ( i = 0; i < NUM_OF_CAL_DATA_PRES_SENSORS; i++ ) + for ( i = 0; i < NUM_OF_PRESSURE_SENSORS; i++ ) { // Get calibration payload and assign it to a pointer record = (POLYNOMIAL_CAL_PAYLOAD_T*)&pressure->pressureSensors[ i ]; @@ -566,274 +664,188 @@ // 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; + isCalRecordValid = ( isCalRecordValid == FALSE ) ? FALSE : isHardwareRecordValid; } - for ( i = 0; i < PRES_SENSORS_RESERVED_SPACE_COUNT; i++ ) + DD_TEMP_SENSORS_CAL_RECORD_T* temperature = &ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord; + for ( i = 0; i < NUM_OF_TEMPERATURE_SENSORS; 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; + isCalRecordValid = ( isCalRecordValid == FALSE ) ? FALSE : isHardwareRecordValid; } - for ( i = 0; i < TEMP_SENSORS_RESERVED_SPACE_COUNT; i++ ) + DD_CONC_PUMPS_CAL_RECORD_T* concPump = &ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord; + for ( i = 0; i < NUM_OF_CONCENTRATE_PUMPS; 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 ]; + record = (POLYNOMIAL_CAL_PAYLOAD_T*)&concPump->concentratePumps[ i ]; isHardwareRecordValid = isPolynomialRecordValid( record ); - isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; + 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_D12_DIALYSATE_PUMP_RECORD_T* d12Pump = &ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord; + isHardwareRecordValid = isDDPumpD12RecordValid( d12Pump ); + isCalRecordValid = ( isCalRecordValid == FALSE ) ? FALSE : isHardwareRecordValid; - DD_RO_PUMP_CAL_RECORD_T* roPump = &ddCalibrationRecord.ddCalibrationGroups.roPumpRecord; - isHardwareRecordValid = isDDROPumpRecordValid( roPump ); - isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; + DD_D48_DIALYSATE_PUMP_RECORD_T* d48Pump = &ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord; + record = (POLYNOMIAL_CAL_PAYLOAD_T*)&d48Pump->d48DialysatePump; + isHardwareRecordValid = isPolynomialRecordValid( record ); + 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_RESERVOIR_VOLUME_RECORD_T* reservoirVol = &ddCalibrationRecord.ddCalibrationGroups.reservoirVolumesRecord; - for ( i = 0; i < NUM_OF_CAL_DATA_RSRVRS; i++ ) + DD_ACID_CONCENTRATES_RECORD_T* acidConc = &ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord; + for ( i = 0; i < NUM_OF_ACID_TYPE; i++ ) { - isHardwareRecordValid = isDDReservoirVolRecordValid( &reservoirVol->reservoir[ i ] ); - 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; + 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++ ) + DD_BICARB_CONCENTRATES_RECORD_T* bicarbConc = &ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord; + for ( i = 0; i < NUM_OF_BICARB_TYPE; i++ ) { isHardwareRecordValid = isDDBicarbConcentrateRecordValid( &bicarbConc->bicarbConcentrate[ i ] ); - isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; + isCalRecordValid = ( isCalRecordValid == FALSE ) ? FALSE : isHardwareRecordValid; } - DD_FILTER_CAL_RECORD_T* roFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.roFilter; - isHardwareRecordValid = isDDFilterRecordValid( roFilter ); - isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; + DD_ACCEL_SENSOR_CAL_RECORD_T* accelerometer = &ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord; + isHardwareRecordValid = isDDAccelerometerSensorRecordValid( accelerometer ); + isCalRecordValid = ( isCalRecordValid == FALSE ) ? FALSE : isHardwareRecordValid; - DD_FILTER_CAL_RECORD_T* ultraFilter = &ddCalibrationRecord.ddCalibrationGroups.filtersRecord.ultraFilter; - isHardwareRecordValid = isDDFilterRecordValid( ultraFilter ); - isCalRecordValid = isCalRecordValid == FALSE ? FALSE : isHardwareRecordValid; + DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T* bloodLeak = &ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord; + isHardwareRecordValid = isDDBloodLeakSensorValid( bloodLeak ); + 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 ) ) + if ( ( FALSE == isCalRecordValid ) || ( recordCRC != ddCalibrationGroup.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 ); + // Initialize the padding + updateRecordPadding( NVM_USAGE_INFO_RECORD ); + + // Recalculate the CRC + ddCalibrationGroup.crc = crc16 ( (U08*)&ddCalibrationGroup, sizeof( DD_CALIBRATION_GROUP_T ) - sizeof( U16 ) ); + + activateAlarmNoData( ALARM_ID_DD_NVM_INVALID_CALIBRATION_RECORD_CRC ); } 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 + * The isDDPumpD12RecordValid function checks if the D12 Dialysate Pump + * record is valid. It verifies CRC and updates + * the record with default values if invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to DD D12 Dialysate record to check * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDDrainPumpRecordValid( DD_DRAIN_PUMP_CAL_RECORD_T* record ) +static BOOL isDDPumpD12RecordValid( DD_D12_DIALYSATE_PUMP_RECORD_T* record ) { BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_DRAIN_PUMP_CAL_RECORD_T) - sizeof(U16) ); + U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_D12_DIALYSATE_PUMP_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; + record->targetPumpSpeed = DEFAULT_D12_PUMP_TARGET_SPEED; + record->calibrationTime = RECORD_DEFAULT_TIME; + record->crc = crc16 ( (U08*)record, sizeof( DD_D12_DIALYSATE_PUMP_RECORD_T ) - sizeof( U16 ) ); + 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 + * The isDDAcidConcentrateRecordValid function checks if the acid + * concentrate calibration record is valid. It verifies CRC and updates + * the record with default values if invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to DD acid concentrate record to check * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDROPumpRecordValid( DD_RO_PUMP_CAL_RECORD_T* record ) +static BOOL isDDAcidConcentrateRecordValid( DD_ACID_CONCENTRATE_T* record ) { BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_RO_PUMP_CAL_RECORD_T) - sizeof(U16) ); + 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->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; + record->acidConcMixRatio = DEFAULT_ACID_CONC_MIXING_RATIO; + record->acidFullBottleVolumeML = DEFAULT_ACID_BOTTLE_VOL_ML; + record->acidConductivityUSPerCM = DEFAULT_ACID_COND_US_PER_CM; + record->acidBottleTemperature = DEFAULT_ACID_BOTTLE_TEMP_C; + record->calibrationTime = RECORD_DEFAULT_TIME; + record->crc = crc16 ( (U08*)record, sizeof( DD_ACID_CONCENTRATE_T ) - sizeof( U16 ) ); + 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 + * The isDDBicarbConcentrateRecordValid function checks if the bicarb + * concentrate calibration record is valid. It verifies CRC and updates + * the record with default values if invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to DD bicarb concentrate record to check * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDPreROPurgeVolumeRecordValid( DD_PRE_RO_PURGE_VOLUME_T* record ) +static BOOL isDDBicarbConcentrateRecordValid( DD_BICARB_CONCENTRATE_T* record ) { BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_PRE_RO_PURGE_VOLUME_T) - sizeof(U16) ); + 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->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; + record->bicarbConcMixRatio = DEFAULT_BICARB_CONC_MIXING_RATIO; + record->bicarbStartVolumeML = DEFAULT_BICARB_BOTTLE_VOL_ML; + record->bicarbConductivityUSPerCM = DEFAULT_BICARB_COND_US_PER_CM; + record->bicarbBottleTemperature = DEFAULT_BICARB_BOTTLE_TEMP_C; + record->calibrationTime = RECORD_DEFAULT_TIME; + record->crc = crc16 ( (U08*)record, sizeof( DD_BICARB_CONCENTRATE_T ) - sizeof( U16 ) ); + 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 + * The isDDAccelerometerSensorRecordValid function checks if the + * accelerometer sensor calibration record is valid. It verifies CRC + * and updates the record with default values if invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to accelerometer sensor calibration record to check * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDDrainLineVolRecordValid( DD_DRAIN_LINE_VOLUME_T* record ) +static BOOL isDDAccelerometerSensorRecordValid( DD_ACCEL_SENSOR_CAL_RECORD_T* record ) { BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_DRAIN_LINE_VOLUME_T) - sizeof(U16) ); + 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->volume = DEFAULT_FLUSH_LINES_VOLUME_L; + 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_DRAIN_LINE_VOLUME_T) - sizeof(U16) ); + 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; @@ -844,28 +856,25 @@ /*********************************************************************//** * @brief - * The isDDReservoirVolRecordValid function checks whether the calibration - * record of reservoir volume is valid or not. - * @details Inputs: none - * @details Outputs: none - * @param record: DD_RESERVOIR_VOLUME_DATA_T pointer + * The isDDBloodLeakSensorValid function checks if the blood leak sensor + * calibration record is valid. It verifies CRC and updates the record + * with default values if invalid. + * @details \b Inputs: none + * @details \b Outputs: none + * @param record Pointer to blood leak sensor calibration record to check * @return TRUE if the record is valid otherwise FALSE *************************************************************************/ -static BOOL isDDReservoirVolRecordValid( DD_RESERVOIR_VOLUME_DATA_T* record ) +static BOOL isDDBloodLeakSensorValid( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T* record ) { BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_RESERVOIR_VOLUME_DATA_T) - sizeof(U16) ); + U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ) - sizeof( U16 ) ); U16 recordCRC = record->crc; if ( calcCRC != recordCRC ) { - // CRC did not pass so set all values to default - record->maxResidualFluid = RECORD_DEFAULT_CONST; - record->normalFillVolume = RECORD_DEFAULT_CONST; - record->rsrvrUnfilledWeight = EMPTY_RESERVOIR_WEIGHT_GRAMS; - record->rsrvrVolume = RECORD_DEFAULT_CONST; - record->calibrationTime = RECORD_DEFAULT_TIME; - record->crc = crc16 ( (U08*)record, sizeof(DD_RESERVOIR_VOLUME_DATA_T) - sizeof(U16) ); + record->setPoint = DEFAULT_BLOOD_LEAK_SET_POINT; + record->calibrationTime = RECORD_DEFAULT_TIME; + record->crc = crc16 ( (U08*)record, sizeof( DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ) - sizeof( U16 ) ); // Set the to FALSE since the record is not valid status = FALSE; @@ -876,318 +885,1228 @@ /*********************************************************************//** * @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 + * The initDDSystemRecord function initializes the DD system record + * with default values. It resets configuration fields and fills + * string fields with default characters. + * @details \b Inputs: none + * @details \b Outputs: ddSystemGroup.ddSystemRecord + * @return none *************************************************************************/ -static BOOL isDDGenericVolRecordValid( DD_GENERIC_VOLUME_DATA_T* record ) +static void initDDSystemRecord( void ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_GENERIC_VOLUME_DATA_T ) - sizeof( U16 ) ); - U16 recordCRC = record->crc; + ddSystemGroup.ddSystemRecord.isROFeatured = FALSE; + ddSystemGroup.ddSystemRecord.isROFeaturedBoostPump = FALSE; + memset( ddSystemGroup.ddSystemRecord.topLevelPN, RECORD_DEFAULT_CHARACTER, sizeof( ddSystemGroup.ddSystemRecord.topLevelPN ) ); + memset( ddSystemGroup.ddSystemRecord.topLevelSN, RECORD_DEFAULT_CHARACTER, sizeof( ddSystemGroup.ddSystemRecord.topLevelSN ) ); + ddSystemGroup.ddSystemRecord.mfgLocation = 0; + ddSystemGroup.ddSystemRecord.mfgDate = 0; +} - if ( calcCRC != recordCRC ) +/*********************************************************************//** + * @brief + * The initDDServiceRecord function initializes the DD service record + * with default values. It resets service related information and + * timestamps. + * @details \b Inputs: none + * @details \b Outputs: ddServiceGroup.ddServiceRecord + * @return none + *************************************************************************/ +static void initDDServiceRecord( void ) +{ + ddServiceGroup.ddServiceRecord.isHDFOnlineFluid = FALSE; + ddServiceGroup.ddServiceRecord.waterRecovery = 0; + ddServiceGroup.ddServiceRecord.serviceLoc = 0; + ddServiceGroup.ddServiceRecord.lastServiceEpochDate = 0; + ddServiceGroup.ddServiceRecord.serviceIntervalSeconds = 0; + + // TODO: Update lastResetTimeEpoch to current timestamp published by UI. + ddServiceGroup.ddServiceRecord.lastResetTimeEpoch = RECORD_DEFAULT_TIME; +} + +/*********************************************************************//** + * @brief + * The initDDInstitutionalRecord function initializes the DD + * institutional record with default values. It sets configuration + * limits, alarm thresholds, and treatment options to default values. + * @details \b Inputs: none + * @details \b Outputs: ddInstitutionalGroup.ddInstitutionalRecord + * @return none + *************************************************************************/ +static void initDDInstitutionalRecord( void ) +{ + ddInstitutionalGroup.ddInstitutionalRecord.minDialysateFlowMLPM = DEFAULT_MIN_DIALYSATE_FLOW_MLPM; + ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateFlowMLPM = DEFAULT_MAX_DIALYSATE_FLOW_MLPM; + ddInstitutionalGroup.ddInstitutionalRecord.minDialysateTempC = DEFAULT_MIN_DIALYSATE_TEMP_C; + ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateTempC = DEFAULT_MAX_DIALYSATE_TEMP_C; + ddInstitutionalGroup.ddInstitutionalRecord.minAcidConcentrate = DEFAULT_MIN_ACID_CONCENTRATE; + ddInstitutionalGroup.ddInstitutionalRecord.maxAcidConcentrate = DEFAULT_MAX_ACID_CONCENTRATE; + ddInstitutionalGroup.ddInstitutionalRecord.minBicarbCartridgeSizeG = DEFAULT_MIN_BICARB_CARTRIDGE_SIZE_G; + ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbCartridgeSizeG = DEFAULT_MAX_BICARB_CARTRIDGE_SIZE_G; + ddInstitutionalGroup.ddInstitutionalRecord.minSodiumMEQL = DEFAULT_MIN_SODIUM_MEQL; + ddInstitutionalGroup.ddInstitutionalRecord.maxSodiumMEQL = DEFAULT_MAX_SODIUM_MEQL; + ddInstitutionalGroup.ddInstitutionalRecord.minBicarbonateMEQL = DEFAULT_MIN_BICARBONATE_MEQL; + ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbonateMEQL = DEFAULT_MAX_BICARBONATE_MEQL; + ddInstitutionalGroup.ddInstitutionalRecord.minRORejectionRatioPCT = DEFAULT_MAX_RO_REJECTION_RATIO_PCT; + ddInstitutionalGroup.ddInstitutionalRecord.disinfectionFrequency = DEFAULT_NUM_OF_DISINFECTION_FREQUENCY; + ddInstitutionalGroup.ddInstitutionalRecord.disinfectionCycleTime = DEFAULT_NUM_OF_DISINFECTION_CYCLE_TIME; + ddInstitutionalGroup.ddInstitutionalRecord.minInletWaterCondAlarmLimitUSPCM = DEFAULT_MIN_INLET_WATER_COND_ALARM_US_P_CM; + ddInstitutionalGroup.ddInstitutionalRecord.maxInletWaterCondAlarmLimitUSPCM = DEFAULT_MAX_INLET_WATER_COND_ALARM_US_P_CM; + ddInstitutionalGroup.ddInstitutionalRecord.acidConcentrateJugSizeL = DEFAULT_ACID_CONCENTRATE_JUG_SIZE; + ddInstitutionalGroup.ddInstitutionalRecord.minAcidAlarmLimitPCT = DEFAULT_MIN_ACID_ALARM_US_P_CM; + ddInstitutionalGroup.ddInstitutionalRecord.minBicarbAlarmLimitPCT = DEFAULT_MIN_BICARB_ALARM_US_P_CM; + ddInstitutionalGroup.ddInstitutionalRecord.postTreatDrainOption = DEFAULT_POST_TREATMENT_DRAIN_OPTION; + ddInstitutionalGroup.ddInstitutionalRecord.postTreatDryBicarbOption = DEFAULT_POST_TREATMENT_DRY_BICARB_OPTION; + + // TODO: Update lastUpdatedTime to current timestamp published by UI. + ddInstitutionalGroup.ddInstitutionalRecord.lastUpdatedTime = RECORD_DEFAULT_TIME; +} + +/*********************************************************************//** + * @brief + * The initDDUsageRecord function initializes the DD usage record with + * default values. It resets usage information, counters, and + * maintenance timestamps. + * @details \b Inputs: none + * @details \b Outputs: ddUsageInfoGroup.ddUsageInfoRecord + * @return none + *************************************************************************/ +static void initDDUsageRecord( void ) +{ + ddUsageInfoGroup.ddUsageInfoRecord.roWaterGenTotalL = 0.0F; + ddUsageInfoGroup.ddUsageInfoRecord.roWaterGenSinceLastServiceL = 0.0F; + ddUsageInfoGroup.ddUsageInfoRecord.lastBasicFlushCompleteDateEpoch = 0; + ddUsageInfoGroup.ddUsageInfoRecord.lastHeatDisCompleteDateEpoch = 0; + ddUsageInfoGroup.ddUsageInfoRecord.lastHeatActiveCoolCompleteDateEpoch = 0; + ddUsageInfoGroup.ddUsageInfoRecord.lastFilterFlushCompleteDateEpoch = 0; +// ddUsageInfoGroup.ddUsageInfoRecord.lastResetTimeEpoch = getRTCTimestamp(); +} + +/*********************************************************************//** + * @brief + * The updateRecordPadding function updates the padding bytes of the + * specified NV record. It clears all padding bytes to ensure + * consistent CRC calculation and record storage. + * @details \b Inputs: none + * @details \b Outputs: ddSystemGroup.padding, + * ddServiceGroup.padding, ddCalibrationGroup.padding, + * ddInstitutionalGroup.padding, ddUsageInfoGroup.padding + * @param recType Record type whose padding needs to be updated + * @return none + *************************************************************************/ +static void updateRecordPadding( NVM_RECORD_TYPE_T recType ) +{ + U32 i = 0; + + switch ( recType ) { - // 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; + case NVM_SYSTEM_RECORD: + for ( i = 0; i < SYSTEM_RECORD_PADDING_LENGTH; i++ ) + { + ddSystemGroup.padding[ i ] = 0; + } + break; + + case NVM_SERVICE_RECORD: + for ( i = 0; i < SERVICE_RECORD_PADDING_LENGTH; i++ ) + { + ddServiceGroup.padding[ i ] = 0; + } + break; + + case NVM_CALIBRATION_RECORD: + for ( i = 0; i < CALIBRATION_RECORD_PADDING_LENGTH; i++ ) + { + ddCalibrationGroup.padding[ i ] = 0; + } + break; + + case NVM_INSTITUTIONAL_RECORD: + for ( i = 0; i < INSTITUTIONAL_RECORD_PADDING_LENGTH; i++ ) + { + ddInstitutionalGroup.padding[ i ] = 0; + } + break; + + case NVM_USAGE_INFO_RECORD: + for ( i = 0; i < USAGE_INFO_RECORD_PADDING_LENGTH; i++ ) + { + ddUsageInfoGroup.padding[ i ] = 0; + } + break; + + default: + break; } +} - return status; +/*********************************************************************//** + * @brief + * The updateRecordCRC function updates the CRC values of the specified + * NV record and its associated group. It recalculates CRCs based on + * the current record contents. + * @details \b Inputs: none + * @details \b Outputs: ddSystemGroup.ddSystemRecord.crc, + * ddSystemGroup.crc, ddServiceGroup.ddServiceRecord.crc, + * ddServiceGroup.crc, ddCalibrationGroup.crc, + * ddInstitutionalGroup.ddInstitutionalRecord.crc, + * ddInstitutionalGroup.crc, + * ddUsageInfoGroup.ddUsageInfoRecord.crc, + * ddUsageInfoGroup.crc + * @param recType Record type whose CRC needs to be updated + * @return none + *************************************************************************/ +void updateRecordCRC( NVM_RECORD_TYPE_T recType ) +{ + switch ( recType ) + { + case NVM_SYSTEM_RECORD: + 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 ) ); + break; + + case NVM_SERVICE_RECORD: + 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 ) ); + break; + + case NVM_CALIBRATION_RECORD: + ddCalibrationGroup.crc = crc16 ( (U08*)&ddCalibrationGroup, + sizeof( DD_CALIBRATION_GROUP_T ) - sizeof( U16 ) ); + break; + + case NVM_INSTITUTIONAL_RECORD: + ddInstitutionalGroup.ddInstitutionalRecord.crc = crc16 ( (U08*)&ddInstitutionalGroup.ddInstitutionalRecord, + sizeof( DD_INSTITUTIONAL_RECORD_T ) - sizeof( U16 ) ); + ddInstitutionalGroup.crc = crc16 ( (U08*)&ddInstitutionalGroup, + sizeof( DD_INSTITUTIONAL_GROUP_T ) - sizeof( U16 ) ); + break; + + case NVM_USAGE_INFO_RECORD: + ddUsageInfoGroup.ddUsageInfoRecord.crc = crc16 ( (U08*)&ddUsageInfoGroup.ddUsageInfoRecord, + sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); + ddUsageInfoGroup.crc = crc16 ( (U08*)&ddUsageInfoGroup, + sizeof( DD_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); + break; + + default: + break; + } } /*********************************************************************//** * @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 + * The setLastDisinfectDate function updates the last disinfect time in + * usage info and schedules a write to memory if queue is available. + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid disinfect + * type is selected or write retries exceed limit + * @details \b Inputs: ddUsageInfoGroup, usageWriteTries + * @details \b Outputs: ddUsageInfoGroup, usageWriteTries + * @param disinfect Type of disinfect operation + * @param epochTime Last disinfect time in epoch + * @return TRUE if queue is not full otherwise FALSE *************************************************************************/ -static BOOL isDDAcidConcentrateRecordValid( DD_ACID_CONCENTRATE_T* record ) +BOOL setLastDisinfectDate( DD_USAGE_INFO_ITEMS_T disinfect, U32 epochTime ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_ACID_CONCENTRATE_T ) - sizeof( U16 ) ); - U16 recordCRC = record->crc; + BOOL status = FALSE; - if ( calcCRC != recordCRC ) + if ( FALSE == isRecordQueueFull() ) { - // 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; + switch ( disinfect ) + { + case USAGE_INFO_BASIC_FLUSH: + ddUsageInfoGroup.ddUsageInfoRecord.lastBasicFlushCompleteDateEpoch = epochTime; + break; + + case USAGE_INFO_HEAT_DIS: + ddUsageInfoGroup.ddUsageInfoRecord.lastHeatDisCompleteDateEpoch = epochTime; + break; + + case USAGE_INFO_FILTER_FLUSH: + ddUsageInfoGroup.ddUsageInfoRecord.lastFilterFlushCompleteDateEpoch = epochTime; + break; + + case USAGE_INFO_HEAT_DIS_ACTIVE_COOL: + ddUsageInfoGroup.ddUsageInfoRecord.lastHeatActiveCoolCompleteDateEpoch = epochTime; + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVM_INVALID_USAGE_INFO_SELECTED, ( U32 )disinfect ); + break; + } + + ddUsageInfoGroup.ddUsageInfoRecord.crc = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfoRecord, 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; + + enqueueEraseAndWriteSector( NVM_USAGE_INFO_RECORD ); + sendNVEvent( NVM_USAGE_INFO_RECORD, 0, 0 ); } + else if ( ++usageWriteTries > MAX_NUM_OF_WRITE_TRIES ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVM_WRITE_USAGE_INFO_FAILURE, ( U32 )disinfect ); + } 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 + * The setServiceTime function updates the latest service time and + * resets related usage information. It schedules writing updated + * records if sufficient queue space is available. + * @details \b Inputs: ddServiceGroup, ddUsageInfoGroup + * @details \b Outputs: ddServiceGroup, ddUsageInfoGroup + * @return TRUE if the queue has sufficient space to enqueue all the + * changed records otherwise FALSE *************************************************************************/ -static BOOL isDDBicarbConcentrateRecordValid( DD_BICARB_CONCENTRATE_T* record ) +BOOL setServiceTime( void ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof( DD_BICARB_CONCENTRATE_T ) - sizeof( U16 ) ); - U16 recordCRC = record->crc; + BOOL status = FALSE; - if ( calcCRC != recordCRC ) + if ( getAvailableRecordQueueCount() >= ( MIN_JOBS_NEEDED_TO_WRITE_ALL_RECORDS + 1 ) ) { - // 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; + // 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.ddUsageInfoRecord.roWaterGenSinceLastServiceL = 0; + ddUsageInfoGroup.ddUsageInfoRecord.crc = crc16( (U08*)&ddUsageInfoGroup.ddUsageInfoRecord, 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 + enqueueEraseAndWriteSector( NVM_SERVICE_RECORD ); + enqueueEraseAndWriteSector( NVM_USAGE_INFO_RECORD ); + // Both the usage and service records have been updated + sendNVEvent( NVM_USAGE_INFO_RECORD, 0, 0 ); + sendNVEvent( NVM_SERVICE_RECORD, 0, 0 ); + + status = TRUE; } 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 + * The getMinRORejectionRatioInInstitRecordPCT function gets the minimum + * RO rejection ratio value from the institutional record in percent. + * @details \b Inputs: ddInstitutionalGroup + * @details \b Outputs: none + * @return the min RO rejection ratio in institutional record in percent *************************************************************************/ -static BOOL isDDFilterRecordValid( DD_FILTER_CAL_RECORD_T* record ) +U32 getMinRORejectionRatioInInstitRecordPCT( void ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_FILTER_CAL_RECORD_T) - sizeof(U16) ); - U16 recordCRC = record->crc; + return ddInstitutionalGroup.ddInstitutionalRecord.minRORejectionRatioPCT; +} - if ( calcCRC != recordCRC ) +/*********************************************************************//** + * @brief + * The getMinInletWaterConductivityLimitInstitRecordUSPCM function gets + * the inlet water conductivity alarm limit value from the institutional + * record in uS/cm. + * @details \b Inputs: ddInstitutionalGroup + * @details \b Outputs: none + * @return the inlet water conductivity alarm limit in uS/cm in + * institutional record + *************************************************************************/ + +F32 getMinInletWaterConductivityLimitInstitRecordUSPCM( void ) +{ + return ddInstitutionalGroup.ddInstitutionalRecord.minInletWaterCondAlarmLimitUSPCM; +} + +/*********************************************************************//** + * @brief + * The getPressureSensorCalRecord function gets the calibration record + * of the specified pressure sensor. + * @details \b Inputs: ddCalibrationGroup.ddCalibrationRecord + * @details \b Outputs: none + * @param snsrIdx Pressure sensor index + * @return record corresponding pressure sensor calibration record + *************************************************************************/ +POLYNOMIAL_CAL_PAYLOAD_T getPressureSensorCalRecord( U08 snsrIdx ) +{ + POLYNOMIAL_CAL_PAYLOAD_T record; + benignPolynomialCalRecord( &record ); + + if ( snsrIdx < NUM_OF_PRESSURE_SENSORS ) { - // 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) ); + record = ( ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord.pressureSensors[ snsrIdx ] ); + } - // Set the to FALSE since the record is not valid - status = FALSE; + return record; +} + +/*********************************************************************//** + * @brief + * The getTemperatureSensorCalRecord function gets the calibration + * record of the specified temperature sensor. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord + * @details \b Outputs: none + * @param snsrIdx Temperature sensor index + * @return record corresponding temperature sensor calibration record + *************************************************************************/ +POLYNOMIAL_CAL_PAYLOAD_T getTemperatureSensorCalRecord( U08 snsrIdx ) +{ + POLYNOMIAL_CAL_PAYLOAD_T record; + benignPolynomialCalRecord( &record ); + + if ( snsrIdx < NUM_OF_TEMPERATURE_SENSORS ) + { + record = ( ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord.tempSensors[ snsrIdx ] ); } - return status; + return record; } /*********************************************************************//** * @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 + * The getConcPumpCalRecord function gets the calibration record of the + * specified concentrate pump. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord + * @details \b Outputs: none + * @param pumpIdx Concentrate pump index + * @return record corresponding concentrate pump calibration record *************************************************************************/ -static BOOL isDDFanRecordValid( DD_FAN_CAL_RECORD_T* record ) +POLYNOMIAL_CAL_PAYLOAD_T getConcPumpCalRecord( U08 pumpIdx ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_FAN_CAL_RECORD_T) - sizeof(U16) ); - U16 recordCRC = record->crc; + POLYNOMIAL_CAL_PAYLOAD_T record; + benignPolynomialCalRecord( &record ); - if ( calcCRC != recordCRC ) + if ( pumpIdx < NUM_OF_CONCENTRATE_PUMPS ) { - // 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) ); + record = ( ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord.concentratePumps[ pumpIdx ] ); + } - // Set the to FALSE since the record is not valid - status = FALSE; + return record; +} + +/*********************************************************************//** + * @brief + * The getD12PumpCalRecord function gets the calibration record of the + * D12 dialysate pump. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord + * @details \b Outputs: none + * @return ddCalibrationGroup.ddCalibrationRecord. + * d12DialysatePumpRecord + *************************************************************************/ +DD_D12_DIALYSATE_PUMP_RECORD_T getD12PumpCalRecord( void ) +{ + return ( ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord ); +} + +/*********************************************************************//** + * @brief + * The getD48PumpCalRecord function gets the calibration record of the + * D48 dialysate pump. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord + * @details \b Outputs: none + * @return ddCalibrationGroup.ddCalibrationRecord. + * d48DialysatePumpRecord + *************************************************************************/ +DD_D48_DIALYSATE_PUMP_RECORD_T getD48PumpCalRecord( void ) +{ + return ( ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord ); +} + +/*********************************************************************//** + * @brief + * The getAcidConcentrateCalRecord function gets the calibration record + * of the specified acid concentrate. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord + * @details \b Outputs: none + * @param acidIdx Acid concentrate index + * @return record corresponding acid concentrate calibration record + *************************************************************************/ +DD_ACID_CONCENTRATE_T getAcidConcentrateCalRecord( U08 acidIdx ) +{ + DD_ACID_CONCENTRATE_T record = { 0 }; + + if ( acidIdx < NUM_OF_ACID_TYPE ) + { + record = ( ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord.acidConcentrate[ acidIdx ] ); } - return status; + return record; } /*********************************************************************//** * @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 + * The getBicarbConcentrateCalRecord function gets the calibration + * record of the specified bicarb concentrate. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord + * @details \b Outputs: none + * @param bicarbIdx Bicarb concentrate index + * @return record corresponding bicarb concentrate calibration record *************************************************************************/ -static BOOL isDDAccelerometerSensorRecordValid( DD_ACCEL_SENSOR_CAL_RECORD_T* record ) +DD_BICARB_CONCENTRATE_T getBicarbConcentrateCalRecord( U08 bicarbIdx ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_ACCEL_SENSOR_CAL_RECORD_T) - sizeof(U16) ); - U16 recordCRC = record->crc; + DD_BICARB_CONCENTRATE_T record = { 0 }; - if ( calcCRC != recordCRC ) + if ( bicarbIdx < NUM_OF_BICARB_TYPE ) { - // 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) ); + record = ( ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord.bicarbConcentrate[ bicarbIdx ] ); + } - // Set the to FALSE since the record is not valid - status = FALSE; + return record; +} + +/*********************************************************************//** + * @brief + * The getAccelSensorCalRecord function gets the calibration record of + * the accelerometer sensor. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord. + * accelerometerSensorCalRecord + * @details \b Outputs: none + * @return ddCalibrationGroup.ddCalibrationRecord. + * accelerometerSensorCalRecord + *************************************************************************/ +DD_ACCEL_SENSOR_CAL_RECORD_T getAccelSensorCalRecord( void ) +{ + return ( ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord ); +} + +/*********************************************************************//** + * @brief + * The getBloodLeakSensorCalRecord function gets the calibration record + * of the blood leak sensor. + * @details \b Inputs: + * ddCalibrationGroup.ddCalibrationRecord. + * bloodLeakSensorCalRecord + * @details \b Outputs: none + * @return ddCalibrationGroup.ddCalibrationRecord. + * bloodLeakSensorCalRecord + *************************************************************************/ +DD_BLOOD_LEAK_SENSOR_CAL_RECORD_T getBloodLeakSensorCalRecord( void ) +{ + return ( ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord ); +} + +/*********************************************************************//** + * @brief + * The getNVMRecord function copies the requested non-volatile + * data into the provided buffer and checks if the data is valid. It + * raises the specified alarm if invalid data is detected. + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid record is + * selected, nvAlarm if non-volatile data is invalid + * @details \b Inputs: ddCalibrationGroup + * @details \b Outputs: none + * @param nvData The non-volatile data to be copied + * @param bufferAddress Address of the provided buffer + * @param bufferLength Length of the provided buffer + * @param numOfSnsrs2Check Number of sensors to check + * @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 getNVMRecord( 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*)&ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord ); + for ( i = 0; i < numOfSnsrs2Check; i++ ) + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord.pressureSensors[ i ].calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_TEMP_SENSORS: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord ); + for ( i = 0; i < numOfSnsrs2Check; i++ ) + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord.tempSensors[ i ].calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_CONCENTRATE_PUMPS_RECORD: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord ); + for ( i = 0; i < numOfSnsrs2Check; i++ ) + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord.concentratePumps[ i ].calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_D12_PUMP_RECORD: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord ); + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord.calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_D48_PUMP_RECORD: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord ); + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord.d48DialysatePump.calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_ACID_CONCENTREATES: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord ); + for ( i = 0; i < numOfSnsrs2Check; i++ ) + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord.acidConcentrate[ i ].calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_BICARB_CONCENTRATES: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord ); + for ( i = 0; i < numOfSnsrs2Check; i++ ) + isNVDataInvalid |= ( 0 == ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord.bicarbConcentrate[ i ].calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_ACCEL_SENSORS: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord; + isNVDataInvalid = ( 0 == ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord.calibrationTime ? TRUE : FALSE ); + break; + + case GET_CAL_BLOOD_LEAK_SENSOR: + nvDataStartPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord; + nvDataLength = sizeof( ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord ); + isNVDataInvalid = ( 0 == ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord.calibrationTime ? TRUE : FALSE ); + break; + + case GET_SYSTEM_RECORD: + nvDataStartPtr = (U08*)&ddSystemGroup.ddSystemRecord; + nvDataLength = sizeof( ddSystemGroup.ddSystemRecord ); + break; + + case GET_SERVICE_RECORD: + nvDataStartPtr = (U08*)&ddServiceGroup.ddServiceRecord; + nvDataLength = sizeof( ddServiceGroup.ddServiceRecord ); + break; + + case GET_INSTITUTIONAL_RECORD: + nvDataStartPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord; + nvDataLength = sizeof( ddInstitutionalGroup.ddInstitutionalRecord ); + break; + + case GET_USAGE_RECORD: + nvDataStartPtr = (U08*)&ddUsageInfoGroup.ddUsageInfoRecord; + nvDataLength = sizeof( ddUsageInfoGroup.ddUsageInfoRecord ); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_NVM_INVALID_RECORD_SELECTED, ( U32 )nvData ); + break; } - return status; + // 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 + { +// activateAlarmNoData( nvAlarm ); + } + } + + // Reverse the polarity to signal the outside users that the calibration has passed. + return ( FALSE == isNVDataInvalid ? TRUE : FALSE ); } /*********************************************************************//** * @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 + * The setNVMRecord function updates the specified NV record with the + * provided data buffer. It copies the record data and updates the + * corresponding CRC values. + * @details \b Inputs: none + * @details \b Outputs: ddSystemGroup.ddSystemRecord, + * ddServiceGroup.ddServiceRecord, + * ddUsageInfoGroup.ddUsageInfoRecord, + * ddSystemGroup.crc, ddServiceGroup.crc, + * ddUsageInfoGroup.crc + * @param recType Record type to update + * @param bufferAddress Pointer to the source data buffer + * @return TRUE if the record was updated successfully otherwise FALSE *************************************************************************/ -static BOOL isDDHeatingCalRecordValid( DD_HEATING_CAL_RECORD_T* record ) +BOOL setNVMRecord( NVM_RECORD_TYPE_T recType, U08* bufferAddress ) { - BOOL status = TRUE; - U16 calcCRC = crc16 ( (U08*)record, sizeof(DD_HEATING_CAL_RECORD_T) - sizeof(U16) ); - U16 recordCRC = record->crc; + BOOL result = FALSE; + U08* destPtr = NULL; + U16 dataSize = 0; - if ( calcCRC != recordCRC ) + switch ( recType ) { - // 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) ); + case NVM_SYSTEM_RECORD: + destPtr = (U08*)&ddSystemGroup.ddSystemRecord; + dataSize = sizeof( ddSystemGroup.ddSystemRecord ); + break; - // Set the to FALSE since the record is not valid - status = FALSE; + case NVM_SERVICE_RECORD: + destPtr = (U08*)&ddServiceGroup.ddServiceRecord; + dataSize = sizeof( ddServiceGroup.ddServiceRecord ); + break; + + case NVM_USAGE_INFO_RECORD: + destPtr = (U08*)&ddUsageInfoGroup.ddUsageInfoRecord; + dataSize = sizeof( ddUsageInfoGroup.ddUsageInfoRecord ); + break; + + default: + break; } - return status; + if ( ( destPtr != NULL ) && ( bufferAddress != NULL ) && ( dataSize > 0 ) ) + { + + memcpy( destPtr, bufferAddress, dataSize ); + updateRecordCRC( recType ); + result = TRUE; + } + + return result; + } /*********************************************************************//** * @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 + * The setNVMCalRecord function updates the specified calibration + * record with the provided data buffer. It copies the calibration + * data and updates the calibration record CRC. + * @details \b Inputs: none + * @details \b Outputs: ddCalibrationGroup.ddCalibrationRecord, + * ddCalibrationGroup.crc + * @param calRecType Calibration record type to update + * @param bufferAddress Pointer to the source data buffer + * @param idx Calibration record index + * @return TRUE if the calibration record was updated successfully + * otherwise FALSE *************************************************************************/ -BOOL setLastDisinfectDate( DG_USAGE_INFO_ITEMS_T disinfect, U32 epochTime ) +BOOL setNVMCalRecord( DD_CAL_REC_TYPE calRecType, U08* bufferAddress, U08 idx ) { - BOOL status = FALSE; + BOOL result = FALSE; + U08* destPtr = NULL; + U16 dataSize = 0; - if ( FALSE == isQueueFull() ) + switch ( calRecType ) { - switch ( disinfect ) - { - case USAGE_INFO_BASIC_FLUSH: - dgUsageInfoGroup.dgUsageInfo.lastBasicFlushCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_PRESSURE_SENSOR: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord.pressureSensors[ idx ]; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.presSensorsCalRecord.pressureSensors[ 0 ] ); + break; - case USAGE_INFO_CHEM_DIS_START: - dgUsageInfoGroup.dgUsageInfo.lastChemDisStartDateEpoch = epochTime; - break; + case DD_CAL_RECORD_TEMPERATURE_SENSOR: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord.tempSensors[ idx ]; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.tempSensorsCalRecord.tempSensors[ 0 ] ); + break; - case USAGE_INFO_CHEM_DIS: - dgUsageInfoGroup.dgUsageInfo.lastChemDisCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_CONCENTRATE_PUMP: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord.concentratePumps[ idx ]; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.concentratePumpsRecord.concentratePumps[ 0 ] ); + break; - case USAGE_INFO_CHEM_FLUSH: - dgUsageInfoGroup.dgUsageInfo.lastChemDisFlushCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_D12_PUMP: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.d12DialysatePumpRecord ); + break; - case USAGE_INFO_HEAT_DIS: - dgUsageInfoGroup.dgUsageInfo.lastHeatDisCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_D48_PUMP: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.d48DialysatePumpRecord ); + break; - case USAGE_INFO_FILTER_FLUSH: - dgUsageInfoGroup.dgUsageInfo.lastFilterFlushCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_ACID_CONCENTRATE: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord.acidConcentrate[ idx ]; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.acidConcentratesRecord.acidConcentrate[ 0 ] ); + break; - case USAGE_INFO_HEAT_DIS_ACTIVE_COOL: - dgUsageInfoGroup.dgUsageInfo.lastHeatActiveCoolCompleteDateEpoch = epochTime; - break; + case DD_CAL_RECORD_BICARB_CONCENTRATE: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord.bicarbConcentrate[ idx ]; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.bicarbConcentratesRecord.bicarbConcentrate[ 0 ] ); + break; - default: -// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_USAGE_INFO_SELECTED, disinfect ); - break; - } + case DD_CAL_RECORD_ACCELEROMETER_SENSOR: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.accelerometerSensorCalRecord ); + break; - dgUsageInfoGroup.dgUsageInfo.crc = crc16( (U08*)&dgUsageInfoGroup.dgUsageInfo, sizeof( DG_USAGE_INFO_RECORD_T ) - sizeof( U16 ) ); - dgUsageInfoGroup.crc = crc16( (U08*)&dgUsageInfoGroup, sizeof( DG_USAGE_INFO_GROUP_T ) - sizeof( U16 ) ); - usageWriteTries = 0; - status = TRUE; + case DD_CAL_RECORD_BLLOD_LEAK_SENSOR: + destPtr = (U08*)&ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord; + dataSize = sizeof( ddCalibrationGroup.ddCalibrationRecord.bloodLeakSensorCalRecord ); + break; - enqueueRecordJob( NVDATAMGMT_WRITE, NVDATAMGMT_USAGE_INFO_RECORD ); - SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ NVDATAMGMT_USAGE_INFO_RECORD ].nvEvent, 0, 0 ) + default: + break; } - else if ( ++usageWriteTries > MAX_NUM_OF_WRITE_TRIES ) + + if ( ( destPtr != NULL ) && ( bufferAddress != NULL ) && ( dataSize > 0 ) ) { -// SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_WRITE_USAGE_INFO_TO_NV_FAILURE, disinfect ); + memcpy( destPtr, bufferAddress, dataSize ); + updateRecordCRC( NVM_CALIBRATION_RECORD ); + result = TRUE; } - return status; + return result; } /*********************************************************************//** * @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 + * The getNVMInstitRecord function gets the value of the specified + * institutional record item. + * @details \b Inputs: ddInstitutionalGroup.ddInstitutionalRecord + * @details \b Outputs: none + * @param institRecType Institutional record item to retrieve + * @param valuePtr Pointer to the buffer where the value will be copied + * @return TRUE if the value was retrieved successfully otherwise FALSE *************************************************************************/ -BOOL setServiceTime( void ) +BOOL getNVMInstitRecord( DD_INSTIT_REC_TYPE institRecType, U08 *valuePtr ) { - BOOL status = FALSE; + BOOL result = FALSE; - if ( getAvailableRecordQueueCount() >= ( MIN_JOBS_NEEDED_FOR_SECTOR_0 + 1 ) ) + U08 *srcPtr = NULL; + U16 dataSize = 0; + + switch (institRecType) { - // 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 + case DD_INSTIT_MIN_DIALYSATE_FLOW_MLPM: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minDialysateFlowMLPM; + dataSize = sizeof(U32); + break; - 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 ) ); + case DD_INSTIT_MAX_DIALYSATE_FLOW_MLPM: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateFlowMLPM; + dataSize = sizeof(U32); + break; - // 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 ) + case DD_INSTIT_MIN_DIALYSATE_TEMP_C: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minDialysateTempC; + dataSize = sizeof(F32); + break; - status = TRUE; + case DD_INSTIT_MAX_DIALYSATE_TEMP_C: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateTempC; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_ACID_CONCENTRATE: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minAcidConcentrate; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_ACID_CONCENTRATE: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxAcidConcentrate; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_BICARB_CARTRIDGE_SIZE_G: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbCartridgeSizeG; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_BICARB_CARTRIDGE_SIZE_G: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbCartridgeSizeG; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_SODIUM_MEQL: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minSodiumMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_SODIUM_MEQL: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxSodiumMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_BICARBONATE_MEQL: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbonateMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_BICARBONATE_MEQL: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbonateMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_RO_REJECTION_RATIO_PCT: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minRORejectionRatioPCT; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_DISINFECTION_FREQUENCY: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.disinfectionFrequency; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_DISINFECTION_CYCLE_TIME: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.disinfectionCycleTime; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_INLET_WATER_COND_ALARM_LIMIT_USPCM: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minInletWaterCondAlarmLimitUSPCM; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MAX_INLET_WATER_COND_ALARM_LIMIT_USPCM: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxInletWaterCondAlarmLimitUSPCM; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_ACID_CONCENTRATE_JUG_SIZE_L: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.acidConcentrateJugSizeL; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_ACID_ALARM_LIMIT_PCT: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minAcidAlarmLimitPCT; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_BICARB_ALARM_LIMIT_PCT: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbAlarmLimitPCT; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_POST_TREAT_DRAIN_OPTION: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.postTreatDrainOption; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_POST_TREAT_DRY_BICARB_OPTION: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.postTreatDryBicarbOption; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_LAST_UPDATED_TIME: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.lastUpdatedTime; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_CRC: + srcPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.crc; + dataSize = sizeof(U16); + break; + + default: + break; } + if ( ( NULL != srcPtr ) && ( NULL != valuePtr ) && ( dataSize > 0 ) ) + { + memcpy( valuePtr, srcPtr, dataSize ); + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setNVMInstitRecord function updates the specified institutional + * record item with the provided value. It updates the institutional + * record CRC after the value is written. + * @details \b Inputs: none + * @details \b Outputs: ddInstitutionalGroup.ddInstitutionalRecord, + * ddInstitutionalGroup.crc + * @param institRecType Institutional record item to update + * @param valuePtr Pointer to the value to be written + * @return TRUE if the value was updated successfully otherwise FALSE + *************************************************************************/ +BOOL setNVMInstitRecord( DD_INSTIT_REC_TYPE institRecType, U08 *valuePtr ) +{ + BOOL result = FALSE; + U08 *destPtr = NULL; + U16 dataSize = 0; + + switch (institRecType) + { + case DD_INSTIT_MIN_DIALYSATE_FLOW_MLPM: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minDialysateFlowMLPM; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_DIALYSATE_FLOW_MLPM: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateFlowMLPM; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_DIALYSATE_TEMP_C: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minDialysateTempC; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MAX_DIALYSATE_TEMP_C: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxDialysateTempC; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_ACID_CONCENTRATE: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minAcidConcentrate; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_ACID_CONCENTRATE: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxAcidConcentrate; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_BICARB_CARTRIDGE_SIZE_G: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbCartridgeSizeG; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_BICARB_CARTRIDGE_SIZE_G: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbCartridgeSizeG; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_SODIUM_MEQL: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minSodiumMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_SODIUM_MEQL: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxSodiumMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_BICARBONATE_MEQL: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbonateMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MAX_BICARBONATE_MEQL: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxBicarbonateMEQL; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_MIN_RO_REJECTION_RATIO_PCT: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minRORejectionRatioPCT; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_DISINFECTION_FREQUENCY: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.disinfectionFrequency; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_DISINFECTION_CYCLE_TIME: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.disinfectionCycleTime; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_INLET_WATER_COND_ALARM_LIMIT_USPCM: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minInletWaterCondAlarmLimitUSPCM; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MAX_INLET_WATER_COND_ALARM_LIMIT_USPCM: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.maxInletWaterCondAlarmLimitUSPCM; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_ACID_CONCENTRATE_JUG_SIZE_L: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.acidConcentrateJugSizeL; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_ACID_ALARM_LIMIT_PCT: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minAcidAlarmLimitPCT; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_MIN_BICARB_ALARM_LIMIT_PCT: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.minBicarbAlarmLimitPCT; + dataSize = sizeof(F32); + break; + + case DD_INSTIT_POST_TREAT_DRAIN_OPTION: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.postTreatDrainOption; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_POST_TREAT_DRY_BICARB_OPTION: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.postTreatDryBicarbOption; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_LAST_UPDATED_TIME: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.lastUpdatedTime; + dataSize = sizeof(U32); + break; + + case DD_INSTIT_CRC: + destPtr = (U08*)&ddInstitutionalGroup.ddInstitutionalRecord.crc; + dataSize = sizeof(U16); + break; + + default: + break; + } + + if ( ( NULL != destPtr ) && ( NULL != valuePtr ) && ( dataSize > 0 ) ) + { + memcpy( destPtr, valuePtr, dataSize ); + + // Update CRC after every change + updateRecordCRC( NVM_INSTITUTIONAL_RECORD ); + + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getInstitRecDataType function gets the data type associated with + * the specified institutional record item. + * @details \b Inputs: institRecDataTypeTable + * @details \b Outputs: none + * @param institRecType Institutional record type + * @return Data type of the institutional record component + *************************************************************************/ +CRITICAL_DATA_TYPES_T getInstitRecDataType( DD_INSTIT_REC_TYPE institRecType ) +{ + return institRecDataTypeTable[ institRecType ]; +} + +/*********************************************************************//** + * @brief + * The sendNVEvent function sends the event associated with the + * specified NV record type. + * @details \b Inputs: RECORDS_SPECS + * @details \b Outputs: none + * @param recType NV record type whose event will be sent + * @param d1 First event data + * @param d2 Second event data + * @return none + *************************************************************************/ +void sendNVEvent( NVM_RECORD_TYPE_T recType, U32 d1, U32 d2 ) +{ + SEND_EVENT_WITH_2_U32_DATA( RECORDS_SPECS[ recType ].nvEvent, d1, d2 ); +} + +/*********************************************************************//** + * @brief + * The updateNVSelfTestResult function updates the NV data management + * self-test result with the provided value. + * @details \b Inputs: none + * @details \b Outputs: nvmSelfTestResult + * @param result Self-test result to be updated + * @return none + *************************************************************************/ +void updateNVSelfTestResult( SELF_TEST_STATUS_T result ) +{ + nvmSelfTestResult = result; +} + +/*********************************************************************//** + * @brief + * The updateNVSelfTestState function updates the NV data management + * self-test state with the provided value. + * @details \b Inputs: none + * @details \b Outputs: nvmSelfTestState + * @param state Self-test state to be updated + * @return none + *************************************************************************/ +void updateNVSelfTestState( NVM_SELF_TEST_STATE_T state ) +{ + nvmSelfTestState = state; +} + +/*********************************************************************//** + * @brief + * The updateSelfTestReadRecordsFlag function updates the flag that + * indicates whether self-test record reading is complete. + * @details \b Inputs: none + * @details \b Outputs: isSelfTestReadRecordsDone + * @param value Flag value to be updated + * @return none + *************************************************************************/ +void updateSelfTestReadRecordsFlag( BOOL value ) +{ + isSelfTestReadRecordsDone = value; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The updateNVRecordCRC function overrides the CRC value of + * the selected non-volatile record and schedules it for writing. + * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT if invalid job is + * selected + * @details \b Inputs: none + * @details \b Outputs: ddCalibrationGroup, ddSystemGroup, + * ddServiceGroup, ddInstitutionalGroup, ddUsageInfoGroup + * @param job The job whose CRC needs to be overridden + * @param crc The CRC value to be set + * @return TRUE if the job was scheduled successfully otherwise FALSE + *************************************************************************/ +BOOL updateNVRecordCRC( U32 job, U16 crc ) +{ + BOOL status = FALSE; + NVM_RECORD_TYPE_T nvJob = (NVM_RECORD_TYPE_T)job; + + switch( nvJob ) + { + case NVM_CALIBRATION_RECORD: + ddCalibrationGroup.crc = crc; + break; + + case NVM_SYSTEM_RECORD: + ddSystemGroup.ddSystemRecord.crc = crc; + break; + + case NVM_SERVICE_RECORD: + ddServiceGroup.ddServiceRecord.crc = crc; + break; + + case NVM_INSTITUTIONAL_RECORD: + ddInstitutionalGroup.ddInstitutionalRecord.crc = crc; + break; + + case NVM_USAGE_INFO_RECORD: + ddUsageInfoGroup.ddUsageInfoRecord.crc = crc; + break; + + default: + // Software fault + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, ( U32 )nvJob ); + break; + } + + status = enqueueEraseAndWriteSector( nvJob ); + return status; } + +/**@}*/ +