/************************************************************************** * * Copyright (c) 2026 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file BPDriver.c * * @author (last) Varshini Nagabooshanam * @date (last) 18-May-2026 * * @author (original) Varshini Nagabooshanam * @date (original) 18-May-2026 * ***************************************************************************/ #include "AlarmMgmtTD.h" #include "BPDriver.h" #include "Common.h" #include "FpgaTD.h" #include "TaskGeneral.h" /** * @addtogroup BPDriver * @{ */ // ********** private definitions ********** #define BP_COMMAND_CLEAR_DELAY ( ( 10 / TASK_GENERAL_INTERVAL ) + 1 ) ///< Blood pressure command interval #define BP_RESP_CODE_MASK 0x3C ///< Blood pressure response code mask. #define BP_RESP_CODE_SHIFT 2 ///< Blood pressure response code bit shift. #define BP_MODULE_ERROR_MASK 0x40 ///< Blood pressure module error mask. #define BP_MODULE_BUSY_CLEAR 0 ///< Blood pressure module buy clear #define BP_FPGA_CMD_GIVEN_MASK 0x10 ///< Blood pressure FPGA command #define BP_MODULE_CMD_STARTED_MASK 0x01 ///< Blood pressure module command started mask #define BP_MODULE_CMD_IN_PROGRESS_MASK 0x02 ///< Blood pressure module command in progess mask /// Blood pressure driver states. typedef enum { BP_DRIVER_IDLE_STATE = 0, ///< Blood pressure driver idle state BP_DRIVER_CLEAR_CMD_STATE, ///< Blood pressure driver clear command state BP_DRIVER_WAIT_CLEAR_CMD_STATE, ///< Blood pressure driver wait clear command state BP_DRIVER_SEND_CMD_STATE, ///< Blood pressure driver send command state BP_DRIVER_WAIT_FPGA_ACK_STATE, ///< Blood pressure driver wait FPGA acknowledge state BP_DRIVER_CLEAR_CMD_AFTER_ACK_STATE, ///< Blood pressure driver clear command after acknowledge state BP_DRIVER_WAIT_MODULE_START_STATE, ///< Blood pressure driver wait module start state BP_DRIVER_WAIT_MEASUREMENT_COMPLETE_STATE, ///< Blood pressure driver wait measurement complete state BP_DRIVER_GET_DATA_STATE, ///< Blood pressure driver get data state NUM_OF_BP_DRIVER_STATES ///< Number of Blood pressure driver states } BP_DRIVER_STATE_T; // ********** private data ********** static BP_DRIVER_STATE_T bpDriverState; ///< Current blood pressure driver state. static BP_VITALS_DATA_T bpResults; ///< Latest blood pressure measurement results. static BOOL bpMeasurementReady; ///< Blood pressure measurement ready static BOOL bpDriverError; ///< Blood pressure driver error static BOOL requestAdultBPMeasurement; ///< Request adult BP measurement static BOOL requestPedsBPMeasurement; ///< Request pediatric BP measurement static BOOL requestAbortBPMeasurement; ///< Request abort BP measurement static BOOL bpCuffConnected; ///< Blood pressure cuff connection static U08 pendingBPCommand; ///< Pending BP command static U08 bpCommandClearCtr; ///< Command clear delay counter // ********** private function prototypes ********** static U08 getBPResponseCode( void ); static BP_DRIVER_STATE_T handleBPDriverIdleState( void ); static BP_DRIVER_STATE_T handleBPDriverClearCmdState( void ); static BP_DRIVER_STATE_T handleBPDriverWaitClearCmdState( void ); static BP_DRIVER_STATE_T handleBPDriverSendCmdState( void ); static BP_DRIVER_STATE_T handleBPDriverWaitFpgaAckState( void ); static BP_DRIVER_STATE_T handleBPDriverClearCmdAfterAckState( void ); static BP_DRIVER_STATE_T handleBPDriverWaitModuleStartState( void ); static BP_DRIVER_STATE_T handleBPDriverWaitMeasurementCompleteState( void ); static BP_DRIVER_STATE_T handleBPDriverGetDataState( void ); /*********************************************************************//** * @brief * The initBPDriver function initializes the blood pressure driver. * @details \b Inputs: none * @details \b Outputs: BPDriver unit is initialized * @return none ***************************************************************************/ void initBPDriver( void ) { bpDriverState = BP_DRIVER_IDLE_STATE; bpMeasurementReady = FALSE; bpDriverError = FALSE; requestAdultBPMeasurement = FALSE; requestPedsBPMeasurement = FALSE; requestAbortBPMeasurement = FALSE; bpCuffConnected = FALSE; bpResults.systolic = 0; bpResults.diastolic = 0; bpResults.heartRate = 0; pendingBPCommand = (U08)BP_CMD_IDLE; bpCommandClearCtr = 0; } /*********************************************************************//** * @brief * The getBPResponseCode function returns the FPGA NIBP response code. * @details \b Inputs: none * @details \b Outputs: none * @return FPGA NIBP response code. ***************************************************************************/ static U08 getBPResponseCode( void ) { return ( ( getNIBPStatusResponse() & BP_RESP_CODE_MASK ) >> BP_RESP_CODE_SHIFT ); } /*********************************************************************//** * @brief * The execBPDriver function executes the blood pressure driver state * machine. * @details \b Alarm: ALARM_ID_TD_SOFTWARE_FAULT * @details \b Inputs: bpDriverState * @details \b Outputs: bpDriverState * @return none ***************************************************************************/ void execBPDriver( void ) { bpCuffConnected = ( getNIBPControlStatus() != 0 ) ? TRUE : FALSE; switch ( bpDriverState ) { case BP_DRIVER_IDLE_STATE: bpDriverState = handleBPDriverIdleState(); break; case BP_DRIVER_CLEAR_CMD_STATE: bpDriverState = handleBPDriverClearCmdState(); break; case BP_DRIVER_WAIT_CLEAR_CMD_STATE: bpDriverState = handleBPDriverWaitClearCmdState(); break; case BP_DRIVER_SEND_CMD_STATE: bpDriverState = handleBPDriverSendCmdState(); break; case BP_DRIVER_WAIT_FPGA_ACK_STATE: bpDriverState = handleBPDriverWaitFpgaAckState(); break; case BP_DRIVER_CLEAR_CMD_AFTER_ACK_STATE: bpDriverState = handleBPDriverClearCmdAfterAckState(); break; case BP_DRIVER_WAIT_MODULE_START_STATE: bpDriverState = handleBPDriverWaitModuleStartState(); break; case BP_DRIVER_WAIT_MEASUREMENT_COMPLETE_STATE: bpDriverState = handleBPDriverWaitMeasurementCompleteState(); break; case BP_DRIVER_GET_DATA_STATE: bpDriverState = handleBPDriverGetDataState(); break; default: SET_ALARM_WITH_2_U32_DATA( ALARM_ID_TD_SOFTWARE_FAULT, SW_FAULT_ID_TD_BP_DRIVER_STATE, bpDriverState ); bpDriverState = BP_DRIVER_IDLE_STATE; break; } } /*********************************************************************//** * @brief * The handleBPDriverIdleState function executes the BP driver idle * state handling. * @details \b Inputs: requestAdultBPMeasurement, requestPedsBPMeasurement, * requestAbortBPMeasurement * @details \b Outputs: pendingBPCommand, bpMeasurementReady, bpDriverError * @return next BP module state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverIdleState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_IDLE_STATE; if ( TRUE == requestAdultBPMeasurement ) { SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_BUTTON, BP_DRIVER_IDLE_STATE, BP_DRIVER_CLEAR_CMD_STATE ); requestAdultBPMeasurement = FALSE; bpMeasurementReady = FALSE; bpDriverError = FALSE; pendingBPCommand = (U08)BP_CMD_START_BP; nextState = BP_DRIVER_CLEAR_CMD_STATE; } else if ( TRUE == requestPedsBPMeasurement ) { requestPedsBPMeasurement = FALSE; bpMeasurementReady = FALSE; bpDriverError = FALSE; pendingBPCommand = (U08)BP_CMD_START_PEDS_BP; nextState = BP_DRIVER_CLEAR_CMD_STATE; } else if ( TRUE == requestAbortBPMeasurement ) { requestAbortBPMeasurement = FALSE; pendingBPCommand = (U08)BP_CMD_ABORT_BP; nextState = BP_DRIVER_CLEAR_CMD_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBPDriverClearCmdState function clears the BP command ready bit. * @details \b Inputs: none * @details \b Outputs: bpCommandClearCtr * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverClearCmdState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_CLEAR_CMD_STATE; setNIBPCommand( (U08)BP_CMD_IDLE ); bpCommandClearCtr = 0; return nextState; } /*********************************************************************//** * @brief * The handleBPDriverWaitClearCmdState function waits after clearing the * BP command ready bit. * @details \b Inputs: bpCommandClearCtr * @details \b Outputs: bpCommandClearCtr * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverWaitClearCmdState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_CLEAR_CMD_STATE; bpCommandClearCtr++; if ( bpCommandClearCtr >= BP_COMMAND_CLEAR_DELAY ) { bpCommandClearCtr = 0; nextState = BP_DRIVER_SEND_CMD_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBPDriverSendCmdState function sends the pending BP command. * @details \b Inputs: pendingBPCommand * @details \b Outputs: none * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverSendCmdState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_FPGA_ACK_STATE; setNIBPCommand( pendingBPCommand ); return nextState; } /*********************************************************************//** * @brief * The handleBPDriverWaitFpgaAckState function waits for FPGA command * acknowledge. * @details \b Inputs: none * @details \b Outputs: none * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverWaitFpgaAckState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_FPGA_ACK_STATE; if ( 0 != ( getNIBPControlStatus() & BP_FPGA_CMD_GIVEN_MASK ) ) { nextState = BP_DRIVER_CLEAR_CMD_AFTER_ACK_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBPDriverClearCmdAfterAckState function clears the BP command * ready bit after FPGA acknowledge. * @details \b Inputs: none * @details \b Outputs: none * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverClearCmdAfterAckState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_MODULE_START_STATE; setNIBPCommand( (U08)BP_CMD_IDLE ); return nextState; } /*********************************************************************//** * @brief * The handleBPDriverWaitModuleStartState function waits for the BP module * to signal that the command started. * @details \b Inputs: pendingBPCommand * @details \b Outputs: none * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverWaitModuleStartState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_MODULE_START_STATE; if ( 0 != ( getNIBPStatusResponse() & BP_MODULE_CMD_STARTED_MASK ) ) { if ( ( (U08)BP_CMD_START_BP == pendingBPCommand ) || ( (U08)BP_CMD_START_PEDS_BP == pendingBPCommand ) ) { nextState = BP_DRIVER_WAIT_MEASUREMENT_COMPLETE_STATE; } else if ( (U08)BP_CMD_GET_BP_DATA == pendingBPCommand ) { nextState = BP_DRIVER_GET_DATA_STATE; } else { nextState = BP_DRIVER_IDLE_STATE; } } return nextState; } /*********************************************************************//** * @brief * The handleBPDriverWaitMeasurementCompleteState function waits for the * BP measurement command to complete. * @details \b Inputs: none * @details \b Outputs: pendingBPCommand, bpDriverError * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverWaitMeasurementCompleteState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_WAIT_MEASUREMENT_COMPLETE_STATE; if ( 0 == ( getNIBPStatusResponse() & BP_MODULE_CMD_IN_PROGRESS_MASK ) ) { pendingBPCommand = (U08)BP_CMD_GET_BP_DATA; nextState = BP_DRIVER_CLEAR_CMD_STATE; } else if ( 0 != ( getNIBPStatusResponse() & BP_MODULE_ERROR_MASK ) ) { bpDriverError = TRUE; nextState = BP_DRIVER_IDLE_STATE; } return nextState; } /*********************************************************************//** * @brief * The handleBPDriverGetDataState function retrieves blood pressure * measurement results. * @details \b Inputs: none * @details \b Outputs: bpResults, bpMeasurementReady, pendingBPCommand * @return next BP driver state ***************************************************************************/ static BP_DRIVER_STATE_T handleBPDriverGetDataState( void ) { BP_DRIVER_STATE_T nextState = BP_DRIVER_IDLE_STATE; SEND_EVENT_WITH_2_U32_DATA( TD_EVENT_BUTTON, BP_DRIVER_GET_DATA_STATE, 11 ); bpResults.systolic = (U32)getNIBPSystolicPressure(); bpResults.diastolic = (U32)getNIBPDiastolicPressure(); bpResults.heartRate = (U32)getNIBPHeartRate(); bpMeasurementReady = TRUE; pendingBPCommand = (U08)BP_CMD_IDLE; return nextState; } /*********************************************************************//** * @brief * The startAdultBPMeasurement function requests an adult blood pressure * measurement. * @details \b Inputs: none * @details \b Outputs: requestAdultBPMeasurement * @return none ***************************************************************************/ void startAdultBPMeasurement( void ) { requestAdultBPMeasurement = TRUE; } /*********************************************************************//** * @brief * The startPedsBPMeasurement function requests a pediatric blood pressure * measurement. * @details \b Inputs: none * @details \b Outputs: requestPedsBPMeasurement * @return none ***************************************************************************/ void startPedsBPMeasurement( void ) { requestPedsBPMeasurement = TRUE; } /*********************************************************************//** * @brief * The abortBPMeasurement function aborts the active blood pressure * measurement. * @details \b Inputs: none * @details \b Outputs: requestAbortBPMeasurement * @return none ***************************************************************************/ void abortBPMeasurement( void ) { requestAbortBPMeasurement = TRUE; } /*********************************************************************//** * @brief * The isBPMeasurementReady function returns the blood pressure * measurement ready status * @details \b Inputs: none * @details \b Outputs: bpMeasurementReady * @return TRUE if measurement ready, FALSE otherwise. ***************************************************************************/ BOOL isBPMeasurementReady( void ) { return bpMeasurementReady; } /*********************************************************************//** * @brief * The hasBPDriverError function returns the blood pressure driver * error status. * @details \b Inputs: none * @details \b Outputs: bpDriverError * @return TRUE if module error exists, FALSE otherwise. ***************************************************************************/ BOOL hasBPDriverError( void ) { return bpDriverError; } /*********************************************************************//** * @brief * The hasBPDriverError function returns the blood pressure driver * connection status. * @details \b Inputs: none * @details \b Outputs: bpCuffConnected * @return TRUE if module error exists, FALSE otherwise. ***************************************************************************/ BOOL isBPCuffConnected( void ) { return bpCuffConnected; } /*********************************************************************//** * @brief * The getBPResults function returns the latest BP measurement results. * @note * This function shall only be called from the GeneralTask context to * avoid concurrent access while bpResults is being updated. * @details \b Inputs: bpResults * @details \b Outputs: results * @return TRUE if results copied, FALSE otherwise. ***************************************************************************/ BOOL getBPResults( BP_VITALS_DATA_T *results ) { BOOL result = FALSE; if ( ( NULL != results ) && ( TRUE == bpMeasurementReady ) ) { *results = bpResults; bpMeasurementReady = FALSE; result = TRUE; } return result; } /**@}*/