Index: leahi_dialin/td/proxies/dd_proxy.py =================================================================== diff -u -r2cfe3b26afa7d5ebdb1df6a7fdfd06532880713c -red37b7bb23aba19839c0c52610c669360914f5c1 --- leahi_dialin/td/proxies/dd_proxy.py (.../dd_proxy.py) (revision 2cfe3b26afa7d5ebdb1df6a7fdfd06532880713c) +++ leahi_dialin/td/proxies/dd_proxy.py (.../dd_proxy.py) (revision ed37b7bb23aba19839c0c52610c669360914f5c1) @@ -23,12 +23,12 @@ class DDProxy(AbstractSubSystem): """ - Dialysate Delivery (DD) Dialin API sub-class for RO proxy ( injection ) related commands. + Treatment Delivery (DD) Dialin API sub-class for DD proxy ( injection ) related commands. """ def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ - HD_Buttons constructor + DDProxy constructor @param can_interface: the Denali CAN interface object """ Fisheye: Tag ed37b7bb23aba19839c0c52610c669360914f5c1 refers to a dead (removed) revision in file `leahi_dialin/td/proxies/ro_proxy.py'. Fisheye: No comparison available. Pass `N' to diff? Index: leahi_dialin/td/proxies/ui_proxy.py =================================================================== diff -u --- leahi_dialin/td/proxies/ui_proxy.py (revision 0) +++ leahi_dialin/td/proxies/ui_proxy.py (revision ed37b7bb23aba19839c0c52610c669360914f5c1) @@ -0,0 +1,245 @@ +########################################################################### +# +# Copyright (c) 2020-2025 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 ui_proxy.py +# +# @author (last) Micahel Garthwaite +# @date (last) 18-Aug-2023 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 +# +############################################################################ +import struct +from logging import Logger + +from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.utils.conversions import integer_to_bytearray, byte_to_bytearray, float_to_bytearray + + +class UIProxy(AbstractSubSystem): + """ + Treatment Delivery (TD) Dialin API sub-class for UI proxy ( injection ) related commands. + """ + + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): + """ + DDProxy constructor + + @param can_interface: the Denali CAN interface object + """ + + super().__init__() + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + channel_id = DenaliChannels.td_to_ui_ch_id + msg_id = MsgIds.MSG_ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_tx_parameters_val_resp_sync) + + channel_id = DenaliChannels.td_to_ui_ch_id + msg_id = MsgIds.MSG_ID_TD_RESP_ULTRAFILTRATION_VOLUME_TO_VALIDATE.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_uf_val_resp_sync) + + channel_id = DenaliChannels.td_to_ui_ch_id + msg_id = MsgIds.MSG_ID_TD_RESP_INITIATE_TREATMENT_WORKFLOW.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_initiate_treatment_resp_sync) + + channel_id = DenaliChannels.td_to_ui_ch_id + msg_id = MsgIds.MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_uf_pause_resp_sync) + + # MSG_ID_TD_RESP_TREATMENT_PARAMS_TO_VALIDATE + self.tx_params_acceptance = 0 + self.tx_params_blood_flow_rr = 0 + self.tx_params_dialysate_flow_rr = 0 + self.tx_params_tx_duration_rr = 0 + self.tx_params_saline_bolus_vol_rr = 0 + self.tx_params_acid_rr = 0 + self.tx_params_bicarb_rr = 0 + self.tx_params_dialyzer_type_rr = 0 + self.tx_params_bp_meas_interval_rr = 0 + self.tx_params_rinseback_flow_rate_rr = 0 + self.tx_params_art_pres_limit_window_rr = 0 + self.tx_params_ven_pres_limit_window_rr = 0 + self.tx_params_ven_pres_limit_asymmetric_rr = 0 + self.tx_params_tmp_pres_limit_window_rr = 0 + self.tx_params_dialysate_temperature_rr = 0 + self.tx_params_uf_volume_rr = 0 + self.tx_params_validate_timestamp = 0 + + # MSG_ID_TD_RESP_ULTRAFILTRATION_VOLUME_TO_VALIDATE + self.uf_volume_acceptance = 0 + self.uf_volume_rr = 0 + self.uf_volume_ml = 0.0 + self.uf_volume_timestamp = 0 + + # MSG_ID_TD_RESP_INITIATE_TREATMENT_WORKFLOW + self.initiate_tx_acceptance = 0 + self.initiate_tx_rr = 0 + self.initiate_tx_timestamp = 0 + + # MSG_ID_TD_UF_PAUSE_RESUME_RESPONSE + self.uf_pause_resume_acceptance = 0 + self.uf_pause_resume_rr = 0 + self.uf_pause_resume_timestamp = 0 + + def _handler_tx_parameters_val_resp_sync(self, message: dict, timestamp=0.0) -> None: + """ + Handles treatment parameters validation response from the TD. Treatment parameters acceptance and rejection + are captured. + + :param message: the published TD treatment parameters validation response message. + :param timestamp: timestamp in epoch time of the received message + :return: none + """ + self.tx_params_acceptance = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.tx_params_blood_flow_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.tx_params_dialysate_flow_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + self.tx_params_tx_duration_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + self.tx_params_saline_bolus_vol_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + self.tx_params_acid_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + self.tx_params_bicarb_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] + self.tx_params_dialyzer_type_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] + self.tx_params_bp_meas_interval_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] + self.tx_params_rinseback_flow_rate_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10]))[0] + self.tx_params_art_pres_limit_window_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11]))[0] + self.tx_params_ven_pres_limit_window_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12]))[0] + self.tx_params_ven_pres_limit_asymmetric_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_13:MsgFieldPositions.END_POS_FIELD_13]))[0] + self.tx_params_tmp_pres_limit_window_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_14:MsgFieldPositions.END_POS_FIELD_14]))[0] + self.tx_params_dialysate_temperature_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_15:MsgFieldPositions.END_POS_FIELD_15]))[0] + self.tx_params_uf_volume_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_16:MsgFieldPositions.END_POS_FIELD_16]))[0] + self.tx_params_validate_timestamp = timestamp + + def _handler_uf_val_resp_sync(self, message: dict, timestamp=0.0) -> None: + """ + Handles ultrafiltration volume validation response from the TD. Ultrafiltration volume acceptance and + rejection are captured. + + :param message: the published TD ultrafiltration volume validation response message. + :param timestamp: timestamp in epoch time of the received message + :return: none + """ + self.uf_volume_acceptance = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.uf_volume_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.uf_volume_ml = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + self.uf_volume_timestamp = timestamp + + def _handler_initiate_treatment_resp_sync(self, message: dict, timestamp=0.0) -> None: + """ + Handles inititate treatment response from the TD. Treatment acceptance and rejection + are captured. + + :param message: the published TD inititate treatment response message. + :param timestamp: timestamp in epoch time of the received message + :return: none + """ + self.initiate_tx_acceptance = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.initiate_tx_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.initiate_tx_timestamp = timestamp + + def _handler_uf_pause_resp_sync(self, message: dict, timestamp=0.0) -> None: + """ + Handles ultrafiltration pause response from the TD. Ultrafiltration pause acceptance and rejection + are captured. + + :param message: the published TD inititate treatment response message. + :param timestamp: timestamp in epoch time of the received message + :return: none + """ + self.uf_pause_resume_acceptance = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.uf_pause_resume_rr = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.uf_pause_resume_timestamp = timestamp + + def cmd_send_ui_treatment_param_data(self, blood_flow_rate: int, + dialyate_flow_rate: int, + treatment_duration: int, + saline_bolus_volume: int, + acid_concentrate: int, + bicarb_concentrate: int, + dialyzer_type: int, + bp_interval: int, + rinseback_flow_rate: int, + arterial_pressure_limt: int, + venous_pressure_limit: int, + venous_pressure_asymmetric: int, + tmp_pressure_limit: int, + dialysate_temp: int) -> None: + """ + Constructs and sends a UI set treatment parameters message. + + + :param blood_flow_rate: (int) blood flow rate (in mL/min) + :param dialyate_flow_rate: (int) dialysate flow rate (in mL/min) + :param treatment_duration: (int) treatment duration (in min) + :param saline_bolus_volume: (int) Saline bolus volume (in mL) + :param acid_concentrate: (int) acid concentrate type + :param bicarb_concentrate: (int) bicarbonate concentrate type + :param dialyzer_type: (int) dialyzer type + :param bp_interval: (int) blood pressure measurement interval (in min) + :param rinseback_flow_rate: (int) rinseback flow rate (in mL/min) + :param arterial_pressure_limt: (int) arterial pressure alarm limit window (in mmHg) + :param venous_pressure_limit: (int) venous pressure alarm limit window (in mmHg) + :param venous_pressure_asymmetric: (int) venous pressure alarm limit asymmetric (in mmHg) + :param tmp_pressure_limit: (int) transmembrane pressure alarm limit window + :param dialysate_temp: (int) dialysate temperature (in deg C) + + :return: None + """ + + bld = integer_to_bytearray(blood_flow_rate) + dia = integer_to_bytearray(dialyate_flow_rate) + dur = integer_to_bytearray(treatment_duration) + sal = integer_to_bytearray(saline_bolus_volume) + acc = integer_to_bytearray(acid_concentrate) + bic = integer_to_bytearray(bicarb_concentrate) + dzr = integer_to_bytearray(dialyzer_type) + bpi = integer_to_bytearray(bp_interval) + rbf = integer_to_bytearray(rinseback_flow_rate) + apw = integer_to_bytearray(arterial_pressure_limt) + vpw = integer_to_bytearray(venous_pressure_limit) + vpa = integer_to_bytearray(venous_pressure_asymmetric) + tmp = float_to_bytearray(tmp_pressure_limit) + dtp = float_to_bytearray(dialysate_temp) + + payload = bld + dia + dur + sal + acc + bic + dzr + bpi + rbf + apw + vpw + vpa + tmp + dtp + message = DenaliMessage.build_message(channel_id=DenaliChannels.ui_to_td_ch_id, + message_id=MsgIds.MSG_ID_UI_NEW_TREATMENT_PARAMS_REQUEST.value, + payload=payload) + + self.logger.debug("Sending treatment parameters to TD.") + + self.can_interface.send(message, 0) \ No newline at end of file