Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rc85d9f0a8023fabdf1cd557965958d225e2b9085 -r2e89a75592087ba15cae7070a92173e9f1efa8fe --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision c85d9f0a8023fabdf1cd557965958d225e2b9085) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 2e89a75592087ba15cae7070a92173e9f1efa8fe) @@ -29,7 +29,8 @@ #include "SafetyShutdown.h" #include "TaskGeneral.h" #include "TaskPriority.h" -#include "TemperatureSensors.h" +#include "TDInterface.h" +#include "Temperature.h" #include "Timers.h" #include "Utilities.h" @@ -39,46 +40,65 @@ */ // ********** private definitions ********** - -#define HEATERS_MAX_DUTY_CYCLE 1.00F ///< Heaters max duty cycle (100%). -#define HEATERS_MIN_DUTY_CYCLE 0.00F ///< Heaters minimum duty cycle (0.00%). -#define HEATERS_DISINFECT_DUTY_CYCLE 0.80F ///< Heaters disinfect cycle. -#define HEATERS_DISINFECT_TRANSFER_DUTY_CYCLE 0.60F ///< Heaters disinfect transfer duty cycle. +#define AC_HEATER_TX_MAX_DUTY_CYCLE 0.50F ///< AC Heater treatment mode max duty cycle (50% of 1400W : 700W ) +#define AC_HEATER_HEAT_MAX_DUTY_CYCLE 0.70F ///< AC Heater heat disinfect mode max duty cycle (70% of 1400W : 980W ) +#define AC_HEATER_MAX_DUTY_CYCLE 1.0F ///< AC Heater max duty cycle (100.0%) or ON state +#define DC_HEATER_MAX_DUTY_CYCLE 1.0F ///< DC Heater max duty cycle (100%) or ON state +#define HEATERS_MIN_DUTY_CYCLE 0.0F ///< Heaters minimum duty cycle (0.00%) or OFF state #define HEATERS_DISINFECT_TEMPERATURE_DRIFT_C 3.0F ///< Heaters disinfect temperature drift in C. #define HEATERS_ZERO_DELTA_TEMP_C 0.0F ///< Heaters zero delta temperature in C. -#define HEATERS_DUTY_CYCLE_CONVERSION_FACTOR 127.0F ///< Heaters duty cycle 0: OFF, 127: 100% duty cycle. +#define HEATERS_DUTY_CYCLE_CONVERSION_FACTOR 100.0F ///< Heaters duty cycle 0: OFF, 100: 100% duty cycle. +#define HEATERS_ZERO_EFFICIENCY 0.0F ///< Zero heater efficiency +#define HEATER_CNTL_TRANSFER_DELTA_TEMP_C 0.50F ///< AC heater delta temperature to transfer control from open to close loop -#define PRIMARY_HEATER_P_COEFFICIENT 1.0F ///< P Term for primary heater control. -#define PRIMARY_HEATER_I_COEFFICIENT 1.0F ///< I Term for primary heater control. -#define TRIMMER_HEATER_P_COEFFICIENT 1.0F ///< P Term for trimmer heater control. -#define TRIMMER_HEATER_I_COEFFICIENT 1.0F ///< I Term for trimmer heater control. +#define D5_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control +//#define D5_HEAT_TX_P_COEFFICIENT 0.050F ///< P Term for AC primary heater control during treatment mode. +//#define D5_HEAT_TX_I_COEFFICIENT 0.015F ///< I Term for AC primary heater control during treatment mode. -#define HEATERS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. +#define D5_HEAT_TX_P_COEFFICIENT 0.035F ///< P Term for AC primary heater control during treatment mode. +#define D5_HEAT_TX_I_COEFFICIENT 0.004F ///< I Term for AC primary heater control during treatment mode. +#define D45_HEAT_P_COEFFICIENT 0.20F ///< P Term for trimmer heater control. +#define D45_HEAT_I_COEFFICIENT 0.05F ///< I Term for trimmer heater control. +#define D45_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control + +#define HEATERS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. +#define HEATER_TEMP_CONTROL_TRANSFER 1.0F ///< Primary Heater temperature difference to switch to control function #define HEATER_TARGET_TEMPERATURE_MIN 10.0F ///< Minimum allowed target temperature for the heaters. #define HEATER_TARGET_TEMPERATURE_MAX 90.0F ///< Maximum allowed target temperature for the heaters. -#define PRIMARY_HEATER_ON_NO_FLUID_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Primary heater on with no flow time out in milliseconds. -#define TRIMMER_HEATER_ON_NO_FLUID_TIMEOUT_MS ( 12 * MS_PER_SECOND ) ///< Trimmer heater on with no flow time out in milliseconds. +#define D5_HEAT_ON_NO_FLUID_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Primary heater on with no flow time out in milliseconds. +#define D45_HEAT_ON_NO_FLUID_TIMEOUT_MS ( 12 * MS_PER_SECOND ) ///< Trimmer heater on with no flow time out in milliseconds. #define HEATERS_MAX_OPERATING_VOLTAGE_V 24.0F ///< Heaters max operating voltage in volts. #define HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Heaters voltage out of range time out in milliseconds. #define HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL 0.2F ///< Heaters max voltage out of range tolerance. -#define TRIMMER_HEATER_INITIAL_CONTROL_INTERVAL_COUNT ( ( 5 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Trimmer heater initial control interval count. -#define TRIMMER_HEATER_CONTROL_INTERVAL_COUNT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. -#define PRIMARY_HEATER_CONTROL_INTERVAL_COUNT ( ( 1 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Primary heater control interval count. +#define D5_HEATER_DEADBAND_CONTROL 0.1F ///< Heater deadband range for conrtol. +//#define D5_HEAT_CONTROL_INTERVAL_MS 30000 /// Primary heater control interval in milli seconds +#define D5_HEAT_CONTROL_INTERVAL_MS 3000 /// Primary heater control interval in milli seconds +#define D5_HEAT_CONTROL_INTERVAL_COUNT ( D5_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Primary heater control interval count. +#define D45_HEAT_CONTROL_INTERVAL_MS ( 1 * MS_PER_SECOND ) ///< Trimmer heater control interval in milli seconds +#define D45_HEAT_CONTROL_INTERVAL_COUNT ( D45_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. +#define PRIMARY_HEATER_MAX_PWR_WATTS 1400.0F ///< AC Primary Heater Max Power consumeption in Watts +#define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatement mode +#define HEAT_PRIMARY_HEATER_MAX_PWR_WATTS 980.0F ///< Estimated power to be supplied to the primary heater during heat disinfect mode +#define MAX_INLET_FLOW_LPM ( 600.0F / 1000.0F ) ///< Maximum inlet flow to hydraulics chamber from FP +#define LITER_IN_ML 1000.0F ///< Liter in milliliter units +#define TRIMMER_HEATER_MAX_PWR_WATTS 120.0F ///< Maximum power supplied to trimmer heater +#define AC_HEATER_PWM_PERIOD 10000 ///< PWM period 100 ms( in 10us resoultion), 1/10Hz = 1000000us/10us = 10000. +#define AC_HEATER_EFFICIENCY 0.90F ///< Approximated AC heater efficiency to be used in energy calcualtions. +#define DC_HEATER_EFFICIENCY 1.0F ///< DC heater efficiency +#define D5_HEAT_CONTROL_INTERVAL_START_COUNT ( D5_HEAT_CONTROL_INTERVAL_COUNT - 10 ) ///< AC heater control interval start count to jump feedforward control from open loop. #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. //static const F32 HEATERS_VOLTAGE_TOLERANCE_V = HEATERS_MAX_OPERATING_VOLTAGE_V * HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL; ///< Heaters voltage tolerance in volts. /// Heaters data structure typedef struct { - F32 targetTempC; ///< Heater target temperature. HEATERS_STATE_T state; ///< Heater state. BOOL startHeaterSignal; ///< Heater start indication flag. BOOL heaterOnState; ///< Heater on/off status flag. - OVERRIDE_F32_T dutyCycle; ///< Heater duty cycle. F32 targetFlowLPM; ///< Heater target flow in L/min to calculate the duty cycle. F32 nomTargetFlowLPM; ///< Heater nominal target flow in L/min. BOOL hasTargetTempChanged; ///< Heater target temperature change flag indicator. @@ -87,19 +107,40 @@ F32 prevDiaTargetFlowLPM; ///< Heater previous target dialysate flow in L/min. } HEATER_STATUS_T; +/// Payload record structure for heaters start request +typedef struct +{ + U32 heaterID; ///< Heater ID (0: Primary, 1: Trimmer) + U32 startStop; ///< Heater Start:1 and Stop: 0 + F32 temperature; ///< Temperature range ( 10.0 to 90.0 deg ) +} HEATER_START_CMD_PAYLOAD_T; + static HEATER_STATUS_T heatersStatus[ NUM_OF_DD_HEATERS ]; ///< Heaters status. +static OVERRIDE_F32_T targetTempC[ NUM_OF_DD_HEATERS ]; ///< Heater target temperature. +static OVERRIDE_F32_T control[ NUM_OF_DD_HEATERS ]; ///< Heater control ( Primary : On/Off, Trimmer : Dutycycle). +static OVERRIDE_F32_T pwmPeriod[ NUM_OF_DD_HEATERS ]; ///< Total PWM period ( ON state + Off State of PWM) +static U32 controlInterval[ NUM_OF_DD_HEATERS ]; ///< Heater control interval time. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. +static const F32 WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES = 4184.0F / (F32)SEC_PER_MIN; ///< Water specific heat in J/KgC / 60. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. +static F32 convertDC; ///< AC Heater converted duty cycle +static F32 lastDialTargetTemperatureSet; ///< last dialysate target temperature set for heater control +static BOOL startupHeaterControl; ///< First time control with the energy equation. +//For testing +#ifdef __HEATERS_DEBUG__ +static F32 pIControlSignal[ NUM_OF_CONTROLLER_SIGNAL ]; +#endif // ********** private function prototypes ********** static HEATERS_STATE_T handleHeaterStateOff( DD_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateRampToTarget( DD_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToTarget( DD_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToDisinfectTarget( DD_HEATERS_T heater ); +static F32 calculateDutyCycle( F32 flowrate, F32 deltaTemp, F32 power, F32 efficiency, F32 min, F32 max ); -static void setHeaterDutyCycle( DD_HEATERS_T heater ); -static F32 getHeaterDutyCycle( DD_HEATERS_T heater ); +static void setHeaterControl( DD_HEATERS_T heater ); +static F32 getHeaterControl( DD_HEATERS_T heater ); static void publishHeatersData( void ); //static void monitorHeatersVoltage( void ); @@ -114,39 +155,80 @@ void initHeaters( void ) { DD_HEATERS_T heater; - dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; +#ifdef __HEATERS_DEBUG__ + U32 i; +#endif + // Assign start count + dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + + //Enable PWM based heater control + setFPGAD5HeaterPWMEnableControl( TRUE ); + + // Define PWM period for AC heater + pwmPeriod[ D5_HEAT ].data = AC_HEATER_PWM_PERIOD; + pwmPeriod[ D5_HEAT ].ovData = AC_HEATER_PWM_PERIOD; + pwmPeriod[ D5_HEAT ].ovInitData = AC_HEATER_PWM_PERIOD; + pwmPeriod[ D5_HEAT ].override = OVERRIDE_RESET; + + // TODO : Trimmer heater PWM period + pwmPeriod[ D45_HEAT ].data = 0.0F; + pwmPeriod[ D45_HEAT ].ovData = 0.0F; + pwmPeriod[ D45_HEAT ].ovInitData = 0.0F; + pwmPeriod[ D45_HEAT ].override = OVERRIDE_RESET; + + //Initialize Converted Duty cycle + convertDC = 0.0F; + controlInterval[ D5_HEAT ] = D5_HEAT_CONTROL_INTERVAL_COUNT; + controlInterval[ D45_HEAT ] = D45_HEAT_CONTROL_INTERVAL_COUNT; + + // Assign counter close to the target period + heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; + heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; + startupHeaterControl = TRUE; + lastDialTargetTemperatureSet = 0.0F; + for ( heater = DD_HEATERS_FIRST; heater < NUM_OF_DD_HEATERS; heater++ ) { - heatersStatus[ heater ].targetTempC = 0.0F; + targetTempC[ heater ].data = 0.0F; + targetTempC[ heater ].ovData = 0.0F; + targetTempC[ heater ].ovInitData = 0.0F; + targetTempC[ heater ].override = OVERRIDE_RESET; heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; heatersStatus[ heater ].startHeaterSignal = FALSE; heatersStatus[ heater ].heaterOnState = FALSE; - heatersStatus[ heater ].dutyCycle.data = HEATERS_MIN_DUTY_CYCLE; - heatersStatus[ heater ].dutyCycle.ovData = HEATERS_MIN_DUTY_CYCLE; - heatersStatus[ heater ].dutyCycle.ovInitData = HEATERS_MIN_DUTY_CYCLE; - heatersStatus[ heater ].dutyCycle.override = OVERRIDE_RESET; + control[ heater ].data = HEATERS_MIN_DUTY_CYCLE; + control[ heater ].ovData = HEATERS_MIN_DUTY_CYCLE; + control[ heater ].ovInitData = HEATERS_MIN_DUTY_CYCLE; + control[ heater ].override = OVERRIDE_RESET; heatersStatus[ heater ].targetFlowLPM = 0.0F; heatersStatus[ heater ].nomTargetFlowLPM = 0.0F; heatersStatus[ heater ].hasTargetTempChanged = FALSE; - heatersStatus[ heater ].controlIntervalCounter = 0; heatersStatus[ heater ].isThisFirstControl = TRUE; heatersStatus[ heater ].prevDiaTargetFlowLPM = 0.0F; + setHeaterControl( heater ); } - // Initialize the primary controller PI controller - initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATER_P_COEFFICIENT, PRIMARY_HEATER_I_COEFFICIENT, - HEATERS_MIN_DUTY_CYCLE, HEATERS_MAX_DUTY_CYCLE ); + // Initialize the primary heater PI controller + initializePIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, D5_HEAT_TX_P_COEFFICIENT, D5_HEAT_TX_I_COEFFICIENT, + HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE, TRUE, D5_HEAT_TX_INIT_FEED_FORWARD ); // Initialize the trimmer heater PI controller - initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, TRIMMER_HEATER_I_COEFFICIENT, - HEATERS_MIN_DUTY_CYCLE, HEATERS_MAX_DUTY_CYCLE ); + initializePIController( PI_CONTROLLER_ID_D45_HEAT, HEATERS_MIN_DUTY_CYCLE, D45_HEAT_P_COEFFICIENT, D45_HEAT_I_COEFFICIENT, + HEATERS_MIN_DUTY_CYCLE, DC_HEATER_MAX_DUTY_CYCLE, FALSE, D45_HEAT_TX_INIT_FEED_FORWARD ); +#ifdef __HEATERS_DEBUG__ + for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) + { + pIControlSignal[ i ] = 0.0F; + } +#endif + // Initialize the persistent alarms - //initPersistentAlarm( ALARM_ID_DD_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, 0, HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ); - //initPersistentAlarm( ALARM_ID_DD_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, 0, HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ); - initPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_PRIMARY_HEATER_IS_ON, 0, PRIMARY_HEATER_ON_NO_FLUID_TIMEOUT_MS ); - initPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_TRIMMER_HEATER_IS_ON, 0, TRIMMER_HEATER_ON_NO_FLUID_TIMEOUT_MS ); + //initPersistentAlarm( ALARM_ID_DD_D5_HEAT_VOLTAGE_OUT_OF_RANGE, 0, HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ); + //initPersistentAlarm( ALARM_ID_DD_D45_HEAT_VOLTAGE_OUT_OF_RANGE, 0, HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D5_HEAT_IS_ON, 0, D5_HEAT_ON_NO_FLUID_TIMEOUT_MS ); + initPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D45_HEAT_IS_ON, 0, D45_HEAT_ON_NO_FLUID_TIMEOUT_MS ); } /*********************************************************************//** @@ -166,17 +248,25 @@ { BOOL result = FALSE; - if( heater < NUM_OF_DD_HEATERS ) + if ( heater < NUM_OF_DD_HEATERS ) { // Assume the target temperature has not changed heatersStatus[ heater ].hasTargetTempChanged = FALSE; // Check if the requested temperature is within the allowed range - if ( ( targetTemperature >= HEATER_TARGET_TEMPERATURE_MIN ) && ( targetTemperature <= HEATER_TARGET_TEMPERATURE_MAX ) ) + if ( ( ( targetTemperature >= HEATER_TARGET_TEMPERATURE_MIN ) && ( targetTemperature <= HEATER_TARGET_TEMPERATURE_MAX ) ) && + ( lastDialTargetTemperatureSet != targetTemperature ) ) { - heatersStatus[ heater ].targetTempC = targetTemperature; + targetTempC[ heater ].data = targetTemperature; heatersStatus[ heater ].hasTargetTempChanged = TRUE; result = TRUE; + lastDialTargetTemperatureSet = targetTemperature; + + if ( D5_HEAT == heater ) + { + startupHeaterControl = TRUE; + } + } } else @@ -192,17 +282,35 @@ * The getHeaterTargetTemperature function returns the given heater target * temperature. * @details \b Inputs: none - * @details \b Outputs: heaterStatus + * @details \b Outputs: targetTempC * @param heater: heater ID to get heater target temperature. * @return the given heater target temperature *************************************************************************/ F32 getHeaterTargetTemperature( DD_HEATERS_T heater ) { - return heatersStatus[ heater ].targetTempC; + F32 targetTemp = getF32OverrideValue( &targetTempC[ heater ] ); + + return targetTemp; } /*********************************************************************//** * @brief + * The getHeaterPWMPeriod function returns the given heater PWM + * period. + * @details \b Inputs: none + * @details \b Outputs: pwmPeriod + * @param heater: heater ID to get heater PWM period. + * @return the given heater PWM period. + *************************************************************************/ +F32 getHeaterPWMPeriod( DD_HEATERS_T heater ) +{ + F32 pwmPrd = getF32OverrideValue( &pwmPeriod[ heater ] ); + + return pwmPrd; +} + +/*********************************************************************//** + * @brief * The isHeaterOn function returns the given heater status whether * it is on or off * @details \b Inputs: heaterStatus @@ -217,31 +325,48 @@ /*********************************************************************//** * @brief + * The signalHeaterControlOnQDUpdate function updates heater control based on + * the latest treatment paratmeter (Dialysate Flow rate) change + * @details \b Inputs: heatersStatus + * @details \b Outputs: none + * @param heater: heater ID to update the heater control. + * @return none + *************************************************************************/ +void signalHeaterControlOnQDUpdate( DD_HEATERS_T heater ) +{ + if ( D5_HEAT == heater ) + { + // check heater state + if ( HEATER_EXEC_STATE_CONTROL_TO_TARGET == heatersStatus[ heater ].state ) + { + // Set flag to recalculate the feedforward signals + startupHeaterControl = TRUE; + } + } +} + +/*********************************************************************//** + * @brief * The startHeater function starts the given heater by setting the flag. * @details \b Inputs: heatersStatus * @details \b Outputs: startHeaterSignal * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid heater ID passed * @param heater: heater ID to set the heater start signal. - * @return status TRUE when heater start flag set otherwise, FALSE + * @return None *************************************************************************/ -BOOL startHeater( DD_HEATERS_T heater ) +void startHeater( DD_HEATERS_T heater ) { - BOOL status = FALSE; - if( heater < NUM_OF_DD_HEATERS ) { if ( HEATER_EXEC_STATE_OFF == heatersStatus[ heater ].state ) { heatersStatus[ heater ].startHeaterSignal = TRUE; - status = TRUE; } } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_INVALID_HEATER_ID_SELECTED, heater ) } - - return status; } /*********************************************************************//** @@ -258,13 +383,24 @@ { if( heater < NUM_OF_DD_HEATERS ) { - heatersStatus[ heater ].startHeaterSignal = FALSE; - heatersStatus[ heater ].heaterOnState = FALSE; - heatersStatus[ heater ].dutyCycle.data = HEATERS_MIN_DUTY_CYCLE; - heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; + heatersStatus[ heater ].startHeaterSignal = FALSE; + heatersStatus[ heater ].heaterOnState = FALSE; + control[ heater ].data = HEATERS_MIN_DUTY_CYCLE; + heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; + //Update control interval counter + if ( D5_HEAT == heater ) + { + heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; + startupHeaterControl = TRUE; + } + else + { + heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; + } + // update duty cycle - setHeaterDutyCycle( heater ); + setHeaterControl( heater ); } else { @@ -287,13 +423,6 @@ for ( heater = DD_HEATERS_FIRST; heater < NUM_OF_DD_HEATERS; heater++ ) { - // Check if the heater is requested to be off - if ( FALSE == heatersStatus[ heater ].heaterOnState ) - { - // stop the heater - stopHeater( heater ); - } - switch( heatersStatus[ heater ].state ) { case HEATER_EXEC_STATE_OFF: @@ -318,6 +447,12 @@ SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_INVALID_EXEC_STATE, heater ); break; } + // Check if the heater is requested to be off + if ( FALSE == heatersStatus[ heater ].heaterOnState ) + { + // stop the heater + stopHeater( heater ); + } } } @@ -344,29 +479,29 @@ ALARM_ID_T alarm; BOOL isLevelLow = FALSE; - switch ( heater ) + if ( D5_HEAT == heater ) { - case DD_PRIMARY_HEATER: - alarm = ALARM_ID_DD_FLUID_TOO_LOW_WHILE_PRIMARY_HEATER_IS_ON; - isLevelLow = ( ( getLevelStatus( FLOATER_1 ) != 0 )? FALSE : TRUE ); - break; - - case DD_TRIMMER_HEATER: - alarm = ALARM_ID_DD_FLUID_TOO_LOW_WHILE_TRIMMER_HEATER_IS_ON; - isLevelLow = ( ( getLevelStatus( SPENT_DIALYSATE_LEVEL ) != 0 )? FALSE : TRUE ); - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_INVALID_HEATER_ID_SELECTED, heater ) - break; + alarm = ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D5_HEAT_IS_ON; + isLevelLow = ( ( getLevelStatus( D6_LEVL ) != 0 )? FALSE : TRUE ); } + else + { + alarm = ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D45_HEAT_IS_ON; + isLevelLow = ( ( getLevelStatus( D46_LEVL ) != 0 )? FALSE : TRUE ); + } checkPersistentAlarm( alarm, isLevelLow, 0.0F, 0.0F ); } else { - checkPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_PRIMARY_HEATER_IS_ON, FALSE, 0.0F, 0.0F ); - checkPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_TRIMMER_HEATER_IS_ON, FALSE, 0.0F, 0.0F ); + if ( D5_HEAT == heater ) + { + checkPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D5_HEAT_IS_ON, FALSE, 0.0F, 0.0F ); + } + else + { + checkPersistentAlarm( ALARM_ID_DD_FLUID_TOO_LOW_WHILE_D45_HEAT_IS_ON, FALSE, 0.0F, 0.0F ); + } } } @@ -395,7 +530,7 @@ heatersStatus[ heater ].heaterOnState = TRUE; heatersStatus[ heater ].startHeaterSignal = FALSE; - // proceed to ramp state + // proceed to setup state state = HEATER_EXEC_STATE_RAMP_TO_TARGET; } @@ -408,29 +543,71 @@ * control while they are ramping to target temperature. * @details \b Inputs: heaterStatus * @details \b Outputs: heaterStatus - * @param heater: The heater Id to handle the ramping up to target temp. + * @param heater: The heater Id to handle the initial setup control for heater. * @return next state of the state machine *************************************************************************/ static HEATERS_STATE_T handleHeaterStateRampToTarget( DD_HEATERS_T heater ) { - HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; - F32 dutyCycle = 0.0F; - DD_OP_MODE_T opMode = getCurrentOperationMode(); + HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; + F32 ctrl = 0.0F; + DD_OP_MODE_T opMode = getCurrentOperationMode(); + F32 measuredTemperature = 0.0F; + F32 targetTemperature = getHeaterTargetTemperature( heater ); - if ( DD_MODE_HEAT != opMode ) + if ( D5_HEAT == heater ) { - dutyCycle = ( ( heatersStatus[ heater ].targetTempC / HEATER_TARGET_TEMPERATURE_MAX ) * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR ) + FLOAT_TO_INT_ROUNDUP_OFFSET; - state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; + measuredTemperature = getD4AverageTemperature(); + + if ( DD_MODE_HEAT != opMode ) + { + F32 deltaTempC = measuredTemperature - targetTemperature; + F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); + + if ( capDeltaTempC >= HEATER_CNTL_TRANSFER_DELTA_TEMP_C ) + { + // Transfer Control to target when delta temp is minimal. + state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; + } + else + { + // Start Open loop control with max power + control[ heater ].data = AC_HEATER_TX_MAX_DUTY_CYCLE; + } + } + else + { + // TODO : Calculate required duty cycle + state = HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET; + } } else { - // TODO : Calculate required duty cycle - state = HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET; + measuredTemperature = getD50AverageTemperature(); + + if ( DD_MODE_HEAT != opMode ) + { + F32 deltaTempC = targetTemperature - measuredTemperature; + F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); + F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; + F32 dutyCycle = calculateDutyCycle( flowrate, capDeltaTempC, TRIMMER_HEATER_MAX_PWR_WATTS, DC_HEATER_EFFICIENCY, + HEATERS_MIN_DUTY_CYCLE, DC_HEATER_MAX_DUTY_CYCLE ); + + control[ heater ].data = dutyCycle; + resetPIController( PI_CONTROLLER_ID_D45_HEAT, dutyCycle, D45_HEAT_TX_INIT_FEED_FORWARD ); + + state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; + } + else + { + // TODO : Calculate required duty cycle + state = HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET; + } + + // Update the duty cycle + control[ heater ].data = ctrl; } - // Update the duty cycle - heatersStatus[ heater ].dutyCycle.data = dutyCycle; - setHeaterDutyCycle( heater ); + setHeaterControl( heater ); return state; } @@ -448,34 +625,69 @@ static HEATERS_STATE_T handleHeaterStateControlToTarget( DD_HEATERS_T heater ) { HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - F32 targetTemperature = heatersStatus[ heater ].targetTempC; + F32 targetTemperature = getHeaterTargetTemperature( heater ); + F32 inletTemperature = 0.0F; F32 measuredTemperature = 0.0F; - F32 dutyCycle = 0.0F; + F32 ctrl = 0.0F; - if( ++heatersStatus[ heater ].controlIntervalCounter > PRIMARY_HEATER_CONTROL_INTERVAL_COUNT ) + if ( ++heatersStatus[ heater ].controlIntervalCounter >= controlInterval[ heater ] ) { - switch ( heater ) + if ( D5_HEAT == heater ) { - case DD_PRIMARY_HEATER: - measuredTemperature = getTemperatureValue( (U32)TEMPSENSORS_HYDRAULICS_PRIMARY_HEATER ); - dutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, targetTemperature, measuredTemperature ); - break; + measuredTemperature = getD4AverageTemperature(); + // Inlet temperature post heat exchanger + inletTemperature = getTemperatureValue( X6_TEMP ); - case DD_TRIMMER_HEATER: - measuredTemperature = getTemperatureValue( (U32)TEMPSENSORS_TRIMMER_HEATER ); - dutyCycle = runPIController( PI_CONTROLLER_ID_TRIMMER_HEATER, targetTemperature, measuredTemperature ); - break; + if ( TRUE == startupHeaterControl ) + { + startupHeaterControl = FALSE; + F32 deltaTempC = targetTemperature - inletTemperature; + F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); + F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; + F32 feedforward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, AC_HEATER_EFFICIENCY, + HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); + control[ heater ].data = feedforward; + resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); + } + else + { + F32 deltaTempC = fabs( targetTemperature - measuredTemperature ); - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_INVALID_HEATER_ID_SELECTED, heater ) - break; + if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) + { + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); + control[ heater ].data = ctrl; + } + } +#ifdef __HEATERS_DEBUG__ + U32 i; + + for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) + { + pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D5_HEAT, (PI_CONTROLLER_SIGNALS_ID)i ); + } +#endif } + else + { + measuredTemperature = getD50AverageTemperature(); + ctrl = runPIController( PI_CONTROLLER_ID_D45_HEAT, targetTemperature, measuredTemperature ); + control[ heater ].data = ctrl; +//#ifdef __HEATERS_DEBUG__ +// U32 i; +// +// for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) +// { +// pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D45_HEAT, (PI_CONTROLLER_SIGNALS_ID)i ); +// } +//#endif + } + heatersStatus[ heater ].hasTargetTempChanged = FALSE; - heatersStatus[ heater ].dutyCycle.data = ( dutyCycle * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR ) + FLOAT_TO_INT_ROUNDUP_OFFSET; heatersStatus[ heater ].controlIntervalCounter = 0; - setHeaterDutyCycle( heater ); + setHeaterControl( heater ); } return state; @@ -497,37 +709,42 @@ //TODO : update dutycycle for the heat disinfect state - setHeaterDutyCycle( DD_TRIMMER_HEATER ); - setHeaterDutyCycle( DD_PRIMARY_HEATER ); + setHeaterControl( D45_HEAT ); + setHeaterControl( D5_HEAT ); return state; } /*********************************************************************//** * @brief - * The setHeaterDutyCycle function sets the duty cycle of a heater. - * @details \b Inputs: dutyCycle + * The setHeaterControl function sets the duty cycle of a heater. + * @details \b Inputs: control * @details \b Outputs: FPGA heater control * @details \b Alarms: ALARM_ID_DD_SOFTWARE_FAULT when invalid heater ID * is selected. * @param heater: The heater Id that its duty cycle is set * @return none *************************************************************************/ -static void setHeaterDutyCycle( DD_HEATERS_T heater ) +static void setHeaterControl( DD_HEATERS_T heater ) { if ( heater < NUM_OF_DD_HEATERS ) { - F32 duty; + F32 control = getHeaterControl( heater ); + F32 period = getHeaterPWMPeriod ( heater ); - duty = getHeaterDutyCycle( heater ); - - if ( DD_PRIMARY_HEATER == heater ) + if ( D5_HEAT == heater ) { - setFPGAPrimaryHeaterPWMControl( (U08)duty ); + //Convert duty cycle into LowState and multiply by period + F32 duty = AC_HEATER_MAX_DUTY_CYCLE - control; + convertDC = duty * period; + + setFPGAD5HeaterPWMPeriod( (U16)period ); + setFPGAD5HeaterPWMLowState( (U16)convertDC ); } else { - setFPGATrimmerHeaterPWMControl( (U08)duty ); + U08 ctrl = ( control * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR ) + FLOAT_TO_INT_ROUNDUP_OFFSET; + setFPGAD45HeaterPWMControl( ctrl ); } } else @@ -538,27 +755,58 @@ /*********************************************************************//** * @brief - * The getHeaterDutyCycle function returns the heater's duty cycle. + * The getHeaterControl function returns the heater's duty cycle. * @details \b Inputs: heaterStatus * @details \b Outputs: none * @param heater: The heater Id to get the duty cycle. * @return PWM duty cycle for the given heater *************************************************************************/ -static F32 getHeaterDutyCycle( DD_HEATERS_T heater ) +static F32 getHeaterControl( DD_HEATERS_T heater ) { - F32 duty = getF32OverrideValue( &heatersStatus[ heater ].dutyCycle ); + F32 duty = getF32OverrideValue( &control[ heater ] ); return duty; } /*********************************************************************//** * @brief + * The calculateDutyCycle function calculates the heater's duty cycle + * based on the delta temperature, flowrate and power applied to the heater. + * @details \b Inputs: none + * @details \b Outputs: duty cycle + * @param flowrate: dialysate flowrate. + * @param deltaTemp: Temperature difference between actual and target. + * @param power: Power supplied to the heater + * @param efficiency: Heater efficeincy to compensate heatloss + * @param min: heaters minimum duty cycle + * @param max: heaters maximum duty cycle + * @return calcualted PWM duty cycle + *************************************************************************/ +static F32 calculateDutyCycle( F32 flowrate, F32 deltaTemp, F32 power, F32 efficiency, F32 min, F32 max ) +{ + F32 duty = ( WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * deltaTemp * flowrate ) / power; + + // Updated duty with efficiency + if ( HEATERS_ZERO_EFFICIENCY != efficiency ) + { + duty = duty / efficiency; + } + + // Apply min/max limits + duty = MIN( duty, max ); + duty = MAX( duty, min ); + + return duty; +} + +/*********************************************************************//** + * @brief * The monitorHeatersVoltage function monitors the heaters' voltages * @details \b Inputs: Voltage range * @details \b Outputs: none - * @details \b Alarms: ALARM_ID_DD_MAIN_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE when + * @details \b Alarms: ALARM_ID_DD_MAIN_D5_HEAT_VOLTAGE_OUT_OF_RANGE when * primary heater voltage found out of range. - * @details \b Alarms: ALARM_ID_DD_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE when + * @details \b Alarms: ALARM_ID_D45_HEAT_VOLTAGE_OUT_OF_RANGE when * trimmer heater voltage found out of range. * @return none *************************************************************************/ @@ -568,8 +816,8 @@ // F32 trimmerVoltage = getMonitoredLineLevel( MONITORED_LINE_24V_GND_TRIM_HTR_V ); // // // Voltage to PWM is reverse. If PWM = 0 -> V = 24V -// F32 mainPriDC = getHeaterDutyCycle( DD_PRIMARY_HEATER ); -// F32 trimmerDC = getHeaterDutyCycle( DD_TRIMMER_HEATER ); +// F32 mainPriDC = getHeaterControl( D5_HEAT ); +// F32 trimmerDC = getHeaterControl( D45_HEAT ); // // // The expected voltage is the inverse of the duty cycle // F32 mainPriExpectedVoltage = HEATERS_MAX_OPERATING_VOLTAGE_V * ( 1.0F - mainPriDC ); @@ -579,15 +827,15 @@ // BOOL isTrimmerOut = FALSE; // // // If the system is DVT, check the FPGA persistent alarm of the main primary heater's voltage ADC -// checkFPGAPersistentAlarms( FPGA_PERS_ERROR_MAIN_PRIMARY_HEATER_VOLTAGE_ADC, getFPGAHeaterGateADCReadCount() ); +// checkFPGAPersistentAlarms( FPGA_PERS_ERROR_MAIN_D5_HEAT_VOLTAGE_ADC, getFPGAHeaterGateADCReadCount() ); // // isMainPriOut = ( fabs( mainPriExpectedVoltage - mainPriVoltage ) > HEATERS_VOLTAGE_TOLERANCE_V ? TRUE : FALSE ); // isTrimmerOut = ( fabs( trimmerExpectedVoltage - trimmerVoltage ) > HEATERS_VOLTAGE_TOLERANCE_V ? TRUE : FALSE ); // // if ( getCurrentOperationMode() != DD_MODE_INIT ) // { -// checkPersistentAlarm( ALARM_ID_DD_MAIN_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, isMainPriOut, mainPriDC, HEATERS_VOLTAGE_TOLERANCE_V ); -// checkPersistentAlarm( ALARM_ID_DD_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, isTrimmerOut, trimmerDC, HEATERS_VOLTAGE_TOLERANCE_V ); +// checkPersistentAlarm( ALARM_ID_DD_MAIN_D5_HEAT_VOLTAGE_OUT_OF_RANGE, isMainPriOut, mainPriDC, HEATERS_VOLTAGE_TOLERANCE_V ); +// checkPersistentAlarm( ALARM_ID_D45_HEAT_VOLTAGE_OUT_OF_RANGE, isTrimmerOut, trimmerDC, HEATERS_VOLTAGE_TOLERANCE_V ); // } //} @@ -607,14 +855,30 @@ { HEATERS_DATA_T data; - data.mainPrimayHeaterDC = getHeaterDutyCycle( DD_PRIMARY_HEATER ) * FRACTION_TO_PERCENT_FACTOR; - data.trimmerHeaterDC = getHeaterDutyCycle( DD_TRIMMER_HEATER ) * FRACTION_TO_PERCENT_FACTOR; - data.primaryTargetTemp = heatersStatus[ DD_PRIMARY_HEATER ].targetTempC; - data.trimmerTargetTemp = heatersStatus[ DD_TRIMMER_HEATER ].targetTempC; - data.primaryHeaterState = heatersStatus[ DD_PRIMARY_HEATER ].state; - data.trimmerHeaterState = heatersStatus[ DD_TRIMMER_HEATER ].state; - data.primaryControlCounter = heatersStatus[ DD_PRIMARY_HEATER ].controlIntervalCounter; - data.trimmerControlCounter = heatersStatus[ DD_TRIMMER_HEATER ].controlIntervalCounter; + data.d5_HeaterDC = getHeaterControl( D5_HEAT ) * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; + data.d45_HeaterDC = getHeaterControl( D45_HEAT ) * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; + data.d5_HeaterTargetTemp = getHeaterTargetTemperature( D5_HEAT ); + data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); + data.d5_HeaterState = heatersStatus[ D5_HEAT ].state; + data.d45_HeaterState = heatersStatus[ D45_HEAT ].state; +#ifndef __HEATERS_DEBUG__ + data.d5_HeaterControlCounter = heatersStatus[ D5_HEAT ].controlIntervalCounter; + data.d45_HeaterControlCounter = heatersStatus[ D45_HEAT ].controlIntervalCounter; +#else + data.d5_HeaterControlCounter = (U32)convertDC; + data.d45_HeaterControlCounter = (U32)getHeaterPWMPeriod( D5_HEAT ); +#endif +#ifdef __HEATERS_DEBUG__ + data.dbg1 = pIControlSignal[ 0 ]; + data.dbg2 = pIControlSignal[ 1 ]; + data.dbg3 = pIControlSignal[ 2 ]; + data.dbg4 = pIControlSignal[ 3 ]; + data.dbg5 = pIControlSignal[ 4 ]; + data.dbg6 = pIControlSignal[ 5 ]; + data.dbg7 = pIControlSignal[ 6 ]; + data.dbg8 = pIControlSignal[ 7 ]; + data.dbg9 = pIControlSignal[ 8 ]; +#endif dataPublicationTimerCounter = 0; @@ -657,9 +921,91 @@ *************************************************************************/ BOOL testHeaterDutyCycleOverride( MESSAGE_T *message ) { - BOOL result = f32ArrayOverride( message, &heatersStatus[0].dutyCycle, NUM_OF_DD_HEATERS - 1 ); + BOOL result = f32ArrayOverride( message, &control[ 0 ], NUM_OF_DD_HEATERS - 1 ); return result; } +/*********************************************************************//** + * @brief + * The testHeaterTargetTemperatureOverride function overrides the specified heater's + * target temperature. + * @details \b Inputs: targetTempC + * @details \b Outputs: targetTempC + * @param message Override message from Dialin which includes an ID of + * the heater to override and the target temperature of the heater. + * @return TRUE if the override was successful otherwise FALSE + *************************************************************************/ +BOOL testHeaterTargetTemperatureOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &targetTempC[ 0 ], NUM_OF_DD_HEATERS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testHeaterPWMPeriodOverride function overrides the specified heater's + * PWM period. + * @details \b Inputs: pwmPeriod + * @details \b Outputs: pwmPeriod + * @param message Override message from Dialin which includes an ID of + * the heater to override and the PWM period of the heater. + * @return TRUE if the override was successful otherwise FALSE + *************************************************************************/ +BOOL testHeaterPWMPeriodOverride( MESSAGE_T *message ) +{ + BOOL result = f32ArrayOverride( message, &pwmPeriod[ 0 ], NUM_OF_DD_HEATERS - 1 ); + + return result; +} + +/*********************************************************************//** + * @brief + * The testHeaterStartStopOverride function starts/stops a given heater + * at mentioned temperature. + * @details \b Inputs: tester logged in + * @details \b Outputs: heatersStatus[] + * @param message set message from Dialin which includes the heater to set + * and the state to set the heater to. + * @return TRUE if set request is successful, FALSE if not + *************************************************************************/ +BOOL testHeaterStartStopOverride( MESSAGE_T *message ) +{ + BOOL result = FALSE; + + // Verify tester has logged in with DD + if ( TRUE == isTestingActivated() ) + { + // Verify payload length is valid + if ( sizeof( HEATER_START_CMD_PAYLOAD_T ) == message->hdr.payloadLen ) + { + HEATER_START_CMD_PAYLOAD_T payload; + + memcpy( &payload, message->payload, sizeof(HEATER_START_CMD_PAYLOAD_T) ); + + if ( (DD_HEATERS_T)payload.heaterID < NUM_OF_DD_HEATERS ) + { + // Handle start command + if ( ( TRUE == payload.startStop ) && + ( ( payload.temperature >= HEATER_TARGET_TEMPERATURE_MIN ) && ( payload.temperature <= HEATER_TARGET_TEMPERATURE_MAX ) ) ) + { + setHeaterTargetTemperature( (DD_HEATERS_T)payload.heaterID, payload.temperature ); + startHeater( (DD_HEATERS_T)payload.heaterID ); + result = TRUE; + } + + //Handle stop command + if ( FALSE == payload.startStop ) + { + stopHeater( (DD_HEATERS_T)payload.heaterID ); + result = TRUE; + } + } + } + } + + return result; +} + /**@}*/