/************************************************************************** * * Copyright (c) 2021-2023 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) 16-Aug-2023 * * @author (original) Peman Montazemi * @date (original) 18-Mar-2021 * ***************************************************************************/ #include // For pow function #include // For memset and strlen #include // For sprintf #include "AlarmMgmt.h" #include "BloodLeak.h" #include "FPGA.h" #include "NVDataMgmtHDRecords.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "Switches.h" #include "SystemCommMessages.h" #include "TaskPriority.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_TIMOUE_MS ( 2 * MS_PER_SECOND ) ///< Blood leak embedded mode informative command timeout in milliseconds. #define BLOOD_LEAK_EMB_MODE_NUM_OF_INFO_CMDS 3 ///< 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 /// Defined states for the blood leak detector state machine. typedef enum BloodLeakStates { BLOOD_LEAK_WAIT_FOR_POST_STATE = 0, ///< Wait for post state. BLOOD_LEAK_CHECK_SET_POINT_STATE, ///< Check set point state. BLOOD_LEAK_INIT_STATE, ///< Init state. BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_STATE, ///< Blood leak check for zero and self test commands state. BLOOD_LEAK_NORMAL_STATE, ///< 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; 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; // ********** 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. static BOOL bloodLeakExitNormalRequested; ///< Blood leak exit normal state requested. static U32 bloodLeakRecoveryStartTimeMS; ///< Blood leak recovery start time in milliseconds. // 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. // ********** 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 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 ); /*********************************************************************//** * @brief * The initBloodLeak function initializes the Blood Leak module. * @details Inputs: none * @details Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence * bloodLeakDataPublicationTimerCounter, bloodLeakEmbModeHasZeroBeenRqustd * bloodLeakEmbModeSubstate, bloodLeakEmbModeCmdEnqueueCount * bloodLeakPersistenceCtr, bloodLeakSignalEmbModeReq, * bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeOpsStartTime, * bloodLeakEmbModeRespBuffer, bloodLeakEmbModeRespIndex, * bloodLeakExitNormalRequested, bloodLeakEmbModeCmdSeqLength, * bloodLeakEmbModeHasRxRqstBeenSent, bloodLeakEmbModeInfoCmdEnqLastTimeStamp, * bloodLeakEmbModeInfoCmdCounter, bloodLeakRecoveryStartTimeMS, * @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 ); // 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 Inputs: bloodLeakState * @details Outputs: bloodLeakCalRecord, bloodLeakState * @return none *************************************************************************/ void execBloodLeak( void ) { if ( TRUE == isNewCalibrationRecordAvailable() ) { 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 ); } 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_NORMAL_STATE: bloodLeakState = handleBloodLeakNormalState(); break; case BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE: bloodLeakState = handleBloodLeakRecoverBloodDetectState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_HD_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 Inputs: bloodLeakEmbModeSubstate * @details Outputs: bloodLeakEmbModeSubstate * @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_HD_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 Inputs: bloodLeakEmbModeCmdEnqueueCount * @details Outputs: bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakEmbModeCmdEnqueueCount, bloodLeakSelfTestStatus * @return TRUE if the zero commands were successfully queued otherwise, FALSE *************************************************************************/ BOOL zeroBloodLeak( void ) { BOOL status = TRUE; 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 ); } else if ( ++bloodLeakEmbModeCmdEnqueueCount > BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_LEAK_ENQUEUE_FAILURE ) } return status; } /*********************************************************************//** * @brief * The hasBloodLeakZeroSequenceFailed function returns TURE if the number * of times the zero sequence has failed. * @details Inputs: bloodLeakEmbModeCmd * @details 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 exitBloodLeakNormalState requests that the blood leak sensor to exit * its normal state. * @details Inputs: bloodLeakState * @details 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 Inputs: none * @details Outputs: none * @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_HD_BLOOD_LEAK_INVALID_CAL_RECORD; BOOL calStatus = getNVRecord2Driver( GET_CAL_BLOOD_LEAK_SENSOR, (U08*)&bloodLeakCalRecord, length, 0, alarm ); 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 Inputs: bloodLeakEmbModeCmd * @details Outputs: bloodLeakEmbModeCmd * @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 { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_HD_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 Inputs: bloodLeakCalRecord * @details Outputs: bloodLeakCalRecord * @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; if ( ( bloodLeakSetPoint != bloodLeakCalRecord.setPoint ) && ( TRUE == isCommandRespReady ) ) { if ( bloodLeakEmbModeCmd[ D_EMB_MODE_CMD ].commandRqstCount < BLOOD_LEAK_EMB_MODE_MAX_NUM_CMD_TRIES ) { enqueueEmbModeCmd( D_EMB_MODE_CMD ); } else { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_HD_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 Inputs: bloodLeakEmbModeHasZeroBeenRqustd * @details 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 Inputs: bloodLeakEmbModeCmd * @details 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 zero sequence, transition to other states resetEmbModeCmdRqstCount( Z_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( G_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( Q_EMB_MODE_CMD ); resetEmbModeCmdRqstCount( T_EMB_MODE_CMD ); bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; state = BLOOD_LEAK_NORMAL_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( HD_EVENT_BLOOD_LEAK_SELF_TEST_RESULT, bloodLeakSelfTestStatus, state ); } return state; } /*********************************************************************//** * @brief * The handleBloodLeakNormalState function handles the Blood Leak module * in normal state. * @details Inputs: bloodLeakStatus, bloodLeakPersistenceCtr, * bloodLeakExitNormalRequested * @details Outputs: bloodLeakStatus, bloodLeakPersistenceCtr, * bloodLeakExitNormalRequested, bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakRecoveryStartTimeMS * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakNormalState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_NORMAL_STATE; bloodLeakStatus.data = getFPGABloodDetectProcessedStatus(); if ( STATE_OPEN == getSwitchStatus( PUMP_TRACK_SWITCH ) ) { // If the pump track on open, zero the persistent counter to not check the blood leak alarm bloodLeakPersistenceCtr = 0; } switch ( getCurrentOperationMode() ) { case MODE_TREA: case MODE_SERV: if ( FALSE == isDialysateLineInBypass() ) { if ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) { if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; if ( getTestConfigStatus( TEST_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != TRUE ) { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ); bloodLeakRecoveryStartTimeMS = getMSTimerCount(); state = BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE; } } } else if ( bloodLeakPersistenceCtr > 0 ) { bloodLeakPersistenceCtr--; } else { clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); clearAlarmCondition( ALARM_ID_HD_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 Inputs: bloodLeakStatus, bloodLeakRecoveryStartTimeMS, * bloodLeakEmbModeHasZeroBeenRqustd, bloodLeakExitNormalRequested * @details Outputs: bloodLeakStatus, bloodLeakRecoveryStartTimeMS, * bloodLeakPersistenceCtr, bloodLeakEmbModeHasZeroBeenRqustd, * bloodLeakExitNormalRequested * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakRecoverBloodDetectState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_RECOVER_BLOOD_DETECT_STATE; bloodLeakStatus.data = getFPGABloodDetectProcessedStatus(); if ( BLOOD_LEAK_NOT_DETECTED == getBloodLeakStatus() ) { 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_HD_BLOOD_LEAK_RECOVERING_PLEASE_WAIT ); } } else { bloodLeakRecoveryStartTimeMS = getMSTimerCount(); } if ( isAlarmActive( ALARM_ID_HD_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 getBloodLeakStatus function gets the current reading for the blood * leak detector. * @details Inputs: bloodLeakStatus * @details Outputs: none * @return the current blood leak status. *************************************************************************/ BLOOD_LEAK_STATUS_T getBloodLeakStatus( void ) { BLOOD_LEAK_STATUS_T result = (BLOOD_LEAK_STATUS_T)bloodLeakStatus.data; if ( OVERRIDE_KEY == bloodLeakStatus.override ) { result = (BLOOD_LEAK_STATUS_T)bloodLeakStatus.ovData; } return result; } /*********************************************************************//** * @brief * The getBloodLeakSelfTestStatus function gets the status for the blood * leak detector self-test. * @details Inputs: bloodLeakSelfTestStatus * @details Outputs: none * @return status of blood leak detector self-test. *************************************************************************/ SELF_TEST_STATUS_T getBloodLeakSelfTestStatus( void ) { #ifndef _RELEASE_ if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_SELF_TEST ) ) { bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; } #endif return bloodLeakSelfTestStatus; } /*********************************************************************//** * @brief * The handleBloodLeakEmbModeWaitForCommandState function handles the wait for * command state. The state prepares the message to be sent to the blood leak * sensor. * @details Inputs: bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeCmd * @details Outputs: bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeCmdSeq, * bloodLeakUARTCmdIndex, bloodLeakEmbModeRespIndex, bloodLeakEmbModeCmdSeqLength, * bloodLeakEmbModeOpsStartTime, bloodLeakEmbModeSetPoint, bloodLeakEmbModeRespBuffer * @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_HD_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 Inputs: bloodLeakEmbModeRqstedCmd, bloodLeakCalCharacter, bloodLeakUARTCmdIndex * bloodLeakEmbModeCmdSeqLength * @details Outputs: bloodLeakEmbModeRqstedCmd, bloodLeakCalCommandSquence, * bloodLeakUARTCmdIndex, bloodLeakEmbModeCmdSeqLength, bloodLeakEmbModeCmdSeqLength, * bloodLeakSetPointSequence * @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_HD_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 Inputs: bloodLeakEmbModeHasRxRqstBeenSent, bloodLeakEmbModeRespBuffer, * bloodLeakEmbModeRespIndex, bloodLeakEmbModeRqstedCmd, bloodLeakEmbModeOpsStartTime * @details 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 Inputs: bloodLeakEmbModeCmd, bloodLeakEmbModeRespIndex * @details 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 ) && ( NU_EMB_MODE_CMD == expChar2 ) ) { // 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 ) { // 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 > 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 if ( ( expChar1 != NU_EMB_MODE_CMD ) && ( expChar2 != NU_EMB_MODE_CMD ) ) { // This is the case that both expected chars are not null. Either of the chars are accepted like P or F if ( bloodLeakEmbModeRespIndex < length ) { // 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 if ( ( NU_EMB_MODE_CMD == expChar1 ) && ( NU_EMB_MODE_CMD == expChar2 ) ) { // 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 Inputs: bloodLeakEmbModeCmd * @details 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 Inputs: none * @details 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 Inputs: bloodLeakDataPublicationTimerCounter * @details Outputs: bloodLeakDataPublicatimerCouonTinter, bloodLeakPersistenceCtr, * bloodLeakState * @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; bloodLeakDataPublicationCounter = 0; broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); } } /*********************************************************************//** * @brief * The initEmbModeSpecs function initializes the embedded mode specifications * structure. * @details Inputs: none * @details 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 Inputs: none * @details 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 Inputs: none * @details 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 Inputs: none * @details 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 Inputs: bloodLeakEmbModeCmdQCount * @details 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 Inputs: bloodLeakEmbModeCmdQCount * @details 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 Inputs: bloodLeakEmbModeInfoCmdEnqueueLastTimeStamp, bloodLeakState, * bloodLeakEmbModeInfoCmdCounter * @details Outputs: bloodLeakEmbModeInfoCmdEnqueueLastTimeStamp, bloodLeakState, * bloodLeakEmbModeInfoCmdCounter * @return none *************************************************************************/ static void enqueueInfoEmbModeCmds( void ) { if ( ( TRUE == didTimeout( bloodLeakEmbModeInfoCmdEnqLastTimeStamp, BLOOD_LEAK_EMB_MODE_INFO_CMD_TIMOUE_MS ) ) && ( bloodLeakState >= BLOOD_LEAK_INIT_STATE ) && ( bloodLeakState != BLOOD_LEAK_CHECK_ZERO_AND_SELF_TEST_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 ); } else if ( 2 == bloodLeakEmbModeInfoCmdCounter ) { enqueueEmbModeCmd( D_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 ); } } /*********************************************************************//** * @brief * The getBloodLeakRxBytesAvailable function returns the number of received * bytes available from FPGA. * @details Inputs: none * @details 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 Inputs: none * @details 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 Inputs: none * @details Outputs: none * @return TRUE if the dialysate line is in bypass otherwise, FALSE *************************************************************************/ static BOOL isDialysateLineInBypass( void ) { BOOL status = TRUE; status &= ( VALVE_POSITION_C_CLOSE == getValvePosition( VDI ) ? TRUE : FALSE ); status &= ( VALVE_POSITION_C_CLOSE == getValvePosition( VDO ) ? TRUE : FALSE ); status &= ( getMeasuredDialInPumpSpeed() <= NEARLY_ZERO ? TRUE : FALSE ); return status; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /*********************************************************************//** * @brief * The testSetBloodLeakDataPublishIntervalOverride function overrides the * blood leak data publish interval. * @details Inputs: none * @details Outputs: bloodLeakDataPublishInterval * @param value override blood leak data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodLeakDataPublishIntervalOverride( U32 value ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { U32 intvl = value / TASK_PRIORITY_INTERVAL; result = TRUE; bloodLeakDataPublishInterval.ovData = intvl; bloodLeakDataPublishInterval.override = OVERRIDE_KEY; } return result; } /*********************************************************************//** * @brief * The testResetBloodLeakDataPublishIntervalOverride function resets the override * of the blood leak data publish interval. * @details Inputs: none * @details Outputs: bloodLeakDataPublishInterval * @return TRUE if override reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodLeakDataPublishIntervalOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakDataPublishInterval.override = OVERRIDE_RESET; bloodLeakDataPublishInterval.ovData = bloodLeakDataPublishInterval.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakStatusOverride function overrides the status * of the blood leak detector. * @details Inputs: none * @details Outputs: bloodLeakStatus * @param none * @param status override blood leak detector with this * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetBloodLeakStatusOverride( BLOOD_LEAK_STATUS_T status ) { BOOL result = FALSE; if ( status < NUM_OF_BLOOD_LEAK_STATUS ) { if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakStatus.ovData = (U32)status; bloodLeakStatus.override = OVERRIDE_KEY; } } return result; } /*********************************************************************//** * @brief * The testResetBloodLeakStatusOverride function resets the override of the * blood leak detector status. * @details Inputs: none * @details Outputs: bloodLeakStatus * @param none * @return TRUE if reset successful, FALSE if not *************************************************************************/ BOOL testResetBloodLeakStatusOverride( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { result = TRUE; bloodLeakStatus.override = OVERRIDE_RESET; bloodLeakStatus.ovData = bloodLeakStatus.ovInitData; } return result; } /*********************************************************************//** * @brief * The testSetBloodLeak2EmbeddedMode function sets the blood leak driver to the * embedded more for calibration. * @details Inputs: none * @details Outputs: bloodLeakSignalEmbeddedModeReq * @return TRUE if switching to embedded mode was accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeak2EmbeddedMode( void ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { HD_OP_MODE_T mode = getCurrentOperationMode(); // Check if the mode is fault, service or standby before accepting a transition to // the embedded mode if ( ( MODE_FAUL == mode ) || ( MODE_SERV == mode ) || ( MODE_STAN == mode ) ) { bloodLeakSignalEmbModeReq = TRUE; bloodLeakEmbModeRqstedCmd = CS_EMB_MODE_CMD; result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakEmbeddedModeCommand function sets the blood leak * calibration command. * @details Inputs: none * @details Outputs: bloodLeakEmbModeSetPoint * @param command the command ID to be sent to blood leak in embedded mode * @param setpointPayload the set point value that is sent with the set point * command. This value is 0 with other commands since they do not have a payload * @return TRUE if the command is accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeakEmbeddedModeCommand( U08 command, U16 setPointPayload ) { BOOL result = FALSE; if ( ( TRUE == isTestingActivated() ) && ( command < NUM_OF_EMB_CMDS ) ) { enqueueEmbModeCmd( command ); bloodLeakEmbModeSetPoint = setPointPayload; result = TRUE; } return result; } /**@}*/