Index: firmware/App/Controllers/DrainPump.c =================================================================== diff -u -rc1ef106ed0f97dc998230c6e154aa2362aa476d8 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision c1ef106ed0f97dc998230c6e154aa2362aa476d8) +++ firmware/App/Controllers/DrainPump.c (.../DrainPump.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -41,17 +41,22 @@ // ********** private definitions ********** -#define DRAIN_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< interval at which the Drain Pump data is published on the CAN bus. -#define DRP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval at which the Drain pump is controlled. +#define DRAIN_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< interval (ms/task time) at which the Drain Pump data is published on the CAN bus -#define DRP_SPEED_ADC_TO_RPM_FACTOR 12.94 ///< conversion factor from ADC counts to RPM for Drain pump. -#define DRP_SPEED_RPM_TO_ADC_FACTOR ( 1.0 / DRP_SPEED_ADC_TO_RPM_FACTOR ) ///< conversion factor from RPM to ADC counts for Drain pump. +#define DRP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the Drain pump is controlled +#define DRP_SPEED_ADC_TO_RPM_FACTOR 12.94 ///< conversion factor from ADC counts to RPM for Drain pump +#define DRP_SPEED_RPM_TO_ADC_FACTOR ( 1.0 / DRP_SPEED_ADC_TO_RPM_FACTOR ) ///< conversion factor from RPM to ADC counts for Drain pump + +#define DRAIN_PUMP_P_COEFFICIENT 0.005 ///< P term for drain pump delta pressure control +#define DRAIN_PUMP_I_COEFFICIENT 0.0015 ///< I term for drain pump delta pressure control + /// Enumeration of drain pump states. typedef enum DrainPump_States { DRAIN_PUMP_OFF_STATE = 0, ///< Drain pump off state - DRAIN_PUMP_CONTROL_TO_TARGET_STATE, ///< Drain pump control to target state + DRAIN_PUMP_CONTROL_TO_TARGET_STATE, ///< Drain pump control to target state + DRAIN_PUMP_OPEN_LOOP_STATE, ///< Drain pump open loop state NUM_OF_DRAIN_PUMP_STATES ///< Number of drain pump states } DRAIN_PUMP_STATE_T; @@ -74,27 +79,31 @@ // ********** private data ********** -static DRAIN_PUMP_STATE_T drainPumpState = DRAIN_PUMP_OFF_STATE; ///< current state of drain pump controller state machine. -static U32 drainPumpDataPublicationTimerCounter = 0; ///< Drain pump data publish timer counter. -static BOOL isDrainPumpOn = FALSE; ///< Flag indicates drain pump is running or off. -static U32 drainPumpDAC = 0; ///< Initial drain pump DAC value. -static U32 drainPumpDACSet = 0; ///< Current set drain pump DAC value. -static PUMP_CONTROL_MODE_T drainPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested drain pump control mode. -static PUMP_CONTROL_MODE_T drainPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Current set drain pump control mode. +static DRAIN_PUMP_STATE_T drainPumpState = DRAIN_PUMP_OFF_STATE; ///< current state of drain pump controller state machine +static U32 drainPumpDataPublicationTimerCounter = 0; ///< used to schedule drain pump data publication to CAN bus +static U32 drainPumpDAC = 0; ///< initial drain pump DAC value +static U32 drainPumpDACSet = 0; ///< currently set drain pump DAC value +static PUMP_CONTROL_MODE_T drainPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; ///< requested drain pump control mode +static PUMP_CONTROL_MODE_T drainPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< currently set drain pump control mode static OVERRIDE_U32_T drainPumpDataPublishInterval = { DRAIN_PUMP_DATA_PUB_INTERVAL, DRAIN_PUMP_DATA_PUB_INTERVAL, - 0, 0 }; ///< Drain pump data publish interval. -static OVERRIDE_U32_T targetDrainPumpSpeed = { 0, 0, 0, 0 }; ///< Target drain pump speed. -static U32 drainControlTimerCounter = 0; ///< Timer counter for control drain pump. + 0, 0 }; ///< interval (in ms) at which to publish RO flow data to CAN bus +static OVERRIDE_U32_T targetDrainPumpSpeed = { 0, 0, 0, 0 }; ///< Target RO pressure (in PSI) +static OVERRIDE_F32_T targetDrainPumpDeltaPressure = { 0.0, 0.0, 0.0, 0.0 }; ///< Target delta pressure for the drain pump -static DRAIN_PUMP_SELF_TEST_STATE_T drainPumpSelfTestState; ///< Current drain pump self-test state. -static U32 drainPumpSelfTestTimerCount = 0; ///< Timer counter for drain pump self-test. +static U32 drainControlTimerCounter = 0; ///< determines when to perform control on drain pump +/* These variables are used for POST. POST will be implemented later +static DRAIN_PUMP_SELF_TEST_STATE_T drainPumpSelfTestState = DRAIN_PUMP_SELF_TEST_STATE_START; ///< current drain pump self test state +static U32 drainPumpSelfTestTimerCount = 0; ///< timer counter for drain pump self test +*/ + // ********** private function prototypes ********** static DRAIN_PUMP_STATE_T handleDrainPumpOffState( void ); -static DRAIN_PUMP_STATE_T handleDrainPumpControlToTargetState( void ); +static DRAIN_PUMP_STATE_T handleDrainPumpControlToTargetState( void ); +static DRAIN_PUMP_STATE_T handleDrainPumpOpenLoopState( void ); static void stopDrainPump( void ); static void publishDrainPumpData( void ); static U32 getPublishDrainPumpDataInterval( void ); @@ -110,20 +119,25 @@ void initDrainPump( void ) { stopDrainPump(); + + // Initialize the drain pump PI controller + initializePIController( PI_CONTROLLER_ID_DRAIN_PUMP, MIN_DRAIN_PUMP_RPM_TARGET, + DRAIN_PUMP_P_COEFFICIENT, DRAIN_PUMP_I_COEFFICIENT, + MIN_DRAIN_PUMP_RPM_TARGET, MAX_DRAIN_PUMP_RPM_TARGET ); } /*********************************************************************//** * @brief * The setDrainPumpTargetSpeed function sets a new target speed for the drain pump. * @details - * Inputs : none - * Outputs : targetDrainPumpPressure - * @param rpm new target drain pump speed (in RPM) - * @return TRUE if new target speed is set, FALSE if not + * Inputs: none + * Outputs: targetDrainPumpPressure + * @param: rpm : new target drain pump speed (in RPM). + * @return: TRUE if new target speed is set, FALSE if not *************************************************************************/ BOOL setDrainPumpTargetSpeed( U32 rpm ) { - BOOL result = FALSE; + BOOL result = FALSE; if ( ( 0 == rpm ) || ( ( rpm >= MIN_DRAIN_PUMP_RPM_TARGET ) && ( rpm <= MAX_DRAIN_PUMP_RPM_TARGET ) ) ) @@ -139,31 +153,53 @@ } return result; +} + +/*********************************************************************//** + * @brief + * The setDrainPumpTargetDeltaPressure function sets the target delta\n + * pressure in between the PRd and PDr sensors + * @details + * Inputs: targetDrainPumpDeltaP + * Outputs: targetDrainPumpDeltaP + * @param: deltaP : new target drain pump delta pressure + * @return: TRUE if new target speed is set, FALSE if not + *************************************************************************/ +BOOL setDrainPumpTargetDeltaPressure ( F32 deltaP ) +{ + BOOL result = FALSE; + + targetDrainPumpDeltaPressure.data = deltaP; + drainPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; + result = TRUE; + + return result; } /*********************************************************************//** * @brief * The signalDrainPumpHardStop function stops the Drain pump immediately. * @details - * Inputs : none - * Outputs : Drain pump stopped, set point reset, state changed to off - * @return none + * Inputs: none + * Outputs: Drain pump stopped, set point reset, state changed to off + * @return: none *************************************************************************/ void signalDrainPumpHardStop( void ) { targetDrainPumpSpeed.data = 0; stopDrainPump(); - drainPumpState = DRAIN_PUMP_OFF_STATE; + drainPumpState = DRAIN_PUMP_OFF_STATE; + drainPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; // Set the control mode to none drainControlTimerCounter = 0; } /*********************************************************************//** * @brief * The execDrainPumpMonitor function executes the drain pump monitor. * @details - * Inputs : none - * Outputs : publish drain pump data - * @return none + * Inputs: none + * Outputs: none + * @return: none *************************************************************************/ void execDrainPumpMonitor( void ) { @@ -181,9 +217,9 @@ * @brief * The execDrainPumpController function executes the drain pump controller. * @details - * Inputs : drainPumpState - * Outputs : drainPumpState - * @return none + * Inputs: drainPumpState + * Outputs: drainPumpState + * @return: none *************************************************************************/ void execDrainPumpController( void ) { @@ -195,6 +231,10 @@ case DRAIN_PUMP_CONTROL_TO_TARGET_STATE: drainPumpState = handleDrainPumpControlToTargetState(); + break; + + case DRAIN_PUMP_OPEN_LOOP_STATE: + drainPumpState = handleDrainPumpOpenLoopState(); break; default: @@ -209,9 +249,9 @@ * The handleDrainPumpOffState function handles the drain pump off state of * the drain pump controller state machine. * @details - * Inputs : targetDrainPumpSpeed - * Outputs : drainPumpPWMDutyCyclePctSet, isDrainPumpOn - * @return next state + * Inputs: targetDrainPumpSpeed + * Outputs: drainPumpPWMDutyCyclePctSet + * @return: next state *************************************************************************/ static DRAIN_PUMP_STATE_T handleDrainPumpOffState( void ) { @@ -234,19 +274,36 @@ #endif #endif - // if we've been given a pressure, transition to control to target state - if ( getTargetDrainPumpSpeed() > 0 ) + // If the target drain pump speed was not 0 and the control mode + // is open loop, set the drain pump to open loop + if ( getTargetDrainPumpSpeed() > 0 && drainPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) { // set drain pump enable pin SET_DRAIN_PUMP_ENABLE(); - // set drain pump control mode - drainPumpControlModeSet = drainPumpControlMode; + // set drain pump DAC drainPumpDACSet = drainPumpDAC; setFPGADrainPumpSpeed( drainPumpDACSet ); - // set pump to on - isDrainPumpOn = TRUE; - result = DRAIN_PUMP_CONTROL_TO_TARGET_STATE; + + result = DRAIN_PUMP_OPEN_LOOP_STATE; + } + // If the drain pump is set to closed loop, call the proper state + // It is checked for the value of delta pressure because it can be anything + // including 0 + else if ( drainPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + // set drain pump enable pin + SET_DRAIN_PUMP_ENABLE(); + + resetPIController( PI_CONTROLLER_ID_DRAIN_PUMP, MIN_DRAIN_PUMP_RPM_TARGET ); + + U32 rpm = targetDrainPumpSpeed.data; + drainPumpDAC = (U32)((F32)rpm * DRP_SPEED_RPM_TO_ADC_FACTOR + FLOAT_TO_INT_ROUNDUP_OFFSET); + // set drain pump DAC + drainPumpDACSet = drainPumpDAC; + setFPGADrainPumpSpeed( drainPumpDACSet ); + + result = DRAIN_PUMP_CONTROL_TO_TARGET_STATE; } return result; @@ -257,9 +314,9 @@ * The handleDrainPumpControlToTargetState function handles the "control to * target" state of the drain pump controller state machine. * @details - * Inputs : none - * Outputs : drainPumpState - * @return next state + * Inputs: none + * Outputs: drainPumpState + * @return: next state *************************************************************************/ static DRAIN_PUMP_STATE_T handleDrainPumpControlToTargetState( void ) { @@ -268,18 +325,29 @@ // control at set interval if ( ++drainControlTimerCounter >= DRP_CONTROL_INTERVAL ) { + F32 inletDrainPressure = getMeasuredDGPressure ( PRESSURE_SENSOR_DRAIN_PUMP_INLET ); + F32 outletDrainPressure = getMeasuredDGPressure ( PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ); + F32 pressureDiff = inletDrainPressure - outletDrainPressure; + F32 rpm = runPIController( PI_CONTROLLER_ID_DRAIN_PUMP, targetDrainPumpDeltaPressure.data, pressureDiff ); + drainPumpDACSet = (U32)(rpm * DRP_SPEED_RPM_TO_ADC_FACTOR + FLOAT_TO_INT_ROUNDUP_OFFSET); + setFPGADrainPumpSpeed( drainPumpDACSet ); + + // From a merge from master if ( drainPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) { #ifndef EMC_TEST_BUILD // TODO - will drain pump have a closed loop? #endif } + drainControlTimerCounter = 0; - } + } + // From a merge from master if ( 0 == getTargetDrainPumpSpeed() ) { - signalDrainPumpHardStop(); + signalDrainPumpHardStop(); + result = DRAIN_PUMP_OFF_STATE; } @@ -301,19 +369,32 @@ #endif return result; +} + +/*********************************************************************//** + * @brief + * The handleDrainPumpOpenLoopState function handles the open loop \n + * state + * @details + * Inputs: none + * Outputs: none + * @return: next state + *************************************************************************/ +static DRAIN_PUMP_STATE_T handleDrainPumpOpenLoopState( void ) +{ + return DRAIN_PUMP_OPEN_LOOP_STATE; } /*********************************************************************//** * @brief * The stopDrainPump function sets the drain pump DAC to zero. * @details - * Inputs : none - * Outputs : isDrainPumpOn, DAC zeroed, clear drain pump enable - * @return none + * Inputs: none + * Outputs: DAC zeroed + * @return: none *************************************************************************/ static void stopDrainPump( void ) { - isDrainPumpOn = FALSE; drainPumpDAC = 0; drainPumpDACSet = 0; setFPGADrainPumpSpeed( drainPumpDACSet ); @@ -325,9 +406,9 @@ * The getPublishDrainPumpDataInterval function gets the drain pump data * publication interval. * @details - * Inputs : drainPumpDataPublishInterval - * Outputs : none - * @return the current drain pump data publication interval (in ms). + * Inputs: drainPumpDataPublishInterval + * Outputs: none + * @return: the current Drain pump data publication interval (in ms). *************************************************************************/ static U32 getPublishDrainPumpDataInterval( void ) { @@ -346,9 +427,9 @@ * The getTargetDrainPumpSpeed function gets the current target drain pump * speed. * @details - * Inputs : targetDrainPumpSpeed + * Inputs: targetDrainPumpSpeed * Outputs : none - * @return the current target drain pump speed. + * @return: the current target drain pump speed. *************************************************************************/ U32 getTargetDrainPumpSpeed( void ) { @@ -366,17 +447,23 @@ * @brief * The publishDrainPumpData function publishes drain pump data at the set interval. * @details - * Inputs : target speed - * Outputs : Drain pump data is published to CAN bus. - * @return none + * Inputs: target speed + * Outputs: Drain pump data is published to CAN bus. + * @return: none *************************************************************************/ static void publishDrainPumpData( void ) { // publish Drain pump data on interval if ( ++drainPumpDataPublicationTimerCounter >= getPublishDrainPumpDataInterval() ) { - U32 const spdStPt = getTargetDrainPumpSpeed(); - broadcastDrainPumpData( spdStPt, drainPumpDACSet ); + // TODO: This was a const in master, why? + U32 spdStPt = getTargetDrainPumpSpeed(); + + F32 pressureDiff = fabs( getMeasuredDGPressure ( PRESSURE_SENSOR_DRAIN_PUMP_INLET ) - + getMeasuredDGPressure ( PRESSURE_SENSOR_DRAIN_PUMP_OUTLET ) ); + + broadcastDrainPumpData( spdStPt, drainPumpDACSet, pressureDiff, (U32)drainPumpState ); + drainPumpDataPublicationTimerCounter = 0; } } @@ -386,9 +473,9 @@ * The execDrainPumpTest function executes the state machine for the drain * pump self-test. * @details - * Inputs : none - * Outputs : none - * @return the current state of the drain pump self-test. + * Inputs: none + * Outputs: none + * @return: the current state of the Drain Pump self test. *************************************************************************/ SELF_TEST_STATUS_T execDrainPumpTest( void ) { @@ -398,8 +485,9 @@ return result; } + +/**@}*/ - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -410,10 +498,10 @@ * The testSetDrainPumpDataPublishIntervalOverride function overrides the * drain pump data publish interval. * @details - * Inputs : none - * Outputs : drainPumpDataPublishInterval - * @param value override drain pump data publish interval with (in ms) - * @return TRUE if override successful, FALSE if not + * Inputs: none + * Outputs: drainPumpDataPublishInterval + * @param: value : override RO pump data publish interval with (in ms) + * @return: TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetDrainPumpDataPublishIntervalOverride( U32 value ) { @@ -436,9 +524,9 @@ * The testResetDrainPumpDataPublishIntervalOverride function resets the * override of the drain pump data publish interval. * @details - * Inputs : none - * Outputs : drainPumpDataPublishInterval - * @return TRUE if override reset successful, FALSE if not + * Inputs: none + * Outputs: drainPumpDataPublishInterval + * @return: TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetDrainPumpDataPublishIntervalOverride( void ) { @@ -459,10 +547,10 @@ * The testSetTargetDrainPumpSpeedOverride function overrides the target * drain pump speed (in RPM). * @details - * Inputs : none - * Outputs : targetDrainPumpSpeed - * @param value override target drain pump speed (in RPM) - * @return TRUE if override successful, FALSE if not + * Inputs: none + * Outputs: targetDrainPumpSpeed + * @param: value : override target drain pump speed (in RPM) + * @return: TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetTargetDrainPumpSpeedOverride( U32 value ) { @@ -484,9 +572,9 @@ * The testResetTargetDrainPumpSpeedOverride function resets the override of the * target drain pump speed (in RPM). * @details - * Inputs : none - * Outputs : targetDrainPumpSpeed - * @return TRUE if override reset successful, FALSE if not + * Inputs: none + * Outputs: targetDrainPumpSpeed + * @return: TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetTargetDrainPumpSpeedOverride( void ) { @@ -502,6 +590,56 @@ } return result; -} +} + +/*********************************************************************//** + * @brief + * The testSetTargetDrainPumpDeltaPressureOverride function overrides \n + * the target drain pump delta pressure + * @details + * Inputs: none + * Outputs: targetDrainPumpDeltaPressure + * @param: value : override target drain pump delta pressure + * @return: TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetDrainPumpDeltaPressureOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetDrainPumpDeltaPressure.ovInitData = targetDrainPumpDeltaPressure.data; // backup current target delta pressure + targetDrainPumpDeltaPressure.ovData = value; + targetDrainPumpDeltaPressure.override = OVERRIDE_KEY; + result = setDrainPumpTargetDeltaPressure( value ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetTargetDrainPumpDeltaPressureOverride function resets the \n + * override of the target drain pump delta pressure + * @details + * Inputs: none + * Outputs: targetDrainPumpDeltaPressure + * @return: TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetTargetDrainPumpDeltaPressureOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetDrainPumpDeltaPressure.data = targetDrainPumpDeltaPressure.ovInitData; // restore pre-override target delta pressure + targetDrainPumpDeltaPressure.override = OVERRIDE_RESET; + targetDrainPumpDeltaPressure.ovInitData = 0; + targetDrainPumpDeltaPressure.ovData = 0; + result = setDrainPumpTargetDeltaPressure( targetDrainPumpDeltaPressure.data ); + } + + return result; +} /**@}*/ Index: firmware/App/Controllers/DrainPump.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Controllers/DrainPump.h (.../DrainPump.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Controllers/DrainPump.h (.../DrainPump.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -39,17 +39,24 @@ void execDrainPumpMonitor( void ); void execDrainPumpController( void ); -BOOL setDrainPumpTargetSpeed( U32 rpm ); +BOOL setDrainPumpTargetSpeed( U32 rpm ); + +BOOL setDrainPumpTargetDeltaPressure ( F32 deltaP ); + void signalDrainPumpHardStop( void ); SELF_TEST_STATUS_T execDrainPumpTest( void ); U32 getTargetDrainPumpSpeed( void ); BOOL testSetDrainPumpDataPublishIntervalOverride( U32 value ); -BOOL testResetDrainPumpDataPublishIntervalOverride( void ); +BOOL testResetDrainPumpDataPublishIntervalOverride( void ); + BOOL testSetTargetDrainPumpSpeedOverride( U32 value ); -BOOL testResetTargetDrainPumpSpeedOverride( void ); +BOOL testResetTargetDrainPumpSpeedOverride( void ); + +BOOL testSetTargetDrainPumpDeltaPressureOverride( F32 value ); +BOOL testResetTargetDrainPumpDeltaPressureOverride( void ); /**@}*/ Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -rc1ef106ed0f97dc998230c6e154aa2362aa476d8 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision c1ef106ed0f97dc998230c6e154aa2362aa476d8) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -45,6 +45,29 @@ #define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. +#define MAX_RO_PUMP_PWM_STEP_CHANGE 0.01 ///< max duty cycle change for controller +#define MAX_RO_PUMP_PWM_DUTY_CYCLE 0.99 ///< max duty cycle +#define MIN_RO_PUMP_PWM_DUTY_CYCLE 0.00 ///< min duty cycle + +#define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the RO pump is controlled +#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump pressure control +#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump pressure control + +#define ROP_RAMP_UP_P_COEFFICIENT 0.0 ///< P term for RO pump flow control +#define ROP_RAMP_UP_I_COEFFICIENT 0.01 ///< I term for RO pump flow control +#define ROP_FLOW_TARGET_TOLERANCE 0.05 ///< Tolerance in between the target flow rate and the actual flow rate in liter + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor) + +#define FLOW_SAMPLES_TO_AVERAGE (250 / TASK_PRIORITY_INTERVAL) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER (1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE) ///< Optimization - multiplying is faster than dividing +#define FLOW_VERIFICATION_COUNTER_TARGET 40U ///< The time in counts to check the flow and make sure it is in range + +#define RO_FLOW_ADC_TO_LPM_FACTOR 10909.0909 ///< conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). + +// Initial PWM for the requested flow rate. It is assumed that 100% duty cycle will provide 1.2 LPM +#define ROP_FLOW_TO_PWM_DC(flow) ((F32)(flow / 1.2)) ///< Initial conversion factor from target flow rate to PWM duty cycle estimate + #define MAX_RO_PUMP_PWM_STEP_CHANGE 0.01 ///< Max duty cycle change for controller. #define MAX_RO_PUMP_PWM_DUTY_CYCLE 0.99 ///< Max duty cycle. #define MIN_RO_PUMP_PWM_DUTY_CYCLE 0.00 ///< Min duty cycle. @@ -66,7 +89,10 @@ typedef enum ROPump_States { RO_PUMP_OFF_STATE = 0, ///< RO pump off state - RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state + RO_PUMP_RAMP_UP_STATE, ///< RO pump ramp up to target flow rate state + RO_PUMP_VERIFY_FLOW_STATE, ///< RO pump maintain the flow rate for a set period of time + RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state + RO_PUMP_OPEN_LOOP_STATE, ///< RO pump open loop state NUM_OF_RO_PUMP_STATES ///< Number of RO pump states } RO_PUMP_STATE_T; @@ -83,36 +109,55 @@ // pin assignments for pump test DIP switch 0 #define RO_PUMP_TEST_SPI5_PORT_MASK 0x00000100 // (ENA - re-purposed as input GPIO) // dialIn pump stop and direction macros -#define GET_DIP_SW0_TEST() ( ( mibspiREG5->PC2 & RO_PUMP_TEST_SPI5_PORT_MASK ) != 0 ) +#define GET_DIP_SW0_TEST() ( ( mibspiREG5->PC2 & RO_PUMP_TEST_SPI5_PORT_MASK ) != 0 ) // ********** private data ********** -static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< Current state of RO pump controller state machine. -static U32 roPumpDataPublicationTimerCounter = 0; ///< RO pump data publication timer counter. -static BOOL isROPumpOn = FALSE; ///< RO pump is currently running. -static F32 roPumpPWMDutyCyclePct = 0.0; ///< Initial RO pump PWM duty cycle. -static F32 roPumpPWMDutyCyclePctSet = 0.0; ///< Currently set RO pump PWM duty cycle. -static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested RO pump control mode. -static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set RO pump control mode. +static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< current state of RO pump controller state machine +static U32 roPumpDataPublicationTimerCounter = 0; ///< used to schedule RO pump data publication to CAN bus +static BOOL isROPumpOn = FALSE; ///< RO pump is currently running +static F32 roPumpPWMDutyCyclePct = 0.0; ///< initial RO pump PWM duty cycle +static F32 roPumpPWMDutyCyclePctSet = 0.0; ///< currently set RO pump PWM duty cycle +static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< requested RO pump control mode //TODO remove +static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< currently set RO pump control mode +static OVERRIDE_F32_T targetROPumpFlowRate = { 0, 0, 0, 0 }; ///< Target RO flow rate (in LPM) static OVERRIDE_U32_T roPumpDataPublishInterval = { RO_PUMP_DATA_PUB_INTERVAL, - RO_PUMP_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus. + RO_PUMP_DATA_PUB_INTERVAL, + 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus +static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< measured RO flow rate (in LPM) +static F32 measuredROPumpPressure = 0.0; ///< measured RO pressure (in PSI) // TODO remove +static F32 tgtROPumpPressure = 0.0; ///< Target RO control pressure (in PSI) + +static U32 flowVerificationCounter = 0; ///< Counter to verify the flow is in range + +static U32 roControlTimerCounter = 0; ///< determines when to perform control on ro pump + +static U32 roPumpOpenLoopTargetPWM = 0; ///< Target RO pump open loop PWM +static F32 roPumpFlowRateRunningSum = 0; +static F32 roPumpPressureRunningSum = 0; + +/* The variables used for POST. They are not in use yet, so they are commented out +static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< current ro pump self test state +static U32 roPumpSelfTestTimerCount = 0; ///< timer counter for ro pump self test +*/ + static OVERRIDE_U32_T targetROPumpPressure = { 0, 0, 0, 0 }; ///< Target RO pressure (in PSI). -static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured RO flow rate (in LPM). -static F32 measuredROPumpPressure = 0.0; ///< Measured RO pressure (in PSI). static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. static U32 flowFilterCounter = 0; ///< Flow filtering counter. -static U32 roControlTimerCounter = 0; ///< Timer counter for perform control on RO pump. static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current RO pump self-test state. static U32 roPumpSelfTestTimerCount = 0; ///< Timer counter for RO pump self-test. // ********** private function prototypes ********** static RO_PUMP_STATE_T handleROPumpOffState( void ); -static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); +static RO_PUMP_STATE_T handleROPumpRampUpState( void ); +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ); +static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); static void setROPumpControlSignalPWM( F32 newPWM ); static void stopROPump( void ); static void publishROPumpData( void ); @@ -122,50 +167,114 @@ * @brief * The initROPump function initializes the ROPump module. * @details - * Inputs : none - * Outputs : ROPump module initialized. + * Inputs: none + * Outputs: ROPump module initialized. * @return none *************************************************************************/ void initROPump( void ) { stopROPump(); - // initialize RO pump PI controller - initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE, ROP_P_COEFFICIENT, - ROP_I_COEFFICIENT, MIN_RO_PUMP_PWM_DUTY_CYCLE, MAX_RO_PUMP_PWM_DUTY_CYCLE ); + // Initialize RO pump PI controller + initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE, + ROP_P_COEFFICIENT, ROP_I_COEFFICIENT, + MIN_RO_PUMP_PWM_DUTY_CYCLE, MAX_RO_PUMP_PWM_DUTY_CYCLE ); + + // Initialize the P controller during ramp up + initializePIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_PWM_DUTY_CYCLE, + ROP_RAMP_UP_P_COEFFICIENT, ROP_RAMP_UP_I_COEFFICIENT, + MIN_RO_PUMP_PWM_DUTY_CYCLE, MAX_RO_PUMP_PWM_DUTY_CYCLE ); +} + +//TODO TEST AND REMOVE +/*********************************************************************//** + * @brief + * The setROPumpTargetPressure function sets a new target pressure for the RO pump. + * @details + * Inputs : none + * Outputs : targetROPumpPressure, roPumpPWMDutyCyclePct + * @param roPressure new target RO pressure + * @param mode new control mode + * @return TRUE if new target pressure is set, FALSE if not + *************************************************************************/ +BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ) +{ + BOOL result = FALSE; + + // verify pressure + if ( roPressure >= 10 && roPressure <= 50 ) + { + targetROPumpPressure.data = roPressure; + roPumpControlMode = mode; + // set PWM duty cycle target to an estimated initial target based on target pressure - then we'll control to pressure going forward +#ifdef EMC_TEST_BUILD + roPumpPWMDutyCyclePct = 1.0; +#else + roPumpPWMDutyCyclePct = ROP_PSI_TO_PWM_DC( roPressure ); +#endif + + result = TRUE; + } + else // requested pressure out of range + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPressure ) // TODO - replace 1st param with s/w fault enum + } + + return result; +} +//TODO TEST AND REMOVE + +/*********************************************************************//** + * @brief + * The setROPumpTargetPWM function sets the PWM that the pump should run + * @details + * Inputs: roPumpOpenLooptargetPWM, roPumpControlMode + * Outputs: roPumpOpenLooptargetPWM, roPumpControlMode + * @param: pwm + * @return whether the value was set (TRUE) or not (FALSE) + *************************************************************************/ +BOOL setROPumpTargetPWM( U32 pwm ) +{ + BOOL result = FALSE; + + if ( pwm > 0 ) + { + roPumpOpenLoopTargetPWM = pwm; + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( getTargetROPumpFlowRate() ); + roPumpControlMode = PUMP_CONTROL_MODE_OPEN_LOOP; + result = TRUE; + } + return result; } /*********************************************************************//** * @brief - * The setROPumpTargetPressure function sets a new target pressure for the RO pump. + * The setROPumpTargetFlowRate function sets a new target flow rate for the \n + * RO pump. * @details - * Inputs : none - * Outputs : targetROPumpPressure, roPumpPWMDutyCyclePct - * @param roPressure new target RO pressure - * @param mode new control mode - * @return TRUE if new target pressure is set, FALSE if not + * Inputs: none + * Outputs: targetROPumpFlowRate, roPumpPWMDutyCyclePct + * @param: roFlowRate : new target RO flow rate + * @return TRUE if new target flow rate is set, FALSE if not *************************************************************************/ -BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ) +BOOL setROPumpTargetFlowRate( F32 roFlowRate ) { BOOL result = FALSE; - // verify pressure - if ( roPressure >= MIN_RO_PRESSURE && roPressure <= MAX_RO_PRESSURE ) + if ( roFlowRate < MAX_RO_FLOWRATE_LPM && roFlowRate >= MIN_RO_FLOWRATE_LPM ) { - targetROPumpPressure.data = roPressure; - roPumpControlMode = mode; - // set PWM duty cycle target to an estimated initial target based on target pressure - then we'll control to pressure going forward -#ifdef EMC_TEST_BUILD - roPumpPWMDutyCyclePct = 1.0; -#else - roPumpPWMDutyCyclePct = ROP_PSI_TO_PWM_DC( roPressure ); + targetROPumpFlowRate.data = roFlowRate; + roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); +#ifdef EMC_TEST_BUILD + roPumpPWMDutyCyclePct = 1.0; +#else + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); #endif - - result = TRUE; } else // requested pressure out of range { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPressure ) // TODO - replace 1st param with s/w fault enum + //SET_ALARM_WITH_2_U32_DATA( ALARM_ID_SOFTWARE_FAULT, 0, roFlowRate ) // TODO - replace 1st param with s/w fault enum } return result; @@ -175,26 +284,28 @@ * @brief * The signalROPumpHardStop function stops the RO pump immediately. * @details - * Inputs : none - * Outputs : RO pump stopped, set point reset, state changed to off + * Inputs: none + * Outputs: RO pump stopped, set point reset, state changed to off * @return none *************************************************************************/ void signalROPumpHardStop( void ) { - targetROPumpPressure.data = 0; + targetROPumpFlowRate.data = 0; stopROPump(); roPumpState = RO_PUMP_OFF_STATE; roPumpPWMDutyCyclePct = 0.0; - roControlTimerCounter = 0; + roControlTimerCounter = 0; + flowVerificationCounter = 0; + isROPumpOn = FALSE; resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE ); } /*********************************************************************//** * @brief * The execROPumpMonitor function executes the RO Pump monitor. * @details - * Inputs : flowFilterCounter - * Outputs : measuredROPumpPressure, measuredROFlowRateLPM + * Inputs: none + * Outputs: measuredROPumpPressure, measuredROFlowRateLPM * @return none *************************************************************************/ void execROPumpMonitor( void ) @@ -235,8 +346,8 @@ * @brief * The execROPumpController function executes the RO Pump controller. * @details - * Inputs : roPumpState - * Outputs : roPumpState + * Inputs: roPumpState + * Outputs: roPumpState * @return none *************************************************************************/ void execROPumpController( void ) @@ -247,23 +358,36 @@ roPumpState = handleROPumpOffState(); break; + case RO_PUMP_RAMP_UP_STATE: + roPumpState = handleROPumpRampUpState(); + break; + + case RO_PUMP_VERIFY_FLOW_STATE: + roPumpState = handleROPumpVerifyFlowState(); + break; + case RO_PUMP_CONTROL_TO_TARGET_STATE: roPumpState = handleROPumpControlToTargetState(); + break; + + case RO_PUMP_OPEN_LOOP_STATE: + roPumpState = handleROPumpOpenLoopState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPumpState ) // TODO - replace 1st param with s/w fault enum roPumpState = RO_PUMP_OFF_STATE; break; - } + } } /*********************************************************************//** * @brief * The isROPumpOn function returns the status of RO pump. * @details - * Inputs : none - * Outputs : none + * Inputs: none + * Outputs: none + * @param: none * @return isROPumpOn *************************************************************************/ BOOL isReverseOsmosisPumpOn( void ) @@ -273,11 +397,11 @@ /*********************************************************************//** * @brief - * The handleROPumpOffState function handles the RO pump off state of the - * RO pump controller state machine. - * @details - * Inputs : targetROPumpPressure - * Outputs : roPumpPWMDutyCyclePctSet, isROPumpOn + * The handleROPumpOffState function handles the ro pump off state \n + * of the ro pump controller state machine. + * @details + * Inputs: roPumpPWMDutyCyclePctSet, isROPumpOn + * Outputs: roPumpPWMDutyCyclePctSet, isROPumpOn * @return next state *************************************************************************/ static RO_PUMP_STATE_T handleROPumpOffState( void ) @@ -306,32 +430,129 @@ #endif } #endif -#endif +#endif - // if we've been given a pressure, transition to control to target state - if ( getTargetROPumpPressure() > 0 ) + // If there is a flow, transition to P controller to get + // the corresponding pressure of that flow + if ( getTargetROPumpFlowRate() > 0 && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) { - roPumpControlModeSet = roPumpControlMode; - // set initial PWM duty cycle + roPumpControlModeSet = roPumpControlMode; + // set initial PWM duty cycle roPumpPWMDutyCyclePctSet = roPumpPWMDutyCyclePct; - setROPumpControlSignalPWM( roPumpPWMDutyCyclePctSet ); + setROPumpControlSignalPWM ( roPumpPWMDutyCyclePctSet ); // reset controller - resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpPWMDutyCyclePctSet ); + resetPIController ( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, roPumpPWMDutyCyclePctSet ); // set pump to on isROPumpOn = TRUE; - result = RO_PUMP_CONTROL_TO_TARGET_STATE; + result = RO_PUMP_RAMP_UP_STATE; + } + + if ( roPumpOpenLoopTargetPWM > 0 && roPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) + { + setROPumpControlSignalPWM ( roPumpOpenLoopTargetPWM ); + isROPumpOn = TRUE; + result = RO_PUMP_OPEN_LOOP_STATE; } return result; } + +/*********************************************************************//** + * @brief + * The handleROPumpRampUpState function handles the ro pump ramp up state \n + * of the ro pump controller state machine. + * @details + * Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet + * Outputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet + * @return next state + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpRampUpState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_RAMP_UP_STATE; + // control at set interval + if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) + { + F32 targetFlowRate = getTargetROPumpFlowRate(); + + F32 actualFlowRate = (F32)getMeasuredROFlowRate(); + + if ( fabs( actualFlowRate - targetFlowRate ) > ROP_FLOW_TARGET_TOLERANCE ) + { + F32 newPWM = runPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, targetFlowRate, actualFlowRate ); + roPumpPWMDutyCyclePctSet = newPWM; + setROPumpControlSignalPWM( newPWM ); + } + else + { + result = RO_PUMP_VERIFY_FLOW_STATE; + } + + roControlTimerCounter = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpVerifyFlowState function handles the RO pump verify \n + * flow state of the RO pump controller state machine. + * @details + * Inputs: flowVerificationCounter, roPumpPWMDutyCyclePctSet, \n + * tgtROPumpPressure, roPumpFlowRateRunningSum, roPumpPressureRunningSum + * Outputs: flowVerificationCounter, roPumpPWMDutyCyclePctSet, \n + * tgtROPumpPressure, roPumpFlowRateRunningSum, roPumpPressureRunningSum + * @return next state + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_VERIFY_FLOW_STATE; + + // Calculate the running sum of the flow rate and RO pump outlet pressure + roPumpFlowRateRunningSum = roPumpFlowRateRunningSum + (F32)getMeasuredROFlowRate(); + roPumpPressureRunningSum = roPumpPressureRunningSum + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // Check if the time for flow verification has elapsed + if ( ++flowVerificationCounter >= FLOW_VERIFICATION_COUNTER_TARGET ) + { + // Calculate the average pressure and flow rate + F32 avgPressure = roPumpPressureRunningSum / flowVerificationCounter; + F32 avgFlowRate = roPumpFlowRateRunningSum / flowVerificationCounter; + + F32 targetFlowRate = getTargetROPumpFlowRate(); + + // Calculate the flow rate deviation from the target flow rate + F32 flowRateDeviation = ( targetFlowRate - avgFlowRate ) / targetFlowRate; + // Use the flow rate deviation to adjust the average calculated pressure. This + // pressure is used as the target pressure + avgPressure = avgPressure + ( avgPressure * flowRateDeviation ); + + // Reset the P controller for the flow rate + resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_PWM_DUTY_CYCLE ); + tgtROPumpPressure = avgPressure; + + // set initial PWM duty cycle + roPumpPWMDutyCyclePctSet = roPumpPWMDutyCyclePct; + setROPumpControlSignalPWM( roPumpPWMDutyCyclePctSet ); + // reset controller + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpPWMDutyCyclePctSet ); + flowVerificationCounter = 0; + roPumpFlowRateRunningSum = 0; + roPumpPressureRunningSum = 0; + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + + return result; +} + /*********************************************************************//** * @brief * The handleROPumpControlToTargetState function handles the "control to * target" state of the RO pump controller state machine. * @details - * Inputs : none - * Outputs : roPumpState + * Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter + * Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter * @return next state *************************************************************************/ static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ) @@ -341,18 +562,18 @@ // control at set interval if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) { - if ( roPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) - { - F32 tgtPres = (F32)getTargetROPumpPressure(); - F32 actPres = measuredROPumpPressure; - F32 newPWM; + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); -#ifndef EMC_TEST_BUILD + F32 newPWM = runPIController( PI_CONTROLLER_ID_RO_PUMP, tgtROPumpPressure, actualPressure ); + roPumpPWMDutyCyclePctSet = newPWM; + setROPumpControlSignalPWM( newPWM ); + +/*#ifndef EMC_TEST_BUILD newPWM = runPIController( PI_CONTROLLER_ID_RO_PUMP, tgtPres, actPres ); roPumpPWMDutyCyclePctSet = newPWM; setROPumpControlSignalPWM( newPWM ); -#endif - } +#endif*/ + roControlTimerCounter = 0; } @@ -373,16 +594,30 @@ #endif return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpOpenLoopState function handles the open loop state \n + * of the RO pump controller + * @details + * Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter + * Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter + * @return next state + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ) +{ + return RO_PUMP_OPEN_LOOP_STATE; } /*********************************************************************//** * @brief * The setROPumpControlSignalPWM function sets the PWM duty cycle for the * RO pump to a given %. * @details - * Inputs : none - * Outputs : PWM duty cycle zeroed - * @param newPWM new duty cycle % to apply to PWM + * Inputs: none + * Outputs: PWM duty cycle zeroed + * @param: newPWM : new duty cycle % to apply to PWM * @return none *************************************************************************/ static void setROPumpControlSignalPWM( F32 newPWM ) @@ -394,8 +629,8 @@ * @brief * The stopROPump function sets the RO pump PWM to zero. * @details - * Inputs : none - * Outputs : PWM duty cycle zeroed + * Inputs: none + * Outputs: PWM duty cycle zeroed * @return none *************************************************************************/ static void stopROPump( void ) @@ -409,8 +644,8 @@ * @brief * The getPublishROPumpDataInterval function gets the RO pump data publish interval. * @details - * Inputs : roPumpDataPublishInterval - * Outputs : none + * Inputs: roPumpDataPublishInterval + * Outputs: none * @return the current RO pump data publication interval (in ms). *************************************************************************/ static U32 getPublishROPumpDataInterval( void ) @@ -427,19 +662,20 @@ /*********************************************************************//** * @brief - * The getTargetROPumpPressure function gets the current target RO pump pressure. + * The getTargetROPumpFlowRate function gets the current target RO pump \n + * flow rate * @details - * Inputs : targetROPumpPressure - * Outputs : none - * @return the current target RO pressure (in PSI). + * Inputs: targetROPumpFlowRate + * Outputs: targetROPumpFlowRate + * @return the current target RO flow rate (in LPM). *************************************************************************/ -U32 getTargetROPumpPressure( void ) +F32 getTargetROPumpFlowRate( void ) { - U32 result = targetROPumpPressure.data; + F32 result = targetROPumpFlowRate.data; - if ( OVERRIDE_KEY == targetROPumpPressure.override ) + if ( OVERRIDE_KEY == targetROPumpFlowRate.override ) { - result = targetROPumpPressure.ovData; + result = targetROPumpFlowRate.ovData; } return result; @@ -449,8 +685,8 @@ * @brief * The getMeasuredROFlowRate function gets the measured RO pump flow rate. * @details - * Inputs : measuredROFlowRateLPM - * Outputs : none + * Inputs: measuredROFlowRateLPM + * Outputs: none * @return the current RO pump flow rate (in LPM). *************************************************************************/ F32 getMeasuredROFlowRate( void ) @@ -469,19 +705,18 @@ * @brief * The publishROPumpData function publishes RO pump data at the set interval. * @details - * Inputs : target pressure, measured pressure, measured RO pump speed. - * Outputs : RO pump data is published to CAN bus. + * Inputs: target pressure, measured pressure, measured RO pump speed. + * Outputs: RO pump data is published to CAN bus. * @return none *************************************************************************/ static void publishROPumpData( void ) { // publish RO pump data on interval if ( ++roPumpDataPublicationTimerCounter >= getPublishROPumpDataInterval() ) { - U32 presStPt = getTargetROPumpPressure(); F32 measFlow = getMeasuredROFlowRate(); F32 pumpPWMPctDutyCycle = roPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; - broadcastROPumpData( presStPt, measFlow, pumpPWMPctDutyCycle ); + broadcastROPumpData( tgtROPumpPressure, measFlow, pumpPWMPctDutyCycle, (U32)roPumpState ); roPumpDataPublicationTimerCounter = 0; } } @@ -490,9 +725,9 @@ * @brief * The execROPumpTest function executes the state machine for the ROPump self-test. * @details - * Inputs : none - * Outputs : none - * @return the current state of the ROPump self-test. + * Inputs: none + * Outputs: none + * @return the current state of the ROPump self test. *************************************************************************/ SELF_TEST_STATUS_T execROPumpTest( void ) { @@ -514,9 +749,9 @@ * The testSetROPumpDataPublishIntervalOverride function overrides the * RO pump data publish interval. * @details - * Inputs : none - * Outputs : roPumpDataPublishInterval - * @param value override RO pump data publish interval with (in ms) + * Inputs: none + * Outputs: roPumpDataPublishInterval + * @param: value : override RO pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) @@ -540,8 +775,8 @@ * The testResetROPumpDataPublishIntervalOverride function resets the override * of the RO pump data publish interval. * @details - * Inputs : none - * Outputs : roPumpDataPublishInterval + * Inputs: none + * Outputs: roPumpDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetROPumpDataPublishIntervalOverride( void ) @@ -560,29 +795,29 @@ /*********************************************************************//** * @brief - * The testSetTargetROPumpPressureOverride function overrides the target - * RO pressure. + * The testSetTargetROPumpFlowRateOverride function overrides the target \n + * RO flow rate. \n * @details - * Inputs : none - * Outputs : targetROPumpPressure - * @param value override target RO pressure (in PSI) + * Inputs: targetROPumpFlowRate + * Outputs: targetROPumpPressure + * @param: value : override target RO flow rate (in LPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetTargetROPumpPressureOverride( U32 value ) +BOOL testSetTargetROPumpFlowRateOverride( F32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { - targetROPumpPressure.ovInitData = targetROPumpPressure.data; // backup current target pressure - targetROPumpPressure.ovData = value; - targetROPumpPressure.override = OVERRIDE_KEY; - result = setROPumpTargetPressure( value, roPumpControlMode ); + targetROPumpFlowRate.ovInitData = targetROPumpFlowRate.data; // backup current target pressure + targetROPumpFlowRate.ovData = value; + targetROPumpFlowRate.override = OVERRIDE_KEY; + result = setROPumpTargetFlowRate( value ); } return result; } - + /*********************************************************************//** * @brief * The testResetTargetROPumpPressureOverride function resets the override of the @@ -592,30 +827,80 @@ * Outputs : targetROPumpPressure * @return TRUE if override reset successful, FALSE if not *************************************************************************/ -BOOL testResetTargetROPumpPressureOverride( void ) +BOOL testResetTargetROPumpFlowRateOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { - targetROPumpPressure.data = targetROPumpPressure.ovInitData; // restore pre-override target pressure - targetROPumpPressure.override = OVERRIDE_RESET; - targetROPumpPressure.ovInitData = 0; - targetROPumpPressure.ovData = 0; - result = setROPumpTargetPressure( targetROPumpPressure.data, roPumpControlMode ); + targetROPumpFlowRate.data = targetROPumpFlowRate.ovInitData; // restore pre-override target pressure + targetROPumpFlowRate.override = OVERRIDE_RESET; + targetROPumpFlowRate.ovInitData = 0; + targetROPumpFlowRate.ovData = 0; + result = setROPumpTargetFlowRate( targetROPumpFlowRate.data ); } return result; -} +} + +/*********************************************************************//** + * @brief + * The testSetTargetROPumpPressureOverride function overrides the target + * RO pressure. + * @details + * Inputs : none + * Outputs : targetROPumpPressure + * @param value override target RO pressure (in PSI) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetROPumpPressureOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetROPumpPressure.ovInitData = targetROPumpPressure.data; // backup current target pressure + targetROPumpPressure.ovData = value; + targetROPumpPressure.override = OVERRIDE_KEY; + result = setROPumpTargetPressure( value, roPumpControlMode ); + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetTargetROPumpPressureOverride function resets the override of the + * target RO pressure. + * @details + * Inputs : none + * Outputs : targetROPumpPressure + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetTargetROPumpPressureOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + targetROPumpPressure.data = targetROPumpPressure.ovInitData; // restore pre-override target pressure + targetROPumpPressure.override = OVERRIDE_RESET; + targetROPumpPressure.ovInitData = 0; + targetROPumpPressure.ovData = 0; + result = setROPumpTargetPressure( targetROPumpPressure.data, roPumpControlMode ); + } + + return result; +} /*********************************************************************//** * @brief * The testSetMeasuredROFlowRateOverride function overrides the measured * RO flow rate. * @details - * Inputs : none - * Outputs : measuredROFlowRateLPM - * @param value override measured RO pump motor speed (in LPM) + * Inputs: none + * Outputs: measuredROFlowRateLPM + * @param: value : override measured RO pump motor speed (in LPM) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetMeasuredROFlowRateOverride( F32 value ) @@ -637,8 +922,10 @@ * The testResetMeasuredROFlowRateOverride function resets the override of the * measured RO flow rate. * @details - * Inputs : none - * Outputs : measuredROFlowRateLPM + * Inputs: none + * Outputs: measuredROFlowRateLPM + * @param: none + * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testResetMeasuredROFlowRateOverride( void ) Index: firmware/App/Controllers/ROPump.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -29,30 +29,35 @@ */ // ********** public definitions ********** +#define MAX_RO_FLOWRATE_LPM 1.2 ///< Maximum target RO flow rate (in LPM) +#define MIN_RO_FLOWRATE_LPM 0.2 ///< Minimum target RO flow rate (in LPM) -#define MAX_RO_PRESSURE 140 ///< Maximum target RO outlet pressure (in PSI). -#define MIN_RO_PRESSURE 100 ///< Minimum target RO outlet pressure (in PSI). - // ********** public function prototypes ********** void initROPump( void ); void execROPumpMonitor( void ); void execROPumpController( void ); -BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ); +BOOL setROPumpTargetFlowRate( F32 roFlowRate ); +BOOL setROPumpTargetPWM( U32 pwm ); void signalROPumpHardStop( void ); BOOL isReverseOsmosisPumpOn( void ); SELF_TEST_STATUS_T execROPumpTest( void ); - -U32 getTargetROPumpPressure( void ); -F32 getMeasuredROFlowRate( void ); +DATA_GET_PROTOTYPE( F32, getTargetROPumpFlowRate ); +DATA_GET_PROTOTYPE( F32, getMeasuredROFlowRate ); + BOOL testSetROPumpDataPublishIntervalOverride( U32 value ); BOOL testResetROPumpDataPublishIntervalOverride( void ); -BOOL testSetTargetROPumpPressureOverride( U32 value ); + +BOOL testSetTargetROPumpFlowRateOverride( F32 value ); +BOOL testResetTargetROPumpFlowRateOverride( void ); + +BOOL testSetTargetROPumpPressureOverride( U32 value ); BOOL testResetTargetROPumpPressureOverride( void ); + BOOL testSetMeasuredROFlowRateOverride( F32 value ); BOOL testResetMeasuredROFlowRateOverride( void ); Index: firmware/App/Controllers/TemperatureSensors.c =================================================================== diff -u -rc1ef106ed0f97dc998230c6e154aa2362aa476d8 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision c1ef106ed0f97dc998230c6e154aa2362aa476d8) +++ firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -118,9 +118,15 @@ static TEMPSENSORS_EXEC_STATES_T tempSensorsExecState; ///< TemperatureSensor exec state. static TEMP_SENSOR_T tempSensors [ NUM_OF_TEMPERATURE_SENSORS ]; ///< Temperature sensors' data structure. + +#define TEMP_SENSORS_DATA_PUBLISH_INTERVAL (500 / TASK_PRIORITY_INTERVAL) ///< Temperature sensors publish data time interval + +// From master static U32 elapsedTime; ///< Elapsed time variable. static U32 internalHeatersConversionTimer; ///< Conversion timer variable to calculate the heaters internal temperature. +// From master + static F32 tempValuesForPublication [ NUM_OF_TEMPERATURE_SENSORS ]; ///< Temperature sensors data publication array. static U32 dataPublicationTimerCounter; ///< Temperature sensors data publish timer counter. static OVERRIDE_U32_T tempSensorsPublishInterval = { TEMP_SENSORS_DATA_PUBLISH_INTERVAL, @@ -712,6 +718,7 @@ { // Look at the error counter and the specific error flag to make sure the error is a temp sensor // Add a byte array to have bits for each sensor to find out exactly what sensor failed + processTempSnsrsADCRead( TEMPSENSORS_INLET_PRIMARY_HEATER, getFPGATPiTemp(), getFPGARTDErrorCount(), getFPGARTDReadCount() ); processTempSnsrsADCRead( TEMPSENSORS_OUTLET_PRIMARY_HEATER, getFPGATPoTemp(), getFPGARTDErrorCount(), getFPGARTDReadCount() ); processTempSnsrsADCRead( TEMPSENSORS_CONDUCTIVITY_SENSOR_1, getFPGACD1Temp(), getFPGARTDErrorCount(), getFPGARTDReadCount() ); Index: firmware/App/DGCommon.h =================================================================== diff -u -r53fae43fd819a81671910ae5c5a019b5d4f145cb -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/DGCommon.h (.../DGCommon.h) (revision 53fae43fd819a81671910ae5c5a019b5d4f145cb) +++ firmware/App/DGCommon.h (.../DGCommon.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -35,6 +35,11 @@ // #define SIMULATE_UI 1 // #define TASK_TIMING_OUTPUT_ENABLED 1 // re-purposes drain pump enable pin for task timing // #define DISABLE_HEATERS_AND_TEMPS 1 + +// #define ENABLE_DIP_SWITCHES 1 +// #define EMC_TEST_BUILD 1 +// #define ALARMS_DEBUG 1 + // #define DISABLE_ACCELS 1 #define SKIP_POST 1 #define ENABLE_DIP_SWITCHES 1 Index: firmware/App/Modes/ModeHeatDisinfect.c =================================================================== diff -u -rc1ef106ed0f97dc998230c6e154aa2362aa476d8 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision c1ef106ed0f97dc998230c6e154aa2362aa476d8) +++ firmware/App/Modes/ModeHeatDisinfect.c (.../ModeHeatDisinfect.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -15,88 +15,1289 @@ * ***************************************************************************/ +#include "Timers.h" #include "ModeHeatDisinfect.h" #include "OperationModes.h" +#include "Valves.h" +#include "Heaters.h" +#include "DrainPump.h" +#include "LoadCell.h" +#include "ROPump.h" +#include "TemperatureSensors.h" +#include "UVReactors.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" #include "Pressures.h" +// TODO control composition pumps +// TODO add code NVDataMgmt regarding heat disinfection +// TODO add logic for water temperature above 85 C + /** * @addtogroup DGHeatDisinfectMode * @{ */ // ********** private definitions ********** +#define HEAT_DISINFECT_TIME_INTERVAL_DAYS 2U ///< Heat disinfect time interval in days //TODO change the interval to actual value (was it every 21 days?) +#define HEAT_DISINFECT_TIME_INTERVAL_SECONDS ( HEAT_DISINFECT_TIME_INTERVAL_DAYS * SECONDS_IN_A_DAY ) ///< Heat disinfect time interval in seconds + +#define HEAT_DISINFECT_TARGET_TEMPERATURE 30U ///< Heat disinfection target temperature //TODO change the target temperature back to 85C +#define MAX_TPO_AND_TDI_SENSORS_DIFFERENCE 1U ///< Maximum allowed temperature difference in between TDi and TPo //TODO remove +#define MAX_TEMPERATURE_DEVIATION_FROM_TARGET 4U ///< Maximum allowed temperature deviation from target temperature + +#define HEAT_DISINFECT_RECIRC_PATH_TIME_MINS 1U ///< Recirculation path heat disinfection duration in minutes +#define HEAT_DISINFECT_R1_TO_R2_TIME_MINS 1U ///< Reservoir 1 to reservoir 2 heat disinfection duration in minutes +#define HEAT_DISINFECT_R2_TO_R1_TIME_MINS 1U ///< Reservoir 2 to reservoir 1 heat disinfection duration in minutes + +#define MINUTES_TO_MS_CONVERSION 60000U ///< Minutes to milliseconds conversion + +#define HEAT_DISINFECT_EVAC_RECIRC_PATH_TIME_MS 4000U ///< Evacuate recirculation path time in ms //TODO do we need this? Change this to the amount of time the composite pumps will run +#define HEAT_DISINFECT_RECIRC_PATH_TIME_MS ( HEAT_DISINFECT_RECIRC_PATH_TIME_MINS * MINUTES_TO_MS_CONVERSION ) ///< Recirculation path heat disinfection duration in ms +#define HEAT_DISINFECT_R1_TO_R2_TIME_MS ( HEAT_DISINFECT_R1_TO_R2_TIME_MINS * MINUTES_TO_MS_CONVERSION ) ///< Reservoir 1 to reservoir 2 heat disinfection duration in ms +#define HEAT_DISINFECT_R2_TO_R1_TIME_MS ( HEAT_DISINFECT_R2_TO_R1_TIME_MINS * MINUTES_TO_MS_CONVERSION ) ///< Reservoir 2 to reservoir 1 heat disinfection duration in ms +#define HEAT_DISINFECT_TARGET_CYCLES 5U ///< No of cycles to run heat disinfection //TODO change this value to the actual value + +#define HEAT_DISINFECT_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Heat disinfection data publication time interval + +#define DRAIN_PUMP_TARGET_DELTA_PRESSURE 0U ///< Drain pump target delta pressure +#define DRAIN_PUMP_EVACUATE_FLUID_TARGET_RPM 2800U ///< Drain pump target RPM during evacuating the fluid path +#define DRAIN_PUMP_DISINFECT_DRAIN_PATH_TARGET_RPM 1500U ///< Drain pump target RPM during heat disinfection +#define RO_PUMP_TARGET_FLOW_RATE_LPM 0.9 ///< RO pump target flow rate + +#define FULL_RESERVOIRS_WEIGHT_GRAMS 500U ///< The weight of a full reservoir //TODO Change this value to full value +#define EMPTY_RESERVOIRS_WEIGHT_GRAMS 300U ///< The weight of an empty reservoir //TODO Change this value to full value + // ********** private data ********** -static DG_HEAT_DISINFECT_STATE_T heatState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state. +/// Heat disinfect evacuate/fill states +typedef enum heat_disinfect_internal_states +{ + INTERNAL_HEAT_DISINFECT_STATE_OFF = 0, ///< Internal heat disinfect state off + INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER, ///< Internal heat disinfect fill with water + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH, ///< Internal heat disinfect evacuate recirculation path + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1, ///< Internal heat disinfect evacuate reservoir 1 + INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_2, ///< Internal heat disinfect evacuate reservoir 2 + INTERNAL_HEAT_DISINFECT_STATE_COMPLETE, ///< Internal heat disinfect complete + NUM_OF_INTERNAL_STATES ///< Number of internal heat disinfect states +} INTERNAL_HEAT_DISINFECT_STATE_T; +static INTERNAL_HEAT_DISINFECT_STATE_T heatDisinfectInternalState = INTERNAL_HEAT_DISINFECT_STATE_OFF; ///< Currently active internal heat disinfect state +static DG_HEAT_DISINFECT_STATE_T heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; ///< Currently active heat disinfect state +static U32 heatDisinfectStartTime = 0; ///< Overall heat disinfection elapsed time +static U32 stateTimer = 0; ///< Timer of an individual state +static U32 drainPumpTargetRPM = 0; ///< Drain pump current target RPM +static U32 heatDisinfectCurrentCycle = 1; ///< Current cycle count of the heat disinfect mode +static U32 heatDisinfectPublishCounter = 0; ///< Current publication counter of heat disinfect mode + +static OVERRIDE_F32_T heatDisinfectRecircDuration = { HEAT_DISINFECT_RECIRC_PATH_TIME_MS, + HEAT_DISINFECT_RECIRC_PATH_TIME_MS, + 0, 0 }; ///< Duration of recirculation path heat disinfeciton + +static OVERRIDE_F32_T heatDisinfectR1ToR2Duration = { HEAT_DISINFECT_R1_TO_R2_TIME_MS, + HEAT_DISINFECT_R1_TO_R2_TIME_MS, + 0, 0 }; ///< Duration of reservoir 1 to reservoir 2 heat disinfection + +static OVERRIDE_F32_T heatDisinfectR2ToR1Duration = { HEAT_DISINFECT_R2_TO_R1_TIME_MS, + HEAT_DISINFECT_R2_TO_R1_TIME_MS, + 0, 0 }; ///< Duration of reservoir 2 to reservoir 1 heat disinfection + +static OVERRIDE_U32_T heatDisinfectNoOfCyclesToRun = { HEAT_DISINFECT_TARGET_CYCLES, + HEAT_DISINFECT_TARGET_CYCLES, + 0, 0 }; ///< Number of cycles to run heat disinfection + +static OVERRIDE_U32_T heatDisinfectDataPublishInterval = { HEAT_DISINFECT_DATA_PUB_INTERVAL, + HEAT_DISINFECT_DATA_PUB_INTERVAL, + 0, 0 }; ///< Heat disinfect mode data publish interval + // ********** private function prototypes ********** +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectOffState( void ); +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterState( void ); +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacRecircPathState( void ); +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisifnectEvacReservoir1State( void ); +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacReservoir2State( void ); + +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStart( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacuateDialysateFillWithWater( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectHeatWater( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRecirculationPath( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectR1ToR2( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectR2ToR1( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainPath( void ); +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterDeprimeReservoirs( void ); + +static void stopActuators( void ); +static void setActuatorsToFillWater( void ); + +static BOOL isTemperatureInRange( void ); +static void execHeatDisinfectInternalStates( void ); +static void publishHeatDisinfectData( void ); +static U32 getPublishHeatDisinfectDataInterval( void ); + +static DATA_GET_PROTOTYPE( U32, getPublishHeatDisinfectDataInterval ); +static DATA_GET_PROTOTYPE( F32, getRecirculationDuration ); +static DATA_GET_PROTOTYPE( F32, getR1ToR2Duration ); +static DATA_GET_PROTOTYPE( F32, getR2ToR1Duration ); +static DATA_GET_PROTOTYPE( U32, getNoOfCyclesToRun ); + /*********************************************************************//** * @brief * The initHeatDisinfectMode function initializes the heat disinfect mode module. * @details - * Inputs : none - * Outputs : Initialized heat disinfect mode module + * Inputs: none + * Outputs: none * @return none *************************************************************************/ void initHeatDisinfectMode( void ) { - heatState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectStartTime = 0; + drainPumpTargetRPM = 0; + heatDisinfectCurrentCycle = 1; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_START; } /*********************************************************************//** * @brief - * The transitionToHeatDisinfectMode function prepares for transition to heat disinfect mode. + * The transitionToHeatDisinfectMode function prepares for transition + * to heat disinfect mode. * @details - * Inputs : none - * Outputs : Prepare for transition to heat disinfect mode + * Inputs: none + * Outputs: none * @return none *************************************************************************/ void transitionToHeatDisinfectMode( void ) { initHeatDisinfectMode(); + stopActuators(); } /*********************************************************************//** * @brief - * The execHeatDisinfectMode function executes the heat disinfect mode state machine. + * The execHeatDisinfectMode function executes the heat disinfect Mode + * state machine. * @details - * Inputs : none - * Outputs : Heat disinfect mode state machine executed - * @return current state + * Inputs: none + * Outputs: none + * @return current state. *************************************************************************/ U32 execHeatDisinfectMode( void ) { - checkInletPressureFault(); + //checkInletPressureFault(); // execute current heat disinfect state - switch ( heatState ) + switch ( heatDisinfectState ) { case DG_HEAT_DISINFECT_STATE_START: + heatDisinfectState = handleHeatDisinfectStart(); break; + case DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER: + heatDisinfectState = handleHeatDisinfectEvacuateDialysateFillWithWater(); + break; + + case DG_HEAT_DISINFECT_STATE_HEAT_WATER: + heatDisinfectState = handleHeatDisinfectHeatWater(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_RECIRC_PATH: + heatDisinfectState = handleHeatDisinfectRecirculationPath(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_1_TO_2: + heatDisinfectState = handleHeatDisinfectR1ToR2(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_2_TO_1: + heatDisinfectState = handleHeatDisinfectR2ToR1(); + break; + + case DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH: + heatDisinfectState = handleHeatDisinfectDrainPath(); + break; + + case DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS: + heatDisinfectState = handleHeatDisinfectFillWithWaterDeprimeReservoirs(); + break; + + case DG_HEAT_DISINFECT_STATE_COMPLETE: + // Do nothing + break; + default: // TODO - s/w fault - heatState = DG_HEAT_DISINFECT_STATE_START; + heatDisinfectState = DG_HEAT_DISINFECT_STATE_COMPLETE; break; } - return heatState; + publishHeatDisinfectData(); + + return (U32)heatDisinfectState; } /*********************************************************************//** * @brief * The getCurrentHeatDisinfectState function returns the current state of the * heat disinfect mode. * @details - * Inputs : heatState - * Outputs : none + * Inputs: heatState + * Outputs: none * @return the current state of heat disinfect mode. *************************************************************************/ DG_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ) { - return heatState; + return heatDisinfectState; } +/*********************************************************************//** + * @brief + * The startDGHeatDisinfect function starts heat disinfect mode. + * @details + * Inputs: none + * Outputs: none + * @return: TRUE if the switch was successful + *************************************************************************/ +BOOL startDGHeatDisinfect( void ) +{ + // TODO: make sure DG is not in the middle of something and it is in standby + requestNewOperationMode( DG_MODE_HEAT ); + + return TRUE; // TODO Check whether it is the right request before switching +} + +/*********************************************************************//** + * @brief + * The stopDGHeatDisinfect function stops heat disinfect mode. + * @details + * Inputs: heatDisinfectionState + * Outputs: heatDisinfectionState + * @return none + *************************************************************************/ +void stopDGHeatDisinfect( void ) +{ + stopActuators(); + requestNewOperationMode( DG_MODE_STAN ); +} + +// ********** private function definitions ********** + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectStart function handles heat disinfect start state + * @details + * Inputs: drainPumpTargetRPM, heatDisinfectInternalState, + * heatDisinfectStartTime + * Outputs: drainPumpTargetRPM, heatDisinfectInternalState, + * heatDisinfectStartTime + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectStart( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER; + + stopActuators(); + drainPumpTargetRPM = DRAIN_PUMP_EVACUATE_FLUID_TARGET_RPM; + heatDisinfectInternalState = INTERNAL_HEAT_DISINFECT_STATE_OFF; + + heatDisinfectStartTime = getMSTimerCount(); + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectEvacuateDialysateFillWithWater function handles \n + * evacuate dialysate and fill with water state + * @details + * Inputs: heatDisinfectInternalState + * Outputs: none + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacuateDialysateFillWithWater( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER; + + execHeatDisinfectInternalStates(); //TODO test to see if it is needed to be in an if statement + + if ( heatDisinfectInternalState == INTERNAL_HEAT_DISINFECT_STATE_COMPLETE ) + { + // Done with evacuation and fill, set the states to heat up water + // Drain pump is stopped to exit the open loop mode + signalDrainPumpHardStop(); + + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NC ); + setValveState ( VRD, VALVE_STATE_R2_C_TO_NC ); + setValveState ( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRF, VALVE_STATE_R2_C_TO_NO ); + + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + setDrainPumpTargetDeltaPressure( DRAIN_PUMP_TARGET_DELTA_PRESSURE ); + + setPrimaryHeaterTargetTemperature( HEAT_DISINFECT_TARGET_TEMPERATURE ); + startPrimaryHeater(); + + state = DG_HEAT_DISINFECT_STATE_HEAT_WATER; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectHeatWater function handles heat water state + * @details + * Inputs: stateTimer + * Outputs: stateTimer + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectHeatWater( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_HEAT_WATER; + + F32 TPi = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + + if ( fabs(TPi - HEAT_DISINFECT_TARGET_TEMPERATURE) <= MAX_TEMPERATURE_DEVIATION_FROM_TARGET && + fabs(TDi - HEAT_DISINFECT_TARGET_TEMPERATURE) <= MAX_TEMPERATURE_DEVIATION_FROM_TARGET ) + { + // Set the states to disinfect recirculation path + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState ( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRF, VALVE_STATE_R2_C_TO_NO ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_RECIRC_PATH; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectRecirculationPath function handles disinfect \n + * recirculate path state + * @details + * Inputs: stateTimer + * Outputs: stateTimer + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectRecirculationPath( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_RECIRC_PATH; + + // If the temperature is out of tolerance, go back to heat water + if ( ! isTemperatureInRange() ) + { + state = DG_HEAT_DISINFECT_STATE_HEAT_WATER; + } + else if ( didTimeout( stateTimer, getRecirculationDuration() ) ) + { + // Set the state for reservoir 1 to reservoir 2 + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState ( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState ( VRF, VALVE_STATE_R1_C_TO_NC ); + + setDrainPumpTargetDeltaPressure( DRAIN_PUMP_TARGET_DELTA_PRESSURE ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_1_TO_2; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectReservoir1To2 function handles disinfect \n + * reservoir 1 to reservoir 2 state + * @details + * Inputs: stateTimer + * Outputs: stateTimer + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectR1ToR2( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_1_TO_2; + + // If the temperature is out of tolerance, go back to heat water + if ( ! isTemperatureInRange() ) + { + state = DG_HEAT_DISINFECT_STATE_HEAT_WATER; + } + else if ( didTimeout( stateTimer, getR1ToR2Duration() ) ) + { + // Set the state for reservoir 1 to reservoir 2 + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState ( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState ( VRF, VALVE_STATE_R1_C_TO_NC ); + + setDrainPumpTargetDeltaPressure( DRAIN_PUMP_TARGET_DELTA_PRESSURE ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_2_TO_1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectReservoir2To1 function handles disinfect \n + * reservoir 2 to reservoir 1 state + * @details + * Inputs: heatDisinfectCurrentCycle, heatDisinfectInternalState, + * drainPumpTargetRPM, stateTimer + * Outputs: heatDisinfectCurrentCycle, heatDisinfectInternalState, + * drainPumpTargetRPM, stateTimer + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectR2ToR1( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_RESERVOIR_2_TO_1; + + // If the temperature is out of tolerance, go back to heat water + if ( ! isTemperatureInRange() ) + { + state = DG_HEAT_DISINFECT_STATE_HEAT_WATER; + } + else if ( didTimeout( stateTimer, getR2ToR1Duration() ) ) + { + // Set the state for reservoir 1 to reservoir 2 + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState ( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState ( VRF, VALVE_STATE_R1_C_TO_NC ); + + setDrainPumpTargetDeltaPressure( DRAIN_PUMP_TARGET_DELTA_PRESSURE ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + + if ( ++heatDisinfectCurrentCycle > getNoOfCyclesToRun() ) + { + drainPumpTargetRPM = DRAIN_PUMP_DISINFECT_DRAIN_PATH_TARGET_RPM; + heatDisinfectInternalState = INTERNAL_HEAT_DISINFECT_STATE_OFF; + state = DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH; + } + else + { + setValveState ( VPI, VALVE_STATE_OPEN ); + setValveState ( VBF, VALVE_STATE_OPEN ); + setValveState ( VSP, VALVE_STATE_CLOSED ); + setValveState ( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState ( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState ( VDR, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRC, VALVE_STATE_RECIRC_C_TO_NC ); + setValveState ( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState ( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState ( VRF, VALVE_STATE_R2_C_TO_NO ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + stateTimer = getMSTimerCount(); + state = DG_HEAT_DISINFECT_STATE_DISINFECT_RECIRC_PATH; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectDrainPath function handles disinfect drain path \n + * state + * @details + * Inputs: drainPumpTargetRPM, heatDisinfectInternalState + * Outputs: drainPumpTargetRPM, heatDisinfectInternalState + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectDrainPath( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH; + + execHeatDisinfectInternalStates(); //TODO test to see if it is needed to be in an if statement + + if ( heatDisinfectInternalState == INTERNAL_HEAT_DISINFECT_STATE_COMPLETE ) + { + drainPumpTargetRPM = DRAIN_PUMP_EVACUATE_FLUID_TARGET_RPM; + heatDisinfectInternalState = INTERNAL_HEAT_DISINFECT_STATE_OFF; + state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFillWithWaterDeprimeReservoirs function handles \n + * fill with water and deprime the reservoirs state + * @details + * Inputs: none + * Outputs: none + * @return next state + *************************************************************************/ +static DG_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterDeprimeReservoirs( void ) +{ + DG_HEAT_DISINFECT_STATE_T state = DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS; + + execHeatDisinfectInternalStates(); //TODO test to see if it is needed to be in an if statement + + // Done with heat disinfect + if ( heatDisinfectInternalState == INTERNAL_HEAT_DISINFECT_STATE_COMPLETE ) + { + state = DG_HEAT_DISINFECT_STATE_COMPLETE; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The execHeatDisinfectInternalStates function executes the heat \n + * disinfection internal state machine + * @details + * Inputs: heatDisinfectInternalState + * Outputs: heatDisinfectInternalState + * @return none + *************************************************************************/ +static void execHeatDisinfectInternalStates( void ) +{ + switch ( heatDisinfectInternalState ) + { + case INTERNAL_HEAT_DISINFECT_STATE_OFF: + heatDisinfectInternalState = handleHeatDisinfectOffState(); + break; + + case INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER: + heatDisinfectInternalState = handleHeatDisinfectFillWithWaterState(); + break; + + case INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH: + heatDisinfectInternalState = handleHeatDisinfectEvacRecircPathState(); + break; + + case INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1: + heatDisinfectInternalState = handleHeatDisifnectEvacReservoir1State(); + break; + + case INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_2: + heatDisinfectInternalState = handleHeatDisinfectEvacReservoir2State(); + break; + + case INTERNAL_HEAT_DISINFECT_STATE_COMPLETE: + // Do nothing + break; + + default: + // TODO add sw fault + heatDisinfectInternalState = INTERNAL_HEAT_DISINFECT_STATE_COMPLETE; + break; + } +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectOffState function handles internal heat disinfect \n + * off state + * @details + * Inputs: heatDisinfectState, stateTimer + * Outputs: stateTimer + * @return next state + *************************************************************************/ +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectOffState( void ) +{ + INTERNAL_HEAT_DISINFECT_STATE_T state = INTERNAL_HEAT_DISINFECT_STATE_OFF; + + // If the state is evacuate dialysate, start with evacuating recirculate path + if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER ) + { + // Set the actuators for evacuate recirculation path + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + stateTimer = getMSTimerCount(); // For evac recirc path. TODO later, it should be controlled using + // the composite pump + + state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH; + } + else if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS ) + { + setActuatorsToFillWater(); + // Start the UV reactors to disinfect the water that + // is being filled up + startInletUVReactor(); + startOutletUVReactor(); + + state = INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + } + else if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH ) + { + // Set the actuators for draining the path + signalROPumpHardStop(); + signalDrainPumpHardStop(); + stopPrimaryHeater(); + stopTrimmerHeater(); + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setDrainPumpTargetSpeed( drainPumpTargetRPM ); + + state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectFillWithWaterState function handles internal \n + * fill with water state + * @details + * Inputs: heatDisinfectState, stateTimer + * Outputs: stateTimer + * @return next state + *************************************************************************/ +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectFillWithWaterState( void ) +{ + INTERNAL_HEAT_DISINFECT_STATE_T state = INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + + F32 reservoir1Weight = getLoadCellFilteredWeight( LOAD_CELL_A1 ); + F32 reservoir2Weight = getLoadCellFilteredWeight( LOAD_CELL_B1 ); + + if ( reservoir1Weight >= FULL_RESERVOIRS_WEIGHT_GRAMS && + reservoir2Weight >= FULL_RESERVOIRS_WEIGHT_GRAMS ) + { + if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER ) + { + stopActuators(); + state = INTERNAL_HEAT_DISINFECT_STATE_COMPLETE; + } + else if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS ) + { + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); + stateTimer = getMSTimerCount(); + + state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectEvacRecircPathState function handles internal \n + * evacuate recirculation path state + * @details + * Inputs: stateTimer, drainPumpTargetRPM + * Outputs: none + * @return next state + *************************************************************************/ +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacRecircPathState( void ) +{ + INTERNAL_HEAT_DISINFECT_STATE_T state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RECIRC_PATH; + + // TODO change this to composition pump mode + if ( didTimeout( stateTimer, HEAT_DISINFECT_EVAC_RECIRC_PATH_TIME_MS ) ) + { + // Set the state to evacuate reservoir 1 + signalROPumpHardStop(); + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setDrainPumpTargetSpeed( drainPumpTargetRPM ); + + state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisifnectEvacReservoir1State function handles internal \n + * evacuate reservoir 1 state + * @details + * Inputs: none + * Outputs: none + * @return next state + *************************************************************************/ +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisifnectEvacReservoir1State( void ) +{ + INTERNAL_HEAT_DISINFECT_STATE_T state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_1; + + F32 reservoir1Weight = getLoadCellFilteredWeight( LOAD_CELL_A1 ); + + if ( reservoir1Weight <= EMPTY_RESERVOIRS_WEIGHT_GRAMS ) + { + // Set the state to evacuate reservoir 2 + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NC ); + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + setDrainPumpTargetSpeed( drainPumpTargetRPM ); //probably it is not needed TODO test this + + state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_2; + } + + return state; +} + +/*********************************************************************//** + * @brief + * The handleHeatDisinfectEvacReservoir2State function handles internal \n + * evacuate reservoir 2 state + * @details + * Inputs: heatDisinfectState + * Outputs: none + * @return next state + *************************************************************************/ +static INTERNAL_HEAT_DISINFECT_STATE_T handleHeatDisinfectEvacReservoir2State( void ) +{ + INTERNAL_HEAT_DISINFECT_STATE_T state = INTERNAL_HEAT_DISINFECT_STATE_EVACUATE_RESERVOIR_2; + + F32 reservoir2Weight = getLoadCellFilteredWeight ( LOAD_CELL_B1 ); + + if ( reservoir2Weight <= EMPTY_RESERVOIRS_WEIGHT_GRAMS ) + { + if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_EVACUATE_DIALYSATE_FILL_WITH_WATER ) + { + setActuatorsToFillWater(); + state = INTERNAL_HEAT_DISINFECT_STATE_FILL_WITH_WATER; + } + else if ( heatDisinfectState == DG_HEAT_DISINFECT_STATE_FILL_WITH_WATER_DEPRIME_RESERVOIRS || + heatDisinfectState == DG_HEAT_DISINFECT_STATE_DISINFECT_DRAIN_PATH ) + { + state = INTERNAL_HEAT_DISINFECT_STATE_COMPLETE; + } + } + + return state; +} + +/*********************************************************************//** + * @brief + * The stopActuators function sets all the actuators in stop and \n + * de-energized state + * @details + * Inputs: none + * Outputs: none + * @return none + *************************************************************************/ +static void stopActuators( void ) +{ + // De-energize all the valves + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_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_R2_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R1_C_TO_NC ); + setValveState( VRI, VALVE_STATE_R1_C_TO_NO ); + setValveState( VRF, VALVE_STATE_R2_C_TO_NO ); + + //TODO composition pumps + signalROPumpHardStop(); + signalDrainPumpHardStop(); + stopInletUVReactor(); + stopOutletUVReactor(); + stopPrimaryHeater(); + stopTrimmerHeater(); +} + +/*********************************************************************//** + * @brief + * The isTemperatureInRange function checks whether the water temperature \n + * is out of range + * @details + * Inputs: none + * Outputs: none + * @return TRUE if the water temperature is still in range + *************************************************************************/ +static BOOL isTemperatureInRange( void ) +{ + BOOL result = FALSE; + F32 TPi = getTemperatureValue( TEMPSENSORS_OUTLET_PRIMARY_HEATER ); + F32 TDi = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); + + if ( fabs(TPi - HEAT_DISINFECT_TARGET_TEMPERATURE) <= MAX_TEMPERATURE_DEVIATION_FROM_TARGET && + fabs(TDi - HEAT_DISINFECT_TARGET_TEMPERATURE) <= MAX_TEMPERATURE_DEVIATION_FROM_TARGET ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The setActuatorsToFillWater function sets the actuators to fill with \n + * water mode + * @details + * Inputs: none + * Outputs: none + * @return none + *************************************************************************/ +static void setActuatorsToFillWater( void ) +{ + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VBF, VALVE_STATE_OPEN ); + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPD, VALVE_STATE_OPEN_C_TO_NO ); + setValveState( VPO, VALVE_STATE_FILL_C_TO_NC ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VRO, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRD, VALVE_STATE_R2_C_TO_NO ); + setValveState( VRI, VALVE_STATE_R2_C_TO_NC ); + setValveState( VRF, VALVE_STATE_R1_C_TO_NC ); + setROPumpTargetFlowRate( RO_PUMP_TARGET_FLOW_RATE_LPM ); +} + +/*********************************************************************//** + * @brief + * The getPublishHeatDisinfectDataInterval function sets the data publish \n + * interval + * @details + * Inputs: heatDisinfectDataPublishInterval + * Outputs: none + * @return result : data publish time interval + *************************************************************************/ +static U32 getPublishHeatDisinfectDataInterval( void ) +{ + U32 result = heatDisinfectDataPublishInterval.data; + + if ( OVERRIDE_KEY == heatDisinfectDataPublishInterval.override ) + { + result = heatDisinfectDataPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishHeatDisinfectData function publishes heat disinfect mode + * @details + * Inputs: heatDisinfectPublishCounter, heatDisinfectCurrentCycle, + * heatDisinfectInternalState + * Outputs: heatDisinfectPublishCounter + * @return none + *************************************************************************/ +static void publishHeatDisinfectData ( void ) +{ + if ( ++heatDisinfectPublishCounter >= getPublishHeatDisinfectDataInterval() ) + { + F32 elapsedtime = calcTimeSince( heatDisinfectStartTime ) / MINUTES_TO_MS_CONVERSION; + broadcastHeatDisinfectData( (U32)heatDisinfectInternalState, elapsedtime, heatDisinfectCurrentCycle ); + heatDisinfectPublishCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The testSetHeatDisinfectDataPublishIntervalOverride function overrides \n + * the data publication interval + * @details + * Inputs: heatDisinfectDataPublishInterval + * Outputs: heatDisinfectDataPublishInterval + * @param: value : The requested value for override + * @return: result : TRUE if override was successful + *************************************************************************/ +BOOL testSetHeatDisinfectDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_GENERAL_INTERVAL; + + result = TRUE; + heatDisinfectDataPublishInterval.ovData = intvl; + heatDisinfectDataPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetHeatDisinfectDataPublishIntervalOverride function \n + * resets the overridden data publication time interval + * @details + * Inputs: heatDisinfectDataPublishInterval + * Outputs: heatDisinfectDataPublishInterval + * @return: result : TRUE if reset was successful + *************************************************************************/ +BOOL testResetHeatDisinfectDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectDataPublishInterval.override = OVERRIDE_RESET; + heatDisinfectDataPublishInterval.ovData = heatDisinfectDataPublishInterval.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetHeatDisinfectRecircDurationOverride function overrides the \n + * duration of the recirculation path heat disinfection in minutes + * @details + * Inputs: heatDisinfectRecircDuration + * Outputs: heatDisinfectRecircDuration + * @param: recircMins : recirculation duration in minutes + * @return: result : TRUE if override was successful + *************************************************************************/ +BOOL testSetHeatDisinfectRecircDurationOverride( F32 recircMins ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + heatDisinfectRecircDuration.ovInitData = heatDisinfectRecircDuration.data; + heatDisinfectRecircDuration.ovData = recircMins * MINUTES_TO_MS_CONVERSION; + heatDisinfectRecircDuration.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetHeatDisinfectRecircDurationOverride function resets the \n + * overridden duration of recirculation path heat disinfection + * @details + * Inputs: heatDisinfectRecircDuration + * Outputs: heatDisinfectRecircDuration + * @return: result : TRUE if reset was successful + *************************************************************************/ +BOOL testResetHeatDisinfectRecircDurationOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectRecircDuration.ovData = heatDisinfectRecircDuration.ovInitData; + heatDisinfectRecircDuration.override = OVERRIDE_RESET; + } + + return result; +} + + /*********************************************************************//** + * @brief + * The testSetHeatDisinfectR1ToR2DurationOverride function overrides\n + * the duration of reservoir 1 to reservoir 2 heat disinfection in minutes + * @details + * Inputs: heatDisinfectR1ToR2Duration + * Outputs: heatDisinfectR1ToR2Duration + * @param: R1ToR2Mins : reservoir 1 to reservoir 2 duration in minutes + * @return: result : TRUE if override was successful + *************************************************************************/ +BOOL testSetHeatDisinfectR1ToR2DurationOverride( F32 R1ToR2Mins ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectR1ToR2Duration.ovInitData = heatDisinfectR1ToR2Duration.data; + heatDisinfectR1ToR2Duration.ovData = R1ToR2Mins * MINUTES_TO_MS_CONVERSION; + heatDisinfectR1ToR2Duration.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetHeatDisinfectR1ToR2DurationOverride function \n + * resets the overridden reservoir 1 to reservoir 2 duration + * @details + * Inputs: heatDisinfectR1ToR2Duration + * Outputs: heatDisinfectR1ToR2Duration + * @return: result : TRUE if reset was successful + *************************************************************************/ +BOOL testResetHeatDisinfectR1ToR2DurationOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectR1ToR2Duration.ovData = heatDisinfectR1ToR2Duration.ovInitData; + heatDisinfectR1ToR2Duration.override = OVERRIDE_RESET; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetHeatDisinfectionR2ToR1DurationOverride function overrides \n + * the duration of reservoir 2 to reservoir 1 heat disinfection in minutes + * Inputs: heatDisinfectR2ToR1Duration + * Outputs: heatDisinfectR2ToR1Duration + * @param: R2ToR1Mins : reservoir 2 to reservoir 1 duration in minutes + * @return: result : TRUE is override was successful + *************************************************************************/ +BOOL testSetHeatDisinfectionR2ToR1DurationOverride( F32 R2ToR1Mins ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectR2ToR1Duration.ovInitData = heatDisinfectR2ToR1Duration.data; + heatDisinfectR2ToR1Duration.ovData = R2ToR1Mins * MINUTES_TO_MS_CONVERSION; + heatDisinfectR2ToR1Duration.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetHeatDisinfectionR2ToR1DurationOverride function \n + * resets the overridden reservoir 2 to reservoir 1 duration + * @details + * Inputs : heatDisinfectR2ToR1Duration + * Outputs : heatDisinfectR2ToR1Duration + * @return result : TRUE if reset was successful + *************************************************************************/ +BOOL testResetHeatDisinfectionR2ToR1DurationOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectR2ToR1Duration.ovData = heatDisinfectR2ToR1Duration.ovInitData; + heatDisinfectR2ToR1Duration.override = OVERRIDE_RESET; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetHeatDisinfectNoOfCyclesOverride function overrides the \n + * number of cycles to run during heat disinfection + * @details + * Inputs: heatDisinfectNoOfCyclesToRun + * Outputs: heatDisinfectNoOfCyclesToRun + * @param: cycles : number of cycles to run heat disinfection + * @return: result : TRUE if override was successful + *************************************************************************/ +BOOL testSetHeatDisinfectNoOfCyclesOverride( U32 cycles ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectNoOfCyclesToRun.ovInitData = heatDisinfectNoOfCyclesToRun.data; + heatDisinfectNoOfCyclesToRun.ovData = cycles; + heatDisinfectNoOfCyclesToRun.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetHeatDisinfectNoOfCyclesOverride function \n + * resets the cycles to run heat disinfection + * @details + * Inputs: heatDisinfectNoOfCyclesToRun + * Outputs: heatDisinfectNoOfCyclesToRun + * @return: result : TRUE if reset was successful + *************************************************************************/ +BOOL testResetHeatDisinfectNoOfCyclesOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + heatDisinfectNoOfCyclesToRun.ovData = heatDisinfectNoOfCyclesToRun.ovInitData; + heatDisinfectNoOfCyclesToRun.override = OVERRIDE_RESET; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getRecirculationDuration function gets the duration of recirculation \n + * path heat disinfection + * @details + * Inputs: heatDisinfectRecircDuration + * Outputs: none + * @return: result : the duration in minutes + *************************************************************************/ +static F32 getRecirculationDuration( void ) +{ + F32 result = heatDisinfectRecircDuration.data; + + if ( OVERRIDE_KEY == heatDisinfectRecircDuration.override ) + { + result = heatDisinfectRecircDuration.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getRSVR1ToRSVR2Duration function gets the duration of reservoir 1 \n + * to reservoir 2 heat disinfection + * @details + * Inputs: heatDisinfectR1ToR2Duration + * Outputs: none + * @return: result : the duration in minutes + *************************************************************************/ +static F32 getR1ToR2Duration( void ) +{ + F32 result = heatDisinfectR1ToR2Duration.data; + + if ( OVERRIDE_KEY == heatDisinfectR1ToR2Duration.override ) + { + result = heatDisinfectR1ToR2Duration.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getRSVR2ToRSVR1Duration function gets the duration of reservoir 2 \n + * to reservoir 1 heat disinfection + * @details + * Inputs: heatDisinfectR2ToR1Duration + * Outputs: none + * @return: result : the duration in minutes + *************************************************************************/ +static F32 getR2ToR1Duration() +{ + F32 result = heatDisinfectR2ToR1Duration.data; + + if ( OVERRIDE_KEY == heatDisinfectR2ToR1Duration.override ) + { + result = heatDisinfectR2ToR1Duration.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getNoOfCyclesToRun function gets the number of cycles to run \n + * heat disinfection + * @details + * Inputs: heatDisinfectNoOfCyclesToRun + * Outputs: none + * @return: result : the no of cycles + *************************************************************************/ +static U32 getNoOfCyclesToRun() +{ + U32 result = heatDisinfectNoOfCyclesToRun.data; + + if ( OVERRIDE_KEY == heatDisinfectNoOfCyclesToRun.override ) + { + result = heatDisinfectNoOfCyclesToRun.ovData; + } + + return result; +} + /**@}*/ Index: firmware/App/Modes/ModeHeatDisinfect.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Modes/ModeHeatDisinfect.h (.../ModeHeatDisinfect.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Modes/ModeHeatDisinfect.h (.../ModeHeatDisinfect.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -23,8 +23,10 @@ /** * @defgroup DGHeatDisinfectMode DGHeatDisinfectMode - * @brief Heat disinfection mode module. Manages the state machine for the heat disinfection mode. * + * @brief Heat disinfection mode module. Manages the state machine for the + * heat disinfect mode. + * * @addtogroup DGHeatDisinfectMode * @{ */ @@ -39,6 +41,24 @@ DG_HEAT_DISINFECT_STATE_T getCurrentHeatDisinfectState( void ); // get the current state of the heat disinfect mode. +BOOL startDGHeatDisinfect( void ); +void stopDGHeatDisinfect( void ); + +BOOL testSetHeatDisinfectDataPublishIntervalOverride( U32 value ); +BOOL testResetHeatDisinfectDataPublishIntervalOverride( void ); + +BOOL testSetHeatDisinfectRecircDurationOverride( F32 recircMins ); +BOOL testResetHeatDisinfectRecircDurationOverride( void ); + +BOOL testSetHeatDisinfectR1ToR2DurationOverride( F32 R1ToR2Mins ); +BOOL testResetHeatDisinfectR1ToR2DurationOverride( void ); + +BOOL testSetHeatDisinfectionR2ToR1DurationOverride( F32 R2ToR1Mins ); +BOOL testResetHeatDisinfectionR2ToR1DurationOverride( void ); + +BOOL testSetHeatDisinfectNoOfCyclesOverride( U32 cycles ); +BOOL testResetHeatDisinfectNoOfCyclesOverride( void ); + /**@}*/ #endif Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -r3e5c98eae83ce4efe2b36031d4e920bbf71fd098 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 3e5c98eae83ce4efe2b36031d4e920bbf71fd098) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -90,9 +90,11 @@ { case DG_POST_STATE_START: postState = DG_POST_STATE_FPGA; -#ifdef SKIP_POST + + // FOR TESTING REMOVE postState = DG_POST_STATE_COMPLETED; -#endif + postPassed = TRUE; + // FOR TESTING REMOVE break; case DG_POST_STATE_FPGA: Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -85,7 +85,7 @@ setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setROPumpTargetPressure( TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); + setROPumpTargetFlowRate( 0.8 ); signalDrainPumpHardStop(); startPrimaryHeater(); // UV on Index: firmware/App/Services/MessagePayloads.h =================================================================== diff -u --- firmware/App/Services/MessagePayloads.h (revision 0) +++ firmware/App/Services/MessagePayloads.h (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -0,0 +1,141 @@ +/************************************************************************** +* +* Copyright (c) 2019-2020 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 MessagePayloads.h +* +* @author (last) Quang Nguyen +* @date (last) 26-Aug-2020 +* +* @author (original) Sean Nash +* @date (original) 29-Jul-2020 +* +***************************************************************************/ + +#ifndef __MESSAGE_PAYLOADS_H__ +#define __MESSAGE_PAYLOADS_H__ + +/** + * @addtogroup SystemCommMessages + * @{ + */ + +// ********** public definitions ********** + +#pragma pack(push,1) + +/// Alarm status struct. +typedef struct +{ + U32 alarmState; ///< Alarm state: 0 = no alarms, 1 = low priority, 2 = medium priority, 3 = high priority + U32 alarmTop; ///< ID of top active alarm + U32 escalatesIn; ///< Seconds before escalating alarm + U32 silenceExpiresIn; ///< Seconds before alarm silence expires + U16 alarmsFlags; ///< Alarm bit flags: 1 = true, 0 = false for each bit +} ALARM_COMP_STATUS_PAYLOAD_T; + +/// DG version struct. +typedef struct +{ + U08 major; ///< DG version major revision + U08 minor; ///< DG version major revision + U08 micro; ///< DG version micro revision + U16 build; ///< DG build version + U08 fpgaId; ///< DG FPGA ID + U08 fpgaMajor; ///< DG FPGA major revision + U08 fpgaMinor; ///< DG FPGA minor revision + U08 fpgaLab; ///< DG FPGA lab revision +} DG_VERSIONS_T; + +/// Treatment time data struct. +typedef struct +{ + U32 treatmentTimePrescribedinSec; ///< Treatment time in seconds + U32 treatmentTimeElapsedinSec; ///< Treatment time elapsed in seconds + U32 treatmentTimeRemaininginSec; ///< Treatment time remaining in seconds +} TREATMENT_TIME_DATA_T; + +/// Loadcell measurements struct. +typedef struct +{ + F32 loadCellA1inGram; ///< Loadcell A1 measurement in gram + F32 loadCellA2inGram; ///< Loadcell A2 measurement in gram + F32 loadCellB1inGram; ///< Loadcell B1 measurement in gram + F32 loadCellB2inGram; ///< Loadcell B2 measurement in gram +} LOAD_CELL_DATA_T; + +/// RO pump data struct. +typedef struct +{ + U32 setROPumpPressure; ///< RO pump pressure set target + F32 measROFlowRate; ///< RO flow rate measurement + F32 roPumpPWM; ///< RO pump pwm + U32 roPumpState; ///< RO pump current state + F32 roPumpTgtPressure; ///< RO pump target pressure +} RO_PUMP_DATA_T; + +/// Drain pump data struct. +typedef struct +{ + U32 setDrainPumpSpeed; ///< Drain pump speed set target + U32 dacValue; ///< Drain pump DAC value + F32 deltaPressure; ///< Drain pump delta pressure + U32 drainPState; ///< Drain pump state +} DRAIN_PUMP_DATA_T; + +/// Pressure data struct. +typedef struct +{ + F32 roPumpInletPressure; ///< RO pump inlet pressure + F32 roPumpOutletPressure; ///< RO pump outlet pressure + F32 drainPumpInletPressure; ///< Drain pump inlet pressure + F32 drainPumpOutletPressure; ///< Drain pump outlet pressure +} PRESSURES_DATA_T; + +/// Conductivity data struct. +typedef struct +{ + F32 roRejectionRatio; ///< RO rejection ratio + F32 cpi; ///< CPi conductivity sensor value + F32 cpo; ///< CPo conductivity sensor value +} CONDUCTIVITY_DATA_T; + +/// Reservoir data struct. +typedef struct +{ + U32 activeReservoir; ///< Active reservoir ID + U32 fillToVolumeMl; ///< Volume target to fill to + U32 drainToVolumeMl; ///< Volume target to drain to +} RESERVOIR_DATA_T; + +/// Target temperature payload struct. +typedef struct +{ + F32 targetPrimaryHeaterTemp; ///< Primary heater set temperature target + F32 targetTrimmerHeaterTemp; ///< Trimmer heater set temperature target +} TARGET_TEMPS_PAYLOAD_T; + +/// Heaters data struct. +typedef struct +{ + U32 mainPrimayHeaterDC; ///< Main primary heater DC + U32 smallPrimaryHeaterDC; ///< Small primary heater DC + U32 trimmerHeaterDC; ///< Trimmer heater DC +} HEATERS_DATA_T; + +/// Accelerometer calibration data struct. +typedef struct +{ + F32 xOffset; ///< Accelerometer calibration x-offset + F32 yOffset; ///< Accelerometer calibration y-offset + F32 zOffset; ///< Accelerometer calibration z-offset +} ACCEL_CAL_PAYLOAD_T; + +#pragma pack(pop) + +/**@}*/ + +#endif Index: firmware/App/Services/PIControllers.c =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -52,7 +52,9 @@ static PI_CONTROLLER_T piControllers[ NUM_OF_PI_CONTROLLERS_IDS ] = { // Kp Ki uMax uMin ref meas err esw esum ctrl { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_RO_PUMP - { 0.0, 0.0, 0.89, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_PRIMARY_HEATER + { 0.0, 0.0, 0.99, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // I_CONTROLLER_ID_RO_PUMP_RAMP_UP + { 0.0, 0.0, 3000, 300, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_DRAIN_PUMP + { 0.0, 0.0, 1.39, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_PRIMARY_HEATER { 0.0, 0.0, 0.50, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } // PI_CONTROLLER_ID_TRIMMER_HEATER }; Index: firmware/App/Services/PIControllers.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -33,10 +33,12 @@ /// Enumeration of PI controllers. typedef enum ControllerList { - PI_CONTROLLER_ID_RO_PUMP = 0, ///< RO Pump controller - PI_CONTROLLER_ID_PRIMARY_HEATER, ///< Primary Heater controller - PI_CONTROLLER_ID_TRIMMER_HEATER, ///< Trimmer Heater controller - NUM_OF_PI_CONTROLLERS_IDS ///< Number of PI controllers + PI_CONTROLLER_ID_RO_PUMP = 0, ///< RO Pump controller. + PI_CONTROLLER_ID_PRIMARY_HEATER, ///< Primary Heater controller. + PI_CONTROLLER_ID_TRIMMER_HEATER, ///< Trimmer Heater controller. + I_CONTROLLER_ID_RO_PUMP_RAMP_UP, ///< RO Pump controller during ramp up time. + PI_CONTROLLER_ID_DRAIN_PUMP, ///< Drain Pump controller. + NUM_OF_PI_CONTROLLERS_IDS ///< Number of PI controllers. } PI_CONTROLLER_ID_T; /// Enumeration of PI controller signals. Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -14,102 +14,102 @@ * @date (original) 05-Nov-2019 * ***************************************************************************/ - -#include // for memcpy() - -#include "can.h" -#include "sci.h" -#include "sys_dma.h" - -#include "SystemComm.h" -#include "Comm.h" -#include "Interrupts.h" -#include "Timers.h" -#include "Utilities.h" -#include "SystemCommMessages.h" - + +#include // for memcpy() + +#include "can.h" +#include "sci.h" +#include "sys_dma.h" + +#include "SystemComm.h" +#include "Comm.h" +#include "Interrupts.h" +#include "Timers.h" +#include "Utilities.h" +#include "SystemCommMessages.h" + /** * @addtogroup SystemComm * @{ */ -// ********** private definitions ********** - -#define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit -#define NUM_OF_CAN_IN_BUFFERS 6 ///< Number of CAN buffers for receiving -#ifndef DEBUG_ENABLED - #define NUM_OF_MSG_IN_BUFFERS 6 ///< Number of Msg buffers for receiving -#else - #define NUM_OF_MSG_IN_BUFFERS 7 - #define SCI1_RECEIVE_DMA_REQUEST 30 - #define SCI1_TRANSMIT_DMA_REQUEST 31 -#endif - -#define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< if transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on +// ********** private definitions ********** + +#define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit +#define NUM_OF_CAN_IN_BUFFERS 6 ///< Number of CAN buffers for receiving +#ifndef DEBUG_ENABLED + #define NUM_OF_MSG_IN_BUFFERS 6 ///< Number of Msg buffers for receiving +#else + #define NUM_OF_MSG_IN_BUFFERS 7 + #define SCI1_RECEIVE_DMA_REQUEST 30 + #define SCI1_TRANSMIT_DMA_REQUEST 31 +#endif + +#define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< if transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on #define MAX_XMIT_RETRIES 5 ///< maximum number of retries on no transmit complete interrupt timeout - + #define HD_COMM_TIMEOUT_IN_MS 2000 ///< HD has not sent any broadcast messages 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 - -#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) ///< maximum time for a Denali message that requires ACK to be ACK'd -#define MSG_NOT_ACKED_MAX_RETRIES 3 ///< maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm -#define PENDING_ACK_LIST_SIZE 25 ///< maximum number of Delanli messages that can be pending ACK at any given time - -#pragma pack(push, 1) -/// Record for transmitted message that is pending acknowledgement from receiver. -typedef struct -{ - BOOL used; ///< Flag indicates whether the pending ACK slot is used or not - U16 seqNo; ///< Sequence number - U16 retries; ///< Retry count - U32 timeStamp; ///< Message time stamp - COMM_BUFFER_T channel; ///< Comm buffer channel - U32 msgSize; ///< Message size - U08 msg[ MAX_ACK_MSG_SIZE ]; ///< Bytes representation of the message -} PENDING_ACK_RECORD_T; - -#pragma pack(pop) - -// ********** private data ********** +#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 -/// Array of out-going CAN buffers. -const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = -{ - COMM_BUFFER_OUT_CAN_DG_ALARM, - COMM_BUFFER_OUT_CAN_DG_2_HD, +#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) ///< maximum time for a Denali message that requires ACK to be ACK'd +#define MSG_NOT_ACKED_MAX_RETRIES 3 ///< maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm +#define PENDING_ACK_LIST_SIZE 25 ///< maximum number of Delanli messages that can be pending ACK at any given time + +#pragma pack(push, 1) + +/// Record for transmitted message that is pending acknowledgement from receiver. +typedef struct +{ + BOOL used; ///< Flag indicates whether the pending ACK slot is used or not + U16 seqNo; ///< Sequence number + U16 retries; ///< Retry count + U32 timeStamp; ///< Message time stamp + COMM_BUFFER_T channel; ///< Comm buffer channel + U32 msgSize; ///< Message size + U08 msg[ MAX_ACK_MSG_SIZE ]; ///< Bytes representation of the message +} PENDING_ACK_RECORD_T; + +#pragma pack(pop) + +// ********** private data ********** + +/// Array of out-going CAN buffers. +const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = +{ + COMM_BUFFER_OUT_CAN_DG_ALARM, + COMM_BUFFER_OUT_CAN_DG_2_HD, COMM_BUFFER_OUT_CAN_DG_BROADCAST, - COMM_BUFFER_OUT_CAN_PC, + COMM_BUFFER_OUT_CAN_PC, COMM_BUFFER_OUT_CAN_DG_2_UI -}; +}; -/// Array of in-coming CAN buffers. -const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = -{ - COMM_BUFFER_IN_CAN_HD_ALARM, - COMM_BUFFER_IN_CAN_UI_ALARM, - COMM_BUFFER_IN_CAN_HD_2_DG, - COMM_BUFFER_IN_CAN_HD_BROADCAST, - COMM_BUFFER_IN_CAN_UI_BROADCAST, - COMM_BUFFER_IN_CAN_PC, -#ifdef DEBUG_ENABLED - COMM_BUFFER_IN_UART_PC -#endif -}; +/// Array of in-coming CAN buffers. +const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = +{ + COMM_BUFFER_IN_CAN_HD_ALARM, + COMM_BUFFER_IN_CAN_UI_ALARM, + COMM_BUFFER_IN_CAN_HD_2_DG, + COMM_BUFFER_IN_CAN_HD_BROADCAST, + COMM_BUFFER_IN_CAN_UI_BROADCAST, + COMM_BUFFER_IN_CAN_PC, +#ifdef DEBUG_ENABLED + COMM_BUFFER_IN_UART_PC +#endif +}; -static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. -static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; ///< Keep channel last packet was sent on CAN bus in case we need to re-send. -static U32 lastCANPacketSentTimeStamp = 0; ///< Keep time last packet sent on CAN bus so we can timeout on transmission attempt. - -static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< list of outgoing messages that are awaiting an ACK - +static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. +static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; ///< Keep channel last packet was sent on CAN bus in case we need to re-send. +static U32 lastCANPacketSentTimeStamp = 0; ///< Keep time last packet sent on CAN bus so we can timeout on transmission attempt. + +static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< list of outgoing messages that are awaiting an ACK + static volatile BOOL dgIsOnlyCANNode = TRUE; ///< flag indicating whether DG is alone on CAN bus. -static U32 canXmitRetryCtr = 0; ///< counter for CAN transmit retries. -static volatile BOOL hdIsCommunicating = FALSE; ///< has HD sent a message since last check -static volatile U32 timeOfLastHDCheckIn = 0; ///< last time we received an HD broadcast - +static U32 canXmitRetryCtr = 0; ///< counter for CAN transmit retries. +static volatile BOOL hdIsCommunicating = FALSE; ///< has HD sent a message since last check +static volatile U32 timeOfLastHDCheckIn = 0; ///< last time we received an HD broadcast + #ifdef DEBUG_ENABLED // debug buffers static U08 pcXmitPacket[ 1024 ]; @@ -119,73 +119,73 @@ static g_dmaCTRL pcDMARecvControlRecord; #endif -// ********** private function prototypes ********** - -static void clearCANXmitBuffers( void ); - -static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); -static U32 transmitNextCANPacket( void ); - -static void processIncomingData( void ); -static S32 parseMessageFromBuffer( U08 *data, U32 len ); -static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ); -static void processReceivedMessages( void ); -static void processReceivedMessage( MESSAGE_T *message ); - -static void checkForCommTimeouts( void ); -static void checkTooManyBadMsgCRCs( void ); - -static BOOL matchACKtoPendingACKList( S16 seqNo ); -static void checkPendingACKList( void ); - +// ********** private function prototypes ********** + +static void clearCANXmitBuffers( void ); + +static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); +static U32 transmitNextCANPacket( void ); + +static void processIncomingData( void ); +static S32 parseMessageFromBuffer( U08 *data, U32 len ); +static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ); +static void processReceivedMessages( void ); +static void processReceivedMessage( MESSAGE_T *message ); + +static void checkForCommTimeouts( void ); +static void checkTooManyBadMsgCRCs( void ); + +static BOOL matchACKtoPendingACKList( S16 seqNo ); +static void checkPendingACKList( void ); + #ifdef DEBUG_ENABLED static void initUARTAndDMA( void ); static U32 transmitNextUARTPacket( void ); #endif -/*********************************************************************//** - * @brief - * The initSystemComm function initializes the SystemComm module. - * @details - * Inputs : none - * Outputs : SystemComm module initialized. - * @return none - *************************************************************************/ -void initSystemComm( void ) -{ - U32 i; - -#ifdef DEBUG_ENABLED - // initialize UART and DMA for PC communication - initUARTAndDMA(); -#endif - +/*********************************************************************//** + * @brief + * The initSystemComm function initializes the SystemComm module. + * @details + * Inputs : none + * Outputs : SystemComm module initialized. + * @return none + *************************************************************************/ +void initSystemComm( void ) +{ + U32 i; + +#ifdef DEBUG_ENABLED + // initialize UART and DMA for PC communication + initUARTAndDMA(); +#endif + // initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); - // initialize pending ACK list - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - pendingAckList[ i ].used = FALSE; - } -} - -/*********************************************************************//** - * @brief - * The isHDCommunicating function determines whether the HD is communicating - * with the DG. - * @details - * Inputs : hdIsCommunicating - * Outputs : none - * @return TRUE if HD has broadcast since last call, FALSE if not - *************************************************************************/ -BOOL isHDCommunicating( void ) -{ - return hdIsCommunicating; + // initialize pending ACK list + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + pendingAckList[ i ].used = FALSE; + } } /*********************************************************************//** * @brief + * The isHDCommunicating function determines whether the HD is communicating + * with the DG. + * @details + * Inputs : hdIsCommunicating + * Outputs : none + * @return TRUE if HD has broadcast since last call, FALSE if not + *************************************************************************/ +BOOL isHDCommunicating( void ) +{ + return hdIsCommunicating; +} + +/*********************************************************************//** + * @brief * The isDGOnlyCANNode function determines whether the DG is the only node * currently on the CAN bus. * @details @@ -196,41 +196,41 @@ BOOL isDGOnlyCANNode( void ) { return dgIsOnlyCANNode; -} - -/*********************************************************************//** - * @brief - * The execSystemCommRx function manages received data from other sub-systems. - * @details - * Inputs : none - * Outputs : Incoming frames processed. - * @return none - *************************************************************************/ -void execSystemCommRx( void ) -{ - // parse messages from comm buffers and queue them - processIncomingData(); - - // process received messages in the queue - processReceivedMessages(); - - // check for sub-system comm timeouts - checkForCommTimeouts(); - - // check ACK list for messages that need to be re-sent because they haven't been ACK'd - checkPendingACKList(); -} - -/*********************************************************************//** - * @brief - * The execSystemCommTx function manages data to be transmitted to other sub-systems. - * @details - * Inputs : none - * Outputs : Next outgoing frame transmitted. - * @return none - *************************************************************************/ -void execSystemCommTx( void ) +} + +/*********************************************************************//** + * @brief + * The execSystemCommRx function manages received data from other sub-systems. + * @details + * Inputs : none + * Outputs : Incoming frames processed. + * @return none + *************************************************************************/ +void execSystemCommRx( void ) { + // parse messages from comm buffers and queue them + processIncomingData(); + + // process received messages in the queue + processReceivedMessages(); + + // check for sub-system comm timeouts + checkForCommTimeouts(); + + // check ACK list for messages that need to be re-sent because they haven't been ACK'd + checkPendingACKList(); +} + +/*********************************************************************//** + * @brief + * The execSystemCommTx function manages data to be transmitted to other sub-systems. + * @details + * Inputs : none + * Outputs : Next outgoing frame transmitted. + * @return none + *************************************************************************/ +void execSystemCommTx( void ) +{ // don't bother with transmitting if no other nodes on CAN bus if ( FALSE == dgIsOnlyCANNode ) { @@ -276,227 +276,227 @@ } // end - are we retrying xmit or are we alone on CAN bus } // end - pending xmit timeout? } // end - transmit in progress or not - } // end - DG not alone on CAN bus - -#ifdef DEBUG_ENABLED - // if UART transmitter is idle, start transmitting any pending packets - if ( FALSE == isSCI1DMATransmitInProgress() ) - { - transmitNextUARTPacket(); - } -#endif -} - -/*********************************************************************//** - * @brief + } // end - DG not alone on CAN bus + +#ifdef DEBUG_ENABLED + // if UART transmitter is idle, start transmitting any pending packets + if ( FALSE == isSCI1DMATransmitInProgress() ) + { + transmitNextUARTPacket(); + } +#endif +} + +/*********************************************************************//** + * @brief * The handleCANMsgInterrupt function handles a CAN message interrupt. This * may have occurred because a CAN packet transmission has completed or - * because a CAN packet has been received. The appropriate handler is called. - * @details - * Inputs : none - * Outputs : message interrupt handled - * @param srcCANBox which CAN message box triggered this interrupt - * @return none - *************************************************************************/ -void handleCANMsgInterrupt( CAN_MESSAGE_BOX_T srcCANBox ) -{ - // message interrupt is for a transmit message box? - if ( TRUE == isCANBoxForXmit( srcCANBox ) ) - { - U32 bytesXmitted = transmitNextCANPacket(); - - if ( 0 == bytesXmitted ) - { - signalCANXmitsCompleted(); - } - } - else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) - { - U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; - - // get CAN packet received on given CAN message box - if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) - { - U32 result = canGetData( canREG1, srcCANBox, data ); - - // if packet retrieved, add to buffer - if ( result != 0 ) - { - // add CAN packet to appropriate comm buffer based on the message box it came in on (s/b same #) - addToCommBuffer( srcCANBox, data, CAN_MESSAGE_PAYLOAD_SIZE ); - } - } - } - else - { - // shouldn't get here - not an active message box - // s/w fault? - } -} - -/*********************************************************************//** - * @brief - * The handleUARTMsgRecvPacketInterrupt function handles a DMA UART receive - * packet completed interrupt. - * @details - * Inputs : none - * Outputs : none - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -void handleUARTMsgRecvPacketInterrupt( void ) -{ - // buffer received packet - addToCommBuffer( COMM_BUFFER_IN_UART_PC, pcRecvPacket, PC_MESSAGE_PACKET_SIZE ); - // prepare to receive next packet - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} -#endif - -/*********************************************************************//** - * @brief - * The handleUARTMsgXmitPacketInterrupt function handles a DMA UART transmit - * packet completed interrupt. - * @details - * Inputs : none - * Outputs : none - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -void handleUARTMsgXmitPacketInterrupt( void ) -{ - U32 bytesXmitted = transmitNextUARTPacket(); - - if ( 0 == bytesXmitted ) - { - signalSCI1XmitsCompleted(); - } -} -#endif - -/*********************************************************************//** - * @brief - * The initUARTAndDMA function initializes the SCI1 peripheral and the DMA - * to go with it for PC communication. - * @details - * Inputs : none - * Outputs : SCI1 and DMA initialized - * @return none - *************************************************************************/ -#ifdef DEBUG_ENABLED -static void initUARTAndDMA( void ) -{ - // Enable DMA block transfer complete interrupts - dmaEnableInterrupt( DMA_CH1, BTC ); - dmaEnableInterrupt( DMA_CH3, BTC ); - // assign DMA channels to h/w DMA requests - dmaReqAssign( DMA_CH1, SCI1_RECEIVE_DMA_REQUEST ); - dmaReqAssign( DMA_CH3, SCI1_TRANSMIT_DMA_REQUEST ); - // set DMA channel priorities - dmaSetPriority( DMA_CH1, HIGHPRIORITY ); - dmaSetPriority( DMA_CH3, LOWPRIORITY ); - - // initialize PC DMA Transmit Control Record - pcDMAXmitControlRecord.PORTASGN = 4; // port B (only choice per datasheet) - pcDMAXmitControlRecord.DADD = (U32)(&(sciREG->TD)); // dest. is SCI2 xmit register - pcDMAXmitControlRecord.SADD = (U32)pcXmitPacket; // source - pcDMAXmitControlRecord.CHCTRL = 0; // no chaining - pcDMAXmitControlRecord.ELCNT = 1; // frame is 1 element - pcDMAXmitControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames - pcDMAXmitControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte - pcDMAXmitControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMAXmitControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer - pcDMAXmitControlRecord.ADDMODEWR = ADDR_FIXED; // dest. addressing mode is fixed - pcDMAXmitControlRecord.ADDMODERD = ADDR_INC1; // source addressing mode is post-increment - pcDMAXmitControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off - pcDMAXmitControlRecord.ELSOFFSET = 0; // not used - pcDMAXmitControlRecord.ELDOFFSET = 0; // not used - pcDMAXmitControlRecord.FRSOFFSET = 0; // not used - pcDMAXmitControlRecord.FRDOFFSET = 0; // not used - - // initialize PC DMA Receipt Control Record - pcDMARecvControlRecord.PORTASGN = 4; // port B (only choice per datasheet) - pcDMARecvControlRecord.SADD = (U32)(&(sciREG->RD)); // source is SCI2 recv register - pcDMARecvControlRecord.DADD = (U32)pcRecvPacket; // transfer destination address - pcDMARecvControlRecord.CHCTRL = 0; // no chaining - pcDMARecvControlRecord.ELCNT = 1; // frame is 1 element - pcDMARecvControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames - pcDMARecvControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte - pcDMARecvControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMARecvControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer - pcDMARecvControlRecord.ADDMODERD = ADDR_FIXED; // source addressing mode is fixed - pcDMARecvControlRecord.ADDMODEWR = ADDR_INC1; // dest. addressing mode is post-increment - pcDMARecvControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off - pcDMARecvControlRecord.ELDOFFSET = 0; // not used - pcDMARecvControlRecord.ELSOFFSET = 0; // not used - pcDMARecvControlRecord.FRDOFFSET = 0; // not used - pcDMARecvControlRecord.FRSOFFSET = 0; // not used - - // initiate PC packet receiving readiness via DMA - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} -#endif - -/*********************************************************************//** - * @brief - * The isCANBoxForXmit function determines whether a given CAN message box - * is configured for transmit. - * @details - * Inputs : CAN_OUT_BUFFERS[] - * Outputs : none - * @param srcCANBox which CAN message box to check - * @return TRUE if the given CAN message box is configured for transmit, FALSE if not. - *************************************************************************/ -BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ) -{ - BOOL result = FALSE; - U32 i; - - for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) - { - if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) - { - result = TRUE; - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The isCANBoxForRecv function determines whether a given CAN message box - * is configured for receiving. - * @details - * Inputs : MSG_IN_BUFFERS[] - * Outputs : none - * @param srcCANBox which CAN message box to check - * @return TRUE if the given CAN message box is configured for receiving, FALSE if not. - *************************************************************************/ -BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ) -{ - BOOL result = FALSE; - U32 i; - - for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) - { - if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) - { - result = TRUE; - break; - } - } - - return result; + * because a CAN packet has been received. The appropriate handler is called. + * @details + * Inputs : none + * Outputs : message interrupt handled + * @param srcCANBox which CAN message box triggered this interrupt + * @return none + *************************************************************************/ +void handleCANMsgInterrupt( CAN_MESSAGE_BOX_T srcCANBox ) +{ + // message interrupt is for a transmit message box? + if ( TRUE == isCANBoxForXmit( srcCANBox ) ) + { + U32 bytesXmitted = transmitNextCANPacket(); + + if ( 0 == bytesXmitted ) + { + signalCANXmitsCompleted(); + } + } + else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) + { + U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; + + // get CAN packet received on given CAN message box + if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) + { + U32 result = canGetData( canREG1, srcCANBox, data ); + + // if packet retrieved, add to buffer + if ( result != 0 ) + { + // add CAN packet to appropriate comm buffer based on the message box it came in on (s/b same #) + addToCommBuffer( srcCANBox, data, CAN_MESSAGE_PAYLOAD_SIZE ); + } + } + } + else + { + // shouldn't get here - not an active message box + // s/w fault? + } } /*********************************************************************//** * @brief + * The handleUARTMsgRecvPacketInterrupt function handles a DMA UART receive + * packet completed interrupt. + * @details + * Inputs : none + * Outputs : none + * @return none + *************************************************************************/ +#ifdef DEBUG_ENABLED +void handleUARTMsgRecvPacketInterrupt( void ) +{ + // buffer received packet + addToCommBuffer( COMM_BUFFER_IN_UART_PC, pcRecvPacket, PC_MESSAGE_PACKET_SIZE ); + // prepare to receive next packet + dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); + dmaSetChEnable( DMA_CH1, DMA_HW ); + setSCI1DMAReceiveInterrupt(); +} +#endif + +/*********************************************************************//** + * @brief + * The handleUARTMsgXmitPacketInterrupt function handles a DMA UART transmit + * packet completed interrupt. + * @details + * Inputs : none + * Outputs : none + * @return none + *************************************************************************/ +#ifdef DEBUG_ENABLED +void handleUARTMsgXmitPacketInterrupt( void ) +{ + U32 bytesXmitted = transmitNextUARTPacket(); + + if ( 0 == bytesXmitted ) + { + signalSCI1XmitsCompleted(); + } +} +#endif + +/*********************************************************************//** + * @brief + * The initUARTAndDMA function initializes the SCI1 peripheral and the DMA + * to go with it for PC communication. + * @details + * Inputs : none + * Outputs : SCI1 and DMA initialized + * @return none + *************************************************************************/ +#ifdef DEBUG_ENABLED +static void initUARTAndDMA( void ) +{ + // Enable DMA block transfer complete interrupts + dmaEnableInterrupt( DMA_CH1, BTC ); + dmaEnableInterrupt( DMA_CH3, BTC ); + // assign DMA channels to h/w DMA requests + dmaReqAssign( DMA_CH1, SCI1_RECEIVE_DMA_REQUEST ); + dmaReqAssign( DMA_CH3, SCI1_TRANSMIT_DMA_REQUEST ); + // set DMA channel priorities + dmaSetPriority( DMA_CH1, HIGHPRIORITY ); + dmaSetPriority( DMA_CH3, LOWPRIORITY ); + + // initialize PC DMA Transmit Control Record + pcDMAXmitControlRecord.PORTASGN = 4; // port B (only choice per datasheet) + pcDMAXmitControlRecord.DADD = (U32)(&(sciREG->TD)); // dest. is SCI2 xmit register + pcDMAXmitControlRecord.SADD = (U32)pcXmitPacket; // source + pcDMAXmitControlRecord.CHCTRL = 0; // no chaining + pcDMAXmitControlRecord.ELCNT = 1; // frame is 1 element + pcDMAXmitControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames + pcDMAXmitControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte + pcDMAXmitControlRecord.WRSIZE = ACCESS_8_BIT; // + pcDMAXmitControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer + pcDMAXmitControlRecord.ADDMODEWR = ADDR_FIXED; // dest. addressing mode is fixed + pcDMAXmitControlRecord.ADDMODERD = ADDR_INC1; // source addressing mode is post-increment + pcDMAXmitControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off + pcDMAXmitControlRecord.ELSOFFSET = 0; // not used + pcDMAXmitControlRecord.ELDOFFSET = 0; // not used + pcDMAXmitControlRecord.FRSOFFSET = 0; // not used + pcDMAXmitControlRecord.FRDOFFSET = 0; // not used + + // initialize PC DMA Receipt Control Record + pcDMARecvControlRecord.PORTASGN = 4; // port B (only choice per datasheet) + pcDMARecvControlRecord.SADD = (U32)(&(sciREG->RD)); // source is SCI2 recv register + pcDMARecvControlRecord.DADD = (U32)pcRecvPacket; // transfer destination address + pcDMARecvControlRecord.CHCTRL = 0; // no chaining + pcDMARecvControlRecord.ELCNT = 1; // frame is 1 element + pcDMARecvControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames + pcDMARecvControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte + pcDMARecvControlRecord.WRSIZE = ACCESS_8_BIT; // + pcDMARecvControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer + pcDMARecvControlRecord.ADDMODERD = ADDR_FIXED; // source addressing mode is fixed + pcDMARecvControlRecord.ADDMODEWR = ADDR_INC1; // dest. addressing mode is post-increment + pcDMARecvControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off + pcDMARecvControlRecord.ELDOFFSET = 0; // not used + pcDMARecvControlRecord.ELSOFFSET = 0; // not used + pcDMARecvControlRecord.FRDOFFSET = 0; // not used + pcDMARecvControlRecord.FRSOFFSET = 0; // not used + + // initiate PC packet receiving readiness via DMA + dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); + dmaSetChEnable( DMA_CH1, DMA_HW ); + setSCI1DMAReceiveInterrupt(); +} +#endif + +/*********************************************************************//** + * @brief + * The isCANBoxForXmit function determines whether a given CAN message box + * is configured for transmit. + * @details + * Inputs : CAN_OUT_BUFFERS[] + * Outputs : none + * @param srcCANBox which CAN message box to check + * @return TRUE if the given CAN message box is configured for transmit, FALSE if not. + *************************************************************************/ +BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ) +{ + BOOL result = FALSE; + U32 i; + + for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) + { + if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) + { + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isCANBoxForRecv function determines whether a given CAN message box + * is configured for receiving. + * @details + * Inputs : MSG_IN_BUFFERS[] + * Outputs : none + * @param srcCANBox which CAN message box to check + * @return TRUE if the given CAN message box is configured for receiving, FALSE if not. + *************************************************************************/ +BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ) +{ + BOOL result = FALSE; + U32 i; + + for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) + { + if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) + { + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The clearCANXmitBuffers function clears all CAN transmit buffers. * @details * Inputs : CAN_OUT_BUFFERS[] @@ -511,378 +511,378 @@ { clearBuffer( CAN_OUT_BUFFERS[ i ] ); } -} - - -/************************************************************************* -********************** TRANSMIT SUPPORT FUNCTIONS ************************ -*************************************************************************/ - -/*********************************************************************//** - * @brief - * The findNextHighestPriorityCANPacketToTransmit function gets the next - * 8 byte packet and initiates a CAN transmit on the appropriate CAN channel. - * @details - * Inputs : Output CAN Comm Buffer(s) - * Outputs : none - * @return buffer with highest priority CAN packet to transmit, - * COMM_BUFFER_NOT_USED if not CAN packets pending transmit found - *************************************************************************/ -static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ) -{ - COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; - U32 i; - - // search for next priority CAN packet to transmit - for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) - { - if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) - { - result = CAN_OUT_BUFFERS[ i ]; - break; // found highest priority packet to transmit - we're done - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The transmitNextCANPacket function gets the next 8 byte packet and initiates - * a CAN transmit on the appropriate CAN channel. - * @details - * Inputs : Output CAN Comm Buffers - * Outputs : CAN packet transmit initiated. - * @return number of bytes transmitted - *************************************************************************/ -static U32 transmitNextCANPacket( void ) -{ - U32 result = 0; - COMM_BUFFER_T buffer = findNextHighestPriorityCANPacketToTransmit(); - - // if a buffer is found with a packet to transmit, get packet from buffer and transmit it - if ( buffer != COMM_BUFFER_NOT_USED ) - { - U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; - U32 dataSize = getFromCommBuffer( buffer, data, CAN_MESSAGE_PAYLOAD_SIZE ); - CAN_MESSAGE_BOX_T mBox = buffer; // CAN message boxes and comm buffers are aligned - - // if there's another CAN packet to send, send it - if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) - { - // we're transmitting another packet - signal transmitter is busy - signalCANXmitsInitiated(); - // remember packet data being transmitted here in case transmission fails and we need to re-send - memcpy( lastCANPacketSent, data, CAN_MESSAGE_PAYLOAD_SIZE ); - lastCANPacketSentChannel = mBox; - lastCANPacketSentTimeStamp = getMSTimerCount(); - if ( 0 != canTransmit( canREG1, mBox, data ) ) - { - result = CAN_MESSAGE_PAYLOAD_SIZE; - } - else - { - signalCANXmitsCompleted(); - // TODO - shouldn't get here, but let's see if we do - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)mBox ) - } - } - else - { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The transmitNextUARTPacket function sets up and initiates a DMA transmit - * of the next packet pending transmit (if any) via UART. - * @details - * Inputs : Output UART Comm Buffer(s) - * Outputs : UART DMA transmit initiated. - * @return number of bytes transmitted - *************************************************************************/ -#ifdef DEBUG_ENABLED -static U32 transmitNextUARTPacket( void ) -{ - U32 result = 0; - U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); - - if ( dataPend > 0 ) - { - result = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, dataPend ); - - // if there's data to transmit, transmit it - if ( result > 0 ) - { - signalSCI1XmitsInitiated(); - pcDMAXmitControlRecord.FRCNT = result; // set DMA transfer size - dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); - dmaSetChEnable( DMA_CH3, DMA_HW ); - setSCI1DMATransmitInterrupt(); - } - } - - return result; -} -#endif - - -/************************************************************************* -********************** RECEIVE SUPPORT FUNCTIONS ************************* -*************************************************************************/ - -/*********************************************************************//** - * @brief - * The processIncomingData function parses out messages from the input - * comm buffers and adds them to the received message queue. - * @details - * Inputs : Input Comm Buffers - * Outputs : Parsed message(s) added to received message queue - * @return none - *************************************************************************/ -static void processIncomingData( void ) -{ - U08 data[ 512 ]; // message work space - U32 i; - BOOL badCRCDetected = FALSE; - - // queue any received messages - for ( i = 0; i < NUM_OF_MSG_IN_BUFFERS; i++ ) - { - BOOL messagesInBuffer = TRUE; // assume true at first to get into while loop - - while ( TRUE == messagesInBuffer ) - { - U32 numOfBytesInBuffer; - - // assume false so we don't get stuck in loop - only set to true if we find another complete message in buffer - messagesInBuffer = FALSE; - - // since messages can have 8-byte alignment padding left unconsumed by last get, get padding out of buffer - consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); - // do we have enough bytes in buffer for smallest message? - numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[ i ] ); - if ( numOfBytesInBuffer >= MESSAGE_OVERHEAD_SIZE ) - { // peek at minimum of all bytes available or max message size (+1 for sync byte) - U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); - S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); - +} + + +/************************************************************************* +********************** TRANSMIT SUPPORT FUNCTIONS ************************ +*************************************************************************/ + +/*********************************************************************//** + * @brief + * The findNextHighestPriorityCANPacketToTransmit function gets the next + * 8 byte packet and initiates a CAN transmit on the appropriate CAN channel. + * @details + * Inputs : Output CAN Comm Buffer(s) + * Outputs : none + * @return buffer with highest priority CAN packet to transmit, + * COMM_BUFFER_NOT_USED if not CAN packets pending transmit found + *************************************************************************/ +static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ) +{ + COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; + U32 i; + + // search for next priority CAN packet to transmit + for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) + { + if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) + { + result = CAN_OUT_BUFFERS[ i ]; + break; // found highest priority packet to transmit - we're done + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The transmitNextCANPacket function gets the next 8 byte packet and initiates + * a CAN transmit on the appropriate CAN channel. + * @details + * Inputs : Output CAN Comm Buffers + * Outputs : CAN packet transmit initiated. + * @return number of bytes transmitted + *************************************************************************/ +static U32 transmitNextCANPacket( void ) +{ + U32 result = 0; + COMM_BUFFER_T buffer = findNextHighestPriorityCANPacketToTransmit(); + + // if a buffer is found with a packet to transmit, get packet from buffer and transmit it + if ( buffer != COMM_BUFFER_NOT_USED ) + { + U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; + U32 dataSize = getFromCommBuffer( buffer, data, CAN_MESSAGE_PAYLOAD_SIZE ); + CAN_MESSAGE_BOX_T mBox = buffer; // CAN message boxes and comm buffers are aligned + + // if there's another CAN packet to send, send it + if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) + { + // we're transmitting another packet - signal transmitter is busy + signalCANXmitsInitiated(); + // remember packet data being transmitted here in case transmission fails and we need to re-send + memcpy( lastCANPacketSent, data, CAN_MESSAGE_PAYLOAD_SIZE ); + lastCANPacketSentChannel = mBox; + lastCANPacketSentTimeStamp = getMSTimerCount(); + if ( 0 != canTransmit( canREG1, mBox, data ) ) + { + result = CAN_MESSAGE_PAYLOAD_SIZE; + } + else + { + signalCANXmitsCompleted(); + // TODO - shouldn't get here, but let's see if we do + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)mBox ) + } + } + else + { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The transmitNextUARTPacket function sets up and initiates a DMA transmit + * of the next packet pending transmit (if any) via UART. + * @details + * Inputs : Output UART Comm Buffer(s) + * Outputs : UART DMA transmit initiated. + * @return number of bytes transmitted + *************************************************************************/ +#ifdef DEBUG_ENABLED +static U32 transmitNextUARTPacket( void ) +{ + U32 result = 0; + U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); + + if ( dataPend > 0 ) + { + result = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, dataPend ); + + // if there's data to transmit, transmit it + if ( result > 0 ) + { + signalSCI1XmitsInitiated(); + pcDMAXmitControlRecord.FRCNT = result; // set DMA transfer size + dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); + dmaSetChEnable( DMA_CH3, DMA_HW ); + setSCI1DMATransmitInterrupt(); + } + } + + return result; +} +#endif + + +/************************************************************************* +********************** RECEIVE SUPPORT FUNCTIONS ************************* +*************************************************************************/ + +/*********************************************************************//** + * @brief + * The processIncomingData function parses out messages from the input + * comm buffers and adds them to the received message queue. + * @details + * Inputs : Input Comm Buffers + * Outputs : Parsed message(s) added to received message queue + * @return none + *************************************************************************/ +static void processIncomingData( void ) +{ + U08 data[ 512 ]; // message work space + U32 i; + BOOL badCRCDetected = FALSE; + + // queue any received messages + for ( i = 0; i < NUM_OF_MSG_IN_BUFFERS; i++ ) + { + BOOL messagesInBuffer = TRUE; // assume true at first to get into while loop + + while ( TRUE == messagesInBuffer ) + { + U32 numOfBytesInBuffer; + + // assume false so we don't get stuck in loop - only set to true if we find another complete message in buffer + messagesInBuffer = FALSE; + + // since messages can have 8-byte alignment padding left unconsumed by last get, get padding out of buffer + consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); + // do we have enough bytes in buffer for smallest message? + numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[ i ] ); + if ( numOfBytesInBuffer >= MESSAGE_OVERHEAD_SIZE ) + { // peek at minimum of all bytes available or max message size (+1 for sync byte) + U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); + S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); + dgIsOnlyCANNode = FALSE; // if we're getting a message, we can't be alone canXmitRetryCtr = 0; - if ( msgSize > 0 ) // valid, complete message found? - { - MESSAGE_WRAPPER_T rcvMsg; - U08 *dataPtr = data+1; // skip over sync byte - - // consume message (+sync byte) - msgSize = getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, msgSize + 1 ); - // convert received message data to a message and add to message queue - messagesInBuffer = TRUE; // keep processing this buffer - // blank the new message record - blankMessageInWrapper( &rcvMsg ); - // copy message header portion of message data to the new message - memcpy( &(rcvMsg.msg.hdr), dataPtr, sizeof(MESSAGE_HEADER_T) ); - dataPtr += sizeof(MESSAGE_HEADER_T); - // copy message payload portion of message data to the new message - memcpy( &(rcvMsg.msg.payload), dataPtr, rcvMsg.msg.hdr.payloadLen ); - dataPtr += rcvMsg.msg.hdr.payloadLen; - // copy CRC portion of message data to the new message - rcvMsg.crc = *dataPtr; - // add new message to queue for later processing - addToMsgQueue( MSG_Q_IN, &rcvMsg ); - // if message from HD broadcast channel, update HD comm status - if ( COMM_BUFFER_IN_CAN_HD_BROADCAST == MSG_IN_BUFFERS[ i ] ) - { + if ( msgSize > 0 ) // valid, complete message found? + { + MESSAGE_WRAPPER_T rcvMsg; + U08 *dataPtr = data+1; // skip over sync byte + + // consume message (+sync byte) + msgSize = getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, msgSize + 1 ); + // convert received message data to a message and add to message queue + messagesInBuffer = TRUE; // keep processing this buffer + // blank the new message record + blankMessageInWrapper( &rcvMsg ); + // copy message header portion of message data to the new message + memcpy( &(rcvMsg.msg.hdr), dataPtr, sizeof(MESSAGE_HEADER_T) ); + dataPtr += sizeof(MESSAGE_HEADER_T); + // copy message payload portion of message data to the new message + memcpy( &(rcvMsg.msg.payload), dataPtr, rcvMsg.msg.hdr.payloadLen ); + dataPtr += rcvMsg.msg.hdr.payloadLen; + // copy CRC portion of message data to the new message + rcvMsg.crc = *dataPtr; + // add new message to queue for later processing + addToMsgQueue( MSG_Q_IN, &rcvMsg ); + // if message from HD broadcast channel, update HD comm status + if ( COMM_BUFFER_IN_CAN_HD_BROADCAST == MSG_IN_BUFFERS[ i ] ) + { hdIsCommunicating = TRUE; - timeOfLastHDCheckIn = getMSTimerCount(); - } - } - else if ( -1 == msgSize ) // candidate message with bad CRC found? - { - badCRCDetected = TRUE; - getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, 1 ); // consume sync byte so we can re-sync - messagesInBuffer = TRUE; // keep processing this buffer - } // looks like there is a complete message in the comm buffer - } // enough data left in comm buffer to possibly be a complete message - } // while loop to get all complete messages for each comm buffer - } // for loop to check all comm buffers for messages - - // if any bad CRCs detected, see if too many - if ( TRUE == badCRCDetected ) - { - checkTooManyBadMsgCRCs(); - } -} - -/*********************************************************************//** - * @brief - * The consumeBufferPaddingBeforeSync function removes any bytes in a given - * buffer that lie before a sync byte. - * @details - * Inputs : none - * Outputs : Any padding at front of comm buffer is consumed. - * @param buffer the comm buffer to process - * @return none - *************************************************************************/ -static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ) -{ - U08 data; - U32 numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); - - // consume bytes out of buffer 1 at a time until we find the sync byte or it's empty - while ( numOfBytesInBuffer > 0 ) - { - peekFromCommBuffer( buffer, &data, 1 ); - if ( MESSAGE_SYNC_BYTE == data ) - { - break; // we found a sync - we're done - } - else // not a sync byte, so consume it - { - getFromCommBuffer( buffer, &data, 1 ); - numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); - } - } -} - -/*********************************************************************//** - * @brief - * The parseMessageFromBuffer function looks for a complete message in a - * given buffer. If a message is found, its size is returned. - * @details - * Inputs : none - * Outputs : If a complete message can be found in buffer contents, it is parsed out. - * @param data pointer to byte array to search for a message - * @param len number of bytes in the data to search - * @return size of message if found, zero if no complete message found, - * -1 if message found but CRC fails. - *************************************************************************/ -static S32 parseMessageFromBuffer( U08 *data, U32 len ) -{ - U32 i; - U32 payloadSize; - U32 msgSize; - S32 result = 0; - - for ( i = 0; i < len; i++ ) - { - // find sync byte - if ( MESSAGE_SYNC_BYTE == data[ i ] ) - { - U32 pos = i + 1; // skip past sync byte implemented - U32 remSize = len - pos; - - // if a minimum sized msg would fit in remaining, continue - if ( remSize >= MESSAGE_OVERHEAD_SIZE ) - { - payloadSize = data[ pos + sizeof(MESSAGE_HEADER_T) - sizeof(U08) ]; - msgSize = MESSAGE_OVERHEAD_SIZE + payloadSize; - // we now know the size of the message - we can now know if full message is contained in buffer - if ( msgSize <= remSize ) - { // check CRC to make sure it's a valid message - if ( data[i+msgSize] == crc8( &data[pos], msgSize - 1 ) ) - { - result = msgSize; // we found a complete, valid message of this size - } - else // CRC failed - { - result = -1; // we found a complete, invalid message - } - } - } - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The processReceivedMessages function processes any messages in the - * received message queues. - * @details - * Inputs : Received Message Queues - * Outputs : Message(s) processed. - * @return none - *************************************************************************/ -static void processReceivedMessages( void ) -{ - BOOL isThereMsgRcvd = TRUE; // assume TRUE at first to get into while loop - MESSAGE_WRAPPER_T message; - - while ( TRUE == isThereMsgRcvd ) - { - // see if any messages received - isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); - if ( TRUE == isThereMsgRcvd ) - { // CRC should be good because we checked it during parsing before adding to queue - but check it again for good measure - if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) - { - // if ACK, mark pending message ACK'd - if ( MSG_ID_ACK == message.msg.hdr.msgID ) - { - matchACKtoPendingACKList( message.msg.hdr.seqNo ); - } - else - { - // if received message requires ACK, queue one up - if ( message.msg.hdr.seqNo < 0 ) - { - sendACKMsg( &message.msg ); - } - // otherwise, process the received message - processReceivedMessage( &message.msg ); - } - } - else // CRC failed - { - checkTooManyBadMsgCRCs(); - } - } - } -} - -/*********************************************************************//** - * @brief - * The checkForCommTimeouts function checks for sub-system communication timeout errors. - * @details - * Inputs : timeOfLastDGCheckIn, timeOfLastUICheckIn - * Outputs : possibly a comm t/o alarm - * @return none - *************************************************************************/ -static void checkForCommTimeouts( void ) -{ - if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) - { - hdIsCommunicating = FALSE; -#ifndef DEBUG_ENABLED - activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm if we're in middle of a treatment? or if in a mode that comm loss would impact badly? -#endif - } -} - -/*********************************************************************//** - * @brief - * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs - * within a set period of time. Assumed function is being called when a new - * bad CRC is detected so a new bad CRC will be added to the list. - * @details - * Inputs : badCRCTimeStamps[], badCRCListIdx, badCRCListCount - * Outputs : possibly a "too many bad CRCs" alarm - * @return none - *************************************************************************/ -static void checkTooManyBadMsgCRCs( void ) + timeOfLastHDCheckIn = getMSTimerCount(); + } + } + else if ( -1 == msgSize ) // candidate message with bad CRC found? + { + badCRCDetected = TRUE; + getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, 1 ); // consume sync byte so we can re-sync + messagesInBuffer = TRUE; // keep processing this buffer + } // looks like there is a complete message in the comm buffer + } // enough data left in comm buffer to possibly be a complete message + } // while loop to get all complete messages for each comm buffer + } // for loop to check all comm buffers for messages + + // if any bad CRCs detected, see if too many + if ( TRUE == badCRCDetected ) + { + checkTooManyBadMsgCRCs(); + } +} + +/*********************************************************************//** + * @brief + * The consumeBufferPaddingBeforeSync function removes any bytes in a given + * buffer that lie before a sync byte. + * @details + * Inputs : none + * Outputs : Any padding at front of comm buffer is consumed. + * @param buffer the comm buffer to process + * @return none + *************************************************************************/ +static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ) { + U08 data; + U32 numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); + + // consume bytes out of buffer 1 at a time until we find the sync byte or it's empty + while ( numOfBytesInBuffer > 0 ) + { + peekFromCommBuffer( buffer, &data, 1 ); + if ( MESSAGE_SYNC_BYTE == data ) + { + break; // we found a sync - we're done + } + else // not a sync byte, so consume it + { + getFromCommBuffer( buffer, &data, 1 ); + numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); + } + } +} + +/*********************************************************************//** + * @brief + * The parseMessageFromBuffer function looks for a complete message in a + * given buffer. If a message is found, its size is returned. + * @details + * Inputs : none + * Outputs : If a complete message can be found in buffer contents, it is parsed out. + * @param data pointer to byte array to search for a message + * @param len number of bytes in the data to search + * @return size of message if found, zero if no complete message found, + * -1 if message found but CRC fails. + *************************************************************************/ +static S32 parseMessageFromBuffer( U08 *data, U32 len ) +{ + U32 i; + U32 payloadSize; + U32 msgSize; + S32 result = 0; + + for ( i = 0; i < len; i++ ) + { + // find sync byte + if ( MESSAGE_SYNC_BYTE == data[ i ] ) + { + U32 pos = i + 1; // skip past sync byte implemented + U32 remSize = len - pos; + + // if a minimum sized msg would fit in remaining, continue + if ( remSize >= MESSAGE_OVERHEAD_SIZE ) + { + payloadSize = data[ pos + sizeof(MESSAGE_HEADER_T) - sizeof(U08) ]; + msgSize = MESSAGE_OVERHEAD_SIZE + payloadSize; + // we now know the size of the message - we can now know if full message is contained in buffer + if ( msgSize <= remSize ) + { // check CRC to make sure it's a valid message + if ( data[i+msgSize] == crc8( &data[pos], msgSize - 1 ) ) + { + result = msgSize; // we found a complete, valid message of this size + } + else // CRC failed + { + result = -1; // we found a complete, invalid message + } + } + } + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The processReceivedMessages function processes any messages in the + * received message queues. + * @details + * Inputs : Received Message Queues + * Outputs : Message(s) processed. + * @return none + *************************************************************************/ +static void processReceivedMessages( void ) +{ + BOOL isThereMsgRcvd = TRUE; // assume TRUE at first to get into while loop + MESSAGE_WRAPPER_T message; + + while ( TRUE == isThereMsgRcvd ) + { + // see if any messages received + isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); + if ( TRUE == isThereMsgRcvd ) + { // CRC should be good because we checked it during parsing before adding to queue - but check it again for good measure + if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) + { + // if ACK, mark pending message ACK'd + if ( MSG_ID_ACK == message.msg.hdr.msgID ) + { + matchACKtoPendingACKList( message.msg.hdr.seqNo ); + } + else + { + // if received message requires ACK, queue one up + if ( message.msg.hdr.seqNo < 0 ) + { + sendACKMsg( &message.msg ); + } + // otherwise, process the received message + processReceivedMessage( &message.msg ); + } + } + else // CRC failed + { + checkTooManyBadMsgCRCs(); + } + } + } +} + +/*********************************************************************//** + * @brief + * The checkForCommTimeouts function checks for sub-system communication timeout errors. + * @details + * Inputs : timeOfLastDGCheckIn, timeOfLastUICheckIn + * Outputs : possibly a comm t/o alarm + * @return none + *************************************************************************/ +static void checkForCommTimeouts( void ) +{ + if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) + { + hdIsCommunicating = FALSE; +#ifndef DEBUG_ENABLED + activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm if we're in middle of a treatment? or if in a mode that comm loss would impact badly? +#endif + } +} + +/*********************************************************************//** + * @brief + * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs + * within a set period of time. Assumed function is being called when a new + * bad CRC is detected so a new bad CRC will be added to the list. + * @details + * Inputs : badCRCTimeStamps[], badCRCListIdx, badCRCListCount + * Outputs : possibly a "too many bad CRCs" alarm + * @return none + *************************************************************************/ +static void checkTooManyBadMsgCRCs( void ) +{ if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_COMM_TOO_MANY_BAD_CRCS, 2 ); // 2 for DG - } + } #ifdef DEBUG_ENABLED { char debugStr[100]; @@ -891,264 +891,268 @@ sendDebugDataToUI( (U08*)debugStr ); } #endif -} - -/*********************************************************************//** - * @brief - * The addMsgToPendingACKList function adds a given message to the pending - * ACK list. Messages in this list will require receipt of an ACK message - * for this particular message within a limited time. - * @details - * Inputs : pendingAckList[] - * Outputs : pendingAckList[] - * @param msg pointer to msg within the message data - * @param msgData pointer to message data to add to pending ACK list - * @param len number of bytes of message data - * @return TRUE if message added successfully, FALSE if not - *************************************************************************/ -BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) -{ - BOOL result = FALSE; - U32 i; - - // find first open slot in pending ACK list and add given msg data to it - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - _disable_IRQ(); // slot selection needs interrupt protection - if ( FALSE == pendingAckList[ i ].used ) - { - S16 seqNo = msg->hdr.seqNo * -1; // remove ACK bit from seq # - - pendingAckList[ i ].used = TRUE; - _enable_IRQ(); - pendingAckList[ i ].seqNo = seqNo; - pendingAckList[ i ].channel = channel; - pendingAckList[ i ].timeStamp = getMSTimerCount(); - pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; - pendingAckList[ i ].msgSize = len; - memcpy( pendingAckList[ i ].msg, msgData, len ); - result = TRUE; - break; - } - else - { - _enable_IRQ(); - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The matchACKtoPendingACKList function searches the pending ACK list to - * see if the sequence number from a received ACK msg matches any. If found, - * the list entry is removed. - * @details - * Inputs : pendingAckList[] - * Outputs : pendingAckList[] - * @param seqNo sequence number to match to an entry in the list - * @return TRUE if a match was found, FALSE if not - *************************************************************************/ -static BOOL matchACKtoPendingACKList( S16 seqNo ) -{ - BOOL result = FALSE; - U32 i; - - // find match - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) - { // remove message pending ACK from list - pendingAckList[ i ].used = FALSE; - result = TRUE; - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief +} + +/*********************************************************************//** + * @brief + * The addMsgToPendingACKList function adds a given message to the pending + * ACK list. Messages in this list will require receipt of an ACK message + * for this particular message within a limited time. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param msg pointer to msg within the message data + * @param msgData pointer to message data to add to pending ACK list + * @param len number of bytes of message data + * @return TRUE if message added successfully, FALSE if not + *************************************************************************/ +BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) +{ + BOOL result = FALSE; + U32 i; + + // find first open slot in pending ACK list and add given msg data to it + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + _disable_IRQ(); // slot selection needs interrupt protection + if ( FALSE == pendingAckList[ i ].used ) + { + S16 seqNo = msg->hdr.seqNo * -1; // remove ACK bit from seq # + + pendingAckList[ i ].used = TRUE; + _enable_IRQ(); + pendingAckList[ i ].seqNo = seqNo; + pendingAckList[ i ].channel = channel; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; + pendingAckList[ i ].msgSize = len; + memcpy( pendingAckList[ i ].msg, msgData, len ); + result = TRUE; + break; + } + else + { + _enable_IRQ(); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The matchACKtoPendingACKList function searches the pending ACK list to + * see if the sequence number from a received ACK msg matches any. If found, + * the list entry is removed. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @param seqNo sequence number to match to an entry in the list + * @return TRUE if a match was found, FALSE if not + *************************************************************************/ +static BOOL matchACKtoPendingACKList( S16 seqNo ) +{ + BOOL result = FALSE; + U32 i; + + // find match + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) + { // remove message pending ACK from list + pendingAckList[ i ].used = FALSE; + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The checkPendingACKList function searches the pending ACK list to see if - * any have expired. Any such messages will be queued for retransmission - * and if max retries reached a fault is triggered. - * @details - * Inputs : pendingAckList[] - * Outputs : pendingAckList[] - * @return none - *************************************************************************/ -static void checkPendingACKList( void ) -{ - U32 i; - - // find expired messages pending ACK - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { // pending ACK expired? - if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) - { // if retries left, reset and resend pending message - if ( pendingAckList[ i ].retries > 0 ) - { // re-queue message for transmit - pendingAckList[ i ].retries--; - pendingAckList[ i ].timeStamp = getMSTimerCount(); - addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); + * any have expired. Any such messages will be queued for retransmission + * and if max retries reached a fault is triggered. + * @details + * Inputs : pendingAckList[] + * Outputs : pendingAckList[] + * @return none + *************************************************************************/ +static void checkPendingACKList( void ) +{ + U32 i; + + // find expired messages pending ACK + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { // pending ACK expired? + if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) + { // if retries left, reset and resend pending message + if ( pendingAckList[ i ].retries > 0 ) + { // re-queue message for transmit + pendingAckList[ i ].retries--; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); } - // if no retries left, alarm - else - { - U16 msgID; - - memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); + // if no retries left, alarm + else + { + U16 msgID; + + memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CAN_MESSAGE_NOT_ACKED, (U32)msgID ); - pendingAckList[ i ].used = FALSE; // take pending message off of list - } - } - } -} - -/*********************************************************************//** - * @brief - * The processReceivedMessage function processes a given message. - * @details - * Inputs : none - * Outputs : message processed - * @param message pointer to message to process - * @return none - *************************************************************************/ -static void processReceivedMessage( MESSAGE_T *message ) -{ - U16 msgID = message->hdr.msgID; - - // handle any messages from other sub-systems - switch ( msgID ) - { - case MSG_ID_POWER_OFF_WARNING: - handlePowerOffWarning( message ); - break; - - case MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS: - handleSetDialysateTemperatureCmd( message ); - break; - - case MSG_ID_REQUEST_FW_VERSIONS: - handleFWVersionCmd( message ); - break; - - case MSG_ID_DG_SWITCH_RESERVOIR_CMD: - handleSwitchReservoirCmd( message ); - break; - - case MSG_ID_DG_FILL_CMD: - handleFillCmd( message ); - break; - - case MSG_ID_DG_DRAIN_CMD: - handleDrainCmd( message ); - break; - - case MSG_ID_STARTING_STOPPING_TREATMENT_CMD: - handleStartStopTreatmentMsg( message ); - break; - - case MSG_ID_DG_SAMPLE_WATER_CMD: - handleSampleWaterCmd( message ); - break; - - case MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD: - handleStartStopTrimmerHeaterCmd( message ); - break; - - case MSG_ID_DG_TESTER_LOGIN_REQUEST: - handleTesterLogInRequest( message ); - break; - - default: - // unrecognized message ID received - ok, ignore - may be a test message handled below - break; - } - - // handle any test messages if tester has logged in successfully - if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) - { - switch ( msgID ) - { - case MSG_ID_DG_ALARM_STATE_OVERRIDE: - handleTestAlarmStateOverrideRequest( message ); - break; - - case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: - handleTestWatchdogCheckInStateOverrideRequest( message ); - break; - - case MSG_ID_DG_SET_RTC_DATE_TIME: - handleSetRTCTimestamp( message ); - break; - - case MSG_ID_START_STOP_PRIMARY_HEATER: - handleStartStopPrimaryHeater ( message ); - break; - - case MSG_ID_LOAD_CELL_OVERRIDE: - handleTestLoadCellOverrideRequest( message ); - break; - - case MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: - handleTestLoadCellDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_PRESSURE_OVERRIDE: - handleTestPressureSensorOverrideRequest( message ); - break; - - case MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: - handleTestPressureDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_RO_PUMP_SET_PT_OVERRIDE: - handleTestROPumpSetPointOverrideRequest( message ); - break; - - case MSG_ID_RO_MEASURED_FLOW_OVERRIDE: - handleTestROMeasuredFlowOverrideRequest( message ); - break; - - case MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: - handleTestROPumpDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_DRAIN_PUMP_SET_RPM_OVERRIDE: - handleTestDrainPumpSetPointOverrideRequest( message ); - break; - - case MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: - handleTestDrainPumpDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_VALVE_STATE_OVERRIDE: - handleTestValveStateOverrideRequest( message ); - break; - - case MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: - handleTestValvesStatesPublishIntervalOverrideRequest( message ); - break; - - case MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: - handleTestDGSafetyShutdownOverrideRequest( message ); + pendingAckList[ i ].used = FALSE; // take pending message off of list + } + } + } +} + +/*********************************************************************//** + * @brief + * The processReceivedMessage function processes a given message. + * @details + * Inputs : none + * Outputs : message processed + * @param message pointer to message to process + * @return none + *************************************************************************/ +static void processReceivedMessage( MESSAGE_T *message ) +{ + U16 msgID = message->hdr.msgID; + + // handle any messages from other sub-systems + switch ( msgID ) + { + case MSG_ID_POWER_OFF_WARNING: + handlePowerOffWarning( message ); + break; + + case MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS: + handleSetDialysateTemperatureCmd( message ); + break; + + case MSG_ID_REQUEST_FW_VERSIONS: + handleFWVersionCmd( message ); + break; + + case MSG_ID_DG_SWITCH_RESERVOIR_CMD: + handleSwitchReservoirCmd( message ); + break; + + case MSG_ID_DG_FILL_CMD: + handleFillCmd( message ); + break; + + case MSG_ID_DG_DRAIN_CMD: + handleDrainCmd( message ); + break; + + case MSG_ID_STARTING_STOPPING_TREATMENT_CMD: + handleStartStopTreatmentMsg( message ); + break; + + case MSG_ID_DG_SAMPLE_WATER_CMD: + handleSampleWaterCmd( message ); + break; + + case MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD: + handleStartStopTrimmerHeaterCmd( message ); + break; + + case MSG_ID_DG_TESTER_LOGIN_REQUEST: + handleTesterLogInRequest( message ); + break; + + case MSG_ID_DG_START_STOP_HEAT_DISINFECT: + handleStartStopDGHeatDisinfect( message ); + break; + + default: + // unrecognized message ID received - ok, ignore - may be a test message handled below + break; + } + + // handle any test messages if tester has logged in successfully + if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) + { + switch ( msgID ) + { + case MSG_ID_DG_ALARM_STATE_OVERRIDE: + handleTestAlarmStateOverrideRequest( message ); break; - - case MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE: - handleTestTemperatureSensorsOverrideRequest ( message ); - break; - - case MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE: - handleTestTemperatureSensorsDataPublishOverrideRequest ( message ); - break; - - case MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE: - handleTestHeatersDataPublishOverrideRequest ( message ); + + case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: + handleTestWatchdogCheckInStateOverrideRequest( message ); break; - + + case MSG_ID_DG_SET_RTC_DATE_TIME: + handleSetRTCTimestamp( message ); + break; + + case MSG_ID_START_STOP_PRIMARY_HEATER: + handleStartStopPrimaryHeater ( message ); + break; + + case MSG_ID_LOAD_CELL_OVERRIDE: + handleTestLoadCellOverrideRequest( message ); + break; + + case MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: + handleTestLoadCellDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_PRESSURE_OVERRIDE: + handleTestPressureSensorOverrideRequest( message ); + break; + + case MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: + handleTestPressureDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_RO_PUMP_SET_PT_OVERRIDE: + handleTestROPumpSetPointOverrideRequest( message ); + break; + + case MSG_ID_RO_MEASURED_FLOW_OVERRIDE: + handleTestROMeasuredFlowOverrideRequest( message ); + break; + + case MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: + handleTestROPumpDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_DRAIN_PUMP_SET_RPM_OVERRIDE: + handleTestDrainPumpSetPointOverrideRequest( message ); + break; + + case MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: + handleTestDrainPumpDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_VALVE_STATE_OVERRIDE: + handleTestValveStateOverrideRequest( message ); + break; + + case MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: + handleTestValvesStatesPublishIntervalOverrideRequest( message ); + break; + + case MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: + handleTestDGSafetyShutdownOverrideRequest( message ); + break; + + case MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE: + handleTestTemperatureSensorsOverrideRequest ( message ); + break; + + case MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE: + handleTestTemperatureSensorsDataPublishOverrideRequest ( message ); + break; + + case MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE: + handleTestHeatersDataPublishOverrideRequest ( message ); + break; + case MSG_ID_CONDUCTIVITY_OVERRIDE: handleTestSetConductivityOverrideRequest ( message ); break; @@ -1173,11 +1177,11 @@ handleSetAccelCalibration( message ); break; - default: - // TODO - unrecognized message ID received - ignore - break; - } - } -} + default: + // TODO - unrecognized message ID received - ignore + break; + } + } +} /**@}*/ Index: firmware/App/Services/SystemComm.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/SystemComm.h (.../SystemComm.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -57,12 +57,10 @@ void handleUARTMsgRecvPacketInterrupt( void ); void handleUARTMsgXmitPacketInterrupt( void ); #endif + BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ); BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ); -BOOL isHDCommunicating( void ); -BOOL isDGOnlyCANNode( void ); -BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ); -/**@}*/ - -#endif +BOOL isDGOnlyCANNode( void ); + +#endif Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -40,6 +40,7 @@ #include "Utilities.h" #include "Valves.h" #include "WatchdogMgmt.h" +#include "ModeHeatDisinfect.h" /** * @addtogroup SystemCommMessages @@ -54,7 +55,19 @@ #ifdef DEBUG_ENABLED #define DEBUG_EVENT_MAX_TEXT_LEN 40 #endif + +#pragma pack(push,1) + +/// Heat disinfect data +typedef struct +{ + U32 internalState; ///< Internal state of heat disinfect state machine + F32 elapsedTimeMins; ///< Heat disinfect elapsed time in minutes + U32 currentCycle; ///< Current cycle of the heat disinfect +} DG_HEAT_DISINFECT_DATA_T; +#pragma pack(pop) + // ********** private data ********** static BOOL testerLoggedIn = FALSE; ///< Flag indicates whether tester logged in or not. @@ -497,7 +510,7 @@ * @param setPWM set PWM duty cycle in % * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ -BOOL broadcastROPumpData( U32 tgtPressure, F32 measFlow, F32 setPWM ) +BOOL broadcastROPumpData( F32 tgtPressure, F32 measFlow, F32 setPWM, U32 pumpState ) { BOOL result; MESSAGE_T msg; @@ -509,9 +522,10 @@ msg.hdr.msgID = MSG_ID_RO_PUMP_DATA; msg.hdr.payloadLen = sizeof( RO_PUMP_DATA_T ); - payload.setROPumpPressure = tgtPressure; + payload.roPumpTgtPressure = tgtPressure; payload.measROFlowRate = measFlow; - payload.roPumpPWM = setPWM; + payload.roPumpPWM = setPWM; + payload.roPumpState = pumpState; memcpy( payloadPtr, &payload, sizeof( RO_PUMP_DATA_T ) ); @@ -531,7 +545,7 @@ * @param dac set DAC value * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ -BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac ) +BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac, F32 deltaP, U32 drainPumpState ) { BOOL result; MESSAGE_T msg; @@ -544,7 +558,9 @@ msg.hdr.payloadLen = sizeof( DRAIN_PUMP_DATA_T ); payload.setDrainPumpSpeed = tgtSpeed; - payload.dacValue = dac; + payload.dacValue = dac; + payload.deltaPressure = deltaP; + payload.drainPState = drainPumpState; memcpy( payloadPtr, &payload, sizeof( DRAIN_PUMP_DATA_T ) ); @@ -653,6 +669,41 @@ result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); return result; +} + +/************************************************************************* + * @brief + * The broadcastHeatDisinfectData function sends out DG heat disinfection + * data + * Inputs : DG heat disinfect data + * Outputs : DG heat disinfect data msg constructed and queued + * @param internalState : The state of the internal state machine of the mode + * @param minutesElapsed: Minutes elapsed since the start of heat disinfection + * @param currentCycle: Current cycle count of DG heat disinfection + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastHeatDisinfectData( U32 internalState, F32 minutesElapsed, U32 currentCycle ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + DG_HEAT_DISINFECT_DATA_T payload; + + // create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_DG_HEAT_DISINFECT_DATA; + msg.hdr.payloadLen = sizeof( DG_HEAT_DISINFECT_DATA_T ); + + payload.internalState = internalState; + payload.elapsedTimeMins = minutesElapsed; + payload.currentCycle = currentCycle; + + memcpy( payloadPtr, &payload, sizeof( DG_HEAT_DISINFECT_DATA_T ) ); + + // 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_DG_BROADCAST, ACK_NOT_REQUIRED ); + + return result; } /*********************************************************************//** @@ -1007,6 +1058,66 @@ /************************************************************************* + * @brief + * The handleStartStopDGHeatDisinfect function handles a request start or + * stop DG heat disifect + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return result + *************************************************************************/ +BOOL handleStartStopDGHeatDisinfect( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof(U32) ) + { + BOOL startingDGHeatDisinfect; + + memcpy( &startingDGHeatDisinfect, message->payload, sizeof(U32) ); + + if ( TRUE == startingDGHeatDisinfect ) + { + startDGHeatDisinfect(); + result = TRUE; + } + else + { + stopDGHeatDisinfect(); + result = TRUE; + } + } + sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DG_2_HD, result ); + + return result; +} + +/************************************************************************* + * @brief + * The handleSetROPumpPWM function handles the start of the RO pump with a\n + * PWM. The run is open loop + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return result + *************************************************************************/ +BOOL handleSetROPumpPWM( MESSAGE_T * message ) +{ + BOOL result = FALSE; + + if ( message->hdr.payloadLen == sizeof(U32) ) + { + U32 roPumpPWM; + memcpy( &roPumpPWM, message->payload, sizeof(U32) ); + result = setROPumpTargetPWM( roPumpPWM ); + } + + return result; +} + +/************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -1425,7 +1536,7 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } -/*********************************************************************//** +/*********************************************************************//** * @brief * The handleTestROPumpSetPointOverrideRequest function handles a request to * override the RO pump pressure set point (in PSI). @@ -1656,16 +1767,99 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } -/*********************************************************************//** - * @brief - * The handleTestDGSafetyShutdownOverrideRequest function handles a - * request to override the safety shutdown signal. - * @details - * Inputs : none - * Outputs : message handled - * @param message a pointer to the message to handle - * @return none - *************************************************************************/ +/************************************************************************* + * @brief + * The handleSetDrainPumpDeltaPressure function handles a \n + * request to override the delta pressure for the drain pump + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( U32, handleSetDrainPumpDeltaPressureOverrideRequest, \ + testSetTargetDrainPumpDeltaPressureOverride, testResetTargetDrainPumpDeltaPressureOverride ) + +/************************************************************************* + * @brief + * The handleSetHeatDisinfectRecircStateDurationOverrideRequest function handles a \n + * request to override the heat disinfection recirculation state duration in minutes + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( F32, handleSetHeatDisinfectRecircStateDurationOverrideRequest, \ + testSetHeatDisinfectRecircDurationOverride, testResetHeatDisinfectRecircDurationOverride ) + +/************************************************************************* + * @brief + * The handleSetHeatDisinfectRSVR1ToRSVR2StateDurationOverrideRequest \n + * function handles a request to override the heat disinfection reservoir 1 \n + * to reservoir 2 state duration in minutes + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( F32, handleSetHeatDisinfectRSVR1ToRSVR2StateDurationOverrideRequest, \ + testSetHeatDisinfectR1ToR2DurationOverride, testResetHeatDisinfectR1ToR2DurationOverride ) + +/************************************************************************* + * @brief + * The handleSetHeatDisinfectRSVR2ToRSVR1StateDurationOverrideRequest \n + * function handles a request to override the heat disinfection reservoir 2 \n + * to reservoir 1 state duration in minutes + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( F32, handleSetHeatDisinfectRSVR2ToRSVR1StateDurationOverrideRequest, \ + testSetHeatDisinfectionR2ToR1DurationOverride, testResetHeatDisinfectionR2ToR1DurationOverride ) + +/************************************************************************* + * @brief + * The handleSetHeatDisinfectNoOfCyclesStateDurationOverrideRequest \n + * function handles a request to override the heat disinfection no of \n + * cycles to run request + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( U32, handleSetHeatDisinfectNoOfCyclesStateDurationOverrideRequest, \ + testSetHeatDisinfectNoOfCyclesOverride, testResetHeatDisinfectNoOfCyclesOverride ) + + +/************************************************************************* + * @brief + * The handleSetHeatDisinfectionPublishDataIntervalOverrideRequest \n + * function handles a request to override the heat disinfection data \n + * publish interval + * @details + * Inputs : none + * Outputs : message handled + * @param message : a pointer to the message to handle + * @return none + *************************************************************************/ +DATA_OVERRIDE_HANDLER_FUNC_U32( U32, handleSetHeatDisinfectionPublishDataIntervalOverrideRequest, \ + testSetHeatDisinfectDataPublishIntervalOverride, testResetHeatDisinfectDataPublishIntervalOverride ) + +/*********************************************************************//** + * @brief + * The handleTestDGSafetyShutdownOverrideRequest function handles a + * request to override the safety shutdown signal. + * @details + * Inputs : none + * Outputs : message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ void handleTestDGSafetyShutdownOverrideRequest( MESSAGE_T *message ) { TEST_OVERRIDE_PAYLOAD_T payload; Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -rab304e2ca6e3e40ed8cb12650e9855ae0b9649d8 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision ab304e2ca6e3e40ed8cb12650e9855ae0b9649d8) @@ -58,10 +58,10 @@ BOOL broadcastValvesStates( U16 valvesStates ); // MSG_ID_RO_PUMP_DATA -BOOL broadcastROPumpData( U32 tgtPressure, F32 measFlow, F32 setPWM ); +BOOL broadcastROPumpData( F32 tgtPressure, F32 measFlow, F32 setPWM, U32 pumpState ); // MSG_ID_DRAIN_PUMP_DATA -BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac ); +BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac, F32 deltaP, U32 drainPumpState ); // MSG_ID_DG_PRESSURES_DATA BOOL broadcastPressureSensorsData( F32 measROIn, F32 measROOut, F32 measDrainIn, F32 measDrainOut ); @@ -107,7 +107,16 @@ // MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD void handleStartStopTrimmerHeaterCmd( MESSAGE_T *message ); + +// MSG_ID_HEATERS_READINGS +BOOL broadcastHeatersData ( U32 mainPrimaryDC, U32 smallPrimaryDC, U32 trimmerDC ); +// MSG_ID_TEMPERATURE_SENSORS_READINGS +BOOL broadcastTemperatureSensorsData ( U08 *sensorsValue, U32 byteLength ); + +//MSG_ID_DG_HEAT_DISINFECT_DATA +BOOL broadcastHeatDisinfectData( U32 internalState, F32 minutesElapsed, U32 currentCycle ); + // *********** public test support message functions ********** #ifdef DEBUG_ENABLED @@ -174,6 +183,35 @@ void handleTestValvesStatesPublishIntervalOverrideRequest( MESSAGE_T *message ); // MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: +void handleTestDGSafetyShutdownOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_START_STOP_PRIMARY_HEATER +BOOL handleStartStopPrimaryHeater( MESSAGE_T *message ); + +// MSG_ID_START_STOP_DG_HEAT_DISINFECT +BOOL handleStartStopDGHeatDisinfect( MESSAGE_T *message ); + +// MSG_ID_SET_RO_PUMP_PWM +BOOL handleSetROPumpPWM( MESSAGE_T * message ); + +// MSG_ID_DRAIN_PUMP_SET_DELTA_PRESSURE_OVERRIDE +void handleSetDrainPumpDeltaPressureOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_HEAT_DISINFECT_RECIRC_PATH_DURATION_MINS +void handleSetHeatDisinfectRecircStateDurationOverrideRequest( MESSAGE_T *message ); + +//MSG_ID_HEAT_DISINFECT_RSRVR1_TO_RSRVR2_DURATION_MINS +void handleSetHeatDisinfectRSVR1ToRSVR2StateDurationOverrideRequest( MESSAGE_T *message ); + +//MSG_ID_HEAT_DISINFECT_RSRVR2_TO_RSRVR1_DURATION_MINS +void handleSetHeatDisinfectRSVR2ToRSVR1StateDurationOverrideRequest( MESSAGE_T *message ); + +//MSG_ID_HEAT_DISINFECT_NO_OF_CYCLES_TO_RUN +void handleSetHeatDisinfectNoOfCyclesStateDurationOverrideRequest( MESSAGE_T *message ); + +//MSG_ID_HEAT_DISINFECT_PUBLISH_INTERVAL_OVERRIDE +void handleSetHeatDisinfectionPublishDataIntervalOverrideRequest( MESSAGE_T *message ); + void handleTestDGSafetyShutdownOverrideRequest( MESSAGE_T *message ); // MSG_ID_CONDUCTIVITY_OVERRIDE