/************************************************************************** * * Copyright (c) 2021-2022 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) Darren Cox * @date (last) 10-Mar-2022 * * @author (original) Peman Montazemi * @date (original) 18-Mar-2021 * ***************************************************************************/ #include // For sprintf and strlen #include "AlarmMgmt.h" #include "BloodLeak.h" #include "FPGA.h" #include "NVDataMgmtHDRecords.h" #include "OperationModes.h" #include "SystemCommMessages.h" #include "TaskPriority.h" #include "Timers.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_TIMEOUT_MS 2000 ///< Blood leak detector timeout for zeroing and self-test (15 ms extended edge detection) #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_START_COMM_CTRL_U_ASCII 21 ///< Blood leak start communication command, ^U (Ctrl-U) in ascii. #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_STARTUP_SEQ_LENGTH 6 ///< Blood leak start up sequence array length. #define BLOOD_LEAK_START_FIFO_CTRL_U_INDEX 2 ///< Blood leak start communication sequence ^U index. #define BLOOD_LEAK_START_FIFO_STOP_INDEX 3 ///< Blood leak start communication sequence stop write to FIFO index. #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 15 ///< Blood leak set point sequence maximum length. #define BLOOD_LEAK_WAIT_2_READ_SET_POINT ( 1 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Blood leak wait to read set point in counts. #define BLOOD_LEAK_WAIT_2_READ_CTRL_U ( 1 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Blood leak wait to read control U in counts. #define BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS 3 ///< Blood leak maximum number of trials to write the set point. #define BLOOD_LEAK_MAX_CTRL_U_WRITE_TRIALS 3 ///< Blood leak maximum number of trials to write the control U command. #define BLOOD_LEAK_MIN_WAIT_TIME_2_GET_CAL_MS ( 2 * MS_PER_SECOND ) ///< Blood leak minimum wait time to get calibration in milliseconds. #define DATA_PUBLISH_COUNTER_START_COUNT 60 ///< Data publish counter start count. // Calibration mode defines #define BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH 4 ///< Blood leak embedded mode command sequence length. #define BLOOD_LEAK_EMB_MODE_STOP_INDEX 1 ///< Blood leak embedded mode stop writing to FIFO index. #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_RX_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Blood leak embedded mode calibration receive timeout in milliseconds. #define BLOOD_LEAK_EMB_MODE_RX_BUFFER_EMPTY 0x80 ///< Blood leak embedded mode buffer empty value. #define BLOOD_LEAK_EMB_MODE_NUM_OF_CMDS 10 // TODO remove ///< Blood leak embedded mode number of commands. /// 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_START_UP_STATE, ///< Start up state. BLOOD_LEAK_CHECK_COMM_STATE, ///< Check communication (Control U) state. BLOOD_LEAK_CHECK_SET_POINT_STATE, ///< Check set point state. BLOOD_LEAK_SET_SET_POINT_STATE, ///< Set set point state. BLOOD_LEAK_INIT_STATE, ///< Init state. BLOOD_LEAK_ZERO_STATE, ///< Zero state. BLOOD_LEAK_SELF_TEST_STATE, ///< Self-test state. BLOOD_LEAK_NORMAL_STATE, ///< Normal state. BLOOD_LEAK_CALIBRATION_STATE, ///< Calibration state. NUM_OF_BLOOD_LEAK_STATES ///< Number of blood leak detector states. } BLOOD_LEAK_STATE_T; /// Defined embedded states typedef enum EmbStates { BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE = 0, ///< Blood leak calibration state wait for command state. BLOOD_LEAK_CAL_SEND_COMMAND_STATE, ///< Blood leak calibration state send command state. BLOOD_LEAK_CAL_WAIT_FOR_COMMAND_RESPONSE_STATE, ///< Blood leak calibration state wait for command response state. NUM_CAL_STATES ///< Number of blood leak calibration states. } BLOOD_LEAK_EMB_MODE_STATE_T; /// Defined embedded commands typedef enum EmbCommands { NU = 0, ///< Null command. CS = 19, ///< Control S command to switch to embedded mode. SP = 83, ///< Set point command to set the set point. T = 84, ///< Self test command. G = 71, ///< Get self test command. I = 73, ///< Intensity command. V = 86, ///< Blood detection level command. Z = 90, ///< Zero sensor command. Q = 81, ///< Zero sensor confirm command. D = 68, ///< Display blood detection command. C = 67, ///< Calibration sensor command. NUM_OF_EMB_CMDS, ///< Number of embedded mode commands. } EMB_MODE_CMD_T; /// typedef struct { U08 expChar1; U08 expChar2; U08 length; }; // ********** 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 BOOL bloodLeakZeroRequested; ///< Blood leak zero requested flag static U32 bloodLeakZeroStartTime; ///< Blood leak zeroing start time. static U32 bloodLeakSelfTestStartTime; ///< Blood leak self-test start time. static BOOL bloodLeakIsPOSTComplete; ///< Blood leak is POST complete flag. static U32 bloodLeakPersistenceCtr = 0; ///< 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 bloodLeakDataPublicationTimerCounter; ///< 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 ]; ///< Blood leak set point sequence array. static U32 bloodLeakWait2ReadResponseCounter; ///< Blood leak wait to read response counter. static U32 bloodLeakCommandWriteTryCount; ///< Blood leak current set point write try number. static HD_BLOOD_LEAK_SENSOR_CAL_RECORD_T bloodLeakCalRecord; ///< Blood leak calibration record structure. static U32 bloodLeakGetCalStartTime; ///< Blood leak get calibration start time. static U32 bloodLeakPrevFPGARegisterCount; ///< Blood leak previous FPGA communications counter. /// Blood leak start up sequence array. static const U08 BLOOD_LEAK_START_UP_SEQUENCE[ BLOOD_LEAK_STARTUP_SEQ_LENGTH ] = { BLOOD_LEAK_RESET_TX_FIFO, BLOOD_LEAK_UART_COMM_ACTIVE_LOW, BLOOD_LEAK_START_COMM_CTRL_U_ASCII, BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND, BLOOD_LEAK_UART_COMM_ACTIVE_HIGH, BLOOD_LEAK_UART_COMM_ACTIVE_LOW }; // Embedded mode variables static BOOL bloodLeakSignalEmbModeReq; ///< Blood leak signal embedded mode has been requested. static EMB_MODE_CMD_T bloodLeakEmbModeASCIICmd; ///< Blood leak signal embedded mode ASCII command. static U08 bloodLeakEmbModeCmdSquence[ BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH ]; ///< Blood leak embedded mode command sequence. static BLOOD_LEAK_EMB_MODE_STATE_T bloodLeakEmbModeSubstate; ///< Blood leak embedded mode state. static U32 bloodLeakEmbModeRxTimeout; ///< Blood leak embedded mode receive timeout. static U16 bloodLeakEmbModeSetPoint; ///< Blood leak embedded mode set point command. // ********** private function prototypes ********** static BLOOD_LEAK_STATE_T handleBloodLeakWaitForPostState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakStartupState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakCheckCommState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakCheckSetPointState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakSetSetPointState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakInitState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakZeroState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakSelfTestState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakNormalState( void ); static BLOOD_LEAK_STATE_T handleBloodLeakCalibrationState( void ); static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakWaitForCommandState( void ); static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakSendCommandState( void ); static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakWaitForCommandResponseState( void ); static void prepareSetPointSeq( U16 setPoint ); static void publishBloodLeakData( void ); /*********************************************************************//** * @brief * The initBloodLeak function initializes the Blood Leak module. * @details Inputs: none * @details Outputs: bloodLeakState, bloodLeakStatus, bloodLeakSelfTestStatus, * bloodLeakZeroRequested, bloodLeakZeroRequested, bloodLeakSelfTestStartTime, * bloodLeakUARTCmdIndex, bloodLeakSetPointSequence, bloodLeakPrevFPGARegisterCount * bloodLeakWait2ReadResponseCounter, bloodLeakDataPublicationTimerCounter, * bloodLeakCommandWriteTryCount, bloodLeakGetCalStartTime, bloodLeakEmbModeSubstate * bloodLeakIsPOSTComplete, bloodLeakPersistenceCtr, bloodLeakSignalEmbModeReq, * bloodLeakEmbModeASCIICmd, bloodLeakEmbModeRxTimeout * @return none *************************************************************************/ void initBloodLeak( void ) { bloodLeakDataPublicationTimerCounter = 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; bloodLeakZeroRequested = FALSE; bloodLeakZeroStartTime = 0; bloodLeakSelfTestStartTime = 0; bloodLeakUARTCmdIndex = 0; bloodLeakSetPointSeqLength = 0; bloodLeakWait2ReadResponseCounter = 0; bloodLeakCommandWriteTryCount = 0; bloodLeakGetCalStartTime = getMSTimerCount(); bloodLeakIsPOSTComplete = FALSE; bloodLeakPrevFPGARegisterCount = 0; bloodLeakPersistenceCtr = 0; bloodLeakSignalEmbModeReq = FALSE; bloodLeakEmbModeASCIICmd = NU; bloodLeakEmbModeSubstate = BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE; bloodLeakEmbModeRxTimeout = 0; // 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 calibration command sequence array. // The first index is the command character so it can be changed upon request. // The reset of the commands are never changing. bloodLeakEmbModeCmdSquence[ 0 ] = 0; bloodLeakEmbModeCmdSquence[ 1 ] = BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND; bloodLeakEmbModeCmdSquence[ 2 ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_HIGH; bloodLeakEmbModeCmdSquence[ 3 ] = BLOOD_LEAK_EMB_MODE_COMM_ACTIVE_LOW; } /*********************************************************************//** * @brief * The execBloodLeak function executes the blood leak detector driver. * @details Inputs: bloodLeakGetCalStartTime, bloodLeakSignalEmbeddedModeReq * @details Outputs: bloodLeakStatus, bloodLeakGetCalStartTime * @return none *************************************************************************/ void execBloodLeak( void ) { // Check if there is a new calibration data available and whether there has been sufficient time elapsed from the last data calibration get // The elapsed time is used to make sure the prepare buffer is not called several time when the new calibration signal is TRUE for one second // otherwise, the prepareSetPointSeq is called multiple time and zeros the start index. In the mean time, the state might have changed to set // the set point and with the start index being reset to 0, it keeps sending the first character of the set point ('S'). if ( ( TRUE == isNewCalibrationRecordAvailable() ) && ( calcTimeSince( bloodLeakGetCalStartTime ) > BLOOD_LEAK_MIN_WAIT_TIME_2_GET_CAL_MS ) ) { 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 ); prepareSetPointSeq( bloodLeakCalRecord.setPoint ); // Force the state machine to go back to set the set point that has been received from // the calibration data bloodLeakState = BLOOD_LEAK_SET_SET_POINT_STATE; // Set the calibration start time to make sure the prepare buffer is not set multiple times in a row bloodLeakGetCalStartTime = getMSTimerCount(); } // If a request to transition to embedded mode has been made, change the state to calibration state, and request a transition to service mode. // This type of work can only be done in the service mode and then the user has to restart the device to return to the normal operations of BLD. if ( TRUE == bloodLeakSignalEmbModeReq ) { bloodLeakState = BLOOD_LEAK_CALIBRATION_STATE; requestNewOperationMode( MODE_SERV ); } // Check if the mode is not in init and then run the sensor if ( getCurrentOperationMode() != MODE_INIT ) { switch( bloodLeakState ) { case BLOOD_LEAK_WAIT_FOR_POST_STATE: bloodLeakState = handleBloodLeakWaitForPostState(); break; case BLOOD_LEAK_START_UP_STATE: bloodLeakState = handleBloodLeakStartupState(); break; case BLOOD_LEAK_CHECK_COMM_STATE: bloodLeakState = handleBloodLeakCheckCommState(); break; case BLOOD_LEAK_CHECK_SET_POINT_STATE: bloodLeakState = handleBloodLeakCheckSetPointState(); break; case BLOOD_LEAK_SET_SET_POINT_STATE: bloodLeakState = handleBloodLeakSetSetPointState(); break; case BLOOD_LEAK_INIT_STATE: bloodLeakState = handleBloodLeakInitState(); break; case BLOOD_LEAK_ZERO_STATE: bloodLeakState = handleBloodLeakZeroState(); break; case BLOOD_LEAK_SELF_TEST_STATE: bloodLeakState = handleBloodLeakSelfTestState(); break; case BLOOD_LEAK_NORMAL_STATE: bloodLeakState = handleBloodLeakNormalState(); break; case BLOOD_LEAK_CALIBRATION_STATE: bloodLeakState = handleBloodLeakCalibrationState(); 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; } } // Publish blood leak data if due publishBloodLeakData(); } /*********************************************************************//** * @brief * The zeroBloodLeak function requests that the Blood Leak Detector be * zeroed. * @details Inputs: none * @details Outputs: Blood Leak module zeroing. * @return Boolean as success or failure *************************************************************************/ void zeroBloodLeak( void ) { bloodLeakZeroRequested = TRUE; bloodLeakUARTCmdIndex = 0; } /*********************************************************************//** * @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; bloodLeakIsPOSTComplete = TRUE; } 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: bloodLeakIsPOSTComplete, bloodLeakPrevFPGARegisterCount * @details Outputs: none * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakWaitForPostState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_WAIT_FOR_POST_STATE; if ( TRUE == bloodLeakIsPOSTComplete ) { // Read the value that is in the FPGA counter so it can be used to make sure the blood leak is communicating after // sending Ctrl U bloodLeakPrevFPGARegisterCount = getFPGABloodLeakRegisterCounter(); state = BLOOD_LEAK_START_UP_STATE; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakStartupState function handles the startup state of the * of blood leak state machine. * @details Inputs: bloodLeakUARTCmdIndex * @details Outputs: bloodLeakUARTCmdIndex * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakStartupState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_START_UP_STATE; U32 command = BLOOD_LEAK_START_UP_SEQUENCE[ bloodLeakUARTCmdIndex ]; // Check if ^U index <= index <= 0 to Tx index. If the current value is either ^U or the 0 to command the FIFO to stop writing // use the transmit function otherwise, use the UART control. if ( ( bloodLeakUARTCmdIndex >= BLOOD_LEAK_START_FIFO_CTRL_U_INDEX ) && ( bloodLeakUARTCmdIndex <= BLOOD_LEAK_START_FIFO_STOP_INDEX ) ) { setFPGABloodLeakUARTTransmit( (U08)command ); } else { setFPGABloodLeakUARTControl( (U08)command ); } // Done with writing all the commands, reset the index and transition if ( bloodLeakUARTCmdIndex >= ( BLOOD_LEAK_STARTUP_SEQ_LENGTH - 1 ) ) { // Wait for the sensor to start communication if ( ++bloodLeakWait2ReadResponseCounter > BLOOD_LEAK_WAIT_2_READ_CTRL_U ) { bloodLeakUARTCmdIndex = 0; state = BLOOD_LEAK_CHECK_COMM_STATE; } } else { bloodLeakUARTCmdIndex++; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakCheckCommState function handles the check communication * state to ensure the sensor is communicating. * @details Inputs: bloodLeakCommandWriteTryCount, bloodLeakPrevFPGARegisterCount * @details Outputs: bloodLeakCommandWriteTryCount, bloodLeakPrevFPGARegisterCount * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakCheckCommState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_CHECK_COMM_STATE; // Check if the blood leak sensor has started communicating BOOL isBloodLeakCommunicating = ( bloodLeakPrevFPGARegisterCount != getFPGABloodLeakRegisterCounter() ? TRUE : FALSE ); // The sensor is communicating move on if ( TRUE == isBloodLeakCommunicating ) { state = BLOOD_LEAK_CHECK_SET_POINT_STATE; bloodLeakCommandWriteTryCount = 0; } else { // If the sensor is not communicating, and the number of writes has not exceeded try again, otherwise alarm if ( bloodLeakCommandWriteTryCount < BLOOD_LEAK_MAX_CTRL_U_WRITE_TRIALS ) { bloodLeakCommandWriteTryCount++; bloodLeakPrevFPGARegisterCount = getFPGABloodLeakRegisterCounter(); state = BLOOD_LEAK_START_UP_STATE; } else { // TODO alarm. Should we check the BLD communications all the time like in the monitor? } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakCheckSetPointState function handles the check set point * state to ensure the set point is set correctly. * @details Inputs: none * @details Outputs: bloodLeakUARTCmdIndex * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakCheckSetPointState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_CHECK_SET_POINT_STATE; U16 bloodLeakSetPoint = getFPGABloodLeakDetectSetPoint(); #ifdef BOARD_WITH_NO_HARDWARE // In case it is just a bare board, use this value bloodLeakCalRecord.setPoint = 20; #endif if ( bloodLeakSetPoint != bloodLeakCalRecord.setPoint ) { if ( bloodLeakCommandWriteTryCount < BLOOD_LEAK_MAX_SET_POINT_WRITE_TRIALS ) { prepareSetPointSeq( bloodLeakCalRecord.setPoint ); bloodLeakCommandWriteTryCount++; state = BLOOD_LEAK_SET_SET_POINT_STATE; } 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 { state = BLOOD_LEAK_INIT_STATE; bloodLeakCommandWriteTryCount = 0; } return state; } /*********************************************************************//** * @brief * The handleBloodLeakSetSetPointState function handles the set set point state. * @details Inputs: bloodLeakUARTCmdIndex * @details Outputs: bloodLeakUARTCmdIndex, bloodLeakSetPointSeqLength * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakSetSetPointState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_SET_SET_POINT_STATE; // Check if the current buffer index is less than the buffer length if( bloodLeakUARTCmdIndex < bloodLeakSetPointSeqLength ) { U32 command = bloodLeakSetPointSequence[ bloodLeakUARTCmdIndex ]; // The active high index is the length - 2 they are the last two elements U32 activeHighIndex = bloodLeakSetPointSeqLength - 2; // Check if the current index towards the end of the buffer which are FIFO set and FIFO reset if( activeHighIndex > bloodLeakUARTCmdIndex ) { setFPGABloodLeakUARTTransmit( (U08)command ); } else { setFPGABloodLeakUARTControl( (U08)command ); } bloodLeakUARTCmdIndex++; } else { if ( ++bloodLeakWait2ReadResponseCounter > BLOOD_LEAK_WAIT_2_READ_SET_POINT ) { bloodLeakWait2ReadResponseCounter = 0; bloodLeakUARTCmdIndex = 0; // Done with writing the set point state = BLOOD_LEAK_CHECK_SET_POINT_STATE; } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakInitState function handles the Blood Leak module in init * state. * @details Inputs: none * @details Outputs: none * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakInitState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_INIT_STATE; if ( TRUE == bloodLeakZeroRequested ) { state = BLOOD_LEAK_ZERO_STATE; bloodLeakZeroRequested = FALSE; bloodLeakZeroStartTime = getMSTimerCount(); setFPGABloodLeakZero(); } return state; } /*********************************************************************//** * @brief * The handleBloodLeakZeroState function handles the Blood Leak module in zeroing * state. * @details Inputs: none * @details Outputs: Blood Leak module zeroing. * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakZeroState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_ZERO_STATE; if ( TRUE == FPGABloodLeakZeroDetected() ) { state = BLOOD_LEAK_SELF_TEST_STATE; bloodLeakSelfTestStatus = SELF_TEST_STATUS_IN_PROGRESS; bloodLeakSelfTestStartTime = getMSTimerCount(); clearFPGABloodLeakZero(); setFPGABloodLeakSelfTest(); } else { if ( TRUE == didTimeout( bloodLeakZeroStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_FAULT ); } } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakSelfTestState function handles the Blood Leak module * in self-test state. * @details Inputs: none * @details Outputs: Blood Leak module self test. * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakSelfTestState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_SELF_TEST_STATE; if ( SELF_TEST_STATUS_IN_PROGRESS == bloodLeakSelfTestStatus ) { if ( FALSE == noFPGABloodLeakDetected() ) // Faked blood leak caused by independent MCU board { bloodLeakSelfTestStatus = SELF_TEST_STATUS_PASSED; clearFPGABloodLeakSelfTest(); } else if ( TRUE == didTimeout( bloodLeakSelfTestStartTime, BLOOD_LEAK_TIMEOUT_MS ) ) { bloodLeakSelfTestStatus = SELF_TEST_STATUS_FAILED; activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_SELF_TEST_FAILURE ); } } else { // Blood leak self-test finished, wait for self-test faked blood leak clear if ( TRUE == noFPGABloodLeakDetected() ) { state = BLOOD_LEAK_NORMAL_STATE; } } return state; } /*********************************************************************//** * @brief * The handleBloodLeakNormalState function handles the Blood Leak module * in normal state. * @details Inputs: none * @details Outputs: Blood Leak module normal. * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakNormalState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_NORMAL_STATE; if ( TRUE == noFPGABloodLeakDetected() ) { bloodLeakStatus.data = BLOOD_LEAK_NOT_DETECTED; } else { bloodLeakStatus.data = BLOOD_LEAK_DETECTED; } // Check status reading and act upon if ( ( BLOOD_LEAK_DETECTED == getBloodLeakStatus() ) && ( MODE_TREA == getCurrentOperationMode() ) ) { if ( ++bloodLeakPersistenceCtr > BLOOD_LEAK_PERSISTENCE ) { bloodLeakPersistenceCtr = BLOOD_LEAK_PERSISTENCE; #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { activateAlarmNoData( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); } } } else // Blood leak not detected { if ( bloodLeakPersistenceCtr > 0 ) { bloodLeakPersistenceCtr--; } else { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_BLOOD_LEAK_ALARM ) != SW_CONFIG_ENABLE_VALUE ) #endif { clearAlarmCondition( ALARM_ID_HD_BLOOD_LEAK_DETECTED ); } } } if ( TRUE == bloodLeakZeroRequested ) { state = BLOOD_LEAK_ZERO_STATE; bloodLeakZeroRequested = FALSE; setFPGABloodLeakZero(); bloodLeakZeroStartTime = getMSTimerCount(); } return state; } /*********************************************************************//** * @brief * The handleBloodLeakCalibrationState function handles the Blood leak * calibration state. * @details Inputs: bloodLeakCalSubstate * @details Outputs: bloodLeakCalSubstate * @return next state *************************************************************************/ static BLOOD_LEAK_STATE_T handleBloodLeakCalibrationState( void ) { BLOOD_LEAK_STATE_T state = BLOOD_LEAK_CALIBRATION_STATE; switch ( bloodLeakEmbModeSubstate ) { case BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE: bloodLeakEmbModeSubstate = handleCalBloodLeakWaitForCommandState(); break; case BLOOD_LEAK_CAL_SEND_COMMAND_STATE: bloodLeakEmbModeSubstate = handleCalBloodLeakSendCommandState(); break; case BLOOD_LEAK_CAL_WAIT_FOR_COMMAND_RESPONSE_STATE: bloodLeakEmbModeSubstate = handleCalBloodLeakWaitForCommandResponseState(); break; } 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 handleCalBloodLeakWaitForCommandState function handles the wait for * command state. The state prepares the message to be sent to the blood leak * sensor. * @details Inputs: bloodLeakCalCharacter * @details Outputs: bloodLeakCalCommandSquence, bloodLeakUARTCmdIndex * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakWaitForCommandState( void ) { BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE; switch( bloodLeakEmbModeASCIICmd ) { case NU: // Null command do nothing break; case CS: case T: case G: case I: case V: case Z: case Q: case D: case C: // The requested command is not set point and so update the command sequence buffer. // The first index of calibration command sequence is the requested command in ASCII. bloodLeakEmbModeCmdSquence[ 0 ] = bloodLeakEmbModeASCIICmd; bloodLeakUARTCmdIndex = 0; state = BLOOD_LEAK_CAL_SEND_COMMAND_STATE; break; case SP: prepareSetPointSeq( bloodLeakEmbModeSetPoint ); state = BLOOD_LEAK_CAL_SEND_COMMAND_STATE; break; } return state; } /*********************************************************************//** * @brief * The handleCalBloodLeakSendCommandState function handles the send command * state. The state sends the command sequence to the blood leak sensor one by * one. * @details Inputs: bloodLeakCalCharacter, bloodLeakUARTCmdIndex * @details Outputs: bloodLeakCalCommandSquence, bloodLeakUARTCmdIndex * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakSendCommandState( void ) { U32 command; BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_CAL_SEND_COMMAND_STATE; BOOL isUARTTxDone = FALSE; BOOL isUARTCtrlDone = TRUE; switch ( bloodLeakEmbModeASCIICmd ) { case CS: case T: case G: case I: case V: case Z: case Q: case D: case C: command = bloodLeakEmbModeCmdSquence[ bloodLeakUARTCmdIndex ]; isUARTTxDone = ( bloodLeakUARTCmdIndex <= BLOOD_LEAK_EMB_MODE_STOP_INDEX ? FALSE : TRUE ); isUARTCtrlDone = ( bloodLeakUARTCmdIndex > ( BLOOD_LEAK_EMB_MODE_CMD_SEQ_LENGTH - 1 ) ? TRUE : FALSE ); bloodLeakUARTCmdIndex++; break; case SP: // Check if the current buffer index is less than the buffer length if( bloodLeakUARTCmdIndex < bloodLeakSetPointSeqLength ) { // The active high index is the length - 2 they are the last two elements U32 activeHighIndex = bloodLeakSetPointSeqLength - 2; command = bloodLeakSetPointSequence[ bloodLeakUARTCmdIndex ]; isUARTTxDone = ( activeHighIndex > bloodLeakUARTCmdIndex ? TRUE : FALSE ); isUARTCtrlDone = FALSE; bloodLeakUARTCmdIndex++; } break; } // Check if the current index towards the end of the buffer which are FIFO set and FIFO reset if ( FALSE == isUARTCtrlDone ) { if( FALSE == isUARTTxDone ) { setFPGABloodLeakUARTTransmit( (U08)command ); } else { setFPGABloodLeakUARTControl( (U08)command ); } } else { // Reset the variables for the next bloodLeakEmbModeRxTimeout = getMSTimerCount(); bloodLeakEmbModeASCIICmd = NU; bloodLeakUARTCmdIndex = 0; state = BLOOD_LEAK_CAL_WAIT_FOR_COMMAND_RESPONSE_STATE; } return state; } /*********************************************************************//** * @brief * The handleCalBloodLeakWaitForCommandResponseState function handles the * wait for command responses state. The state receives data in the buffer. * @details Inputs: TODO fill up * @details Outputs: TODo fill up * @return next state *************************************************************************/ static BLOOD_LEAK_EMB_MODE_STATE_T handleCalBloodLeakWaitForCommandResponseState( void ) { BLOOD_LEAK_EMB_MODE_STATE_T state = BLOOD_LEAK_CAL_WAIT_FOR_COMMAND_RESPONSE_STATE; U08 rxFIFOCount = getFPGABloodLeakRxFIFOCount(); if ( rxFIFOCount > 0 ) { U08 data = getFPGABloodLeakRxFIFODataOut(); BOOL test = FALSE; } // 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 == didTimeout( bloodLeakEmbModeRxTimeout, BLOOD_LEAK_EMB_MODE_RX_TIMEOUT_MS ) ) || ( BLOOD_LEAK_EMB_MODE_RX_BUFFER_EMPTY == rxFIFOCount ) ) { state = BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE; } return state; } /*********************************************************************//** * @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 ]; 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 ); // 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_SET_POINT_START_CHAR_ASCII; // Increment the buffer index bufferIndex++; // Loop through the number of digits and get each ASCII value for ( i = 0; i < digitCount; i++ ) { // Write the characters bloodLeakSetPointSequence[ bufferIndex ] = tempCharBuffer[ i ]; bufferIndex++; } // After the characters, insert the carriage return into the buffer bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_CARRIAGE_RETURN_ASCII; bufferIndex++; // After the characters, insert the stop write to FIFO character which is number 0 bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_STOP_WRITE_FIFO_COMMAND; bufferIndex++; // Set active high and active low into the buffer bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_UART_COMM_ACTIVE_HIGH; bufferIndex++; bloodLeakSetPointSequence[ bufferIndex ] = BLOOD_LEAK_UART_COMM_ACTIVE_LOW; // Update the sequence length for writing to the sensor bloodLeakSetPointSeqLength = bufferIndex + 1; // Get ready for the next write to the sensor bloodLeakUARTCmdIndex = 0; } /*********************************************************************//** * @brief * The publishBloodLeakData function publishes blood leak data at the set interval. * @details Inputs: bloodLeakDataPublicationTimerCounter * @details Outputs: bloodLeakDataPublicationTimerCounter * @return none *************************************************************************/ static void publishBloodLeakData( void ) { // Publish blood leak data on interval if ( ++bloodLeakDataPublicationTimerCounter >= getU32OverrideValue( &bloodLeakDataPublishInterval ) ) { BLOOD_LEAK_DATA_T data; data.bloodLeakStatus = (U32)getBloodLeakStatus(); data.bloodLeakState = (U32)bloodLeakState; data.bloodLeakZeroStatusCounter = (U32)getFPGABloodLeakZeroStatusCounter(); data.bloodLeakCounter = (U32)getFPGABloodLeakCounter(); data.bloodLeakZeroedStatus = (U32)getFPGABloodLeakZeroedStatus(); data.bloodLeakDetectSetPoint = (U32)getFPGABloodLeakDetectSetPoint(); data.bloodLeakDetectLevel = (U32)getFPGABloodLeakDetectLevel(); data.bloodLeakStCount = (U32)getFPGABloodLeakStCount(); data.bloodLeakLEDIntesity = (U32)getFPGABloodLeakLEDIntensity(); data.bloodLeakRegisterCounter = (U32)getFPGABloodLeakRegisterCounter(); data.bloodLeakEmbModeRxChars = 0; broadcastData( MSG_ID_HD_BLOOD_LEAK_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&data, sizeof( BLOOD_LEAK_DATA_T ) ); bloodLeakDataPublicationTimerCounter = 0; } } /************************************************************************* * 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; bloodLeakEmbModeASCIICmd = CS; result = TRUE; } } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakEmbeddedModeCommand function sets the blood leak * calibration command. * @details Inputs: bloodLeakSignalEmbeddedModeReq, bloodLeakCalSubstate * @details Outputs: bloodLeakCalASCIIChar * @return TRUE if the command is accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeakEmbeddedModeCommand( U08 command ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // If the HD is already in service mode and in the blood leak is in the embedded mode and the sensor is waiting for another command if ( ( MODE_SERV == getCurrentOperationMode() ) && ( TRUE == bloodLeakSignalEmbModeReq ) && ( BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE == bloodLeakEmbModeSubstate ) ) { bloodLeakEmbModeASCIICmd = (EMB_MODE_CMD_T)command; } } return result; } /*********************************************************************//** * @brief * The testSetBloodLeakSetPoint function sets the blood leak set point in * the embedded mode. * @details Inputs: bloodLeakSignalEmbeddedModeReq, bloodLeakCalSubstate * @details Outputs: bloodLeakCalASCIIChar, bloodLeakCalSetPoint * @return TRUE if the set point is accepted otherwise, FALSE *************************************************************************/ BOOL testSetBloodLeakSetPoint( U16 setPoint ) { BOOL result = FALSE; if ( TRUE == isTestingActivated() ) { // If the HD is already in service mode and in the blood leak is in the embedded mode and the sensor is waiting for another command if ( ( MODE_SERV == getCurrentOperationMode() ) && ( TRUE == bloodLeakSignalEmbModeReq ) && ( BLOOD_LEAK_CAL_WAIT_FOR_COMAND_STATE == bloodLeakEmbModeSubstate ) ) { bloodLeakEmbModeASCIICmd = SP; bloodLeakEmbModeSetPoint = setPoint; } } return result; } /**@}*/