Index: firmware/App/Controllers/FluidLeak.c =================================================================== diff -u --- firmware/App/Controllers/FluidLeak.c (revision 0) +++ firmware/App/Controllers/FluidLeak.c (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -0,0 +1,519 @@ +/************************************************************************** +* +* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file FluidLeak.c +* +* @author (last) Peman Montazemi +* @date (last) 19-Feb-2021 +* +* @author (original) Peman Montazemi +* @date (original) 19-Feb-2021 +* +***************************************************************************/ + +#include "FluidLeak.h" +#include "AlarmMgmt.h" +#include "FPGA.h" +#include "ModeTreatmentParams.h" +#include "OperationModes.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TaskPriority.h" +#include "Timers.h" + +/** + * @addtogroup FluidLeak + * @{ + */ + +// ********** private definitions ********** + +#define FLUID_LEAK_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the fluid leak data is published on the CAN bus. +#define FLUID_LEAK_DETECTED 1 ///< Fluid leak detected state + +// ********** private data ********** + +static U32 fluidLeakDataPublicationTimerCounter = 0; ///< Used to schedule fluid leak data publication to CAN bus. + +/// Interval (in ms) at which to publish fluid leak data to CAN bus. +static OVERRIDE_U32_T fluidLeakDataPublishInterval = { FLUID_LEAK_DATA_PUB_INTERVAL, FLUID_LEAK_DATA_PUB_INTERVAL, 0, 0 }; +static OVERRIDE_U32_T fluidLeakStates[ NUM_OF_FLUID_LEAK_DETECTORS ]; ///< Detected fluid leak state for each fluid leak detector. + +// ********** private function prototypes ********** + +static void publishFluidLeakData( void ); +static U32 getPublishFluidLeakDataInterval( void ); + +/*********************************************************************//** + * @brief + * The initFluidLeak function initializes the Fluid Leak module. + * @details Inputs: none + * @details Outputs: Fluid Leak module initialized. + * @return none + *************************************************************************/ +void initFluidLeak( void ) +{ + resetAirTrap(); + airTrapSelfTestState = AIR_TRAP_SELF_TEST_STATE_START; + airTrapIllegalLevelSensorsCtr = 0; +} + +/*********************************************************************//** + * @brief + * The resetAirTrap function resets certain parts of the air trap module + * between treatments. + * @details Inputs: none + * @details Outputs: Air Trap module reset. + * @return none + *************************************************************************/ +void resetAirTrap( void ) +{ + airTrapControllerState = AIR_TRAP_INIT_STATE; + pendingStartAirTrapController = FALSE; + pendingStopAirTrapController = FALSE; +} + +/*********************************************************************//** + * @brief + * The startAirTrapControl function requests a start to air trap control. + * @details Inputs: airTrapControllerState + * @details Outputs: pendingStartAirTrapController + * @return none + *************************************************************************/ +void startAirTrapControl( void ) +{ + if ( FALSE == isAirTrapControlling() ) + { + pendingStartAirTrapController = TRUE; + } +} + +/*********************************************************************//** + * @brief + * The endAirTrapControl function requests a stop to air trap control. + * @details Inputs: airTrapControllerState + * @details Outputs: pendingStopAirTrapController + * @return none + *************************************************************************/ +void endAirTrapControl( void ) +{ + if ( TRUE == isAirTrapControlling() ) + { + pendingStopAirTrapController = TRUE; + setValveAirTrap( STATE_CLOSED ); // Always exit air trap valve control w/ valve closed. + } +} + +/*********************************************************************//** + * @brief + * The isAirTrapControlling function determines whether the air trap is + * currently controlling. + * @details Inputs: airTrapControllerState + * @details Outputs: none + * @return TRUE if air trap is currently controlling, FALSE if not. + *************************************************************************/ +BOOL isAirTrapControlling( void ) +{ + BOOL result = FALSE; + + if ( airTrapControllerState >= AIR_TRAP_VALVE_CLOSED_STATE ) + { + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The execAirTrapMonitor function executes the air trap monitor. + * @details Inputs: FPGA air trap levels GPIO pin levels, airTrapIllegalLevelSensorsCtr + * @details Outputs: airTrapLevels[], airTrapIllegalLevelSensorsCtr + * @return none + *************************************************************************/ +void execAirTrapMonitor( void ) +{ + BOOL state; + + // Get latest level readings + getFPGAFluidLeakState( &state ); + airTrapLevels[ AIR_TRAP_LEVEL_SENSOR_LOWER ].data = (U32)( TRUE == lower ? AIR_TRAP_LEVEL_AIR : AIR_TRAP_LEVEL_FLUID ); + airTrapLevels[ AIR_TRAP_LEVEL_SENSOR_UPPER ].data = (U32)( TRUE == upper ? AIR_TRAP_LEVEL_AIR : AIR_TRAP_LEVEL_FLUID ); + + // Check level readings are valid + if ( FLUID_LEAK_DETECTED == getFluidLeakState( ) + { + + activateAlarmNoData( ALARM_ID_HD_FLUID_LEAK_DETECTED ); + } + else + { + if ( airTrapIllegalLevelSensorsCtr > 0 ) + { + airTrapIllegalLevelSensorsCtr--; + } + } +} + +/*********************************************************************//** + * @brief + * The execAirTrapMonitorPriming function executes the air trap monitor + * for cartridge priming during pre-treatment mode. + * @details Inputs: airTrapLevels[], airTrapFillAlarmCtr + * @details Outputs: airTrapFillAlarmCtr + * @return none + *************************************************************************/ +void execAirTrapMonitorPriming( void ) +{ + // TODO - Implement when priming sub-mode of pre-treatment mode is implemented. + // ActivateAlarmNoData( ALARM_ID_AIR_TRAP_FILL_DURING_PRIME ); +} + +/*********************************************************************//** + * @brief + * The execAirTrapMonitorTreatment function executes the air trap monitor + * for treatment mode. + * @details Inputs: airTrapLevels[], airTrapFillAlarmCtr + * @details Outputs: airTrapFillAlarmCtr + * @return none + *************************************************************************/ +void execAirTrapMonitorTreatment( void ) +{ + // Check air trap fill timeout during treatment + if ( AIR_TRAP_VALVE_OPEN_STATE == airTrapControllerState ) + { + F32 bldFlowRate = (F32)getTreatmentParameterU32( TREATMENT_PARAM_BLOOD_FLOW ); // Function will never return zero + F32 fillTimeoutMS = ( VENOUS_LINE_VOLUME_ML / bldFlowRate ) * (F32)SEC_PER_MIN * (F32)MS_PER_SECOND; + + if ( TRUE == didTimeout( fillStartTime, fillTimeoutMS ) ) + { +#ifndef DISABLE_AIR_TRAP_LEVELING + activateAlarmNoData( ALARM_ID_AIR_TRAP_FILL_DURING_TREATMENT ); +#endif + } + } +} + +/*********************************************************************//** + * @brief + * The execAirTrapController function executes the air trap control state machine. + * @details Inputs: airTrapControllerState + * @details Outputs: airTrapControllerState + * @return none + *************************************************************************/ +void execAirTrapController( void ) +{ + // If we have faulted, close valve and go to manual control + if ( MODE_FAUL == getCurrentOperationMode() ) + { + airTrapControllerState = AIR_TRAP_MANUAL_CONTROL_STATE; + pendingStartAirTrapController = FALSE; + } + + // Execute air trap state machine + switch( airTrapControllerState ) + { + case AIR_TRAP_INIT_STATE: + airTrapControllerState = AIR_TRAP_MANUAL_CONTROL_STATE; + break; + + case AIR_TRAP_MANUAL_CONTROL_STATE: + airTrapControllerState = handleAirTrapManualControlState(); + break; + + case AIR_TRAP_VALVE_CLOSED_STATE: + airTrapControllerState = handleAirTrapValveClosedState(); + break; + + case AIR_TRAP_VALVE_OPEN_STATE: + airTrapControllerState = handleAirTrapValveOpenState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (U32)SW_FAULT_ID_AIR_TRAP_INVALID_STATE, (U32)airTrapControllerState ) + airTrapControllerState = AIR_TRAP_INIT_STATE; + break; + } + + // Publish air trap data if due + publishAirTrapData(); +} + +/*********************************************************************//** + * @brief + * The handleAirTrapManualControlState function handles the manual control + * state of the air trap. + * @details Inputs: pendingStartAirTrapController + * @details Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapManualControlState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_MANUAL_CONTROL_STATE; + + // Transition to valve control states when requested + if ( TRUE == pendingStartAirTrapController ) + { + pendingStartAirTrapController = FALSE; + setValveAirTrap( STATE_CLOSED ); + result = AIR_TRAP_VALVE_CLOSED_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleAirTrapValveClosedState function handles the valve closed state + * of the air trap. + * @details Inputs: pendingStopAirTrapController, airTrapLevels[] + * @details Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapValveClosedState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_CLOSED_STATE; + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopAirTrapController ) + { + pendingStopAirTrapController = FALSE; + result = AIR_TRAP_MANUAL_CONTROL_STATE; + } + // Transition to open valve state when air detected at lower level + else if ( AIR_TRAP_LEVEL_AIR == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ) ) + { + setValveAirTrap( STATE_OPEN ); + fillStartTime = getMSTimerCount(); + result = AIR_TRAP_VALVE_OPEN_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleAirTrapValveOpenState function handles the valve open state of + * the air trap. + * @details Inputs: pendingStopAirTrapController, airTrapLevels[] + * @details Outputs: none + * @return next state + *************************************************************************/ +static AIR_TRAP_STATE_T handleAirTrapValveOpenState( void ) +{ + AIR_TRAP_STATE_T result = AIR_TRAP_VALVE_OPEN_STATE; + + // Transition to manual valve control state when requested + if ( TRUE == pendingStopAirTrapController ) + { + pendingStopAirTrapController = FALSE; + result = AIR_TRAP_MANUAL_CONTROL_STATE; + } + // Transition to closed valve state when fluid detected at upper level + else if ( AIR_TRAP_LEVEL_FLUID == getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ) ) + { + setValveAirTrap( STATE_CLOSED ); + result = AIR_TRAP_VALVE_CLOSED_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getAirTrapLevel function gets the current reading for the given + * level sensor. + * @details Inputs: airTrapLevels[] + * @details Outputs: none + * @param sensor ID of level sensor to get reading for + * @return the current level sensor reading for the given sensor (air or fluid). + *************************************************************************/ +AIR_TRAP_LEVELS_T getAirTrapLevel( AIR_TRAP_LEVEL_SENSORS_T sensor ) +{ + AIR_TRAP_LEVELS_T result; + + if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) + { + result = (AIR_TRAP_LEVELS_T)airTrapLevels[ sensor ].data; + if ( OVERRIDE_KEY == airTrapLevels[ sensor ].override ) + { + result = (AIR_TRAP_LEVELS_T)airTrapLevels[ sensor ].ovData; + } + } + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, (U32)SW_FAULT_ID_AIR_TRAP_INVALID_LEVEL_SENSOR, (U32)sensor ) + result = AIR_TRAP_LEVEL_AIR; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getPublishAirTrapDataInterval function gets the air trap data + * publication interval. + * @details Inputs: airTrapDataPublishInterval + * @details Outputs: none + * @return the current air trap data publication interval (in task intervals). + *************************************************************************/ +static U32 getPublishAirTrapDataInterval( void ) +{ + U32 result = airTrapDataPublishInterval.data; + + if ( OVERRIDE_KEY == airTrapDataPublishInterval.override ) + { + result = airTrapDataPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishAirTrapData function publishes air trap data at the set interval. + * @details Inputs: airTrapLevels[] + * @details Outputs: if broadcast is due, send air trap data + * @return none + *************************************************************************/ +static void publishAirTrapData( void ) +{ + // Publish air trap data on interval + if ( ++airTrapDataPublicationTimerCounter >= getPublishAirTrapDataInterval() ) + { + AIR_TRAP_LEVELS_T lowLevel = getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_LOWER ); + AIR_TRAP_LEVELS_T highLevel = getAirTrapLevel( AIR_TRAP_LEVEL_SENSOR_UPPER ); + + broadcastAirTrapData( lowLevel, highLevel ); + airTrapDataPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The execAirTrapTest function executes the state machine for the air trap + * self-test. + * @details Inputs: none + * @details Outputs: none + * @return the current state of the PresOccl self-test. + *************************************************************************/ +SELF_TEST_STATUS_T execAirTrapTest( void ) +{ + SELF_TEST_STATUS_T status = SELF_TEST_STATUS_PASSED; + + // TODO - Implement POST + + return status; +} + + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetAirTrapDataPublishIntervalOverride function overrides the + * air trap data publish interval. + * @details Inputs: none + * @details Outputs: airTrapDataPublishInterval + * @param value override air trap data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetAirTrapDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_GENERAL_INTERVAL; + + result = TRUE; + airTrapDataPublishInterval.ovData = intvl; + airTrapDataPublishInterval.override = OVERRIDE_KEY; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetAirTrapDataPublishIntervalOverride function resets the override + * of the air trap data publish interval. + * @details Inputs: none + * @details Outputs: airTrapDataPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetAirTrapDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + airTrapDataPublishInterval.override = OVERRIDE_RESET; + airTrapDataPublishInterval.ovData = airTrapDataPublishInterval.ovInitData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetAirTrapLevelOverride function overrides the measured level + * for a given level sensor. + * @details Inputs: none + * @details Outputs: airTrapLevels[] + * @param sensor ID of level sensor to override + * @param level override level sensor with this + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetAirTrapLevelOverride( AIR_TRAP_LEVEL_SENSORS_T sensor, AIR_TRAP_LEVELS_T level ) +{ + BOOL result = FALSE; + + if ( ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) && ( level < NUM_OF_AIR_TRAP_LEVELS ) ) + { + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + airTrapLevels[ sensor ].ovData = (U32)level; + airTrapLevels[ sensor ].override = OVERRIDE_KEY; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetAirTrapLevelOverride function resets the override of the + * level sensor. + * @details Inputs: none + * @details Outputs: airTrapLevels[] + * @param sensor ID of level sensor to reset override + * @return TRUE if reset successful, FALSE if not + *************************************************************************/ +BOOL testResetAirTrapLevelOverride( AIR_TRAP_LEVEL_SENSORS_T sensor ) +{ + BOOL result = FALSE; + + if ( sensor < NUM_OF_AIR_TRAP_LEVEL_SENSORS ) + { + if ( TRUE == isTestingActivated() ) + { + result = TRUE; + airTrapLevels[ sensor ].override = OVERRIDE_RESET; + airTrapLevels[ sensor ].ovData = airTrapLevels[ sensor ].ovInitData; + } + } + + return result; +} + +/**@}*/ Index: firmware/App/Controllers/FluidLeak.h =================================================================== diff -u --- firmware/App/Controllers/FluidLeak.h (revision 0) +++ firmware/App/Controllers/FluidLeak.h (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -0,0 +1,57 @@ +/************************************************************************** +* +* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* +* THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +* WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +* +* @file FluidLeak.h +* +* @author (last) Peman Montazemi +* @date (last) 09-Mar-2021 +* +* @author (original) Peman Montazemi +* @date (original) 15-Feb-2021 +* +***************************************************************************/ + +#ifndef __FLUID_LEAK_H__ +#define __FLUID_LEAK_H__ + +#include "HDCommon.h" + +/** + * @defgroup FluidLeak FluidLeak + * @brief Fluid Leak detector monitor module. Monitors the + * fluid leak detector. + * + * @addtogroup FluidLeak + * @{ + */ + +// ********** public definitions ********** + +/// Enumeration of fluid leak detector states. +typedef enum FluidLeakDetectorStates +{ + FLUID_LEAK_STATE_WET = 0, ///< Fluid leak detector senses fluid + FLUID_LEAK_STATE_DRY, ///< Fluid leak detector does not sense any fluid + NUM_OF_FLUID_LEAK_STATES ///< Number of fluid leak detector states +} FLUID_LEAK_STATES_T; + +// ********** public function prototypes ********** + +void initFluidLeak( void ); +void execFluidLeakMonitor( void ); +void resetFluidLeak( void ); + +FLUID_LEAK_STATES_T getFluidLeakState( FLUID_LEAK_STATE_DETECTORS_T detector ); + +BOOL testSetFluidLeakDataPublishIntervalOverride( U32 value ); +BOOL testResetFluidLeakDataPublishIntervalOverride( void ); +BOOL testSetFluidLeakStateOverride( FLUID_LEAK_STATES_T state ); +BOOL testResetFluidLeakStateOverride( void ); + +/**@}*/ + +#endif Index: firmware/App/Services/FPGA.c =================================================================== diff -u -r911f6526ec3ba03ba0131681c7fb371c0abda6bb -rf9faa852e6768e386171a1ca3b8337f88cdc3e82 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision 911f6526ec3ba03ba0131681c7fb371c0abda6bb) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -7,8 +7,8 @@ * * @file FPGA.c * -* @author (last) Sean Nash -* @date (last) 14-Oct-2020 +* @author (last) Peman Montazemi +* @date (last) 15-Feb-2021 * * @author (original) Dara Navaei * @date (original) 05-Nov-2019 @@ -81,6 +81,8 @@ #define FPGA_AIRTRAP_LEVEL_LOW_MASK 0x0008 ///< Bit mask for air trap lower level sensor. #define FPGA_AIRTRAP_LEVEL_HIGH_MASK 0x0004 ///< Bit mask for air trap upper level sensor. +#define FPGA_FLUIDLEAK_STATE_MASK 0x0040 ///< Bit mask for fluid leak sensor. + // FPGA Sensors Record #pragma pack(push,1) /// Record structure for FPGA header read. @@ -1401,6 +1403,22 @@ /*********************************************************************//** * @brief + * The getFPGAFluidLeakState function gets the latest fluid leak sensor + * state. + * @details Inputs: fpgaSensorReadings + * @details Outputs: none + * @return none + *************************************************************************/ +void getFPGAFluidLeakState( BOOL *fluidLeak ) +{ + U16 fpgaGPIO = fpgaSensorReadings.fpgaGPIO; + U16 state = fpgaGPIO & FPGA_FLUIDLEAK_STATE_MASK; + + *fluidLeak = ( 0 == state ? FALSE : TRUE ); +} + +/*********************************************************************//** + * @brief * The setValveDialyzerInletPosition function sets the position of VDi * in counts * @details Inputs: fpgaActuatorSetPoints Index: firmware/App/Services/FPGA.h =================================================================== diff -u -rc672f41061bcd500d6593655641cb27ce3ae58fc -rf9faa852e6768e386171a1ca3b8337f88cdc3e82 --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision c672f41061bcd500d6593655641cb27ce3ae58fc) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -75,6 +75,8 @@ void setFPGAValvesControlMode( U16 bits ); U16 getFPGAValvesStatus( void ); +void getFPGAFluidLeakState( BOOL *fluidLeak ); + void setFPGAValveDialyzerInletPosition( S16 setPoint ); S16 getFPGAValveDialyzerInletPosition( void ); U16 getFPGAValveDialyzerInletCurrentCounts( void ); Index: firmware/App/Services/SystemComm.c =================================================================== diff -u -r98f34c2ab63d51a1bf248db454ebc04e184d4748 -rf9faa852e6768e386171a1ca3b8337f88cdc3e82 --- firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision 98f34c2ab63d51a1bf248db454ebc04e184d4748) +++ firmware/App/Services/SystemComm.c (.../SystemComm.c) (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -1187,10 +1187,6 @@ handleUIUserConfirmTreatmentParameters( message ); break; - case MSG_ID_UI_TREATMENT_END_REQUEST: - handleUIUserEndTreatmentRequest( message ); - break; - case MSG_ID_UI_PRESSURE_LIMITS_CHANGE_REQUEST: handleChangePressureLimitsRequest( message ); break; Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r1a5aa1dff6978966ecda860b09c07a84e80399fe -rf9faa852e6768e386171a1ca3b8337f88cdc3e82 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 1a5aa1dff6978966ecda860b09c07a84e80399fe) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision f9faa852e6768e386171a1ca3b8337f88cdc3e82) @@ -1771,7 +1771,6 @@ // Create a message record blankMessage( &msg ); - msg.hdr.msgID = MSG_ID_HD_TREATMENT_END_RESPONSE; msg.hdr.payloadLen = sizeof( BOOL ); memcpy( payloadPtr, &accepted, sizeof( BOOL ) );