Index: leahi_dialin/common/alarm_defs.py =================================================================== diff -u -r4e012034ca4860c30dfdefb1dcc4c3c41eec1094 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/alarm_defs.py (.../alarm_defs.py) (revision 4e012034ca4860c30dfdefb1dcc4c3c41eec1094) +++ leahi_dialin/common/alarm_defs.py (.../alarm_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -14,7 +14,7 @@ # ############################################################################ from enum import unique -from ..utils.base import AlarmEnum +from ..utils.enums import AlarmEnum # Branch: staging Index: leahi_dialin/common/alarm_priorities.py =================================================================== diff -u -r49a5752911c816d6f33e9800cda8c1221f0dca9e -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/alarm_priorities.py (.../alarm_priorities.py) (revision 49a5752911c816d6f33e9800cda8c1221f0dca9e) +++ leahi_dialin/common/alarm_priorities.py (.../alarm_priorities.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -14,7 +14,7 @@ # ############################################################################ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum @unique Index: leahi_dialin/common/dd_defs.py =================================================================== diff -u -r71f2092930ad621e8a738de12faf806e8c46b1b9 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 71f2092930ad621e8a738de12faf806e8c46b1b9) +++ leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -16,7 +16,7 @@ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum # ================================================== Enum Creators: Operations Lvl 1 ================================================== @@ -350,27 +350,7 @@ } -@unique -class DDEventDataTypes(DialinEnum): - EVENT_DATA_TYPE_NONE = 0 # No Event Data Type - EVENT_DATA_TYPE_U32 = 1 # Unsigned 32bit Event Data Type - EVENT_DATA_TYPE_S32 = 2 # Signed 32bit Event Data Type - EVENT_DATA_TYPE_F32 = 3 # Float 32bit Event Data Type - EVENT_DATA_TYPE_BOOL = 4 # Boolean Event Data Type - NUM_OF_EVENT_DATA_TYPES = 5 # Number of Event Data Types -DDEventDataTypes._str_list = { - # Official Name : Accepted strings - 'EVENT_DATA_TYPE_NONE': ['none'], - 'EVENT_DATA_TYPE_U32': ['u32'], - 'EVENT_DATA_TYPE_S32': ['s32'], - 'EVENT_DATA_TYPE_F32': ['f32'], - 'EVENT_DATA_TYPE_BOOL': ['bool', 'boolean'], - 'NUM_OF_EVENT_DATA_TYPES': [], -} - - - # ================================================== Enum Creators: Names ================================================== @unique class DDConcentratePumpNames(DialinEnum): Index: leahi_dialin/common/dd_defs_proxy.py =================================================================== diff -u -rff7652f24de0ff9249d0236df5c436b37ee6e640 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/dd_defs_proxy.py (.../dd_defs_proxy.py) (revision ff7652f24de0ff9249d0236df5c436b37ee6e640) +++ leahi_dialin/common/dd_defs_proxy.py (.../dd_defs_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -15,6 +15,7 @@ ############################################################################ from . import dd_defs +from . import generic_defs class DD_Defs(): @@ -40,7 +41,7 @@ # Events DDEventList = dd_defs.DDEventList - DDEventDataTypes = dd_defs.DDEventDataTypes + DataTypes = generic_defs.DataTypes # Sensor Names DDConcentratePumpNames = dd_defs.DDConcentratePumpNames Index: leahi_dialin/common/disp_defs.py =================================================================== diff -u -rc6b28ca8a6aae3f70458f05b5bf445069e2fe457 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/disp_defs.py (.../disp_defs.py) (revision c6b28ca8a6aae3f70458f05b5bf445069e2fe457) +++ leahi_dialin/common/disp_defs.py (.../disp_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -16,7 +16,7 @@ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum # ================================================== Enum Creators: Disposables ================================================== Index: leahi_dialin/common/fp_defs.py =================================================================== diff -u -r03cf6f1c459aed5f12550222c40c58fc41c51688 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/fp_defs.py (.../fp_defs.py) (revision 03cf6f1c459aed5f12550222c40c58fc41c51688) +++ leahi_dialin/common/fp_defs.py (.../fp_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -17,10 +17,9 @@ from enum import unique from .dd_defs import DDConductivitySensorNames, DDPressureSensorNames, DDValveNames, DDLevelSensorNames -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum - # ================================================== Constants ================================================== BETA_IOFP_COND_SENSOR_OFFSET = DDConductivitySensorNames.NUM_OF_CONDUCTIVITY_SENSORS.value # Offset to translate Dialin FPTemperaturesNames to DD firmware DD Conductivity Sensors enum BETA_IOFP_PRES_SENSOR_OFFSET = DDPressureSensorNames.NUM_OF_PRESSURE_SENSORS.value # Offset to translate Dialin FPTemperaturesNames to DD firmware DD Pressure Sensors enum @@ -337,27 +336,7 @@ } -@unique -class FPEventDataTypes(DialinEnum): - EVENT_DATA_TYPE_NONE = 0 # No Event Data Type - EVENT_DATA_TYPE_U32 = 1 # Unsigned 32bit Event Data Type - EVENT_DATA_TYPE_S32 = 2 # Signed 32bit Event Data Type - EVENT_DATA_TYPE_F32 = 3 # Float 32bit Event Data Type - EVENT_DATA_TYPE_BOOL = 4 # Boolean Event Data Type - NUM_OF_EVENT_DATA_TYPES = 5 # Number of Event Data Types -FPEventDataTypes._str_list = { - # Official Name : Accepted strings - 'EVENT_DATA_TYPE_NONE': ['none'], - 'EVENT_DATA_TYPE_U32': ['u32'], - 'EVENT_DATA_TYPE_S32': ['s32'], - 'EVENT_DATA_TYPE_F32': ['f32'], - 'EVENT_DATA_TYPE_BOOL': ['bool', 'boolean'], - 'NUM_OF_EVENT_DATA_TYPES': [], -} - - - # ================================================== Enum Creators: Names ================================================== @unique class FPBoostPumpNames(DialinEnum): Index: leahi_dialin/common/fp_defs_proxy.py =================================================================== diff -u -r57ca71b2ff74ef3b96b29586f5aefd5abea222df -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/fp_defs_proxy.py (.../fp_defs_proxy.py) (revision 57ca71b2ff74ef3b96b29586f5aefd5abea222df) +++ leahi_dialin/common/fp_defs_proxy.py (.../fp_defs_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -15,6 +15,7 @@ ############################################################################ from . import fp_defs +from . import generic_defs class FP_Defs(): @@ -43,7 +44,7 @@ # Events FPEventList = fp_defs.FPEventList - FPEventDataTypes = fp_defs.FPEventDataTypes + DataTypes = generic_defs.DataTypes # Sensor Names FPBoostPumpNames = fp_defs.FPBoostPumpNames Index: leahi_dialin/common/generic_defs.py =================================================================== diff -u --- leahi_dialin/common/generic_defs.py (revision 0) +++ leahi_dialin/common/generic_defs.py (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -0,0 +1,57 @@ +########################################################################### +# +# Copyright (c) 2021-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 generic_defs.py +# +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026 +# @author (last) Zoltan Miskolci +# @date (last) 01-May-2026 +# +############################################################################ + +from enum import unique + +from ..utils.enums import DialinEnum + + +@unique +class DataTypes(DialinEnum): + NONE = (0, None, 0) # No Data Type - None + U32 = (1, ' Integer + S32 = (2, ' Integer + F32 = (3, ' Float + # Could use ' Integer + U08 = (5, ' Integer + U16 = (6, ' Integer + NUM_OF_DATA_TYPES = (7, None, 0) # Number of Data Types - None + + def __new__(cls, value, unpack_fmt, unpack_size): + obj = object.__new__(cls) + obj._value_ = value # keeps .value as int + obj.unpack_fmt = unpack_fmt # attach extra attribute + obj.unpack_size = unpack_size # attach extra attribute + return obj + + def unpack_attrib(self) -> str: + return self.unpack_fmt + + def size(self) -> int: + return self.unpack_size + +DataTypes._str_list = { + # Official Name : Accepted strings + 'NONE': [], + 'U32': [], + 'S32': [], + 'F32': [], + 'BOOL': ['boolean'], + 'U08': ['u8'], + 'U16': [], + 'NUM_OF_DATA_TYPES': [], +} Fisheye: Tag 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 refers to a dead (removed) revision in file `leahi_dialin/common/global_vars.py'. Fisheye: No comparison available. Pass `N' to diff? Index: leahi_dialin/common/msg_defs.py =================================================================== diff -u -r41de945f9c773e54e965e80d9e46def828beb732 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/msg_defs.py (.../msg_defs.py) (revision 41de945f9c773e54e965e80d9e46def828beb732) +++ leahi_dialin/common/msg_defs.py (.../msg_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -14,10 +14,10 @@ # ############################################################################ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum from .msg_ids import MsgIds - +MSG_HEADER_SIZE = 6 # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class ACK_NOT_REQUIRED = [ ] @@ -75,9 +75,10 @@ REQUEST_REJECT_REASON_TREATMENT_CANNOT_BE_RESUMED = 47 RequestRejectReasons._str_list = {} + class MsgFieldPositions: # Generic response msg field byte positions (where 32-bit data fields are used) - START_POS_FIELD_1 = 6 # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class + START_POS_FIELD_1 = MSG_HEADER_SIZE # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class END_POS_FIELD_1 = START_POS_FIELD_1 + 4 START_POS_FIELD_2 = END_POS_FIELD_1 END_POS_FIELD_2 = START_POS_FIELD_2 + 4 @@ -139,7 +140,7 @@ class MsgFieldPositionsFWVersions: # UI version message field positions - START_POS_MAJOR = 6 # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class + START_POS_MAJOR = MSG_HEADER_SIZE # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class END_POS_MAJOR = START_POS_MAJOR + 1 START_POS_MINOR = END_POS_MAJOR END_POS_MINOR = START_POS_MINOR + 1 Index: leahi_dialin/common/msg_ids.py =================================================================== diff -u -r106e58f4292b0b970a3c2084af19dca26682edc5 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision 106e58f4292b0b970a3c2084af19dca26682edc5) +++ leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -14,7 +14,7 @@ # ############################################################################ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum # Branch: staging Index: leahi_dialin/common/td_defs.py =================================================================== diff -u -r3ca042a93b178bc02327efec6cf08dd2348f9a8e -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/td_defs.py (.../td_defs.py) (revision 3ca042a93b178bc02327efec6cf08dd2348f9a8e) +++ leahi_dialin/common/td_defs.py (.../td_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -16,7 +16,7 @@ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum # ================================================== Enum Creators: Operations Lvl 1 ================================================== @@ -784,27 +784,7 @@ } -@unique -class TDEventDataTypes(DialinEnum): - EVENT_DATA_TYPE_NONE = 0 # No Event Data Type - EVENT_DATA_TYPE_U32 = 1 # Unsigned 32bit Event Data Type - EVENT_DATA_TYPE_S32 = 2 # Signed 32bit Event Data Type - EVENT_DATA_TYPE_F32 = 3 # Float 32bit Event Data Type - EVENT_DATA_TYPE_BOOL = 4 # Boolean Event Data Type - NUM_OF_EVENT_DATA_TYPES = 5 # Number of Event Data Types -TDEventDataTypes._str_list = { - # Official Name : Accepted strings - 'EVENT_DATA_TYPE_NONE': ['none'], - 'EVENT_DATA_TYPE_U32': ['u32'], - 'EVENT_DATA_TYPE_S32': ['s32'], - 'EVENT_DATA_TYPE_F32': ['f32'], - 'EVENT_DATA_TYPE_BOOL': ['bool', 'boolean'], - 'NUM_OF_EVENT_DATA_TYPES': [], -} - - - # ================================================== Enum Creators: Names ================================================== @unique class TDAirPumpNames(DialinEnum): Index: leahi_dialin/common/td_defs_proxy.py =================================================================== diff -u -rc6b28ca8a6aae3f70458f05b5bf445069e2fe457 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/td_defs_proxy.py (.../td_defs_proxy.py) (revision c6b28ca8a6aae3f70458f05b5bf445069e2fe457) +++ leahi_dialin/common/td_defs_proxy.py (.../td_defs_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -15,6 +15,7 @@ ############################################################################ from . import td_defs +from . import generic_defs class TD_Defs(): @@ -62,7 +63,7 @@ # Events TDEventList = td_defs.TDEventList - TDEventDataTypes = td_defs.TDEventDataTypes + DataTypes = generic_defs.DataTypes # Sensor Names TDAirPumpNames = td_defs.TDAirPumpNames Index: leahi_dialin/common/test_config_defs.py =================================================================== diff -u -rfc66ce51dca2af3afb1de1426f3eb1cf5285d66f -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/common/test_config_defs.py (.../test_config_defs.py) (revision fc66ce51dca2af3afb1de1426f3eb1cf5285d66f) +++ leahi_dialin/common/test_config_defs.py (.../test_config_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -15,7 +15,7 @@ ############################################################################ from enum import unique -from ..utils.base import DialinEnum +from ..utils.enums import DialinEnum @unique Index: leahi_dialin/dd/dialysate_delivery.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,14 +8,15 @@ # @file dialysate_delivery.py # # @author (last) Zoltan Miskolci -# @date (last) 08-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Peter Lucia # @date (original) 02-Apr-2020 # ############################################################################ import struct +# Project imports from .modules.alarms import DDAlarms from .modules.balancing_chamber import DDBalancingChamber from .modules.blood_leak import DDBloodLeak @@ -43,10 +44,12 @@ from ..common.constants import NO_RESET from ..common import dd_enum_repository +from ..common.generic_defs import DataTypes from ..common.msg_defs import MsgIds, MsgFieldPositions, MsgFieldPositionsFWVersions from ..common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels -from ..utils.base import AbstractSubSystem, publish, LogManager +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish, LogManager from ..utils.conversions import integer_to_bytearray, bytearray_to_byte @@ -86,20 +89,18 @@ self.callback_id = None # register handler for DD operation mode broadcast messages if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_op_mode_data = MsgIds.MSG_ID_DD_OP_MODE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_op_mode_data, - self._handler_dd_op_mode_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_OP_MODE_DATA.value, + function = self._handler_dd_op_mode_sync) - self.msg_id_dd_version_response = MsgIds.MSG_ID_DD_VERSION_RESPONSE.value - self.can_interface.register_receiving_publication_function(channel_id, - self.msg_id_dd_version_response, - self._handler_dd_version_response_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_VERSION_RESPONSE.value, + function = self._handler_dd_version_response_sync) - self.msg_id_dd_debug_event = MsgIds.MSG_ID_DD_DEBUG_EVENT.value - self.can_interface.register_receiving_publication_function(channel_id, - self.msg_id_dd_debug_event, - self._handler_dd_debug_event_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_DEBUG_EVENT.value, + function = self._handler_dd_debug_event_sync) + # Dialin will send a login message during construction. This is for the leahi subsystems to start # publishing CAN data when there is no UI connected as the UI typically does this job. self.cmd_log_in_to_dd() @@ -186,13 +187,13 @@ @param message: published DD operation mode broadcast message @return: None """ - mode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) - smode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + msg_list = [] + msg_list.append(('self.dd_operation_mode', DataTypes.U32)) + msg_list.append(('self.dd_operation_sub_mode', DataTypes.U32)) - self.dd_operation_mode = mode[0] - self.dd_operation_sub_mode = smode[0] + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_op_mode_timestamp = timestamp @@ -205,32 +206,56 @@ @return: None if not successful, the version string if unpacked successfully """ - major = struct.unpack(' 0 for each in [result['major'], result['minor'], result['micro'], result['build'], result['compatibility']]]): + self.dd_version = f"v{result['major']}.{result['minor']}.{result['micro']}-{result['build']}.{result['compatibility']}" + self.logger.debug(f'DD VERSION: {self.dd_version}') + + if all([len(each) > 0 for each in [result['fpga_id'], result['fpga_major'], result['fpga_minor'], result['fpga_lab']]]): + self.dd_version = f"v{result['fpga_id']}.{result['fpga_major']}.{result['fpga_minor']}-{result['fpga_lab']}" + self.logger.debug(f'DD VERSION: {self.dd_version}') + + """ + major = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray( message['message'][MsgFieldPositionsFWVersions.START_POS_MAJOR:MsgFieldPositionsFWVersions.END_POS_MAJOR])) - minor = struct.unpack(' 0 for each in [major, minor, micro, build, compatibility]]): self.dd_version = f"v{major[0]}.{minor[0]}.{micro[0]}-{build[0]}.{compatibility[0]}" self.logger.debug(f"DD VERSION: {self.dd_version}") - + if all([len(each) > 0 for each in [fpga_id, fpga_major, fpga_minor, fpga_lab]]): self.dd_fpga_version = f"v{fpga_id[0]}.{fpga_major[0]}.{fpga_minor[0]}-{fpga_lab[0]}" self.logger.debug(f"DD FPGA VERSION: {self.dd_fpga_version}") + """ self.dd_version_response_timestamp = timestamp Index: leahi_dialin/dd/modules/alarms.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/alarms.py (.../alarms.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/alarms.py (.../alarms.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,22 +8,25 @@ # @file alarms.py # # @author (last) Zoltan Miskolci -# @date (last) 08-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Quang Nguyen # @date (original) 02-Sep-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +import struct +# Project imports from leahi_dialin.common.alarm_defs import AlarmList from leahi_dialin.common.constants import NO_RESET -from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliMessage, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray @@ -35,7 +38,7 @@ START_POS_ALARM_ID = DenaliMessage.PAYLOAD_START_INDEX END_POS_ALARM_ID = START_POS_ALARM_ID + 2 - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -44,9 +47,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_alarm_broadcast_ch_id - self.msg_id_dd_alarm_triggered = MsgIds.MSG_ID_ALARM_TRIGGERED.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_alarm_triggered, self._handler_alarm_triggered) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_alarm_broadcast_ch_id, + message_id = MsgIds.MSG_ID_ALARM_TRIGGERED.value, + function = self._handler_alarm_triggered) self.alarm_safety_shutdown_status = 0.0 #: The Alarm's Safety Shutdown status value @@ -66,26 +69,7 @@ self.last_alarm_data_1 = 0.0 #: The last Alarm's data part 1 self.last_alarm_data_2 = 0.0 #: The last Alarm's data part 2 - # alarm information - self.alarm_data_type = dict() #: The Alarm's Data type in dict format - # Loop through the list of the event data type enum and update the dictionary - for data_type in dd_enum_repository.DDEventDataTypes: - event_data_type = dd_enum_repository.DDEventDataTypes(data_type).name - struct_unpack_type = None - - # If U32 is in the data type enum (i.e. EVENT_DATA_TYPE_U32), then the key is the enum and the value is - # the corresponding format in the python struct - if 'U32' in event_data_type or 'BOOL' in event_data_type or 'NONE' in event_data_type: - struct_unpack_type = 'I' - elif 'S32' in event_data_type: - struct_unpack_type = 'i' - elif 'F32' in event_data_type: - struct_unpack_type = 'f' - - self.alarm_data_type[event_data_type] = struct_unpack_type - - @publish(["msg_id_dd_alarm_triggered", "alarm_states", "alarm_conditions", "alarm_data", "alarm_priorities", "alarm_ranks", "alarm_clear_top_only_flags", "dd_alarm_triggered_timestamp"]) def _handler_alarm_triggered(self, message, timestamp = 0.0): @@ -95,35 +79,50 @@ @param message: published DD alarm activation message @return: none """ - self.logger.debug("Alarm activated!") - alarm_id = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + # Local variables + alarm_id:int + data_typ_1:int + data_1:int + data_typ_2:int + data_2:int + priority:int + rank:int + clr_top_only:int + + msg_list = [] + msg_list.append(('alarm_id', DataTypes.U32)) + msg_list.append(('data_typ_1', DataTypes.U32)) + msg_list.append(('data_1', 'data_typ_1')) + msg_list.append(('data_typ_2', DataTypes.U32)) + msg_list.append(('data_2', 'data_typ_2')) + msg_list.append(('priority', DataTypes.U32)) + msg_list.append(('rank', DataTypes.U32)) + msg_list.append(('clr_top_only', DataTypes.U32)) - data_typ_1 = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) - # Get the corresponding structure format - struct_data_type_1 = self.alarm_data_type[dd_enum_repository.DDEventDataTypes(data_typ_1[0]).name] - # Get the data value by unpacking the data type - data_1 = struct.unpack(struct_data_type_1, bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3])) + i = 1 + for msg_detail in msg_list: + start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') + end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') + if isinstance(msg_detail[1], DataTypes): + unpack_attrib = msg_detail[1].unpack_attrib() + else: + data_type_val:int + exec(f'data_type_val = {msg_detail[1]}') + unpack_attrib = DataTypes(data_type_val).unpack_attrib() + value = struct.unpack(unpack_attrib,bytearray(message['message'][start_pos:end_pos]))[0] + exec(f'{msg_detail[0]} = {value}') + i += 1 - data_typ_2 = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4])) - # Get the corresponding structure format - struct_data_type_2 = self.alarm_data_type[dd_enum_repository.DDEventDataTypes(data_typ_2[0]).name] - # Get the data value by unpacking the data type - data_2 = struct.unpack(struct_data_type_2, bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5])) - - priority = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6])) - rank = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7])) - clr_top_only = struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8])) - self.logger.debug("Alarm ID: %d %d %d" % (alarm_id[0], data_1[0], data_2[0])) - self.alarm_states[alarm_id[0]] = True - self.alarm_conditions[alarm_id[0]] = True - self.alarm_priorities[alarm_id[0]] = priority[0] - self.alarm_ranks[alarm_id[0]] = rank[0] - self.alarm_clear_top_only_flags[alarm_id[0]] = clr_top_only[0] - self.alarm_data[alarm_id[0]] = [data_1[0], data_2[0]] - self.last_alarm_triggered = alarm_id[0] - self.last_alarm_data_1 = data_1[0] - self.last_alarm_data_2 = data_2[0] + self.alarm_states[alarm_id] = True + self.alarm_conditions[alarm_id] = True + self.alarm_priorities[alarm_id] = priority + self.alarm_ranks[alarm_id] = rank + self.alarm_clear_top_only_flags[alarm_id] = clr_top_only + self.alarm_data[alarm_id] = [data_1, data_2] + self.last_alarm_triggered = alarm_id + self.last_alarm_data_1 = data_1 + self.last_alarm_data_2 = data_2 self.dd_alarm_triggered_timestamp = timestamp @@ -135,7 +134,7 @@ @param message: published DD alarm info message @return: none """ - self.alarm_safety_shutdown_status = struct.unpack('I', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + self.alarm_safety_shutdown_status = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) self.dd_alarm_info_timestamp = timestamp Index: leahi_dialin/dd/modules/balancing_chamber.py =================================================================== diff -u -r039d9f5987f79862f10c026e6ca103d8139be1fa -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/balancing_chamber.py (.../balancing_chamber.py) (revision 039d9f5987f79862f10c026e6ca103d8139be1fa) +++ leahi_dialin/dd/modules/balancing_chamber.py (.../balancing_chamber.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file balancing_chamber.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -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_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -32,7 +35,7 @@ Dialysate Delivery (DD) Dialin API sub-class for Balancing Chamber related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -42,10 +45,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_bal_chamber_data = MsgIds.MSG_ID_DD_BAL_CHAMBER_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_bal_chamber_data, - self._handler_balancing_chamber_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_BAL_CHAMBER_DATA.value, + function = self._handler_balancing_chamber_sync) self.execution_state = 0 #: The Execution state self.switching_state = 0 #: The Switching state @@ -73,24 +75,19 @@ @param message: published balancing chamber data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.switching_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.switching_frequency = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.switching_period = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.bal_chamber_fill_in_progress = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.current_bal_chamber_switching_counter = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.is_pressure_stabilized_during_fill = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] - self.bal_chamber_switch_only_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] - self.is_bal_chamber_switching_active = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] + msg_list = [] + msg_list.append(('self.execution_state', DataTypes.U32)) + msg_list.append(('self.switching_state', DataTypes.U32)) + msg_list.append(('self.switching_frequency', DataTypes.F32)) + msg_list.append(('self.switching_period', DataTypes.U32)) + msg_list.append(('self.bal_chamber_fill_in_progress', DataTypes.U32)) + msg_list.append(('self.current_bal_chamber_switching_counter', DataTypes.U32)) + msg_list.append(('self.is_pressure_stabilized_during_fill', DataTypes.U32)) + msg_list.append(('self.bal_chamber_switch_only_state', DataTypes.U32)) + msg_list.append(('self.is_bal_chamber_switching_active', DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, + message = message) self.dd_bal_chamber_timestamp = timestamp Index: leahi_dialin/dd/modules/blood_leak.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/blood_leak.py (.../blood_leak.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/blood_leak.py (.../blood_leak.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,22 +8,26 @@ # @file blood_leak.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Dara Navaei # @date (original) 21-Aug-2025 # ############################################################################ -import struct +# Module imports from logging import Logger from enum import unique +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish, DialinEnum +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish +from leahi_dialin.utils.enums import DialinEnum from leahi_dialin.utils.conversions import integer_to_bytearray, bytearray_to_byte, bytearray_to_integer, \ unsigned_short_to_bytearray, byte_to_bytearray, float_to_bytearray @@ -54,7 +58,7 @@ BLOOD_LEAK_DETECTED = 0 # Blood detected NO_BLOOD_LEAK_DETECTED = 1 # No blood detected - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Leahi Can Messenger object """ @@ -63,15 +67,13 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_blood_leak_data = MsgIds.MSG_ID_DD_BLOOD_LEAK_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_blood_leak_data, - self._handler_blood_leak_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_BLOOD_LEAK_DATA.value, + function = self._handler_blood_leak_sync) - channel_id = DenaliChannels.dd_to_dialin_ch_id - self.msg_id_dd_send_blood_leak_emb_mode_response = MsgIds.MSG_ID_DD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_send_blood_leak_emb_mode_response, - self._handler_blood_leak_emb_mode_cmd_resp) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_to_dialin_ch_id, + message_id = MsgIds.MSG_ID_DD_SEND_BLOOD_LEAK_EMB_MODE_RESPONSE.value, + function = self._handler_blood_leak_emb_mode_cmd_resp) self.dd_blood_leak_status_timestamp = 0.0 #: The timestamp of the last Blood Leak data message self.dd_blood_leak_emb_mode_response_timestamp = 0.0 #: The timestamp of the last Emb Mode response message @@ -140,29 +142,24 @@ @param message: published blood leak status message @return: None """ - self.blood_leak_status = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.blood_leak_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.blood_leak_error_persistent_ctr = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.blood_leak_serial_comm_state = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.blood_leak_intensity = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.blood_leak_blood_detect = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.blood_leak_intensity_moving_average = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] - self.blood_leak_time_elapsed_since_last_drift_zero_ms = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] - self.blood_leak_in_range_drift_status = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] - self.blood_leak_upper_range_drift_status = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10]))[0] - self.dd_blood_leak_status_timestamp = timestamp + msg_list =[] + msg_list.append(('self.blood_leak_status', DataTypes.U32)) + msg_list.append(('self.blood_leak_state', DataTypes.U32)) + msg_list.append(('self.blood_leak_error_persistent_ctr', DataTypes.U32)) + msg_list.append(('self.blood_leak_serial_comm_state', DataTypes.U32)) + msg_list.append(('self.blood_leak_intensity', DataTypes.U32)) + msg_list.append(('self.blood_leak_blood_detect', DataTypes.U32)) + msg_list.append(('self.blood_leak_intensity_moving_average', DataTypes.F32)) + msg_list.append(('self.blood_leak_time_elapsed_since_last_drift_zero_ms', DataTypes.U32)) + msg_list.append(('self.blood_leak_in_range_drift_status', DataTypes.U32)) + msg_list.append(('self.blood_leak_upper_range_drift_status', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_conductivity_timestamp = timestamp + + @publish(['msg_id_dd_send_blood_leak_emb_mode_response', 'blood_leak_emb_mode_cmd_response', 'dd_blood_leak_emb_mode_response_timestamp']) def _handler_blood_leak_emb_mode_cmd_resp(self, message, timestamp=0.0): Index: leahi_dialin/dd/modules/concentrate_pump.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/concentrate_pump.py (.../concentrate_pump.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/concentrate_pump.py (.../concentrate_pump.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file concentrate_pumps.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ Dialin API sub-class for concentrate pumps related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -41,10 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_conc_pump_data = MsgIds.MSG_ID_DD_CONCENTRATE_PUMP_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_conc_pump_data, - self._handler_concentrate_pumps_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_CONCENTRATE_PUMP_DATA.value, + function = self._handler_concentrate_pumps_sync) self.dd_concentrate_pump_timestamp = 0.0 #: The timestamp of the last message @@ -95,57 +97,37 @@ @param message: published concentrate pumps' data message @return: None """ - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.PULSE_US.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.PULSE_US.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_13:MsgFieldPositions.END_POS_FIELD_13])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_14:MsgFieldPositions.END_POS_FIELD_14])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.PARKED.name] = \ - True if struct.unpack('I', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_15:MsgFieldPositions.END_POS_FIELD_15]))[0] == 1 else False - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.PARKED.name] = \ - True if struct.unpack('I', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_16:MsgFieldPositions.END_POS_FIELD_16]))[0] == 1 else False - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID.name][dd_enum_repository.DDConcentratePumpAttributes.PARK_FAULT.name] = \ - True if struct.unpack('I', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_17:MsgFieldPositions.END_POS_FIELD_17]))[0] == 1 else False - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB.name][dd_enum_repository.DDConcentratePumpAttributes.PARK_FAULT.name] = \ - True if struct.unpack('I', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_18:MsgFieldPositions.END_POS_FIELD_18]))[0] == 1 else False - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_19:MsgFieldPositions.END_POS_FIELD_19])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_20:MsgFieldPositions.END_POS_FIELD_20])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_21:MsgFieldPositions.END_POS_FIELD_21])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_22:MsgFieldPositions.END_POS_FIELD_22])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_23:MsgFieldPositions.END_POS_FIELD_23])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_24:MsgFieldPositions.END_POS_FIELD_24])))[0] - self.dd_concentrate_pumps[dd_enum_repository.DDConcentratePumpNames.D76_UF.name][dd_enum_repository.DDConcentratePumpAttributes.PULSE_US.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_25:MsgFieldPositions.END_POS_FIELD_25])))[0] + sensor_list =[] + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.PULSE_US, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.PULSE_US, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.PARKED, DataTypes.BOOL)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.PARKED, DataTypes.BOOL)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D11_CP1_ACID, dd_enum_repository.DDConcentratePumpAttributes.PARK_FAULT, DataTypes.BOOL)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D10_CP2_BICARB, dd_enum_repository.DDConcentratePumpAttributes.PARK_FAULT, DataTypes.BOOL)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.TARGET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_SET_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.TARGET_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.MEASURED_REV_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.CURRENT_STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConcentratePumpNames.D76_UF, dd_enum_repository.DDConcentratePumpAttributes.PULSE_US, DataTypes.F32)) + self.process_into_dict(dict_to_update = self.dd_concentrate_pumps, + msg_list = sensor_list, + message = message) + self.dd_concentrate_pump_timestamp = timestamp Index: leahi_dialin/dd/modules/conductivity_sensors.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/conductivity_sensors.py (.../conductivity_sensors.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/conductivity_sensors.py (.../conductivity_sensors.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,22 +8,24 @@ # @file conductivity_sensors.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Quang Nguyen # @date (original) 20-Jul-2020 # ############################################################################ - -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -34,7 +36,7 @@ Dialysate Delivery (DD) API sub-class for conductivity sensors related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -44,10 +46,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_conductivity_data = MsgIds.MSG_ID_DD_CONDUCTIVITY_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_conductivity_data, - self._handler_conductivity_sensors_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_CONDUCTIVITY_DATA.value, + function = self._handler_conductivity_sensors_sync) self.dd_conductivity_timestamp = 0.0 #: The timestamp of the last message @@ -71,19 +72,16 @@ @return: None """ sensor_list =[] - sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D17_COND, 'f')) - sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D27_COND, 'f')) - sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D29_COND, 'f')) - sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D43_COND, 'f')) - sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D74_COND, 'f')) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D17_COND, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D27_COND, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D29_COND, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D43_COND, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D74_COND, DataTypes.F32)) - i = 1 - for sensor in sensor_list: - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - self.dd_conductivity[sensor[0].name] = struct.unpack(sensor[1],bytearray(message['message'][start_pos:end_pos]))[0] - i += 1 - + self.process_into_dict(dict_to_update = self.dd_conductivity, + msg_list = sensor_list, + message = message) + self.dd_conductivity_timestamp = timestamp Index: leahi_dialin/dd/modules/dd_test_configs.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/dd_test_configs.py (.../dd_test_configs.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/dd_test_configs.py (.../dd_test_configs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,30 +8,32 @@ # @file dd_test_configs.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Jonny Paguio # @date (original) 20-Aug-2025 # ############################################################################ +# 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.override_templates import cmd_generic_override from leahi_dialin.common.test_config_defs import DDFPTestConfigOptions -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray, bytearray_to_integer - class DDTestConfig(AbstractSubSystem): """ Dialysate Delivery (DD) Dialin API sub-class for setting and getting the test configurations. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali CAN Messenger object """ @@ -41,10 +43,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_to_dialin_ch_id - self.msg_id_dd_send_test_config = MsgIds.MSG_ID_DD_SEND_TEST_CONFIGURATION.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_send_test_config, - self._handler_dd_test_config_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_to_dialin_ch_id, + message_id = MsgIds.MSG_ID_DD_SEND_TEST_CONFIGURATION.value, + function = self._handler_dd_test_config_sync) self.dd_test_configs_response_timestamp = 0.0 #: The timestamp of the latest message self.dd_test_configs = dict() #: The Test Config data in dictionary format Index: leahi_dialin/dd/modules/dialysate_pump.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/dialysate_pump.py (.../dialysate_pump.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/dialysate_pump.py (.../dialysate_pump.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file dialysate_pump.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -33,7 +36,7 @@ Dialysate Delivery (DD) Dialin API sub-class for dialysate pumps related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -43,10 +46,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_dialysate_pumps_data = MsgIds.MSG_ID_DIALYSATE_PUMPS_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_dialysate_pumps_data, - self._handler_dialysate_pumps_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DIALYSATE_PUMPS_DATA.value, + function = self._handler_dialysate_pumps_sync) self.dd_dialysate_pump_timestamp = 0 #: The timestamp of the latest message @@ -88,56 +90,32 @@ @param message: published dialysate pumps' data message @return: None """ - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.TARGET_RPM.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.TARGET_RPM.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])))[0] + sensor_list =[] + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.TARGET_RPM, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.TARGET_RPM, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.CURRENT_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.CURRENT_SPEED, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.TARGET_PRESSURE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.TARGET_PRESSURE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_PRESSURE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_PRESSURE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_CURRENT, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_CURRENT, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.CONTROL, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.CONTROL, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.DIRECTION_ERROR_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.DIRECTION_ERROR_COUNT, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D12_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_DIRECTION, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDConductivitySensorNames.D48_PUMP, dd_enum_repository.DDConductivitySensorNames.MEASURED_DIRECTION, DataTypes.U32)) - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4])))[0] + self.process_into_dict(dict_to_update = self.dd_dialysate_pumps, + msg_list = sensor_list, + message = message) - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.CURRENT_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.CURRENT_SPEED.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.STATE.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.STATE.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.TARGET_PRESSURE.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.TARGET_PRESSURE.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_PRESSURE.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_PRESSURE.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_CURRENT.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_13:MsgFieldPositions.END_POS_FIELD_13])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_CURRENT.name] = ( - struct.unpack('f', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_14:MsgFieldPositions.END_POS_FIELD_14])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.CONTROL.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_15:MsgFieldPositions.END_POS_FIELD_15])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.CONTROL.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_16:MsgFieldPositions.END_POS_FIELD_16])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.DIRECTION_ERROR_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_17:MsgFieldPositions.END_POS_FIELD_17])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.DIRECTION_ERROR_COUNT.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_18:MsgFieldPositions.END_POS_FIELD_18])))[0] - - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D12_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_DIRECTION.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_19:MsgFieldPositions.END_POS_FIELD_19])))[0] - self.dd_dialysate_pumps[dd_enum_repository.DDDialysatePumpNames.D48_PUMP.name][dd_enum_repository.DDDialysatePumpAttributes.MEASURED_DIRECTION.name] = ( - struct.unpack('i', bytearray(message['message'][MsgFieldPositions.START_POS_FIELD_20:MsgFieldPositions.END_POS_FIELD_20])))[0] - self.dd_dialysate_pump_timestamp = timestamp Index: leahi_dialin/dd/modules/drybicart.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/drybicart.py (.../drybicart.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/drybicart.py (.../drybicart.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -7,30 +7,35 @@ # # @file drybicart.py # -# @author (last) Sameer Poyil -# @date (last) 19-Nov-2025 +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026 # @author (original) Sameer Poyil # @date (original) 19-Nov-2025 # ############################################################################ -import struct + +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET , RESET -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish -from leahi_dialin.utils.conversions import integer_to_bytearray, float_to_bytearray +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish +from leahi_dialin.utils.conversions import integer_to_bytearray + class DDDryBicart(AbstractSubSystem): """ DryBicart Dialysate Delivery (DD) Dialin API sub-class for Dry Bicart related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object @@ -41,10 +46,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_dry_bicart_data = MsgIds.MSG_ID_DD_DRY_BICART_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_dry_bicart_data, - self._handler_dry_bicart_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_DRY_BICART_DATA.value, + function = self._handler_dry_bicart_sync) self.dd_dry_bicart_timestamp = 0 #: The timestamp of the last message self.dd_dry_bicart_fill_execution_state = 0 #: The Dry Bicart fill execution state @@ -74,30 +78,22 @@ @param message: published dry bicart data message @return: None """ - self.dd_dry_bicart_fill_execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.dd_bicarb_chamber_fill_execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.dd_dry_bicart_drain_execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.dd_dry_bicart_fill_cycle_counter = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.dd_dry_bicart_max_fill_cycle_count = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.ddd_dry_bicart_fill_request = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.dd_bicarb_chamber_fill_request = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] - self.ddd_dry_bicart_drain_request = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8]))[0] - self.dd_dry_bicart_last_fill_time = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_9:MsgFieldPositions.END_POS_FIELD_9]))[0] - self.dd_dry_bicart_current_fill_time = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_10:MsgFieldPositions.END_POS_FIELD_10]))[0] - self.dd_dryBiCartType = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_11:MsgFieldPositions.END_POS_FIELD_11]))[0] - self.dd_dryBiCartDrainTimePeriod = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_12:MsgFieldPositions.END_POS_FIELD_12]))[0] + msg_list = [] + msg_list.append(('self.dd_dry_bicart_fill_execution_state', DataTypes.U32)) + msg_list.append(('self.dd_bicarb_chamber_fill_execution_state', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_drain_execution_state', DataTypes.F32)) + msg_list.append(('self.dd_dry_bicart_fill_cycle_counter', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_max_fill_cycle_count', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_fill_request', DataTypes.U32)) + msg_list.append(('self.dd_bicarb_chamber_fill_request', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_drain_request', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_last_fill_time', DataTypes.U32)) + msg_list.append(('self.dd_dry_bicart_current_fill_time', DataTypes.U32)) + msg_list.append(('self.dd_dryBiCartType', DataTypes.U32)) + msg_list.append(('self.dd_dryBiCartDrainTimePeriod', DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, + message = message) self.dd_dry_bicart_timestamp = timestamp Index: leahi_dialin/dd/modules/events.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/events.py (.../events.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/events.py (.../events.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file events.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Dara Navaei # @date (original) 12-Oct-2021 # ############################################################################ +# Module imports import struct from logging import Logger from datetime import datetime -from time import time +# Project imports from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish @@ -33,7 +36,7 @@ """ UNKNOWN_STATE = "UNKNOWN_PREVIOUS_STATE" - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali CAN Messenger object @@ -43,15 +46,14 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_event = MsgIds.MSG_ID_DD_EVENT.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_event, self._handler_events_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_EVENT.value, + function = self._handler_events_sync) + + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_OP_MODE_DATA.value, + function = self._handler_dd_op_mode_sync) - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_op_mode_data = MsgIds.MSG_ID_DD_OP_MODE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_op_mode_data, - self._handler_dd_op_mode_sync) - self.dd_events_timestamp = 0.0 #: The timestamp of the last Event message self.dd_event_op_mode = 0 #: The new Operation Mode value self.dd_event_sub_mode = 0 #: The new Operation Sub-Mode value @@ -72,30 +74,13 @@ # Define the dictionaries self._dd_event_dictionary = dict() - self._dd_event_data_type = dict() # Loop through the list of the DD events enums and initial the event dictionary. Each event is a key in the # dictionary and the value is a list. for event in dd_enum_repository.DDEventList: self._dd_event_dictionary[dd_enum_repository.DDEventList(event).name] = [] - # Loop through the list of the event data type enum and update the dictionary - for data_type in dd_enum_repository.DDEventDataTypes: - event_data_type = dd_enum_repository.DDEventDataTypes(data_type).name - struct_unpack_type = None - # If U32 is in the data type enum (i.e. EVENT_DATA_TYPE_U32), then the key is the enum and the value is - # the corresponding format in the python struct - if 'U32' in event_data_type or 'BOOL' in event_data_type: - struct_unpack_type = 'I' - elif 'S32' in event_data_type: - struct_unpack_type = 'i' - elif 'F32' in event_data_type: - struct_unpack_type = 'f' - - self._dd_event_data_type[event_data_type] = struct_unpack_type - - def get_dd_nth_event(self, event_id, event_number=0): """ Returns the nth requested DD event @@ -170,55 +155,55 @@ sub_state = 0 current_sub_tuple = [] - event_id = struct.unpack('i', bytearray( + event_id = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + # Convert the event ID to enum + event_enum = dd_enum_repository.DDEventList(event_id) - if event_id == dd_enum_repository.DDEventList.DD_EVENT_OPERATION_STATUS.value: + if event_enum is dd_enum_repository.DDEventList.DD_EVENT_OPERATION_STATUS: # Get the data type - event_data_type_1 = struct.unpack('i', bytearray( + event_data_type_1 = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - struct_data_type = self._dd_event_data_type[dd_enum_repository.DDEventDataTypes(event_data_type_1).name] - op_mode = struct.unpack(' current_sub_mode_timestamp: + elif current_timestamp > current_sub_mode_timestamp: # If the previous and current of the last two tuples do not match, then an operation mode transition # has occurred and the previous state is converted from the previous class and the current op mode # is converted from current operation states enum class. @@ -285,13 +268,13 @@ previous_sub_mode_enum_class = self._dd_op_mode_2_sub_mode[previous_sub_mode] event_data_1 = previous_sub_mode_enum_class(event_data_1).name event_data_2 = current_sub_mode_enum_class(event_data_2).name - event_tuple = (datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S.%f'), event_state_name, event_data_1, event_data_2) + event_tuple = (current_timestamp, event_enum.name, event_data_1, event_data_2) - elif event_state_name == dd_enum_repository.DDEventList.DD_EVENT_OPERATION_STATUS.name: - event_tuple = (time(), op_mode, sub_mode, sub_state) + elif event_enum is dd_enum_repository.DDEventList.DD_EVENT_OPERATION_STATUS: + event_tuple = (current_timestamp, op_mode, sub_mode, sub_state) # Update event dictionary - self._dd_event_dictionary[event_state_name].append(event_tuple) + self._dd_event_dictionary[event_enum.name].append(event_tuple) self.dd_events_timestamp = timestamp @@ -304,11 +287,11 @@ @param message: published DD operation mode broadcast message @return: None """ - mode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) - smode = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + msg_list = [] + msg_list.append(('self.dd_event_op_mode', DataTypes.U32)) + msg_list.append(('self.dd_event_sub_mode', DataTypes.U32)) - self.dd_event_op_mode = mode[0] - self.dd_event_sub_mode = smode[0] + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_event_op_mode_timestamp = timestamp Index: leahi_dialin/dd/modules/gen_dialysate.py =================================================================== diff -u -rf0566e1e902b870166c829ec82cd2605efac62b0 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/gen_dialysate.py (.../gen_dialysate.py) (revision f0566e1e902b870166c829ec82cd2605efac62b0) +++ leahi_dialin/dd/modules/gen_dialysate.py (.../gen_dialysate.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file gen_dialysate.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -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_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -32,7 +35,7 @@ Dialysate Delivery (DD) Dialin API sub-class for gen dialysate related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -42,10 +45,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_gen_dialysate_mode_data = MsgIds.MSG_ID_DD_GEN_DIALYSATE_MODE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_gen_dialysate_mode_data, - self._handler_gen_dialysate_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_GEN_DIALYSATE_MODE_DATA.value, + function = self._handler_gen_dialysate_sync) self.dd_gen_dialysate_timestamp = 0 #: The timestamp of the last message self.execution_state = 0 #: The Execution state @@ -66,14 +68,15 @@ @param message: published gen dialysate data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.dialysate_delivery_in_progress = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.dialysate_good_to_deliver = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.target_qd = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + msg_list = [] + msg_list.append(('self.execution_state', DataTypes.U32)) + msg_list.append(('self.dialysate_delivery_in_progress', DataTypes.U32)) + msg_list.append(('self.dialysate_good_to_deliver', DataTypes.U32)) + msg_list.append(('self.target_qd', DataTypes.F32)) + + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_gen_dialysate_timestamp = timestamp Index: leahi_dialin/dd/modules/heaters.py =================================================================== diff -u -rda47fb6cd59dfe360546408c65e1ce152848d7a0 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/heaters.py (.../heaters.py) (revision da47fb6cd59dfe360546408c65e1ce152848d7a0) +++ leahi_dialin/dd/modules/heaters.py (.../heaters.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file heaters.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Dara Navaei # @date (original) 29-May-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ Dialysate Delivery (DD) Dialin API sub-class for heaters related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali CAN Messenger object """ @@ -41,9 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_heaters_data = MsgIds.MSG_ID_DD_HEATERS_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_heaters_data, self._handler_heaters_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_HEATERS_DATA.value, + function = self._handler_heaters_sync) self.dd_heaters_timestamp = 0.0 #: The timestamp of the latest message @@ -91,36 +94,34 @@ @param message: published DD heaters data message @returns none """ - sensor_list =[] - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_DUTY_CYCLE.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D45_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_DUTY_CYCLE.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_TARGET_TEMP.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D45_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_TARGET_TEMP.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_STATE.name]', 'i']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D45_HEAT.name][dd_enum_repository.DDHeaterAttributes.HEAT_STATE.name]', 'i']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.FEED_FORWARD.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.PWM_PERIOD.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.ADJUSTED_TARGET_TEMP.name]', 'f']) - sensor_list.append(['self.dd_heaters[dd_enum_repository.DDHeaterNames.D5_HEAT.name][dd_enum_repository.DDHeaterAttributes.TARGET_TEMP_TD.name]', 'f']) - sensor_list.append(['self.dbg1', 'f']) - sensor_list.append(['self.dbg2', 'f']) - sensor_list.append(['self.dbg3', 'f']) - sensor_list.append(['self.dbg4', 'f']) - sensor_list.append(['self.dbg5', 'f']) - sensor_list.append(['self.dbg6', 'f']) - sensor_list.append(['self.dbg7', 'f']) - sensor_list.append(['self.dbg8', 'f']) - sensor_list.append(['self.dbg9', 'f']) + sensor_list = [] + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_DUTY_CYCLE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D45_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_DUTY_CYCLE, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_TARGET_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D45_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_TARGET_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D45_HEAT, dd_enum_repository.DDHeaterAttributes.HEAT_STATE, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.FEED_FORWARD, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.PWM_PERIOD, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.ADJUSTED_TARGET_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDHeaterNames.D5_HEAT, dd_enum_repository.DDHeaterAttributes.TARGET_TEMP_TD, DataTypes.F32)) + msg_list =[] + msg_list.append(('self.dbg1', DataTypes.F32)) + msg_list.append(('self.dbg2', DataTypes.F32)) + msg_list.append(('self.dbg3', DataTypes.F32)) + msg_list.append(('self.dbg4', DataTypes.F32)) + msg_list.append(('self.dbg5', DataTypes.F32)) + msg_list.append(('self.dbg6', DataTypes.F32)) + msg_list.append(('self.dbg7', DataTypes.F32)) + msg_list.append(('self.dbg8', DataTypes.F32)) + msg_list.append(('self.dbg9', DataTypes.F32)) - i = 1 - for sensor in sensor_list: - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - value = struct.unpack(sensor[1],bytearray(message['message'][start_pos:end_pos]))[0] - if 'nan' in str(value).lower(): - value = 0.0 - exec(f'{sensor[0]} = {value}') - i += 1 + self.process_into_dict(dict_to_update = self.dd_heaters, + decoder_list = sensor_list, + message = message) + self.process_into_vars(decoder_list = msg_list, + message = message, + start_from_byte = len(sensor_list) * DataTypes.U32.size()) self.dd_heaters_timestamp = timestamp Index: leahi_dialin/dd/modules/levels.py =================================================================== diff -u -rb8ea59d46e0b361ffb73e2496770041bb6693e1d -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/levels.py (.../levels.py) (revision b8ea59d46e0b361ffb73e2496770041bb6693e1d) +++ leahi_dialin/dd/modules/levels.py (.../levels.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file levels.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Dara Navaei # @date (original) 29-May-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray @@ -31,7 +34,7 @@ Dialysate Delivery (DD) Dialin API sub-class for levels related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali CAN Messenger object """ @@ -41,9 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_level_data = MsgIds.MSG_ID_DD_LEVEL_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_level_data, self._handler_levels_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_LEVEL_DATA.value, + function = self._handler_levels_sync) self.dd_levels_timestamp = 0 #: The timestamp of the latest message @@ -66,21 +69,21 @@ @returns none """ sensor_list =[] - sensor_list.append((dd_enum_repository.DDLevelSensorNames.D46_LEVEL, 'i')) - sensor_list.append((dd_enum_repository.DDLevelSensorNames.D63_LEVEL, 'i')) - sensor_list.append((dd_enum_repository.DDLevelSensorNames.D98_LEVEL, 'i')) - sensor_list.append((dd_enum_repository.DDLevelSensorNames.D6_LEVEL, 'i')) + sensor_list.append((dd_enum_repository.DDLevelSensorNames.D46_LEVEL, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDLevelSensorNames.D63_LEVEL, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDLevelSensorNames.D98_LEVEL, DataTypes.U32)) + sensor_list.append((dd_enum_repository.DDLevelSensorNames.D6_LEVEL, DataTypes.U32)) + msg_list =[] + msg_list.append(('self.dd_bicarb_level', DataTypes.U32)) - i = 1 - for sensor in sensor_list: - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - if i == 5: - self.dd_bicarb_level = struct.unpack('i', bytearray(message['message'][start_pos:end_pos]))[0] - else: - self.dd_level_sensors[sensor[0].name] = struct.unpack(sensor[1], bytearray(message['message'][start_pos:end_pos]))[0] - i += 1 + self.process_into_dict(dict_to_update = self.dd_level_sensors, + decoder_list = sensor_list, + message = message) + self.process_into_vars(decoder_list = msg_list, + message = message, + start_from_byte = len(sensor_list) * DataTypes.U32.size()) + self.dd_levels_timestamp = timestamp Index: leahi_dialin/dd/modules/post_gen_dialysate.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/post_gen_dialysate.py (.../post_gen_dialysate.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/post_gen_dialysate.py (.../post_gen_dialysate.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file post_gen_dialysate.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -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_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish class DDPostGenDialysate(AbstractSubSystem): @@ -31,7 +34,7 @@ Dialysate Delivery (DD) Dialin API sub-class for post gen dialysate related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Leahi Can Messenger object """ @@ -41,10 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_post_gen_dialysate_state_data = MsgIds.MSG_ID_DD_POST_GEN_DIALYSATE_STATE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_post_gen_dialysate_state_data, - self._handler_post_gen_dialysate_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_POST_GEN_DIALYSATE_STATE_DATA.value, + function = self._handler_post_gen_dialysate_sync) self.post_gen_state_timestamp = 0 #: The timestamp of the latest message self.execution_state = 0 #: The execution state @@ -58,9 +60,12 @@ @param message: published post gen dialysate data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + msg_list =[] + msg_list.append(('self.execution_state', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.post_gen_state_timestamp = timestamp Index: leahi_dialin/dd/modules/pre_gen_dialysate.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/pre_gen_dialysate.py (.../pre_gen_dialysate.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/pre_gen_dialysate.py (.../pre_gen_dialysate.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file pre_gen_dialysate.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -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_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish class DDPreGenDialysate(AbstractSubSystem): @@ -31,7 +34,7 @@ Dialysate Delivery (DD) Dialin API sub-class for pre gen dialysate related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Leahi Can Messenger object """ @@ -41,15 +44,13 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_pre_gen_dialysate_state_data = MsgIds.MSG_ID_DD_PRE_GEN_DIALYSATE_STATE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_pre_gen_dialysate_state_data, - self._handler_pre_gen_state_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_PRE_GEN_DIALYSATE_STATE_DATA.value, + function = self._handler_pre_gen_state_sync) - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_pre_gen_dialysate_request_data = MsgIds.MSG_ID_DD_PRE_GEN_DIALYSATE_REQUEST_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_pre_gen_dialysate_request_data, - self._handler_pre_gen_request_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_PRE_GEN_DIALYSATE_REQUEST_DATA.value, + function = self._handler_pre_gen_request_sync) self.pre_gen_state_timestamp = 0 #: The timestamp of the latest Pre-Gen State message self.execution_state = 0 #: The execution state @@ -70,9 +71,12 @@ @param message: published pre gen dialysate data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + msg_list =[] + msg_list.append(('self.execution_state', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.pre_gen_state_timestamp = timestamp @@ -87,17 +91,16 @@ @param message: published pre gen dialysate request message @return: None """ - self.pre_gen_start = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.pre_gen_dial_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.pre_gen_dial_temp = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.pre_gen_acid = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.pre_gen_bicarb = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + msg_list =[] + msg_list.append(('self.pre_gen_start', DataTypes.U32)) + msg_list.append(('self.pre_gen_dial_rate', DataTypes.F32)) + msg_list.append(('self.pre_gen_dial_temp', DataTypes.F32)) + msg_list.append(('self.pre_gen_acid', DataTypes.U32)) + msg_list.append(('self.pre_gen_bicarb', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.pre_gen_request_timestamp = timestamp Index: leahi_dialin/dd/modules/pressure_sensors.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/pressure_sensors.py (.../pressure_sensors.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/pressure_sensors.py (.../pressure_sensors.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,22 +8,24 @@ # @file pressure_sensors.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Sean # @date (original) 14-Apr-2020 # ############################################################################ - -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -32,7 +34,7 @@ DD interface containing pressure related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: The DenaliCANMessenger object """ @@ -41,10 +43,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_pressures_data = MsgIds.MSG_ID_DD_PRESSURES_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_pressures_data, - self._handler_pressures_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_PRESSURES_DATA.value, + function = self._handler_pressures_sync) self.dd_pressures_timestamp = 0 #: The timestamp of the latest message @@ -68,19 +69,18 @@ @param message: published DD pressure data message @return: none """ - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D9_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D66_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D51_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D18_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D41_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.dd_pressures[dd_enum_repository.DDPressureSensorNames.D87_PRES.name] = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + sensor_list =[] + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D9_PRES, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D66_PRES, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D51_PRES, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D18_PRES, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D41_PRES, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDPressureSensorNames.D87_PRES, DataTypes.F32)) + self.process_into_dict(dict_to_update = self.dd_pressures, + decoder_list = sensor_list, + message = message) + self.dd_pressures_timestamp = timestamp Index: leahi_dialin/dd/modules/rinse_pump.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/rinse_pump.py (.../rinse_pump.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/rinse_pump.py (.../rinse_pump.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file rinse_pump.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Jonny Paguio # @date (original) 13-Oct-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_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -32,7 +35,7 @@ Dialysate Delivery (DD) Dialin API sub-class for Rinse Pump related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object """ @@ -42,10 +45,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_rinse_pump_data = MsgIds.MSG_ID_DD_RINSE_PUMP_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_rinse_pump_data, - self._handler_rinse_pump_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_RINSE_PUMP_DATA.value, + function = self._handler_rinse_pump_sync) self.dd_rinse_pump_timestamp = 0 #: The timestamp of the latest message self.d79_state = 0 #: The State of the D79 Pump @@ -63,13 +65,14 @@ @param message: published rinse pump data message @return: None """ - self.d79_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.d79_pump_pwm = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.d79_pump_rpm = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + msg_list =[] + msg_list.append(('self.d79_state', DataTypes.U32)) + msg_list.append(('self.d79_pump_pwm', DataTypes.F32)) + msg_list.append(('self.d79_pump_rpm', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_rinse_pump_timestamp = timestamp Index: leahi_dialin/dd/modules/spent_chamber_fill.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/spent_chamber_fill.py (.../spent_chamber_fill.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/spent_chamber_fill.py (.../spent_chamber_fill.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file spent_chamber_fill.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Jonny Paguio # @date (original) 26-Aug-2025 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish class DDSpentChamberFill(AbstractSubSystem): @@ -30,7 +33,7 @@ Dialysate Delivery (DD) Dialin API sub-class for Spent Chamber Fill related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali Can Messenger object @@ -41,10 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_spent_chamber_fill_data = MsgIds.MSG_ID_DD_SPENT_CHAMBER_FILL_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_spent_chamber_fill_data, - self._handler_spent_chamber_fill_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_SPENT_CHAMBER_FILL_DATA.value, + function = self._handler_spent_chamber_fill_sync) self.dd_spent_chamber_timestamp = 0 #: The timestamp of the latest message self.execution_state = 0 #: The execution state @@ -63,13 +65,14 @@ @param message: published spent chamber fill data message @return: None """ - self.execution_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.switching_period = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.total_spent_chamber_fill_counter = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + msg_list =[] + msg_list.append(('self.execution_state', DataTypes.U32)) + msg_list.append(('self.switching_period', DataTypes.U32)) + msg_list.append(('self.total_spent_chamber_fill_counter', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_spent_chamber_timestamp = timestamp Index: leahi_dialin/dd/modules/temperature_sensors.py =================================================================== diff -u -rc3513cf9ce07af0ba91269c4e5e8cc77d034943f -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/temperature_sensors.py (.../temperature_sensors.py) (revision c3513cf9ce07af0ba91269c4e5e8cc77d034943f) +++ leahi_dialin/dd/modules/temperature_sensors.py (.../temperature_sensors.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,38 +8,40 @@ # @file temperature_sensors.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Dara Navaei # @date (original) 01-Dec-2021 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 class DDTemperatureSensors(AbstractSubSystem): - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): super().__init__() self.can_interface = can_interface self.logger: Logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_temperature_data = MsgIds.MSG_ID_DD_TEMPERATURE_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_temperature_data, - self._handler_temperature_sensors_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_TEMPERATURE_DATA.value, + function = self._handler_temperature_sensors_sync) self.dd_temperatures_timestamp = 0.0 #: The timestamp of the latest message @@ -80,36 +82,33 @@ @returns none """ sensor_list =[] - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D1_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D78_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D4_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D50_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D99_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.BRD_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D16_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D28_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D30_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D44_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D75_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D4_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D50_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D99_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D28_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D30_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D78_AVG_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D9_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D66_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D51_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D18_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D41_TEMP, 'f')) - sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D87_TEMP, 'f')) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D1_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D78_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D4_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D50_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D99_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.BRD_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D16_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D28_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D30_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D44_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D75_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D4_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D50_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D99_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D28_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D30_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D78_AVG_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D9_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D66_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D51_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D18_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D41_TEMP, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDTemperatureSensorNames.D87_TEMP, DataTypes.F32)) - i = 1 - for sensor in sensor_list: - start_pos = eval(f'MsgFieldPositions.START_POS_FIELD_{i}') - end_pos = eval(f'MsgFieldPositions.END_POS_FIELD_{i}') - self.dd_temperatures[sensor[0].name] = struct.unpack(sensor[1],bytearray(message['message'][start_pos:end_pos]))[0] - i += 1 + self.process_into_dict(dict_to_update = self.dd_temperatures, + decoder_list = sensor_list, + message = message) self.dd_temperatures_timestamp = timestamp Index: leahi_dialin/dd/modules/ultrafiltration.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/ultrafiltration.py (.../ultrafiltration.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/ultrafiltration.py (.../ultrafiltration.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,20 +8,23 @@ # @file ultrafiltration.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Micahel Garthwaite # @date (original) 29-Oct-2020 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish class DDUltrafiltration(AbstractSubSystem): @@ -31,7 +34,7 @@ Dialysate Delivery (DD) Dialin API sub-class for post gen dialysate related commands. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Leahi Can Messenger object """ @@ -41,10 +44,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_uf_data = MsgIds.MSG_ID_DD_UF_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_uf_data, - self._handler_ultrafiltration_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_UF_DATA.value, + function = self._handler_ultrafiltration_sync) self.uf_timestamp = 0.0 #: The timestamp of the latest message self.uf_exec_state = 0 #: The Ultrafiltration execution state @@ -63,15 +65,15 @@ @param message: published ultrafiltration data message @return: None """ - self.uf_exec_state = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.uf_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.compensated_uf_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.is_uf_requested = struct.unpack('I', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + msg_list =[] + msg_list.append(('self.uf_exec_state', DataTypes.U32)) + msg_list.append(('self.uf_rate', DataTypes.F32)) + msg_list.append(('self.compensated_uf_rate', DataTypes.F32)) + msg_list.append(('self.is_uf_requested', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.uf_timestamp = timestamp Index: leahi_dialin/dd/modules/valves.py =================================================================== diff -u -rd089b54d2fde7f8c36acce41a47d7acee4ef5da6 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/valves.py (.../valves.py) (revision d089b54d2fde7f8c36acce41a47d7acee4ef5da6) +++ leahi_dialin/dd/modules/valves.py (.../valves.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,23 +8,28 @@ # @file valves.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Peman Montazemi # @date (original) 19-May-2020 # ############################################################################ -import struct -from logging import Logger +# Module imports from collections import OrderedDict +from logging import Logger +import struct +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliMessage, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish from leahi_dialin.utils.conversions import integer_to_bytearray # Valve states @@ -47,7 +52,7 @@ END_POS_SPARE_VALVES_STATES = START_POS_SPARE_VALVES_STATES + 1 END_POS_ALL_VALVES = START_POS_VALVES_STATES + 4 - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ @param can_interface: Denali CAN Messenger object """ @@ -56,9 +61,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_valves_states_data = MsgIds.MSG_ID_DD_VALVES_STATES_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_valves_states_data, self._handler_valves_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_VALVES_STATES_DATA.value, + function = self._handler_valves_sync) self.dd_valves_states_timestamp = 0.0 #: The timestamp of the latest message self.valve_states_all = 0x00000000 #: States of all the vales in binary format @@ -225,10 +230,10 @@ @param message: published DD valves states message @return: none """ - vsa = struct.unpack('I', bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_ALL_VALVES])) + vsa = struct.unpack(DataTypes.U32.unpack_attrib(), bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_ALL_VALVES])) self.valve_states_all = vsa[0] - vst = struct.unpack('H', bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_VALVES_STATES])) + vst = struct.unpack(DataTypes.U16.unpack_attrib(), bytearray(message['message'][self.START_POS_VALVES_STATES:self.END_POS_VALVES_STATES])) # Extract each valve state from U16 valves states using bit-masking self.d14_valv["state"] = self._binary_to_valve_state(vst[0] & 1) self.d52_valv["state"] = self._binary_to_valve_state(vst[0] & 2) @@ -247,7 +252,7 @@ self.d81_valv["state"] = self._binary_to_valve_state(vst[0] & 16384) self.d85_valv["state"] = self._binary_to_valve_state(vst[0] & 32768) - bcv = struct.unpack('B', bytearray(message['message'][self.START_POS_BCV_VALVES_STATES:self.END_POS_BCV_VALVES_STATES])) + bcv = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray(message['message'][self.START_POS_BCV_VALVES_STATES:self.END_POS_BCV_VALVES_STATES])) self.d23_valv["state"] = self._binary_to_valve_state(bcv[0] & 1) self.d19_valv["state"] = self._binary_to_valve_state(bcv[0] & 2) self.d25_valv["state"] = self._binary_to_valve_state(bcv[0] & 4) @@ -257,7 +262,7 @@ self.d26_valv["state"] = self._binary_to_valve_state(bcv[0] & 64) self.d22_valv["state"] = self._binary_to_valve_state(bcv[0] & 128) - spv = struct.unpack('B', bytearray(message['message'][self.START_POS_SPARE_VALVES_STATES:self.END_POS_SPARE_VALVES_STATES])) + spv = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray(message['message'][self.START_POS_SPARE_VALVES_STATES:self.END_POS_SPARE_VALVES_STATES])) self.d88_d79_valv["state"] = self._binary_to_valve_state(spv[0] & 1) self.d83_valv["state"] = self._binary_to_valve_state(spv[0] & 2) self.d91_valv["state"] = self._binary_to_valve_state(spv[0] & 4) @@ -275,7 +280,7 @@ start = self.END_POS_SPARE_VALVES_STATES end = start + 1 for valve_id in self.valves_sensed_states: - valve_state_number = struct.unpack('B', bytearray(message['message'][start:end]))[0] + valve_state_number = struct.unpack(DataTypes.U08.unpack_attrib(), bytearray(message['message'][start:end]))[0] self.valves_sensed_states[valve_id] = valve_state_number start = end end += 1 Index: leahi_dialin/dd/modules/voltages.py =================================================================== diff -u -r20c821bd230fc7689a0275a2918981669ff5cc19 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/modules/voltages.py (.../voltages.py) (revision 20c821bd230fc7689a0275a2918981669ff5cc19) +++ leahi_dialin/dd/modules/voltages.py (.../voltages.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,21 +8,24 @@ # @file voltages.py # # @author (last) Zoltan Miskolci -# @date (last) 07-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Sean Nash # @date (original) 15-Apr-2021 # ############################################################################ -import struct +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.constants import NO_RESET from leahi_dialin.common import dd_enum_repository +from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ Dialysate Delivery (dD) Dialin API sub-class for voltage monitor related commands and data. """ - def __init__(self, can_interface, logger: Logger): + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ DDVoltages constructor """ @@ -40,10 +43,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.dd_sync_broadcast_ch_id - self.msg_id_dd_voltages_data = MsgIds.MSG_ID_DD_VOLTAGES_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, self.msg_id_dd_voltages_data, - self._handler_monitored_voltages_sync) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_VOLTAGES_DATA.value, + function = self._handler_monitored_voltages_sync) self.dd_voltages_timestamp = 0.0 #: The timestamp of the latest message @@ -60,31 +62,19 @@ @param message: published monitored voltages data message @return: none """ - v12 = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) - v33 = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) - v5l = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3])) - v24_1 = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4])) - v24_2 = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5])) - vfc = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6])) - vfa = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7])) - vfp = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_8:MsgFieldPositions.END_POS_FIELD_8])) + sensor_list = [] + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_1_2V, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_3_3V, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_5V_LOGIC, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_24V_1, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_24V_2, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_VCC_V, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_AUX_V, DataTypes.F32)) + sensor_list.append((dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_PVN_V, DataTypes.F32)) - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_1_2V.value] = v12[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_3_3V.value] = v33[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_5V_LOGIC.value] = v5l[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_24V_1.value] = v24_1[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_24V_2.value] = v24_2[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_VCC_V.value] = vfc[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_AUX_V.value] = vfa[0] - self.monitored_voltages[dd_enum_repository.DDMonitoredVoltages.MONITORED_LINE_FPGA_PVN_V.value] = vfp[0] + self.process_into_dict(dict_to_update = self.monitored_voltages, + decoder_list = sensor_list, + message = message) self.dd_voltages_timestamp = timestamp Index: leahi_dialin/dd/proxies/ro_proxy.py =================================================================== diff -u -r18c90a1b2b6c7339bdd192a2d2fac32f2b8a35df -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/proxies/ro_proxy.py (.../ro_proxy.py) (revision 18c90a1b2b6c7339bdd192a2d2fac32f2b8a35df) +++ leahi_dialin/dd/proxies/ro_proxy.py (.../ro_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -8,17 +8,20 @@ # @file ro_proxy.py # # @author (last) Zoltan Miskolci -# @date (last) 08-Jan-2026 +# @date (last) 04-May-2026 # @author (original) Peter Lucia # @date (original) 02-Apr-2020 # ############################################################################ +# Module imports from logging import Logger +# Project imports from leahi_dialin.common.msg_defs import MsgIds -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem +from leahi_dialin.common.override_templates import cmd_generic_override +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem from leahi_dialin.utils.conversions import integer_to_bytearray, float_to_bytearray @@ -53,9 +56,12 @@ stt = integer_to_bytearray(start) rtt = float_to_bytearray(ro_rate) payload = cmd + stt + rtt - message = DenaliMessage.build_message(channel_id=DenaliChannels.dd_to_ro_ch_id, - message_id=MsgIds.MSG_ID_DD_FP_START_STOP_CMD_REQUEST.value, - payload=payload) - self.logger.debug("Sending DD start stop request to RO.") - self.can_interface.send(message, 0) + cmd_generic_override(payload = payload, + reset = None, + channel_id = DenaliChannels.dd_to_ro_ch_id, + msg_id = MsgIds.MSG_ID_DD_FP_START_STOP_CMD_REQUEST, + entity_name = 'DD Start Stop Request to RO', + override_text = 'N/A', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/dd/proxies/td_proxy.py =================================================================== diff -u -r47a803c6dd859a5bcc7a6c82e0cb160c350473ea -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/dd/proxies/td_proxy.py (.../td_proxy.py) (revision 47a803c6dd859a5bcc7a6c82e0cb160c350473ea) +++ leahi_dialin/dd/proxies/td_proxy.py (.../td_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -7,20 +7,23 @@ # # @file td_proxy.py # -# @author (last) Micahel Garthwaite -# @date (last) 18-Aug-2023 +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026ks # @author (original) Peter Lucia # @date (original) 02-Apr-2020 # ############################################################################ -import struct +# Module imports from logging import Logger -from leahi_dialin.common.msg_defs import MsgIds, MsgFieldPositions +# Project imports +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MsgIds from leahi_dialin.common.override_templates import cmd_generic_override -from leahi_dialin.protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels -from leahi_dialin.utils.base import AbstractSubSystem, publish +from leahi_dialin.protocols.CAN import DenaliCanMessenger, DenaliChannels +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 @@ -40,10 +43,9 @@ self.logger = logger if self.can_interface is not None: - channel_id = DenaliChannels.td_to_dd_ch_id - msg_id = MsgIds.MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA.value - self.can_interface.register_receiving_publication_function(channel_id, msg_id, - self._handler_dialysate_delivery_request_response) + self.can_interface.register_receiving_publication_function(channel_id = DenaliChannels.td_to_dd_ch_id, + message_id = MsgIds.MSG_ID_DD_GEN_DIALYSATE_REQUEST_DATA.value, + function = self._handler_dialysate_delivery_request_response) self.dialysate_delivery_request_start = 0 self.dialysate_delivery_request_dial_rate = 0.0 @@ -68,21 +70,18 @@ @param message: published dialysate delivery request response data message @return: None """ - self.dialysate_delivery_request_start = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] - self.dialysate_delivery_request_dial_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] - self.dialysate_delivery_request_uf_rate = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] - self.dialysate_delivery_request_dial_temp = struct.unpack('f', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] - self.dialysate_delivery_request_bypass = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] - self.dialysate_delivery_request_acid = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] - self.dialysate_delivery_request_bicarb = struct.unpack('i', bytearray( - message['message'][MsgFieldPositions.START_POS_FIELD_7:MsgFieldPositions.END_POS_FIELD_7]))[0] + msg_list =[] + msg_list.append(('self.dialysate_delivery_request_start', DataTypes.U32)) + msg_list.append(('self.dialysate_delivery_request_dial_rate', DataTypes.F32)) + msg_list.append(('self.dialysate_delivery_request_uf_rate', DataTypes.F32)) + msg_list.append(('self.dialysate_delivery_request_dial_temp', DataTypes.F32)) + msg_list.append(('self.dialysate_delivery_request_bypass', DataTypes.U32)) + msg_list.append(('self.dialysate_delivery_request_acid', DataTypes.U32)) + msg_list.append(('self.dialysate_delivery_request_bicarb', DataTypes.U32)) + self.process_into_vars(decoder_list = msg_list, + message = message) + self.dd_td_to_dd_request_response_timestamp = timestamp Index: leahi_dialin/protocols/CAN.py =================================================================== diff -u -r779949e7648b7957c57ad970c4056e91abc0819d -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/protocols/CAN.py (.../CAN.py) (revision 779949e7648b7957c57ad970c4056e91abc0819d) +++ leahi_dialin/protocols/CAN.py (.../CAN.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -24,16 +24,13 @@ from can.interfaces import socketcan import math from time import sleep -from datetime import datetime import sys from logging import Logger import struct -from .. import common -from ..common import MsgIds, msg_defs +from ..common import MsgIds, MSG_HEADER_SIZE, ACK_NOT_REQUIRED from ..utils import SingletonMeta, IntervalTimer from concurrent.futures import ThreadPoolExecutor -import os class DenaliMessage: BYTE_ORDER = 'little' @@ -42,7 +39,7 @@ MSG_SEQ_INDEX = 1 MSG_ID_INDEX = 3 PAYLOAD_LENGTH_INDEX = 5 - PAYLOAD_START_INDEX = 6 + PAYLOAD_START_INDEX = MSG_HEADER_SIZE PAYLOAD_LENGTH_FIRST_PACKET = 1 HEADER_LENGTH = 6 PACKET_LENGTH = 8 @@ -107,7 +104,7 @@ seq = cls._seq_num - if message_id not in common.msg_defs.ACK_NOT_REQUIRED: + if message_id not in ACK_NOT_REQUIRED: seq *= -1 message_seq_in_bytes = seq.to_bytes(2, byteorder=DenaliMessage.BYTE_ORDER, signed=True) @@ -297,7 +294,7 @@ message = DenaliMessage.build_message( channel_id=channel_id_tx, - message_id=common.msg_defs.MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, + message_id=MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, payload=payload, seq=-seq) Index: leahi_dialin/utils/abstract_classes.py =================================================================== diff -u --- leahi_dialin/utils/abstract_classes.py (revision 0) +++ leahi_dialin/utils/abstract_classes.py (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -0,0 +1,128 @@ +########################################################################### +# +# Copyright (c) 2020-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 abstract_classes.py +# +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026 +# @author (original) Zoltan Miskolci +# @date (original) 04-May-2026 +# +############################################################################ + +# Module imports +from abc import ABC, abstractmethod +from typing import List, Tuple +import struct + +# Project imports +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import MSG_HEADER_SIZE + + +class AbstractObserver(ABC): + """ + Publicly accessible parent class for all observers. + + The update method will receive data when data is made available + """ + + @abstractmethod + def update(self): + """ + Attach an observer + """ + pass + + +class AbstractSubSystem: + + @abstractmethod + def __init__(self): + """ + Initialization function for the sub system + # The abstract base class requires all abstract methods are overridden by children classes + """ + self._observers = [] + self._datetime_fmt = "%m.%d.%Y_%I.%M.%S.%f" + pass + + + def attach(self, observer: AbstractObserver): + """ + Attach an observer so it is updated upon published events + """ + self._observers.append(observer) + + + def detach(self, observer: AbstractObserver): + """ + Detach an observer + """ + self._observers.remove(observer) + + + def process_into_vars(self, decoder_list: List[Tuple], message, start_from_byte: int=0) -> dict: + """ + Process the CAN message with the help of the decoder list into variables. + + :param decoder_list: (List[Tuple[String, DataTypes]]) Contains the variable name and DataType pair of the indexed message + :param message: (Bytearray) The raw CAN message + :param start_from_byte: (Integer) Start from the nth byte after the header + :return: (Dictionary) A dictionary for the variable_name and value pair + """ + start_pos = MSG_HEADER_SIZE + start_from_byte + results = {} + for decode_details in decoder_list: + # Content of the decode list + variable_name = decode_details[0] + datatype: DataTypes = decode_details[-1] + + end_pos = start_pos + datatype.size() + value = struct.unpack(datatype.unpack_attrib(), bytearray(message['message'][start_pos:end_pos]))[0] + if 'nan' in str(value).lower(): + raise ValueError(f'{value} is not an accepted value!') + if datatype is DataTypes.BOOL: + value = True if value == 1 else False + results[variable_name] = value + exec(f'{variable_name} = {value}') + start_pos = end_pos + return results + + + def process_into_dict(self, dict_to_update: dict, decoder_list: List[Tuple], message, start_from_byte: int=0) -> dict: + """ + Process the CAN message with the help of the decoder list into a dictionary. + + :param decoder_list: (List[Tuple[DialEnum, DialEnum, DataTypes]]) Contains the dictioarny key names and DataType of the indexed message + :param message: (Bytearray) The raw CAN message + :param start_from_byte: (Integer) Start from the nth byte after the header + :return: (Dictionary) The updated dictionary + """ + start_pos = MSG_HEADER_SIZE + start_from_byte + for decode_details in decoder_list: + # Content of the decode list + key_1_enum = decode_details[0] + key_2_enum = decode_details[1] if len(decode_details) >= 3 else None + datatype: DataTypes = decode_details[-1] + + end_pos = start_pos + datatype.size() + value = struct.unpack(datatype.unpack_attrib(), bytearray(message['message'][start_pos:end_pos]))[0] + if 'nan' in str(value).lower(): + raise ValueError(f'{value} is not an accepted value!') + + # If the type is Bool, convert the value from Integer to Boolean + if datatype is DataTypes.BOOL: + value = True if value == 1 else False + + # Save the value into the Dictionary + if len(decode_details) == 2: + dict_to_update[key_1_enum.name] = value + elif len(decode_details) == 3: + dict_to_update[key_1_enum.name][key_2_enum.name] = value + start_pos = end_pos + return dict_to_update Index: leahi_dialin/utils/base.py =================================================================== diff -u -r41de945f9c773e54e965e80d9e46def828beb732 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/utils/base.py (.../base.py) (revision 41de945f9c773e54e965e80d9e46def828beb732) +++ leahi_dialin/utils/base.py (.../base.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -15,31 +15,17 @@ ############################################################################ import logging import os -from abc import ABC, abstractmethod from datetime import datetime -from enum import Enum from threading import Timer + INTERVAL_1s = 1 INTERVAL_5s = 5 INTERVAL_10s = 10 INTERVAL_60s = 60 -class AbstractObserver(ABC): - """ - Publicly accessible parent class for all observers. - The update method will receive data when data is made available - """ - @abstractmethod - def update(self): - """ - Attach an observer - """ - pass - - class _FauxLogger: def __init__(self, printing_enabled=False): @@ -206,31 +192,6 @@ return "{0}{1}{2}".format(path, i, ext) -class AbstractSubSystem: - - @abstractmethod - def __init__(self): - """ - Initialization function for the sub system - # The abstract base class requires all abstract methods are overridden by children classes - """ - self._observers = [] - self._datetime_fmt = "%m.%d.%Y_%I.%M.%S.%f" - pass - - def attach(self, observer: AbstractObserver): - """ - Attach an observer so it is updated upon published events - """ - self._observers.append(observer) - - def detach(self, observer: AbstractObserver): - """ - Detach an observer - """ - self._observers.remove(observer) - - def publish(keys): """ Decorator that accepts a list of variable names to publish @@ -267,50 +228,6 @@ return _decorator -class DialinEnum(Enum): - - @classmethod - def has_value(cls, value): - return value in cls._value2member_map_ - - @classmethod - def from_str(cls, label: str): - for enum_member in cls.__members__.values(): - # If the string matching with the enum's name - if label.lower() == enum_member.name.lower(): - return enum_member - # Replace _ with ' ' and check again - elif label.lower().replace('_', ' ') == enum_member.name.lower().replace('_', ' '): - return enum_member - # If the string matching with the enum's state without the 'mode_' text - elif label.lower() == enum_member.name.lower().replace('mode_', ''): - return enum_member - # If it's in the string list provided for the enum - elif enum_member.name in cls._str_list and label.lower() in cls._str_list[enum_member.name]: - return enum_member - # Replace _ with ' ' and check the list again - elif enum_member.name in cls._str_list and label.lower().replace('_', ' ') in cls._str_list[enum_member.name]: - return enum_member - # Replace _ with ' ' and check the list again with _ with ' ' - elif enum_member.name in cls._str_list and label.lower().replace('_', ' ') in [enum_mem.lower().replace('_', ' ') for enum_mem in cls._str_list[enum_member.name] ]: - return enum_member - # If the enum is the NUM_ collector, then return stop as after that only aliases are present - elif enum_member.name.lower().startswith('num_'): - return None - return None - - -class AlarmEnum(Enum): - def __init__(self, *args): - cls = self.__class__ - if any(self.value == member.value for member in cls): - raise ValueError("aliases not allowed: %r --> %r" % (self.name, cls(self.value).name)) - - @classmethod - def has_value(cls, value): - return value in cls._value2member_map_ - - class IntervalTimer(object): """ A class object that is used to execute a function on a timed interval. @@ -341,16 +258,3 @@ def stop(self): self._timer.cancel() self.is_running = False - - -class InternalEvent: - def __init__(self): - self._listeners = [] - - def add_listener(self, func): - self._listeners.append(func) - return func - - def trigger(self, *args, **kwargs): - for func in self._listeners: - func(*args, **kwargs) Index: leahi_dialin/utils/enums/__init__.py =================================================================== diff -u --- leahi_dialin/utils/enums/__init__.py (revision 0) +++ leahi_dialin/utils/enums/__init__.py (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -0,0 +1,23 @@ +import os +import json + +# mandatory import +# none + +file_name = "config.json" +sw_key = "SW" +config = {} +ok: bool = False +module_name = os.path.basename(os.path.dirname(__file__)) + +try: + with open(file_name, 'r') as file: config = json.load(file); ok = config[sw_key] +except FileNotFoundError: pass +except KeyError : print(f"Error ({module_name}): The key '{sw_key}' was not found." ) +except Exception as e : print(f"Error ({module_name}): An unexpected error occurred: {e}" ) + +if ok: + print(f"{sw_key} is set to bypass the auto imports in '{module_name}' module.") +else: + from .alarm_enum import AlarmEnum + from .dialin_enum import DialinEnum Index: leahi_dialin/utils/enums/alarm_enum.py =================================================================== diff -u --- leahi_dialin/utils/enums/alarm_enum.py (revision 0) +++ leahi_dialin/utils/enums/alarm_enum.py (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -0,0 +1,29 @@ +########################################################################### +# +# Copyright (c) 2020-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 alarm_enum.py +# +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026 +# @author (original) Zoltan Miskolci +# @date (original) 04-May-2026 +# +############################################################################ + +# Module imports +from enum import Enum + + +class AlarmEnum(Enum): + def __init__(self, *args): + cls = self.__class__ + if any(self.value == member.value for member in cls): + raise ValueError("aliases not allowed: %r --> %r" % (self.name, cls(self.value).name)) + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ Index: leahi_dialin/utils/enums/dialin_enum.py =================================================================== diff -u --- leahi_dialin/utils/enums/dialin_enum.py (revision 0) +++ leahi_dialin/utils/enums/dialin_enum.py (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -0,0 +1,51 @@ +########################################################################### +# +# Copyright (c) 2020-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 dialin_enum.py +# +# @author (last) Zoltan Miskolci +# @date (last) 04-May-2026 +# @author (original) Zoltan Miskolci +# @date (original) 04-May-2026 +# +############################################################################ + +# Module imports +from enum import Enum + + +class DialinEnum(Enum): + + @classmethod + def has_value(cls, value): + return value in cls._value2member_map_ + + @classmethod + def from_str(cls, label: str): + for enum_member in cls.__members__.values(): + # If the string matching with the enum's name + if label.lower() == enum_member.name.lower(): + return enum_member + # Replace _ with ' ' and check again + elif label.lower().replace('_', ' ') == enum_member.name.lower().replace('_', ' '): + return enum_member + # If the string matching with the enum's state without the 'mode_' text + elif label.lower() == enum_member.name.lower().replace('mode_', ''): + return enum_member + # If it's in the string list provided for the enum + elif enum_member.name in cls._str_list and label.lower() in cls._str_list[enum_member.name]: + return enum_member + # Replace _ with ' ' and check the list again + elif enum_member.name in cls._str_list and label.lower().replace('_', ' ') in cls._str_list[enum_member.name]: + return enum_member + # Replace _ with ' ' and check the list again with _ with ' ' + elif enum_member.name in cls._str_list and label.lower().replace('_', ' ') in [enum_mem.lower().replace('_', ' ') for enum_mem in cls._str_list[enum_member.name] ]: + return enum_member + # If the enum is the NUM_ collector, then return stop as after that only aliases are present + elif enum_member.name.lower().startswith('num_'): + return None + return None Index: leahi_dialin/utils/nv_ops_utils.py =================================================================== diff -u -r41de945f9c773e54e965e80d9e46def828beb732 -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- leahi_dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision 41de945f9c773e54e965e80d9e46def828beb732) +++ leahi_dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -21,7 +21,8 @@ from typing import List from collections import OrderedDict from .excel_ops import * -from leahi_dialin.utils.base import AbstractObserver, DialinEnum +from leahi_dialin.utils.abstract_classes import AbstractObserver +from leahi_dialin.utils.enums import DialinEnum @unique Index: tools/build_common_defs.py =================================================================== diff -u -r18c90a1b2b6c7339bdd192a2d2fac32f2b8a35df -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 --- tools/build_common_defs.py (.../build_common_defs.py) (revision 18c90a1b2b6c7339bdd192a2d2fac32f2b8a35df) +++ tools/build_common_defs.py (.../build_common_defs.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) @@ -167,7 +167,7 @@ cpp_header="AlarmDefs.h", code_prepend= ("\n" "from enum import unique\n" - "from ..utils.base import AlarmEnum\n"), + "from ..utils.enums import AlarmEnum\n"), code_class_def=("\n\n" "# Branch: {0}\n" "@unique\n" @@ -189,7 +189,7 @@ cpp_header="MsgDefs.h", code_prepend= ("\n" "from enum import unique\n" - "from ..utils.base import DialinEnum\n"), + "from ..utils.enums import DialinEnum\n"), code_class_def=("\n\n" "# Branch: {0}\n" "@unique\n"