Index: firmware/App/Controllers/ConcentratePumps.c =================================================================== diff -u -r368ded18d302d93a7c47192f7360bfefa5acecd8 -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Controllers/ConcentratePumps.c (.../ConcentratePumps.c) (revision 368ded18d302d93a7c47192f7360bfefa5acecd8) +++ firmware/App/Controllers/ConcentratePumps.c (.../ConcentratePumps.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -40,7 +40,8 @@ #define CONCENTRATE_PUMP_SPEED_INCREMENT 2.0F ///< Speed increase (mL/min) when controlling concentrate pump to target step speed. #define CONCENTRATE_PUMP_MIN_SPEED 3.0F ///< Minimum speed for concentrate pump in mL per min. -#define CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_ON_PCT 0.02F ///< Concentrate pump speed out of range tolerance when on in percentage. +#define CONCENTRATE_PUMP_TX_SPD_OUT_OF_RANGE_TOL_PCT 0.02F ///< Concentrate pump treatment speed out of range tolerance when on in percentage. +#define CONCENTRATE_PUMP_CLEANING_SPD_OUT_OF_RANGE_TOL_PCT 0.05F ///< Concentrate pump cleaning mode speed out of range tolerance when on in percentage. #define CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_SLOW_MLPM 1.0F ///< Concentrate pump speed out of range tolerance when slow in mL/min. #define CONCENTRATE_PUMP_LOW_SPEED_THRESHOLD_MLPM 10.0F ///< Concentrate pump low speed threshold in mL/min. #define CONCENTRATE_PUMP_ZERO_FLOW_RATE 0xFFFF ///< Pulse width value when zero flow rate or pump is off. @@ -575,7 +576,6 @@ if ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) { speed = getF32OverrideValue( &concentratePumps[ pumpId ].measuredPumpSpeed ); - speed = ( CONCENTRATE_PUMP_REVERSE_DIR == concentratePumps[ pumpId ].direction ? speed * -1.0F : speed ); } else { @@ -990,17 +990,26 @@ *************************************************************************/ static void monitorPumpSpeed( CONCENTRATE_PUMPS_T pumpId, ALARM_ID_T alarm ) { - F32 cpTargetSpeed = concentratePumps[ pumpId ].currentPumpSpeed; - F32 cpError = fabs( fabs( getMeasuredPumpSpeedMLPM( pumpId ) ) - cpTargetSpeed ); - BOOL isCpSpeedOut = FALSE; - F32 tolerance = CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_SLOW_MLPM; + // NOTE: make all the values absolute to cover both negative and positive target/measured speeds + F32 cpTargetSpeed = fabs( concentratePumps[ pumpId ].currentPumpSpeed ); + F32 cpMeasSpeed = fabs( getMeasuredPumpSpeedMLPM( pumpId ) ); + F32 cpError = fabs( cpMeasSpeed - cpTargetSpeed ); + BOOL isCpSpeedOut = FALSE; + F32 tolerance = CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_SLOW_MLPM; + DG_OP_MODE_T opMode = getCurrentOperationMode(); if ( cpTargetSpeed > CONCENTRATE_PUMP_LOW_SPEED_THRESHOLD_MLPM ) { // Check if the pump is not in the off state and if it is not and greater than the minimum threshold, divide the error // to target speed. If the pump is off the target speed is 0 so the speed check is done differently + // The speed tolerance is looser in heat disinfect and flush than the rest of the modes that the concentrate pump are running. cpError = cpError / cpTargetSpeed; - tolerance = CONCENTRATE_PUMP_SPD_OUT_OF_RANGE_TOL_WHEN_ON_PCT; + tolerance = CONCENTRATE_PUMP_TX_SPD_OUT_OF_RANGE_TOL_PCT; + + if ( ( DG_MODE_HEAT == opMode ) || ( DG_MODE_FLUS == opMode ) ) + { + tolerance = CONCENTRATE_PUMP_CLEANING_SPD_OUT_OF_RANGE_TOL_PCT; + } } isCpSpeedOut = ( cpError > tolerance ? TRUE : FALSE ); @@ -1145,9 +1154,13 @@ if ( ( pumpId < NUM_OF_CONCENTRATE_PUMPS ) && ( TRUE == isTestingActivated() ) ) { - result = TRUE; - concentratePumps[ pumpId ].measuredPumpSpeed.ovData = value; - concentratePumps[ pumpId ].measuredPumpSpeed.override = OVERRIDE_KEY; + if ( value >= 0.0F ) + { + // Only accept the positive values for override since the measured speed cannot be negative + result = TRUE; + concentratePumps[ pumpId ].measuredPumpSpeed.ovData = value; + concentratePumps[ pumpId ].measuredPumpSpeed.override = OVERRIDE_KEY; + } } return result; Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r18a83ba64d9560ce8c4c009560ec1391ae15102f -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 18a83ba64d9560ce8c4c009560ec1391ae15102f) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -626,6 +626,12 @@ if ( TRUE == isThisTheFirstFill() ) { result = DG_FILL_MODE_STATE_PRIME_CONCENTRATE_LINES; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_EXPEDITE_PRE_TREATMENT ) ) + { + // If expedite pre-treatment flag is enabled, do not do the initial fill + result = DG_FILL_MODE_STATE_PRODUCE_DIALYSATE; + } } else { Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -r54abf84364e737dd350153d5fab7dd652f917ef4 -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 54abf84364e737dd350153d5fab7dd652f917ef4) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -1130,6 +1130,12 @@ stateTimer = getMSTimerCount(); rsrvrsVolMonitorTimer = getMSTimerCount(); state = DG_HEAT_DISINFECT_STATE_DISINFECT_R1_TO_R2; + + // Filled up the reservoirs, start the concentrate pumps to prevent the concentrate tubing from swallowing and potential rupture + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_PUMP_SPEED_ML_PER_MIN ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, BICARB_PUMP_SPEED_ML_PER_MIN ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); } else if ( DG_RESERVOIR_NOT_REACHED_TARGET == rsrvr2Status ) { @@ -1192,9 +1198,6 @@ break; case HEAT_DISINFECT_COMPLETE: - requestConcentratePumpOff( CONCENTRATEPUMPS_CP1_ACID, NO_PARK_CONC_PUMPS ); - requestConcentratePumpOff( CONCENTRATEPUMPS_CP2_BICARB, NO_PARK_CONC_PUMPS ); - // Although there is fluid in both reservoirs, but they are set to empty // to begin the transition of hot water from R1 to R2. rsrvr2Status = DG_RESERVOIR_BELOW_TARGET; Index: firmware/App/Modes/ModeHeatDisinfectActiveCool.c =================================================================== diff -u -r368ded18d302d93a7c47192f7360bfefa5acecd8 -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Modes/ModeHeatDisinfectActiveCool.c (.../ModeHeatDisinfectActiveCool.c) (revision 368ded18d302d93a7c47192f7360bfefa5acecd8) +++ firmware/App/Modes/ModeHeatDisinfectActiveCool.c (.../ModeHeatDisinfectActiveCool.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -73,6 +73,10 @@ #define RSRVR_ACTIVE_COOL_BELOW_TARGET_TEMP_TIMEOUT_MS ( 15 * MS_PER_SECOND ) ///< Reservoir active cool temperature below target timeout in milliseconds. #define RSRVR_ACTIVE_COOL_TARGET_TEMP_TIMEOUT_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Reservoir active cool target temperature met in milliseconds. +// Complete states, de-pressurize the concentrate lines +#define ACID_BICARB_DEPRESSURIZE_TUBING_SPEED_MLPM 20.0F ///< Acid and bicarb de-pressurize tubing speed in mL/min. +#define ACID_BICARB_DEPRESSURIZE_TUBING_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Acid and bicarb de-pressurize tubing timeout in milliseconds. + /// Non-volatile write structure typedef struct { @@ -576,11 +580,15 @@ { DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_T state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE; - writeDisinfectDataToNV( USAGE_INFO_HEAT_DIS_ACTIVE_COOL ); - - if ( TRUE == disinfectNVOps.hasDisStatusBeenWrittenToNV ) + if ( TRUE == didTimeout( stateStartTimeMS, ACID_BICARB_DEPRESSURIZE_TUBING_TIMEOUT_MS ) ) { - stopDGHeatDisinfectActiveCool(); + deenergizeActuators( NO_PARK_CONC_PUMPS ); + writeDisinfectDataToNV( USAGE_INFO_HEAT_DIS_ACTIVE_COOL ); + + if ( TRUE == disinfectNVOps.hasDisStatusBeenWrittenToNV ) + { + stopDGHeatDisinfectActiveCool(); + } } return state; @@ -1035,10 +1043,37 @@ setDrainPumpTargetRPM( RSRVR_DRAIN_TARGET_RPM ); break; + case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE: + // Valves + setValveState( VPI, VALVE_STATE_CLOSED ); + setValveState( VBF, VALVE_STATE_CLOSED ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRD1, VALVE_STATE_CLOSED ); + setValveState( VRD2, VALVE_STATE_CLOSED ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + // UV reactors + turnOffUVReactor( INLET_UV_REACTOR ); + turnOffUVReactor( OUTLET_UV_REACTOR ); + // Concentrate pumps + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP1_ACID, ACID_BICARB_DEPRESSURIZE_TUBING_SPEED_MLPM ); + setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2_BICARB, ACID_BICARB_DEPRESSURIZE_TUBING_SPEED_MLPM ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP1_ACID ); + requestConcentratePumpOn( CONCENTRATEPUMPS_CP2_BICARB ); + // RO pump + signalROPumpHardStop(); + // Drain pump + signalDrainPumpHardStop(); + break; + case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_START: case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_WATER_PATH_STATE: case DG_HEAT_DISINFECT_ACTIVE_COOL_CANCEL_BASIC_PATH_STATE: - case DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE: // De-energize the actuators in the state upon transitioning to these states deenergizeActuators( NO_PARK_CONC_PUMPS ); break; @@ -1343,14 +1378,14 @@ rsrvrsStatus.rsrvr[ switchRsrvrID ].rStatus = DG_RESERVOIR_ABOVE_TARGET; state = DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE; - setHeatDisinfectActiveCoolActuators( state ); } else if ( DG_HEAT_DISINFECT_ACTIVE_COOL_DRAIN_R2_STATE == state ) { - deenergizeActuators( NO_PARK_CONC_PUMPS ); state = DG_HEAT_DISINFECT_ACTIVE_COOL_STATE_COMPLETE; } + // Set the actuators state after setting the next state + setHeatDisinfectActiveCoolActuators( state ); stateStartTimeMS = getMSTimerCount(); } Index: firmware/App/Modes/ModeStandby.c =================================================================== diff -u -r18a83ba64d9560ce8c4c009560ec1391ae15102f -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 18a83ba64d9560ce8c4c009560ec1391ae15102f) +++ firmware/App/Modes/ModeStandby.c (.../ModeStandby.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -287,7 +287,6 @@ else if ( TRUE == pendingStartDGHeatDisinfectActiveCoolRequest ) { pendingStartDGHeatDisinfectActiveCoolRequest = FALSE; - requestNewOperationMode( DG_MODE_HCOL ); } else if ( TRUE == pendingStartDGChemicalDisinfectFlushRequest ) Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -re6c60e07b450ec8d58e87bf13d45f96efab54d8b -r00b244580f01f3cbd1b7d2d5a14ee61675bf4642 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision e6c60e07b450ec8d58e87bf13d45f96efab54d8b) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 00b244580f01f3cbd1b7d2d5a14ee61675bf4642) @@ -94,97 +94,97 @@ static volatile U16 nextSeqNo = 1; ///< Next sequence number. /// List of message IDs that are requested not to be transmitted. static BLOCKED_MSGS_DATA_T blockedMessagesForXmit = { 0, 0, 0, 0, 0, 0, 0, 0 }; - -// ********** private function prototypes ********** - -static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); + +// ********** private function prototypes ********** + +static BOOL sendTestAckResponseMsg( MSG_ID_T msgID, BOOL ack ); static BOOL sendAckResponseMsg( MSG_ID_T msgID, COMM_BUFFER_T buffer, BOOL ack ); -static BOOL sendUIResponseMsg( MSG_ID_T msgID, UI_RESPONSE_PAYLOAD_T *uiResponse ); - -/*********************************************************************//** - * @brief - * The serializeMessage function serializes a given message into a given - * array of bytes. A sequence # is added to the message here and the ACK - * bit of the sequence # is set if ACK is required per parameter. A sync byte - * is inserted at the beginning of the message and an 8-bit CRC is appended to - * the end of the message. The message is queued for transmission in the given buffer. - * @details Inputs: none - * @details Outputs: given data array populated with serialized message data and queued for transmit. - * @param msg message to serialize - * @param buffer outgoing buffer that message should be queued in - * @param ackReq is an acknowledgement from receiver required? - * @return size (in bytes) of serialized message populated in given data array. - *************************************************************************/ -U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) -{ - BOOL result = FALSE; - BOOL error = FALSE; - U32 msgSize = 0; - U32 sizeMod, sizePad; - U32 i; - U08 crc; - U08 data[ MAX_ACK_MSG_SIZE ]; // byte array to populate with message data - - // prefix data with message sync byte - data[ msgSize++ ] = MESSAGE_SYNC_BYTE; - - // set sequence # and ACK bit (unless this is an ACK to a received message) - if ( msg.hdr.msgID != MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK ) - { - // thread protect next sequence # access & increment - _disable_IRQ(); - msg.hdr.seqNo = nextSeqNo; - nextSeqNo = INC_WRAP( nextSeqNo, MIN_MSG_SEQ_NO, MAX_MSG_SEQ_NO ); - _enable_IRQ(); - if ( TRUE == ackReq ) - { - msg.hdr.seqNo *= -1; - } - } - - // calculate message CRC - crc = crc8( (U08*)(&msg), sizeof( MESSAGE_HEADER_T ) + msg.hdr.payloadLen ); - - // serialize message header data - memcpy( &data[ msgSize ], &( msg.hdr ), sizeof( MESSAGE_HEADER_T ) ); - msgSize += sizeof( MESSAGE_HEADER_T ); - - // serialize message payload (only used bytes per payloadLen field) - memcpy( &data[ msgSize ], &( msg.payload ), msg.hdr.payloadLen ); - msgSize += msg.hdr.payloadLen; - - // add 8-bit CRC - data[ msgSize++ ] = crc; - - // pad with zero bytes to get length a multiple of CAN_MESSAGE_PAYLOAD_SIZE (8) - sizeMod = msgSize % CAN_MESSAGE_PAYLOAD_SIZE; - sizePad = ( sizeMod == 0 ? 0 : CAN_MESSAGE_PAYLOAD_SIZE - sizeMod ); - for ( i = 0; i < sizePad; i++ ) - { - data[ msgSize++ ] = 0; - } - - // if ACK required, add to pending ACK list - if ( TRUE == ackReq ) - { - if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) - { - error = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL ) - } - } - - if ( FALSE == error ) - { - // add serialized message data to appropriate out-going comm buffer - result = addToCommBuffer( buffer, data, msgSize ); - } - - return result; -} +static BOOL sendUIResponseMsg( MSG_ID_T msgID, UI_RESPONSE_PAYLOAD_T *uiResponse ); /*********************************************************************//** * @brief + * The serializeMessage function serializes a given message into a given + * array of bytes. A sequence # is added to the message here and the ACK + * bit of the sequence # is set if ACK is required per parameter. A sync byte + * is inserted at the beginning of the message and an 8-bit CRC is appended to + * the end of the message. The message is queued for transmission in the given buffer. + * @details Inputs: none + * @details Outputs: given data array populated with serialized message data and queued for transmit. + * @param msg message to serialize + * @param buffer outgoing buffer that message should be queued in + * @param ackReq is an acknowledgement from receiver required? + * @return size (in bytes) of serialized message populated in given data array. + *************************************************************************/ +U32 serializeMessage( MESSAGE_T msg, COMM_BUFFER_T buffer, BOOL ackReq ) +{ + BOOL result = FALSE; + BOOL error = FALSE; + U32 msgSize = 0; + U32 sizeMod, sizePad; + U32 i; + U08 crc; + U08 data[ MAX_ACK_MSG_SIZE ]; // byte array to populate with message data + + // prefix data with message sync byte + data[ msgSize++ ] = MESSAGE_SYNC_BYTE; + + // set sequence # and ACK bit (unless this is an ACK to a received message) + if ( msg.hdr.msgID != MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK ) + { + // thread protect next sequence # access & increment + _disable_IRQ(); + msg.hdr.seqNo = nextSeqNo; + nextSeqNo = INC_WRAP( nextSeqNo, MIN_MSG_SEQ_NO, MAX_MSG_SEQ_NO ); + _enable_IRQ(); + if ( TRUE == ackReq ) + { + msg.hdr.seqNo *= -1; + } + } + + // calculate message CRC + crc = crc8( (U08*)(&msg), sizeof( MESSAGE_HEADER_T ) + msg.hdr.payloadLen ); + + // serialize message header data + memcpy( &data[ msgSize ], &( msg.hdr ), sizeof( MESSAGE_HEADER_T ) ); + msgSize += sizeof( MESSAGE_HEADER_T ); + + // serialize message payload (only used bytes per payloadLen field) + memcpy( &data[ msgSize ], &( msg.payload ), msg.hdr.payloadLen ); + msgSize += msg.hdr.payloadLen; + + // add 8-bit CRC + data[ msgSize++ ] = crc; + + // pad with zero bytes to get length a multiple of CAN_MESSAGE_PAYLOAD_SIZE (8) + sizeMod = msgSize % CAN_MESSAGE_PAYLOAD_SIZE; + sizePad = ( sizeMod == 0 ? 0 : CAN_MESSAGE_PAYLOAD_SIZE - sizeMod ); + for ( i = 0; i < sizePad; i++ ) + { + data[ msgSize++ ] = 0; + } + + // if ACK required, add to pending ACK list + if ( TRUE == ackReq ) + { + if ( FALSE == addMsgToPendingACKList( &msg, buffer, data, msgSize ) ) + { + error = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_MSG_PENDING_ACK_LIST_FULL ) + } + } + + if ( FALSE == error ) + { + // add serialized message data to appropriate out-going comm buffer + result = addToCommBuffer( buffer, data, msgSize ); + } + + return result; +} + +/*********************************************************************//** + * @brief * The sendACKMsg function constructs and queues for transmit an ACK message * for a given received message. * @details Inputs: none @@ -450,9 +450,6 @@ *************************************************************************/ void handleRTCSyncFromHD( MESSAGE_T *message ) { - // TODO - remove the code below until the issue for the synchronization - // of the DG RTC to the HD RTC is resolved. -/* // Only sync RTC to HD date/time when ... if ( TRUE == syncDG2HDDateTime() ) { @@ -464,7 +461,6 @@ setRTCEpoch( epoch.epochTime ); } } -*/ } /*********************************************************************//**