Index: leahi_dialin/td/modules/treatment.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -re45b20cdc5d4c5dcff8cef530b173ca94cb2e422 --- leahi_dialin/td/modules/treatment.py (.../treatment.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/td/modules/treatment.py (.../treatment.py) (revision e45b20cdc5d4c5dcff8cef530b173ca94cb2e422) @@ -8,21 +8,24 @@ # @file treatment.py # # @author (last) Zoltan Miskolci -# @date (last) 08-Jan-2026 +# @date (last) 05-May-2026 # @author (original) Michael Garthwaite # @date (original) 22-Apr-2025 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_ids import MsgIds from leahi_dialin.common.override_templates import cmd_generic_override from leahi_dialin.common import td_enum_repository -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import CanMessenger, CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray, float_to_bytearray @@ -31,7 +34,7 @@ Treatment Delivery (TD) Dialin API sub-class for treatment related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: CanMessenger, logger: Logger): """ TDTreatment constructor """ @@ -40,26 +43,30 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.td_sync_broadcast_ch_id - self.msg_id_td_treatment_param_ranges = MsgIds.MSG_ID_TD_TREATMENT_PARAM_RANGES.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_treatment_param_ranges, - self._handler_treatment_param_ranges_sync) - self.msg_id_td_saline_bolus_data = MsgIds.MSG_ID_TD_SALINE_BOLUS_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_saline_bolus_data, - self._handler_saline_bolus_sync) - self.msg_id_td_uf_data = MsgIds.MSG_ID_TD_ULTRAFILTRATION_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_uf_data, - self._handler_uf_sync) - self.msg_id_td_treatment_time_data = MsgIds.MSG_ID_TD_TREATMENT_TIME_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_treatment_time_data, - self._handler_treatment_time_sync) - self.msg_id_td_treatment_state_data = MsgIds.MSG_ID_TD_TREATMENT_STATE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_treatment_state_data, - self._handler_treatment_state_sync) - self.msg_id_td_rsp_current_treatment_parameters = MsgIds.MSG_ID_TD_RSP_CURRENT_TREATMENT_PARAMETERS.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_td_rsp_current_treatment_parameters, - self._handler_resp_treatment_parameters_sync) + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_TREATMENT_PARAM_RANGES.value, + function = self._handler_treatment_param_ranges_sync) + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_SALINE_BOLUS_DATA.value, + function = self._handler_saline_bolus_sync) + + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_ULTRAFILTRATION_DATA.value, + function = self._handler_uf_sync) + + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_TREATMENT_TIME_DATA.value, + function = self._handler_treatment_time_sync) + + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_TREATMENT_STATE_DATA.value, + function = self._handler_treatment_state_sync) + + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_RSP_CURRENT_TREATMENT_PARAMETERS.value, + function = self._handler_resp_treatment_parameters_sync) + # Treatment param ranges data self.min_tx_time = 0 #: Minimum Treatment time self.max_tx_time = 0 #: Maximum Treatment time @@ -133,19 +140,16 @@ @param message: published treatment parameter range data message @return: none """ - self.min_tx_time = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.max_tx_time = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.min_uf_volume = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.max_uf_volume = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.min_dial_rate = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.max_dial_rate = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + msg_list = [] + msg_list.append(['self.min_tx_time', DataTypes.U32]) + msg_list.append(['self.max_tx_time', DataTypes.U32]) + msg_list.append(['self.min_uf_volume', DataTypes.F32]) + msg_list.append(['self.max_uf_volume', DataTypes.F32]) + msg_list.append(['self.min_dial_rate', DataTypes.U32]) + msg_list.append(['self.max_dial_rate', DataTypes.U32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.tx_params_timestamp = timestamp @@ -158,15 +162,14 @@ @param message: published saline bolus data message @return: none """ - self.tgt_saline_volume = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.cum_saline_volume = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.bol_saline_volume = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.saline_bolus_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + msg_list = [] + msg_list.append(['self.tgt_saline_volume', DataTypes.U32]) + msg_list.append(['self.cum_saline_volume', DataTypes.F32]) + msg_list.append(['self.bol_saline_volume', DataTypes.F32]) + msg_list.append(['self.saline_bolus_state', DataTypes.U32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.saline_bolus_timestamp = timestamp @@ -179,15 +182,14 @@ @param message: published ultrafiltration data message @return: none """ - self.set_uf_volume = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.tgt_uf_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.uf_volume_delivered = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.uf_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + msg_list = [] + msg_list.append(['self.set_uf_volume', DataTypes.F32]) + msg_list.append(['self.tgt_uf_rate', DataTypes.F32]) + msg_list.append(['self.uf_volume_delivered', DataTypes.F32]) + msg_list.append(['self.uf_state', DataTypes.U32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.uf_timestamp = timestamp @@ -200,13 +202,13 @@ @param message: published treatment time data message @return: none """ - self.tx_time_prescribed = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.tx_time_elapsed = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.tx_time_remaining = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + msg_list = [] + msg_list.append(['self.tx_time_prescribed', DataTypes.U32]) + msg_list.append(['self.tx_time_elapsed', DataTypes.U32]) + msg_list.append(['self.tx_time_remaining', DataTypes.U32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.tx_time_timestamp = timestamp @@ -219,23 +221,18 @@ @param message: published treatment state data message @return: none """ - self.tx_sub_mode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.blood_prime_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.dialysis_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.isolated_uf_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.tx_stop_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.rinseback_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.tx_recirc_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] - self.tx_end_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] + msg_list = [] + msg_list.append(['self.tx_sub_mode', DataTypes.U32]) + msg_list.append(['self.blood_prime_state', DataTypes.U32]) + msg_list.append(['self.dialysis_state', DataTypes.U32]) + msg_list.append(['self.isolated_uf_state', DataTypes.U32]) + msg_list.append(['self.tx_stop_state', DataTypes.U32]) + msg_list.append(['self.rinseback_state', DataTypes.U32]) + msg_list.append(['self.tx_recirc_state', DataTypes.U32]) + msg_list.append(['self.tx_end_state', DataTypes.U32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.tx_state_timestamp = timestamp @@ -251,47 +248,30 @@ @param message: published treatment parameter response data message @return: none """ - self.blood_flow_rate = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.dialysate_flow_rate = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.tx_duration = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.saline_bolus_volume = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.hep_stop_time = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.hep_time = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.acid_con = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] - self.bicarb_con = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] - self.dialyzer_type = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] - self.bp_interval = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10]))[0] - self.rb_flow_rate = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11]))[0] - self.rb_volume = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12]))[0] - self.art_pressure_window = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_13:MsgFieldPositions.END_POS_FIELD_13]))[0] - self.venous_pressure_window = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_14:MsgFieldPositions.END_POS_FIELD_14]))[0] - self.venous_asymm_window = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_15:MsgFieldPositions.END_POS_FIELD_15]))[0] - self.tmp_limit_window = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_16:MsgFieldPositions.END_POS_FIELD_16]))[0] - self.dialysate_temp = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_17:MsgFieldPositions.END_POS_FIELD_17]))[0] - self.hep_dispense_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_18:MsgFieldPositions.END_POS_FIELD_18]))[0] - self.hep_bolus_vol = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_19:MsgFieldPositions.END_POS_FIELD_19]))[0] - self.uf_vol = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_20:MsgFieldPositions.END_POS_FIELD_20]))[0] + msg_list = [] + msg_list.append(['self.blood_flow_rate', DataTypes.U32]) + msg_list.append(['self.dialysate_flow_rate', DataTypes.U32]) + msg_list.append(['self.tx_duration', DataTypes.U32]) + msg_list.append(['self.saline_bolus_volume', DataTypes.U32]) + msg_list.append(['self.hep_stop_time', DataTypes.U32]) + msg_list.append(['self.hep_time', DataTypes.U32]) + msg_list.append(['self.acid_con', DataTypes.U32]) + msg_list.append(['self.bicarb_con', DataTypes.U32]) + msg_list.append(['self.dialyzer_type', DataTypes.U32]) + msg_list.append(['self.bp_interval', DataTypes.U32]) + msg_list.append(['self.rb_flow_rate', DataTypes.U32]) + msg_list.append(['self.rb_volume', DataTypes.U32]) + msg_list.append(['self.art_pressure_window', DataTypes.U32]) + msg_list.append(['self.venous_pressure_window', DataTypes.U32]) + msg_list.append(['self.venous_asymm_window', DataTypes.U32]) + msg_list.append(['self.tmp_limit_window', DataTypes.U32]) + msg_list.append(['self.dialysate_temp', DataTypes.F32]) + msg_list.append(['self.hep_dispense_rate', DataTypes.F32]) + msg_list.append(['self.hep_bolus_vol', DataTypes.F32]) + msg_list.append(['self.uf_vol', DataTypes.F32]) + self.process_into_vars(decoder_list = msg_list, + message = message) self.tx_param_req_timestamp = timestamp @@ -322,7 +302,7 @@ return cmd_generic_override( payload = payload, reset = NO_RESET, - channel_id = DenaliChannels.dialin_to_td_ch_id, + channel_id = CanChannels.dialin_to_td_ch_id, msg_id = MsgIds.MSG_ID_TD_SET_TREATMENT_PARAMETER, entity_name = f'TD {param_name}', override_text = str(tx_param_value),