/************************************************************************** * * Copyright (c) 2024-2024 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 TDInterface.c * * @author (last) Vinayakam Mani * @date (last) 28-Oct-2024 * * @author (original) Vinayakam Mani * @date (original) 28-Oct-2024 * ***************************************************************************/ #include "DialysatePumps.h" #include "FPInterface.h" #include "FPOperationModes.h" #include "Messaging.h" #include "MessagePayloads.h" #include "ModeGenDialysate.h" #include "ModeInitPOST.h" #include "ModePreGenDialysate.h" #include "ModeStandby.h" #include "OperationModes.h" #include "PersistentAlarm.h" #include "SystemCommDD.h" #include "TaskGeneral.h" #include "TDInterface.h" #include "Timers.h" /** * @addtogroup TDInterface * @{ */ // ********** private definitions ********** #define TD_DATA_FRESHNESS_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< TD data freshness timeout (in ms). #define TD_DIALYSATE_FLOWRATE_MIN_ML_MIN ( 50.0F ) ///< TD Min dialysate flow rate (mL/min) #define TD_DIALYSATE_FLOWRATE_MAX_ML_MIN ( 600.0F ) ///< TD Max dialysate flow rate (mL/min) #define TD_UF_RATE_MIN_ML_MIN ( 0.0F ) ///< TD Min UF rate (mL/min) #define TD_UF_RATE_MAX_ML_MIN ( 2000.0F / 60.0F ) ///< TD Max UF rate (mL/min) #define TD_DIALYSATE_TEMP_MIN_DEGC ( 35.0F ) ///< TD Min dialysate temperature (deg C) #define TD_DIALYSATE_TEMP_MAX_DEGC ( 38.0F ) ///< TD Max dialysate temperature (deg C) #define TD_ACID_TYPE_MIN ( 0U ) ///< TD Min acid type index #define TD_ACID_TYPE_MAX ( (U32)( NUM_OF_ACID_TYPE - 1U ) ) ///< TD Max acid type index #define TD_BICARB_TYPE_MIN ( 0U ) ///< TD Min bicarb type index #define TD_BICARB_TYPE_MAX ( (U32)( NUM_OF_BICARB_TYPE - 1U ) ) ///< TD Max bicarb type index typedef enum { TD_TREATMENT_OVERRIDE_DIALYSATE_FLOWRATE = 0, ///< TD Dialysate flow rate TD_TREATMENT_OVERRIDE_UF_RATE, ///< TD Ultrafilteration rate TD_TREATMENT_OVERRIDE_DIALYSATE_TEMP, ///< TD Target Dialysate Temperature TD_TREATMENT_OVERRIDE_ACID_TYPE, ///< TD Acid type TD_TREATMENT_OVERRIDE_BICARB_TYPE, ///< TD Bicarb type TD_TREATMENT_OVERRIDE_PARAM_COUNT ///< Number of TD override treatment parameters } TD_TREATMENT_OVERRIDE_INDEX_T; // ********** private data ********** // TD status static TD_OP_MODE_T tdCurrentOpMode; ///< Current TD operation mode. static U32 tdSubMode; ///< Current state (sub-mode) of current TD operation mode. static BOOL tdDialyzerBypass; ///< TD dialyzer bypass static BOOL tdOpModeDataFreshFlag = FALSE; ///< Flag to signal/process fresh TD op mode data static OVERRIDE_F32_T tdDialysateFlowrate; ///< TD override Dialysate flow rate static OVERRIDE_F32_T tdUFRate; ///< TD override ultrafiltration rate static OVERRIDE_F32_T tdDialysateTemp; ///< TD override Target Dialysate Temperature static OVERRIDE_U32_T tdAcidType; ///< TD override Acid type static OVERRIDE_U32_T tdBicarbType; ///< TD override Bicarb type // ********** private function prototypes ********** static void checkTDDataFreshness( ALARM_ID_T alarmID, BOOL *tdFreshDataFlag ); /*********************************************************************//** * @brief * The initTDInterface function initializes the TD Interface unit. * @details \b Inputs: none * @details \b Outputs: TD Interface unit initialized. * @return none *************************************************************************/ void initTDInterface( void ) { // Initialize unit state variables tdCurrentOpMode = MODE_INIT; tdSubMode = 0U; tdDialyzerBypass = FALSE; tdOpModeDataFreshFlag = FALSE; // Initialize overrides tdDialysateFlowrate.data = 0.0F; tdDialysateFlowrate.ovData = 0.0F; tdDialysateFlowrate.ovInitData = TD_DIALYSATE_FLOWRATE_MIN_ML_MIN; tdDialysateFlowrate.override = OVERRIDE_RESET; tdUFRate.data = 0.0F; tdUFRate.ovData = 0.0F; tdUFRate.ovInitData = TD_UF_RATE_MIN_ML_MIN; tdUFRate.override = OVERRIDE_RESET; tdDialysateTemp.data = 0.0F; tdDialysateTemp.ovData = 0.0F; tdDialysateTemp.ovInitData = TD_DIALYSATE_TEMP_MIN_DEGC; tdDialysateTemp.override = OVERRIDE_RESET; tdAcidType.data = TD_ACID_TYPE_MIN; tdAcidType.ovData = TD_ACID_TYPE_MIN; tdAcidType.ovInitData = TD_ACID_TYPE_MIN; tdAcidType.override = OVERRIDE_RESET; tdBicarbType.data = TD_BICARB_TYPE_MIN; tdBicarbType.ovData = TD_BICARB_TYPE_MIN; tdBicarbType.ovInitData = TD_BICARB_TYPE_MIN; tdBicarbType.override = OVERRIDE_RESET; } /**********************************************************************//** * @brief * The checkTDDataFreshness function checks the freshness of data coming from * the TD sub-system. * @details \b Alarm: Given alarm is triggered if TD is communicating but has * not published new data for too long. * @details \b Inputs: TD communicating flag * @details \b Outputs: none * @param alarm ID of alarm to check * @param tdFreshDataFlag Pointer to flag indicating whether new data has been * received since last time this function has seen it. * @return None *************************************************************************/ static void checkTDDataFreshness( ALARM_ID_T alarmID, BOOL *tdFreshDataFlag ) { if ( TRUE == *tdFreshDataFlag ) { *tdFreshDataFlag = FALSE; checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } else { // Alarm if not receiving TD fresh data message in timely manner if ( TRUE == isTDCommunicating() ) { checkPersistentAlarm( alarmID, TRUE, 0.0, 0.0 ); } else { checkPersistentAlarm( alarmID, FALSE, 0.0, 0.0 ); } } } /*********************************************************************//** * @brief * The execTDInterfaceMonitor function executes the TD Interface monitoring * function. Ensures TD is sending fresh data in a timely manner. * @details \b Inputs: none * @details \b Outputs: none * @return none *************************************************************************/ void execTDInterfaceMonitor( void ) { } /*********************************************************************//** * @brief * The getTDOpMode function gets the current latest reported TD operating mode. * @details \b Inputs: tdCurrentOpMode * @details \b Outputs: none * @return Latest reported TD operating mode. *************************************************************************/ TD_OP_MODE_T getTDOpMode( void ) { return tdCurrentOpMode; } /*********************************************************************//** * @brief * The getTDSubMode function gets the latest reported TD operating sub-mode. * @details \b Inputs: tdSubMode * @details \b Outputs: none * @return Latest reported TD operating sub-mode. *************************************************************************/ U32 getTDSubMode( void ) { return tdSubMode; } /*********************************************************************//** * @brief * The setTDOpMode function sets the latest TD operating mode reported by * the TD (called by TD published message handler). * @details \b Alarm: ALARM_ID_DD_SOFTWARE_FAULT if reported TD mode is invalid. * @details \b Inputs: none * @details \b Outputs: tdCurrentOpMode, ddSubMode, tdOpModeDataFreshFlag * @param opMode The operating mode reported by DD * @param subMode The sub-mode of operating mode reported by TD * @return none *************************************************************************/ void setTDOpMode( U32 opMode, U32 subMode ) { if ( opMode < NUM_OF_MODES ) { // update TD op mode and sub-mode tdCurrentOpMode = (TD_OP_MODE_T)opMode; tdSubMode = subMode; } else { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DD_SOFTWARE_FAULT, SW_FAULT_ID_INVALID_TD_OPERATING_MODE, opMode ); } tdOpModeDataFreshFlag = TRUE; } /*********************************************************************//** * @brief * The setTDDialysateFlowrate function sets the latest TD dialysate flow * rate. * @details \b Inputs: none * @details \b Outputs: tdDialysateFlowrate * @param dialysate flow rate. * @return none. *************************************************************************/ void setTDDialysateFlowrate( F32 dialFlowrate ) { tdDialysateFlowrate.data = dialFlowrate; } /*********************************************************************//** * @brief * The setTDUFRate function sets the latest TD UF rate. * @details \b Inputs: none * @details \b Outputs: tdUFRate * @param ultrafiltration flow rate. * @return none. *************************************************************************/ void setTDUFRate( F32 ufRate ) { tdUFRate.data = ufRate; } /*********************************************************************//** * @brief * The setTDTargetDialysateTemperature function sets the latest TD dialysate * temperature. * @details \b Inputs: none * @details \b Outputs: tdDialysateTemp * @param Target dialysate temperature. * @return none. *************************************************************************/ void setTDTargetDialysateTemperature( F32 dialTemperature ) { tdDialysateTemp.data = dialTemperature; } /*********************************************************************//** * @brief * The setTDDialyzerBypass function sets the latest TD dialyzer bypass * enable. * @details \b Inputs: none * @details \b Outputs: tdDialyzerBypass * @param Dialyzer Bypass enable. * @return none. *************************************************************************/ void setTDDialyzerBypass( BOOL dialBypass ) { tdDialyzerBypass = dialBypass; } /*********************************************************************//** * @brief * The setTDAcidAndBicarbType function sets the acid and bicarb types to be * used in dialysate generation. * @details \b Inputs: none * @details \b Outputs: tdAcidType,tdBicarbType * @param acid which is the type of acid * @param bicarb which is the type of bicarb * @return none *************************************************************************/ void setTDAcidAndBicarbType( U32 acid, U32 bicarb ) { tdAcidType.data = (DD_ACID_TYPES_T)acid; tdBicarbType.data = (DD_BICARB_TYPES_T)bicarb; } /*********************************************************************//** * @brief * The getTDDialysateFlowrate function gets the latest TD dialysate flow * rate. * @details \b Inputs: tdDialysateFlowrate * @details \b Outputs: none * @return Latest TD dialysate flow rate. *************************************************************************/ F32 getTDDialysateFlowrate( void ) { return getF32OverrideValue( &tdDialysateFlowrate ); } /*********************************************************************//** * @brief * The getTDUFrate function gets the latest TD ultrafiltration flow * rate. * @details \b Inputs: tdUFRate * @details \b Outputs: none * @return Latest UF rate. *************************************************************************/ F32 getTDUFRate( void ) { return getF32OverrideValue( &tdUFRate ); } /*********************************************************************//** * @brief * The getTDTargetDialysateTemperature function gets the latest TD * target dialysate temperature rate. * @details \b Inputs: tdDialysateTemp * @details \b Outputs: none * @return Latest target dialysate temperature. *************************************************************************/ F32 getTDTargetDialysateTemperature( void ) { return getF32OverrideValue( &tdDialysateTemp ); } /*********************************************************************//** * @brief * The getTDDialyzerBypass function gets the latest TD dailyzer bypass valve * enable flag. * @details \b Inputs: tdDialyzerBypass * @details \b Outputs: none * @return Latest dialyzer bypass valve enable. *************************************************************************/ BOOL getTDDialyzerBypass( void ) { return tdDialyzerBypass; } /****************************************************************************** * @brief * The getTDAcidConcentrateType function gets the latest Acid concentrate * type. * @details \b Inputs: tdAcidType * @details \b Outputs: None * @return Latest acid concentrate type. . ******************************************************************************/ DD_ACID_TYPES_T getTDAcidConcentrateType( void ) { U32 value = getU32OverrideValue( &tdAcidType ); return (DD_ACID_TYPES_T)value; } /*********************************************************************//** * @brief * The getTDBicarbConcentrateType function gets the latest Bicarb concentrate * type. * @details \b Inputs: tdBicarbType * @details \b Outputs: none * @return Latest bicarb concentrate type. *************************************************************************/ DD_BICARB_TYPES_T getTDBicarbConcentrateType( void ) { U32 value = getU32OverrideValue( &tdBicarbType ); return (DD_BICARB_TYPES_T)value; } /*********************************************************************//** * @brief * The handlePreGenDialysateRequestMsg function handles a pre gen dailysate * delivery request from TD to perform required self test and priming process. * @details Inputs: none * @details Outputs: message handled * @param message a pointer to the message to handle * @return TRUE if message is sucessfully parsed, FALSE if not. *************************************************************************/ BOOL handlePreGenDialysateRequestMsg( MESSAGE_T *message ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T fpReason = REQUEST_REJECT_REASON_NONE; if ( message->hdr.payloadLen == sizeof( PRE_GEN_DIALYSATE_REQ_PAYLOAD_T ) ) { PRE_GEN_DIALYSATE_REQ_PAYLOAD_T startPreGenRequest; DD_OP_MODE_T ddMode = getCurrentOperationMode(); memcpy( &startPreGenRequest, message->payload, sizeof( PRE_GEN_DIALYSATE_REQ_PAYLOAD_T ) ); // Process the pre-gen dialysate delivery request message if ( ( DD_MODE_STAN == ddMode ) && ( TRUE == startPreGenRequest.start ) ) { // Start FP Pre-Generate Permeate fpReason = signalStartGenPermeate(); // start pre-gen dialysate result = requestDDPreGenStart(); if ( REQUEST_REJECT_REASON_NONE != fpReason ) { result = FALSE; } // Update Temperature, Acid/Bicarb type and dialysate rate for pregen process. setTDDialysateFlowrate( startPreGenRequest.dialRate ); setTDTargetDialysateTemperature( startPreGenRequest.dialTemp ); setTDAcidAndBicarbType( startPreGenRequest.acidType, startPreGenRequest.bicarbType ); } else if ( DD_MODE_PREG == ddMode ) { if ( FALSE == startPreGenRequest.start ) { // stop pre generate diaysate delivery result = requestDDPreGenStop(); // stop FP Pre-Generate Permeate fpReason = signalStopGenPermeate(); if ( REQUEST_REJECT_REASON_NONE != fpReason ) { result = FALSE; } } } } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DD_2_TD, result ); return result; } /*********************************************************************//** * @brief * The handleDialysateDeliveryRequestMsg function handles a dailysate * delivery request from TD and updates dialysate flowrate, UF rate, * dialysate temperature, dialyzer bypass and concentrate types ( acid * and bicarb types). * @details Inputs: none * @details Outputs: message handled * @param message a pointer to the message to handle * @return TRUE if message is sucessfully parsed, FALSE if not. *************************************************************************/ BOOL handleDialysateDeliveryRequestMsg( MESSAGE_T *message ) { BOOL result = FALSE; REQUEST_REJECT_REASON_CODE_T fpReason = REQUEST_REJECT_REASON_NONE; if ( message->hdr.payloadLen == sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ) { DIALYSATE_DELIVERY_REQ_PAYLOAD_T startTxRequest; DD_OP_MODE_T ddMode = getCurrentOperationMode(); memcpy( &startTxRequest, message->payload, sizeof( DIALYSATE_DELIVERY_REQ_PAYLOAD_T ) ); // Process the dialysate delivery request message if ( ( DD_MODE_PREG == ddMode ) && ( TRUE == startTxRequest.start ) ) { // Set dialysate flow rate, UF rate and dialysate temperature setTDDialysateFlowrate( startTxRequest.dialRate ); setTDUFRate( startTxRequest.ufRate ); setTDTargetDialysateTemperature( startTxRequest.dialTemp ); // Set concentrate types, Bypass dialyzer setTDAcidAndBicarbType( startTxRequest.acidType, startTxRequest.bicarbType ); setTDDialyzerBypass( startTxRequest.bypassDialyzer ); // start dialysate generation result = requestDDGenDialStart(); } else if ( DD_MODE_GEND == ddMode ) { if ( FALSE == startTxRequest.start ) { // stop dialysate generation result = requestDDGenDialyasteStop(); // stop FP Pre-Generate Permeate fpReason = signalStopGenPermeate(); if ( REQUEST_REJECT_REASON_NONE != fpReason ) { result = FALSE; } } else { // Set dialysate flow rate, UF rate and dialysate temperature setTDDialysateFlowrate( startTxRequest.dialRate ); setTDUFRate( startTxRequest.ufRate ); setTDTargetDialysateTemperature( startTxRequest.dialTemp ); // Set concentrate types, Bypass dialyzer setTDAcidAndBicarbType( startTxRequest.acidType, startTxRequest.bicarbType ); setTDDialyzerBypass( startTxRequest.bypassDialyzer ); // Signal to update treatement parameters setTreatmentParamUpdate(); result = TRUE; } } } sendAckResponseMsg( (MSG_ID_T)message->hdr.msgID, COMM_BUFFER_OUT_CAN_DD_2_TD, result ); return result; } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /****************************************************************************** * @brief * Processes TD treatment parameter override request from Dialin. * @details \b Inputs: Override payload from Dialin (TEST_OVERRIDE_ARRAY_PAYLOAD_T) * @details \b Outputs: Updated TD override structures and treatment parameter * update flag. * @param message Pointer to the override message received from Dialin. * @return TRUE if the override is successfully applied, FALSE otherwise. ******************************************************************************/ BOOL testTDTreatmentParamsOverride( MESSAGE_T *message ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; getOverrideArrayPayloadFromMessage( message, &payload ); if ( DD_MODE_GEND == getCurrentOperationMode() ) { switch ( (TD_TREATMENT_OVERRIDE_INDEX_T)payload.index ) { case TD_TREATMENT_OVERRIDE_DIALYSATE_FLOWRATE: result = f32Override( message, &tdDialysateFlowrate ); break; case TD_TREATMENT_OVERRIDE_UF_RATE: result = f32Override( message, &tdUFRate ); break; case TD_TREATMENT_OVERRIDE_DIALYSATE_TEMP: result = f32Override( message, &tdDialysateTemp ); break; case TD_TREATMENT_OVERRIDE_ACID_TYPE: result = u32Override( message,&tdAcidType,TD_ACID_TYPE_MIN,TD_ACID_TYPE_MAX ); break; case TD_TREATMENT_OVERRIDE_BICARB_TYPE: result = u32Override( message,&tdBicarbType,TD_BICARB_TYPE_MIN,TD_BICARB_TYPE_MAX ); break; default: result = FALSE; break; } if ( TRUE == result ) { setTreatmentParamUpdate(); } } return result; } /**@}*/