Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r9cc5da6947aa143a10f95519eb7f366c1b095d61 -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 9cc5da6947aa143a10f95519eb7f366c1b095d61) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -52,13 +52,11 @@ #define MIN_RO_PUMP_DUTY_CYCLE 0.0F ///< 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_RAMP_UP_CONTROL_INTERVAL ( 500 / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_RAMP_UP_P_COEFFICIENT 0.22F ///< P term for RO pump ramp up to flow control. -#define ROP_FLOW_CONTROL_P_COEFFICIENT 0.4F ///< P term for RO pump flow control. -#define ROP_FLOW_CONTROL_I_COEFFICIENT 0.3F ///< I term for RO pump flow control. +#define ROP_FLOW_CONTROL_P_COEFFICIENT 0.15F ///< P term for RO pump flow control. +#define ROP_FLOW_CONTROL_I_COEFFICIENT 0.65F ///< I term for RO pump flow control. #define ROP_MAX_PRESSURE_P_COEFFICIENT 0.01F ///< P term for RO pump max pressure control. #define ROP_MAX_PRESSURE_I_COEFFICIENT 0.01F ///< I term for RO pump max pressure control. - +#define ROP_PWM_STEP_LIMIT 0.50F ///< Current maximum PWM step limit used in RO Profiles. #define ROP_FLOW_TARGET_TOLERANCE 0.03F ///< Tolerance in between the target flow rate and the actual flow rate in percentage. #define ROP_RAMP_DOWN_DUTY_CYCLE_RATIO 0.03F ///< Pump ramp down duty cycle ratio when the pressure higher than max defined. @@ -71,7 +69,7 @@ // 110000 pulses/liter // For 2 LPM => 2LPM x 110000 pulses/liter * 1 edges/pulse * 1 min/60 seconds = 3666.66 counts/sec => 272.72 microseconds => for 1 LPM = 136.36 counts #define RO_FLOW_ADC_TO_LPM_FACTOR 272.72F ///< Conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). -#define ROP_FLOW_TO_PWM_SLOPE 0.1F ///< Slope of flow to PWM line equation. +#define ROP_FLOW_TO_PWM_SLOPE 0.5F ///< Slope of flow to PWM line equation. #define ROP_FLOW_TO_PWM_INTERCEPT 0.0F ///< Intercept of flow to PWM line equation. /// Initial conversion factor from target flow rate to PWM duty cycle estimate. @@ -118,7 +116,7 @@ static BOOL isROPumpOn; ///< RO pump is currently running. static F32 roPumpPWMDutyCyclePct; ///< Initial RO pump PWM duty cycle. static F32 roPumpDutyCyclePctSet; ///< Currently set RO pump PWM duty cycle. -static F32 roPumpFeedbackDutyCyclePct; ///< RO pump feedback duty cycle in percent. +static OVERRIDE_F32_T roPumpFeedbackDutyCyclePct = { 0, 0, 0, 0 }; ///< RO pump feedback duty cycle in percent. static PUMP_CONTROL_MODE_T roPumpControlMode; ///< Requested RO pump control mode. static F32 pendingROPumpCmdMaxPressure; ///< Delayed (pending) RO pump max pressure (in PSI) setting. static F32 pendingROPumpCmdTargetFlow; ///< Delayed (pending) RO pump target flow rate (in mL/min) setting. @@ -130,7 +128,22 @@ static U32 roControlTimerCounter; ///< Determines when to perform control on RO pump. static F32 roPumpOpenLoopTargetDutyCycle; ///< Target RO pump open loop PWM. static F32 roVolumeL; ///< RO water generated in liters. +static U32 roPumpControlInterval; ///< RO pump Control interval. +static RO_PI_FLOW_PROFILES_T currentROPumpProfile; +///< RO Pump flow profile table. +///< Most values are currently the same until future efforts into tuning op modes. +///< TODO: Fine tune each op mode. +static PI_CONTROLLER_PROFILE_DATA_T roPIFlowProfiles[ NUM_OF_RO_PI_FLOW_PROFILES ] = +{ // Kp Ki uMin uMax maxErrorSumStep Control Interval + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FLUSH + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_GEN_IDLE + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_FILL + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_DRAIN + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_HEAT + { ROP_FLOW_CONTROL_P_COEFFICIENT, ROP_FLOW_CONTROL_I_COEFFICIENT, MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE, ROP_PWM_STEP_LIMIT, ROP_CONTROL_INTERVAL }, ///< RO_PI_FLOW_PROFILE_OPEN_LOOP +};// Kp Ki uMin uMax maxErrorSumStep Control Interval + // ********** private function prototypes ********** static RO_PUMP_STATE_T handleROPumpOffState( void ); @@ -139,10 +152,12 @@ static RO_PUMP_STATE_T handleROPumpControlToMaxPressureState( void ); static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); +static F32 roPumpFlowToPWM( RO_PI_FLOW_PROFILES_T profileID, F32 targetFlow ); static void setROPumpTargetDutyCycle( F32 duty ); static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); static void stopROPump( void ); static void publishROPumpData( void ); +static F32 getROFeedbackDutyCycle( void ); /*********************************************************************//** * @brief @@ -185,7 +200,7 @@ roPumpState = RO_PUMP_OFF_STATE; roPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; isROPumpOn = FALSE; - roPumpFeedbackDutyCyclePct = 0.0F; + roPumpFeedbackDutyCyclePct.data = 0.0F; roVolumeL = 0.0F; targetROPumpFlowRateLPM = 0.0F; roPumpPWMDutyCyclePct = 0.0F; @@ -194,16 +209,18 @@ pendingROPumpCmdTargetFlow = 0.0F; pendingROPumpCmdCountDown = 0; targetROPumpMaxPressure = 0.0F; + roPumpControlInterval = ROP_CONTROL_INTERVAL; + currentROPumpProfile = RO_PI_FLOW_PROFILE_GEN_IDLE; } /*********************************************************************//** * @brief * The setROPumpTargetFlowRate function sets a new target flow rate for the * RO pump. * @details Inputs: targetROPumpPressure, targetROPumpFlowRate, - * roPumpControlMode, rampUp2FlowTimeoutCounter + * roPumpControlMode, rampUp2FlowTimeoutCounter, currentROPumpProfile * @details Outputs: targetROPumpPressure, targetROPumpFlowRate, - * roPumpControlMode, rampUp2FlowTimeoutCounter + * roPumpControlMode, rampUp2FlowTimeoutCounter, roPumpPWMDutyCyclePct * @param roFlowRate which is target RO flow rate * @param maxPressure which is the maximum allowed pressure that the RO pump * can reach @@ -224,9 +241,8 @@ targetROPumpMaxPressure = maxPressure; targetROPumpFlowRateLPM = roFlowRate; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; - roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; // Get the initial guess of the duty cycle - roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); + roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; isROPumpOn = TRUE; result = TRUE; @@ -322,10 +338,10 @@ * The execROPumpMonitor function executes the RO pump monitor. The RO flow * sensor is read, filtered, converted to L/min and calibrated. * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, - * measuredROFlowRateLPM, measuredROFlowRateLPM, roPumpState, - * flowOutOfRangeCounter, roPumpControlMode + * measuredROFlowRateLPM, roPumpState, roPumpFeedbackDutyCyclePct, + * flowOutOfRangeCounter, roPumpControlMode, Ppo * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, - * measuredROFlowRateLPM, measuredROFlowRateLPM + * measuredROFlowRateLPM, roVolumeL, roPumpFeedbackDutyCyclePct * @return none *************************************************************************/ void execROPumpMonitor( void ) @@ -379,10 +395,10 @@ { // The feedback voltage is on the 0V line so when the duty cycle is 0, the feedback is 2.5V // The duty cycle is calculated by getting the 1 - (ratio of feedback / to the voltage at 0 percent duty cycle). - roPumpFeedbackDutyCyclePct = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); - isDutyCylceOutOfRange = ( fabs( roPumpFeedbackDutyCyclePct - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); + roPumpFeedbackDutyCyclePct.data = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); + isDutyCylceOutOfRange = ( fabs( getROFeedbackDutyCycle() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); - checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, roPumpFeedbackDutyCyclePct, roPumpDutyCyclePctSet ); + checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, getROFeedbackDutyCycle(), roPumpDutyCyclePctSet ); // Check if it the alarm has timed out and if the pump is supposed to be off but it is still on, activate the safety shutdown if ( ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) && ( FALSE == isROPumpOn ) ) @@ -416,9 +432,8 @@ pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; - roPumpState = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; // Get the initial guess of the duty cycle - roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( targetROPumpFlowRateLPM ); + roPumpPWMDutyCyclePct = roPumpFlowToPWM( currentROPumpProfile, targetROPumpFlowRateLPM ); roControlTimerCounter = 0; isROPumpOn = TRUE; } @@ -523,6 +538,21 @@ /*********************************************************************//** * @brief + * The getROFeedbackDutyCyle function returns the RO pump feedback + * duty cycle. + * @details Inputs: roPumpFeedbackDutyCyclePct + * @details Outputs: none + * @return ro pump feedback duty cycle + *************************************************************************/ +static F32 getROFeedbackDutyCyle( void ) +{ + F32 feedbackdutyCycle = getF32OverrideValue( &roPumpFeedbackDutyCyclePct ); + + return feedbackdutyCycle; +} + +/*********************************************************************//** + * @brief * The resetROGenerateVolumeL function resets the RO generated volume in liters. * @details Inputs: none * @details Outputs: roVolumeL @@ -547,17 +577,17 @@ RO_PUMP_STATE_T state = RO_PUMP_OFF_STATE; // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow - if ( getTargetROPumpFlowRateLPM() > 0.0F && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + if ( ( getTargetROPumpFlowRateLPM() > 0.0F ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Set pump to on isROPumpOn = TRUE; - roPumpDutyCyclePctSet = ROP_FLOW_TO_PWM_DC( getTargetROPumpFlowRateLPM() ); + roPumpDutyCyclePctSet = roPumpFlowToPWM( currentROPumpProfile, getTargetROPumpFlowRateLPM() ); setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - state = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; + state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; } // If the target duty cycle is greater than zero (minimum is 10%) and the mode has been set to open // loop, set the duty cycle - if ( roPumpOpenLoopTargetDutyCycle > 0.0F && roPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) + if ( ( roPumpOpenLoopTargetDutyCycle > 0.0F ) && ( PUMP_CONTROL_MODE_OPEN_LOOP == roPumpControlMode ) ) { setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); isROPumpOn = TRUE; @@ -571,55 +601,16 @@ * @brief * The handleROPumpRampUpToTargetFlowState function handles the RO pump * ramp up to flow state of the controller state machine. - * @details Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, - * rampUp2FlowTimeoutCounter - * @details Outputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, - * rampUp2FlowTimeoutCounter + * @details Inputs: none + * @details Outputs: none * @return next state of the controller state machine *************************************************************************/ static RO_PUMP_STATE_T handleROPumpRampUpToTargetFlowState( void ) { - RO_PUMP_STATE_T state = RO_PUMP_RAMP_UP_TO_TARGET_FLOW_STATE; + RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; - // Get the current pressure from the sensor - F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); - F32 targetFlowRate = getTargetROPumpFlowRateLPM(); - F32 actualFlowRate = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); - F32 flowRateDeviation = fabs( targetFlowRate - actualFlowRate ) / targetFlowRate; - BOOL isFlowOutOfRange = flowRateDeviation > ROP_FLOW_TARGET_TOLERANCE; - F32 targetPressure = getTargetROPumpPressurePSI(); + // TODO - remove function and state - obsolete - if ( ++roControlTimerCounter >= ROP_RAMP_UP_CONTROL_INTERVAL ) - { - // If the actual pressure is greater than the target pressure or it is within the tolerance of the maximum pressure, move to set - // to target pressure straight. At the beginning the maximum pressure is set in the targetROPumpPressure override variable. - // If the flow rate was reached without reaching to maximum pressure, the pressure that was set to targetROPumpPressure override will - // be reset to the corresponding pressure of the target flow rate. - if ( ( actualPressure > targetPressure ) || ( ( targetPressure - actualPressure ) < MAX_PRESSURE_TARGET_TOLERANCE ) ) - { - resetPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, roPumpDutyCyclePctSet ); - state = RO_PUMP_CONTROL_TO_MAX_PRESSURE_STATE; - } - // If the actual flow is still far from target flow, update the duty cycle using the I controller and stay in this state - else if ( TRUE == isFlowOutOfRange ) - { - roPumpDutyCyclePctSet += ( targetFlowRate - actualFlowRate ) * ROP_RAMP_UP_P_COEFFICIENT; - // If the duty cycle is out of the define range for the RO pump, set the boundaries - roPumpDutyCyclePctSet = roPumpDutyCyclePctSet < MIN_RO_PUMP_DUTY_CYCLE ? MIN_RO_PUMP_DUTY_CYCLE : roPumpDutyCyclePctSet; - roPumpDutyCyclePctSet = roPumpDutyCyclePctSet > MAX_RO_PUMP_DUTY_CYCLE ? MAX_RO_PUMP_DUTY_CYCLE : roPumpDutyCyclePctSet; - - setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); - } - // Reached to the target flow go to the next state - else - { - resetPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPumpDutyCyclePctSet ); - state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; - } - - roControlTimerCounter = 0; - } - return state; } @@ -636,7 +627,7 @@ RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; // Control at set interval - if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + if ( ( ++roControlTimerCounter >= roPumpControlInterval ) && ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) ) { // Get the pressure to use it for setting the control F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); @@ -787,14 +778,89 @@ pumpData.roPumpDutyCycle = roPumpDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; pumpData.roMeasFlowRateLPM = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); pumpData.roPumpState = (U32)roPumpState; - pumpData.roPumpFBDutyCycle = roPumpFeedbackDutyCyclePct * FRACTION_TO_PERCENT_FACTOR; + pumpData.roPumpFBDutyCycle = getROFeedbackDutyCycle() * FRACTION_TO_PERCENT_FACTOR; broadcastData( MSG_ID_RO_PUMP_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&pumpData, sizeof( RO_PUMP_DATA_T ) ); roPumpDataPublicationTimerCounter = 0; } } +/*********************************************************************//** + * @brief + * The setROPIFlowProfile function sets the RO flow PI controller to new coefficients + * and calculates the initial duty cycle. + * @details Inputs: targetROPumpFlowRateLPM + * @details Outputs: roPumpControlInterval, currentROPumpProfile + * @param profileID the ID for which flow profile to be used + * @return none + *************************************************************************/ +void setROPIFlowProfile( RO_PI_FLOW_PROFILES_T profileID ) +{ + F32 initialControlDutyCycle; + if ( profileID < NUM_OF_RO_PI_FLOW_PROFILES ) + { + roPumpControlInterval = roPIFlowProfiles[ profileID ].controlInterval; + initialControlDutyCycle = roPumpFlowToPWM( profileID, (getTargetROPumpFlowRateLPM()) ); + + initializePIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, initialControlDutyCycle, + roPIFlowProfiles[ profileID ].Kp, roPIFlowProfiles[ profileID ].Ki, + roPIFlowProfiles[ profileID ].uMin, roPIFlowProfiles[ profileID ].uMax ); + + setPIControllerStepLimit( PI_CONTROLLER_ID_RO_PUMP_FLOW, roPIFlowProfiles[ profileID ].maxErrorSumStep ); + currentROPumpProfile = profileID; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_PI_PROFILE_SELECTED, profileID ) + } +} + +/*********************************************************************//** + * @brief + * The roPumpFlowToPWM function calculates the duty cycle for the given target + * flow in relation to which PI profile has been selected. + * @details Inputs: none + * @details Outputs: dutyCyclePct + * @param profileID the ID for which flow profile to be used + * targetFlow the flow as a parameter for the conversion calculation + * @return dutyCyclePct, the duty cycle for the given flow + *************************************************************************/ +static F32 roPumpFlowToPWM( RO_PI_FLOW_PROFILES_T profileID, F32 targetFlow ) +{ + F32 dutyCyclePct = 0; + if ( profileID < NUM_OF_RO_PI_FLOW_PROFILES ) + { + switch( profileID ) + { + case RO_PI_FLOW_PROFILE_FLUSH: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + case RO_PI_FLOW_PROFILE_GEN_IDLE: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + case RO_PI_FLOW_PROFILE_FILL: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + case RO_PI_FLOW_PROFILE_DRAIN: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + case RO_PI_FLOW_PROFILE_HEAT: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + default: + dutyCyclePct = ROP_FLOW_TO_PWM_DC( targetFlow ); + break; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_PI_PROFILE_SELECTED, profileID ) + } + return dutyCyclePct; +} + + /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ @@ -930,4 +996,55 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetROPumpMeasuredFeedbackDutyCycleOverride function overrides the + * feedback duty cycle. + * @details Inputs: none + * @details Outputs: roPumpFeedbackDutyCyclePct + * @param value override feedback duty cycle. + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetROPumpMeasuredFeedbackDutyCycleOverride( F32 value ) +{ + BOOL status = FALSE; + + // Check if the requested drain pump RPM is within range + if ( ( value >= MIN_RO_PUMP_DUTY_CYCLE ) && ( value <= MAX_RO_PUMP_DUTY_CYCLE ) ) + { + // Check if the user is logged in + if ( TRUE == isTestingActivated() ) + { + roPumpFeedbackDutyCyclePct.ovData = value; + roPumpFeedbackDutyCyclePct.override = OVERRIDE_KEY; + status = TRUE; + } + } + + return status; +} + +/*********************************************************************//** + * @brief + * The testResetROPumpMeasuredFeedbackDutyCycleOverride function resets the + * feedback duty cycle. + * @details Inputs: none + * @details Outputs: roPumpFeedbackDutyCyclePct + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetROPumpMeasuredFeedbackDutyCycleOverride( void ) +{ + BOOL status = FALSE; + + // Check if the user is logged in + if ( TRUE == isTestingActivated() ) + { + roPumpFeedbackDutyCyclePct.ovData = roPumpFeedbackDutyCyclePct.ovInitData; + roPumpFeedbackDutyCyclePct.override = OVERRIDE_RESET; + status = TRUE; + } + + return status; +} + /**@}*/ Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r715b8517f4f25d4fa5444d1aae8d8d729ceba77c -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 715b8517f4f25d4fa5444d1aae8d8d729ceba77c) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -116,7 +116,6 @@ static U32 flushBubblesStartTime; ///< Starting time for flush bubbles. static U32 concentratePumpPrimeCount; ///< Interval count for concentrate pump prime. -static F32 integratedVolumeML; ///< Total RO flow rate over period of time. static BOOL didFMPCheckStart; ///< Flag indicates whether FMP flow vs. LC volume check has begun. static F32 acidConductivityTotal; ///< Total of acid conductivity during fill. static F32 bicarbConductivityTotal; ///< Total of bicarb conductivity during fill. @@ -138,6 +137,7 @@ static OVERRIDE_F32_T usedBicarbVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< The integrated bicarb concentration volume has been used in mL. static OVERRIDE_U32_T fillModeDataPublishInterval = { FILL_MODE_DATA_PUB_INTERVAL, FILL_MODE_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish fill mode data to CAN bus. +static OVERRIDE_F32_T integratedVolumeML = { 0.0, 0.0, 0.0, 0.0 }; ///< Total RO flow rate over period of time. // ********** private function prototypes ********** @@ -173,7 +173,7 @@ dialysateFillStartTime = 0; dataPublishCounter = DATA_PUBLISH_COUNTER_START_COUNT; reservoirBaseWeight = 0.0F; - integratedVolumeML = 0.0F; + integratedVolumeML.data = 0.0F; didFMPCheckStart = FALSE; concentrateTestStartTime = 0; acidConductivityTotal = 0.0F; @@ -328,6 +328,20 @@ /*********************************************************************//** * @brief + * The getIntegratedVolumeML function returns the integrated volume in mL + * @details Inputs: integratedVolumeML + * @details Outputs: integrated volume + * @return integrated volume + *************************************************************************/ +F32 getIntegratedVolumeML( void ) +{ + + F32 integratedVolume = getF32OverrideValue(&integratedVolumeML); + return integratedVolume; +} + +/*********************************************************************//** + * @brief * The resetFillStatusParameters function resets the fill status parameters. * @details Inputs: none * @details Outputs: fillStatus @@ -767,7 +781,7 @@ reservoirBaseWeight = getReservoirWeight( getInactiveReservoir() ); } - integratedVolumeML += getMeasuredROFlowRateWithConcPumpsLPM() * ML_PER_LITER * FLOW_INTEGRATOR; + integratedVolumeML.data += getMeasuredROFlowRateWithConcPumpsLPM() * ML_PER_LITER * FLOW_INTEGRATOR; } usedAcidVolumeML.data += getMeasuredPumpSpeed( CONCENTRATEPUMPS_CP1_ACID ) * FLOW_INTEGRATOR; @@ -804,7 +818,7 @@ { if ( integratedVolumeToLoadCellReadingPercent > FLOW_INTEGRATED_VOLUME_CHECK_TOLERANCE ) // SRSDG 240 { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_FLOW_METER_CHECK_FAILURE, filledVolumeML, integratedVolumeML ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_FLOW_METER_CHECK_FAILURE, filledVolumeML, getIntegratedVolumeML() ); } } @@ -1007,8 +1021,8 @@ * @brief * The publishFillModeData function publishes fill mode data * at the set interval. - * @details Inputs: fillModeDataPublicationTimerCounter - * @details Outputs: fillModeDataPublicationTimerCounter + * @details Inputs: fillModeDataPublicationTimerCounter, fillModeDataPublishInterval + * @details Outputs: fillModeData * @return none *************************************************************************/ static void publishFillModeData( void ) @@ -1025,7 +1039,7 @@ fillModeData.pctDiffInConductivity = pctDiffInConductivity; fillModeData.usedAcidVolumeML = getChemicalUsedVolumeML( ACID ); fillModeData.usedBicarbVolumeML = getChemicalUsedVolumeML( BICARB ); - fillModeData.integratedVolumeML = integratedVolumeML; + fillModeData.integratedVolumeML = getIntegratedVolumeML(); broadcastData( MSG_ID_DG_FILL_MODE_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&fillModeData, sizeof( DG_FILL_MODE_DATA_T ) ); @@ -1181,4 +1195,49 @@ return result; } +/*********************************************************************//** + * @brief + * The testSetIntegratedVolumeOverride function overrides the + * integrated volume. + * @details Inputs: value + * @details Outputs: integratedVolumeML + * @param: value integrated volume in mL + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetIntegratedVolumeOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + integratedVolumeML.ovData = value; + integratedVolumeML.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetIntegratedVolumeOverride function resets the + * override of integrated volume. + * @details Inputs: none + * @details Outputs: integratedVolumeML + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetIntegratedVolumeOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + integratedVolumeML.override = OVERRIDE_RESET; + integratedVolumeML.ovData = integratedVolumeML.ovInitData; + result = TRUE; + } + + return result; +} + /**@}*/ Index: firmware/App/Modes/ModeFill.h =================================================================== diff -u -r2b6abbe347b2da260a4d46aca233bbfb6a59bf04 -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Modes/ModeFill.h (.../ModeFill.h) (revision 2b6abbe347b2da260a4d46aca233bbfb6a59bf04) +++ firmware/App/Modes/ModeFill.h (.../ModeFill.h) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -8,7 +8,7 @@ * @file ModeFill.h * * @author (last) Dara Navaei -* @date (last) 21-Jun-2022 +* @date (last) 07-Nov-2022 * * @author (original) Leonardo Baloa * @date (original) 19-Nov-2019 @@ -31,11 +31,12 @@ // ********** public definitions ********** +/// Chemical bottles typedef enum { - ACID = 0, - BICARB, - NUM_OF_CHEMICALS, + ACID = 0, ///< Acid. + BICARB, ///< Bicarb. + NUM_OF_CHEMICALS, ///< Number of chemicals. } CHEMICAL_BOTTLES_T; /// DG broadcast dialysate fill data structure. Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r9cc5da6947aa143a10f95519eb7f366c1b095d61 -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 9cc5da6947aa143a10f95519eb7f366c1b095d61) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -901,6 +901,10 @@ handleServiceModeRequest( message ); break; + case MSG_ID_HD_REQUEST_DG_ALARMS: + handleResendAllAlarmsCommand( message ); + break; + // NOTE: This case must be last case MSG_ID_DG_TESTER_LOGIN_REQUEST: handleTesterLogInRequest( message ); @@ -1196,10 +1200,6 @@ handleSetDGUsageInfoRecord( message ); break; - case MSG_ID_HD_REQUEST_DG_ALARMS: - handleResendAllAlarmsCommand( message ); - break; - case MSG_ID_DG_SET_OP_MODE_REQUEST: handleTestSetOpModeRequest( message ); break; @@ -1216,6 +1216,18 @@ handleTestDGDrainPumpDirectionOverrideRequest( message ); break; + case MSG_ID_DG_RO_FEEDBACK_VOLTAGE_OVERRIDE: + handleTestDGROPumpFeedbackVoltageOverrideRequest( message ); + break; + + case MSG_ID_DG_DIALYSATE_FILL_INTEGRATED_VOLUME_OVERRIDE: + handleTestDGFillIntegratedVolumeOverrideRequest( message ); + break; + + case MSG_ID_FILL_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE: + handleTestDGFillModeBroadcastOverrideRequest( message ); + break; + default: // TODO - unrecognized message ID received - ignore break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r9cc5da6947aa143a10f95519eb7f366c1b095d61 -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 9cc5da6947aa143a10f95519eb7f366c1b095d61) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -15,7 +15,7 @@ * ***************************************************************************/ -#include // for memcpy() +#include // for memcpy() #include "reg_system.h" @@ -3854,4 +3854,163 @@ return result; } +/*********************************************************************//** + * @brief + * The handleTestDrainPumpMeasuredCurrentOverride function handles a request + * to override the drain pump measured current + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestDrainPumpMeasuredCurrentOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetDrainPumpMeasuredCurrentOverride( payload.state.f32 ); + } + else + { + result = testResetDrainPumpMeasuredCurrentOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestGenIdlePublishIntervalOverride function handles a request + * to override the gen idle state publish interval + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestGenIdlePublishIntervalOverride( MESSAGE_T * message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetGenIdleSubstatesPublishIntervalOverride( payload.state.u32 ); + } + else + { + result = testResetGenIdleSubstatesPublishIntervalOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestDGROPumpFeedbackVoltageOverrideRequest function handles a request + * to override the gen idle state publish interval + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestDGROPumpFeedbackVoltageOverrideRequest( MESSAGE_T * message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetROPumpMeasuredFeedbackDutyCycleOverride( payload.state.f32 ); + } + else + { + result = testResetROPumpMeasuredFeedbackDutyCycleOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** + * @brief + * The handleTestDGFillModeBroadcastOverrideRequest function handles a request + * to override the gen idle state publish interval + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestDGFillModeBroadcastOverrideRequest( MESSAGE_T * message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetFillModeDataPublishIntervalOverride( payload.state.u32 ); + } + else + { + result = testResetFillModeDataPublishIntervalOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} +/*********************************************************************//** + * @brief + * The handleTestDGFillIntegratedVolumeOverrideRequest function handles a request + * to override the gen idle state publish interval + * @details Inputs: none + * @details Outputs: message handled + * @param message a pointer to the message to handle + * @return none + *************************************************************************/ +void handleTestDGFillIntegratedVolumeOverrideRequest( MESSAGE_T * message ) +{ + TEST_OVERRIDE_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof( TEST_OVERRIDE_PAYLOAD_T ) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof( TEST_OVERRIDE_PAYLOAD_T ) ); + if ( FALSE == payload.reset ) + { + result = testSetIntegratedVolumeOverride( payload.state.u32 ); + } + else + { + result = testResetIntegratedVolumeOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r9cc5da6947aa143a10f95519eb7f366c1b095d61 -rf565edd6de62272b1c18fe425e37bc2128aa5832 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 9cc5da6947aa143a10f95519eb7f366c1b095d61) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision f565edd6de62272b1c18fe425e37bc2128aa5832) @@ -404,6 +404,12 @@ BOOL handleSetHDOperationMode( MESSAGE_T *message ); // MSG_ID_DG_DRAIN_PUMP_CURRENT_OVERRIDE +void handleTestDrainPumpMeasuredCurrentOverride( MESSAGE_T *message ); + +// MSG_ID_DG_GEN_IDLE_PUBLISH_INTERVAL_OVERRIDE +void handleTestGenIdlePublishIntervalOverride( MESSAGE_T * message ); + +// MSG_ID_DG_DRAIN_PUMP_CURRENT_OVERRIDE void handleTestDGDrainPumpCurrentOverrideRequest( MESSAGE_T *message ); // MSG_ID_DG_DRAIN_PUMP_DIRECTION_OVERRIDE @@ -412,6 +418,16 @@ // MSG_ID_DG_VALVES_SENSED_STATE_OVERRIDE void handleTestDGValvesSensedStateOverrideRequest( MESSAGE_T *message ); +// MSG_ID_FILL_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE +void handleTestDGFillModeBroadcastOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DG_RO_FEEDBACK_VOLTAGE_OVERRIDE +void handleTestDGROPumpFeedbackVoltageOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DG_DIALYSATE_FILL_INTEGRATED_VOLUME_OVERRIDE +void handleTestDGFillIntegratedVolumeOverrideRequest( MESSAGE_T *message ); + + /**@}*/ #endif