/************************************************************************** * * 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 ) ///< 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 tdDialysateFlowrateOverride; ///< TD override Dialysate flow rate static OVERRIDE_F32_T tdUFRateOverride; ///< TD override ultrafiltration rate static OVERRIDE_F32_T tdDialysateTempOverride; ///< TD override Target Dialysate Temperature static OVERRIDE_U32_T tdAcidTypeOverride; ///< TD override Acid type static OVERRIDE_U32_T tdBicarbTypeOverride; ///< 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 F32 overrides tdDialysateFlowrateOverride.data = 0.0F; tdDialysateFlowrateOverride.ovData = 0.0F; tdDialysateFlowrateOverride.ovInitData = TD_DIALYSATE_FLOWRATE_MIN_ML_MIN; tdDialysateFlowrateOverride.override = OVERRIDE_RESET; tdUFRateOverride.data = 0.0F; tdUFRateOverride.ovData = 0.0F; tdUFRateOverride.ovInitData = TD_UF_RATE_MIN_ML_MIN; tdUFRateOverride.override = OVERRIDE_RESET; tdDialysateTempOverride.data = 0.0F; tdDialysateTempOverride.ovData = 0.0F; tdDialysateTempOverride.ovInitData = TD_DIALYSATE_TEMP_MIN_DEGC; tdDialysateTempOverride.override = OVERRIDE_RESET; tdAcidTypeOverride.data = TD_ACID_TYPE_MIN; tdAcidTypeOverride.ovData = TD_ACID_TYPE_MIN; tdAcidTypeOverride.ovInitData = TD_ACID_TYPE_MIN; tdAcidTypeOverride.override = OVERRIDE_RESET; tdBicarbTypeOverride.data = TD_BICARB_TYPE_MIN; tdBicarbTypeOverride.ovData = TD_BICARB_TYPE_MIN; tdBicarbTypeOverride.ovInitData = TD_BICARB_TYPE_MIN; tdBicarbTypeOverride.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: tdDialysateFlowrateOverride * @param dialysate flow rate. * @return none. *************************************************************************/ void setTDDialysateFlowrate( F32 dialFlowrate ) { tdDialysateFlowrateOverride.data = dialFlowrate; } /*********************************************************************//** * @brief * The setTDUFRate function sets the latest TD UF rate. * @details \b Inputs: none * @details \b Outputs: tdUFRateOverride * @param ultrafiltration flow rate. * @return none. *************************************************************************/ void setTDUFRate( F32 ufRate ) { tdUFRateOverride.data = ufRate; } /*********************************************************************//** * @brief * The setTDTargetDialysateTemperature function sets the latest TD dialysate * temperature. * @details \b Inputs: none * @details \b Outputs: tdDialysateTempOverride * @param Target dialysate temperature. * @return none. *************************************************************************/ void setTDTargetDialysateTemperature( F32 dialTemperature ) { tdDialysateTempOverride.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 ) { tdAcidTypeOverride.data = (DD_ACID_TYPES_T)acid; tdBicarbTypeOverride.data = (DD_BICARB_TYPES_T)bicarb; } /*********************************************************************//** * @brief * The getTDDialysateFlowrate function gets the latest TD dialysate flow * rate. * @details \b Inputs: tdDialysateFlowrateOverride * @details \b Outputs: none * @return Latest TD dialysate flow rate. *************************************************************************/ F32 getTDDialysateFlowrate( void ) { return getF32OverrideValue( &tdDialysateFlowrateOverride ); } /*********************************************************************//** * @brief * The getTDUFrate function gets the latest TD ultrafiltration flow * rate. * @details \b Inputs: tdUFRateOverride * @details \b Outputs: none * @return Latest UF rate. *************************************************************************/ F32 getTDUFRate( void ) { return getF32OverrideValue( &tdUFRateOverride ); } /*********************************************************************//** * @brief * The getTDTargetDialysateTemperature function gets the latest TD * target dialysate temperature rate. * @details \b Inputs: tdDialysateTempOverride * @details \b Outputs: none * @return Latest target dialysate temperature. *************************************************************************/ F32 getTDTargetDialysateTemperature( void ) { return getF32OverrideValue( &tdDialysateTempOverride ); } /*********************************************************************//** * @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: tdAcidTypeOverride * @details \b Outputs: none * @return Latest acid concentrate type. *************************************************************************/ DD_ACID_TYPES_T getTDAcidConcentrateType( void ) { return ( DD_ACID_TYPES_T )tdAcidTypeOverride.data; } /*********************************************************************//** * @brief * The getTDBicarbConcentrateType function gets the latest Bicarb concentrate * type. * @details \b Inputs: tdBicarbTypeOverride * @details \b Outputs: none * @return Latest bicarb concentrate type. *************************************************************************/ DD_BICARB_TYPES_T getTDBicarbConcentrateType( void ) { return ( DD_BICARB_TYPES_T )tdBicarbTypeOverride.data; } /*********************************************************************//** * @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 * Handles TD treatment parameter override requests. * @details * Applies override values for treatment parameters when a tester is logged in. * \b Inputs: TEST_OVERRIDE_ARRAY_PAYLOAD_T structure from Dialin. * \b Outputs: Updated F32/U32 override values for applicable parameters. * @param message Pointer to the override message received from Dialin. * @return TRUE if the override is successfully applied, FALSE otherwise. ******************************************************************************/ static BOOL testTDTreatmentParamsOverride( MESSAGE_T *message ) { BOOL result = FALSE; TEST_OVERRIDE_ARRAY_PAYLOAD_T payload; OVERRIDE_TYPE_T ovType; ovType = getOverrideArrayPayloadFromMessage( message, &payload ); if ( ( TRUE == isTestingActivated() ) && ( DD_MODE_GEND == getCurrentOperationMode() ) && ( ovType != OVERRIDE_INVALID ) && ( ovType < NUM_OF_OVERRIDE_TYPES ) ) { switch ( (TD_TREATMENT_OVERRIDE_INDEX_T)payload.index ) { case TD_TREATMENT_OVERRIDE_DIALYSATE_FLOWRATE: { F32 value = payload.state.f32; if ( ( ovType == OVERRIDE_OVERRIDE ) && ( ( value < TD_DIALYSATE_FLOWRATE_MIN_ML_MIN ) || ( value > TD_DIALYSATE_FLOWRATE_MAX_ML_MIN ) ) ) { result = FALSE; } else { result = f32Override( message, &tdDialysateFlowrateOverride ); } break; } case TD_TREATMENT_OVERRIDE_UF_RATE: { F32 value = payload.state.f32; if ( ( ovType == OVERRIDE_OVERRIDE ) && ( ( value < TD_UF_RATE_MIN_ML_MIN ) || ( value > TD_UF_RATE_MAX_ML_MIN ) ) ) { result = FALSE; } else { result = f32Override( message, &tdDialysateFlowrateOverride ); } break; } case TD_TREATMENT_OVERRIDE_DIALYSATE_TEMP: { F32 value = payload.state.f32; if ( ( ovType == OVERRIDE_OVERRIDE ) && ( ( value < TD_DIALYSATE_TEMP_MIN_DEGC ) || ( value > TD_DIALYSATE_TEMP_MAX_DEGC ) ) ) { result = FALSE; } else { result = f32Override( message, &tdDialysateTempOverride ); } break; } case TD_TREATMENT_OVERRIDE_ACID_TYPE: result = u32Override( message, &tdAcidTypeOverride, TD_ACID_TYPE_MIN, TD_ACID_TYPE_MAX ); break; case TD_TREATMENT_OVERRIDE_BICARB_TYPE: result = u32Override( message, &tdBicarbTypeOverride, TD_BICARB_TYPE_MIN, TD_BICARB_TYPE_MAX ); break; default: result = FALSE; break; } if ( TRUE == result ) { setTreatmentParamUpdate(); } } return result; } /**@}*/