/************************************************************************** * * Copyright (c) 2025-2026 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 BloodLeak.c * * @author (last) Dara Navaei * @date (last) 10-Sep-2024 * * @author (original) Dara Navaei * @date (original) 10-Sep-2024 * ***************************************************************************/ #include // For pow function #include // For memset and strlen #include // For sprintf #include "AlarmMgmtDD.h" #include "BloodLeakDriver.h" #include "BloodLeak.h" #include "FpgaDD.h" #include "Messaging.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "TaskPriority.h" #include "TDInterface.h" #include "Timers.h" #include "Utilities.h" /** * @addtogroup BloodLeak * @{ */ // ********** private definitions ********** #define BLOOD_LEAK_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the blood leak data is published on the CAN bus. #define BLOOD_LEAK_PERSISTENCE ( 10 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence for blood leak detected alarm. #define BLOOD_LEAK_RESET_TX_FIFO 2 ///< Blood leak reset transmit FIFO command. #define BLOOD_LEAK_UART_COMM_ACTIVE_LOW 0 ///< Blood leak UART communication active low command. #define BLOOD_LEAK_UART_COMM_ACTIVE_HIGH 1 ///< Blood leak UART communication active high command. #define BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH 11 ///< Blood leak set point maximum character length. #define BLOOD_LEAK_SET_POINT_START_CHAR_ASCII 83 ///< Blood leak set point sequence start character in ASCII (letter S). #define BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND 0 ///< Blood leak set point stop writing to FIFO command. #define BLOOD_LEAK_SET_POINT_START_CHAR_INDEX 0 ///< Blood leak set point sequence start character index number. #define BLOOD_LEAK_CARRIAGE_RETURN_ASCII 13 ///< Blood leak set point sequence carriage return character in ASCII. #define BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH 17 ///< Blood leak set point sequence maximum length. #define BLOOD_LEAK_ZERO_CMD_STATUS_READY 0x80 ///< Blood leak zero command status ready value. #define BLOOD_LEAK_SELF_TEST_CMD_STATUS_READY 0x80 ///< Blood leak self test command status ready value. #define BLOOD_LEAK_STATUS_BIT_HIGH 1 ///< Blood leak status bit high. #define BLOOD_LEAK_STATUS_BIT_LOW 0 ///< Blood leak status bit low. #define BLOOD_LEAK_ZERO_CMD_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Blood leak zero command timeout in milliseconds. #define BLOOD_LEAK_SELF_TEST_CMD_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Blood leak self test command timeout in milliseconds. #define BLOOD_LEAK_BETWEEN_ZERO_ST_WAIT_MS 250 ///< Blood leak wait time in between zero and self test commands in milliseconds. #define DATA_PUBLISH_COUNTER_START_COUNT 60 ///< Data publish counter start count. #define BLOOD_LEAK_DETECT_RECOVERY_MIN_TIME_MS ( 2 * MS_PER_SECOND ) ///< Blood leak blood detect recovery minimum time in milliseconds. // Embedded mode defines #define BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH 6 ///< Blood leak embedded mode command sequence length. #define BLOOD_LEAK_EMB_MODE_RQST_RX_LENGTH 2 ///< Blood leak embedded mode request new Rx data length. #define BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_HIGH 5 ///< Blood leak embedded mode communication active high command. #define BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW 4 ///< Blood leak embedded mode communication active low command. #define BLOOD_LEAK_EMB_MODE_COMM_RESET 6 ///< Blood leak embedded mode communication reset. #define BLOOD_LEAK_EMB_MODE_COMM_READ_REQST 12 ///< Blood leak embedded mode communication read Rx byte request. #define BLOOD_LEAK_EMB_MODE_RX_BUFFER_EMPTY 0x80 ///< Blood leak embedded mode buffer empty value. #define BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN 5 ///< Blood leak embedded mode number of commands. #define BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES 3 ///< Blood leak embedded mode max number of command tries. #define BLOOD_LEAK_EMB_MODE_0_NUM_ASCII 48 ///< Blood leak embedded mode character 0 in ASCII. #define BLOOD_LEAK_EMB_MODE_9_NUM_ASCII 57 ///< Blood leak embedded mode character 9 in ASCII. #define BLOOD_LEAK_EMB_MODE_SET_PNT_RESP_LEN 4 ///< Blood leak embedded mode set point response length. #define BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX 0 ///< Blood leak embedded mode command (UART/Transmit) column index number. #define BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX 1 ///< Blood leak embedded mode is command type UART or transmit flag. #define BLOOD_LEAK_EMB_MODE_PASS_ASCII 80 ///< Blood leak embedded mode P (pass) in ASCII. #define BLOOD_LEAK_EMB_MODE_FAIL_ASCII 70 ///< Blood leak embedded mode F (fail) in ASCII. #define BLOOD_LEAK_EMB_MODE_RESET_INDEX 0 ///< Blood leak embedded mode reset FIFO command index. #define BLOOD_LEAK_EMB_MODE_CMD_INDEX 2 ///< Blood leak embedded mode command index. #define BLOOD_LEAK_EMB_MODE_STOP_WRITE_INDEX 3 ///< Blood leak embedded mode stop write to FIFO index. #define BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX 4 ///< Blood leak embedded mode active high command index. #define BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX 0 ///< Blood leak embedded mode request Rx to read index. #define BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE 12 ///< Blood leak embedded mode command queue maximum size. #define BLOOD_LEAK_EMB_MODE_ZERO_CMD_RQRD_Q 5 ///< Blood leak embedded mode zero command required queue count. #define BLOOD_LEAK_EMB_MODE_NUM_OF_RETRIES 3 ///< Blood leak embedded mode number of retries to enqueue. #define BLOOD_LEAK_EMB_MODE_INFO_CMD_TIMEOUT_MS ( 1 * MS_PER_SECOND ) ///< Blood leak embedded mode informative command timeout in milliseconds. #define BLOOD_LEAK_EMB_MODE_NUM_OF_INFO_CMDS 2 ///< Blood leak embedded mode number of informative commands. #define BLOOD_LEAK_FPGA_ERROR_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Blood leak embedded mode FPGA error timeout in milliseconds. #define BLOOD_LEAK_RXFIFO_COUNT_MASK 0x03FF ///< Mask high order bits of blood leak sensor rx count. // ***************** zeroing status *************** // #define BLD_NOMINAL_INTENSITY 930 ///< Blood leak nominal intensity. #define BLD_MAX_INTENSITY_DRFT_AFTER_ZEROING 10 ///< Blood leak max intensity drift after zeroing. #define BLD_MAX_INTENSITY_OUT_OF_RANGE 0.40F ///< Blood leak maximum allowed intensity. #define BLD_MIN_INTENSITY_OUT_OF_RANGE 0.35F ///< Blood leak minimum allowed intensity. #define BLD_ZERO_MIN_INTERVAL_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Blood leak zeroing minimum interval in milliseconds. #define BLD_ZERO_MVG_AVG_NUM_OF_SAMPLES 16 ///< Blood leak number of moving average samples. #define BLD_ZERO_IN_RANGE_DRIFT_TIMEOUT_MS ( 10 * MS_PER_SECOND ) ///< Blood leak zero value drift in range timeout in milliseconds. #define BLD_MAX_UPPER_INTENSITY_DRIFT ( BLD_NOMINAL_INTENSITY + 20 ) ///< Blood leak maximum upper range intensity drift. #define BLD_START_OF_TX_MIN_INTENSITY_DRIFT 915 ///< Blood leak start of treatment minimum intensity. #define BLD_UPPER_INTENSITY_INTERVAL_MS ( 30 * SEC_PER_MIN * MS_PER_SECOND ) ///< Blood leak upper drift interval in milliseconds. #define BLD_ZERO_UPPER_RANGE_DRIFT_TIMEOUT_MS ( 60 * MS_PER_SECOND ) ///< Blood leak zero upper range drift timeout in milliseconds. // Defined states for the blood leak detector state machine. typedef enum BloodLeakStates { BLOOD_LEAK_WAIT_FOR_POST_STATE = 0, ///< Blood leak wait for post state. BLOOD_LEAK_CHECK_SET_POINT_STATE, ///< Blood leak check set point state. BLOOD_LEAK_INIT_STATE, ///< Blood leak init state. BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE, ///< Blood leak check for zero and self test commands state. BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE, ///< Blood leak verify intensity after zeroing state. BLOOD_LEAK_NORMAL_STATE, ///< Blood leak normal state. BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE, ///< Blood leak recover blood detect state. NUM_OF_BLOOD_LEAK_STATES ///< Number of blood leak detector states. } BLOOD_LEAK_STATE_T; /// Defined embedded states typedef enum EmbStates { BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE = 0, ///< Blood leak embedded mode state wait for command state. BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE, ///< Blood leak embedded mode state send command state. BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMMAND_RESPONSE_STATE, ///< Blood leak embedded mode state wait for command response state. NUM_OF_BLOOD_LEAK_EMB_MODE_STATES ///< Number of blood leak embedded mode states. } BLOOD_LEAK_EMB_MODE_STATE_T; /// Blood leak detector embedded mode commands typedef enum EmbCommands { NU_EMB_MODE_CMD = 0, ///< Null command. CS_EMB_MODE_CMD, ///< Control S command to switch to embedded mode. SP_EMB_MODE_CMD, ///< Set point command to set the set point. T_EMB_MODE_CMD, ///< Self test command. G_EMB_MODE_CMD, ///< Get self test command. I_EMB_MODE_CMD, ///< Intensity command. V_EMB_MODE_CMD, ///< Blood detection level command. Z_EMB_MODE_CMD, ///< Zero sensor command. Q_EMB_MODE_CMD, ///< Zero sensor confirm command. D_EMB_MODE_CMD, ///< Display blood detection command. C_EMB_MODE_CMD, ///< Calibration sensor command. NUM_OF_EMB_CMDS, ///< Number of embedded mode commands. } BLOOD_LEAK_EMB_MODE_CMD_T; #pragma pack(push,1) /// Embedded mode commands specifications typedef struct { U08 commandASCII; ///< Blood leak sensor command ID number in ASCII. U08 expChar1; ///< Blood leak sensor expected response in character. U08 expChar2; ///< Blood leak sensor expected response in character. U32 length; ///< Blood leak sensor expected response length in bytes. U32 timeoutMS; ///< Blood leak sensor receive timeout in milliseconds. U32 commandResp; ///< Blood leak sensor command response back. U08 commandRqstCount; ///< Blood leak sensor command request count. BOOL isCmdRespRdy; ///< Blood leak sensor is command response ready flag. } EMB_MODE_CMD_T; #pragma pack(pop) /// Blood leak zeroing status data structure typedef struct { U32 lastZeroingStartTimeMS; ///< Blood leak last zero sequence start time in milliseconds. U32 driftInRangeDebounceTimeMS; ///< Blood leak drift is in range debounce start time in milliseconds. U32 rawIntensity[ BLD_ZERO_MVG_AVG_NUM_OF_SAMPLES ]; ///< Blood leak raw intensity array. U32 intensityRunningSum; ///< Blood leak intensity running sum for moving average. U32 rawIntensityNextIndex; ///< Blood leak raw intensity next index for moving average. OVERRIDE_F32_T intensityMovingAverage; ///< Blood leak intensity moving average. OVERRIDE_U32_T zeroingDriftIntervalTimeMS; ///< Blood leak zeroing interval time in milliseconds. OVERRIDE_U32_T zeroingUpperRangeIntervalTimeMS; ///< BLood leak zeroing upper range interval time in milliseconds. U32 driftUpperRangeDebounceTimeMS; ///< Blood leak drift in upper range debounce time in milliseconds. U32 driftInRangeStatus; ///< Blood leak drift in range status. U32 driftUpperRangeStatus; ///< Blood leak drift upper range status. } BLOOD_LEAK_ZEROING_STATUS_T; // ********** private data ********** static BLOOD_LEAK_STATE_T bloodLeakState; ///< Current state of blood leak state machine. static OVERRIDE_U32_T bloodLeakStatus; ///< Detected blood leak status for blood leak detector. static SELF_TEST_STATUS_T bloodLeakSelfTestStatus; ///< Current status of blood leak self-test. static U32 bloodLeakPersistenceCtr; ///< Blood leak alarm persistence timer counter. static OVERRIDE_U32_T bloodLeakDataPublishInterval = { BLOOD_LEAK_PUB_INTERVAL, BLOOD_LEAK_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish blood leak data to CAN bus. static U32 bloodLeakDataPublicationCounter; ///< Timer counter used to schedule blood leak data publication to CAN bus. static U08 bloodLeakSetPointSequence[ BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ][ 2 ]; ///< Blood leak set point sequence array. static BOOL bloodLeakExitNormalRequested; ///< Blood leak exit normal state requested. static U32 bloodLeakRecoveryStartTimeMS; ///< Blood leak recovery start time in milliseconds. static BLOOD_LEAK_ZEROING_STATUS_T bloodLeakZeroingStatus; ///< Blood leak zeroing status. // Embedded mode variables static BLOOD_LEAK_EMB_MODE_STATE_T bloodLeakEmbModeSubstate; ///< Blood leak embedded mode state. ///< Blood leak embedded mode set point command. static EMB_MODE_CMD_T bloodLeakEmbModeCmd[ NUM_OF_EMB_CMDS ]; ///< Blood leak embedded mode commands. static U08 bloodLeakEmbModeCmdQ[ BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE ]; ///< Blood leak embedded mode command queue. static BOOL bloodLeakEmbModeHasZeroBeenRqustd; ///< Blood leak embedded mode flag to indicate zero has been requested. static U32 bloodLeakEmbModeCmdEnqueueCount; ///< Blood leak embedded mode command enqueue count // ********** private function prototypes ********** static BLOOD_LEAK_STATE_T handleBloodLeakWaitForPostState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakCheckSetPointState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakInitState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakCheckZeroAndSelfTestState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakVerifyIntensityAfterZeroingState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakNormalState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakRecoverBloodDetectState( void ); static void publishBloodLeakData( void ); static BLOOD_LEAK_STATUS_T getFPGABloodDetectProcessedStatus( void ); static BOOL isDialysateLineInBypass( void ); static void processBloodLeakIntensityData( void ); static BOOL isLowerRangeIntensityDriftZeroingNeeded( void ); static BOOL isUpperIntensityZeroingNeeded( void ); /*********************************************************************//** * @brief * The initBloodLeak function initializes the Blood Leak module. * @details \b Inputs: none * @details \b Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence * bloodLeakDataPublicationTimerCounter, bloodLeakEmbModeHasZeroBeenRqustd * bloodLeakEmbModeSubstate, bloodLeakEmbModeCmdEnqueueCount * bloodLeakPersistenceCtr, bloodLeakSignalEmbModeReq, * bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeOpsStartTime, * bloodLeakEmbModeRespBuffer, bloodLeakEmbModeRespIndex, * bloodLeakExitNormalRequested, bloodLeakEmbModeCmdSeqLength, * bloodLeakEmbModeHasRxRqstBeenSent, bloodLeakEmbModeInfoCmdEnqLastTimeStamp, * bloodLeakEmbModeInfoCmdCounter, bloodLeakRecoveryStartTimeMS, * bloodLeakZeroingStatus * @return none *************************************************************************/ void initBloodLeak( void ) { // Initialize the embedded mode specifications //initEmbModeSpecs(); bloodLeakDataPublicationCounter = DATA_PUBLISH_COUNTER_START_COUNT; bloodLeakState = BLOOD_LEAK_WAIT_FOR_POST_STATE; bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovInitData = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.ovData = BLOOD_LEAK_NOT_DETECTED; bloodLeakStatus.override = OVERRIDE_RESET; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; bloodLeakPersistenceCtr = 0; bloodLeakEmbModeSubstate = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; bloodLeakExitNormalRequested = FALSE; bloodLeakEmbModeHasZeroBeenRqustd = FALSE; bloodLeakEmbModeCmdEnqueueCount = 0; bloodLeakRecoveryStartTimeMS = getMSTimerCount(); // Set the blood leak embedded mode command queue to zero memset( bloodLeakEmbModeCmdQ, 0x0, BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE ); // Set the blood leak set pint sequence to 0 to be initialized memset( bloodLeakSetPointSequence, 0x0, BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ); // Initialize the blood leak zeroing sequence status structure memset( &bloodLeakZeroingStatus, 0x0, sizeof( BLOOD_LEAK_ZEROING_STATUS_T ) ); bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS.data = BLD_ZERO_MIN_INTERVAL_MS; bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS.ovInitData = BLD_ZERO_MIN_INTERVAL_MS; bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS.ovData = 0; bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS.override = 0; bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS.data = BLD_UPPER_INTENSITY_INTERVAL_MS; bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS.ovInitData = BLD_UPPER_INTENSITY_INTERVAL_MS; bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS.ovData = 0; bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS.override = 0; } /*********************************************************************//** * @brief * The execBloodLeak function executes the blood leak detector driver. * @details \b Inputs: bloodLeakState * @details \b Outputs: bloodLeakCalRecord, bloodLeakState * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when in an unknown state * @return none *************************************************************************/ void execBloodLeak( void ) { //if ( TRUE == isNewCalibrationRecordAvailable() ) // TODO uncomment when non-volatile memory has been implemented //{ // U32 length = sizeof( HD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ); // // getNVRecord2Driver( GET_CAL_BLOOD_LEAK_SENSOR, (U08*)&bloodLeakCalRecord, length, 0, ALARM_ID_HD_BLOOD_LEAK_INVALID_CAL_RECORD ); //} processBloodLeakIntensityData(); switch( bloodLeakState ) { case BLOOD_LEAK_WAIT_FOR_POST_STATE: bloodLeakState = handleBloodLeakWaitForPostState(); break; case BLOOD_LEAK_CHECK_SET_POINT_STATE: bloodLeakState = handleBloodLeakCheckSetPointState(); break; case BLOOD_LEAK_INIT_STATE: bloodLeakState = handleBloodLeakInitState(); break; case BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE: bloodLeakState = handleBloodLeakCheckZeroAndSelfTestState(); break; case BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE: bloodLeakState = handleBloodLeakVerifyIntensityAfterZeroingState(); break; case BLOOD_LEAK_NORMAL_STATE: bloodLeakState = handleBloodLeakNormalState(); break; case BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE: bloodLeakState = handleBloodLeakRecoverBloodDetectState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_TD_INVALID_BLOOD_LEAK_STATE, bloodLeakState ) bloodLeakState = BLOOD_LEAK_INIT_STATE; break; } // Publish blood leak data if due publishBloodLeakData(); } /*********************************************************************//** * @brief * The zeroBloodLeak function requests that the Blood Leak Detector be * zeroed. * @details \b Inputs: bloodLeakEmbModeCmdEnqueueCount * @details \b Outputs: bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakEmbModeCmdEnqueueCount, bloodLeakSelfTestStatus * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when there not enough queues available * @return TRUE if the zero commands were successfully queued otherwise, FALSE *************************************************************************/ BOOL zeroBloodLeak( void ) { BOOL status = FALSE; if ( getAvailableEmbModeQueueCount() >= BLOOD_LEAK_EMB_MODE_ZERO_CMD_RQRD_Q ) { status = TRUE; bloodLeakEmbModeHasZeroBeenRqustd = TRUE; // Since the zero commands have been queued, reset the counter bloodLeakEmbModeCmdEnqueueCount = 0; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; // Enqueue the zero and self test sequence (Z->G->Z->Q->T) enqueueEmbModeCmd( Z_EMB_MODE_CMD ); enqueueEmbModeCmd( G_EMB_MODE_CMD ); enqueueEmbModeCmd( Z_EMB_MODE_CMD ); enqueueEmbModeCmd( Q_EMB_MODE_CMD ); enqueueEmbModeCmd( T_EMB_MODE_CMD ); SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BLOOD_LEAK_ZEROING_REQUEST, 0, 0 ) } else if ( ++bloodLeakEmbModeCmdEnqueueCount > BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_ENQUEUE_FAILURE ) } return status; } /*********************************************************************//** * @brief * The zeroBloodLeakReset function resets the commandRqstCount for all the * zero blood leak commands. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void zeroBloodLeakReset( void ) { resetEmbModeCmdRqstCount( Z_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( G_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( Q_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( T_EMB_MODE_CMD ); } /*********************************************************************//** * @brief * The hasBloodLeakZeroSequenceFailed function returns TURE if the number * of times the zero sequence has failed. * @details \b Inputs: bloodLeakEmbModeCmd * @details \b Outputs: none * @return TRUE if zero sequence failed otherwise, FALSE *************************************************************************/ BOOL hasBloodLeakZeroSequenceFailed( void ) { // The zero sequence contains Z->G->Z->Q->T and each of the commands has a request counter but for checking whether the // zero sequence has failed only the Z command is checked. When the zero sequence is enqueued, all of the them enqueued so they are // at the same request count number. BOOL status = ( bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].commandRqstCount > BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ? TRUE : FALSE ); return status; } /*********************************************************************//** * @brief * The getBloodLeakStatus function gets the current reading for the blood * leak detector. * @details \b Inputs: bloodLeakStatus * @details \b Outputs: none * @return the current blood leak status. *************************************************************************/ BLOOD_LEAK_STATUS_T getBloodLeakStatus( void ) { BLOOD_LEAK_STATUS_T result = (BLOOD_LEAK_STATUS_T)getU32OverrideValue( &bloodLeakStatus ); return result; } /*********************************************************************//** * @brief * The getBloodLeakSelfTestStatus function gets the status for the blood * leak detector self-test. * @details \b Inputs: bloodLeakSelfTestStatus * @details \b Outputs: none * @return status of blood leak detector self-test. *************************************************************************/ SELF_TEST_STATUS_T getBloodLeakSelfTestStatus( void ) { return bloodLeakSelfTestStatus; } /*********************************************************************//** * @brief * The isBloodLeakZeroingNeeded function checks whether blood leak zeroing * is needed in terms of drift. * @details \b Inputs: none * @details \b Outputs: none * @return TRUE if blood leak zeroing is needed otherwise, FALSE *************************************************************************/ BOOL isBloodLeakZeroingNeeded( void ) { BOOL status = FALSE; TD_OP_MODE_T opMode = getTDOpMode(); if ( MODE_PRET == opMode ) { U32 intensity = getEmbModeInfoValue( I_EMB_MODE_CMD ); if ( ( intensity <= BLD_START_OF_TX_MIN_INTENSITY_DRIFT ) || ( intensity >= BLD_MAX_UPPER_INTENSITY_DRIFT ) ) { SEND_EVENT_WITH_2_F32_DATA( DD_EVENT_BLOOD_LEAK_ZEROING_REQUIRED, intensity, opMode ) status = TRUE; } } else if ( MODE_TREA == opMode ) { status |= isLowerRangeIntensityDriftZeroingNeeded(); status |= isUpperIntensityZeroingNeeded(); } return status; } /*********************************************************************//** * @brief * The exitBloodLeakNormalState requests that the blood leak sensor to exit * its normal state. * @details \b Inputs: bloodLeakState * @details \b Outputs: bloodLeakExitNormalRequested * @return none *************************************************************************/ void exitBloodLeakNormalState( void ) { if ( BLOOD_LEAK_NORMAL_STATE == bloodLeakState ) { bloodLeakExitNormalRequested = TRUE; } } /*********************************************************************//** * @brief * The execBloodLeakSelfTest function executes the blood leak self-test. * @details \b Inputs: none * @details \b Outputs: none * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_INVALID_CAL_RECORD when the * calibration record is not available. * @return blood leak self test results (SELF_TEST_STATUS_T) *************************************************************************/ SELF_TEST_STATUS_T execBloodLeakSelfTest( void ) { SELF_TEST_STATUS_T result = SELF_TEST_STATUS_IN_PROGRESS; //U32 length = sizeof( HD_BLOOD_LEAK_SENSOR_CAL_RECORD_T ); ALARM_ID_T alarm = ALARM_ID_DD_BLOOD_LEAK_INVALID_CAL_RECORD; BOOL calStatus = TRUE; //getNVRecord2Driver( GET_CAL_BLOOD_LEAK_SENSOR, (U08*)&bloodLeakCalRecord, length, 0, alarm ); // TODO uncomment if ( TRUE == calStatus ) { result = SELF_TEST_STATUS_PASSED; } else { result = SELF_TEST_STATUS_FAILED; } return result; } /*********************************************************************//** * @brief * The handleBloodLeakWaitForPostState function handles the wait for POST * state of the of blood leak state machine. * @details \b Inputs: bloodLeakEmbModeCmd * @details \b Outputs: bloodLeakEmbModeCmd * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_SENSOR_EMBEDDED_MODE_FAILURE if * the embedded mode was not started correctly. * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakWaitForPostState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_WAIT_FOR_POST_STATE; BOOL isEmbModeReady = FALSE; U32 cmdResp = bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandResp; if ( BLOOD_LEAK_EMB_MODE_PASS_ASCII == cmdResp ) { isEmbModeReady = TRUE; } else if ( ( TRUE == bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].isCmdRespRdy ) && ( BLOOD_LEAK_EMB_MODE_FAIL_ASCII == cmdResp ) ) { if ( bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandRqstCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { // Enqueue the commands to set the embedded mode and request the set point of the blood leak sensor // Since set point was requested in the init function as well, both are requested here because we have to be // in the embedded mode first enqueueEmbModeCmd( CS_EMB_MODE_CMD ); enqueueEmbModeCmd( D_EMB_MODE_CMD ); } else { activateAlarmNoData( ALARM_ID_DD_BLOOD_LEAK_SENSOR_EMBEDDED_MODE_FAILURE ); } } if ( ( getCurrentOperationMode() != MODE_INIT ) && ( TRUE == isEmbModeReady ) ) { resetEmbModeCmdRqstCount( CS_EMB_MODE_CMD ); state = BLOOD_LEAK_CHECK_SET_POINT_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakCheckSetPointState function handles the check set point * state to ensure the set point is set correctly. * @details \b Inputs: bloodLeakCalRecord * @details \b Outputs: bloodLeakCalRecord * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_SENSOR_SET_POINT_SET_FAILURE if * the blood leak detector's set point does not match with the set point in * the calibration record. * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakCheckSetPointState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_CHECK_SET_POINT_STATE; //U16 bloodLeakSetPoint = bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandResp; BOOL isCommandRespReady = bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].isCmdRespRdy; U08 commandDRqstCount = bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRqstCount; SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BLOOD_LEAK_NUM_OF_SET_POINT_CHECK_FAILURES, (U32)commandDRqstCount, state ) if ( FALSE ) // TODO bring back the blood leak set point once the calibration system is ready //if ( ( bloodLeakSetPoint != bloodLeakCalRecord.setPoint ) && ( TRUE == isCommandRespReady ) ) { if ( commandDRqstCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { enqueueEmbModeCmd( D_EMB_MODE_CMD ); } else { activateAlarmNoData( ALARM_ID_DD_BLOOD_LEAK_SENSOR_SET_POINT_SET_FAILURE ); } } else if ( TRUE == isCommandRespReady ) { resetEmbModeCmdRqstCount( D_EMB_MODE_CMD ); state = BLOOD_LEAK_INIT_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakInitState function handles the Blood Leak module in init * state. * @details \b Inputs: bloodLeakEmbModeHasZeroBeenRqustd * @details \b Outputs: none * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakInitState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_INIT_STATE; // Check if the zero command has been requested if ( TRUE == bloodLeakEmbModeHasZeroBeenRqustd ) { bloodLeakEmbModeHasZeroBeenRqustd = FALSE; state = BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakCheckZeroAndSelfTestState function handles the blood * leak check zero and self test state. * @details \b Inputs: bloodLeakEmbModeCmd * @details \b Outputs: bloodLeakEmbModeCmd, bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakSelfTestStatus * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakCheckZeroAndSelfTestState( void ) { U08 i; BLOOD_LEAK_STATE_T state = BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE; BOOL areCommandsReady = TRUE; // Check to see if all commands in sequence have been responded to for ( i = 0; i < NUM_OF_EMB_CMDS; i++ ) { switch( i ) { case Z_EMB_MODE_CMD: case G_EMB_MODE_CMD: case Q_EMB_MODE_CMD: case T_EMB_MODE_CMD: // All the commands shall be processed and have data prior to checking the results areCommandsReady &= bloodLeakEmbModeCmd[ i ].isCmdRespRdy; break; default: // Do nothing with the rest of the commands break; } } // When all commands in sequence have been responded to, determine whether anything went wrong if ( TRUE == areCommandsReady ) { // Enqueue the zero and self test sequence (Z->G->Z->Q->T) BOOL hasCmdSqncFailed = FALSE; BOOL hasCurrCmdFailed = FALSE; for ( i = 0; i < NUM_OF_EMB_CMDS; i++ ) { switch( i ) { case Z_EMB_MODE_CMD: case Q_EMB_MODE_CMD: case T_EMB_MODE_CMD: // Check to see if any of the command responses failed hasCurrCmdFailed = ( BLOOD_LEAK_EMB_MODE_PASS_ASCII == bloodLeakEmbModeCmd[ i ].commandResp ? FALSE : TRUE ); hasCmdSqncFailed |= hasCurrCmdFailed; break; case G_EMB_MODE_CMD: // G command will return a value that has to be greater than 0 hasCurrCmdFailed = ( bloodLeakEmbModeCmd[ i ].commandResp > 0 ? FALSE : TRUE ); hasCmdSqncFailed |= hasCurrCmdFailed; break; default: // Do nothing with the rest of the commands break; } } // Pass self-test if entire sequence was successful if ( FALSE == hasCmdSqncFailed ) { // Done with the commands, request a fresh intensity read to check its range enqueueEmbModeCmd( I_EMB_MODE_CMD ); state = BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE; } // If not successful, retry if we've not run out else { bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; state = BLOOD_LEAK_INIT_STATE; SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BLOOD_LEAK_SELF_TEST_RESULT, bloodLeakSelfTestStatus, state ) } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakVerifyIntensityAfterZeroingState function checks the * blood leak sensor's intensity after zeroing the sensor. * @details \b Inputs: bloodLeakEmbModeCmd * @details \b Outputs: bloodLeakSelfTestStatus * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakVerifyIntensityAfterZeroingState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE; if ( TRUE == bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].isCmdRespRdy ) { U32 intensity = getEmbModeInfoValue( I_EMB_MODE_CMD ); state = BLOOD_LEAK_INIT_STATE; bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; if ( abs( BLD_NOMINAL_INTENSITY - intensity ) <= BLD_MAX_INTENSITY_DRFT_AFTER_ZEROING ) { // Done with zero sequence, transition to other states zeroBloodLeakReset(); bloodLeakZeroingStatus.lastZeroingStartTimeMS = getMSTimerCount(); bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; state = BLOOD_LEAK_NORMAL_STATE; if ( TRUE == isAlarmActive( ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ) ) { state = BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE; } } SEND_EVENT_WITH_2_U32_DATA( DD_EVENT_BLOOD_LEAK_SELF_TEST_RESULT, bloodLeakSelfTestStatus, state ) } return state; } /*********************************************************************//** * @brief * The handleBloodLeakNormalState function handles the Blood Leak module * in normal state. * @details \b Inputs: bloodLeakStatus, bloodLeakPersistenceCtr, * bloodLeakExitNormalRequested * @details \b Outputs: bloodLeakStatus, bloodLeakPersistenceCtr, * bloodLeakExitNormalRequested, bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakRecoveryStartTimeMS * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_DETECTED if blood has been * detected during treatment * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT if blood * has been detected during treatment * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakNormalState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_NORMAL_STATE; bloodLeakStatus.data = getFPGABloodDetectProcessedStatus(); switch ( getTDOpMode() ) { case MODE_TREA: case MODE_SERV: // TODO uncomment //if ( ( FALSE == isDialysateLineInBypass() ) && ( getTreatmentState() != TREATMENT_RECIRC_STATE ) && ( getDialysisState() != DIALYSIS_SALINE_BOLUS_STATE ) ) if ( TRUE ) { if ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) { if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; //if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != TRUE ) // TODO enable when test config is caught up { activateAlarmNoData( ALARM_ID_DD_BLOOD_LEAK_DETECTED ); activateAlarmNoData( ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ); bloodLeakRecoveryStartTimeMS = getMSTimerCount(); state = BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE; } } } else if ( bloodLeakPersistenceCtr > 0 ) { bloodLeakPersistenceCtr--; } else { clearAlarmCondition( ALARM_ID_DD_BLOOD_LEAK_DETECTED ); clearAlarmCondition( ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ); } } default: // Do nothing. Do not check for blood in other modes. break; } if ( TRUE == bloodLeakExitNormalRequested ) { bloodLeakExitNormalRequested = FALSE; state = BLOOD_LEAK_INIT_STATE; } else if ( TRUE == bloodLeakEmbModeHasZeroBeenRqustd ) { // Check whether zeroing the sensor has been requested or not if yes, transition to zero command state otherwise, stay in this state bloodLeakEmbModeHasZeroBeenRqustd = FALSE; state = BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakRecoverBloodDetectState function handles the blood * leak recover blood detect state. * @details \b Inputs: bloodLeakStatus, bloodLeakRecoveryStartTimeMS, * bloodLeakEmbModeHasZeroBeenRqustd, bloodLeakExitNormalRequested * @details \b Outputs: bloodLeakStatus, bloodLeakRecoveryStartTimeMS, * bloodLeakPersistenceCtr, bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakExitNormalRequested * @details \b Alarm: ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT if blood * has been detected during treatment * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakRecoverBloodDetectState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE; bloodLeakStatus.data = getFPGABloodDetectProcessedStatus(); // Check if the blood is not detected but at the same time the Dialin pump should be running to make sure we are in the // blood recovery state of the treatment stop so the blood detection recovery is not done on the stagnant fluid // NOTE: should we check of the measured flow is about 600 mL/min? if ( ( BLOOD_LEAK_NOT_DETECTED == getBloodLeakStatus() ) /*&& ( TRUE == isDialInPumpRunning() ) */ ) { if ( TRUE == didTimeout( bloodLeakRecoveryStartTimeMS, BLOOD_LEAK_DETECT_RECOVERY_MIN_TIME_MS ) ) { // Blood has not been detected for the specified period of time so clear the alarm condition clearAlarmCondition( ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ); } } else { bloodLeakRecoveryStartTimeMS = getMSTimerCount(); } if ( isAlarmActive( ALARM_ID_DD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ) != TRUE ) { // Once the user hit resume, transition back to normal state to continue detecting for blood // Reset the blood detect counter prior to transitioning back bloodLeakPersistenceCtr = 0; state = BLOOD_LEAK_NORMAL_STATE; } else if ( TRUE == bloodLeakEmbModeHasZeroBeenRqustd ) { // Check whether zeroing the sensor has been requested or not if yes, transition to zero command state otherwise, stay in this state bloodLeakEmbModeHasZeroBeenRqustd = FALSE; state = BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE; } return state; } /*********************************************************************//** * @brief * The publishBloodLeakData function publishes blood leak data at the set interval. * @details \b Inputs: bloodLeakDataPublicationTimerCounter * @details \b Outputs: bloodLeakDataPublicationTimerCounter, bloodLeakPersistenceCtr, * bloodLeakState, bloodLeakZeroingStatus * @details \b Message: MSG_ID_DD_BLOOD_LEAK_DATA DD blood leak broadcast message * @return none *************************************************************************/ static void publishBloodLeakData( void ) { // Publish blood leak data on interval if ( ++bloodLeakDataPublicationCounter >= getU32OverrideValue( &bloodLeakDataPublishInterval ) ) { BLOOD_LEAK_DATA_T data; data.bloodLeakStatus = (U32)getBloodLeakStatus(); data.bloodLeakState = (U32)bloodLeakState; data.bloodLeakPersistentCounter = bloodLeakPersistenceCtr; data.bloodLeakSerialCommState = bloodLeakEmbModeSubstate; data.bloodLeakIntensity = getEmbModeInfoValue( I_EMB_MODE_CMD ); data.bloodLeakDetect = getEmbModeInfoValue( V_EMB_MODE_CMD ); data.bloodLeakIntensityMovingAvg = getF32OverrideValue( &bloodLeakZeroingStatus.intensityMovingAverage ); data.bloodLeakTimeSinceZeroMS = calcTimeSince( bloodLeakZeroingStatus.lastZeroingStartTimeMS ); data.driftInRangeStatus = bloodLeakZeroingStatus.driftInRangeStatus; data.driftUpperRangeStatus = bloodLeakZeroingStatus.driftUpperRangeStatus; bloodLeakDataPublicationCounter = 0; broadcastData( MSG_ID_DD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); } } /*********************************************************************//** * @brief * The getFPGABloodDetectProcessedStatus function returns the status of the * blood detect from FPGA meaning the status that is read from the sensor. * @details \b Inputs: none * @details \b Outputs: none * @return BLOOD_LEAK_NOT_DETECTED if blood has not been detected otherwise, * BLOOD_LEAK_DETECTED *************************************************************************/ static BLOOD_LEAK_STATUS_T getFPGABloodDetectProcessedStatus( void ) { // If the blood leak status bit is low (0) it means blood has not been detected, otherwise, blood has been detected return ( BLOOD_LEAK_STATUS_BIT_LOW == getFPGABloodLeakStatus() ? BLOOD_LEAK_NOT_DETECTED : BLOOD_LEAK_DETECTED ); } /*********************************************************************//** * @brief * The isDialysateLineInBypass function checks and returns whether the * dialysate line is in bypass mode or not. * @details \b Inputs: none * @details \b Outputs: none * @return TRUE if the dialysate line is in bypass otherwise, FALSE *************************************************************************/ static BOOL isDialysateLineInBypass( void ) { BOOL status = TRUE; // TODO uncomment //status &= ( VALVE_POSITION_C_CLOSE == getValvePosition( VDI ) ? TRUE : FALSE ); //status &= ( VALVE_POSITION_C_CLOSE == getValvePosition( VDO ) ? TRUE : FALSE ); return status; } /*********************************************************************//** * @brief * The processBloodLeakIntensityData function calculates the moving average * of blood leak intensity data. * @details \b Inputs: none * @details \b Outputs: bloodLeakZeroingStatus * @return none *************************************************************************/ static void processBloodLeakIntensityData( void ) { if ( ( TRUE == bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].isCmdRespRdy ) && ( bloodLeakState != BLOOD_LEAK_VERIFY_INTENSITY_AFTER_ZEROING_STATE ) ) { U32 index = bloodLeakZeroingStatus.rawIntensityNextIndex; U32 indexValue = bloodLeakZeroingStatus.rawIntensity[ index ]; U32 newIntensity = getEmbModeInfoValue( I_EMB_MODE_CMD ); bloodLeakZeroingStatus.rawIntensity[ index ] = newIntensity; bloodLeakZeroingStatus.intensityRunningSum = bloodLeakZeroingStatus.intensityRunningSum - indexValue + newIntensity; bloodLeakZeroingStatus.intensityMovingAverage.data = (F32)bloodLeakZeroingStatus.intensityRunningSum / (F32)BLD_ZERO_MVG_AVG_NUM_OF_SAMPLES; bloodLeakZeroingStatus.rawIntensityNextIndex = INC_WRAP( index, 0, BLD_ZERO_MVG_AVG_NUM_OF_SAMPLES - 1 ); resetEmbModeCmdRespConsumedFlag( I_EMB_MODE_CMD ); } } /*********************************************************************//** * @brief * The isLowerRangeIntensityDriftZeroingNeeded function checks whether blood * leak zeroing is needed in terms of drift in range drift (35-40%). * @details \b Inputs: bloodLeakZeroingStatus * @details \b Outputs: bloodLeakZeroingStatus * @return TRUE if blood leak zeroing is needed otherwise, FALSE *************************************************************************/ static BOOL isLowerRangeIntensityDriftZeroingNeeded( void ) { /* * Nominal intensity = 930 * Set point is queried from the blood leak detector * Min drift from top = 930 - (setpoint * 40%) * Max drift from top = 930 - (setpoint * 35%) * If Min drift from top ≤ moving average intensity ≤ Max drift from top then the debounce timer is set * If the debounce time has been elapsed the signal to zero the BLD is set */ BOOL status = FALSE; BOOL isZeroingNeeded = TRUE; U32 setPoint = bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandResp; F32 driftMinFromTop = BLD_NOMINAL_INTENSITY - ( setPoint * BLD_MAX_INTENSITY_OUT_OF_RANGE ); F32 driftMaxFromTop = BLD_NOMINAL_INTENSITY - ( setPoint * BLD_MIN_INTENSITY_OUT_OF_RANGE ); U32 zeroingIntervalMS = getU32OverrideValue( &bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS ); BOOL isZeroingAllowed = didTimeout( bloodLeakZeroingStatus.lastZeroingStartTimeMS, zeroingIntervalMS ); F32 intensityMvgAvg = getF32OverrideValue( &bloodLeakZeroingStatus.intensityMovingAverage ); isZeroingNeeded &= ( intensityMvgAvg >= driftMinFromTop ? TRUE : FALSE ); isZeroingNeeded &= ( intensityMvgAvg <= driftMaxFromTop ? TRUE : FALSE ); if ( FALSE == isZeroingNeeded ) { // Intensity drift is not in range so reset the debounce timer bloodLeakZeroingStatus.driftInRangeDebounceTimeMS = getMSTimerCount(); } if ( ( TRUE == isZeroingAllowed ) && ( TRUE == didTimeout( bloodLeakZeroingStatus.driftInRangeDebounceTimeMS, BLD_ZERO_IN_RANGE_DRIFT_TIMEOUT_MS ) ) ) { // If the moving average intensity is set and then the debounce time has elapsed the signal to zero is set to true. status = TRUE; } bloodLeakZeroingStatus.driftInRangeStatus = status; return status; } /*********************************************************************//** * @brief * The isUpperIntensityZeroingNeeded function checks whether blood * leak zeroing is needed in terms of drift upper range intensity (>= 950). * @details \b Inputs: bloodLeakZeroingStatus * @details \b Outputs: bloodLeakZeroingStatus * @return TRUE if blood leak zeroing is needed otherwise, FALSE *************************************************************************/ static BOOL isUpperIntensityZeroingNeeded( void ) { BOOL status = FALSE; U32 zeroingUpperIntervalMS = getU32OverrideValue( &bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS ); BOOL isZeroingAllowed = didTimeout( bloodLeakZeroingStatus.lastZeroingStartTimeMS, zeroingUpperIntervalMS ); F32 intensityMvgAvg = getF32OverrideValue( &bloodLeakZeroingStatus.intensityMovingAverage ); BOOL isUpperZeroingNeeded = ( intensityMvgAvg >= BLD_MAX_UPPER_INTENSITY_DRIFT ? TRUE : FALSE ); if ( FALSE == isUpperZeroingNeeded ) { bloodLeakZeroingStatus.driftUpperRangeDebounceTimeMS = getMSTimerCount(); } if ( ( TRUE == isZeroingAllowed ) && ( TRUE == didTimeout( bloodLeakZeroingStatus.driftUpperRangeDebounceTimeMS, BLD_ZERO_UPPER_RANGE_DRIFT_TIMEOUT_MS ) ) ) { status = TRUE; } bloodLeakZeroingStatus.driftUpperRangeStatus = status; return status; } /*********************************************************************//** * @brief * The sendBloodLeakEmbeddedModeCommandResponse function sends out * the blood leak embedded mode command response. * @details \b Inputs: none * @details \b Outputs: blood leak embedded mode command response msg constructed and queued * @details \b Message: MSG_ID_DD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE DD blood leak response command * @param cmd: the command its response is being sent * @param responseLen: the length of the buffer * @param response: pointer to the response buffer * @return TRUE if msg successfully queued for transmit, FALSE if not *************************************************************************/ static BOOL sendBloodLeakEmbeddedModeCommandResponse( U08 cmd, U32 responseLen, U08 *responseBuffer ) { BLOOD_LEAK_EMB_MODE_RESP_T response; BOOL result = FALSE; response.command = cmd; response.responseLen = responseLen; memcpy( response.responseBuffer, responseBuffer, responseLen ); result = sendMessage( MSG_ID_DD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE, COMM_BUFFER_OUT_CAN_PC, (U08*)&response, sizeof( BLOOD_LEAK_EMB_MODE_RESP_T ) ); return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testBloodLeakDataPublishIntervalOverride function overrides the * bloode leak detector data publish interval. * @details \b Inputs: none * @details \b Outputs: bloodLeakDataPublishInterval * @param message Override message from Dialin which includes the value * that overrides the blood leak data publish interval * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakDataPublishIntervalOverride( MESSAGE_T *message ) { BOOL result = u32BroadcastIntervalOverride( message, &bloodLeakDataPublishInterval, TASK_PRIORITY_INTERVAL ); return result; } /*********************************************************************//** * @brief * The testBloodLeakStatusOverride function overrides the * bloode leak detector status. * @details \b Inputs: none * @details \b Outputs: bloodLeakStatus * @param message Override message from Dialin which includes the value * that overrides the blood leak status * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakStatusOverride( MESSAGE_T *message ) { BOOL result = u32Override( message, &bloodLeakStatus, (U32)BLOOD_LEAK_DETECTED, (U32)NUM_OF_BLOOD_LEAK_STATUS ); return result; } /*********************************************************************//** * @brief * The testBloodLeakIntensityMovingAverageOverride function overrides the * blood leak intensity moving average. * @details \b Inputs: none * @details \b Outputs: bloodLeakZeroingStatus * @param message Override message from Dialin to override the blood leak * intensity moving average. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakIntensityMovingAverageOverride( MESSAGE_T *message ) { BOOL result = f32Override( message, &bloodLeakZeroingStatus.intensityMovingAverage ); return result; } /*********************************************************************//** * @brief * The testBloodLeakZeroingIntervalInMillisecondsOverride function overrides the * blood leak zeroing interval in milliseconds. * @details \b Inputs: none * @details \b Outputs: bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS, * bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS * @param message from Dialin to override the blood leak * zeroing interval. * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakZeroingIntervalInMillisecondsOverride( MESSAGE_T *message ) { BOOL result = FALSE; U08* payloadPtr = message->payload; U32 min = 0; U32 max = 100000; BOOL isUpperRangeInterval; memcpy( &isUpperRangeInterval, payloadPtr, sizeof( BOOL ) ); if ( FALSE == isUpperRangeInterval ) { result = u32Override( message, &bloodLeakZeroingStatus.zeroingDriftIntervalTimeMS, min, max ); } else { result = u32Override( message, &bloodLeakZeroingStatus.zeroingUpperRangeIntervalTimeMS, min, max ); } return result; } /*********************************************************************//** * @brief * The testBloodLeakZeroSequenceRequest function requests the blood leak * detector's zero sequence command. * @details \b Inputs: none * @details \b Outputs: none * @param message from Dialin to request zero sequence * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakZeroSequenceRequest( MESSAGE_T *message ) { BOOL result = FALSE; if ( 0 == message->hdr.payloadLen ) { result = TRUE; zeroBloodLeak(); } return result; } /**@}*/