Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rae31b4c999dccae70fb40fb9d98a4380ce2c7415 -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision ae31b4c999dccae70fb40fb9d98a4380ce2c7415) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -55,7 +55,6 @@ #define HEATER_CNTL_TRANSFER_DELTA_TEMP_C 0.50F ///< AC heater delta temperature to transfer control from open to close loop #define ADJ_DELTA_TEMP_STEP 2.0F ///< Adjust target temperature based on D28 feedback per cycle. #define MAX_ADJ_DELTA_TEMP_C 7.0F ///< Maximum adjusted delta temperature to add/remove from calculated target temperature - #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. @@ -78,26 +77,43 @@ #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 D5_HEATER_DEADBAND_CONTROL 0.1F ///< Heater deadband range for conrtol. +#define D5_HEATER_DEADBAND_CONTROL 0.1F ///< Heater dead band range for control. +#define D5_HEATER_PWM_ADJ_SLOPE_FACTOR 0.00005F ///< AC heater close loop PWM adjustment slope factor +#define D5_HEATER_PWM_INTERCEPT_FACTOR 0.0055F ///< AC heater close loop PWM adjustment intercept factor //#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 D5_TARGET_TEMP_ADJUST_INTERVAL_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature -#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 D5_TARGET_TEMP_ADJUST_LOW_QD_INTERVAL ( 3 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature - outer loop control interval for low Qd. +#define D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL ( 1 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature - outer loop control interval for high Qd. +#define PRIMARY_HEATER_MAX_PWR_WATTS 1400.0F ///< AC Primary Heater Max Power consumption in Watts +#define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatment 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_PWM_PERIOD 10000 ///< PWM period 100ms( in 10us resolution), 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 RINSE_PUMP_EST_FLOWRATE 110 ///< Estimated rinse pump flow rate #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. +#define AC_HEAT_EFFICIENCY_LOW 0.1F ///< Lower allowable range for heater efficiency adjustment +#define AC_HEAT_EFFICIENCY_HIGH 10.0F ///< higher allowable range for heater efficiency adjustment +#define AC_HEAT_PWM_ADJUST_PERCENT 0.5F ///< AC heater PWM gain adjustment percentage for close loop control +#define AC_HEAT_PWM_ADJ_MIN -0.10F ///< Minimum PWM value that can adjust the calculated Feed forward value +#define AC_HEAT_PWM_ADJ_MAX 0.10F ///< Maximum PWM value that can adjust the calculated Feed forward value +#define AC_HEAT_PWM_MIN_MAX_FACTOR 2.0F ///< factor used to calculate range values for PWM adjustment +#define D5_HEAT_OUT_TX_P_COEFFICIENT 0.5F ///< P Term for AC primary heater outer loop control during treatment mode. +#define D5_HEAT_OUT_TX_I_COEFFICIENT 0.40F ///< I Term for AC primary heater outer loop control during treatment mode. +#define D5_HEAT_OUT_MIN_DELTA_TEMP 0.0F ///< Minimum Delta temperature that can be adjusted for D5 control +#define D5_HEAT_OUT_MAX_DELTA_TEMP 50.0 ///< Maximum Delta temperature that can be adjusted for D5 control +#define D5_HEAT_OUT_DEADBAND_CONTROL 0.1F ///< Heater outer loop dead band range for control. +#define HIGH_DIAL_FLOW_RATE 300.0F ///< Decide outer loop heater control based on the dialysate flow rate + //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 @@ -126,7 +142,7 @@ 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 control[ NUM_OF_DD_HEATERS ]; ///< Heater control ( Primary : On/Off, Trimmer : Duty cycle). 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. @@ -137,8 +153,12 @@ 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 d5Efficiency; ///< AC heater efficiency factor. +static F32 adjustD5PWM; ///< AC heater close loop PWM adjustment +static F32 capAdjustD5PWM; ///< AC heater PWM adjustment after range check static F32 lastDialTargetTemperatureSet[ NUM_OF_DD_HEATERS ]; ///< last dialysate target temperature set for heater control -static BOOL startupHeaterControl; ///< First time control with the energy equation. +static F32 d5FeedForward; ///< AC heater feed forward calculated value +static U32 d5OuterLoopControlInterval; ///< AC heater outer loop control valve //For testing #ifdef __HEATERS_DEBUG__ @@ -196,15 +216,19 @@ convertDC = 0.0F; controlInterval[ D5_HEAT ] = D5_HEAT_CONTROL_INTERVAL_COUNT; controlInterval[ D45_HEAT ] = D45_HEAT_CONTROL_INTERVAL_COUNT; + d5OuterLoopControlInterval = D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL; // 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[ D5_HEAT ] = 0.0F; lastDialTargetTemperatureSet[ D45_HEAT ] = 0.0F; primaryTargetTempAdjCounter = 0; adjustedPrimaryTargetTemp = 0.0F; + d5Efficiency = AC_HEATER_EFFICIENCY; + adjustD5PWM = 0.0F; + capAdjustD5PWM = 0.0F; + d5FeedForward = 0.0F; isTargetTempAdjusted = FALSE; isDialyzerTempFeedbackEnabled = TRUE; @@ -233,6 +257,9 @@ 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 ); + initializePIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, D5_HEAT_OUT_MIN_DELTA_TEMP, D5_HEAT_OUT_TX_P_COEFFICIENT, D5_HEAT_OUT_TX_I_COEFFICIENT, + D5_HEAT_OUT_MIN_DELTA_TEMP, D5_HEAT_OUT_MAX_DELTA_TEMP, TRUE, D5_HEAT_TX_INIT_FEED_FORWARD ); + // Initialize the trimmer heater PI controller 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 ); @@ -281,11 +308,6 @@ heatersStatus[ heater ].hasTargetTempChanged = TRUE; result = TRUE; lastDialTargetTemperatureSet[ heater ] = targetTemperature; - - if ( D5_HEAT == heater ) - { - startupHeaterControl = TRUE; - } } } else @@ -371,9 +393,11 @@ // check heater state if ( HEATER_EXEC_STATE_CONTROL_TO_TARGET == heatersStatus[ heater ].state ) { - // Set flag to recalculate the feedforward signals - startupHeaterControl = TRUE; + // Reset the adjusted temperature target isTargetTempAdjusted = FALSE; + + // Reset the AC heater PWM adjustment + adjustD5PWM = HEATERS_MIN_DUTY_CYCLE; } } } @@ -402,7 +426,7 @@ *************************************************************************/ static void updatePrimaryHeaterTargetTemp( void ) { - if ( ++primaryTargetTempAdjCounter >= D5_TARGET_TEMP_ADJUST_INTERVAL_MS ) + if ( ++primaryTargetTempAdjCounter >= d5OuterLoopControlInterval ) { F32 targetTempfromTD = getTDTargetDialysateTemperature(); F32 measuredTempAtDialyzer = 0.0F; @@ -420,7 +444,9 @@ F32 dialysateFlowrate = getTDDialysateFlowrate(); F32 deltaTempC = targetTempfromTD - measuredTempAtDialyzer; F32 capDeltaTempC = MIN( fabs(deltaTempC), ADJ_DELTA_TEMP_STEP ); + F32 ctrl = 0.0F; +#if 0 //Assign the initial calcualted temp for adjsutment if ( FALSE == isTargetTempAdjusted ) { @@ -453,6 +479,21 @@ isTargetTempAdjusted = TRUE; primaryTargetTempAdjCounter = 0; +#else + if ( FALSE == isTargetTempAdjusted ) + { + isTargetTempAdjusted = TRUE; + adjustedPrimaryTargetTemp = calcTargetTemp; + resetPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, calcTargetTemp, HEATERS_MIN_DUTY_CYCLE ); + } + else if ( fabs(deltaTempC) >= D5_HEAT_OUT_DEADBAND_CONTROL ) + { + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, targetTempfromTD, measuredTempAtDialyzer ); + adjustedPrimaryTargetTemp = ctrl; + } + + primaryTargetTempAdjCounter = 0; +#endif } } @@ -503,7 +544,6 @@ if ( D5_HEAT == heater ) { heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; - startupHeaterControl = TRUE; } else { @@ -663,6 +703,7 @@ F32 ctrl = 0.0F; DD_OP_MODE_T opMode = getCurrentOperationMode(); F32 measuredTemperature = 0.0F; + F32 feedforward = 0.0F; F32 targetTemperature = getHeaterTargetTemperature( heater ); if ( D5_HEAT == heater ) @@ -676,6 +717,10 @@ if ( capDeltaTempC >= HEATER_CNTL_TRANSFER_DELTA_TEMP_C ) { + // Reset PI Controllers with + resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); + resetPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, targetTemperature, HEATERS_MIN_DUTY_CYCLE ); + // Transfer Control to target when delta temp is minimal. state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; } @@ -737,10 +782,14 @@ { HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; F32 targetTemperature = getHeaterTargetTemperature( heater ); - F32 inletTemperature = 0.0F; F32 measuredTemperature = 0.0F; F32 ctrl = 0.0F; - +#if 0 + F32 d5_eff = 0.0F; + F32 d5_p_gain = 0.0F; + F32 d5_final_FF = 0.0F; + F32 d5_cap_final_FF = 0.0F; +#endif // Update primary heater target temperature at defined interval if ( D5_HEAT == heater ) { @@ -751,64 +800,92 @@ { if ( D5_HEAT == heater ) { - measuredTemperature = getD4AverageTemperature(); // Inlet temperature post heat exchanger - inletTemperature = getTemperatureValue( D78_TEMP ); + F32 inletTemperature = getD78AverageTemperature(); + F32 deltaTempC = targetTemperature - inletTemperature; + F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); + F32 flowrate = ( getTDDialysateFlowrate() + RINSE_PUMP_EST_FLOWRATE ) / LITER_IN_ML ; + d5FeedForward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, d5Efficiency, + HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); - if ( TRUE == startupHeaterControl ) + //Update the calculated feed forward value + setPIControllerFeedForward( PI_CONTROLLER_ID_D5_HEAT, d5FeedForward ); + + // decide outer loop control interval based on the Qd + flowrate = getTDDialysateFlowrate(); + d5OuterLoopControlInterval = ( flowrate >= HIGH_DIAL_FLOW_RATE ? D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL : D5_TARGET_TEMP_ADJUST_LOW_QD_INTERVAL ); + + // If D28 feedback control is enabled and adjusted temp calculation is done + // then update the target temperature. + if ( ( TRUE == isTargetTempAdjusted ) && ( TRUE == isDialyzerTempFeedbackEnabled ) ) { - 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 ); - startupHeaterControl = FALSE; - control[ heater ].data = feedforward; - resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); + targetTemperature = adjustedPrimaryTargetTemp; } - else +#if 1 + measuredTemperature = getD4AverageTemperature(); + deltaTempC = fabs( targetTemperature - measuredTemperature ); + + if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) { - F32 deltaTempC = 0.0F; + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); + control[ heater ].data = ctrl; + } +#else + measuredTemperature = getD4AverageTemperature(); + deltaTempC = targetTemperature - measuredTemperature; + capDeltaTempC = fabs(deltaTempC); + d5_p_gain = ( D5_HEATER_PWM_ADJ_SLOPE_FACTOR * getTDDialysateFlowrate() ) + D5_HEATER_PWM_INTERCEPT_FACTOR; - // If D28 feedback control is enabled and adjusted temp calculation is done - // then update the target temperature. - if ( ( TRUE == isTargetTempAdjusted ) && ( TRUE == isDialyzerTempFeedbackEnabled ) ) + if ( d5FeedForward > NEARLY_ZERO ) + { + if ( capDeltaTempC >= D5_HEATER_DEADBAND_CONTROL ) { - targetTemperature = adjustedPrimaryTargetTemp; - } - deltaTempC = fabs( targetTemperature - measuredTemperature ); + F32 minAdjPWM = -(d5_p_gain * AC_HEAT_PWM_MIN_MAX_FACTOR); + F32 maxAdjPWM = d5_p_gain * AC_HEAT_PWM_MIN_MAX_FACTOR; - if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) - { - ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); - control[ heater ].data = ctrl; + // Compute the PWM adjustment with 50% gain adjustment + adjustD5PWM += ( d5_p_gain * AC_HEAT_PWM_ADJUST_PERCENT * deltaTempC ); + adjustD5PWM = RANGE(adjustD5PWM, minAdjPWM, maxAdjPWM ); } } -//#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(); + else + { + //When feed forward produces zero PWM, no adjustment is needed + adjustD5PWM = HEATERS_MIN_DUTY_CYCLE; + } - ctrl = runPIController( PI_CONTROLLER_ID_D45_HEAT, targetTemperature, measuredTemperature ); - control[ heater ].data = ctrl; + // Update the feed forward PWM with the close loop adjustment + d5_final_FF = d5FeedForward + adjustD5PWM; + d5_cap_final_FF = RANGE(d5_final_FF,HEATERS_MIN_DUTY_CYCLE,AC_HEATER_TX_MAX_DUTY_CYCLE ); + + // assign the feed forward control + control[ heater ].data = d5_cap_final_FF; +#endif #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 ); + pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, (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 ].controlIntervalCounter = 0; @@ -989,7 +1066,7 @@ data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); data.d5_HeaterState = heatersStatus[ D5_HEAT ].state; data.d45_HeaterState = heatersStatus[ D45_HEAT ].state; - data.d5_dutyCycleCnt = convertDC; + data.d5_feedforward = d5FeedForward * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; data.d5_PWMPeriod = getHeaterPWMPeriod( D5_HEAT ); data.d5_adjsutedTargetTemp = adjustedPrimaryTargetTemp; data.d5_targetTempFromTD = getTDTargetDialysateTemperature(); @@ -1004,7 +1081,6 @@ data.dbg8 = pIControlSignal[ 7 ]; data.dbg9 = pIControlSignal[ 8 ]; #endif - dataPublicationTimerCounter = 0; broadcastData( MSG_ID_DD_HEATERS_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( HEATERS_DATA_T ) ); Index: firmware/App/DDCommon.h =================================================================== diff -u -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/DDCommon.h (.../DDCommon.h) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) +++ firmware/App/DDCommon.h (.../DDCommon.h) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -7,8 +7,8 @@ * * @file DDCommon.h * -* @author (last) Sameer Kalliadan Poyil -* @date (last) 10-Feb-2026 +* @author (last) Jashwant Gantyada +* @date (last) 13-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 07-Aug-2024 @@ -25,7 +25,7 @@ #define DD_VERSION_MAJOR 0 #define DD_VERSION_MINOR 0 #define DD_VERSION_MICRO 0 -#define DD_VERSION_BUILD 47 +#define DD_VERSION_BUILD 92 // ********** development build switches ********** @@ -48,19 +48,15 @@ //Uncomment below for bicarb chamber filling //#define __BICARB_CHAMBER_FILL__ 1 -//Uncomment below for Maxon controller speed change -#define __MAXON_SPEED_UPDATE__ 1 +//UnComment below for DryBicarb testing +//#define __DRY_BICARB__ 1 //Uncomment below to disable heaters debug message #define __HEATERS_DEBUG__ 1 -//Uncomment below to disable Teensy conductivity driver -#define __TEENSY_CONDUCTIVITY_DRIVER__ 1 - //Uncomment below to disable revised heater model #define __REVISED_HEATER_MODEL__ 1 - #include #include #endif Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -7,14 +7,14 @@ * * @file ModeGenDialysate.c * -* @author (last) Vinayakam Mani -* @date (last) 11-Feb-2026 +* @author (last) Dara Navaei +* @date (last) 18-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 06-Nov-2024 * ***************************************************************************/ -#include "math.h" // for 'exp' +#include // For ceilf #include "BalancingChamber.h" #include "ConcentratePumps.h" @@ -34,6 +34,7 @@ #include "TaskGeneral.h" #include "TDInterface.h" #include "Temperature.h" +#include "TestSupport.h" #include "Timers.h" #include "Ultrafiltration.h" #include "Valves.h" @@ -64,6 +65,10 @@ #define ZERO_DIAL_FLOW_RATE 0.0F ///< Zero dialysate flow rate #define SPENT_CHAMBER_FILL_MAX_COUNT 10 ///< Total number of spent chamber fill allowed. #define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. +#define PUMP_SPEED_SLOPE_FACTOR_DIENER_2000 1.24F ///< D48 Diener 2000 pump speed slope (y = 1.24x + 30). +#define PUMP_SPEED_INTERCEPT_FACTOR_DIENER_2000 30.0F ///< D48 Diener 2000 pump speed intercept. +#define PUMP_SPEED_SLOPE_FACTOR_DIENER_1000 2.869F ///< D48 Diener 1000 pump speed slope (y = 2.869x + 25.956). +#define PUMP_SPEED_INTERCEPT_FACTOR_DIENER_1000 25.956F ///< D48 Diener 1000 pump speed intercept. #define B1B2_HEAT_DIS_FIRST_COEFF 0.00000000487858F ///< First coefficient for Heat loss dissipation calculation from D4 to D28(cubic equation). #define B1B2_HEAT_DIS_SEC_COEFF 0.0000063124F ///< Second coefficient for Heat loss dissipation calculation from D4 to D28. #define B1B2_HEAT_DIS_THIRD_COEFF 0.00258513F ///< Third coefficient for Heat loss dissipation calculation from D4 to D28. @@ -75,7 +80,7 @@ #define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. //Testing -#define DELAY_BC_SWITCHING_AT_START_UP ( 10 * MS_PER_SECOND ) ///< Provide a balancing chamber switching start up delay to stabilize pump speed etc., +#define DELAY_BC_SWITCHING_AT_START_UP ( 10 * MS_PER_SECOND ) ///< Provide a balancing chamber switching start up delay to stabilize pump speed etc., /// Payload record structure for Gen dialysate execution state set request typedef struct { @@ -99,6 +104,7 @@ static U32 bypassStateDelayStartTimeMS; ///< Delay balancing chamber switching for a second to preapre pump steady state. static BOOL delayBypassStateFlag; ///< To indicate change in treatment parameters static F32 dialysateToDialyzerFlowRate; ///< Current dialysate to dialyzer flow rate (ml/min) +static U32 d48PumpSpeed; ///< Initial D48 pump speed based on the Qd. // ********** private function prototypes ********** @@ -118,6 +124,7 @@ static F32 calculateHeatDissipationB3( void ); static F32 calculateInitialTemp( F32 targetTemp, F32 heatDissipation ); static void publishGenDialysateModeData( void ); +static U32 getFreshDialPumpInitialRpm( void ); /*********************************************************************//** * @brief @@ -151,6 +158,7 @@ bicarbFillStartTimeMS = 0; pendingSpentChamberFill = FALSE; pendingBicarbChamberFill = FALSE; + d48PumpSpeed = getDialysatePumpMinRPM( D48_PUMP ); //Testing bypassStateDelayStartTimeMS = 0; delayBypassStateFlag = TRUE; @@ -174,8 +182,15 @@ *************************************************************************/ U32 transitionToGenDialysateMode( void ) { + U32 initialD48PumpSpeed = 0U; + initGenDialysateMode(); setCurrentSubState( NO_SUB_STATE ); + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); + //calculateD48PumpSpeedForBCFill(); + initialD48PumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + setD48PumpSpeedForBCFill( initialD48PumpSpeed ); transitionToUltrafiltration(); return genDialysateState; @@ -208,6 +223,26 @@ /*********************************************************************//** * @brief + * The getFreshDialPumpInitialRpm function returns fresh dialysate pump initial + * rpm based on hardwawre configuration. + * @details Inputs: FRESH_DIAL_PUMP_INITIAL_RPM, FRESH_DIAL_PUMP_INITIAL_RPM_B1_9_B2_0 + * @details Outputs: none + * @return fresh dialysate pump initial RPM for the active hardware variant + *************************************************************************/ +static U32 getFreshDialPumpInitialRpm( void ) +{ + U32 rpm = FRESH_DIAL_PUMP_INITIAL_RPM_B1_9_B2_0; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) ) + { + rpm = FRESH_DIAL_PUMP_INITIAL_RPM; + } + + return rpm; +} + +/*********************************************************************//** + * @brief * The setModeGenDStateTransition function sets the actuators and variables * for the state transition in generate dialysis mode. * @details Inputs: Valve states, Pump speed @@ -221,6 +256,9 @@ switch( state ) { case DD_GEND_STATE_START: + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); + // Do nothing break; @@ -250,26 +288,38 @@ startHeater( D5_HEAT ); //Turn on Trimmer heater - setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + } + else + { + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } startHeater( D45_HEAT ); //Testing : Enable close loop once testing is complete //setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); //Rinse pump On setRinsePumpState( RINSE_PUMP_STATE_ON ); transitionToBalChamberFill(); + // Activate Balancing Chamber Switching + requestBalChamberSwitching( TRUE ); //Testing bypassStateDelayStartTimeMS = getMSTimerCount(); delayBypassStateFlag = TRUE; break; case DD_GEND_DIALYSATE_DELIVERY_STATE: + // Activate Balancing Chamber Switching + requestBalChamberSwitching( TRUE ); + //Previous state setValveState( D47_VALV, VALVE_STATE_CLOSED ); // spent chamber purge valve setValveState( D8_VALV, VALVE_STATE_CLOSED ); @@ -287,13 +337,20 @@ startHeater( D5_HEAT ); //Turn on Trimmer heater - setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_1_0_HW ) == TRUE ) + { + setHeaterTargetTemperature( D45_HEAT, getD4AverageTemperature() ); + } + else + { + setHeaterTargetTemperature( D45_HEAT, getD99AverageTemperature() ); + } startHeater( D45_HEAT ); //setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); //setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, FALSE ); - setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); //Rinse pump On setRinsePumpState( RINSE_PUMP_STATE_ON ); @@ -311,6 +368,9 @@ break; case DD_GEND_SPENT_CHAMBER_FILL_STATE: + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); + //Set valves and actuators setValveState( D35_VALV, VALVE_STATE_CLOSED ); // VDI setValveState( D40_VALV, VALVE_STATE_CLOSED ); // VDO @@ -343,7 +403,7 @@ // Stop trimmer heater stopHeater( D45_HEAT ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_FILL_RPM, TRUE ); //Rinse pump On @@ -354,6 +414,9 @@ break; case DD_GEND_BICARB_CHAMBER_FILL_STATE: + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); + requestConcentratePumpOff( D11_PUMP, FALSE ); requestConcentratePumpOff( D10_PUMP, FALSE ); requestConcentratePumpOff( D76_PUMP, FALSE ); @@ -385,12 +448,14 @@ //Rinse pump On setRinsePumpState( RINSE_PUMP_STATE_ON ); - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); - setDialysatePumpTargetRPM( D48_PUMP, SPENT_DIAL_PUMP_INITIAL_RPM, TRUE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); + setDialysatePumpTargetRPM( D48_PUMP, d48PumpSpeed, TRUE ); break; case DD_GEND_DIALYSATE_DELIVERY_PAUSE: - setDialysatePumpTargetRPM( D12_PUMP, FRESH_DIAL_PUMP_INITIAL_RPM, TRUE ); + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); + setDialysatePumpTargetRPM( D12_PUMP, getFreshDialPumpInitialRpm(), TRUE ); signalDialysatePumpHardStop( D48_PUMP ); requestConcentratePumpOff( D11_PUMP, FALSE ); requestConcentratePumpOff( D10_PUMP, FALSE ); @@ -431,6 +496,8 @@ break; case DD_GEND_ISOLATED_UF_STATE: + // Deactivate Balancing Chamber Switching + requestBalChamberSwitching( FALSE ); //TODO : define actuators states break; @@ -558,6 +625,31 @@ /*********************************************************************//** * @brief + * The getD48PumpSpeedForBCFill function returns the calculated D48 pump speed + * @details \b Inputs: d48PumpSpeed + * @details \b Outputs: none + * @return D48 pump speed. + *************************************************************************/ +U32 getD48PumpSpeedForBCFill( void ) +{ + return d48PumpSpeed; +} + +/*********************************************************************//** + * @brief + * The setD48PumpSpeedForBCFill function sets the updated D48 pump speed. + * @details \b Inputs: none + * @details \b Outputs: d48PumpSpeed + * @param pumpSpeed Dialysate pump speed + * @return none. + *************************************************************************/ +void setD48PumpSpeedForBCFill( U32 pumpSpeed ) +{ + d48PumpSpeed = pumpSpeed; +} + +/*********************************************************************//** + * @brief * The monitorChamberLevelStatus function checks the spent chamber and bicarb * chamber level status and updates the corrosponding flags. * @details \b Inputs: Spent and bicarb chamber levels. @@ -602,7 +694,7 @@ #ifndef __REVISED_HEATER_MODEL__ if ( dialFlowrate >= LOW_DIAL_FLOW_RATE ) { - // linear releationship seen against high dialysate flowrate Vs DeltaTemp + // linear relationship seen against high dialysate flowrate Vs DeltaTemp // deltaTemp = (-0.0029 * Qd) + 3.47 deltaTemp = ( LINEAR_SLOPE_FACTOR * dialFlowrate ) + LINEAR_INTERCEPT_FACTOR; } @@ -707,6 +799,47 @@ /*********************************************************************//** * @brief + * The getCalculatedD48PumpSpeedForBCFill function returns the D48 pump speed + * calculated from dialysate flow rate (Qd) for continuous delivery. + * @details \b Inputs: Qd from TD, test config TEST_CONFIG_DD_ENABLE_DIENER_1000_PUMP. + * @details \b Outputs: none + * @return Calculated D48 pump speed in RPM (Diener 1000 or 2000 formula per test config). + *************************************************************************/ +U32 getCalculatedD48PumpSpeedForBCFill( void ) +{ + F32 dialFlowrate = getTDDialysateFlowrate(); + F32 slope; + F32 intercept; + F32 calculatedSpeed; + U32 rpm; + + if ( TRUE == getTestConfigStatus( TEST_CONFIG_DD_ENABLE_DIENER_2000_PUMP ) ) + { + slope = PUMP_SPEED_SLOPE_FACTOR_DIENER_2000; + intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_2000; + } + else + { + slope = PUMP_SPEED_SLOPE_FACTOR_DIENER_1000; + intercept = PUMP_SPEED_INTERCEPT_FACTOR_DIENER_1000; + } + + // Calculate nominal speed from Qd. + calculatedSpeed = ( slope * dialFlowrate ) + intercept; + + // Prevent negative before converting to unsigned and round up using ceilf. + if ( calculatedSpeed < 0.0F ) + { + calculatedSpeed = 0.0F; + } + + rpm = (U32)ceilf( calculatedSpeed ); + + return rpm; +} + +/*********************************************************************//** + * @brief * The handleGenDDialysateIsolatedUFState function performs the * Isolated ultrafiltration operations. * @details \b Inputs: none. @@ -747,11 +880,6 @@ delayBypassStateFlag = FALSE; } } - else - { - //Execute balancing chamber - execBalancingChamberControl(); - } if ( getTestConfigStatus( TEST_CONFIG_DD_ENABLE_SPENT_CHAMBER_H_FILL ) == TRUE ) { @@ -828,9 +956,6 @@ #endif else { - //Execute balancing chamber - execBalancingChamberControl(); - //Execute ultrafiltration execUFControl(); } @@ -994,6 +1119,8 @@ *************************************************************************/ void updateTreatmentSettings( void ) { + F32 initialPumpSpeed = 0.0F; + // Update any dynamic treatment parameter changes if ( TRUE == isTreatmentParamUpdated ) { @@ -1012,6 +1139,11 @@ //TODO: update others parameters setting as needed. signalUFRateUpdate(); + //Update D48 pump speed + //calculateD48PumpSpeedForBCFill(); + initialPumpSpeed = getCalculatedD48PumpSpeedForBCFill(); + setD48PumpSpeedForBCFill( initialPumpSpeed ); + //reset the flag isTreatmentParamUpdated = FALSE; } Index: firmware/App/Monitors/Temperature.c =================================================================== diff -u -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/Monitors/Temperature.c (.../Temperature.c) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) +++ firmware/App/Monitors/Temperature.c (.../Temperature.c) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -7,20 +7,15 @@ * * @file Temperature.c * -* @author (last) Vinayakam Mani -* @date (last) 11-Feb-2026 +* @author (last) Michael Garthwaite +* @date (last) 06-Mar-2026 * * @author (original) Vinayakam Mani * @date (original) 25-Sep-2024 * ***************************************************************************/ #include "BalancingChamber.h" -#ifdef __TEENSY_CONDUCTIVITY_DRIVER__ -#include "ConductivityTeensy.h" -#else -#include "ConductivitySensors.h" -#endif #include "Conductivity.h" #include "Flow.h" #include "Messaging.h" @@ -363,7 +358,6 @@ d50TempSampleIntervalCounter = 0; } - // Moving average sample collection interval varies based on the dialysate flow rate if ( ++d99TempSampleIntervalCounter >= tempDataCollectionTimeInterval ) { @@ -415,6 +409,9 @@ static void filterDialTemperatureReadings( void ) { DIAL_TEMPERATURE_SENSORS_T i; + F32 temperatureC = 0.0F; + U32 currentIndex = 0; + F32 prevSampleToRemoveC = 0.0f; for ( i = DIAL_TEMP_FIRST; i < NUM_OF_DIAL_TEMPS; i++ ) { @@ -426,14 +423,19 @@ else if ( TRUE == didTimeout( dialTempMovingAvgData[ i ].dialTempDataColStartTimeMS, D28_D30_DATA_COLLECTION_TIME_MS ) ) { CONDUCTIVITY_SENSORS_T sensor = ( DIAL_TEMP_D28 == i ? D27_COND : D29_COND ); -#ifdef __TEENSY_CONDUCTIVITY_DRIVER__ - F32 temperatureC = getTeensyConductivityTemperatureValue( sensor ); -#else - F32 temperatureC = getConductivityTemperatureValue( sensor ); -#endif - U32 currentIndex = dialTempMovingAvgData[ i ].dialTempSamplesNextIndex; - F32 prevSampleToRemoveC = dialTempMovingAvgData[ i ].dialTempSamplesC[ currentIndex ]; + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) != TRUE ) + { + temperatureC = getTeensyConductivityTemperatureValue( sensor ); + } + else + { + temperatureC = getConductivityTemperature( sensor ); + } + + currentIndex = dialTempMovingAvgData[ i ].dialTempSamplesNextIndex; + prevSampleToRemoveC = dialTempMovingAvgData[ i ].dialTempSamplesC[ currentIndex ]; + dialTempMovingAvgData[ i ].dialTempDataColStartTimeMS = getMSTimerCount(); dialTempMovingAvgData[ i ].dialTempColHasTimerBeenSet = TRUE; dialTempMovingAvgData[ i ].dialTempSamplesC[ currentIndex ] = temperatureC; @@ -574,19 +576,24 @@ data.d50Temp = getTemperatureValue( D50_TEMP ); data.d99Temp = getTemperatureValue( D99_TEMP ); data.boardTemp = getTemperatureValue( BRD_TEMP ); -#ifdef __TEENSY_CONDUCTIVITY_DRIVER__ - data.d16CondTemp = getTeensyConductivityTemperatureValue( D17_COND ); - data.d28CondTemp = getTeensyConductivityTemperatureValue( D27_COND ); - data.d30CondTemp = getTeensyConductivityTemperatureValue( D29_COND ); - data.d44CondTemp = getTeensyConductivityTemperatureValue( D43_COND ); - data.d75CondTemp = getTeensyConductivityTemperatureValue( D74_COND ); -#else - data.d16CondTemp = getConductivityTemperatureValue( D17_COND ); - data.d28CondTemp = getConductivityTemperatureValue( D27_COND ); - data.d30CondTemp = getConductivityTemperatureValue( D29_COND ); - data.d44CondTemp = getConductivityTemperatureValue( D43_COND ); - data.d75CondTemp = getConductivityTemperatureValue( D74_COND ); -#endif + + if ( getTestConfigStatus( TEST_CONFIG_DD_FP_ENABLE_BETA_2_0_HW ) != TRUE ) + { + data.d16CondTemp = getTeensyConductivityTemperatureValue( D17_COND ); + data.d28CondTemp = getTeensyConductivityTemperatureValue( D27_COND ); + data.d30CondTemp = getTeensyConductivityTemperatureValue( D29_COND ); + data.d44CondTemp = getTeensyConductivityTemperatureValue( D43_COND ); + data.d75CondTemp = getTeensyConductivityTemperatureValue( D74_COND ); + } + else + { + data.d16CondTemp = getConductivityTemperature( D17_COND ); + data.d28CondTemp = getConductivityTemperature( D27_COND ); + data.d30CondTemp = getConductivityTemperature( D29_COND ); + data.d44CondTemp = getConductivityTemperature( D43_COND ); + data.d75CondTemp = getConductivityTemperature( D74_COND ); + } + data.d4AvgTemp = getD4AverageTemperature(); data.d50AvgTemp = getD50AverageTemperature(); data.d99AvgTemp = getD99AverageTemperature(); Index: firmware/App/Monitors/Temperature.h =================================================================== diff -u -rb14374d1a56e47fdb79c913950a5cd17a403c4ac -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/Monitors/Temperature.h (.../Temperature.h) (revision b14374d1a56e47fdb79c913950a5cd17a403c4ac) +++ firmware/App/Monitors/Temperature.h (.../Temperature.h) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -50,6 +50,7 @@ F32 d99AvgTemp; ///< D99 moving average temperature value F32 d28AvgTemp; ///< D28 moving average temperature value F32 d30AvgTemp; ///< D30 moving average temperature value + F32 d78AvgTemp; ///< D78 moving average temperature value F32 d9PresTemp; ///< Hydraulics outlet pressure temperature F32 d66PresTemp; ///< Bicarb bag temperature F32 d51PresTemp; ///< Spent Dialysate temperature @@ -83,6 +84,7 @@ F32 getD4AverageTemperature( void ); F32 getD50AverageTemperature( void ); F32 getD99AverageTemperature( void ); +F32 getD78AverageTemperature( void ); void checkDialysateTemperatureSensors( void ); BOOL testDDTemperatureSensorsDataPublishIntervalOverride( MESSAGE_T *message ); Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -r046bc2b62cf942b7e846fa5bff698b94238edf24 -r4053bb88fd83acda93e7b6a27480658e82814609 --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 046bc2b62cf942b7e846fa5bff698b94238edf24) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 4053bb88fd83acda93e7b6a27480658e82814609) @@ -153,6 +153,7 @@ SW_FAULT_ID_BICARB_CHAMBER_FILL_INVALID_EXEC_STATE = 122, SW_FAULT_ID_DRY_BICART_DRAIN_INVALID_EXEC_STATE = 123, SW_FAULT_ID_INVALID_RINSE_PUMP = 124, + SW_FAULT_ID_PI_CTRL_INVALID_FEED_FORWARD_LIMIT = 125, NUM_OF_SW_FAULT_IDS } DD_SW_FAULT_ID_T;