/************************************************************************** * * Copyright (c) 2025-2025 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) Sean Nash * @date (last) 12-Sep-2025 * * @author (original) Dara Navaei * @date (original) 18-Aug-2025 * ***************************************************************************/ #include // For pow function #include // For memset and strlen #include // For sprintf #include "AlarmMgmtDD.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; /// 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; /// 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; #pragma pack(push,1) /// Blood leak embedded mode response command structure typedef struct { U08 command; ///< Blood leak command. U32 responseLen; ///< Blood leak response length. U08 responseBuffer[ BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ]; ///< Blood leak response buffer. } BLOOD_LEAK_EMB_MODE_RESP_T; #pragma pack(pop) // ********** 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 U32 bloodLeakUARTCmdIndex; ///< Blood leak UART command index. static U32 bloodLeakSetPointSeqLength; ///< Blood leak set point sequence actual length. static U08 bloodLeakSetPointSequence[ BLOOD_LEAK_SET_POINT_SEQ_MAX_LENGTH ][ 2 ]; ///< Blood leak set point sequence array. //static HD_BLOOD_LEAK_SENSOR_CAL_RECORD_T bloodLeakCalRecord; ///< Blood leak calibration record structure. // TODO uncomment 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 BOOL bloodLeakSignalEmbModeReq; ///< Blood leak signal embedded mode has been requested. static U08 bloodLeakEmbModeRqstedCmd; ///< Blood leak signal embedded mode requested command. static U08 bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH ][ 2 ]; ///< Blood leak embedded mode command sequence. static BLOOD_LEAK_EMB_MODE_STATE_T bloodLeakEmbModeSubstate; ///< Blood leak embedded mode state. static U32 bloodLeakEmbModeOpsStartTime; ///< Blood leak embedded mode operations start time. static U16 bloodLeakEmbModeSetPoint; ///< Blood leak embedded mode set point command. static EMB_MODE_CMD_T bloodLeakEmbModeCmd[ NUM_OF_EMB_CMDS ]; ///< Blood leak embedded mode commands. static U08 bloodLeakEmbModeRespBuffer[ BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ]; ///< Blood leak embedded mode response buffer. static U32 bloodLeakEmbModeRespIndex; ///< Blood leak embedded mode response buffer index. static U32 bloodLeakEmbModeCmdSeqLength; ///< Blood leak embedded mode command sequence length. static BOOL bloodLeakEmbModeHasRxRqstBeenSent; ///< Blood leak embedded mode Rx request has been sent signal. static U08 bloodLeakEmbModeCmdQ[ BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE ]; ///< Blood leak embedded mode command queue. static U08 bloodLeakEmbModeCmdQRearIndex; ///< Blood leak embedded mode command queue rear index. static U08 bloodLeakEmbModeCmdQFrontIndex; ///< Blood leak embedded mode command queue front index. static U08 bloodLeakEmbModeCmdQCount; ///< Blood leak embedded mode command queue count. static BOOL bloodLeakEmbModeHasZeroBeenRqustd; ///< Blood leak embedded mode flag to indicate zero has been requested. static U32 bloodLeakEmbModeCmdEnqueueCount; ///< Blood leak embedded mode command enqueue count. static U32 bloodLeakEmbModeInfoCmdEnqLastTimeStamp; ///< Blood leak embedded mode informative command (i.e. I, V, D) timer. static U32 bloodLeakEmbModeInfoCmdCounter; ///< Blood leak embedded mode informative command counter. static OVERRIDE_U32_T bloodLeakEmbModeIntensityOverride; ///< Blood leak embedded mode intensity override. static OVERRIDE_U32_T bloodLeakEmbModeDetectOverride; ///< Blood leak embedded mode blood detect override. // ********** 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 BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeWaitForCommandState( void ); static BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeSendCommandState( void ); static BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeWaitForCommandResponseState( void ); static void processReceivedEmbModeChar( U08 data ); static void convertString2Integer( U08 cmd, U32 respLength ); static void prepareSetPointSeq( U16 setPoint ); static void publishBloodLeakData( void ); static void initEmbModeSpecs( void ); static void enqueueEmbModeCmd( U08 cmd ); static U08 dequeueEmbModeCmd( void ); static BOOL isEmbModeCmdQueueEmpty( void ); static U32 getAvailableEmbModeQueueCount( void ); static void enqueueInfoEmbModeCmds( void ); static U16 getBloodLeakRxBytesAvailable( void ); static void resetEmbModeCmdRqstCount( U08 cmd ); static BLOOD_LEAK_STATUS_T getFPGABloodDetectProcessedStatus( void ); static BOOL isDialysateLineInBypass( void ); static void processBloodLeakIntensityData( void ); static void resetEmbModeCmdRespConsumedFlag( U08 cmd ); static U32 getEmbModeInfoValue( U08 cmd ); static BOOL isLowerRangeIntensityDriftZeroingNeeded( void ); static BOOL isUpperIntensityZeroingNeeded( void ); static BOOL sendBloodLeakEmbeddedModeCommandResponse( U08 cmd, U32 responseLen, U08 *responseBuffer ); /*********************************************************************//** * @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; bloodLeakUARTCmdIndex = 0; bloodLeakSetPointSeqLength = 0; bloodLeakPersistenceCtr = 0; bloodLeakSignalEmbModeReq = FALSE; bloodLeakEmbModeRqstedCmd = NU_EMB_MODE_CMD; bloodLeakEmbModeSubstate = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; bloodLeakEmbModeOpsStartTime = 0; bloodLeakEmbModeRespIndex = 0; bloodLeakExitNormalRequested = FALSE; bloodLeakEmbModeCmdSeqLength = 0; bloodLeakEmbModeHasRxRqstBeenSent = FALSE; bloodLeakEmbModeCmdQFrontIndex = 0; bloodLeakEmbModeCmdQRearIndex = 0; bloodLeakEmbModeCmdQCount = 0; bloodLeakEmbModeHasZeroBeenRqustd = FALSE; bloodLeakEmbModeCmdEnqueueCount = 0; bloodLeakEmbModeInfoCmdEnqLastTimeStamp = getMSTimerCount(); bloodLeakEmbModeInfoCmdCounter = 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 embedded mode response buffer memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); // Initialize the blood leak embedded mode command sequence memset( bloodLeakEmbModeCmdSeq, 0x0, BLOOD_LEAK_EMB_MODE_CMD_SEQ_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; // Enqueue the commands to set the embedded mode and request the set point of the blood leak sensor enqueueEmbModeCmd( CS_EMB_MODE_CMD ); enqueueEmbModeCmd( D_EMB_MODE_CMD ); } /*********************************************************************//** * @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; } enqueueInfoEmbModeCmds(); // Publish blood leak data if due publishBloodLeakData(); } /*********************************************************************//** * @brief * The execBloodLeakEmbModeCommand function executes the blood leak embedded * mode command. * @details \b Inputs: bloodLeakEmbModeSubstate * @details \b Outputs: bloodLeakEmbModeSubstate * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT when in an unknown state * @return none *************************************************************************/ void execBloodLeakEmbModeCommand( void ) { switch ( bloodLeakEmbModeSubstate ) { case BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE: bloodLeakEmbModeSubstate = handleBloodLeakEmbModeWaitForCommandState(); break; case BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE: bloodLeakEmbModeSubstate = handleBloodLeakEmbModeSendCommandState(); break; case BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMMAND_RESPONSE_STATE: bloodLeakEmbModeSubstate = handleBloodLeakEmbModeWaitForCommandResponseState(); break; default: SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_EMBEDDED_MODE_INVALID_STATE ) bloodLeakEmbModeSubstate = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; break; } } /*********************************************************************//** * @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_MODE_SUB_MODE_T tdModes; getTDOperationMode( &tdModes ); if ( MODE_PRET == tdModes.tdMode ) { 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, tdModes.tdMode ) status = TRUE; } } else if ( MODE_TREA == tdModes.tdMode ) { 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; TD_MODE_SUB_MODE_T tdModes; getTDOperationMode( &tdModes ); bloodLeakStatus.data = getFPGABloodDetectProcessedStatus(); switch ( tdModes.tdMode ) { 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 handleBloodLeakEmbModeWaitForCommandState function handles the wait for * command state. The state prepares the message to be sent to the blood leak * sensor. * @details \b Inputs: bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeCmd * @details \b Outputs: bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeCmdSeq, * bloodLeakUARTCmdIndex, bloodLeakEmbModeRespIndex, bloodLeakEmbModeCmdSeqLength, * bloodLeakEmbModeOpsStartTime, bloodLeakEmbModeSetPoint, bloodLeakEmbModeRespBuffer * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if incorrect blood leak command has * been selected * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeWaitForCommandState( void ) { BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; if ( FALSE == isEmbModeCmdQueueEmpty() ) { U08 commandASCII = 0; bloodLeakEmbModeRqstedCmd = dequeueEmbModeCmd(); commandASCII = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].commandASCII; switch( bloodLeakEmbModeRqstedCmd ) { case NU_EMB_MODE_CMD: // Null command do nothing break; case CS_EMB_MODE_CMD: case T_EMB_MODE_CMD: case G_EMB_MODE_CMD: case I_EMB_MODE_CMD: case V_EMB_MODE_CMD: case Z_EMB_MODE_CMD: case Q_EMB_MODE_CMD: case D_EMB_MODE_CMD: case C_EMB_MODE_CMD: // First clear the buffer from the older data memset( bloodLeakEmbModeCmdSeq, 0x0, 2 * BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH ); // Set the command sequence bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_RESET_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_RESET; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_RESET_INDEX ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_RESET_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_RESET_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_CMD_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = commandASCII; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_CMD_INDEX ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_STOP_WRITE_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_STOP_WRITE_INDEX ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_HIGH; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_ACTIVE_HIGH_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; // Set the variables for the next state bloodLeakUARTCmdIndex = 0; bloodLeakEmbModeRespIndex = 0; bloodLeakEmbModeCmdSeqLength = BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH; bloodLeakEmbModeOpsStartTime = getMSTimerCount(); state = BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE; // Clear the response buffer to able to receive fresh data memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); break; case SP_EMB_MODE_CMD: prepareSetPointSeq( bloodLeakEmbModeSetPoint ); bloodLeakEmbModeRespIndex = 0; bloodLeakEmbModeOpsStartTime = getMSTimerCount(); state = BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE; // Clear the command sequence buffer in case it is needed to send byte read request. The byte // read requests are sent using this buffer while the set point is set using the set point buffer memset( bloodLeakEmbModeCmdSeq, 0x0, 2 * BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH ); // Clear the response buffer to able to receive fresh data memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_INVALID_EMB_MODE_CMD_SELECTED, bloodLeakEmbModeRqstedCmd ) break; } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakEmbModeSendCommandState function handles the send command * state. The state sends the command sequence to the blood leak sensor one by one. * @details \b Inputs: bloodLeakEmbModeRqstedCmd, bloodLeakCalCharacter, bloodLeakUARTCmdIndex * bloodLeakEmbModeCmdSeqLength * @details \b Outputs: bloodLeakEmbModeRqstedCmd, bloodLeakCalCommandSquence, * bloodLeakUARTCmdIndex, bloodLeakEmbModeCmdSeqLength, bloodLeakEmbModeCmdSeqLength, * bloodLeakSetPointSequence * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if incorrect blood leak command has * been selected * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeSendCommandState( void ) { U08 command; BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE; BOOL isUARTCtrlCmd = FALSE; BOOL isUARTCtrlDone = TRUE; switch ( bloodLeakEmbModeRqstedCmd ) { case CS_EMB_MODE_CMD: case T_EMB_MODE_CMD: case G_EMB_MODE_CMD: case I_EMB_MODE_CMD: case V_EMB_MODE_CMD: case Z_EMB_MODE_CMD: case Q_EMB_MODE_CMD: case D_EMB_MODE_CMD: case C_EMB_MODE_CMD: command = bloodLeakEmbModeCmdSeq[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ]; isUARTCtrlCmd = bloodLeakEmbModeCmdSeq[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ]; isUARTCtrlDone = ( bloodLeakUARTCmdIndex > ( bloodLeakEmbModeCmdSeqLength - 1 ) ? TRUE : FALSE ); bloodLeakUARTCmdIndex++; break; case SP_EMB_MODE_CMD: // Check if the first element in the command sequence buffer is the read request. If it is, the set point command sequence has already been sent // and we are requesting the buffer to read and get its response back so use this buffer to send data to the sensor // Otherwise, send the set point command sequence to the sensor since the set point is sent prior to reading the response back from the sensor if ( BLOOD_LEAK_EMB_MODE_COMM_READ_REQST == bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] ) { command = bloodLeakEmbModeCmdSeq[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ]; isUARTCtrlCmd = bloodLeakEmbModeCmdSeq[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ]; isUARTCtrlDone = ( bloodLeakUARTCmdIndex > ( bloodLeakEmbModeCmdSeqLength - 1 ) ? TRUE : FALSE ); } else { command = bloodLeakSetPointSequence[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ]; isUARTCtrlCmd = bloodLeakSetPointSequence[ bloodLeakUARTCmdIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ]; isUARTCtrlDone = ( bloodLeakUARTCmdIndex > ( bloodLeakSetPointSeqLength - 1 ) ? TRUE : FALSE ); } bloodLeakUARTCmdIndex++; break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_INVALID_EMB_MODE_CMD_SELECTED, bloodLeakEmbModeRqstedCmd ) break; } if ( ( bloodLeakEmbModeRqstedCmd != CS_EMB_MODE_CMD ) && ( bloodLeakUARTCmdIndex - 1 > BLOOD_LEAK_EMB_MODE_RESET_INDEX ) && ( bloodLeakUARTCmdIndex - 1 <= BLOOD_LEAK_EMB_MODE_RESET_INDEX + 1 ) ) { if ( 0 == getBloodLeakRxBytesAvailable() ) { // TODO do nothing right now. I case it was decided to use the terminal mode again, make sure the reset went through prior to sending the // reset of the command sequence } } // Check if the current index towards the end of the buffer which are FIFO set and FIFO reset if ( FALSE == isUARTCtrlDone ) { if ( FALSE == isUARTCtrlCmd ) { setFPGABloodLeakUARTTransmit( command ); } else { setFPGABloodLeakUARTControl( command ); } } else { // If the element in the first index of the command sequence buffer is the read a byte request, set the variable to TRUE so the // wait for data to receive state knows that the request has been sent and it can read the byte. U08 commandInIndex0 = bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ]; bloodLeakEmbModeHasRxRqstBeenSent = ( BLOOD_LEAK_EMB_MODE_COMM_READ_REQST == commandInIndex0 ? TRUE : FALSE ); bloodLeakUARTCmdIndex = 0; bloodLeakEmbModeCmdSeqLength = 0; state = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMMAND_RESPONSE_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakEmbModeWaitForCommandResponseState function handles the * wait for command responses state. The state receives data in the buffer. * @details \b Inputs: bloodLeakEmbModeHasRxRqstBeenSent, bloodLeakEmbModeRespBuffer, * bloodLeakEmbModeRespIndex, bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeOpsStartTime * @details \b Outputs: bloodLeakEmbModeCmd, bloodLeakEmbModeRqstedCmd, * bloodLeakEmbModeCmdSeq, bloodLeakEmbModeRespBuffer * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleBloodLeakEmbModeWaitForCommandResponseState( void ) { BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMMAND_RESPONSE_STATE; U16 rxFIFOCount = getBloodLeakRxBytesAvailable(); BOOL hasCharBeenReceived = FALSE; U32 commandTimeoutMS = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].timeoutMS; U32 length = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].length; if ( TRUE == bloodLeakEmbModeHasRxRqstBeenSent ) { // If the read request sequence has been sent already, read the next byte in the buffer and process it U08 data = getFPGABloodLeakRxFIFODataOut(); hasCharBeenReceived = TRUE; bloodLeakEmbModeHasRxRqstBeenSent = FALSE; processReceivedEmbModeChar( data ); } else if ( ( rxFIFOCount > 0 ) && ( FALSE == bloodLeakEmbModeHasRxRqstBeenSent ) ) { // If there is still more data in the buffer and a read sequence has not been sent, create the sequence and send it // First clear the buffer from the older data. Set to 2 times the length because the array is 2D memset( bloodLeakEmbModeCmdSeq, 0x0, 2 * BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH ); bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_READ_REQST; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW; bloodLeakEmbModeCmdSeq[ BLOOD_LEAK_EMB_MODE_REQUEST_RX_INDEX + 1 ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; // Set the variables for the next state bloodLeakUARTCmdIndex = 0; bloodLeakEmbModeCmdSeqLength = BLOOD_LEAK_EMB_MODE_RQST_RX_LENGTH; state = BLOOD_LEAK_EMB_MODE_SEND_COMMAND_STATE; } // If wait for the receive FIFO has timed out or all there is no buffer left in the Rx FIFO transition back to wait for command state for the next command if ( ( TRUE == hasCharBeenReceived ) && ( bloodLeakEmbModeRespIndex >= length ) ) { U08 i; BOOL isNull = FALSE; for ( i = 0; i < length; i++ ) { // Loop through the elements of the buffer and make sure none of the elements are not NULL. // The elements are checked until the specified length that is expected for a command isNull |= ( bloodLeakEmbModeRespBuffer[ i ] != NU_EMB_MODE_CMD ? FALSE : TRUE ); } // Check if the failed command is Control S which is switch to embedded mode and if // it failed set the embedded mode request to false so the other commands cannot be sent again bloodLeakSignalEmbModeReq = ( ( CS_EMB_MODE_CMD == bloodLeakEmbModeRqstedCmd ) && ( NU_EMB_MODE_CMD == bloodLeakEmbModeRespBuffer[ 0 ] ) ? FALSE : TRUE ); if ( TRUE == isNull ) { // There is null in the characters that were supposed to be received and not be null but null was found // Clear the response buffer and write the ASCII fail in the first element of the response buffer // Set the length to be 1 because there is only 1 character (fail) is in the buffer memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); length = 1; bloodLeakEmbModeRespBuffer[ 0 ] = BLOOD_LEAK_EMB_MODE_FAIL_ASCII; } else if ( CS_EMB_MODE_CMD == bloodLeakEmbModeRqstedCmd ) { memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); length = 1; bloodLeakEmbModeRespBuffer[ 0 ] = BLOOD_LEAK_EMB_MODE_PASS_ASCII; } else if ( 1 == length ) { U08 passChar = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].expChar1; U08 data = bloodLeakEmbModeRespBuffer[ 0 ]; bloodLeakEmbModeRespBuffer[ 0 ] = ( passChar == data ? BLOOD_LEAK_EMB_MODE_PASS_ASCII : BLOOD_LEAK_EMB_MODE_FAIL_ASCII ); } convertString2Integer( bloodLeakEmbModeRqstedCmd, length ); sendBloodLeakEmbeddedModeCommandResponse( bloodLeakEmbModeRqstedCmd, length, bloodLeakEmbModeRespBuffer ); // Done with receiving the data bloodLeakEmbModeRqstedCmd = NU_EMB_MODE_CMD; state = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; } if ( TRUE == didTimeout( bloodLeakEmbModeOpsStartTime, commandTimeoutMS ) ) { // Command timed out. Clear the receive buffer from any data and put a Fail in there to be sent up memset( bloodLeakEmbModeRespBuffer, 0x0, BLOOD_LEAK_EMB_MODE_RESP_BUFFER_LEN ); // Only F (fail) will be sent so the length of the buffer is 1 length = 1; bloodLeakEmbModeRespBuffer[ 0 ] = BLOOD_LEAK_EMB_MODE_FAIL_ASCII; convertString2Integer( bloodLeakEmbModeRqstedCmd, length ); sendBloodLeakEmbeddedModeCommandResponse( bloodLeakEmbModeRqstedCmd, length, bloodLeakEmbModeRespBuffer ); bloodLeakEmbModeRqstedCmd = NU_EMB_MODE_CMD; state = BLOOD_LEAK_EMB_MODE_WAIT_FOR_COMAND_STATE; } return state; } /*********************************************************************//** * @brief * The processReceivedEmbModeChar function processes the character that * has been received. * @details \b Inputs: bloodLeakEmbModeCmd, bloodLeakEmbModeRespIndex * @details \b Outputs: bloodLeakEmbModeRespBuffer, bloodLeakEmbModeRespIndex * @param data which is the data that has been received from the BLD * @return none *************************************************************************/ static void processReceivedEmbModeChar( U08 data ) { /* * There are 3 types of data that can be received from the the sensor: * 1. It could be a start character and the length (i.e. VXXXX) * 2. It could be two discrete characters (i.e. P, F) * 3. It could be none of the two characters (i.e. XXXX) */ U08 length = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].length; U08 expChar1 = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].expChar1; U08 expChar2 = bloodLeakEmbModeCmd[ bloodLeakEmbModeRqstedCmd ].expChar2; if ( expChar1 != NU_EMB_MODE_CMD ) { // This is the case that there is a start character. If current character buffer index is less than the // length of the expected response of the command. if ( bloodLeakEmbModeRespIndex < length ) { if ( NU_EMB_MODE_CMD == expChar2 ) { // Check if the expected char is received and the response buffer is empty because the index is 0, // insert the buffer data if ( ( expChar1 == data ) && ( 0 == bloodLeakEmbModeRespIndex ) ) { bloodLeakEmbModeRespBuffer[ bloodLeakEmbModeRespIndex ] = data; bloodLeakEmbModeRespIndex++; } // Check if the buffer index is cd ve> 0 so the first char has been inserted and the rest is data but it is not the echo of the command // For instance, V has been inserted and XXXX is inserted that is followed by V. So V123 and not VVV12. else if ( ( bloodLeakEmbModeRespIndex > 0 ) && ( data != expChar1 ) ) { bloodLeakEmbModeRespBuffer[ bloodLeakEmbModeRespIndex ] = data; bloodLeakEmbModeRespIndex++; } } else { // Check if either of the expected chars are received and if they are insert it into the response buffer if ( ( expChar1 == data ) || ( expChar2 == data ) ) { bloodLeakEmbModeRespBuffer[ bloodLeakEmbModeRespIndex ] = data; bloodLeakEmbModeRespIndex++; } } } } else { // This is the case that there are no expected characters and the received value are numbers if ( bloodLeakEmbModeRespIndex < length ) { // If the received character is in the range of numbers chars (0 to 9), then insert them into the response buffer if ( ( data >= BLOOD_LEAK_EMB_MODE_0_NUM_ASCII ) && ( data <= BLOOD_LEAK_EMB_MODE_9_NUM_ASCII ) ) { bloodLeakEmbModeRespBuffer[ bloodLeakEmbModeRespIndex ] = data; bloodLeakEmbModeRespIndex++; } } } } /*********************************************************************//** * @brief * The convertString2Integer function converts the buffer of the answers in * string (ASCII) to integer. * @details \b Inputs: bloodLeakEmbModeCmd * @details \b Outputs: bloodLeakEmbModeRespBuffer, bloodLeakEmbModeCmd * @param cmd which is the embedded mode command * @param respLength the length of the received response from the sensor * @return none *************************************************************************/ static void convertString2Integer( U08 cmd, U32 respLength ) { if ( 1 == respLength ) { bloodLeakEmbModeCmd[ cmd ].commandResp = bloodLeakEmbModeRespBuffer[ 0 ]; } else { U08 i; U32 bufferValue; U32 respExpectedLength = bloodLeakEmbModeCmd[ cmd ].length; // Reset the command response bloodLeakEmbModeCmd[ cmd ].commandResp = 0; for ( i = 0; i < respExpectedLength; i++ ) { // The last value is inserted into the response buffer (i.e. S030) // So the buffer array is used from the last element of the array bufferValue = bloodLeakEmbModeRespBuffer[ respExpectedLength - 1 - i ]; if ( ( bufferValue >= BLOOD_LEAK_EMB_MODE_0_NUM_ASCII ) && ( bufferValue <= BLOOD_LEAK_EMB_MODE_9_NUM_ASCII ) ) { // If the value in the response buffer is within the ASCII values of 0 (ASCII 48) to 9 (ASCII 57) then it is a number and needs to be converted to integer // Subtract the buffer value from ASCII 48 to get the offset (i.e. buffer = 50 - 48 = 2) // Add the offset value to the command response in the right order (i.e. if i = 1, then it is 2 x 10 ^1 = 20) bufferValue -= BLOOD_LEAK_EMB_MODE_0_NUM_ASCII; bloodLeakEmbModeCmd[ cmd ].commandResp += ( bufferValue * pow( 10, i ) ); } } } // Set the command response ready bloodLeakEmbModeCmd[ cmd ].isCmdRespRdy = TRUE; } /*********************************************************************//** * @brief * The prepareSetPointSeq function prepares the set point sequence to be * written to the blood leak sensor. * @details \b Inputs: none * @details \b Outputs: bloodLeakSetPointSequence, bloodLeakSetPointSeqLength * @param setPoint the set point that has to be prepared to be sent to the sensor * @return none *************************************************************************/ static void prepareSetPointSeq( U16 setPoint ) { U08 i; U32 digitCount; char tempCharBuffer[ BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH ]; U08 command; U32 bufferIndex = BLOOD_LEAK_SET_POINT_START_CHAR_INDEX; memset( tempCharBuffer, 0x0, BLOOD_LEAK_SET_POINT_MAX_CHAR_LENGTH ); // Convert the set point number to the equivalent ASCII number with the unsigned integer data type sprintf( tempCharBuffer, "%u", (U32)setPoint ); // Calculate the length of the character buffer. strlen does not count the null character. digitCount = strlen( tempCharBuffer ); command = ( TRUE == bloodLeakSignalEmbModeReq ? BLOOD_LEAK_EMB_MODE_COMM_RESET : BLOOD_LEAK_RESET_TX_FIFO ); bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = command; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bufferIndex++; command = ( TRUE == bloodLeakSignalEmbModeReq ? BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW : BLOOD_LEAK_UART_COMM_ACTIVE_LOW ); bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = command; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bufferIndex++; // Set the first item to the ASCII character of S. The format to set the set point is // SXXXCR10. It starts with S followed by the characters up to 3 digits, carriage return and a 1 and a 0 to write to the buffer. bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_SET_POINT_START_CHAR_ASCII; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bufferIndex++; // Loop through the number of digits and get each ASCII value for ( i = 0; i < digitCount; i++ ) { // Write the characters bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = tempCharBuffer[ i ]; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bufferIndex++; } // After the characters, insert the carriage return into the buffer bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_CARRIAGE_RETURN_ASCII; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bufferIndex++; // After the characters, insert the stop write to FIFO character which is number 0 bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = FALSE; bufferIndex++; // Set active high into the buffer. // If the mode is embedded mode, the active high (and active low) values are different than in the Ctrl U mode since the bit values are different command = ( TRUE == bloodLeakSignalEmbModeReq ? BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_HIGH : BLOOD_LEAK_UART_COMM_ACTIVE_HIGH ); bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = command; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; bufferIndex++; command = ( TRUE == bloodLeakSignalEmbModeReq ? BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW : BLOOD_LEAK_UART_COMM_ACTIVE_LOW ); bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_CMD_COL_INDEX ] = command; bloodLeakSetPointSequence[ bufferIndex ][ BLOOD_LEAK_EMB_MODE_IS_UART_COL_INDEX ] = TRUE; // Update the sequence length for writing to the sensor bloodLeakSetPointSeqLength = bufferIndex + 1; bloodLeakUARTCmdIndex = 0; } /*********************************************************************//** * @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 initEmbModeSpecs function initializes the embedded mode specifications * structure. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeCmd * @return none *************************************************************************/ static void initEmbModeSpecs( void ) { // Null command bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].commandASCII = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].expChar1 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].length = 0; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].timeoutMS = 0; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ NU_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Control S command bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandASCII = 19; // ASCII for Control S bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].expChar1 = 69; // ASCII for E (Embedded ...) bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ CS_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Set point command bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].commandASCII = 83; // ASCII for S bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].expChar1 = 32; // For space (Set point is returned by a space at the beginning of returning the set point value) bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].timeoutMS = 10 * MS_PER_SECOND; bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ SP_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Self test command bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].commandASCII = 84; // ASCII for T bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].expChar1 = 80; // ASCII for P bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].expChar2 = 70; // ASCII for F bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].length = 1; bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ T_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Get self test command bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].commandASCII = 71; // ASCII for G bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].expChar1 = 71; bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].timeoutMS = 10 * MS_PER_SECOND; bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ G_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Intensity command bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].commandASCII = 73; // ASCII for I bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].expChar1 = 73; bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ I_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Blood detection command bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].commandASCII = 86; // ASCII for V bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].expChar1 = 86; bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ V_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Zero sensor command bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].commandASCII = 90; // ASCII for Z bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].expChar1 = 89; // ASCII for Y bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].length = 1; bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].timeoutMS = 10 * MS_PER_SECOND; bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ Z_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Zero confirm command bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].commandASCII = 81; // ASCII for Q bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].expChar1 = 80; // ASCII for P bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].expChar2 = 70; // ASCII for F bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].length = 1; bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ Q_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Display blood detection command bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandASCII = 68; bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].expChar1 = 68; // ASCII for D bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].length = 5; bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].isCmdRespRdy = FALSE; // Calibrate command bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].commandASCII = 67; bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].expChar1 = 67; // ASCII for C bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].expChar2 = NU_EMB_MODE_CMD; bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].length = 4; bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].timeoutMS = 5 * MS_PER_SECOND; bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].commandResp = 0; bloodLeakEmbModeCmd[ C_EMB_MODE_CMD ].isCmdRespRdy = FALSE; } /*********************************************************************//** * @brief * The enqueueEmbModeCmd function enqueues an embedded mode command. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeCmdQRearIndex, bloodLeakEmbModeCmdQCount * bloodLeakEmbModeCmdQ, bloodLeakEmbModeCmd * @param cmd the command to enqueue * @return none *************************************************************************/ static void enqueueEmbModeCmd( U08 cmd ) { // Enqueue the command and increment the rear embedded mode index // Set the command response to be false so the command was just queued to be read bloodLeakEmbModeCmdQ[ bloodLeakEmbModeCmdQRearIndex ] = cmd; bloodLeakEmbModeCmdQRearIndex = INC_WRAP( bloodLeakEmbModeCmdQRearIndex, 0, BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE - 1 ); bloodLeakEmbModeCmd[ cmd ].isCmdRespRdy = FALSE; bloodLeakEmbModeCmd[ cmd ].commandRqstCount++; bloodLeakEmbModeCmdQCount++; } /*********************************************************************//** * @brief * The resetEmbModeCmdRqstCount function resets embedded mode command request * count. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeCmd * @param cmd the command to reset its request count * @return none *************************************************************************/ static void resetEmbModeCmdRqstCount( U08 cmd ) { bloodLeakEmbModeCmd[ cmd ].commandRqstCount = 0; } /*********************************************************************//** * @brief * The dequeueEmbModeCmd function dequeues the embedded mode command. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeCmdQFrontIndex, bloodLeakEmbModeCmdQCount * @return command that is dequeued *************************************************************************/ static U08 dequeueEmbModeCmd( void ) { U08 command = 0; U08 tempIndex; _disable_IRQ(); tempIndex = bloodLeakEmbModeCmdQFrontIndex; if ( FALSE == isEmbModeCmdQueueEmpty() ) { bloodLeakEmbModeCmdQFrontIndex = INC_WRAP( bloodLeakEmbModeCmdQFrontIndex, 0, BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE - 1 ); command = bloodLeakEmbModeCmdQ[ tempIndex ]; bloodLeakEmbModeCmdQCount--; } _enable_IRQ(); return command; } /*********************************************************************//** * @brief * The isEmbModeCmdQueueEmpty function checks whether the embedded mode command * queue is empty or not. * @details \b Inputs: bloodLeakEmbModeCmdQCount * @details \b Outputs: none * @return TRUE if the queue is empty otherwise, FALSE *************************************************************************/ static BOOL isEmbModeCmdQueueEmpty( void ) { BOOL isEmpty = TRUE; if ( bloodLeakEmbModeCmdQCount > 0 ) { isEmpty = FALSE; } return isEmpty; } /*********************************************************************//** * @brief * The getAvailableEmbModeQueueCount function returns the available embedded * mode queue count. * @details \b ts: bloodLeakEmbModeCmdQCount * @details \b Outputs: none * @return Current available embedded mode queue count *************************************************************************/ static U32 getAvailableEmbModeQueueCount( void ) { return BLOOD_LEAK_EMB_MODE_CMD_Q_MAX_SIZE - bloodLeakEmbModeCmdQCount; } /*********************************************************************//** * @brief * The enqueueInfoEmbModeCmds function enqueues the informative embedded * mode commands. * @details \b Inputs: bloodLeakEmbModeInfoCmdEnqueueLastTimeStamp, bloodLeakState, * bloodLeakEmbModeInfoCmdCounter * @details \b Outputs: bloodLeakEmbModeInfoCmdEnqueueLastTimeStamp, bloodLeakState, * bloodLeakEmbModeInfoCmdCounter * @return none *************************************************************************/ static void enqueueInfoEmbModeCmds( void ) { if ( TRUE == didTimeout( bloodLeakEmbModeInfoCmdEnqLastTimeStamp, BLOOD_LEAK_EMB_MODE_INFO_CMD_TIMEOUT_MS ) ) { switch ( bloodLeakState ) { case BLOOD_LEAK_INIT_STATE: case BLOOD_LEAK_NORMAL_STATE: case BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE: // Enqueue the next command. Make sure the blood leak state is greater than init state and it is not the zero and self test state // to make sure setting the embedded mode and getting the set point and zero sequence should go undisturbed. if ( 0 == bloodLeakEmbModeInfoCmdCounter ) { enqueueEmbModeCmd( I_EMB_MODE_CMD ); } else if ( 1 == bloodLeakEmbModeInfoCmdCounter ) { enqueueEmbModeCmd( V_EMB_MODE_CMD ); } // Set the timer for the next time out to enqueue // Reset the counter. The counter starts from 0 bloodLeakEmbModeInfoCmdEnqLastTimeStamp = getMSTimerCount(); bloodLeakEmbModeInfoCmdCounter = INC_WRAP( bloodLeakEmbModeInfoCmdCounter, 0, BLOOD_LEAK_EMB_MODE_NUM_OF_INFO_CMDS - 1 ); break; default: // Do nothing as the other commands are ignored break; } } } /*********************************************************************//** * @brief * The getBloodLeakRxBytesAvailable function returns the number of received * bytes available from FPGA. * @details \b Inputs: none * @details \b Outputs: none * @return Number of received bytes available *************************************************************************/ static U16 getBloodLeakRxBytesAvailable( void ) { return getFPGABloodLeakRxFIFOCount() & BLOOD_LEAK_RXFIFO_COUNT_MASK; } /*********************************************************************//** * @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 resetEmbModeCmdRespConsumedFlag function sets the cmd response ready flag * to false its flag that fresh data is ready. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeCmd * @param cmd the command to signal its data has been consumed * @return none *************************************************************************/ static void resetEmbModeCmdRespConsumedFlag( U08 cmd ) { bloodLeakEmbModeCmd[ cmd ].isCmdRespRdy = FALSE; } /*********************************************************************//** * @brief * The getEmbModeInfoValue function gets the data of the embedded info cmds. * This is only for the info values (I, V). * @details \b Inputs: bloodLeakEmbModeIntensityOverride, * bloodLeakEmbModeDetectOverride * @details \b Outputs: bloodLeakEmbModeCmd * @param cmd the command to get the read data * @return the value of the read command *************************************************************************/ static U32 getEmbModeInfoValue( U08 cmd ) { U32 value = bloodLeakEmbModeCmd[ cmd ].commandResp; switch( cmd ) { case I_EMB_MODE_CMD: if ( OVERRIDE_KEY == bloodLeakEmbModeIntensityOverride.override ) { value = bloodLeakEmbModeIntensityOverride.ovData; } break; case V_EMB_MODE_CMD: if ( OVERRIDE_KEY == bloodLeakEmbModeDetectOverride.override ) { value = bloodLeakEmbModeDetectOverride.ovData; } break; default: // Do nothing with the rest of the commands break; } return value; } /*********************************************************************//** * @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_DD_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 testSetBloodLeak2EmbeddedMode function sets the blood leak driver to the * embedded more for calibration. * @details \b Inputs: none * @details \b Outputs: bloodLeakSignalEmbeddedModeReq * @param message Override message from Dialin * @return TRUE if switching to embedded mode was accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeak2EmbeddedMode( MESSAGE_T *message ) { BOOL result = FALSE; TD_MODE_SUB_MODE_T tdModes; getTDOperationMode( &tdModes ); // Check if the mode is fault, service or standby before accepting a transition to // the embedded mode if ( ( MODE_FAUL == tdModes.tdMode ) || ( MODE_SERV == tdModes.tdMode ) || ( MODE_STAN == tdModes.tdMode ) ) { bloodLeakSignalEmbModeReq = TRUE; bloodLeakEmbModeRqstedCmd = CS_EMB_MODE_CMD; result = TRUE; } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakEmbeddedModeCommand function sets the blood leak * calibration command. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeSetPoint * @param message Override message from Dialin to set the command and the * setpoint payload value * @return TRUE if the command is accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeakEmbeddedModeCommand( MESSAGE_T *message ) { BOOL result = FALSE; U08* payloadPtr = message->payload; U08 command; U16 setPointPayload; memcpy( &command, payloadPtr, sizeof( U08 ) ); payloadPtr += sizeof( U08 ); memcpy( &setPointPayload, payloadPtr, sizeof( U16 ) ); if ( command < NUM_OF_EMB_CMDS ) { enqueueEmbModeCmd( command ); bloodLeakEmbModeSetPoint = setPointPayload; result = TRUE; } return result; } /*********************************************************************//** * @brief * The testBloodLeakEmbeddedModeInfoOverride function overrides the * blood leak embedded mode info values. * @details \b Inputs: none * @details \b Outputs: bloodLeakEmbModeIntensityOverride, * bloodLeakEmbModeDetectOverride * @param message Override message from Dialin to set the command and the * embedded mode info values * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testBloodLeakEmbeddedModeInfoOverride( MESSAGE_T *message ) { BOOL result = FALSE; U08* payloadPtr = message->payload; U08 command; memcpy( &command, payloadPtr, sizeof( U08 ) ); if ( command < NUM_OF_EMB_CMDS ) { U32 min = 0; U32 max = 100000; switch( command ) { case I_EMB_MODE_CMD: result = u32Override( message, &bloodLeakEmbModeIntensityOverride, min, max ); break; case V_EMB_MODE_CMD: result = u32Override( message, &bloodLeakEmbModeDetectOverride, min, max ); break; default: // Do nothing with the rest of the commands. They cannot be overridden. break; } } 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; } /**@}*/