Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,624 +14,953 @@ * @date (original) 04-Apr-2020 * ***************************************************************************/ - -#include - -#include "etpwm.h" -#include "mibspi.h" - -#include "FPGA.h" -#include "OperationModes.h" -#include "PIControllers.h" -#include "Pressures.h" -#include "ROPump.h" -#include "SystemCommMessages.h" -#include "TaskGeneral.h" -#include "TaskPriority.h" -#include "Timers.h" -#ifdef EMC_TEST_BUILD -#include "Heaters.h" -#endif -#ifdef ENABLE_DIP_SWITCHES -#include "Valves.h" -#endif - -/** - * @addtogroup ROPump - * @{ - */ - -// ********** private definitions ********** - -#define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. - -#define MAX_RO_PUMP_PWM_STEP_CHANGE 0.01 ///< Max duty cycle change for controller. -#define MAX_RO_PUMP_PWM_DUTY_CYCLE 0.99 ///< Max duty cycle. -#define MIN_RO_PUMP_PWM_DUTY_CYCLE 0.00 ///< Min duty cycle. - -#define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump control. -#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump control. - -#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). - -#define FLOW_SAMPLES_TO_AVERAGE (250 / TASK_PRIORITY_INTERVAL) ///< Averaging flow data over 250 ms intervals. -#define FLOW_AVERAGE_MULTIPLIER (1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE) ///< Optimization - multiplying is faster than dividing. -// TODO - this is a place holder for real conversion -#define ROP_PSI_TO_PWM_DC(p) ( 0.2 + ( (F32)((p) - 100) * 0.01 ) ) ///< conversion factor from target PSI to PWM duty cycle estimate. -#define RO_FLOW_ADC_TO_LPM_FACTOR 10909.0909 ///< conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). - -/// Enumeration of RO pump states. -typedef enum ROPump_States -{ - RO_PUMP_OFF_STATE = 0, ///< RO pump off state - RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state - NUM_OF_RO_PUMP_STATES ///< Number of RO pump states -} RO_PUMP_STATE_T; - -/// Enumeration of RO pump self-test states. -typedef enum ROPump_Self_Test_States -{ - RO_PUMP_SELF_TEST_STATE_START = 0, ///< RO pump self-test start state - RO_PUMP_TEST_STATE_IN_PROGRESS, ///< RO pump self-tests in progress state - RO_PUMP_TEST_STATE_COMPLETE, ///< RO pump self-tests completed state - NUM_OF_RO_PUMP_SELF_TEST_STATES ///< Number of RO pump self-test states -} RO_PUMP_SELF_TEST_STATE_T; - -// TODO - test code - remove later -// pin assignments for pump test DIP switch 0 -#define RO_PUMP_TEST_SPI5_PORT_MASK 0x00000100 // (ENA - re-purposed as input GPIO) -// dialIn pump stop and direction macros -#define GET_DIP_SW0_TEST() ( ( mibspiREG5->PC2 & RO_PUMP_TEST_SPI5_PORT_MASK ) != 0 ) - -// ********** private data ********** - -static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< Current state of RO pump controller state machine. -static U32 roPumpDataPublicationTimerCounter = 0; ///< RO pump data publication timer counter. -static BOOL isROPumpOn = FALSE; ///< RO pump is currently running. -static F32 roPumpPWMDutyCyclePct = 0.0; ///< Initial RO pump PWM duty cycle. -static F32 roPumpPWMDutyCyclePctSet = 0.0; ///< Currently set RO pump PWM duty cycle. -static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested RO pump control mode. -static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set RO pump control mode. - +#include + +#include "etpwm.h" +#include "mibspi.h" + +#include "FPGA.h" +#include "OperationModes.h" +#include "PIControllers.h" +#include "PersistentAlarm.h" +#include "Pressures.h" +#include "ROPump.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TaskPriority.h" +#include "Timers.h" +#ifdef EMC_TEST_BUILD +#include "Heaters.h" +#endif +#ifdef ENABLE_DIP_SWITCHES +#include "Valves.h" +#endif + +/** + * @addtogroup ROPump + * @{ + */ + +// ********** private definitions ********** + +#define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. + +#define MAX_RO_PUMP_DUTY_CYCLE 0.99 ///< max duty cycle. +#define MIN_RO_PUMP_DUTY_CYCLE 0.0 ///< min duty cycle. + +#define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the RO pump is controlled. +#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump pressure control. +#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump pressure control. + +#define ROP_RAMP_UP_P_COEFFICIENT 0.0 ///< P term for RO pump flow control. +#define ROP_RAMP_UP_I_COEFFICIENT 0.1 ///< I term for RO pump flow control. +#define ROP_FLOW_TARGET_TOLERANCE 0.05 ///< Tolerance in between the target flow rate and the actual flow rate in liter. + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). + +#define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. +#define FLOW_VERIFICATION_COUNTER_TARGET 40U ///< The time in counts to check the flow and make sure it is in range. + +#define RO_FLOW_ADC_TO_LPM_FACTOR 10909.0909 ///< conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). + +#define ROP_FLOW_TO_PWM_DC(flow) ( (F32)( flow / MAX_RO_FLOWRATE_LPM ) ) ///< Initial conversion factor from target flow rate to PWM duty cycle estimate. + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). + +#define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. +#define MAX_ALLOWED_FLOW_DEVIATION 0.1 ///< Max allowed deviation from target flow. +#define FLOW_OUT_OF_RANGE_TIME_OUT ( 5000 / TASK_PRIORITY_INTERVAL ) ///< Flow out of range time out in counts. +#define MAX_PRESSURE_TARGET_TOLERANCE 5 ///< Pressure tolerance from maximum set pressure by user in psi. +#define MAX_ALLOWED_PRESSURE_PSI 130 ///< Maximum allowed pressure that the RO pump can go to. +#define MIN_ALLOWED_PRESSURE_PSI 10 ///< Minimum allowed pressure that the RO pump can go to. +#define MAX_ALLOWED_MEASURED_PRESSURE_PSI 135 ///< Maximum allowed pressure that the sensor measures. RO pump shut off pressure is 140psi. +#define MAX_PRESSURE_OUT_OF_RANGE_TIME_OUT ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Maximum allowed time that the pressure can be very high. +#define MAX_ALLOWED_RAMP_UP_TIME ( 30 * MS_PER_SECOND ) ///< Maximum allowed ramp up time to a flow rate in ms. +#define RAMP_UP_TIME_OUT_COUNT ( MAX_ALLOWED_RAMP_UP_TIME / \ + TASK_GENERAL_INTERVAL ) ///< Ramp up time out in counts. + +// TODO - this is a place holder for real conversion +#define ROP_PSI_TO_PWM_DC(p) ( 0.2 + ( (F32)((p) - 100) * 0.01 ) ) ///< conversion factor from target PSI to PWM duty cycle estimate. TODO remove? + +/// Enumeration of RO pump states. +typedef enum ROPump_States +{ + RO_PUMP_OFF_STATE = 0, ///< RO pump off state + RO_PUMP_RAMP_UP_STATE, ///< RO pump ramp up to target flow rate state + RO_PUMP_VERIFY_FLOW_STATE, ///< RO pump maintain the flow rate for a set period of time + RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state + RO_PUMP_OPEN_LOOP_STATE, ///< RO pump open loop state + NUM_OF_RO_PUMP_STATES ///< Number of RO pump states +} RO_PUMP_STATE_T; + +/// Enumeration of RO pump self-test states. +typedef enum ROPump_Self_Test_States +{ + RO_PUMP_SELF_TEST_STATE_START = 0, ///< RO pump self-test start state + RO_PUMP_TEST_STATE_IN_PROGRESS, ///< RO pump self-tests in progress state + RO_PUMP_TEST_STATE_COMPLETE, ///< RO pump self-tests completed state + NUM_OF_RO_PUMP_SELF_TEST_STATES ///< Number of RO pump self-test states +} RO_PUMP_SELF_TEST_STATE_T; + +// TODO - test code - remove later +// pin assignments for pump test DIP switch 0 +#define RO_PUMP_TEST_SPI5_PORT_MASK 0x00000100 // (ENA - re-purposed as input GPIO) +// dialIn pump stop and direction macros +#define GET_DIP_SW0_TEST() ( ( mibspiREG5->PC2 & RO_PUMP_TEST_SPI5_PORT_MASK ) != 0 ) + +// ********** private data ********** + +static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< current state of RO pump controller state machine +static U32 roPumpDataPublicationTimerCounter = 0; ///< used to schedule RO pump data publication to CAN bus +static BOOL isROPumpOn = FALSE; ///< RO pump is currently running +static F32 roPumpPWMDutyCyclePct = 0.0; ///< initial RO pump PWM duty cycle +static F32 roPumpDutyCyclePctSet = 0.0; ///< currently set RO pump PWM duty cycle +static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< requested RO pump control mode +static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< currently set RO pump control mode + +static F32 targetROPumpFlowRate = 0.0; ///< Target RO flow rate (in L/min) +static U32 targetROPumpPressure = 0; ///< Target RO pressure (in PSI) + static OVERRIDE_U32_T roPumpDataPublishInterval = { RO_PUMP_DATA_PUB_INTERVAL, - RO_PUMP_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus. -static OVERRIDE_U32_T targetROPumpPressure = { 0, 0, 0, 0 }; ///< Target RO pressure (in PSI). -static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured RO flow rate (in LPM). -static F32 measuredROPumpPressure = 0.0; ///< Measured RO pressure (in PSI). - -static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. -static U32 flowFilterCounter = 0; ///< Flow filtering counter. - -static U32 roControlTimerCounter = 0; ///< Timer counter for perform control on RO pump. - -static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current RO pump self-test state. -static U32 roPumpSelfTestTimerCount = 0; ///< Timer counter for RO pump self-test. - -// ********** private function prototypes ********** - -static RO_PUMP_STATE_T handleROPumpOffState( void ); -static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); -static void setROPumpControlSignalPWM( F32 newPWM ); -static void stopROPump( void ); -static void publishROPumpData( void ); -static U32 getPublishROPumpDataInterval( void ); - -/*********************************************************************//** - * @brief - * The initROPump function initializes the ROPump module. - * @details Inputs: none - * @details Outputs: ROPump module initialized. - * @return none - *************************************************************************/ -void initROPump( void ) -{ - stopROPump(); - - // initialize RO pump PI controller - initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE, ROP_P_COEFFICIENT, - ROP_I_COEFFICIENT, MIN_RO_PUMP_PWM_DUTY_CYCLE, MAX_RO_PUMP_PWM_DUTY_CYCLE ); -} - -/*********************************************************************//** - * @brief - * The setROPumpTargetPressure function sets a new target pressure for the RO pump. - * @details Inputs: none - * @details Outputs: targetROPumpPressure, roPumpPWMDutyCyclePct - * @param roPressure new target RO pressure - * @param mode new control mode - * @return TRUE if new target pressure is set, FALSE if not - *************************************************************************/ -BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ) -{ - BOOL result = FALSE; - - // verify pressure - if ( roPressure >= MIN_RO_PRESSURE && roPressure <= MAX_RO_PRESSURE ) - { - targetROPumpPressure.data = roPressure; - roPumpControlMode = mode; - // set PWM duty cycle target to an estimated initial target based on target pressure - then we'll control to pressure going forward -#ifdef EMC_TEST_BUILD - roPumpPWMDutyCyclePct = 1.0; -#else - roPumpPWMDutyCyclePct = ROP_PSI_TO_PWM_DC( roPressure ); -#endif - - result = TRUE; - } - else // requested pressure out of range - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPressure ) // TODO - replace 1st param with s/w fault enum - } - - return result; -} - -/*********************************************************************//** - * @brief - * The signalROPumpHardStop function stops the RO pump immediately. - * @details Inputs: none - * @details Outputs: RO pump stopped, set point reset, state changed to off - * @return none - *************************************************************************/ -void signalROPumpHardStop( void ) -{ - targetROPumpPressure.data = 0; - stopROPump(); - roPumpState = RO_PUMP_OFF_STATE; - roPumpPWMDutyCyclePct = 0.0; - roControlTimerCounter = 0; - resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE ); -} - -/*********************************************************************//** - * @brief - * The execROPumpMonitor function executes the RO Pump monitor. - * @details Inputs: flowFilterCounter - * @details Outputs: measuredROPumpPressure, measuredROFlowRateLPM - * @return none - *************************************************************************/ -void execROPumpMonitor( void ) -{ - U16 roFlowReading = getFPGAROPumpFlowRate(); - S32 roFlow = (S32)roFlowReading; - - // update sum for flow average calculation - measuredFlowReadingsSum += roFlow; - // filter every 250ms - if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) - { - F32 avgROFlow = (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER; - - if ( ( avgROFlow == FLOW_SENSOR_ZERO_READING ) || ( measuredFlowReadingsSum == 0 ) ) - { - measuredROFlowRateLPM.data = 0.0; - } - else - { - measuredROFlowRateLPM.data = RO_FLOW_ADC_TO_LPM_FACTOR / avgROFlow; - } - measuredFlowReadingsSum = 0; - flowFilterCounter = 0; - } - - measuredROPumpPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); - - // TODO - check pressure? - - // TODO - check flow? - - // publish RO pump data on interval - publishROPumpData(); -} - -/*********************************************************************//** - * @brief - * The execROPumpController function executes the RO Pump controller. - * @details Inputs: roPumpState - * @details Outputs: roPumpState - * @return none - *************************************************************************/ -void execROPumpController( void ) -{ - switch ( roPumpState ) - { - case RO_PUMP_OFF_STATE: - roPumpState = handleROPumpOffState(); - break; - - case RO_PUMP_CONTROL_TO_TARGET_STATE: - roPumpState = handleROPumpControlToTargetState(); - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPumpState ) // TODO - replace 1st param with s/w fault enum - roPumpState = RO_PUMP_OFF_STATE; - break; - } -} - -/*********************************************************************//** - * @brief - * The isROPumpOn function returns the status of RO pump. - * @details Inputs: none - * @details Outputs: none - * @return isROPumpOn - *************************************************************************/ -BOOL isReverseOsmosisPumpOn( void ) -{ - return isROPumpOn; -} - -/*********************************************************************//** - * @brief + RO_PUMP_DATA_PUB_INTERVAL, + 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus +static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< measured RO flow rate (in L/min) + +static U32 flowVerificationCounter = 0; ///< Counter to verify the flow is in range + +static U32 roControlTimerCounter = 0; ///< determines when to perform control on RO pump + +static F32 roPumpOpenLoopTargetDutyCycle = 0; ///< Target RO pump open loop PWM +static F32 roPumpFlowRateRunningSum = 0; ///< RO pump flow rate running sum +static F32 roPumpPressureRunningSum = 0; ///< RO pump pressure running sum + +/* These variables are used for POST. POST has not been implemented yet +static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current ro pump self test state +static U32 roPumpSelfTestTimerCount = 0; ///< Timer counter for ro pump self test +*/ + +static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging +static U32 flowFilterCounter = 0; ///< Flow filtering counter +static U32 rampUp2FlowTimeoutCounter = 0; ///< Counter for ramping up to flow time + +// ********** private function prototypes ********** + +static RO_PUMP_STATE_T handleROPumpOffState( void ); +static RO_PUMP_STATE_T handleROPumpRampUpState( void ); +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ); +static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); + +static void setROPumpTargetDutyCycle( F32 duty ); +static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); +static void stopROPump( void ); +static void publishROPumpData( void ); +static U32 getPublishROPumpDataInterval( void ); + +/*********************************************************************//** + * @brief + * The initROPump function initializes the RO Pump module. + * @details Inputs: rampUp2FlowTimeoutCounter + * @details Outputs: rampUp2FlowTimeoutCounter + * @return none + *************************************************************************/ +void initROPump( void ) +{ + stopROPump(); + + // Initialize RO pump PI controller + initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE, ROP_P_COEFFICIENT, ROP_I_COEFFICIENT, + MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); + + // Initialize the I controller during ramp up + initializePIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_DUTY_CYCLE, ROP_RAMP_UP_P_COEFFICIENT, ROP_RAMP_UP_I_COEFFICIENT, + MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); + + // Initialize the persistent alarm for flow out of upper and lower range + initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_UPPER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_RANGE, TRUE, + FLOW_OUT_OF_RANGE_TIME_OUT, FLOW_OUT_OF_RANGE_TIME_OUT ); + + initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_LOWER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_RANGE, TRUE, + FLOW_OUT_OF_RANGE_TIME_OUT, FLOW_OUT_OF_RANGE_TIME_OUT ); + + // Initialize the persistent alarm for max allowed pressure out of range + initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_PRESSURE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, TRUE, + MAX_PRESSURE_OUT_OF_RANGE_TIME_OUT, MAX_PRESSURE_OUT_OF_RANGE_TIME_OUT ); + + rampUp2FlowTimeoutCounter = 0; +} + +/*********************************************************************//** + * @brief + * The setROPumpTargetDutyCycle function sets the duty cycle that the + * pump should run. + * @details Inputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, + * roPumpPWMDutyCyclePctSet, roPumpControlMode + * @details Outputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, + * roPumpPWMDutyCyclePctSet, roPumpControlMode + * @param: duty which is the duty cycle + * @return none + *************************************************************************/ +static void setROPumpTargetDutyCycle( F32 duty ) +{ + roPumpOpenLoopTargetDutyCycle = duty; + roPumpPWMDutyCyclePct = roPumpOpenLoopTargetDutyCycle; + roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; + roPumpControlMode = PUMP_CONTROL_MODE_OPEN_LOOP; +} + +/*********************************************************************//** + * @brief + * The setROPumpTargetFlowRate function sets a new target flow rate for the + * RO pump. + * @details Inputs: targetROPumpPressure, targetROPumpFlowRate, + * roPumpControlMode, rampUp2FlowTimeoutCounter + * @details Outputs: targetROPumpPressure, targetROPumpFlowRate, + * roPumpControlMode, rampUp2FlowTimeoutCounter + * @param roFlowRate which is target RO flow rate + * @param maxPressure which is the maximum allowed pressure that the RO pump + * can reach + * @return TRUE if new target flow rate is set successfully, FALSE if not + *************************************************************************/ +BOOL setROPumpTargetFlowRate( F32 roFlowRate, U32 maxPressure ) +{ + BOOL result = FALSE; + + // First of all, the flow rate must be in range + if ( ( roFlowRate < MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) + { + // Then the max pressure that we are allowed to reach must be in range + if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) + { + // For now maximum allowed pressure is inserted into the target pressure override + // if the target flow rate exceeded the max pressure, it will set the maximum pressure + targetROPumpPressure = maxPressure; + targetROPumpFlowRate = roFlowRate; + roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; + // Get the initial guess of the duty cycle + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); + rampUp2FlowTimeoutCounter = 0; + result = TRUE; + } + // Requested max pressure is out of range + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, maxPressure ) + } + +/*#ifdef EMC_TEST_BUILD + roPumpPWMDutyCyclePct = 1.0; +#else + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); +#endif*/ + } + // Requested flow rate is out of range + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, roFlowRate ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalROPumpHardStop function stops the RO pump immediately and + * resets all the variables associated with the RO pump run. + * @details Inputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, + * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, flowVerificationCounter, + * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter + * @details Outputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, + * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, + * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter + * @return none + *************************************************************************/ +void signalROPumpHardStop( void ) +{ + stopROPump(); + targetROPumpFlowRate = 0; + roPumpState = RO_PUMP_OFF_STATE; + roPumpPWMDutyCyclePct = 0.0; + roPumpOpenLoopTargetDutyCycle = 0.0; + roControlTimerCounter = 0; + flowVerificationCounter = 0; + isROPumpOn = FALSE; + rampUp2FlowTimeoutCounter = 0; + resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE ); +} + +/*********************************************************************//** + * @brief + * The execROPumpMonitor function executes the RO pump monitor. + * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredROFlowRateLPM, measuredROFlowRateLPM, roPumpState, + * flowOutOfRangeCounter, roPumpControlMode + * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredROFlowRateLPM, measuredROFlowRateLPM + * @return none + *************************************************************************/ +void execROPumpMonitor( void ) +{ + U16 roFlowReading = getFPGAROPumpFlowRate(); + S32 roFlow = (S32)roFlowReading; + // Update sum for flow average calculation + measuredFlowReadingsSum += roFlow; + + // Read the pressure at the sensor. The pump cannot be more that the maximum allowed pressure + // to make sure the hardware (especially the ROF) is not damaged. If it is the case, we need to + // stop immediately + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + BOOL isPressureMax = actualPressure >= MAX_ALLOWED_MEASURED_PRESSURE_PSI; + checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure ); + + // Read flow at the control set + if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) + { + F32 avgROFlow = (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER; + + // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that + // the flow is 0. Otherwise, convert the count to flow rate in mL/min + if ( ( roFlowReading == FLOW_SENSOR_ZERO_READING ) || ( roFlowReading == 0 ) ) + { + measuredROFlowRateLPM.data = 0.0; + } + else + { + measuredROFlowRateLPM.data = RO_FLOW_ADC_TO_LPM_FACTOR / avgROFlow; + } + + measuredFlowReadingsSum = 0; + flowFilterCounter = 0; + } + + // To monitor the flow, the control mode must be in closed loop and the pump should be control to target state, + // meaning, it is controlling to a certain pressure + if ( roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP && roPumpState == RO_PUMP_CONTROL_TO_TARGET_STATE ) + { + F32 currentFlow = getMeasuredROFlowRate(); + F32 targetFlow = getTargetROPumpFlowRate(); + F32 error = 1.0 - ( currentFlow / targetFlow ); + BOOL isFlowOutOfRange = error > MAX_ALLOWED_FLOW_DEVIATION; + + // Figure out whether flow is out of range from which side + if ( isFlowOutOfRange ) + { + BOOL isFlowOutOfUpperRange = currentFlow > targetFlow; + BOOL isFlowOutOfLowerRange = currentFlow < targetFlow; + + // Check for flow out of range + checkPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_UPPER_RANGE, isFlowOutOfUpperRange, currentFlow ); + checkPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_LOWER_RANGE, isFlowOutOfLowerRange, currentFlow ); + } + } + + // Publish RO pump data on interval + publishROPumpData(); +} + +/*********************************************************************//** + * @brief + * The execROPumpController function executes the RO pump controller. + * @details Inputs: roPumpState + * @details Outputs: roPumpState + * @return none + *************************************************************************/ +void execROPumpController( void ) +{ + switch ( roPumpState ) + { + case RO_PUMP_OFF_STATE: + roPumpState = handleROPumpOffState(); + break; + + case RO_PUMP_RAMP_UP_STATE: + roPumpState = handleROPumpRampUpState(); + break; + + case RO_PUMP_VERIFY_FLOW_STATE: + roPumpState = handleROPumpVerifyFlowState(); + break; + + case RO_PUMP_CONTROL_TO_TARGET_STATE: + roPumpState = handleROPumpControlToTargetState(); + break; + + case RO_PUMP_OPEN_LOOP_STATE: + roPumpState = handleROPumpOpenLoopState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_EXEC_STATE, roPumpState ) + roPumpState = RO_PUMP_OFF_STATE; + break; + } +} + +/*********************************************************************//** + * @brief + * The isReverseOsmosisPumpOn function returns the on/off status of RO pump. + * @details Inputs: isROPumpOn + * @details Outputs: none + * @return isROPumpOn the boolean flag that is TRUE if the pump is on and + * FALSE if it is off + *************************************************************************/ +BOOL isReverseOsmosisPumpOn( void ) +{ + return isROPumpOn; +} + +/*********************************************************************//** + * @brief + * The execROPumpTest function executes the state machine for the RO pump + * self-test. + * @details + * Inputs: TODO FILL UP + * Outputs: TODO FILL UP + * @return the current state of the ROPump self test. + *************************************************************************/ +SELF_TEST_STATUS_T execROPumpTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; + + // TODO - implement self-test(s) + + return result; +} + +/*********************************************************************//** + * @brief * The handleROPumpOffState function handles the RO pump off state of the - * RO pump controller state machine. - * @details Inputs: targetROPumpPressure - * @details Outputs: roPumpPWMDutyCyclePctSet, isROPumpOn - * @return next state - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpOffState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_OFF_STATE; - -#ifdef DEBUG_ENABLED -#ifdef ENABLE_DIP_SWITCHES - // TODO - test code - remove later - if ( GET_DIP_SW0_TEST() ) - { - setValveState( VSP, VALVE_STATE_CLOSED ); - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setROPumpTargetPressure( 120, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#ifdef EMC_TEST_BUILD - { - F32 fanPWM = 0.25; - etpwmSetCmpA( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); - etpwmSetCmpB( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); - setPrimaryHeaterTargetTemperature( 50.0 ); - startPrimaryHeater(); - } -#endif - } -#endif -#endif - - // if we've been given a pressure, transition to control to target state - if ( getTargetROPumpPressure() > 0 ) - { - roPumpControlModeSet = roPumpControlMode; - // set initial PWM duty cycle - roPumpPWMDutyCyclePctSet = roPumpPWMDutyCyclePct; - setROPumpControlSignalPWM( roPumpPWMDutyCyclePctSet ); - // reset controller - resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpPWMDutyCyclePctSet ); - // set pump to on - isROPumpOn = TRUE; - result = RO_PUMP_CONTROL_TO_TARGET_STATE; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The handleROPumpControlToTargetState function handles the "control to - * target" state of the RO pump controller state machine. - * @details Inputs: none - * @details Outputs: roPumpState - * @return next state - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_CONTROL_TO_TARGET_STATE; - - // control at set interval - if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) - { - if ( roPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) - { - F32 tgtPres = (F32)getTargetROPumpPressure(); - F32 actPres = measuredROPumpPressure; - F32 newPWM; - -#ifndef EMC_TEST_BUILD - newPWM = runPIController( PI_CONTROLLER_ID_RO_PUMP, tgtPres, actPres ); - roPumpPWMDutyCyclePctSet = newPWM; - setROPumpControlSignalPWM( newPWM ); -#endif - } - roControlTimerCounter = 0; - } - -#ifdef DEBUG_ENABLED -#ifdef ENABLE_DIP_SWITCHES - // TODO - test code - remove later - if ( !GET_DIP_SW0_TEST() ) - { - signalROPumpHardStop(); - result = RO_PUMP_OFF_STATE; -#ifdef EMC_TEST_BUILD - etpwmSetCmpA( etpwmREG6, 0 ); - etpwmSetCmpB( etpwmREG6, 0 ); - stopPrimaryHeater(); -#endif - } -#endif -#endif - - return result; -} - -/*********************************************************************//** - * @brief - * The setROPumpControlSignalPWM function sets the PWM duty cycle for the - * RO pump to a given %. - * @details Inputs: none - * @details Outputs: PWM duty cycle zeroed - * @param newPWM new duty cycle % to apply to PWM - * @return none - *************************************************************************/ -static void setROPumpControlSignalPWM( F32 newPWM ) -{ - etpwmSetCmpB( etpwmREG2, (U32)( (S32)( ( newPWM * (F32)(etpwmREG2->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); -} - -/*********************************************************************//** - * @brief - * The stopROPump function sets the RO pump PWM to zero. - * @details Inputs: none - * @details Outputs: PWM duty cycle zeroed - * @return none - *************************************************************************/ -static void stopROPump( void ) -{ - isROPumpOn = FALSE; - roPumpPWMDutyCyclePctSet = 0.0; - etpwmSetCmpB( etpwmREG2, 0 ); -} - -/*********************************************************************//** - * @brief - * The getPublishROPumpDataInterval function gets the RO pump data publish interval. - * @details Inputs: roPumpDataPublishInterval - * @details Outputs: none - * @return the current RO pump data publication interval (in ms). - *************************************************************************/ -static U32 getPublishROPumpDataInterval( void ) -{ - U32 result = roPumpDataPublishInterval.data; - - if ( OVERRIDE_KEY == roPumpDataPublishInterval.override ) - { - result = roPumpDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getTargetROPumpPressure function gets the current target RO pump pressure. - * @details Inputs: targetROPumpPressure - * @details Outputs: none - * @return the current target RO pressure (in PSI). - *************************************************************************/ -U32 getTargetROPumpPressure( void ) -{ - U32 result = targetROPumpPressure.data; - - if ( OVERRIDE_KEY == targetROPumpPressure.override ) - { - result = targetROPumpPressure.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getMeasuredROFlowRate function gets the measured RO pump flow rate. - * @details Inputs: measuredROFlowRateLPM - * @details Outputs: none - * @return the current RO pump flow rate (in LPM). - *************************************************************************/ -F32 getMeasuredROFlowRate( void ) -{ - F32 result = measuredROFlowRateLPM.data; - - if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) - { - result = measuredROFlowRateLPM.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The publishROPumpData function publishes RO pump data at the set interval. - * @details Inputs: target pressure, measured pressure, measured RO pump speed. - * @details Outputs: RO pump data is published to CAN bus. - * @return none - *************************************************************************/ -static void publishROPumpData( void ) -{ - // publish RO pump data on interval - if ( ++roPumpDataPublicationTimerCounter >= getPublishROPumpDataInterval() ) - { - U32 presStPt = getTargetROPumpPressure(); - F32 measFlow = getMeasuredROFlowRate(); - F32 pumpPWMPctDutyCycle = roPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; - broadcastROPumpData( presStPt, measFlow, pumpPWMPctDutyCycle ); - roPumpDataPublicationTimerCounter = 0; - } -} - -/*********************************************************************//** - * @brief - * The execROPumpTest function executes the state machine for the ROPump self-test. - * @details Inputs: none - * @details Outputs: none - * @return the current state of the ROPump self-test. - *************************************************************************/ -SELF_TEST_STATUS_T execROPumpTest( void ) -{ - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - - // TODO - implement self-test(s) - - return result; -} - - -/************************************************************************* - * TEST SUPPORT FUNCTIONS - *************************************************************************/ + * controller state machine. + * @details Inputs: roPumpControlMode, roPumpControlModeSet, roPumpControlMode, + * roPumpPWMDutyCyclePctSet, roPumpPWMDutyCyclePct, isROPumpOn, + * roPumpOpenLoopTargetDutyCycle + * @details Outputs: roPumpControlModeSet, roPumpPWMDutyCyclePctSet, + * roPumpPWMDutyCyclePct, isROPumpOn + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpOffState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_OFF_STATE; - -/*********************************************************************//** - * @brief - * The testSetROPumpDataPublishIntervalOverride function overrides the - * RO pump data publish interval. - * @details Inputs: none - * @details Outputs: roPumpDataPublishInterval - * @param value override RO pump data publish interval with (in ms) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - U32 intvl = value / TASK_PRIORITY_INTERVAL; - - result = TRUE; - roPumpDataPublishInterval.ovData = intvl; - roPumpDataPublishInterval.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetROPumpDataPublishIntervalOverride function resets the override - * of the RO pump data publish interval. - * @details Inputs: none - * @details Outputs: roPumpDataPublishInterval - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetROPumpDataPublishIntervalOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - roPumpDataPublishInterval.override = OVERRIDE_RESET; - roPumpDataPublishInterval.ovData = roPumpDataPublishInterval.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetTargetROPumpPressureOverride function overrides the target - * RO pressure. - * @details Inputs: none - * @details Outputs: targetROPumpPressure - * @param value override target RO pressure (in PSI) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetTargetROPumpPressureOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - targetROPumpPressure.ovInitData = targetROPumpPressure.data; // backup current target pressure - targetROPumpPressure.ovData = value; - targetROPumpPressure.override = OVERRIDE_KEY; - result = setROPumpTargetPressure( value, roPumpControlMode ); - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetTargetROPumpPressureOverride function resets the override of the - * target RO pressure. - * @details Inputs: none - * @details Outputs: targetROPumpPressure - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetTargetROPumpPressureOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - targetROPumpPressure.data = targetROPumpPressure.ovInitData; // restore pre-override target pressure - targetROPumpPressure.override = OVERRIDE_RESET; - targetROPumpPressure.ovInitData = 0; - targetROPumpPressure.ovData = 0; - result = setROPumpTargetPressure( targetROPumpPressure.data, roPumpControlMode ); - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetMeasuredROFlowRateOverride function overrides the measured - * RO flow rate. - * @details Inputs: none - * @details Outputs: measuredROFlowRateLPM - * @param value override measured RO pump motor speed (in LPM) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetMeasuredROFlowRateOverride( F32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - measuredROFlowRateLPM.ovData = value; - measuredROFlowRateLPM.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetMeasuredROFlowRateOverride function resets the override of the - * measured RO flow rate. - * @details Inputs: none - * @details Outputs: measuredROFlowRateLPM - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testResetMeasuredROFlowRateOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - measuredROFlowRateLPM.override = OVERRIDE_RESET; - measuredROFlowRateLPM.ovData = measuredROFlowRateLPM.ovInitData; - } - - return result; -} +#ifdef DEBUG_ENABLED +#ifdef ENABLE_DIP_SWITCHES + // TODO - test code - remove later + if ( GET_DIP_SW0_TEST() ) + { + setValveState( VSP, VALVE_STATE_CLOSED ); + setValveState( VPI, VALVE_STATE_OPEN ); + setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); + setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); + setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); + setROPumpTargetPressure( 120 ); +#ifdef EMC_TEST_BUILD + { + F32 fanPWM = 0.25; + etpwmSetCmpA( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); + etpwmSetCmpB( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); + setPrimaryHeaterTargetTemperature( 50.0 ); + startPrimaryHeater(); + } +#endif + } +#endif +#endif + // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow + if ( getTargetROPumpFlowRate() > 0 && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + roPumpControlModeSet = roPumpControlMode; + // Set initial PWM duty cycle + roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + // Reset controller + resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, roPumpDutyCyclePctSet ); + // Set pump to on + isROPumpOn = TRUE; + result = RO_PUMP_RAMP_UP_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 && roPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) + { + setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); + isROPumpOn = TRUE; + result = RO_PUMP_OPEN_LOOP_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpRampUpState function handles the RO pump ramp up state + * of the controller state machine. + * @details Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, + * rampUp2FlowTimeoutCounter + * @details Outputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, + * rampUp2FlowTimeoutCounter + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpRampUpState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_RAMP_UP_STATE; + + // Get the current pressure from the sensor + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // If we are still in the ramp up mode after the specified time, get the current pressure + // and control from this + if ( ++rampUp2FlowTimeoutCounter > RAMP_UP_TIME_OUT_COUNT ) + { + targetROPumpPressure = actualPressure; + rampUp2FlowTimeoutCounter = 0; + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + // Control at set interval + else if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) + { + F32 targetFlowRate = getTargetROPumpFlowRate(); + F32 actualFlowRate = (F32)getMeasuredROFlowRate(); + + // 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 > getTargetROPumpPressure() || ( getTargetROPumpPressure() - actualPressure ) > MAX_PRESSURE_TARGET_TOLERANCE ) + { + result = RO_PUMP_CONTROL_TO_TARGET_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 ( fabs( actualFlowRate - targetFlowRate ) > ROP_FLOW_TARGET_TOLERANCE ) + { + roPumpDutyCyclePctSet = runPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, targetFlowRate, actualFlowRate ); + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + } + // Reached to the target flow go to the next state + else + { + result = RO_PUMP_VERIFY_FLOW_STATE; + } + + roControlTimerCounter = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpVerifyFlowState function handles the RO pump verify + * flow state of the RO pump controller state machine. + * @details Inputs: flowVerificationCounter, targetROPumpPressure, + * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum + * @details Outputs: flowVerificationCounter, targetROPumpPressure, + * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_VERIFY_FLOW_STATE; + + // Calculate the running sum of the flow rate and RO pump outlet pressure + roPumpFlowRateRunningSum = roPumpFlowRateRunningSum + (F32)getMeasuredROFlowRate(); + roPumpPressureRunningSum = roPumpPressureRunningSum + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // Check if the time for flow verification has elapsed + if ( ++flowVerificationCounter >= FLOW_VERIFICATION_COUNTER_TARGET ) + { + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // If the flow has been achieved without reaching to the maximum pressure, set the new pressure + // otherwise, stay with the maximum allowed pressure as target pressure + if ( actualPressure < getTargetROPumpPressure() ) + { + // Calculate the average pressure and flow rate + F32 avgPressure = roPumpPressureRunningSum / flowVerificationCounter; + F32 avgFlowRate = roPumpFlowRateRunningSum / flowVerificationCounter; + + F32 targetFlowRate = getTargetROPumpFlowRate(); + + // Calculate the flow rate deviation from the target flow rate + F32 flowRateDeviation = ( targetFlowRate - avgFlowRate ) / targetFlowRate; + // Use the flow rate deviation to adjust the average calculated pressure. This + // pressure is used as the target pressure + avgPressure = avgPressure + ( avgPressure * flowRateDeviation ); + // Save the target pressure + targetROPumpPressure = avgPressure; + } + + // Reset the I controller for the flow rate as it is no longer needed + resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_DUTY_CYCLE ); + + // Set initial PWM duty cycle + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + // Reset controller + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); + // Reset all the variables before leaving + flowVerificationCounter = 0; + roPumpFlowRateRunningSum = 0; + roPumpPressureRunningSum = 0; + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpControlToTargetState function handles the control to + * target state of the RO pump controller state machine. + * @details Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter, + * roPumpControlModeSet + * @details Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_CONTROL_TO_TARGET_STATE; + + // Control at set interval + if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL && roPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + // Get the pressure to use it for setting the control + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP, getTargetROPumpPressure(), actualPressure ); + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + + roControlTimerCounter = 0; + } + +#ifdef DEBUG_ENABLED +#ifdef ENABLE_DIP_SWITCHES + // TODO - test code - remove later + if ( !GET_DIP_SW0_TEST() ) + { + signalROPumpHardStop(); + result = RO_PUMP_OFF_STATE; +#ifdef EMC_TEST_BUILD + etpwmSetCmpA( etpwmREG6, 0 ); + etpwmSetCmpB( etpwmREG6, 0 ); + stopPrimaryHeater(); +#endif + } +#endif +#endif + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpOpenLoopState function handles the open loop state of + * the RO pump controller state machine. + * @details Inputs: none + * @details Outputs: none + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ) +{ + return RO_PUMP_OPEN_LOOP_STATE; +} + +/*********************************************************************//** + * @brief + * The setROPumpControlSignalDutyCycle function sets the duty cycle for the + * RO pump to a given duty cycle. + * @details Inputs: none + * @details Outputs: none + * @param dutyCycle which is the duty cycle + * @return none + *************************************************************************/ +static void setROPumpControlSignalDutyCycle( F32 dutyCycle ) +{ + etpwmSetCmpB( etpwmREG2, (U32)( (S32)( ( dutyCycle * (F32)(etpwmREG2->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The stopROPump function sets the RO pump duty cycle to zero. + * @details Inputs: isROPumpOn, roPumpPWMDutyCyclePctSet + * @details Outputs: isROPumpOn, roPumpPWMDutyCyclePctSet + * @return none + *************************************************************************/ +static void stopROPump( void ) +{ + isROPumpOn = FALSE; + roPumpDutyCyclePctSet = 0.0; + etpwmSetCmpB( etpwmREG2, 0 ); +} + +/*********************************************************************//** + * @brief + * The getPublishROPumpDataInterval function gets the RO pump data publish + * interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @return the current RO pump data publication interval (in ms). + *************************************************************************/ +static U32 getPublishROPumpDataInterval( void ) +{ + U32 result = roPumpDataPublishInterval.data; + + if ( OVERRIDE_KEY == roPumpDataPublishInterval.override ) + { + result = roPumpDataPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTargetROPumpFlowRate function gets the current target RO pump + * flow rate. + * @details Inputs: targetROPumpFlowRate + * @details Outputs: targetROPumpFlowRate + * @return the current target RO flow rate (in L/min). + *************************************************************************/ +F32 getTargetROPumpFlowRate( void ) +{ + return targetROPumpFlowRate; +} + +/*********************************************************************//** + * @brief + * The getMeasuredROFlowRate function gets the measured RO pump flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @return the current RO pump flow rate (in L/min). + *************************************************************************/ +F32 getMeasuredROFlowRate( void ) +{ + F32 result = measuredROFlowRateLPM.data; + + if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) + { + result = measuredROFlowRateLPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTargetROPumpPressure function gets the current target RO pump + * pressure. + * @details Inputs: targetROPumpPressure + * @details Outputs: targetROPumpPressure + * @return the current target RO targetROPumpPressure in psi. + *************************************************************************/ +F32 getTargetROPumpPressure( void ) +{ + return targetROPumpPressure; +} + +/*********************************************************************//** + * @brief + * The publishROPumpData function publishes RO pump data at the set interval. + * @details Inputs: roPumpDataPublicationTimerCounter + * @details Outputs: roPumpDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishROPumpData( void ) +{ + // publish RO pump data on interval + if ( ++roPumpDataPublicationTimerCounter >= getPublishROPumpDataInterval() ) + { + RO_PUMP_DATA_T pumpData; + + pumpData.roPumpTgtPressure = getTargetROPumpPressure(); + pumpData.measROFlowRate = getMeasuredROFlowRate(); + pumpData.roPumpDutyCycle = roPumpDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + pumpData.roPumpState = (U32)roPumpState; + + broadcastROPumpData( &pumpData ); + roPumpDataPublicationTimerCounter = 0; + } +} + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetROPumpDataPublishIntervalOverride function overrides the + * RO pump data publish interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @param: value : override RO pump data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_PRIORITY_INTERVAL; + roPumpDataPublishInterval.ovData = intvl; + roPumpDataPublishInterval.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetROPumpDataPublishIntervalOverride function resets the + * override of the RO pump data publish interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetROPumpDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + roPumpDataPublishInterval.override = OVERRIDE_RESET; + roPumpDataPublishInterval.ovData = roPumpDataPublishInterval.ovInitData; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetROPumpFlowRateOverride function overrides the target + * flow rate. + * @details Inputs: none + * @details Outputs: none + * @param value which is override target RO flow rate (in L/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetROPumpFlowAndPressure( F32 flow, U32 pressure ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // The flow rate and pressure must be in range + if ( flow < MAX_RO_FLOWRATE_LPM && flow >= MIN_RO_FLOWRATE_LPM ) + { + if ( pressure >= MIN_ALLOWED_PRESSURE_PSI && pressure <= MAX_ALLOWED_PRESSURE_PSI ) + { + result = setROPumpTargetFlowRate( flow, pressure ); + } + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetROPumpPressureOverride function overrides the target + * RO pressure. + * @details Inputs: targetROPumpPressure + * @details Outputs: targetROPumpPressure + * @param value override target RO pressure (in psi) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetROPumpPressure( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // Make sure the requested pressure is in range + if ( value >= MIN_ALLOWED_PRESSURE_PSI && value <= MAX_ALLOWED_PRESSURE_PSI ) + { + targetROPumpPressure = value; + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredROFlowRateOverride function overrides the measured + * RO flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @param: value : override measured RO pump motor speed (in L/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredROFlowRateOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + measuredROFlowRateLPM.ovInitData = measuredROFlowRateLPM.data; + measuredROFlowRateLPM.ovData = value; + measuredROFlowRateLPM.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredROFlowRateOverride function resets the override + * of the measured RO flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredROFlowRateOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + measuredROFlowRateLPM.data = measuredROFlowRateLPM.ovInitData; + measuredROFlowRateLPM.override = OVERRIDE_RESET; + measuredROFlowRateLPM.ovInitData = 0.0; + measuredROFlowRateLPM.ovData = 0.0; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetDutyCycleOverride function overrides the target duty + * cycle of the RO pump. + * @details Inputs: none + * @details Outputs: none + * @param value which is the duty cycle to be set + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetDutyCycle( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // Check if duty cycle is within range + if ( value >= MIN_RO_PUMP_DUTY_CYCLE && value <= MAX_RO_PUMP_DUTY_CYCLE ) + { + setROPumpTargetDutyCycle( value ); + result = TRUE; + } + } + + return result; +} + /**@}*/ Index: firmware/App/Controllers/ROPump.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Controllers/ROPump.h (.../ROPump.h) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,48 +14,66 @@ * @date (original) 04-Apr-2020 * ***************************************************************************/ - -#ifndef __RO_PUMP_H__ -#define __RO_PUMP_H__ - -#include "DGCommon.h" - -/** - * @defgroup ROPump ROPump - * @brief RO Pump monitor and controller module. Controls and monitors the RO pump. - * - * @addtogroup ROPump - * @{ - */ - -// ********** public definitions ********** - -#define MAX_RO_PRESSURE 140 ///< Maximum target RO outlet pressure (in PSI). -#define MIN_RO_PRESSURE 100 ///< Minimum target RO outlet pressure (in PSI). - -// ********** public function prototypes ********** - -void initROPump( void ); -void execROPumpMonitor( void ); -void execROPumpController( void ); - -BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ); -void signalROPumpHardStop( void ); - -BOOL isReverseOsmosisPumpOn( void ); - -SELF_TEST_STATUS_T execROPumpTest( void ); -U32 getTargetROPumpPressure( void ); -F32 getMeasuredROFlowRate( void ); - -BOOL testSetROPumpDataPublishIntervalOverride( U32 value ); -BOOL testResetROPumpDataPublishIntervalOverride( void ); -BOOL testSetTargetROPumpPressureOverride( U32 value ); -BOOL testResetTargetROPumpPressureOverride( void ); -BOOL testSetMeasuredROFlowRateOverride( F32 value ); -BOOL testResetMeasuredROFlowRateOverride( void ); - -/**@}*/ - -#endif +#ifndef __RO_PUMP_H__ +#define __RO_PUMP_H__ + +#include "DGCommon.h" + +/** + * @defgroup ROPump ROPump + * @brief RO Pump monitor and controller module. Controls and monitors the RO pump and the flow meter. + * The flow meter is manufactured by SwissFlow, PN: 82015311. + * The diaphragm (RO) pump is manufactured by Aquatec, PN: 5889-2MM1-V724DY. + * + * @addtogroup ROPump + * @{ + */ + +// ********** public definitions ********** +#define MAX_RO_FLOWRATE_LPM 1.0 ///< Maximum target RO flow rate in L/min. +#define MIN_RO_FLOWRATE_LPM 0.2 ///< Minimum target RO flow rate in L/min. + +/// RO pump data struct. +typedef struct +{ + F32 roPumpTgtPressure; ///< RO pump target pressure + F32 measROFlowRate; ///< RO flow rate measurement + F32 roPumpDutyCycle; ///< RO pump duty cycle + U32 roPumpState; ///< RO pump current state +} RO_PUMP_DATA_T; + +// ********** public function prototypes ********** + +void initROPump( void ); +void execROPumpMonitor( void ); +void execROPumpController( void ); + +BOOL setROPumpTargetFlowRate( F32 roFlowRate, U32 maxPressure ); + +void signalROPumpHardStop( void ); + +BOOL isReverseOsmosisPumpOn( void ); + +SELF_TEST_STATUS_T execROPumpTest( void ); + +F32 getTargetROPumpFlowRate( void ); +F32 getMeasuredROFlowRate( void ); + +F32 getTargetROPumpPressure( void ); + +BOOL testSetROPumpDataPublishIntervalOverride( U32 value ); +BOOL testResetROPumpDataPublishIntervalOverride( void ); + +BOOL testSetMeasuredROFlowRateOverride( F32 value ); +BOOL testResetMeasuredROFlowRateOverride( void ); + +BOOL testSetTargetROPumpFlowAndPressure( F32 flow, U32 pressure ); + +BOOL testSetTargetROPumpPressure( U32 value ); + +BOOL testSetTargetDutyCycle( F32 value ); + +/**@}*/ + +#endif Index: firmware/App/Modes/ModeFill.c =================================================================== diff -u -r3461c140ba07e74863dee1d4c51d0119076fecf8 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 3461c140ba07e74863dee1d4c51d0119076fecf8) +++ firmware/App/Modes/ModeFill.c (.../ModeFill.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -71,8 +71,9 @@ { fillState = DG_FILL_MODE_STATE_START; - initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, - FALSE, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD ); + // TODO figure this out + //initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, + // FALSE, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD, RO_FLOW_RATE_OUT_OF_RANGE_PERSISTENCE_PERIOD ); } /*********************************************************************//** @@ -170,7 +171,7 @@ requestConcentratePumpsOn( CONCENTRATEPUMPS_CP2 ); // TODO: Change to set flow rate once RO pump driver is updated // setROPumpFlowRate( FILL_TARGET_RO_FLOW_RATE ); - setROPumpTargetPressure( FILL_TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); + //setROPumpTargetPressure( FILL_TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); result = DG_FILL_MODE_STATE_DIALYSATE_PRODUCTION; } @@ -268,7 +269,7 @@ setConcentratePumpTargetSpeed( CONCENTRATEPUMPS_CP2, bicarbCP2PumpFlowRate ); BOOL const isROPumpFlowRateOutOfRange = ( measuredROFlowRate <= FILL_MIN_RO_FLOW_RATE ) || ( measuredROFlowRate >= FILL_MAX_RO_FLOW_RATE ); - checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, isROPumpFlowRateOutOfRange, measuredROFlowRate ); + //checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_FLOW_RATE_OUT_OF_RANGE, isROPumpFlowRateOutOfRange, measuredROFlowRate ); TODO figure this out } /**@}*/ Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r3461c140ba07e74863dee1d4c51d0119076fecf8 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 3461c140ba07e74863dee1d4c51d0119076fecf8) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -84,7 +84,7 @@ setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setROPumpTargetPressure( TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); + //setROPumpTargetPressure( TARGET_RO_PRESSURE_PSI, PUMP_CONTROL_MODE_CLOSED_LOOP ); TODO fill this up signalDrainPumpHardStop(); startPrimaryHeater(); requestConcentratePumpsOff( CONCENTRATEPUMPS_CP1 ); Index: firmware/App/Services/AlarmMgmt.h =================================================================== diff -u -ra726311564521affd46cbbaf129bdffb22e1d58f -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision a726311564521affd46cbbaf129bdffb22e1d58f) +++ firmware/App/Services/AlarmMgmt.h (.../AlarmMgmt.h) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -147,6 +147,21 @@ SW_FAULT_ID_CONCENTRATE_PUMP_EXEC_INVALID_STATE, // 55 SW_FAULT_ID_CONCENTRATE_PUMP_INVALID_PUMP_ID, SW_FAULT_ID_CONCENTRATE_PUMP_SPEED_OUT_OF_RANGE, + SW_FAULT_ID_UV_REACTORS_INVALID_EXEC_STATE, + SW_FAULT_ID_UV_REACTORS_INVALID_SELF_TEST_STATE, + SW_FAULT_ID_THERMISTORS_INVALID_EXEC_STATE, // 60 + SW_FAULT_ID_THERMISTORS_INVALID_SELF_TEST_STATE, + SW_FAULT_ID_INVALID_THERMISTOR_SELECTED, + SW_FAULT_ID_FAN_INVALID_EXEC_STATE, + SW_FAULT_ID_FAN_INVALID_SELF_TEST_STATE, + SW_FAULT_ID_INVALID_FAN_SELECTED, // 65 + SW_FAULT_ID_RO_PUMP_INVALID_EXEC_STATE, + SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, + SW_FAULT_ID_DRAIN_PUMP_INVALID_EXEC_STATE, + SW_FAULT_ID_UV_REACTORS_INVALID_REACTOR_SELECTD, + SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, // 70 + SW_FAULT_ID_DRAIN_PUMP_INVALID_DELTA_PRESSURE_SELECTED, + SW_FAULT_ID_INVALID_TEMPERATURE_SENSOR_SELECTED, NUM_OF_SW_FAULT_IDS } SW_FAULT_ID_T; Index: firmware/App/Services/MessagePayloads.h =================================================================== diff -u -r7cc6fbb41e6b460fedff71581f6205ef36d5deb6 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/MessagePayloads.h (.../MessagePayloads.h) (revision 7cc6fbb41e6b460fedff71581f6205ef36d5deb6) +++ firmware/App/Services/MessagePayloads.h (.../MessagePayloads.h) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -67,14 +67,6 @@ F32 loadCellB2inGram; ///< Loadcell B2 measurement in gram } LOAD_CELL_DATA_T; -/// RO pump data struct. -typedef struct -{ - U32 setROPumpPressure; ///< RO pump pressure set target - F32 measROFlowRate; ///< RO flow rate measurement - F32 roPumpPWM; ///< RO pump pwm -} RO_PUMP_DATA_T; - /// Drain pump data struct. typedef struct { Index: firmware/App/Services/PIControllers.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Services/PIControllers.c (.../PIControllers.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,231 +14,252 @@ * @date (original) 04-Feb-2020 * ***************************************************************************/ - -#include "math.h" - -#include "SystemCommMessages.h" -#include "PIControllers.h" - -/** - * @addtogroup PIControllers - * @{ - */ - -// ********** private definitions ********** -/// Record for PI controller. -typedef struct { - // -- PI's parameters -- - F32 Kp; ///< Proportional Value. - F32 Ki; ///< Integral Value. - F32 uMax; ///< Maximum control signal. - F32 uMin; ///< Minimum control signal. - // -- PI's signals -- - F32 referenceSignal; ///< reference signal. - F32 measuredSignal; ///< measured signal. - F32 errorSignal; ///< reference - measured signal. - F32 errorSumBeforeWindUp; ///< error signal before windup correction. - F32 errorSum; ///< error integral after windup correction. - F32 controlSignal; ///< actual control signal. -} PI_CONTROLLER_T; - -#define MIN_KI NEARLY_ZERO ///< minimum integral coefficient - cannot be zero. -#define SET_CONTROLLER( c, id ) ( (c) = &piControllers[ id ] ) ///< macro to set a local controller pointer to a given piController. - -// ********** private data ********** - -/// PI Controllers - initial configurations. -static PI_CONTROLLER_T piControllers[ NUM_OF_PI_CONTROLLERS_IDS ] = -{ // Kp Ki uMax uMin ref meas err esw esum ctrl - { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_RO_PUMP - { 0.0, 0.0, 0.89, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, // PI_CONTROLLER_ID_PRIMARY_HEATER - { 0.0, 0.0, 0.50, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } // PI_CONTROLLER_ID_TRIMMER_HEATER -}; - -/*********************************************************************//** - * @brief +#include "math.h" + +#include "SystemCommMessages.h" +#include "PIControllers.h" + +/** + * @addtogroup PIControllers + * @{ + */ + +// ********** private definitions ********** + +/// Enumeration of PI controller direction. +typedef enum controller_Directions +{ + CONTROLLER_BIDIRECTIONAL = 0, ///< Controller runs bidirectional so it only covers positive and negative values + CONTROLLER_UNIDIRECTIONAL, ///< Controller run unidirectional so it only covers positive values + NUM_OF_CONTROLLELR_DIRECTIONS ///< Number of PI controllers directions +} PI_CONTROLLER_DIRECTIONS_T; + +/// Record for PI controller. +typedef struct { + // -- PI's parameters -- + F32 Kp; ///< Proportional Value. + F32 Ki; ///< Integral Value. + F32 uMax; ///< Maximum control signal. + F32 uMin; ///< Minimum control signal. + // -- PI's signals -- + F32 referenceSignal; ///< reference signal. + F32 measuredSignal; ///< measured signal. + F32 errorSignal; ///< reference - measured signal. + F32 errorSumBeforeWindUp; ///< error signal before windup correction. + F32 errorSum; ///< error integral after windup correction. + F32 controlSignal; ///< actual control signal. + PI_CONTROLLER_DIRECTIONS_T direction; ///< PI controller control direction. +} PI_CONTROLLER_T; + +#define MIN_KI NEARLY_ZERO ///< minimum integral coefficient - cannot be zero. +#define SET_CONTROLLER( c, id ) ( (c) = &piControllers[ id ] ) ///< macro to set a local controller pointer to a given piController. + +// ********** private data ********** + +/// PI Controllers - initial configurations. +static PI_CONTROLLER_T piControllers[ NUM_OF_PI_CONTROLLERS_IDS ] = +{ // Kp Ki uMax uMin ref meas err esw esum ctrl + { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_RO_PUMP + { 0.0, 0.0, 0.99, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // I_CONTROLLER_ID_RO_PUMP_RAMP_UP + { 0.0, 0.0, 3000, 300, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_BIDIRECTIONAL }, // PI_CONTROLLER_ID_DRAIN_PUMP + { 0.0, 0.0, 1.39, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL }, // PI_CONTROLLER_ID_PRIMARY_HEATER + { 0.0, 0.0, 0.50, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, CONTROLLER_UNIDIRECTIONAL } // PI_CONTROLLER_ID_TRIMMER_HEATER +}; + +/*********************************************************************//** + * @brief * The initializePIController function initializes controller before operation. * Make sure to call it before first call to runController function. * @details Inputs: none - * @details Outputs: PI controllers module initialized - * @param controllerID ID filter number - * @param initialControlSignal Value of the output on the first iteration - * @param kP Coefficient for proportional - * @param kI Coefficient for integral - * @param controlMin Minimum control output - * @param controlMax Maximum control output - * @return none - *************************************************************************/ -void initializePIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal, - F32 kP, F32 kI, F32 controlMin, F32 controlMax ) -{ - PI_CONTROLLER_T *controller; - - if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) - { - SET_CONTROLLER( controller, controllerID ); - - controller->Kp = kP; - if ( fabs( kI ) > MIN_KI ) // ensure kI is not zero - { - controller->Ki = kI; - } - else - { - controller->Ki = ( kI < 0.0 ? MIN_KI * -1.0 : MIN_KI ); - } - controller->uMin = controlMin; - controller->uMax = controlMax; - resetPIController( controllerID, initialControlSignal ); - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) - } -} - -/*********************************************************************//** - * @brief + * @details Outputs: PI controllers module initialized + * @param controllerID ID filter number + * @param initialControlSignal Value of the output on the first iteration + * @param kP Coefficient for proportional + * @param kI Coefficient for integral + * @param controlMin Minimum control output + * @param controlMax Maximum control output + * @return none + *************************************************************************/ +void initializePIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal, + F32 kP, F32 kI, F32 controlMin, F32 controlMax ) +{ + PI_CONTROLLER_T *controller; + + if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) + { + SET_CONTROLLER( controller, controllerID ); + + controller->Kp = kP; + if ( fabs( kI ) > MIN_KI ) // ensure kI is not zero + { + controller->Ki = kI; + } + else + { + controller->Ki = ( kI < 0.0 ? MIN_KI * -1.0 : MIN_KI ); + } + controller->uMin = controlMin; + controller->uMax = controlMax; + resetPIController( controllerID, initialControlSignal ); + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) + } +} + +/*********************************************************************//** + * @brief * The resetPIController functions resets controller before new set point. * Make sure to call it before first call to runController function. * @details Inputs: none - * @details Outputs: Reset a PI controller - * @param controllerID ID filter number - * @param initialControlSignal Value of the output on the first iteration - * @return none - *************************************************************************/ -void resetPIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal ) -{ - PI_CONTROLLER_T *controller; - - if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) - { - SET_CONTROLLER( controller, controllerID ); - controller->controlSignal = RANGE( initialControlSignal, controller->uMin, controller->uMax ); - controller->referenceSignal = 0.0; - controller->errorSignal = 0.0; - controller->errorSum = controller->controlSignal / controller->Ki; - controller->errorSumBeforeWindUp = controller->errorSum; - controller->measuredSignal = 0.0; - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) - } -} - -/*********************************************************************//** - * @brief + * @details Outputs: Reset a PI controller + * @param controllerID ID filter number + * @param initialControlSignal Value of the output on the first iteration + * @return none + *************************************************************************/ +void resetPIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal ) +{ + PI_CONTROLLER_T *controller; + + if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) + { + SET_CONTROLLER( controller, controllerID ); + controller->controlSignal = RANGE( initialControlSignal, controller->uMin, controller->uMax ); + controller->referenceSignal = 0.0; + controller->errorSignal = 0.0; + controller->errorSum = controller->controlSignal / controller->Ki; + controller->errorSumBeforeWindUp = controller->errorSum; + controller->measuredSignal = 0.0; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) + } +} + +/*********************************************************************//** + * @brief * The runPIController functions executes a PI controller with a new sampled measured signal. * @details Inputs: none - * @details Outputs: Feeds new signal to PI controller - * @param controllerID ID filter number - * @param referenceSignal reference signal value - * @param measuredSignal latest measured sample - * @return value of the control signal - *************************************************************************/ -F32 runPIController(PI_CONTROLLER_ID_T controllerID, F32 referenceSignal, F32 measuredSignal) -{ - PI_CONTROLLER_T *controller; - F32 result = 0.0; - - if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) - { - F32 controlSignalBeforeWindup; - F32 windupError; - - SET_CONTROLLER( controller, controllerID ); - - controller->referenceSignal = referenceSignal; - controller->measuredSignal = measuredSignal; - // calculate error signal - controller->errorSignal = fabs( referenceSignal ) - ( referenceSignal < 0.0 ? ( measuredSignal * -1.0 ) : measuredSignal ); - controller->errorSum += controller->errorSignal; - // anti-windup - controller->errorSumBeforeWindUp = controller->errorSum; - // calculate control signal - controlSignalBeforeWindup = ( controller->Kp * controller->errorSignal ) + ( controller->Ki * controller->errorSum ); - controller->controlSignal = RANGE( controlSignalBeforeWindup, controller->uMin, controller->uMax ); - // handle anti-windup for i term - windupError = controlSignalBeforeWindup - controller->controlSignal; - if ( fabs( windupError ) > NEARLY_ZERO ) - { - controller->errorSum -= ( windupError / controller->Ki ); - } - result = controller->controlSignal; - } - else - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getPIControllerSignals function returns the latest requested signal sample. + * @details Outputs: Feeds new signal to PI controller + * @param controllerID ID filter number + * @param referenceSignal reference signal value + * @param measuredSignal latest measured sample + * @return value of the control signal + *************************************************************************/ +F32 runPIController(PI_CONTROLLER_ID_T controllerID, F32 referenceSignal, F32 measuredSignal) +{ + PI_CONTROLLER_T *controller; + F32 result = 0.0; + + if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) + { + F32 controlSignalBeforeWindup; + F32 windupError; + + SET_CONTROLLER( controller, controllerID ); + + controller->referenceSignal = referenceSignal; + controller->measuredSignal = measuredSignal; + + // Calculate error signal + if ( controller->direction == CONTROLLER_UNIDIRECTIONAL ) + { + // To make sure that the outcome will be positive + controller->errorSignal = fabs( referenceSignal ) - ( referenceSignal < 0.0 ? ( measuredSignal * -1.0 ) : measuredSignal ); + } + else + { + controller->errorSignal = referenceSignal - measuredSignal; + } + + controller->errorSum += controller->errorSignal; + // anti-windup + controller->errorSumBeforeWindUp = controller->errorSum; + // calculate control signal + controlSignalBeforeWindup = ( controller->Kp * controller->errorSignal ) + ( controller->Ki * controller->errorSum ); + controller->controlSignal = RANGE( controlSignalBeforeWindup, controller->uMin, controller->uMax ); + // handle anti-windup for i term + windupError = controlSignalBeforeWindup - controller->controlSignal; + if ( fabs( windupError ) > NEARLY_ZERO ) + { + controller->errorSum -= ( windupError / controller->Ki ); + } + result = controller->controlSignal; + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getPIControllerSignals function returns the latest requested signal sample. * @details Inputs: none - * @details Outputs: none - * @param controllerID ID filter number - * @param signalID signal sample ID request - * @return latest sample requested - *************************************************************************/ -F32 getPIControllerSignals( PI_CONTROLLER_ID_T controllerID, PI_CONTROLLER_SIGNALS_ID signalID ) -{ - PI_CONTROLLER_T *controller; - F32 output = 0.0; - - if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) - { - SET_CONTROLLER( controller, controllerID ); - - switch( signalID ) - { - case CONTROLLER_SIGNAL_REFERENCE: - output = controller->referenceSignal; - break; - - case CONTROLLER_SIGNAL_MEASURED: - output = controller->measuredSignal; - break; - - case CONTROLLER_SIGNAL_ERROR: - output = controller->errorSignal; - break; - - case CONTROLLER_SIGNAL_ERROR_SUM: - output = controller->errorSumBeforeWindUp; - break; - - case CONTROLLER_SIGNAL_ERROR_SUM_AFTER_WINDUP: - output = controller->errorSum; - break; - - case CONTROLLER_SIGNAL_PROPORTIONAL_OUTPUT: - output = controller->Kp * controller->errorSignal; - break; - - case CONTROLLER_SIGNAL_INTEGRAL_OUTPUT: - output = controller->Ki * controller->errorSum; - break; - - case CONTROLLER_SIGNAL_CONTROL: - output = controller->controlSignal; - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_SIGNAL, (U32)signalID ) - break; - } // end of switch - } - else - { // invalid controller given - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) - } - - return output; -} - -/**@}*/ + * @details Outputs: none + * @param controllerID ID filter number + * @param signalID signal sample ID request + * @return latest sample requested + *************************************************************************/ +F32 getPIControllerSignals( PI_CONTROLLER_ID_T controllerID, PI_CONTROLLER_SIGNALS_ID signalID ) +{ + PI_CONTROLLER_T *controller; + F32 output = 0.0; + + if ( controllerID < NUM_OF_PI_CONTROLLERS_IDS ) + { + SET_CONTROLLER( controller, controllerID ); + + switch( signalID ) + { + case CONTROLLER_SIGNAL_REFERENCE: + output = controller->referenceSignal; + break; + + case CONTROLLER_SIGNAL_MEASURED: + output = controller->measuredSignal; + break; + + case CONTROLLER_SIGNAL_ERROR: + output = controller->errorSignal; + break; + + case CONTROLLER_SIGNAL_ERROR_SUM: + output = controller->errorSumBeforeWindUp; + break; + + case CONTROLLER_SIGNAL_ERROR_SUM_AFTER_WINDUP: + output = controller->errorSum; + break; + + case CONTROLLER_SIGNAL_PROPORTIONAL_OUTPUT: + output = controller->Kp * controller->errorSignal; + break; + + case CONTROLLER_SIGNAL_INTEGRAL_OUTPUT: + output = controller->Ki * controller->errorSum; + break; + + case CONTROLLER_SIGNAL_CONTROL: + output = controller->controlSignal; + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_SIGNAL, (U32)signalID ) + break; + } // end of switch + } + else + { // invalid controller given + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_PI_CTRL_INVALID_CONTROLLER, (U32)controllerID ) + } + + return output; +} + +/**@}*/ Index: firmware/App/Services/PIControllers.h =================================================================== diff -u -r54f45c387430e440ab4607451fc84dea61f273f1 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision 54f45c387430e440ab4607451fc84dea61f273f1) +++ firmware/App/Services/PIControllers.h (.../PIControllers.h) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,53 +14,54 @@ * @date (original) 04-Feb-2020 * ***************************************************************************/ - -#ifndef __PICONTROLLERS_H__ -#define __PICONTROLLERS_H__ - -#include "DGCommon.h" - -/** - * @defgroup PIControllers PIControllers - * @brief PIControllers service module. Provides PI controllers for various actuators. - * - * @addtogroup PIControllers - * @{ - */ - -// ********** public definitions ********** - -/// Enumeration of PI controllers. -typedef enum ControllerList -{ - PI_CONTROLLER_ID_RO_PUMP = 0, ///< RO Pump controller - PI_CONTROLLER_ID_PRIMARY_HEATER, ///< Primary Heater controller - PI_CONTROLLER_ID_TRIMMER_HEATER, ///< Trimmer Heater controller - NUM_OF_PI_CONTROLLERS_IDS ///< Number of PI controllers -} PI_CONTROLLER_ID_T; - -/// Enumeration of PI controller signals. -typedef enum ControllerSignals -{ - CONTROLLER_SIGNAL_REFERENCE = 0, ///< Reference value - CONTROLLER_SIGNAL_MEASURED, ///< Measured value - CONTROLLER_SIGNAL_ERROR, ///< Error value - CONTROLLER_SIGNAL_ERROR_SUM, ///< Error sum before anti-windup - CONTROLLER_SIGNAL_ERROR_SUM_AFTER_WINDUP, ///< Error sum after anti-windup - CONTROLLER_SIGNAL_PROPORTIONAL_OUTPUT, ///< P portion of controller output signal - CONTROLLER_SIGNAL_INTEGRAL_OUTPUT, ///< I portion of controller output signal - CONTROLLER_SIGNAL_CONTROL, ///< Controller output signal - NUM_OF_CONTROLLER_SIGNAL ///< Number of PI controller signals -} PI_CONTROLLER_SIGNALS_ID; - -// ********** public function prototypes ********** - -void initializePIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal, - F32 kP, F32 kI, F32 controlMin, F32 controlMax ); -void resetPIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal ); -F32 runPIController( PI_CONTROLLER_ID_T controllerID, F32 referenceSignal, F32 measuredSignal ); -F32 getPIControllerSignals( PI_CONTROLLER_ID_T controllerID, PI_CONTROLLER_SIGNALS_ID signalID ); - -/**@}*/ - -#endif + +#ifndef __PICONTROLLERS_H__ +#define __PICONTROLLERS_H__ + +#include "DGCommon.h" + +/** + * @defgroup PIControllers PIControllers + * @brief PIControllers service module. Provides PI controllers for various actuators. + * + * @addtogroup PIControllers + * @{ + */ + +// ********** public definitions ********** + +/// Enumeration of PI controllers. +typedef enum ControllerList +{ + PI_CONTROLLER_ID_RO_PUMP = 0, ///< RO Pump controller + PI_CONTROLLER_ID_PRIMARY_HEATER, ///< Primary Heater controller + PI_CONTROLLER_ID_TRIMMER_HEATER, ///< Trimmer Heater controller + I_CONTROLLER_ID_RO_PUMP_RAMP_UP, ///< RO Pump controller during ramp up time. + NUM_OF_PI_CONTROLLERS_IDS ///< Number of PI controllers +} PI_CONTROLLER_ID_T; + +/// Enumeration of PI controller signals. +typedef enum ControllerSignals +{ + CONTROLLER_SIGNAL_REFERENCE = 0, ///< Reference value + CONTROLLER_SIGNAL_MEASURED, ///< Measured value + CONTROLLER_SIGNAL_ERROR, ///< Error value + CONTROLLER_SIGNAL_ERROR_SUM, ///< Error sum before anti-windup + CONTROLLER_SIGNAL_ERROR_SUM_AFTER_WINDUP, ///< Error sum after anti-windup + CONTROLLER_SIGNAL_PROPORTIONAL_OUTPUT, ///< P portion of controller output signal + CONTROLLER_SIGNAL_INTEGRAL_OUTPUT, ///< I portion of controller output signal + CONTROLLER_SIGNAL_CONTROL, ///< Controller output signal + NUM_OF_CONTROLLER_SIGNAL ///< Number of PI controller signals +} PI_CONTROLLER_SIGNALS_ID; + +// ********** public function prototypes ********** + +void initializePIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal, + F32 kP, F32 kI, F32 controlMin, F32 controlMax ); +void resetPIController( PI_CONTROLLER_ID_T controllerID, F32 initialControlSignal ); +F32 runPIController( PI_CONTROLLER_ID_T controllerID, F32 referenceSignal, F32 measuredSignal ); +F32 getPIControllerSignals( PI_CONTROLLER_ID_T controllerID, PI_CONTROLLER_SIGNALS_ID signalID ); + +/**@}*/ + +#endif Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r498aa2804b2babde370f74f0cf9a333655fc0410 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 498aa2804b2babde370f74f0cf9a333655fc0410) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,102 +14,102 @@ * @date (original) 05-Nov-2019 * ***************************************************************************/ - -#include // for memcpy() - -#include "can.h" -#include "sci.h" -#include "sys_dma.h" - -#include "SystemComm.h" -#include "Comm.h" -#include "Interrupts.h" -#include "Timers.h" -#include "Utilities.h" -#include "SystemCommMessages.h" - + +#include // for memcpy() + +#include "can.h" +#include "sci.h" +#include "sys_dma.h" + +#include "SystemComm.h" +#include "Comm.h" +#include "Interrupts.h" +#include "Timers.h" +#include "Utilities.h" +#include "SystemCommMessages.h" + /** * @addtogroup SystemComm * @{ */ -// ********** private definitions ********** - -#define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit -#define NUM_OF_CAN_IN_BUFFERS 6 ///< Number of CAN buffers for receiving -#ifndef DEBUG_ENABLED - #define NUM_OF_MSG_IN_BUFFERS 6 ///< Number of Msg buffers for receiving -#else - #define NUM_OF_MSG_IN_BUFFERS 7 - #define SCI1_RECEIVE_DMA_REQUEST 30 - #define SCI1_TRANSMIT_DMA_REQUEST 31 -#endif - -#define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< if transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on +// ********** private definitions ********** + +#define NUM_OF_CAN_OUT_BUFFERS 5 ///< Number of CAN buffers for transmit +#define NUM_OF_CAN_IN_BUFFERS 6 ///< Number of CAN buffers for receiving +#ifndef DEBUG_ENABLED + #define NUM_OF_MSG_IN_BUFFERS 6 ///< Number of Msg buffers for receiving +#else + #define NUM_OF_MSG_IN_BUFFERS 7 + #define SCI1_RECEIVE_DMA_REQUEST 30 + #define SCI1_TRANSMIT_DMA_REQUEST 31 +#endif + +#define CAN_XMIT_PACKET_TIMEOUT_MS 200 ///< if transmitted CAN frame does not cause a transmit complete interrupt within this time, re-send or move on #define MAX_XMIT_RETRIES 5 ///< maximum number of retries on no transmit complete interrupt timeout - + #define HD_COMM_TIMEOUT_IN_MS 2000 ///< HD has not sent any broadcast messages for this much time - -#define MAX_COMM_CRC_FAILURES 5 ///< maximum number of CRC errors within window period before alarm -#define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window - -#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) ///< maximum time for a Denali message that requires ACK to be ACK'd -#define MSG_NOT_ACKED_MAX_RETRIES 3 ///< maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm -#define PENDING_ACK_LIST_SIZE 25 ///< maximum number of Delanli messages that can be pending ACK at any given time - -#pragma pack(push, 1) -/// Record for transmitted message that is pending acknowledgement from receiver. -typedef struct -{ - BOOL used; ///< Flag indicates whether the pending ACK slot is used or not - U16 seqNo; ///< Sequence number - U16 retries; ///< Retry count - U32 timeStamp; ///< Message time stamp - COMM_BUFFER_T channel; ///< Comm buffer channel - U32 msgSize; ///< Message size - U08 msg[ MAX_ACK_MSG_SIZE ]; ///< Bytes representation of the message -} PENDING_ACK_RECORD_T; - -#pragma pack(pop) - -// ********** private data ********** +#define MAX_COMM_CRC_FAILURES 5 ///< maximum number of CRC errors within window period before alarm +#define MAX_COMM_CRC_FAILURE_WINDOW_MS (10 * SEC_PER_MIN * MS_PER_SECOND) ///< CRC error window -/// Array of out-going CAN buffers. -const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = -{ - COMM_BUFFER_OUT_CAN_DG_ALARM, - COMM_BUFFER_OUT_CAN_DG_2_HD, +#define MSG_NOT_ACKED_TIMEOUT_MS ( MS_PER_SECOND * 1 ) ///< maximum time for a Denali message that requires ACK to be ACK'd +#define MSG_NOT_ACKED_MAX_RETRIES 3 ///< maximum number of times a message that requires ACK that was not ACK'd can be re-sent before alarm +#define PENDING_ACK_LIST_SIZE 25 ///< maximum number of Delanli messages that can be pending ACK at any given time + +#pragma pack(push, 1) + +/// Record for transmitted message that is pending acknowledgement from receiver. +typedef struct +{ + BOOL used; ///< Flag indicates whether the pending ACK slot is used or not + U16 seqNo; ///< Sequence number + U16 retries; ///< Retry count + U32 timeStamp; ///< Message time stamp + COMM_BUFFER_T channel; ///< Comm buffer channel + U32 msgSize; ///< Message size + U08 msg[ MAX_ACK_MSG_SIZE ]; ///< Bytes representation of the message +} PENDING_ACK_RECORD_T; + +#pragma pack(pop) + +// ********** private data ********** + +/// Array of out-going CAN buffers. +const COMM_BUFFER_T CAN_OUT_BUFFERS[ NUM_OF_CAN_OUT_BUFFERS ] = +{ + COMM_BUFFER_OUT_CAN_DG_ALARM, + COMM_BUFFER_OUT_CAN_DG_2_HD, COMM_BUFFER_OUT_CAN_DG_BROADCAST, - COMM_BUFFER_OUT_CAN_PC, + COMM_BUFFER_OUT_CAN_PC, COMM_BUFFER_OUT_CAN_DG_2_UI -}; +}; -/// Array of in-coming CAN buffers. -const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = -{ - COMM_BUFFER_IN_CAN_HD_ALARM, - COMM_BUFFER_IN_CAN_UI_ALARM, - COMM_BUFFER_IN_CAN_HD_2_DG, - COMM_BUFFER_IN_CAN_HD_BROADCAST, - COMM_BUFFER_IN_CAN_UI_BROADCAST, - COMM_BUFFER_IN_CAN_PC, -#ifdef DEBUG_ENABLED - COMM_BUFFER_IN_UART_PC -#endif -}; +/// Array of in-coming CAN buffers. +const COMM_BUFFER_T MSG_IN_BUFFERS[ NUM_OF_MSG_IN_BUFFERS ] = +{ + COMM_BUFFER_IN_CAN_HD_ALARM, + COMM_BUFFER_IN_CAN_UI_ALARM, + COMM_BUFFER_IN_CAN_HD_2_DG, + COMM_BUFFER_IN_CAN_HD_BROADCAST, + COMM_BUFFER_IN_CAN_UI_BROADCAST, + COMM_BUFFER_IN_CAN_PC, +#ifdef DEBUG_ENABLED + COMM_BUFFER_IN_UART_PC +#endif +}; -static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. -static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; ///< Keep channel last packet was sent on CAN bus in case we need to re-send. -static U32 lastCANPacketSentTimeStamp = 0; ///< Keep time last packet sent on CAN bus so we can timeout on transmission attempt. - -static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< list of outgoing messages that are awaiting an ACK - +static U08 lastCANPacketSent[ CAN_MESSAGE_PAYLOAD_SIZE ]; ///< Keep last packet sent on CAN bus in case we need to re-send. +static CAN_MESSAGE_BOX_T lastCANPacketSentChannel = (CAN_MESSAGE_BOX_T)0; ///< Keep channel last packet was sent on CAN bus in case we need to re-send. +static U32 lastCANPacketSentTimeStamp = 0; ///< Keep time last packet sent on CAN bus so we can timeout on transmission attempt. + +static PENDING_ACK_RECORD_T pendingAckList[ PENDING_ACK_LIST_SIZE ]; ///< list of outgoing messages that are awaiting an ACK + static volatile BOOL dgIsOnlyCANNode = TRUE; ///< flag indicating whether DG is alone on CAN bus. -static U32 canXmitRetryCtr = 0; ///< counter for CAN transmit retries. -static volatile BOOL hdIsCommunicating = FALSE; ///< has HD sent a message since last check -static volatile U32 timeOfLastHDCheckIn = 0; ///< last time we received an HD broadcast - +static U32 canXmitRetryCtr = 0; ///< counter for CAN transmit retries. +static volatile BOOL hdIsCommunicating = FALSE; ///< has HD sent a message since last check +static volatile U32 timeOfLastHDCheckIn = 0; ///< last time we received an HD broadcast + #ifdef DEBUG_ENABLED // debug buffers static U08 pcXmitPacket[ 1024 ]; @@ -119,71 +119,71 @@ static g_dmaCTRL pcDMARecvControlRecord; #endif -// ********** private function prototypes ********** - -static void clearCANXmitBuffers( void ); - -static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); -static U32 transmitNextCANPacket( void ); - -static void processIncomingData( void ); -static S32 parseMessageFromBuffer( U08 *data, U32 len ); -static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ); -static void processReceivedMessages( void ); -static void processReceivedMessage( MESSAGE_T *message ); - -static void checkForCommTimeouts( void ); -static void checkTooManyBadMsgCRCs( void ); - -static BOOL matchACKtoPendingACKList( S16 seqNo ); -static void checkPendingACKList( void ); - +// ********** private function prototypes ********** + +static void clearCANXmitBuffers( void ); + +static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ); +static U32 transmitNextCANPacket( void ); + +static void processIncomingData( void ); +static S32 parseMessageFromBuffer( U08 *data, U32 len ); +static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ); +static void processReceivedMessages( void ); +static void processReceivedMessage( MESSAGE_T *message ); + +static void checkForCommTimeouts( void ); +static void checkTooManyBadMsgCRCs( void ); + +static BOOL matchACKtoPendingACKList( S16 seqNo ); +static void checkPendingACKList( void ); + #ifdef DEBUG_ENABLED static void initUARTAndDMA( void ); static U32 transmitNextUARTPacket( void ); #endif -/*********************************************************************//** - * @brief - * The initSystemComm function initializes the SystemComm module. - * @details Inputs: none - * @details Outputs: SystemComm module initialized. - * @return none - *************************************************************************/ -void initSystemComm( void ) -{ - U32 i; - -#ifdef DEBUG_ENABLED - // initialize UART and DMA for PC communication - initUARTAndDMA(); -#endif - +/*********************************************************************//** + * @brief + * The initSystemComm function initializes the SystemComm module. + * @details Inputs: none + * @details Outputs: SystemComm module initialized. + * @return none + *************************************************************************/ +void initSystemComm( void ) +{ + U32 i; + +#ifdef DEBUG_ENABLED + // initialize UART and DMA for PC communication + initUARTAndDMA(); +#endif + // initialize bad message CRC time windowed count initTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC, MAX_COMM_CRC_FAILURES, MAX_COMM_CRC_FAILURE_WINDOW_MS ); - // initialize pending ACK list - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - pendingAckList[ i ].used = FALSE; - } -} - -/*********************************************************************//** - * @brief - * The isHDCommunicating function determines whether the HD is communicating - * with the DG. - * @details Inputs: hdIsCommunicating - * @details Outputs: none - * @return TRUE if HD has broadcast since last call, FALSE if not - *************************************************************************/ -BOOL isHDCommunicating( void ) -{ - return hdIsCommunicating; + // initialize pending ACK list + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + pendingAckList[ i ].used = FALSE; + } } /*********************************************************************//** * @brief + * The isHDCommunicating function determines whether the HD is communicating + * with the DG. + * @details Inputs: hdIsCommunicating + * @details Outputs: none + * @return TRUE if HD has broadcast since last call, FALSE if not + *************************************************************************/ +BOOL isHDCommunicating( void ) +{ + return hdIsCommunicating; +} + +/*********************************************************************//** + * @brief * The isDGOnlyCANNode function determines whether the DG is the only node * currently on the CAN bus. * @details Inputs: dgIsOnlyCANNode @@ -193,39 +193,39 @@ BOOL isDGOnlyCANNode( void ) { return dgIsOnlyCANNode; -} - -/*********************************************************************//** - * @brief - * The execSystemCommRx function manages received data from other sub-systems. - * @details Inputs: none - * @details Outputs: Incoming frames processed. - * @return none - *************************************************************************/ -void execSystemCommRx( void ) -{ - // parse messages from comm buffers and queue them - processIncomingData(); - - // process received messages in the queue - processReceivedMessages(); - - // check for sub-system comm timeouts - checkForCommTimeouts(); - - // check ACK list for messages that need to be re-sent because they haven't been ACK'd - checkPendingACKList(); -} - -/*********************************************************************//** - * @brief - * The execSystemCommTx function manages data to be transmitted to other sub-systems. - * @details Inputs: none - * @details Outputs: Next outgoing frame transmitted. - * @return none - *************************************************************************/ -void execSystemCommTx( void ) +} + +/*********************************************************************//** + * @brief + * The execSystemCommRx function manages received data from other sub-systems. + * @details Inputs: none + * @details Outputs: Incoming frames processed. + * @return none + *************************************************************************/ +void execSystemCommRx( void ) { + // parse messages from comm buffers and queue them + processIncomingData(); + + // process received messages in the queue + processReceivedMessages(); + + // check for sub-system comm timeouts + checkForCommTimeouts(); + + // check ACK list for messages that need to be re-sent because they haven't been ACK'd + checkPendingACKList(); +} + +/*********************************************************************//** + * @brief + * The execSystemCommTx function manages data to be transmitted to other sub-systems. + * @details Inputs: none + * @details Outputs: Next outgoing frame transmitted. + * @return none + *************************************************************************/ +void execSystemCommTx( void ) +{ // don't bother with transmitting if no other nodes on CAN bus if ( FALSE == dgIsOnlyCANNode ) { @@ -271,217 +271,217 @@ } // end - are we retrying xmit or are we alone on CAN bus } // end - pending xmit timeout? } // end - transmit in progress or not - } // end - DG not alone on CAN bus - -#ifdef DEBUG_ENABLED - // if UART transmitter is idle, start transmitting any pending packets - if ( FALSE == isSCI1DMATransmitInProgress() ) - { - transmitNextUARTPacket(); - } -#endif -} - -/*********************************************************************//** - * @brief + } // end - DG not alone on CAN bus + +#ifdef DEBUG_ENABLED + // if UART transmitter is idle, start transmitting any pending packets + if ( FALSE == isSCI1DMATransmitInProgress() ) + { + transmitNextUARTPacket(); + } +#endif +} + +/*********************************************************************//** + * @brief * The handleCANMsgInterrupt function handles a CAN message interrupt. This * may have occurred because a CAN packet transmission has completed or - * because a CAN packet has been received. The appropriate handler is called. - * @details Inputs: none - * @details Outputs: message interrupt handled - * @param srcCANBox which CAN message box triggered this interrupt - * @return none - *************************************************************************/ -void handleCANMsgInterrupt( CAN_MESSAGE_BOX_T srcCANBox ) -{ - // message interrupt is for a transmit message box? - if ( TRUE == isCANBoxForXmit( srcCANBox ) ) - { - U32 bytesXmitted = transmitNextCANPacket(); - - if ( 0 == bytesXmitted ) - { - signalCANXmitsCompleted(); - } - } - else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) - { - U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; - - // get CAN packet received on given CAN message box - if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) - { - U32 result = canGetData( canREG1, srcCANBox, data ); - - // if packet retrieved, add to buffer - if ( result != 0 ) - { - // add CAN packet to appropriate comm buffer based on the message box it came in on (s/b same #) - addToCommBuffer( srcCANBox, data, CAN_MESSAGE_PAYLOAD_SIZE ); - } - } - } - else - { - // shouldn't get here - not an active message box - // s/w fault? - } -} - -#ifdef DEBUG_ENABLED -/*********************************************************************//** - * @brief - * The handleUARTMsgRecvPacketInterrupt function handles a DMA UART receive - * packet completed interrupt. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -void handleUARTMsgRecvPacketInterrupt( void ) -{ - // buffer received packet - addToCommBuffer( COMM_BUFFER_IN_UART_PC, pcRecvPacket, PC_MESSAGE_PACKET_SIZE ); - // prepare to receive next packet - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} - -/*********************************************************************//** - * @brief - * The handleUARTMsgXmitPacketInterrupt function handles a DMA UART transmit - * packet completed interrupt. - * @details Inputs: none - * @details Outputs: none - * @return none - *************************************************************************/ -void handleUARTMsgXmitPacketInterrupt( void ) -{ - U32 bytesXmitted = transmitNextUARTPacket(); - - if ( 0 == bytesXmitted ) - { - signalSCI1XmitsCompleted(); - } -} - -/*********************************************************************//** - * @brief - * The initUARTAndDMA function initializes the SCI1 peripheral and the DMA - * to go with it for PC communication. - * @details Inputs: none - * @details Outputs: SCI1 and DMA initialized - * @return none - *************************************************************************/ -static void initUARTAndDMA( void ) -{ - // Enable DMA block transfer complete interrupts - dmaEnableInterrupt( DMA_CH1, BTC ); - dmaEnableInterrupt( DMA_CH3, BTC ); - // assign DMA channels to h/w DMA requests - dmaReqAssign( DMA_CH1, SCI1_RECEIVE_DMA_REQUEST ); - dmaReqAssign( DMA_CH3, SCI1_TRANSMIT_DMA_REQUEST ); - // set DMA channel priorities - dmaSetPriority( DMA_CH1, HIGHPRIORITY ); - dmaSetPriority( DMA_CH3, LOWPRIORITY ); - - // initialize PC DMA Transmit Control Record - pcDMAXmitControlRecord.PORTASGN = 4; // port B (only choice per datasheet) - pcDMAXmitControlRecord.DADD = (U32)(&(sciREG->TD)); // dest. is SCI2 xmit register - pcDMAXmitControlRecord.SADD = (U32)pcXmitPacket; // source - pcDMAXmitControlRecord.CHCTRL = 0; // no chaining - pcDMAXmitControlRecord.ELCNT = 1; // frame is 1 element - pcDMAXmitControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames - pcDMAXmitControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte - pcDMAXmitControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMAXmitControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer - pcDMAXmitControlRecord.ADDMODEWR = ADDR_FIXED; // dest. addressing mode is fixed - pcDMAXmitControlRecord.ADDMODERD = ADDR_INC1; // source addressing mode is post-increment - pcDMAXmitControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off - pcDMAXmitControlRecord.ELSOFFSET = 0; // not used - pcDMAXmitControlRecord.ELDOFFSET = 0; // not used - pcDMAXmitControlRecord.FRSOFFSET = 0; // not used - pcDMAXmitControlRecord.FRDOFFSET = 0; // not used - - // initialize PC DMA Receipt Control Record - pcDMARecvControlRecord.PORTASGN = 4; // port B (only choice per datasheet) - pcDMARecvControlRecord.SADD = (U32)(&(sciREG->RD)); // source is SCI2 recv register - pcDMARecvControlRecord.DADD = (U32)pcRecvPacket; // transfer destination address - pcDMARecvControlRecord.CHCTRL = 0; // no chaining - pcDMARecvControlRecord.ELCNT = 1; // frame is 1 element - pcDMARecvControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames - pcDMARecvControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte - pcDMARecvControlRecord.WRSIZE = ACCESS_8_BIT; // - pcDMARecvControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer - pcDMARecvControlRecord.ADDMODERD = ADDR_FIXED; // source addressing mode is fixed - pcDMARecvControlRecord.ADDMODEWR = ADDR_INC1; // dest. addressing mode is post-increment - pcDMARecvControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off - pcDMARecvControlRecord.ELDOFFSET = 0; // not used - pcDMARecvControlRecord.ELSOFFSET = 0; // not used - pcDMARecvControlRecord.FRDOFFSET = 0; // not used - pcDMARecvControlRecord.FRSOFFSET = 0; // not used - - // initiate PC packet receiving readiness via DMA - dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); - dmaSetChEnable( DMA_CH1, DMA_HW ); - setSCI1DMAReceiveInterrupt(); -} -#endif - -/*********************************************************************//** - * @brief - * The isCANBoxForXmit function determines whether a given CAN message box - * is configured for transmit. - * @details Inputs: CAN_OUT_BUFFERS[] - * @details Outputs: none - * @param srcCANBox which CAN message box to check - * @return TRUE if the given CAN message box is configured for transmit, FALSE if not. - *************************************************************************/ -BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ) -{ - BOOL result = FALSE; - U32 i; - - for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) - { - if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) - { - result = TRUE; - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The isCANBoxForRecv function determines whether a given CAN message box - * is configured for receiving. - * @details Inputs: MSG_IN_BUFFERS[] - * @details Outputs: none - * @param srcCANBox which CAN message box to check - * @return TRUE if the given CAN message box is configured for receiving, FALSE if not. - *************************************************************************/ -BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ) -{ - BOOL result = FALSE; - U32 i; - - for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) - { - if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) - { - result = TRUE; - break; - } - } - - return result; + * because a CAN packet has been received. The appropriate handler is called. + * @details Inputs: none + * @details Outputs: message interrupt handled + * @param srcCANBox which CAN message box triggered this interrupt + * @return none + *************************************************************************/ +void handleCANMsgInterrupt( CAN_MESSAGE_BOX_T srcCANBox ) +{ + // message interrupt is for a transmit message box? + if ( TRUE == isCANBoxForXmit( srcCANBox ) ) + { + U32 bytesXmitted = transmitNextCANPacket(); + + if ( 0 == bytesXmitted ) + { + signalCANXmitsCompleted(); + } + } + else if ( TRUE == isCANBoxForRecv( srcCANBox ) ) + { + U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; + + // get CAN packet received on given CAN message box + if ( FALSE != canIsRxMessageArrived( canREG1, srcCANBox ) ) + { + U32 result = canGetData( canREG1, srcCANBox, data ); + + // if packet retrieved, add to buffer + if ( result != 0 ) + { + // add CAN packet to appropriate comm buffer based on the message box it came in on (s/b same #) + addToCommBuffer( srcCANBox, data, CAN_MESSAGE_PAYLOAD_SIZE ); + } + } + } + else + { + // shouldn't get here - not an active message box + // s/w fault? + } } +#ifdef DEBUG_ENABLED /*********************************************************************//** * @brief + * The handleUARTMsgRecvPacketInterrupt function handles a DMA UART receive + * packet completed interrupt. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +void handleUARTMsgRecvPacketInterrupt( void ) +{ + // buffer received packet + addToCommBuffer( COMM_BUFFER_IN_UART_PC, pcRecvPacket, PC_MESSAGE_PACKET_SIZE ); + // prepare to receive next packet + dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); + dmaSetChEnable( DMA_CH1, DMA_HW ); + setSCI1DMAReceiveInterrupt(); +} + +/*********************************************************************//** + * @brief + * The handleUARTMsgXmitPacketInterrupt function handles a DMA UART transmit + * packet completed interrupt. + * @details Inputs: none + * @details Outputs: none + * @return none + *************************************************************************/ +void handleUARTMsgXmitPacketInterrupt( void ) +{ + U32 bytesXmitted = transmitNextUARTPacket(); + + if ( 0 == bytesXmitted ) + { + signalSCI1XmitsCompleted(); + } +} + +/*********************************************************************//** + * @brief + * The initUARTAndDMA function initializes the SCI1 peripheral and the DMA + * to go with it for PC communication. + * @details Inputs: none + * @details Outputs: SCI1 and DMA initialized + * @return none + *************************************************************************/ +static void initUARTAndDMA( void ) +{ + // Enable DMA block transfer complete interrupts + dmaEnableInterrupt( DMA_CH1, BTC ); + dmaEnableInterrupt( DMA_CH3, BTC ); + // assign DMA channels to h/w DMA requests + dmaReqAssign( DMA_CH1, SCI1_RECEIVE_DMA_REQUEST ); + dmaReqAssign( DMA_CH3, SCI1_TRANSMIT_DMA_REQUEST ); + // set DMA channel priorities + dmaSetPriority( DMA_CH1, HIGHPRIORITY ); + dmaSetPriority( DMA_CH3, LOWPRIORITY ); + + // initialize PC DMA Transmit Control Record + pcDMAXmitControlRecord.PORTASGN = 4; // port B (only choice per datasheet) + pcDMAXmitControlRecord.DADD = (U32)(&(sciREG->TD)); // dest. is SCI2 xmit register + pcDMAXmitControlRecord.SADD = (U32)pcXmitPacket; // source + pcDMAXmitControlRecord.CHCTRL = 0; // no chaining + pcDMAXmitControlRecord.ELCNT = 1; // frame is 1 element + pcDMAXmitControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames + pcDMAXmitControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte + pcDMAXmitControlRecord.WRSIZE = ACCESS_8_BIT; // + pcDMAXmitControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer + pcDMAXmitControlRecord.ADDMODEWR = ADDR_FIXED; // dest. addressing mode is fixed + pcDMAXmitControlRecord.ADDMODERD = ADDR_INC1; // source addressing mode is post-increment + pcDMAXmitControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off + pcDMAXmitControlRecord.ELSOFFSET = 0; // not used + pcDMAXmitControlRecord.ELDOFFSET = 0; // not used + pcDMAXmitControlRecord.FRSOFFSET = 0; // not used + pcDMAXmitControlRecord.FRDOFFSET = 0; // not used + + // initialize PC DMA Receipt Control Record + pcDMARecvControlRecord.PORTASGN = 4; // port B (only choice per datasheet) + pcDMARecvControlRecord.SADD = (U32)(&(sciREG->RD)); // source is SCI2 recv register + pcDMARecvControlRecord.DADD = (U32)pcRecvPacket; // transfer destination address + pcDMARecvControlRecord.CHCTRL = 0; // no chaining + pcDMARecvControlRecord.ELCNT = 1; // frame is 1 element + pcDMARecvControlRecord.FRCNT = PC_MESSAGE_PACKET_SIZE; // block is 8 frames + pcDMARecvControlRecord.RDSIZE = ACCESS_8_BIT; // element size is 1 byte + pcDMARecvControlRecord.WRSIZE = ACCESS_8_BIT; // + pcDMARecvControlRecord.TTYPE = FRAME_TRANSFER; // transfer type is block transfer + pcDMARecvControlRecord.ADDMODERD = ADDR_FIXED; // source addressing mode is fixed + pcDMARecvControlRecord.ADDMODEWR = ADDR_INC1; // dest. addressing mode is post-increment + pcDMARecvControlRecord.AUTOINIT = AUTOINIT_OFF; // auto-init off + pcDMARecvControlRecord.ELDOFFSET = 0; // not used + pcDMARecvControlRecord.ELSOFFSET = 0; // not used + pcDMARecvControlRecord.FRDOFFSET = 0; // not used + pcDMARecvControlRecord.FRSOFFSET = 0; // not used + + // initiate PC packet receiving readiness via DMA + dmaSetCtrlPacket( DMA_CH1, pcDMARecvControlRecord ); + dmaSetChEnable( DMA_CH1, DMA_HW ); + setSCI1DMAReceiveInterrupt(); +} +#endif + +/*********************************************************************//** + * @brief + * The isCANBoxForXmit function determines whether a given CAN message box + * is configured for transmit. + * @details Inputs: CAN_OUT_BUFFERS[] + * @details Outputs: none + * @param srcCANBox which CAN message box to check + * @return TRUE if the given CAN message box is configured for transmit, FALSE if not. + *************************************************************************/ +BOOL isCANBoxForXmit( CAN_MESSAGE_BOX_T srcCANBox ) +{ + BOOL result = FALSE; + U32 i; + + for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) + { + if ( CAN_OUT_BUFFERS[ i ] == srcCANBox ) + { + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The isCANBoxForRecv function determines whether a given CAN message box + * is configured for receiving. + * @details Inputs: MSG_IN_BUFFERS[] + * @details Outputs: none + * @param srcCANBox which CAN message box to check + * @return TRUE if the given CAN message box is configured for receiving, FALSE if not. + *************************************************************************/ +BOOL isCANBoxForRecv( CAN_MESSAGE_BOX_T srcCANBox ) +{ + BOOL result = FALSE; + U32 i; + + for ( i = 0; i < NUM_OF_CAN_IN_BUFFERS; i++ ) + { + if ( MSG_IN_BUFFERS[ i ] == srcCANBox ) + { + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The clearCANXmitBuffers function clears all CAN transmit buffers. * @details Inputs: CAN_OUT_BUFFERS[] * @details Outputs: CAN transmit buffers cleared. @@ -495,369 +495,369 @@ { clearBuffer( CAN_OUT_BUFFERS[ i ] ); } -} - - -/************************************************************************* -********************** TRANSMIT SUPPORT FUNCTIONS ************************ -*************************************************************************/ - -/*********************************************************************//** - * @brief - * The findNextHighestPriorityCANPacketToTransmit function gets the next - * 8 byte packet and initiates a CAN transmit on the appropriate CAN channel. - * @details Inputs: Output CAN Comm Buffer(s) - * @details Outputs: none - * @return buffer with highest priority CAN packet to transmit, - * COMM_BUFFER_NOT_USED if not CAN packets pending transmit found - *************************************************************************/ -static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ) -{ - COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; - U32 i; - - // search for next priority CAN packet to transmit - for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) - { - if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) - { - result = CAN_OUT_BUFFERS[ i ]; - break; // found highest priority packet to transmit - we're done - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The transmitNextCANPacket function gets the next 8 byte packet and initiates - * a CAN transmit on the appropriate CAN channel. - * @details Inputs: Output CAN Comm Buffers - * @details Outputs: CAN packet transmit initiated. - * @return number of bytes transmitted - *************************************************************************/ -static U32 transmitNextCANPacket( void ) -{ - U32 result = 0; - COMM_BUFFER_T buffer = findNextHighestPriorityCANPacketToTransmit(); - - // if a buffer is found with a packet to transmit, get packet from buffer and transmit it - if ( buffer != COMM_BUFFER_NOT_USED ) - { - U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; - U32 dataSize = getFromCommBuffer( buffer, data, CAN_MESSAGE_PAYLOAD_SIZE ); - CAN_MESSAGE_BOX_T mBox = buffer; // CAN message boxes and comm buffers are aligned - - // if there's another CAN packet to send, send it - if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) - { - // we're transmitting another packet - signal transmitter is busy - signalCANXmitsInitiated(); - // remember packet data being transmitted here in case transmission fails and we need to re-send - memcpy( lastCANPacketSent, data, CAN_MESSAGE_PAYLOAD_SIZE ); - lastCANPacketSentChannel = mBox; - lastCANPacketSentTimeStamp = getMSTimerCount(); - if ( 0 != canTransmit( canREG1, mBox, data ) ) - { - result = CAN_MESSAGE_PAYLOAD_SIZE; - } - else - { - signalCANXmitsCompleted(); - // TODO - shouldn't get here, but let's see if we do - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)mBox ) - } - } - else - { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) - } - } - - return result; -} - -#ifdef DEBUG_ENABLED -/*********************************************************************//** - * @brief - * The transmitNextUARTPacket function sets up and initiates a DMA transmit - * of the next packet pending transmit (if any) via UART. - * @details Inputs: Output UART Comm Buffer(s) - * @details Outputs: UART DMA transmit initiated. - * @return number of bytes transmitted - *************************************************************************/ -static U32 transmitNextUARTPacket( void ) -{ - U32 result = 0; - U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); - - if ( dataPend > 0 ) - { - result = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, dataPend ); - - // if there's data to transmit, transmit it - if ( result > 0 ) - { - signalSCI1XmitsInitiated(); - pcDMAXmitControlRecord.FRCNT = result; // set DMA transfer size - dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); - dmaSetChEnable( DMA_CH3, DMA_HW ); - setSCI1DMATransmitInterrupt(); - } - } - - return result; -} -#endif - - -/************************************************************************* -********************** RECEIVE SUPPORT FUNCTIONS ************************* -*************************************************************************/ - -/*********************************************************************//** - * @brief - * The processIncomingData function parses out messages from the input - * comm buffers and adds them to the received message queue. - * @details Inputs: Input Comm Buffers - * @details Outputs: Parsed message(s) added to received message queue - * @return none - *************************************************************************/ -static void processIncomingData( void ) -{ - U08 data[ 512 ]; // message work space - U32 i; - BOOL badCRCDetected = FALSE; - - // queue any received messages - for ( i = 0; i < NUM_OF_MSG_IN_BUFFERS; i++ ) - { - BOOL messagesInBuffer = TRUE; // assume true at first to get into while loop - - while ( TRUE == messagesInBuffer ) - { - U32 numOfBytesInBuffer; - - // assume false so we don't get stuck in loop - only set to true if we find another complete message in buffer - messagesInBuffer = FALSE; - - // since messages can have 8-byte alignment padding left unconsumed by last get, get padding out of buffer - consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); - // do we have enough bytes in buffer for smallest message? - numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[ i ] ); - if ( numOfBytesInBuffer >= MESSAGE_OVERHEAD_SIZE ) - { // peek at minimum of all bytes available or max message size (+1 for sync byte) - U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); - S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); - +} + + +/************************************************************************* +********************** TRANSMIT SUPPORT FUNCTIONS ************************ +*************************************************************************/ + +/*********************************************************************//** + * @brief + * The findNextHighestPriorityCANPacketToTransmit function gets the next + * 8 byte packet and initiates a CAN transmit on the appropriate CAN channel. + * @details Inputs: Output CAN Comm Buffer(s) + * @details Outputs: none + * @return buffer with highest priority CAN packet to transmit, + * COMM_BUFFER_NOT_USED if not CAN packets pending transmit found + *************************************************************************/ +static COMM_BUFFER_T findNextHighestPriorityCANPacketToTransmit( void ) +{ + COMM_BUFFER_T result = COMM_BUFFER_NOT_USED; + U32 i; + + // search for next priority CAN packet to transmit + for ( i = 0; i < NUM_OF_CAN_OUT_BUFFERS; i++ ) + { + if ( numberOfBytesInCommBuffer( CAN_OUT_BUFFERS[ i ] ) >= CAN_MESSAGE_PAYLOAD_SIZE ) + { + result = CAN_OUT_BUFFERS[ i ]; + break; // found highest priority packet to transmit - we're done + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The transmitNextCANPacket function gets the next 8 byte packet and initiates + * a CAN transmit on the appropriate CAN channel. + * @details Inputs: Output CAN Comm Buffers + * @details Outputs: CAN packet transmit initiated. + * @return number of bytes transmitted + *************************************************************************/ +static U32 transmitNextCANPacket( void ) +{ + U32 result = 0; + COMM_BUFFER_T buffer = findNextHighestPriorityCANPacketToTransmit(); + + // if a buffer is found with a packet to transmit, get packet from buffer and transmit it + if ( buffer != COMM_BUFFER_NOT_USED ) + { + U08 data[ CAN_MESSAGE_PAYLOAD_SIZE ]; + U32 dataSize = getFromCommBuffer( buffer, data, CAN_MESSAGE_PAYLOAD_SIZE ); + CAN_MESSAGE_BOX_T mBox = buffer; // CAN message boxes and comm buffers are aligned + + // if there's another CAN packet to send, send it + if ( dataSize == CAN_MESSAGE_PAYLOAD_SIZE ) + { + // we're transmitting another packet - signal transmitter is busy + signalCANXmitsInitiated(); + // remember packet data being transmitted here in case transmission fails and we need to re-send + memcpy( lastCANPacketSent, data, CAN_MESSAGE_PAYLOAD_SIZE ); + lastCANPacketSentChannel = mBox; + lastCANPacketSentTimeStamp = getMSTimerCount(); + if ( 0 != canTransmit( canREG1, mBox, data ) ) + { + result = CAN_MESSAGE_PAYLOAD_SIZE; + } + else + { + signalCANXmitsCompleted(); + // TODO - shouldn't get here, but let's see if we do + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)mBox ) + } + } + else + { // TODO - shouldn't get here - just testing - set first data to new s/w fault enum later + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, (U32)buffer, (U32)dataSize ) + } + } + + return result; +} + +#ifdef DEBUG_ENABLED +/*********************************************************************//** + * @brief + * The transmitNextUARTPacket function sets up and initiates a DMA transmit + * of the next packet pending transmit (if any) via UART. + * @details Inputs: Output UART Comm Buffer(s) + * @details Outputs: UART DMA transmit initiated. + * @return number of bytes transmitted + *************************************************************************/ +static U32 transmitNextUARTPacket( void ) +{ + U32 result = 0; + U32 dataPend = numberOfBytesInCommBuffer( COMM_BUFFER_OUT_UART_PC ); + + if ( dataPend > 0 ) + { + result = getFromCommBuffer( COMM_BUFFER_OUT_UART_PC, pcXmitPacket, dataPend ); + + // if there's data to transmit, transmit it + if ( result > 0 ) + { + signalSCI1XmitsInitiated(); + pcDMAXmitControlRecord.FRCNT = result; // set DMA transfer size + dmaSetCtrlPacket( DMA_CH3, pcDMAXmitControlRecord ); + dmaSetChEnable( DMA_CH3, DMA_HW ); + setSCI1DMATransmitInterrupt(); + } + } + + return result; +} +#endif + + +/************************************************************************* +********************** RECEIVE SUPPORT FUNCTIONS ************************* +*************************************************************************/ + +/*********************************************************************//** + * @brief + * The processIncomingData function parses out messages from the input + * comm buffers and adds them to the received message queue. + * @details Inputs: Input Comm Buffers + * @details Outputs: Parsed message(s) added to received message queue + * @return none + *************************************************************************/ +static void processIncomingData( void ) +{ + U08 data[ 512 ]; // message work space + U32 i; + BOOL badCRCDetected = FALSE; + + // queue any received messages + for ( i = 0; i < NUM_OF_MSG_IN_BUFFERS; i++ ) + { + BOOL messagesInBuffer = TRUE; // assume true at first to get into while loop + + while ( TRUE == messagesInBuffer ) + { + U32 numOfBytesInBuffer; + + // assume false so we don't get stuck in loop - only set to true if we find another complete message in buffer + messagesInBuffer = FALSE; + + // since messages can have 8-byte alignment padding left unconsumed by last get, get padding out of buffer + consumeBufferPaddingBeforeSync( MSG_IN_BUFFERS[ i ] ); + // do we have enough bytes in buffer for smallest message? + numOfBytesInBuffer = numberOfBytesInCommBuffer( MSG_IN_BUFFERS[ i ] ); + if ( numOfBytesInBuffer >= MESSAGE_OVERHEAD_SIZE ) + { // peek at minimum of all bytes available or max message size (+1 for sync byte) + U32 bytesPeeked = peekFromCommBuffer( MSG_IN_BUFFERS[ i ], data, MIN( numOfBytesInBuffer, sizeof( MESSAGE_WRAPPER_T ) + 1 ) ); + S32 msgSize = parseMessageFromBuffer( data, bytesPeeked ); + dgIsOnlyCANNode = FALSE; // if we're getting a message, we can't be alone canXmitRetryCtr = 0; - if ( msgSize > 0 ) // valid, complete message found? - { - MESSAGE_WRAPPER_T rcvMsg; - U08 *dataPtr = data+1; // skip over sync byte - - // consume message (+sync byte) - msgSize = getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, msgSize + 1 ); - // convert received message data to a message and add to message queue - messagesInBuffer = TRUE; // keep processing this buffer - // blank the new message record - blankMessageInWrapper( &rcvMsg ); - // copy message header portion of message data to the new message - memcpy( &(rcvMsg.msg.hdr), dataPtr, sizeof(MESSAGE_HEADER_T) ); - dataPtr += sizeof(MESSAGE_HEADER_T); - // copy message payload portion of message data to the new message - memcpy( &(rcvMsg.msg.payload), dataPtr, rcvMsg.msg.hdr.payloadLen ); - dataPtr += rcvMsg.msg.hdr.payloadLen; - // copy CRC portion of message data to the new message - rcvMsg.crc = *dataPtr; - // add new message to queue for later processing - addToMsgQueue( MSG_Q_IN, &rcvMsg ); - // if message from HD broadcast channel, update HD comm status - if ( COMM_BUFFER_IN_CAN_HD_BROADCAST == MSG_IN_BUFFERS[ i ] ) - { + if ( msgSize > 0 ) // valid, complete message found? + { + MESSAGE_WRAPPER_T rcvMsg; + U08 *dataPtr = data+1; // skip over sync byte + + // consume message (+sync byte) + msgSize = getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, msgSize + 1 ); + // convert received message data to a message and add to message queue + messagesInBuffer = TRUE; // keep processing this buffer + // blank the new message record + blankMessageInWrapper( &rcvMsg ); + // copy message header portion of message data to the new message + memcpy( &(rcvMsg.msg.hdr), dataPtr, sizeof(MESSAGE_HEADER_T) ); + dataPtr += sizeof(MESSAGE_HEADER_T); + // copy message payload portion of message data to the new message + memcpy( &(rcvMsg.msg.payload), dataPtr, rcvMsg.msg.hdr.payloadLen ); + dataPtr += rcvMsg.msg.hdr.payloadLen; + // copy CRC portion of message data to the new message + rcvMsg.crc = *dataPtr; + // add new message to queue for later processing + addToMsgQueue( MSG_Q_IN, &rcvMsg ); + // if message from HD broadcast channel, update HD comm status + if ( COMM_BUFFER_IN_CAN_HD_BROADCAST == MSG_IN_BUFFERS[ i ] ) + { hdIsCommunicating = TRUE; - timeOfLastHDCheckIn = getMSTimerCount(); - } - } - else if ( -1 == msgSize ) // candidate message with bad CRC found? - { - badCRCDetected = TRUE; - getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, 1 ); // consume sync byte so we can re-sync - messagesInBuffer = TRUE; // keep processing this buffer - } // looks like there is a complete message in the comm buffer - } // enough data left in comm buffer to possibly be a complete message - } // while loop to get all complete messages for each comm buffer - } // for loop to check all comm buffers for messages - - // if any bad CRCs detected, see if too many - if ( TRUE == badCRCDetected ) - { - checkTooManyBadMsgCRCs(); - } -} - -/*********************************************************************//** - * @brief - * The consumeBufferPaddingBeforeSync function removes any bytes in a given - * buffer that lie before a sync byte. - * @details Inputs: none - * @details Outputs: Any padding at front of comm buffer is consumed. - * @param buffer the comm buffer to process - * @return none - *************************************************************************/ -static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ) -{ - U08 data; - U32 numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); - - // consume bytes out of buffer 1 at a time until we find the sync byte or it's empty - while ( numOfBytesInBuffer > 0 ) - { - peekFromCommBuffer( buffer, &data, 1 ); - if ( MESSAGE_SYNC_BYTE == data ) - { - break; // we found a sync - we're done - } - else // not a sync byte, so consume it - { - getFromCommBuffer( buffer, &data, 1 ); - numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); - } - } -} - -/*********************************************************************//** - * @brief - * The parseMessageFromBuffer function looks for a complete message in a - * given buffer. If a message is found, its size is returned. - * @details Inputs: none - * @details Outputs: If a complete message can be found in buffer contents, it is parsed out. - * @param data pointer to byte array to search for a message - * @param len number of bytes in the data to search - * @return size of message if found, zero if no complete message found, - * -1 if message found but CRC fails. - *************************************************************************/ -static S32 parseMessageFromBuffer( U08 *data, U32 len ) -{ - U32 i; - U32 payloadSize; - U32 msgSize; - S32 result = 0; - - for ( i = 0; i < len; i++ ) - { - // find sync byte - if ( MESSAGE_SYNC_BYTE == data[ i ] ) - { - U32 pos = i + 1; // skip past sync byte implemented - U32 remSize = len - pos; - - // if a minimum sized msg would fit in remaining, continue - if ( remSize >= MESSAGE_OVERHEAD_SIZE ) - { - payloadSize = data[ pos + sizeof(MESSAGE_HEADER_T) - sizeof(U08) ]; - msgSize = MESSAGE_OVERHEAD_SIZE + payloadSize; - // we now know the size of the message - we can now know if full message is contained in buffer - if ( msgSize <= remSize ) - { // check CRC to make sure it's a valid message - if ( data[i+msgSize] == crc8( &data[pos], msgSize - 1 ) ) - { - result = msgSize; // we found a complete, valid message of this size - } - else // CRC failed - { - result = -1; // we found a complete, invalid message - } - } - } - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The processReceivedMessages function processes any messages in the - * received message queues. - * @details Inputs: Received Message Queues - * @details Outputs: Message(s) processed. - * @return none - *************************************************************************/ -static void processReceivedMessages( void ) -{ - BOOL isThereMsgRcvd = TRUE; // assume TRUE at first to get into while loop - MESSAGE_WRAPPER_T message; - - while ( TRUE == isThereMsgRcvd ) - { - // see if any messages received - isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); - if ( TRUE == isThereMsgRcvd ) - { // CRC should be good because we checked it during parsing before adding to queue - but check it again for good measure - if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) - { - // if ACK, mark pending message ACK'd - if ( MSG_ID_ACK == message.msg.hdr.msgID ) - { - matchACKtoPendingACKList( message.msg.hdr.seqNo ); - } - else - { - // if received message requires ACK, queue one up - if ( message.msg.hdr.seqNo < 0 ) - { - sendACKMsg( &message.msg ); - } - // otherwise, process the received message - processReceivedMessage( &message.msg ); - } - } - else // CRC failed - { - checkTooManyBadMsgCRCs(); - } - } - } -} - -/*********************************************************************//** - * @brief - * The checkForCommTimeouts function checks for sub-system communication timeout errors. - * @details Inputs: timeOfLastDGCheckIn, timeOfLastUICheckIn - * @details Outputs: possibly a comm t/o alarm - * @return none - *************************************************************************/ -static void checkForCommTimeouts( void ) -{ - if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) - { - hdIsCommunicating = FALSE; -#ifndef DEBUG_ENABLED - activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm if we're in middle of a treatment? or if in a mode that comm loss would impact badly? -#endif - } -} - -/*********************************************************************//** - * @brief - * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs - * within a set period of time. Assumed function is being called when a new - * bad CRC is detected so a new bad CRC will be added to the list. - * @details Inputs: badCRCTimeStamps[], badCRCListIdx, badCRCListCount - * @details Outputs: possibly a "too many bad CRCs" alarm - * @return none - *************************************************************************/ -static void checkTooManyBadMsgCRCs( void ) + timeOfLastHDCheckIn = getMSTimerCount(); + } + } + else if ( -1 == msgSize ) // candidate message with bad CRC found? + { + badCRCDetected = TRUE; + getFromCommBuffer( MSG_IN_BUFFERS[ i ], data, 1 ); // consume sync byte so we can re-sync + messagesInBuffer = TRUE; // keep processing this buffer + } // looks like there is a complete message in the comm buffer + } // enough data left in comm buffer to possibly be a complete message + } // while loop to get all complete messages for each comm buffer + } // for loop to check all comm buffers for messages + + // if any bad CRCs detected, see if too many + if ( TRUE == badCRCDetected ) + { + checkTooManyBadMsgCRCs(); + } +} + +/*********************************************************************//** + * @brief + * The consumeBufferPaddingBeforeSync function removes any bytes in a given + * buffer that lie before a sync byte. + * @details Inputs: none + * @details Outputs: Any padding at front of comm buffer is consumed. + * @param buffer the comm buffer to process + * @return none + *************************************************************************/ +static void consumeBufferPaddingBeforeSync( COMM_BUFFER_T buffer ) { + U08 data; + U32 numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); + + // consume bytes out of buffer 1 at a time until we find the sync byte or it's empty + while ( numOfBytesInBuffer > 0 ) + { + peekFromCommBuffer( buffer, &data, 1 ); + if ( MESSAGE_SYNC_BYTE == data ) + { + break; // we found a sync - we're done + } + else // not a sync byte, so consume it + { + getFromCommBuffer( buffer, &data, 1 ); + numOfBytesInBuffer = numberOfBytesInCommBuffer( buffer ); + } + } +} + +/*********************************************************************//** + * @brief + * The parseMessageFromBuffer function looks for a complete message in a + * given buffer. If a message is found, its size is returned. + * @details Inputs: none + * @details Outputs: If a complete message can be found in buffer contents, it is parsed out. + * @param data pointer to byte array to search for a message + * @param len number of bytes in the data to search + * @return size of message if found, zero if no complete message found, + * -1 if message found but CRC fails. + *************************************************************************/ +static S32 parseMessageFromBuffer( U08 *data, U32 len ) +{ + U32 i; + U32 payloadSize; + U32 msgSize; + S32 result = 0; + + for ( i = 0; i < len; i++ ) + { + // find sync byte + if ( MESSAGE_SYNC_BYTE == data[ i ] ) + { + U32 pos = i + 1; // skip past sync byte implemented + U32 remSize = len - pos; + + // if a minimum sized msg would fit in remaining, continue + if ( remSize >= MESSAGE_OVERHEAD_SIZE ) + { + payloadSize = data[ pos + sizeof(MESSAGE_HEADER_T) - sizeof(U08) ]; + msgSize = MESSAGE_OVERHEAD_SIZE + payloadSize; + // we now know the size of the message - we can now know if full message is contained in buffer + if ( msgSize <= remSize ) + { // check CRC to make sure it's a valid message + if ( data[i+msgSize] == crc8( &data[pos], msgSize - 1 ) ) + { + result = msgSize; // we found a complete, valid message of this size + } + else // CRC failed + { + result = -1; // we found a complete, invalid message + } + } + } + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The processReceivedMessages function processes any messages in the + * received message queues. + * @details Inputs: Received Message Queues + * @details Outputs: Message(s) processed. + * @return none + *************************************************************************/ +static void processReceivedMessages( void ) +{ + BOOL isThereMsgRcvd = TRUE; // assume TRUE at first to get into while loop + MESSAGE_WRAPPER_T message; + + while ( TRUE == isThereMsgRcvd ) + { + // see if any messages received + isThereMsgRcvd = getFromMsgQueue( MSG_Q_IN, &message ); + if ( TRUE == isThereMsgRcvd ) + { // CRC should be good because we checked it during parsing before adding to queue - but check it again for good measure + if ( message.crc == crc8( (U08*)(&message), sizeof(MESSAGE_HEADER_T) + message.msg.hdr.payloadLen ) ) + { + // if ACK, mark pending message ACK'd + if ( MSG_ID_ACK == message.msg.hdr.msgID ) + { + matchACKtoPendingACKList( message.msg.hdr.seqNo ); + } + else + { + // if received message requires ACK, queue one up + if ( message.msg.hdr.seqNo < 0 ) + { + sendACKMsg( &message.msg ); + } + // otherwise, process the received message + processReceivedMessage( &message.msg ); + } + } + else // CRC failed + { + checkTooManyBadMsgCRCs(); + } + } + } +} + +/*********************************************************************//** + * @brief + * The checkForCommTimeouts function checks for sub-system communication timeout errors. + * @details Inputs: timeOfLastDGCheckIn, timeOfLastUICheckIn + * @details Outputs: possibly a comm t/o alarm + * @return none + *************************************************************************/ +static void checkForCommTimeouts( void ) +{ + if ( TRUE == didTimeout( timeOfLastHDCheckIn, HD_COMM_TIMEOUT_IN_MS ) ) + { + hdIsCommunicating = FALSE; +#ifndef DEBUG_ENABLED + activateAlarmNoData( ALARM_ID_HD_COMM_TIMEOUT ); // TODO - add this alarm if we're in middle of a treatment? or if in a mode that comm loss would impact badly? +#endif + } +} + +/*********************************************************************//** + * @brief + * The checkTooManyBadMsgCRCs function checks for too many bad message CRCs + * within a set period of time. Assumed function is being called when a new + * bad CRC is detected so a new bad CRC will be added to the list. + * @details Inputs: badCRCTimeStamps[], badCRCListIdx, badCRCListCount + * @details Outputs: possibly a "too many bad CRCs" alarm + * @return none + *************************************************************************/ +static void checkTooManyBadMsgCRCs( void ) +{ if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_BAD_MSG_CRC ) ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_COMM_TOO_MANY_BAD_CRCS, 2 ); // 2 for DG - } + } #ifdef DEBUG_ENABLED { char debugStr[100]; @@ -866,260 +866,256 @@ sendDebugDataToUI( (U08*)debugStr ); } #endif -} - -/*********************************************************************//** - * @brief - * The addMsgToPendingACKList function adds a given message to the pending - * ACK list. Messages in this list will require receipt of an ACK message - * for this particular message within a limited time. - * @details Inputs: pendingAckList[] - * @details Outputs: pendingAckList[] - * @param msg pointer to msg within the message data - * @param msgData pointer to message data to add to pending ACK list - * @param len number of bytes of message data - * @return TRUE if message added successfully, FALSE if not - *************************************************************************/ -BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) -{ - BOOL result = FALSE; - U32 i; - - // find first open slot in pending ACK list and add given msg data to it - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - _disable_IRQ(); // slot selection needs interrupt protection - if ( FALSE == pendingAckList[ i ].used ) - { - S16 seqNo = msg->hdr.seqNo * -1; // remove ACK bit from seq # - - pendingAckList[ i ].used = TRUE; - _enable_IRQ(); - pendingAckList[ i ].seqNo = seqNo; - pendingAckList[ i ].channel = channel; - pendingAckList[ i ].timeStamp = getMSTimerCount(); - pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; - pendingAckList[ i ].msgSize = len; - memcpy( pendingAckList[ i ].msg, msgData, len ); - result = TRUE; - break; - } - else - { - _enable_IRQ(); - } - } - - return result; -} - -/*********************************************************************//** - * @brief - * The matchACKtoPendingACKList function searches the pending ACK list to - * see if the sequence number from a received ACK msg matches any. If found, - * the list entry is removed. - * @details Inputs: pendingAckList[] - * @details Outputs: pendingAckList[] - * @param seqNo sequence number to match to an entry in the list - * @return TRUE if a match was found, FALSE if not - *************************************************************************/ -static BOOL matchACKtoPendingACKList( S16 seqNo ) -{ - BOOL result = FALSE; - U32 i; - - // find match - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { - if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) - { // remove message pending ACK from list - pendingAckList[ i ].used = FALSE; - result = TRUE; - break; - } - } - - return result; -} - -/*********************************************************************//** - * @brief +} + +/*********************************************************************//** + * @brief + * The addMsgToPendingACKList function adds a given message to the pending + * ACK list. Messages in this list will require receipt of an ACK message + * for this particular message within a limited time. + * @details Inputs: pendingAckList[] + * @details Outputs: pendingAckList[] + * @param msg pointer to msg within the message data + * @param msgData pointer to message data to add to pending ACK list + * @param len number of bytes of message data + * @return TRUE if message added successfully, FALSE if not + *************************************************************************/ +BOOL addMsgToPendingACKList( MESSAGE_T *msg, COMM_BUFFER_T channel, U08 *msgData, U32 len ) +{ + BOOL result = FALSE; + U32 i; + + // find first open slot in pending ACK list and add given msg data to it + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + _disable_IRQ(); // slot selection needs interrupt protection + if ( FALSE == pendingAckList[ i ].used ) + { + S16 seqNo = msg->hdr.seqNo * -1; // remove ACK bit from seq # + + pendingAckList[ i ].used = TRUE; + _enable_IRQ(); + pendingAckList[ i ].seqNo = seqNo; + pendingAckList[ i ].channel = channel; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + pendingAckList[ i ].retries = MSG_NOT_ACKED_MAX_RETRIES; + pendingAckList[ i ].msgSize = len; + memcpy( pendingAckList[ i ].msg, msgData, len ); + result = TRUE; + break; + } + else + { + _enable_IRQ(); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The matchACKtoPendingACKList function searches the pending ACK list to + * see if the sequence number from a received ACK msg matches any. If found, + * the list entry is removed. + * @details Inputs: pendingAckList[] + * @details Outputs: pendingAckList[] + * @param seqNo sequence number to match to an entry in the list + * @return TRUE if a match was found, FALSE if not + *************************************************************************/ +static BOOL matchACKtoPendingACKList( S16 seqNo ) +{ + BOOL result = FALSE; + U32 i; + + // find match + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { + if ( ( TRUE == pendingAckList[ i ].used ) && ( pendingAckList[ i ].seqNo == seqNo ) ) + { // remove message pending ACK from list + pendingAckList[ i ].used = FALSE; + result = TRUE; + break; + } + } + + return result; +} + +/*********************************************************************//** + * @brief * The checkPendingACKList function searches the pending ACK list to see if - * any have expired. Any such messages will be queued for retransmission - * and if max retries reached a fault is triggered. - * @details Inputs: pendingAckList[] - * @details Outputs: pendingAckList[] - * @return none - *************************************************************************/ -static void checkPendingACKList( void ) -{ - U32 i; - - // find expired messages pending ACK - for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) - { // pending ACK expired? - if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) - { // if retries left, reset and resend pending message - if ( pendingAckList[ i ].retries > 0 ) - { // re-queue message for transmit - pendingAckList[ i ].retries--; - pendingAckList[ i ].timeStamp = getMSTimerCount(); - addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); + * any have expired. Any such messages will be queued for retransmission + * and if max retries reached a fault is triggered. + * @details Inputs: pendingAckList[] + * @details Outputs: pendingAckList[] + * @return none + *************************************************************************/ +static void checkPendingACKList( void ) +{ + U32 i; + + // find expired messages pending ACK + for ( i = 0; i < PENDING_ACK_LIST_SIZE; i++ ) + { // pending ACK expired? + if ( ( TRUE == pendingAckList[ i ].used ) && ( TRUE == didTimeout( pendingAckList[ i ].timeStamp, MSG_NOT_ACKED_TIMEOUT_MS ) ) ) + { // if retries left, reset and resend pending message + if ( pendingAckList[ i ].retries > 0 ) + { // re-queue message for transmit + pendingAckList[ i ].retries--; + pendingAckList[ i ].timeStamp = getMSTimerCount(); + addToCommBuffer( pendingAckList[ i ].channel, pendingAckList[ i ].msg, pendingAckList[ i ].msgSize ); } - // if no retries left, alarm - else - { - U16 msgID; - - memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); + // if no retries left, alarm + else + { + U16 msgID; + + memcpy( &msgID, &pendingAckList[ i ].msg[ sizeof( U08 ) + sizeof( U16) ], sizeof( U16 ) ); SET_ALARM_WITH_1_U32_DATA( ALARM_ID_CAN_MESSAGE_NOT_ACKED, (U32)msgID ); - pendingAckList[ i ].used = FALSE; // take pending message off of list - } - } - } -} - -/*********************************************************************//** - * @brief - * The processReceivedMessage function processes a given message. - * @details Inputs: none - * @details Outputs: message processed - * @param message pointer to message to process - * @return none - *************************************************************************/ -static void processReceivedMessage( MESSAGE_T *message ) -{ - U16 msgID = message->hdr.msgID; - - // handle any messages from other sub-systems - switch ( msgID ) - { - case MSG_ID_POWER_OFF_WARNING: - handlePowerOffWarning( message ); - break; - - case MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS: - handleSetDialysateTemperatureCmd( message ); - break; - - case MSG_ID_REQUEST_FW_VERSIONS: - handleFWVersionCmd( message ); - break; - - case MSG_ID_DG_SWITCH_RESERVOIR_CMD: - handleSwitchReservoirCmd( message ); - break; - - case MSG_ID_DG_FILL_CMD: - handleFillCmd( message ); - break; - - case MSG_ID_DG_DRAIN_CMD: - handleDrainCmd( message ); - break; - - case MSG_ID_STARTING_STOPPING_TREATMENT_CMD: - handleStartStopTreatmentMsg( message ); - break; - - case MSG_ID_DG_SAMPLE_WATER_CMD: - handleSampleWaterCmd( message ); - break; - - case MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD: - handleStartStopTrimmerHeaterCmd( message ); - break; - - case MSG_ID_DG_TESTER_LOGIN_REQUEST: - handleTesterLogInRequest( message ); - break; - - default: - // unrecognized message ID received - ok, ignore - may be a test message handled below - break; - } - - // handle any test messages if tester has logged in successfully - if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) - { - switch ( msgID ) - { - case MSG_ID_DG_ALARM_STATE_OVERRIDE: - handleTestAlarmStateOverrideRequest( message ); - break; - - case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: - handleTestWatchdogCheckInStateOverrideRequest( message ); - break; - - case MSG_ID_DG_SET_RTC_DATE_TIME: - handleSetRTCTimestamp( message ); - break; - - case MSG_ID_START_STOP_PRIMARY_HEATER: - handleStartStopPrimaryHeater ( message ); - break; - - case MSG_ID_LOAD_CELL_OVERRIDE: - handleTestLoadCellOverrideRequest( message ); - break; - - case MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: - handleTestLoadCellDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_PRESSURE_OVERRIDE: - handleTestPressureSensorOverrideRequest( message ); - break; - - case MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: - handleTestPressureDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_RO_PUMP_SET_PT_OVERRIDE: - handleTestROPumpSetPointOverrideRequest( message ); - break; - - case MSG_ID_RO_MEASURED_FLOW_OVERRIDE: - handleTestROMeasuredFlowOverrideRequest( message ); - break; - - case MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: - handleTestROPumpDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_DRAIN_PUMP_SET_RPM_OVERRIDE: - handleTestDrainPumpSetPointOverrideRequest( message ); - break; - - case MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: - handleTestDrainPumpDataBroadcastIntervalOverrideRequest( message ); - break; - - case MSG_ID_VALVE_STATE_OVERRIDE: - handleTestValveStateOverrideRequest( message ); - break; - - case MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: - handleTestValvesStatesPublishIntervalOverrideRequest( message ); - break; - - case MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: - handleTestDGSafetyShutdownOverrideRequest( message ); + pendingAckList[ i ].used = FALSE; // take pending message off of list + } + } + } +} + +/*********************************************************************//** + * @brief + * The processReceivedMessage function processes a given message. + * @details Inputs: none + * @details Outputs: message processed + * @param message pointer to message to process + * @return none + *************************************************************************/ +static void processReceivedMessage( MESSAGE_T *message ) +{ + U16 msgID = message->hdr.msgID; + + // handle any messages from other sub-systems + switch ( msgID ) + { + case MSG_ID_POWER_OFF_WARNING: + handlePowerOffWarning( message ); + break; + + case MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS: + handleSetDialysateTemperatureCmd( message ); + break; + + case MSG_ID_REQUEST_FW_VERSIONS: + handleFWVersionCmd( message ); + break; + + case MSG_ID_DG_SWITCH_RESERVOIR_CMD: + handleSwitchReservoirCmd( message ); + break; + + case MSG_ID_DG_FILL_CMD: + handleFillCmd( message ); + break; + + case MSG_ID_DG_DRAIN_CMD: + handleDrainCmd( message ); + break; + + case MSG_ID_STARTING_STOPPING_TREATMENT_CMD: + handleStartStopTreatmentMsg( message ); + break; + + case MSG_ID_DG_SAMPLE_WATER_CMD: + handleSampleWaterCmd( message ); + break; + + case MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD: + handleStartStopTrimmerHeaterCmd( message ); + break; + + case MSG_ID_DG_TESTER_LOGIN_REQUEST: + handleTesterLogInRequest( message ); + break; + + default: + // unrecognized message ID received - ok, ignore - may be a test message handled below + break; + } + + // handle any test messages if tester has logged in successfully + if ( ( msgID > MSG_ID_FIRST_DG_TESTER_MESSAGE ) && ( msgID <= END_OF_MSG_IDS ) && ( TRUE == isTestingActivated() ) ) + { + switch ( msgID ) + { + case MSG_ID_DG_ALARM_STATE_OVERRIDE: + handleTestAlarmStateOverrideRequest( message ); break; - - case MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE: - handleTestTemperatureSensorsOverrideRequest ( message ); - break; - - case MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE: - handleTestTemperatureSensorsDataPublishOverrideRequest ( message ); - break; - - case MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE: - handleTestHeatersDataPublishOverrideRequest ( message ); + + case MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE: + handleTestWatchdogCheckInStateOverrideRequest( message ); break; - + + case MSG_ID_DG_SET_RTC_DATE_TIME: + handleSetRTCTimestamp( message ); + break; + + case MSG_ID_START_STOP_PRIMARY_HEATER: + handleStartStopPrimaryHeater ( message ); + break; + + case MSG_ID_LOAD_CELL_OVERRIDE: + handleTestLoadCellOverrideRequest( message ); + break; + + case MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: + handleTestLoadCellDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_PRESSURE_OVERRIDE: + handleTestPressureSensorOverrideRequest( message ); + break; + + case MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: + handleTestPressureDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_RO_MEASURED_FLOW_OVERRIDE: + handleTestROMeasuredFlowOverrideRequest( message ); + break; + + case MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: + handleTestROPumpDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_DRAIN_PUMP_SET_RPM_OVERRIDE: + handleTestDrainPumpSetPointOverrideRequest( message ); + break; + + case MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: + handleTestDrainPumpDataBroadcastIntervalOverrideRequest( message ); + break; + + case MSG_ID_VALVE_STATE_OVERRIDE: + handleTestValveStateOverrideRequest( message ); + break; + + case MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE: + handleTestValvesStatesPublishIntervalOverrideRequest( message ); + break; + + case MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: + handleTestDGSafetyShutdownOverrideRequest( message ); + break; + + case MSG_ID_TEMPERATURE_SENSORS_VALUE_OVERRIDE: + handleTestTemperatureSensorsOverrideRequest ( message ); + break; + + case MSG_ID_TEMPERATURE_SENSORS_PUBLISH_INTERVAL_OVERRIDE: + handleTestTemperatureSensorsDataPublishOverrideRequest ( message ); + break; + + case MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE: + handleTestHeatersDataPublishOverrideRequest ( message ); + break; + case MSG_ID_CONDUCTIVITY_OVERRIDE: handleTestSetConductivityOverrideRequest ( message ); break; @@ -1164,11 +1160,27 @@ handleConcentratePumpPublishIntervalOverride( message ); break; - default: - // TODO - unrecognized message ID received - ignore - break; - } - } -} + case MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE: + handleROPumpDutyCycleOverride( message ); + break; + case MSG_ID_DG_RO_FLOW_RATE_OVERRIDE: + handleROFlowRateOverride( message ); + break; + + case MSG_ID_DG_RO_PUMP_TARGET_FLOW_OVERRIDE: + handleROPumpTargetFlowOverride( message ); + break; + + case MSG_ID_DG_RO_PUMP_TARGET_PRESSURE_OVERRIDE: + handleROPumpTargetPressureOverride( message ); + break; + + default: + // TODO - unrecognized message ID received - ignore + break; + } + } +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -ra6bf8a0785fba2986292aeff04e1aa944ff07195 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision a6bf8a0785fba2986292aeff04e1aa944ff07195) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -478,38 +478,32 @@ return result; } -/*********************************************************************//** - * @brief - * The broadcastROPumpData function sends out RO pump data. - * @details Inputs: none - * @details Outputs: RO pump data msg constructed and queued - * @param tgtPressure target pressure for RO pump in PSI - * @param measFlow measure RO flow rate in LPM - * @param setPWM set PWM duty cycle in % - * @return TRUE if msg successfully queued for transmit, FALSE if not - *************************************************************************/ -BOOL broadcastROPumpData( U32 tgtPressure, F32 measFlow, F32 setPWM ) -{ - BOOL result; - MESSAGE_T msg; - U08 *payloadPtr = msg.payload; - RO_PUMP_DATA_T payload; - - // create a message record - blankMessage( &msg ); - msg.hdr.msgID = MSG_ID_RO_PUMP_DATA; - msg.hdr.payloadLen = sizeof( RO_PUMP_DATA_T ); - - payload.setROPumpPressure = tgtPressure; - payload.measROFlowRate = measFlow; - payload.roPumpPWM = setPWM; - - memcpy( payloadPtr, &payload, sizeof( RO_PUMP_DATA_T ) ); - - // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer - result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); - - return result; +/*********************************************************************//** + * @brief + * The broadcastROPumpData function sends out RO pump data. + * @details + * Inputs : none + * Outputs : RO pump data msg constructed and queued + * @param RO Pump msg constructed and queued + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastROPumpData( RO_PUMP_DATA_T *pumpData ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // create a message record + blankMessage( &msg ); + msg.hdr.msgID = MSG_ID_RO_PUMP_DATA; + msg.hdr.payloadLen = sizeof( RO_PUMP_DATA_T ); + + memcpy( payloadPtr, pumpData, sizeof( RO_PUMP_DATA_T ) ); + + // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, COMM_BUFFER_OUT_CAN_DG_BROADCAST, ACK_NOT_REQUIRED ); + + return result; } /*********************************************************************//** @@ -1416,38 +1410,6 @@ /*********************************************************************//** * @brief - * The handleTestROPumpSetPointOverrideRequest function handles a request to - * override the RO pump pressure set point (in PSI). - * @details Inputs: none - * @details Outputs: message handled - * @param message a pointer to the message to handle - * @return none - *************************************************************************/ -void handleTestROPumpSetPointOverrideRequest( 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 = testSetTargetROPumpPressureOverride( payload.state.u32 ); - } - else - { - result = testResetTargetROPumpPressureOverride(); - } - } - - // respond to request - sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); -} - -/*********************************************************************//** - * @brief * The handleTestROMeasuredFlowOverrideRequest function handles a request to * override the RO flow rate. * @details Inputs: none @@ -2007,4 +1969,114 @@ sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); } +/*********************************************************************//** +* @brief +* The handleROPumpDutyCycleOverride function handles a request to override +* the RO pumps duty cycle. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*************************************************************************/ +void handleROPumpDutyCycleOverride( 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) ); + + result = testSetTargetDutyCycle( payload.state.f32 ); + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** +* @brief +* The handleROFlowRateOverride function handles a request to override +* the RO flow rate. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*******************************************************************/ +void handleROFlowRateOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + if ( FALSE == payload.reset ) + { + result = testSetMeasuredROFlowRateOverride( payload.state.f32 ); + } + else + { + result = testResetMeasuredROFlowRateOverride(); + } + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** +* @brief +* The handleROPumpTargetFlowOverride function handles a request to override +* the RO pump target flow rate. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*******************************************************************/ +void handleROPumpTargetFlowOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + + result = setROPumpTargetFlowRate( payload.state.f32, payload.state.f32 ); + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + +/*********************************************************************//** +* @brief +* The handleROPumpTargetPressureOverride function handles a request to +* override the RO pump target pressure. +* @details Inputs: none +* @details Outputs: message handled +* @param message a pointer to the message to handle +* @return none +*******************************************************************/ +void handleROPumpTargetPressureOverride( MESSAGE_T *message ) +{ + TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; + BOOL result = FALSE; + + // verify payload length + if ( sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) == message->hdr.payloadLen ) + { + memcpy( &payload, message->payload, sizeof(TEST_OVERRIDE_ARRAY_PAYLOAD_T) ); + + result = testSetTargetROPumpPressure( payload.state.f32 ); + } + + // respond to request + sendTestAckResponseMsg( (MSG_ID_T)message->hdr.msgID, result ); +} + /**@}*/ Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r498aa2804b2babde370f74f0cf9a333655fc0410 -r1943944469d5a9f841f366ef9d8969c3072bd7ab --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 498aa2804b2babde370f74f0cf9a333655fc0410) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 1943944469d5a9f841f366ef9d8969c3072bd7ab) @@ -14,64 +14,65 @@ * @date (original) 05-Nov-2019 * ***************************************************************************/ - -#ifndef __SYSTEM_COMM_MESSAGES_H__ -#define __SYSTEM_COMM_MESSAGES_H__ - -#include "DGCommon.h" -#include "MsgQueues.h" +#ifndef __SYSTEM_COMM_MESSAGES_H__ +#define __SYSTEM_COMM_MESSAGES_H__ + +#include "DGCommon.h" +#include "MsgQueues.h" +#include "ROPump.h" + /** * @defgroup SystemCommMessages SystemCommMessages * @brief System communication messages service module. Handles and broadcasts system messages. * * @addtogroup SystemCommMessages * @{ */ - -// ********** public definitions ********** - -// ********** public function prototypes ********** - -// ACK MSG -BOOL sendACKMsg( MESSAGE_T *message ); - -// MSG_ID_ALARM_TRIGGERED -BOOL broadcastAlarmTriggered( U16 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); - -// MSG_ID_ALARM_CLEARED -BOOL broadcastAlarmCleared( U16 alarm ); - + +// ********** public definitions ********** + +// ********** public function prototypes ********** + +// ACK MSG +BOOL sendACKMsg( MESSAGE_T *message ); + +// MSG_ID_ALARM_TRIGGERED +BOOL broadcastAlarmTriggered( U16 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 ); + +// MSG_ID_ALARM_CLEARED +BOOL broadcastAlarmCleared( U16 alarm ); + // MSG_ID_DG_ACCELEROMETER_DATA BOOL broadcastAccelData( F32 x, F32 y, F32 z, F32 xm, F32 ym, F32 zm, F32 xt, F32 yt, F32 zt ); -// MSG_ID_RTC_EPOCH -BOOL broadcastRTCEpoch( U32 epoch ); // TODO - probably don't want DG to broadcast these - -// MSG_ID_DG_OP_MODE -BOOL broadcastDGOperationMode( U32 mode, U32 subMode ); - -// MSG_ID_LOAD_CELL_READINGS -BOOL broadcastLoadCellData( F32 loadCellA1, F32 loadCellA2, F32 loadCellB1, F32 loadCellB2 ); - -// MSG_ID_DG_VALVES_STATES -BOOL broadcastValvesStates( U16 valvesStates ); - -// MSG_ID_RO_PUMP_DATA -BOOL broadcastROPumpData( U32 tgtPressure, F32 measFlow, F32 setPWM ); - -// MSG_ID_DRAIN_PUMP_DATA -BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac ); +// MSG_ID_RTC_EPOCH +BOOL broadcastRTCEpoch( U32 epoch ); // TODO - probably don't want DG to broadcast these +// MSG_ID_DG_OP_MODE +BOOL broadcastDGOperationMode( U32 mode, U32 subMode ); + +// MSG_ID_LOAD_CELL_READINGS +BOOL broadcastLoadCellData( F32 loadCellA1, F32 loadCellA2, F32 loadCellB1, F32 loadCellB2 ); + +// MSG_ID_DG_VALVES_STATES +BOOL broadcastValvesStates( U16 valvesStates ); + +// MSG_ID_RO_PUMP_DATA +BOOL broadcastROPumpData( RO_PUMP_DATA_T *pumpData ); + +// MSG_ID_DRAIN_PUMP_DATA +BOOL broadcastDrainPumpData( U32 tgtSpeed, U32 dac ); + // MSG_ID_DG_CONCENTRATE_PUMP_DATA BOOL broadcastConcentratePumpData( void * concentratePumpDataPtr ); - -// MSG_ID_DG_PRESSURES_DATA -BOOL broadcastPressureSensorsData( F32 measROIn, F32 measROOut, F32 measDrainIn, F32 measDrainOut ); - -// MSG_ID_DG_RESERVOIR_DATA -BOOL broadcastReservoirData( U32 resID, U32 fillToVol, U32 drainToVol ); - + +// MSG_ID_DG_PRESSURES_DATA +BOOL broadcastPressureSensorsData( F32 measROIn, F32 measROOut, F32 measDrainIn, F32 measDrainOut ); + +// MSG_ID_DG_RESERVOIR_DATA +BOOL broadcastReservoirData( U32 resID, U32 fillToVol, U32 drainToVol ); + // MSG_ID_HEATERS_READINGS BOOL broadcastHeatersData ( U32 mainPrimaryDC, U32 smallPrimaryDC, U32 trimmerDC ); @@ -81,110 +82,107 @@ // MSG_ID_DG_CONDUCTIVITY_DATA BOOL broadcastConductivityData( void * conductivityDataPtr ); -// MSG_ID_POWER_OFF_WARNING -void handlePowerOffWarning( MESSAGE_T *message ); - -// MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS -void handleSetDialysateTemperatureCmd( MESSAGE_T *message ); - -// MSG_ID_REQUEST_FW_VERSIONS -void handleFWVersionCmd( MESSAGE_T *message ); - -// MSG_ID_DG_SWITCH_RESERVOIR -void handleSwitchReservoirCmd( MESSAGE_T *message ); - -// MSG_ID_DG_FILL -void handleFillCmd( MESSAGE_T *message ); - -// MSG_ID_DG_DRAIN -void handleDrainCmd( MESSAGE_T *message ); - -// MSG_ID_STARTING_STOPPING_TREATMENT -void handleStartStopTreatmentMsg( MESSAGE_T *message ); - -// MSG_ID_DG_SAMPLE_WATER_CMD -void handleSampleWaterCmd( MESSAGE_T *message ); - +// MSG_ID_POWER_OFF_WARNING +void handlePowerOffWarning( MESSAGE_T *message ); + +// MSG_ID_SET_DG_DIALYSATE_TEMP_TARGETS +void handleSetDialysateTemperatureCmd( MESSAGE_T *message ); + +// MSG_ID_REQUEST_FW_VERSIONS +void handleFWVersionCmd( MESSAGE_T *message ); + +// MSG_ID_DG_SWITCH_RESERVOIR +void handleSwitchReservoirCmd( MESSAGE_T *message ); + +// MSG_ID_DG_FILL +void handleFillCmd( MESSAGE_T *message ); + +// MSG_ID_DG_DRAIN +void handleDrainCmd( MESSAGE_T *message ); + +// MSG_ID_STARTING_STOPPING_TREATMENT +void handleStartStopTreatmentMsg( MESSAGE_T *message ); + +// MSG_ID_DG_SAMPLE_WATER_CMD +void handleSampleWaterCmd( MESSAGE_T *message ); + // MSG_ID_START_STOP_PRIMARY_HEATER BOOL handleStartStopPrimaryHeater( MESSAGE_T * message ); -// MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD -void handleStartStopTrimmerHeaterCmd( MESSAGE_T *message ); - -// *********** public test support message functions ********** - -#ifdef DEBUG_ENABLED -// DEBUG OUTPUT -BOOL sendDebugData( U08 *dbgData, U32 len ); +// MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD +void handleStartStopTrimmerHeaterCmd( MESSAGE_T *message ); +// *********** public test support message functions ********** + +#ifdef DEBUG_ENABLED +// DEBUG OUTPUT +BOOL sendDebugData( U08 *dbgData, U32 len ); + // Debug message to UI for logging void sendDebugDataToUI( U08 *str ); -#endif - -// MSG_TESTER_LOG_IN -void handleTesterLogInRequest( MESSAGE_T *message ); -BOOL isTestingActivated( void ); - -// MSG_ID_DG_ALARM_STATE_OVERRIDE -void handleTestAlarmStateOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE: -void handleTestWatchdogCheckInStateOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_LOAD_CELL_OVERRIDE -void handleTestLoadCellOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: -void handleTestLoadCellDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_TEMPERATURE_SENSORS_OVERRIDE -void handleTestTemperatureSensorsOverrideRequest ( MESSAGE_T *message ); - -// MSG_ID_TEMPERATURE_SENSORS_DATA_PUBLISH_OVERRIDE -void handleTestTemperatureSensorsDataPublishOverrideRequest ( MESSAGE_T *message ); - -// MSG_ID_PUBLSIH_HEATERS_DATA_OVERRIDE -void handleTestHeatersDataPublishOverrideRequest ( MESSAGE_T *message ); - -// MSG_ID_SET_RTC_TIMESTAMP -void handleSetRTCTimestamp( MESSAGE_T *message ); - -// MSG_ID_PRESSURE_OVERRIDE: -void handleTestPressureSensorOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: -void handleTestPressureDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_RO_PUMP_SET_PT_OVERRIDE: -void handleTestROPumpSetPointOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_RO_MEASURED_FLOW_OVERRIDE: -void handleTestROMeasuredFlowOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: -void handleTestROPumpDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_DRAIN_PUMP_SET_PT_OVERRIDE: -void handleTestDrainPumpSetPointOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: -void handleTestDrainPumpDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_VALVE_STATE_OVERRIDE -void handleTestValveStateOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE -void handleTestValvesStatesPublishIntervalOverrideRequest( MESSAGE_T *message ); - -// MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: +#endif + +// MSG_TESTER_LOG_IN +void handleTesterLogInRequest( MESSAGE_T *message ); +BOOL isTestingActivated( void ); + +// MSG_ID_DG_ALARM_STATE_OVERRIDE +void handleTestAlarmStateOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_WATCHDOG_TASK_CHECKIN_OVERRIDE: +void handleTestWatchdogCheckInStateOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_LOAD_CELL_OVERRIDE +void handleTestLoadCellOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_LOAD_CELLL_SEND_INTERVAL_OVERRIDE: +void handleTestLoadCellDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_TEMPERATURE_SENSORS_OVERRIDE +void handleTestTemperatureSensorsOverrideRequest ( MESSAGE_T *message ); + +// MSG_ID_TEMPERATURE_SENSORS_DATA_PUBLISH_OVERRIDE +void handleTestTemperatureSensorsDataPublishOverrideRequest ( MESSAGE_T *message ); + +// MSG_ID_PUBLSIH_HEATERS_DATA_OVERRIDE +void handleTestHeatersDataPublishOverrideRequest ( MESSAGE_T *message ); + +// MSG_ID_SET_RTC_TIMESTAMP +void handleSetRTCTimestamp( MESSAGE_T *message ); + +// MSG_ID_PRESSURE_OVERRIDE: +void handleTestPressureSensorOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_PRESSURE_SEND_INTERVAL_OVERRIDE: +void handleTestPressureDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_RO_MEASURED_FLOW_OVERRIDE: +void handleTestROMeasuredFlowOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE: +void handleTestROPumpDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DRAIN_PUMP_SET_PT_OVERRIDE: +void handleTestDrainPumpSetPointOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DRAIN_PUMP_SEND_INTERVAL_OVERRIDE: +void handleTestDrainPumpDataBroadcastIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_VALVE_STATE_OVERRIDE +void handleTestValveStateOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_VALVES_STATES_PUBLISH_INTERVAL_OVERRIDE +void handleTestValvesStatesPublishIntervalOverrideRequest( MESSAGE_T *message ); + +// MSG_ID_DG_SAFETY_SHUTDOWN_OVERRIDE: void handleTestDGSafetyShutdownOverrideRequest( MESSAGE_T *message ); // MSG_ID_CONDUCTIVITY_OVERRIDE void handleTestSetConductivityOverrideRequest( MESSAGE_T *message ); // MSG_ID_CONDUCTIVITY_PUBLISH_INTERVAL_OVERRIDE -void handleTestSetConductivityDataPublishIntervalOverrideRequest( MESSAGE_T *message ); - +void handleTestSetConductivityDataPublishIntervalOverrideRequest( MESSAGE_T *message ); + // MSG_ID_DG_ACCEL_OVERRIDE: void handleTestDGAccelOverrideRequest( MESSAGE_T *message ); @@ -212,6 +210,18 @@ // MSG_ID_CONCENTRATE_PUMP_PUBLISH_INTERVAL_OVERRIDE void handleConcentratePumpPublishIntervalOverride( MESSAGE_T *message ); +// MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE +void handleROPumpDutyCycleOverride( MESSAGE_T *message ); + +// MSG_ID_DG_RO_FLOW_RATE_OVERRIDE +void handleROFlowRateOverride( MESSAGE_T *message ); + +// MSG_ID_DG_RO_PUMP_TARGET_FLOW_OVERRIDE +void handleROPumpTargetFlowOverride( MESSAGE_T *message ); + +// MSG_ID_DG_RO_PUMP_TARGET_PRESSURE_OVERRIDE +void handleROPumpTargetPressureOverride( MESSAGE_T *message ); + /**@}*/ -#endif +#endif