Index: firmware/App/Controllers/DGInterface.c =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Controllers/DGInterface.c (.../DGInterface.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -23,7 +23,7 @@ #include "DGInterface.h" #include "ModeInitPOST.h" #include "ModeTreatment.h" -#include "ModeTreatmentParams.h" +#include "ModeTreatmentParams.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommMessages.h" @@ -48,8 +48,8 @@ #define DIALYSATE_TEMP_LOW_SAFETY_LIMIT_C 42.0F ///< Dialysate low safety temperature limit in C. #define DIALYSATE_TEMP_LOW_SAFETY_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Dialysate temperature low safety timeout in milliseconds. -// ********** private data ********** - +// ********** private data ********** + // DG status static DG_OP_MODE_T dgCurrentOpMode; ///< Current DG operation mode. static U32 dgSubMode; ///< Current state (sub-mode) of current DG operation mode. @@ -97,6 +97,7 @@ static DG_DISINFECT_UI_STATES_T disinfectsStatus; ///< DG disinfects status. static DG_MIXING_RATIOS_T dgMixingRatios; ///< DG mixing ratios. static HEATERS_DATA_T dgHeatersData; ///< DG heaters data. +static DG_SERVICE_AND_USAGE_DATA_T dgServiceAndUsageData; ///< DG service and usage data. // DG command response static DG_CMD_RESPONSE_T dgCmdResp[ NUM_OF_DG_COMMANDS ]; ///< Keep the latest DG command response for each command. @@ -353,6 +354,22 @@ /*********************************************************************//** * @brief + * The getReservoirWeight function gets the load cell weight of a given reservoir. + * @details Inputs: loadCellWeightInGrams[] + * @details Outputs: none + * @param resID ID of reservoir to get weight for + * @return the current weight of the given reservoir in grams + *************************************************************************/ +F32 getReservoirWeight( DG_RESERVOIR_ID_T resID ) +{ + LOAD_CELL_ID_T lc = ( DG_RESERVOIR_1 == resID ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); + F32 wt = getLoadCellWeight( lc ); + + return wt; +} + +/*********************************************************************//** + * @brief * The getReservoirBackupWeightLargeFilter function gets the backup load cell weight * of the given reservoir after large (32 sample) filter applied. * @details Inputs: lgFilteredReservoirWeightInGrams[] @@ -411,18 +428,17 @@ /*********************************************************************//** * @brief - * The getReservoirWeight function gets the load cell weight of a given reservoir. - * @details Inputs: loadCellWeightInGrams[] + * The getHDVersionDGServiceAndUsageData function copies the HD version of + * the DG service and usage data into the provided buffer. + * @details Inputs: dgServiceAndUsageData * @details Outputs: none - * @param resID ID of reservoir to get weight for - * @return the current weight of the given reservoir in grams + * @param data which is a pointer of type DG_SERVICE_AND_USAGE_DATA_T that + * is the provided buffer + * @return none *************************************************************************/ -F32 getReservoirWeight( DG_RESERVOIR_ID_T resID ) +void getHDVersionDGServiceAndUsageData( DG_SERVICE_AND_USAGE_DATA_T* data ) { - LOAD_CELL_ID_T lc = ( DG_RESERVOIR_1 == resID ? LOAD_CELL_RESERVOIR_1_PRIMARY : LOAD_CELL_RESERVOIR_2_PRIMARY ); - F32 wt = getLoadCellWeight( lc ); - - return wt; + memcpy( data, &dgServiceAndUsageData, sizeof( DG_SERVICE_AND_USAGE_DATA_T ) ); } /*********************************************************************//** @@ -597,6 +613,38 @@ memcpy( &dgHeatersData, data, sizeof( HEATERS_DATA_T ) ); } +/*********************************************************************//** + * @brief + * The setHDVersionDGServiceRecord function sets the HD version of the DG + * service record. + * @details Inputs: none + * @details Outputs: dgServiceAndUsageData + * @param data which is a pointer to the received HD version of the DG service + * record + * @return none + *************************************************************************/ +void setHDVersionDGServiceRecord( HD_VERSION_DG_SERVICE_RECORD_T* data ) +{ + dgServiceAndUsageData.isDGServiceRecordAvailable = TRUE; + memcpy( &dgServiceAndUsageData.dgServiceRecord, data, sizeof( HD_VERSION_DG_SERVICE_RECORD_T ) ); +} + +/*********************************************************************//** + * @brief + * The setHDVersionDGUsageInfo function sets the HD version of the DG + * usage information. + * @details Inputs: none + * @details Outputs: dgServiceAndUsageData + * @param data which is a pointer to the received HD version of the DG usage + * info + * @return none + *************************************************************************/ +void setHDVersionDGUsageInfo( HD_VERSION_DG_USAGE_INFO_T* data ) +{ + dgServiceAndUsageData.isDGUsageInfoAviable = TRUE; + memcpy( &dgServiceAndUsageData.dgUsageInfo, data, sizeof( HD_VERSION_DG_USAGE_INFO_T ) ); +} + /*********************************************************************//** * @brief * The cmdSetDGDialysateHeatingParams function sends the dialysate heating Index: firmware/App/Controllers/DGInterface.h =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Controllers/DGInterface.h (.../DGInterface.h) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -32,80 +32,98 @@ // ********** public definitions ********** -#define DEFAULT_TARGET_FILL_FLOW_RATE_LPM 0.8F ///< Default target fill flow rate in L/min. -#define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. -#define LOAD_CELL_PRIMARY_BACKUP_MAX_ALLOWED_DRIFT_GRAMS 10.0F ///< Reservoir load cell drift difference allowed -#define LOAD_CELL_ILLEGAL_WEIGHT_VALUE -10000.0F ///< Initial value for Load Cells, known bad value +#define DEFAULT_TARGET_FILL_FLOW_RATE_LPM 0.8F ///< Default target fill flow rate in L/min. +#define DRAIN_RESERVOIR_TO_VOLUME_ML 0 ///< Drain reservoir to this volume (in mL) during treatment. +#define LOAD_CELL_PRIMARY_BACKUP_MAX_ALLOWED_DRIFT_GRAMS 10.0F ///< Reservoir load cell drift difference allowed +#define LOAD_CELL_ILLEGAL_WEIGHT_VALUE -10000.0F ///< Initial value for Load Cells, known bad value /// DG Concentrate ratios data structure. typedef struct { - F32 acidMixingRatio; ///< Acid mixing ratio - F32 bicarbMixingRatio; ///< Bicarb mixing ratio - U32 timeFillPrepMS; ///< Fill prepare time in milliseconds + F32 acidMixingRatio; ///< Acid mixing ratio + F32 bicarbMixingRatio; ///< Bicarb mixing ratio + U32 timeFillPrepMS; ///< Fill prepare time in milliseconds } DG_MIXING_RATIOS_T; -/// Dialysate flow meter data structure. -typedef struct -{ - F32 measuredDialysateFlowRate; ///< Dialysate flow meter rate average measurement -} DIALYSATE_FLOW_METER_DATA_T; - /// Payload record structure for a reservoirs data message. typedef struct { - U32 resID; ///< Active reservoir ID - U32 setFillToVolumeMl; ///< Reservoir set fill to target volume in ml - U32 setDrainToVolumeMl; ///< Reservoir set drain to target volume in ml - U32 timeReservoirCycleMS; ///< Reservoir time cycle in milliseconds - U32 timeReservoirFill2SwitchMS; ///< Reservoir time fill to switch in milliseconds - F32 timeUFDecayMS; ///< Ultrafilter decay time in milliseconds - F32 tempUFFill; ///< Ultrafilter fill temperature in C - F32 tempReservoirUseActual; ///< Reservoir actual use temperature in C - F32 tempReservoirEndFill; ///< Reservoir end of the fill temperature in C - F32 tempAvgFill; ///< Average fill temperature in C - F32 tempLastFill; ///< Last fill temperature in C - F32 timereservoirFillMS; ///< Reservoir fill time in milliseconds - F32 tempRsrvr0ActualTrimmer; ///< Temperature actual reservoir in C. - F32 tempFillMixAvgTrimmer; ///< Temperature fill mix average trimmer in C. - F32 tempRsrvrEndFillTrimmer; ///< Temperature reservoir end fill trimmer in C. + U32 resID; ///< Active reservoir ID + U32 setFillToVolumeMl; ///< Reservoir set fill to target volume in ml + U32 setDrainToVolumeMl; ///< Reservoir set drain to target volume in ml + U32 timeReservoirCycleMS; ///< Reservoir time cycle in milliseconds + U32 timeReservoirFill2SwitchMS; ///< Reservoir time fill to switch in milliseconds + F32 timeUFDecayMS; ///< Ultrafilter decay time in milliseconds + F32 tempUFFill; ///< Ultrafilter fill temperature in C + F32 tempReservoirUseActual; ///< Reservoir actual use temperature in C + F32 tempReservoirEndFill; ///< Reservoir end of the fill temperature in C + F32 tempAvgFill; ///< Average fill temperature in C + F32 tempLastFill; ///< Last fill temperature in C + F32 timereservoirFillMS; ///< Reservoir fill time in milliseconds + F32 tempRsrvr0ActualTrimmer; ///< Temperature actual reservoir in C. + F32 tempFillMixAvgTrimmer; ///< Temperature fill mix average trimmer in C. + F32 tempRsrvrEndFillTrimmer; ///< Temperature reservoir end fill trimmer in C. } DG_RESERVOIRS_DATA_PAYLOAD_T; /// Payload record structure for a drain reservoir command message. typedef struct { - U32 drainToVolumeML; ///< Drain to target volume in ml - BOOL tareLoadCells; ///< Flag indicates to tare load cells or not - BOOL rinseConcentrateLines; ///< Flag indicates to rinse concentrate lines or not - BOOL cmd; ///< Flag indicates to start or stop the drain mode + U32 drainToVolumeML; ///< Drain to target volume in ml + BOOL tareLoadCells; ///< Flag indicates to tare load cells or not + BOOL rinseConcentrateLines; ///< Flag indicates to rinse concentrate lines or not + BOOL cmd; ///< Flag indicates to start or stop the drain mode } DRAIN_RESERVOIR_CMD_PAYLOAD_T; /// DG command response data record structure. typedef struct { - U32 commandID; ///< The command DG is responding to - BOOL rejected; ///< Flag indicates if the command has been rejected - U32 rejectCode; ///< Reason code for rejecting the command + U32 commandID; ///< The command DG is responding to + BOOL rejected; ///< Flag indicates if the command has been rejected + U32 rejectCode; ///< Reason code for rejecting the command } DG_CMD_RESPONSE_T; /// DG heat/chemical disinfects and flush state for UI structure. typedef struct DG_Disinfects { - U32 chemDisinfectUIState; ///< DG chemical disinfect UI state - U32 heatDisinfectUIState; ///< DG heat disinfect UI state - U32 flushUIState; ///< DG flush UI state + U32 chemDisinfectUIState; ///< DG chemical disinfect UI state + U32 heatDisinfectUIState; ///< DG heat disinfect UI state + U32 flushUIState; ///< DG flush UI state } DG_DISINFECT_UI_STATES_T; /// Dialysate heating parameters typedef struct { - F32 trimmerTargetTemperature; ///< Trimmer target temperature - U32 timeReservoirCycleMS; ///< Reservoir cycle time in milliseconds - F32 timeReservoirFillMS; ///< Reservoir fill time in milliseconds - U32 timeReservoirWait2SwitchMS; ///< Reservoir wait to switch time in milliseconds - F32 dialysateFlowLPM; ///< Dialysate flow in L/min + F32 trimmerTargetTemperature; ///< Trimmer target temperature + U32 timeReservoirCycleMS; ///< Reservoir cycle time in milliseconds + F32 timeReservoirFillMS; ///< Reservoir fill time in milliseconds + U32 timeReservoirWait2SwitchMS; ///< Reservoir wait to switch time in milliseconds + F32 dialysateFlowLPM; ///< Dialysate flow in L/min } DG_CMD_DIALYSATE_HEATING_PARAMS_T; +/// HD version of DG service record +typedef struct +{ + U32 lastServiceDateEpoch; ///< Last service date in epoch + U32 serviceIntervalSeconds; ///< Service interval in seconds +} HD_VERSION_DG_SERVICE_RECORD_T ; + +/// HD version of DG usage info +typedef struct +{ + U32 lastHeatDisDateEpoch; ///< Last heat disinfect date in epoch + U32 lastChemicalDisDateEpoch; ///< Last chemical disinfect date in epoch + BOOL isDisinfected; ///< Flag to indicate whether DG is disinfected or not +} HD_VERSION_DG_USAGE_INFO_T; + +/// HD version of the DG service record +typedef struct +{ + HD_VERSION_DG_SERVICE_RECORD_T dgServiceRecord; ///< HD version of the DG service record. + HD_VERSION_DG_USAGE_INFO_T dgUsageInfo; ///< HD version of the DG usage info. + BOOL isDGServiceRecordAvailable; ///< Flag to indicate DG service record is available. + BOOL isDGUsageInfoAviable; ///< Flag to indicate DG usage info is available. +} DG_SERVICE_AND_USAGE_DATA_T; + // ********** public function prototypes ********** void initDGInterface( void ); @@ -128,6 +146,7 @@ F32 getDialysateTemperature( void ); DG_DISINFECT_UI_STATES_T getDGDisinfectsStates( void ); DG_MIXING_RATIOS_T getDGMixingRatios( void ); +void getHDVersionDGServiceAndUsageData( DG_SERVICE_AND_USAGE_DATA_T* data ); void setDGOpMode( U32 opMode, U32 subMode ); void setDialysateTemperatureReadings( F32 temp1, F32 temp2 ); @@ -137,6 +156,8 @@ void setDGDisinfectsStates( DG_DISINFECT_UI_STATES_T states ); void setDGMixingRatios( DG_MIXING_RATIOS_T ratios ); void setDGHeatersData( HEATERS_DATA_T *data ); +void setHDVersionDGServiceRecord( HD_VERSION_DG_SERVICE_RECORD_T* data ); +void setHDVersionDGUsageInfo( HD_VERSION_DG_USAGE_INFO_T* data ); void cmdSetDGDialysateHeatingParams( DG_CMD_DIALYSATE_HEATING_PARAMS_T heatingParams ); void cmdStartDG( void ); Index: firmware/App/Modes/ModeFault.c =================================================================== diff -u -rfb1673d2282822995ed233f3e9ea5dfb0567780d -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision fb1673d2282822995ed233f3e9ea5dfb0567780d) +++ firmware/App/Modes/ModeFault.c (.../ModeFault.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -174,8 +174,8 @@ *************************************************************************/ static HD_FAULT_STATE_T handleFaultStartState( void ) { - HD_FAULT_STATE_T state = HD_FAULT_STATE_START; - NVDATAMGMT_RECORDS_READ_STATUS status = getNVRecordsReadStatus(); + HD_FAULT_STATE_T state = HD_FAULT_STATE_START; + NVDATAMGMT_RECORDS_READ_STATUS_T status = getNVRecordsReadStatus(); switch ( status ) { Index: firmware/App/Modes/ModePreTreat.c =================================================================== diff -u -rdf4242fcc91f8cd1aada438b33fa845c223d0e0e -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision df4242fcc91f8cd1aada438b33fa845c223d0e0e) +++ firmware/App/Modes/ModePreTreat.c (.../ModePreTreat.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -598,7 +598,8 @@ signalBloodPumpHardStop(); signalDialOutPumpHardStop(); - setDialInPumpTargetFlowRate( DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + //setDialInPumpTargetFlowRate( DIP_PATIENT_CONNECTION_FLOW_RATE_ML_MIN, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); + setDialInPumpTargetFlowRate( 250, MOTOR_DIR_FORWARD, PUMP_CONTROL_MODE_OPEN_LOOP ); // TODO remove this line once the new flow control is implemented cmdStartDGTrimmerHeater(); } Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -rb99fd6c434ba1f927e46f3ab80fec1239d63f28f -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision b99fd6c434ba1f927e46f3ab80fec1239d63f28f) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -30,6 +30,7 @@ #include "ModeTreatment.h" #include "ModeTreatmentParams.h" #include "OperationModes.h" +#include "RTC.h" #include "Switches.h" #include "SyringePump.h" #include "SystemComm.h" @@ -46,7 +47,7 @@ // ********** private definitions ********** #define DISINFECTS_DATA_PUB_INTERVAL ( 1 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Disinfects data publish interval in counts. -#define SERVICE_TIME_INTERVAL_MS ( 6 * 30 * SECONDS_IN_A_DAY * MS_PER_SECOND ) ///< HD/DG 6-month service interval in milliseconds. +#define DISINFECTS_TIME_INTERVAL_S ( 2 * SECONDS_IN_A_DAY ) ///< HD/DG 2-day service interval in seconds. // ********** private data ********** @@ -62,6 +63,8 @@ /// Interval (in task intervals) at which to publish standby mode data to CAN bus. static OVERRIDE_U32_T standbyModePublishInterval = { DISINFECTS_DATA_PUB_INTERVAL, DISINFECTS_DATA_PUB_INTERVAL, DISINFECTS_DATA_PUB_INTERVAL, 0 }; +static const U32 SERVICE_TIME_INTERVAL_S = (U32)( 365 * 0.5 * SECONDS_IN_A_DAY ); ///< HD/DG 6-month service interval in seconds. + // ********** private function prototypes ********** static HD_STANDBY_STATE_T handleStandbyModeStartState( void ); @@ -80,6 +83,8 @@ static HD_STANDBY_STATE_T handleStandbyModeWaitForDGChemDisinfectStartState( void ); static HD_STANDBY_STATE_T handleStandbyModeDGChemDisininfectInProgressState( void ); +static BOOL isDGDisinfectValid( void ); +static BOOL haveHDDGServicesBeenExpired( void ); static void publishDisinfectData( void ); /*********************************************************************//** @@ -138,6 +143,10 @@ setValvePosition( VBA, VALVE_POSITION_A_INSERT_EJECT ); setValvePosition( VBV, VALVE_POSITION_A_INSERT_EJECT ); + // Request DG service record and usage information from DG + sendDGServiceRequestToDG(); + sendDGUsageInfoRequestToDG(); + return currentStandbyState; } @@ -157,7 +166,7 @@ switch ( currentStandbyState ) { case STANDBY_START_STATE: - currentStandbyState = handleStandbyModeStartState();; + currentStandbyState = handleStandbyModeStartState(); break; case STANDBY_WAIT_FOR_TREATMENT_STATE: @@ -500,7 +509,7 @@ *************************************************************************/ static HD_STANDBY_STATE_T handleStandbyModeWaitForTreatmentState( void ) { - HD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; + HD_STANDBY_STATE_T state = STANDBY_WAIT_FOR_TREATMENT_STATE; DG_OP_MODE_T dgOperationMode = getDGOpMode(); // If DG is filling while we are in standby mode, abort the fill @@ -515,17 +524,30 @@ cmdStopDG(); } - // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). TODO - check required conditions before allowing treatment start, reject if necessary. + // If treatment start is requested by user, initiate treatment workflow (transition to treatment params mode). if ( TRUE == treatStartReqReceived ) { - // Initialize treatment modes before starting a new treatment - initTreatParamsMode(); - initPreTreatmentMode(); - initTreatmentMode(); - initPostTreatmentMode(); - // Start treatment workflow with treatment parameters mode - requestNewOperationMode( MODE_TPAR ); - treatStartReqReceived = FALSE; + BOOL startTreatment = TRUE; + +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_SERVICE_AND_DISINFECT_CHECK ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + startTreatment = isDGDisinfectValid(); + startTreatment = haveHDDGServicesBeenExpired(); + } + + if ( TRUE == startTreatment ) + { + // Initialize treatment modes before starting a new treatment + initTreatParamsMode(); + initPreTreatmentMode(); + initTreatmentMode(); + initPostTreatmentMode(); + // Start treatment workflow with treatment parameters mode + requestNewOperationMode( MODE_TPAR ); + treatStartReqReceived = FALSE; + } } return state; @@ -797,6 +819,85 @@ /*********************************************************************//** * @brief + * The isDGDisinfectValid function checks whether the DG disinfects is + * acceptable to start another treatment. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if the disinfect is valid otherwise, FALSE + ***********************************************************************/ +static BOOL isDGDisinfectValid( void ) +{ + BOOL status = TRUE; + DG_SERVICE_AND_USAGE_DATA_T data; + + getHDVersionDGServiceAndUsageData( &data ); + + if ( TRUE == data.isDGUsageInfoAviable ) + { + if ( TRUE == data.dgUsageInfo.isDisinfected ) + { + U32 chemDisElapsedTimeS = getRTCTimestamp() - data.dgUsageInfo.lastChemicalDisDateEpoch; + BOOL hasChemDisBeenExpired = ( chemDisElapsedTimeS > DISINFECTS_TIME_INTERVAL_S ? TRUE : FALSE ); + U32 heatDisElapsedTimeS = getRTCTimestamp() - data.dgUsageInfo.lastHeatDisDateEpoch; + BOOL hasHeatDisBeenExpired = ( heatDisElapsedTimeS > DISINFECTS_TIME_INTERVAL_S ? TRUE : FALSE ); + + if ( ( TRUE == hasChemDisBeenExpired ) && ( TRUE == hasHeatDisBeenExpired ) ) + { + status = FALSE; + activateAlarmNoData( ALARM_ID_DG_DISINFECT_HAS_BEEN_EXPIRED ); + } + } + else + { + status = FALSE; + activateAlarmNoData( ALARM_ID_DG_DISINFECT_HAS_BEEN_EXPIRED ); + } + } + + return status; +} + +/*********************************************************************//** + * @brief + * The haveHDDGServicesBeenExpired function checks whether the last DG/HD + * service time is still within the interval or not. + * @details Inputs: none + * @details Outputs: none + * @return TRUE if the service time is still valid otherwise, FALSE + ***********************************************************************/ +static BOOL haveHDDGServicesBeenExpired( void ) +{ + BOOL status = TRUE; + DG_SERVICE_AND_USAGE_DATA_T dgData; + HD_SERVICE_RECORD_T hdServiceRecord; + + getHDVersionDGServiceAndUsageData( &dgData ); + getNVRecord2Driver( GET_SRV_RECORD, (U08*)&hdServiceRecord, sizeof( HD_SERVICE_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + + if ( TRUE == dgData.isDGServiceRecordAvailable ) + { + U32 dgSrvcElapsedTimeS = getRTCTimestamp() - dgData.dgServiceRecord.lastServiceDateEpoch; + BOOL hasDGSrvcBeenExpired = ( dgSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); + U32 hdSrvcElapsedTimeS = getRTCTimestamp() - hdServiceRecord.lastServiceEpochDate; + BOOL hasHDSrvcBeenExpied = ( hdSrvcElapsedTimeS > SERVICE_TIME_INTERVAL_S ? TRUE : FALSE ); + + if ( TRUE == hasDGSrvcBeenExpired ) + { + status = FALSE; + activateAlarmNoData( ALARM_ID_DG_SERIVCE_TIME_INTERVAL_HAS_ELAPSED ); + } + if ( TRUE == hasHDSrvcBeenExpied ) + { + status = FALSE; + activateAlarmNoData( ALARM_ID_HD_SERVICE_TIME_INTERVAL_HAS_ELAPSED ); + } + } + + return status; +} + +/*********************************************************************//** + * @brief * The publishDisinfectData function publishes disinfects data at * the set interval. * @details Inputs: dataPublishCounter Index: firmware/App/Modes/ModeTreatment.c =================================================================== diff -u -r19a8bf98a7154e24c35da25225d4b55bf70ddd09 -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 19a8bf98a7154e24c35da25225d4b55bf70ddd09) +++ firmware/App/Modes/ModeTreatment.c (.../ModeTreatment.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -127,6 +127,7 @@ static U32 treatmentStartTimeStamp; ///< Treatment start timestampt for logging purpose. static U32 treatmentEndTimeStamp; ///< Treatment end timestampt for logging purpose. +static BOOL hasTreatmentStartTimeBeenWrittenToNV; ///< Boolean flag to indicate whether treatment start time has been started or not. // ********** private function prototypes ********** @@ -192,6 +193,7 @@ treatmentStartTimeStamp = getRTCTimestamp(); treatmentEndTimeStamp = 0; + hasTreatmentStartTimeBeenWrittenToNV = FALSE; } @@ -245,9 +247,6 @@ initTreatmentRecirc(); initTreatmentEnd(); - // Started the treatment set the start time in epoch - setTxLastStartTimeEpoch( getRTCTimestamp() ); - return currentTreatmentState; } @@ -631,6 +630,12 @@ checkDialysateTemperature(); } + if ( FALSE == hasTreatmentStartTimeBeenWrittenToNV ) + { + // Started the treatment set the start time in epoch + hasTreatmentStartTimeBeenWrittenToNV = setTxLastStartTimeEpoch( getRTCTimestamp() ); + } + // Treatment mode state machine switch ( currentTreatmentState ) { Index: firmware/App/Modes/OperationModes.c =================================================================== diff -u -rc20c77ef196a760a7642d2426e509995e4a98e01 -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision c20c77ef196a760a7642d2426e509995e4a98e01) +++ firmware/App/Modes/OperationModes.c (.../OperationModes.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -140,14 +140,14 @@ transitionToNewOperationMode( newMode ); currentMode = newMode; - if ( MODE_TREA == currentMode ) + if ( ( MODE_TREA == lastMode ) && ( currentMode != MODE_TREA ) ) { - // If the current mode is treatment but transitioning to another mode has been requested (including transitioning to fault mode) + // If the last mode is treatment but the new mode is not treatment // it means the treatment is done. Get the elapsed time since the beginning of the treatment and convert it to hours to be written U32 txElapsedTimeMS = calcTimeSince( getTreatmentStartTimeStamp() ); F32 txElapsedTimeHrs = (F32)txElapsedTimeMS / ( MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND ); // Write the treatment hours and set the service to be false so the treatment hours is not reset - setTxTimeHours( txElapsedTimeHrs, FALSE ); + setTxTimeHours( txElapsedTimeHrs ); } } Index: firmware/App/Modes/SelfTests.c =================================================================== diff -u -rfb1673d2282822995ed233f3e9ea5dfb0567780d -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision fb1673d2282822995ed233f3e9ea5dfb0567780d) +++ firmware/App/Modes/SelfTests.c (.../SelfTests.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -434,7 +434,7 @@ currentDrySelfTestsState = handleDrySelfTestPressureSensorsSetupState(); break; - case DRY_SELF_TESTS_PRESSURE_SENSORS_STATE: + case DRY_SELF_TESTS_PRESSURE_SENSORS_PRESSURIZED_STATE: currentDrySelfTestsState = handleDrySelfTestPressureSensorsState(); break; @@ -908,7 +908,7 @@ *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsSetupState( void ) { - DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STATE; + DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_PRESSURIZED_STATE; if ( TRUE == doesAlarmStatusIndicateStop() ) { @@ -942,7 +942,7 @@ *************************************************************************/ static DRY_SELF_TESTS_STATE_T handleDrySelfTestPressureSensorsState( void ) { - DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_STATE; + DRY_SELF_TESTS_STATE_T state = DRY_SELF_TESTS_PRESSURE_SENSORS_PRESSURIZED_STATE; F32 const arterialPressure = getFilteredArterialPressure(); F32 const venousPressure = getFilteredVenousPressure(); Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r50ce0801d50b365148d2969b0d75e5768744181a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 50ce0801d50b365148d2969b0d75e5768744181a) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -170,6 +170,8 @@ SW_FAULT_ID_DG_INVALID_FILL_COMMAND_REJECTED, SW_FAULT_ID_SEMAPHORE_IN_USE_TIMEOUT, // 140 SW_FAULT_ID_INVALID_FPGA_SENSOR_GROUP_SELECTED, + SW_FAULT_ID_WRITE_USAGE_INFO_TO_NV_FAILURE, + SW_FAULT_ID_INVALID_NV_RECORD_SELECTED, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -46,7 +46,7 @@ #define MAX_XMIT_RETRIES 5 ///< Maximum number of retries on no transmit complete interrupt timeout #define UI_COMM_TIMEOUT_IN_MS 5000 ///< UI has not checked in for this much time -#define DG_COMM_TIMEOUT_IN_MS 2000 ///< DG has not checked in for this much time +#define DG_COMM_TIMEOUT_IN_MS 1000 ///< DG has not checked in for this much time #define MAX_COMM_CRC_FAILURES 5 ///< Maximum number of CRC errors within window period before alarm #define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window @@ -985,7 +985,7 @@ handleDGTemperatureData( message ); break; - case MSG_ID_DG_DIALYSATE_FLOW_METER_DATA: + case MSG_ID_DG_FLOW_SENSORS_DATA: handleDialysateFlowData( message ); break; @@ -1145,6 +1145,14 @@ handleUIServiceModeRequest( message ); break; + case MSG_ID_DG_SERVICE_SCHEDULE_DATA: + handleDGServiceScheduleData( message ); + break; + + case MSG_ID_DG_USAGE_DATA: + handleDGUsageInfoData( message ); + break; + // NOTE: this always must be the last case case MSG_ID_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -2367,12 +2367,12 @@ *************************************************************************/ void handleDialysateFlowData( MESSAGE_T *message ) { - if ( message->hdr.payloadLen == sizeof( DIALYSATE_FLOW_METER_DATA_T ) ) + if ( message->hdr.payloadLen == sizeof( FLOW_SENSORS_DATA_T ) ) { - DIALYSATE_FLOW_METER_DATA_T payload; + FLOW_SENSORS_DATA_T payload; - memcpy( &payload, message->payload, sizeof( DIALYSATE_FLOW_METER_DATA_T ) ); - setDialysateFlowData( payload.measuredDialysateFlowRate ); + memcpy( &payload, message->payload, sizeof( FLOW_SENSORS_DATA_T ) ); + setDialysateFlowData( payload.dialysateFlowRateLPM ); } } @@ -3203,23 +3203,26 @@ { MESSAGE_T msg; HD_SERVICE_RECORD_T service; + DG_SERVICE_AND_USAGE_DATA_T dgData; getNVRecord2Driver( GET_SRV_RECORD, (U08*)&service, sizeof( HD_SERVICE_RECORD_T ), 0, ALARM_ID_NO_ALARM ); + getHDVersionDGServiceAndUsageData( &dgData ); U08 *payloadPtr = msg.payload; - if ( message->hdr.payloadLen == sizeof( U32 ) + sizeof( U32 ) ) - { - // Create a message record - blankMessage( &msg ); - msg.hdr.msgID = MSG_ID_HD_SERVICE_SCHEDULE_DATA; - msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ); + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_SERVICE_SCHEDULE_DATA; + msg.hdr.payloadLen = sizeof( U32 ) + sizeof( U32 ); - // Fill message payload - memcpy( payloadPtr, &service.lastServiceEpochDate, sizeof( U32 ) ); - payloadPtr += sizeof( U32 ); - memcpy( payloadPtr, &service.serviceIntervalSeconds, sizeof( U32 ) ); - } + // Fill message payload + memcpy( payloadPtr, &service.lastServiceEpochDate, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &service.serviceIntervalSeconds, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &dgData.dgServiceRecord.lastServiceDateEpoch, sizeof( U32 ) ); + payloadPtr += sizeof( U32 ); + memcpy( payloadPtr, &dgData.dgServiceRecord.serviceIntervalSeconds, sizeof( U32 ) ); // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_UI, ACK_REQUIRED ); @@ -7098,6 +7101,96 @@ } /*********************************************************************//** + * @brief + * The sendDGUsageInfoRequestToDG function constructs a request msg + * to the DG to request the DG usage info and queues the msg for transmit + * on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG usage info result request msg constructed and queued. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendDGUsageInfoRequestToDG( void ) +{ + BOOL result; + MESSAGE_T msg; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_REQUEST_DG_USAGE_INFO; + msg.hdr.payloadLen = 0; + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_DG, ACK_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief + * The sendDGServiceRequestToDG function constructs a request msg + * to the DG to request the DG service record and queues the msg for transmit + * on the appropriate CAN channel. + * @details Inputs: none + * @details Outputs: DG usage info result request msg constructed and queued. + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL sendDGServiceRequestToDG( void ) +{ + BOOL result; + MESSAGE_T msg; + + // Create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_HD_REQUEST_DG_SERVICE_RECORD; + msg.hdr.payloadLen = 0; + + // Serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_HD_2_DG, ACK_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief + * The handleDGServiceScheduleData function receives the HD version of the + * DG service record. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleDGServiceScheduleData( MESSAGE_T *message ) +{ + if ( message->hdr.payloadLen == sizeof( HD_VERSION_DG_SERVICE_RECORD_T ) ) + { + HD_VERSION_DG_SERVICE_RECORD_T payload; + + memcpy( &payload, message->payload, sizeof( HD_VERSION_DG_SERVICE_RECORD_T ) ); + setHDVersionDGServiceRecord( &payload ); + } +} + +/*********************************************************************//** + * @brief + * The handleDGUsageInfoData function receives the HD version of the + * DG usage info. + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleDGUsageInfoData( MESSAGE_T *message ) +{ + if ( message->hdr.payloadLen == sizeof( HD_VERSION_DG_USAGE_INFO_T ) ) + { + HD_VERSION_DG_USAGE_INFO_T payload; + + memcpy( &payload, message->payload, sizeof( HD_VERSION_DG_USAGE_INFO_T ) ); + setHDVersionDGUsageInfo( &payload ); + } +} + +/*********************************************************************//** * @brief * The handleGetHDUsageInfoRecord function handles a request to get the HD * usage information record. Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r4fc093ea280a0bdb47c20d25efb7c840b9f9867a -r0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 4fc093ea280a0bdb47c20d25efb7c840b9f9867a) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 0bce81180c0ba2b25f5d501ed6aa6b2f9a8b2500) @@ -150,7 +150,7 @@ // MSG_ID_RO_PUMP_DATA: void handleROPumpData( MESSAGE_T *message ); -// MSG_ID_DG_DIALYSATE_FLOW_METER_DATA: +// MSG_ID_DG_FLOW_SENSORS_DATA void handleDialysateFlowData( MESSAGE_T *message ); // MSG_ID_DRAIN_PUMP_DATA: @@ -432,6 +432,18 @@ // MSG_ID_HD_REQUEST_DG_ALARMS BOOL sendRequestForDGResendAlarms( void ); +// MSG_ID_HD_REQUEST_DG_USAGE_INFO +BOOL sendDGUsageInfoRequestToDG( void ); + +// MSG_ID_HD_REQUEST_DG_SERVICE_INFO +BOOL sendDGServiceRequestToDG( void ); + +// MSG_ID_DG_SERVICE_SCHEDULE_DATA +void handleDGServiceScheduleData( MESSAGE_T *message ); + +// MSG_ID_DG_USAGE_DATA +void handleDGUsageInfoData( MESSAGE_T *message ); + // *********** public test support message functions ********** // MSG_TESTER_LOG_IN