Index: leahi_dialin/common/dd_defs.py =================================================================== diff -u -r7ec1428451adfb2aabf7a64794e818a9916250c7 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 7ec1428451adfb2aabf7a64794e818a9916250c7) +++ leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -707,7 +707,7 @@ @unique -class DDBicartChFFillExecStates(DialinEnum): +class DDBicarbChFillExecStates(DialinEnum): BICARB_CHAMBER_START_STATE = 0 # Initial state of Chamber F fill BICARB_CARTRIDGE_FILL_WATER_START_STATE = 1 # Dry bicart fill water start state while dialysate delivery BICARB_CARTRIDGE_FILL_WATER_END_STATE = 2 # Dry bicart fill water end state while dialysate delivery @@ -718,7 +718,7 @@ BICARB_SUPPLY_VENT_END_STATE = 7 # Bicarb Chamber supply vent cartridge and Chamber F end state NUM_OF_BICARB_CHAMBER_FILL_EXEC_STATES = 8 # Number of Bicarb chamber fill state -DDBicartChFFillExecStates._str_list = { +DDBicarbChFillExecStates._str_list = { # Official Name : Accepted strings 'BICARB_CHAMBER_START_STATE': ['start'], 'BICARB_CARTRIDGE_FILL_WATER_START_STATE': ['cartridge fill start', 'cartridge priming start'], Index: leahi_dialin/common/dd_defs_proxy.py =================================================================== diff -u -rd10bf8fc145e54979dbeadaedfbaccf0f45d8234 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/common/dd_defs_proxy.py (.../dd_defs_proxy.py) (revision d10bf8fc145e54979dbeadaedfbaccf0f45d8234) +++ leahi_dialin/common/dd_defs_proxy.py (.../dd_defs_proxy.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -64,7 +64,7 @@ DDConcentratePumpAttributes = dd_defs.DDConcentratePumpAttributes DDConcentratePumpStates = dd_defs.DDConcentratePumpStates DDDialysatePumpAttributes = dd_defs.DDDialysatePumpAttributes - DDDialysatePumpsStates = dd_defs.DDDialysatePumpsStates + DDDialysatePumpStates = dd_defs.DDDialysatePumpStates DDDryBicartDrainExecStates = dd_defs.DDDryBicartDrainExecStates DDDryBicartFillExecStates = dd_defs.DDDryBicartFillExecStates DDHeaterStartStop = dd_defs.DDHeaterStartStop Index: leahi_dialin/common/td_defs.py =================================================================== diff -u -r43f69b19f03145572d88f5f3c0cc739503c6d647 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/common/td_defs.py (.../td_defs.py) (revision 43f69b19f03145572d88f5f3c0cc739503c6d647) +++ leahi_dialin/common/td_defs.py (.../td_defs.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -742,35 +742,39 @@ TD_EVENT_STARTUP = 0 # TD startup event TD_EVENT_OP_MODE_CHANGE = 1 # TD Op mode change event TD_EVENT_SUB_MODE_CHANGE = 2 # TD Op sub-mode change event - TD_EVENT_DRY_SELF_TEST_CARTRIDGE_RESULT = 3 # TD dry self test cartridge result - TD_EVENT_DRY_SELF_TEST_PRESSURE_RESULT = 4 # TD dry self test pressure result - TD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT = 5 # TD wet self test displacement result - TD_EVENT_CPU_RAM_ERROR_STATUS = 6 # TD CPU RAM error status - TD_EVENT_CAL_RECORD_UPDATE = 7 # TD new calibration record updated - TD_EVENT_SYSTEM_RECORD_UPDATE = 8 # TD new system record has been updated - TD_EVENT_SERVICE_UPDATE = 9 # TD new service record has been updated - TD_EVENT_USAGE_INFO_UPDATE = 10 # TD new usage information has been updated - TD_EVENT_SW_CONFIG_UPDATE = 11 # TD new software configuration has been updated - TD_EVENT_BUTTON = 12 # TD button pressed/released - TD_EVENT_SAFETY_LINE = 13 # TD safety line pulled/released - TD_EVENT_SUB_STATE_CHANGE = 14 # TD Op sub-state change event - TD_EVENT_RSRVR_UF_RATE = 15 # TD ultrafiltration measured and expected rates - TD_EVENT_OPERATION_STATUS = 16 # TD operation status event. - TD_EVENT_AIR_TRAP_FILL = 17 # TD initiated an air trap fill (opened VBT briefly). - TD_EVENT_AIR_TRAP_LOWER = 18 # TD started/stopped an air trap lower level operation - TD_EVENT_AIR_PUMP_ON_OFF = 19 # TD turned air pump on or off. - TD_EVENT_DRY_SELF_TEST_PRESSURE_DECAY_WAIT_PERIOD = 20 # TD dry self test pressure decay wait period - TD_EVENT_INSTIT_RECORD_UPDATE = 21 # TD new institutional record has been updated. - TD_EVENT_VALVE_POS_CHANGE = 22 # TD pinch valve position change - TD_EVENT_VALVE_HOMED_POS_SETTING = 23 # TD pinch valve homed encoder positions for A/B/C - NUM_OF_EVENT_IDS = 24 # Total number of TD events + TD_EVENT_DRY_SELF_TEST_TUBESET_RESULT = 3 # TD dry self test cartridge result + TD_EVENT_TUBING_SET_BARCODE_SCAN_REQUEST = 4 # TD tubing set barcode scan request + TD_EVENT_TUBING_SET_BARCODE_SCAN_AUTHENTICATED = 5 # TD tubing set barcode scan authenticated + TD_EVENT_DRY_SELF_TEST_PRESSURE_RESULT = 6 # TD dry self test pressure result + TD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT = 7 # TD wet self test displacement result + TD_EVENT_CPU_RAM_ERROR_STATUS = 8 # TD CPU RAM error status + TD_EVENT_CAL_RECORD_UPDATE = 9 # TD new calibration record updated + TD_EVENT_SYSTEM_RECORD_UPDATE = 10 # TD new system record has been updated + TD_EVENT_SERVICE_UPDATE = 11 # TD new service record has been updated + TD_EVENT_USAGE_INFO_UPDATE = 12 # TD new usage information has been updated + TD_EVENT_SW_CONFIG_UPDATE = 13 # TD new software configuration has been updated + TD_EVENT_BUTTON = 14 # TD button pressed/released + TD_EVENT_SAFETY_LINE = 15 # TD safety line pulled/released + TD_EVENT_SUB_STATE_CHANGE = 16 # TD Op sub-state change event + TD_EVENT_RSRVR_UF_RATE = 17 # TD ultrafiltration measured and expected rates + TD_EVENT_OPERATION_STATUS = 18 # TD aggregated opmode, submode, and substate event. + TD_EVENT_AIR_TRAP_FILL = 19 # TD started/stopped an air trap fill operation. + TD_EVENT_AIR_TRAP_LOWER = 20 # TD started/stopped an air trap lower level operation. + TD_EVENT_AIR_PUMP_ON_OFF = 21 # TD turned air pump on/off. + TD_EVENT_INSTIT_RECORD_UPDATE = 22 # TD new institutional record has been updated. + TD_EVENT_VALVE_POS_CHANGE = 23 # TD pinch valve position change + TD_EVENT_VALVE_HOMED_POS_SETTING = 24 # TD pinch valve homed encoder positions for A/B/C. + TD_EVENT_SYRINGE_PUMP_STATE = 25 # TD syringe pump state change event + NUM_OF_EVENT_IDS = 26 # Total number of TD events TDEventList._str_list = { # Official Name : Accepted strings 'TD_EVENT_STARTUP': ['startup'], 'TD_EVENT_OP_MODE_CHANGE': ['op mode change', 'operation mode change'], 'TD_EVENT_SUB_MODE_CHANGE': ['sub mode change'], - 'TD_EVENT_DRY_SELF_TEST_CARTRIDGE_RESULT': ['dry self test cartridge result'], + 'TD_EVENT_DRY_SELF_TEST_TUBESET_RESULT': ['dry self test tubeset result'], + 'TD_EVENT_TUBING_SET_BARCODE_SCAN_REQUEST': ['barcode authentication request'], + 'TD_EVENT_TUBING_SET_BARCODE_SCAN_AUTHENTICATED': ['barcode authentication result'], 'TD_EVENT_DRY_SELF_TEST_PRESSURE_RESULT': ['dry self test pressure result'], 'TD_EVENT_WET_SELF_TEST_DISPLACEMENT_RESULT': ['wet self test displacement result'], 'TD_EVENT_CPU_RAM_ERROR_STATUS': ['cpu ram error'], @@ -791,6 +795,7 @@ 'TD_EVENT_INSTIT_RECORD_UPDATE': ['instit record update', 'institutional record update'], 'TD_EVENT_VALVE_POS_CHANGE': ['valve position change', 'valve pos change'], 'TD_EVENT_VALVE_HOMED_POS_SETTING': ['valve homed to positions'], + 'TD_EVENT_SYRINGE_PUMP_STATE': ['syringe pump state'], 'NUM_OF_EVENT_IDS': [], } Index: leahi_dialin/dd/modules/events.py =================================================================== diff -u -r3f4937e339925dde0b95f08e49969f8983c5cba4 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/dd/modules/events.py (.../events.py) (revision 3f4937e339925dde0b95f08e49969f8983c5cba4) +++ leahi_dialin/dd/modules/events.py (.../events.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -17,6 +17,7 @@ # Module imports from logging import Logger from datetime import datetime +from typing import Tuple # Project imports from leahi_dialin.common import dd_enum_repository @@ -25,6 +26,7 @@ from leahi_dialin.protocols.CAN import CanMessenger, CanChannels from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars from leahi_dialin.utils.base import publish +from leahi_dialin.utils.enums import DialinEnum class DDEvents(AbstractSubSystem): @@ -49,7 +51,7 @@ self.events_timestamp = 0.0 #: The timestamp of the last Event message - # Dictionary of the mode as key and the sub mode states enum class as the value + # Dictionary of the mode as key and the sub mode enum class as the value self._op_mode_2_sub_mode = {dd_enum_repository.DDOpModes.MODE_FAUL.name: dd_enum_repository.DDFaultStates, dd_enum_repository.DDOpModes.MODE_SERV.name: dd_enum_repository.DDServiceStates, dd_enum_repository.DDOpModes.MODE_INIT.name: dd_enum_repository.DDInitStates, @@ -62,6 +64,14 @@ dd_enum_repository.DDOpModes.MODE_ROPS.name: dd_enum_repository.DDROPermeateStates, dd_enum_repository.DDOpModes.MODE_NLEG.name: dd_enum_repository.DDNotLegalStates} + # Dictionary of the sub-mode as key and the state enum class as the value + self._sub_mode_2_states = { dd_enum_repository.DDFaultStates.DD_FAULT_STATE_START.name: dd_enum_repository.DDFaultNVDataStates, + dd_enum_repository.DDStandbyStates.DD_STANDBY_MODE_STATE_IDLE.name: dd_enum_repository.DDStanDisinfectStates, + dd_enum_repository.DDPreGenDialysateStates.DD_PRE_GEN_WET_SELF_TEST.name: dd_enum_repository.DDPreGenWetSelfTestStates } + + # Dictionary of the state as key and the sub-state enum class as the value + self._state_2_sub_states = { } + # 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. self._event_dictionary = dict() @@ -208,7 +218,8 @@ event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) elif event_enum is dd_enum_repository.DDEventList.DD_EVENT_OPERATION_STATUS: - event_tuple = (current_timestamp, op_mode.value, sub_mode.value, state.value) + op_mode_enum, sub_mode_enum, state_enum, _ = self._operation_status_match(op_mode=op_mode, sub_mode=sub_mode, state=sub_state) + event_tuple = (current_timestamp, op_mode_enum, sub_mode_enum, state_enum) # Update event dictionary self._event_dictionary[event_enum.name].append(event_tuple) @@ -274,3 +285,27 @@ list_of_events = self._event_dictionary[dd_enum_repository.DDEventList(event_id).name] return list_of_events + + + def _operation_status_match(self, op_mode: int, sub_mode: int=None, state:int=None, sub_state: int=None) -> Tuple[DialinEnum, DialinEnum, DialinEnum, DialinEnum]: + """ + Convert operation status values to enums. + + :param op_mode: (Integer) The operation mode value + :param sub_mode: (Integer) The operation sub mode value + :param state: (Integer) The operation state value + :param sub_state: (Integer) The operation sub state value + :return: Returns the DialinEnum for each provied mode/state + """ + op_mode_enum = dd_enum_repository.TDOpModes(op_mode) + sub_mode_enum = None + state_enum = None + sub_state_enum = None + if sub_mode is not None: + sub_mode_enum = self._op_mode_2_sub_mode[op_mode_enum.name](sub_mode) + if state is not None: + state_enum = self._sub_mode_2_states[sub_mode_enum.name](state) + if sub_state is not None: + sub_state_enum = self._state_2_sub_states[state_enum.name](sub_state) + + return op_mode_enum, sub_mode_enum, state_enum, sub_state_enum Index: leahi_dialin/dd/modules/substitution_pump.py =================================================================== diff -u -refb1d2a271b1b06b7fd133beaa5ab4728e58f610 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/dd/modules/substitution_pump.py (.../substitution_pump.py) (revision efb1d2a271b1b06b7fd133beaa5ab4728e58f610) +++ leahi_dialin/dd/modules/substitution_pump.py (.../substitution_pump.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -15,14 +15,13 @@ ############################################################################ # Module imports -import struct 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 +from leahi_dialin.common.msg_ids import MsgIds from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override from leahi_dialin.protocols.CAN import CanMessenger, CanChannels from leahi_dialin.utils.abstract_classes import AbstractSubSystem @@ -51,7 +50,7 @@ message_id = MsgIds.MSG_ID_DD_SUBSTITUTION_PUMP_DATA.value, function = self._handler_substitution_pump_sync) - #: The substitution pump data in dictionary format + self.dd_substitution_pump_timestamp = 0 #: The timestamp of the latest message self.dd_substitution_pumps = { dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name: { dd_enum_repository.DDSubstitutionPumpAttributes.TARGET_SPEED.name: 0.0, @@ -60,8 +59,24 @@ dd_enum_repository.DDSubstitutionPumpAttributes.MEASURED_SPEED.name: 0.0, } } - self.dd_substitution_pump_timestamp = 0 #: The timestamp of the latest message + + +# ============================================================ Properties ============================================================ + @property + def dd_substitution_pumps(self) -> dict: + """ + The Substitution Pumps data + """ + return self._substitution_pumps + + @dd_substitution_pumps.setter + def dd_substitution_pumps(self, value): + self._substitution_pumps = value + + + +# ============================================================ Handlers ============================================================ @publish(["msg_id_dd_rinse_pump_data", "dd_substitution_pumps", "dd_substitution_pump_timestamp"]) @@ -72,18 +87,18 @@ @param message: published substitution pump data message @return: None """ - substitution_pump_list = [] - substitution_pump_list.append((dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.TARGET_SPEED.name, DataTypes.F32)) - substitution_pump_list.append((dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.CURRENT_SPEED.name, DataTypes.F32)) - substitution_pump_list.append((dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.STATE.name, DataTypes.U32)) - substitution_pump_list.append((dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.MEASURED_SPEED.name, DataTypes.F32)) + msg_list = [] + msg_list.append((self.dd_substitution_pumps, dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.TARGET_SPEED.name, DataTypes.F32)) + msg_list.append((self.dd_substitution_pumps, dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.CURRENT_SPEED.name, DataTypes.F32)) + msg_list.append((self.dd_substitution_pumps, dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.STATE.name, DataTypes.U32)) + msg_list.append((self.dd_substitution_pumps, dd_enum_repository.DDSubstitutionPumpNames.D92_PUMP.name, dd_enum_repository.DDSubstitutionPumpAttributes.MEASURED_SPEED.name, DataTypes.F32)) - self.process_into_dict(dict_to_update = self.dd_substitution_pumps, - decoder_list = substitution_pump_list, - message = message) - + self.process_into_vars(decoder_list = msg_list, message = message) self.dd_substitution_pump_timestamp = timestamp + + +# ============================================================ Overrides and Requests ============================================================ def cmd_substitution_pump_data_publish_interval_override(self, ms: int, reset: int = NO_RESET) -> int: """ Constructs and sends the substitution pump data publish interval override command @@ -104,6 +119,7 @@ logger=self.logger, can_interface=self.can_interface) + def cmd_substitution_pump_set_start_stop(self, pump_id: int, command: int, speed: float) -> int: """ Constructs and sends the substitution pump start stop command @@ -127,5 +143,3 @@ override_text=str(spd), logger=self.logger, can_interface=self.can_interface) - - Index: leahi_dialin/fp/modules/events.py =================================================================== diff -u -r3f4937e339925dde0b95f08e49969f8983c5cba4 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/fp/modules/events.py (.../events.py) (revision 3f4937e339925dde0b95f08e49969f8983c5cba4) +++ leahi_dialin/fp/modules/events.py (.../events.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -14,15 +14,19 @@ # ############################################################################ +# Module imports from logging import Logger from datetime import datetime +from typing import Tuple +# Project imports from leahi_dialin.common import dd_enum_repository, fp_enum_repository from leahi_dialin.common.generic_defs import DataTypes from leahi_dialin.common.msg_ids import MsgIds from leahi_dialin.protocols.CAN import CanMessenger, CanChannels, CanMessenger from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars from leahi_dialin.utils.base import publish +from leahi_dialin.utils.enums import DialinEnum class FPEvents(AbstractSubSystem): @@ -47,7 +51,7 @@ self.events_timestamp = 0.0 #: The timestamp of the last Event message - # Dictionary of the mode as key and the sub mode states enum class as the value + # Dictionary of the mode as key and the sub mode enum class as the value self._op_mode_2_sub_mode = {fp_enum_repository.FPOpModes.MODE_FAUL.name: fp_enum_repository.FPFaultStates, fp_enum_repository.FPOpModes.MODE_SERV.name: fp_enum_repository.FPServiceStates, fp_enum_repository.FPOpModes.MODE_INIT.name: fp_enum_repository.FPPostStates, @@ -58,6 +62,17 @@ fp_enum_repository.FPOpModes.MODE_DEGP.name: fp_enum_repository.FPGenPermeateDefStates, fp_enum_repository.FPOpModes.MODE_NLEG.name: fp_enum_repository.FPNotLegalStates} + # Dictionary of the sub-mode as key and the state enum class as the value + self._sub_mode_2_states = { fp_enum_repository.FPFaultStates.DD_FAULT_STATE_START.name: fp_enum_repository.FPFaultNVDataStates, + fp_enum_repository.FPPreGenPermeateStates.FP_PRE_GENP_INLET_PRES_CHECK.name: fp_enum_repository.FPInletPresCheckStates, + fp_enum_repository.FPPreGenPermeateStates.FP_PRE_GENP_FILTER_FLUSH.name: fp_enum_repository.FPFilterFlushStates, + fp_enum_repository.FPPreGenPermeateStates.FP_PRE_GENP_PERMEATE_FLUSH.name: fp_enum_repository.FPPermeateFlushStates, + fp_enum_repository.FPPreGenPermeateStates.FP_PRE_GENP_CONCENTRATE_FLUSH.name: fp_enum_repository.FPConcentrateFlushStates, + fp_enum_repository.FPPreGenPDefStates.FP_PRE_GENP_DEF_FLUSH.name: fp_enum_repository.FPDefFlushStates } + + # Dictionary of the state as key and the sub-state enum class as the value + self._state_2_sub_states = { } + # Loop through the list of the FP events enums and initial the event dictionary. Each event is a key in the # dictionary and the value is a list. self._event_dictionary = dict() @@ -206,7 +221,8 @@ event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) elif event_enum is fp_enum_repository.FPEventList.FP_EVENT_OPERATION_STATUS: - event_tuple = (current_timestamp, op_mode.value, sub_mode.value, state.value) + op_mode_enum, sub_mode_enum, state_enum, _ = self._operation_status_match(op_mode=op_mode, sub_mode=sub_mode, state=sub_state) + event_tuple = (current_timestamp, op_mode_enum, sub_mode_enum, state_enum) # Update event dictionary self._event_dictionary[event_enum.name].append(event_tuple) @@ -272,3 +288,27 @@ list_of_events = self._event_dictionary[fp_enum_repository.FPEventList(event_id).name] return list_of_events + + + def _operation_status_match(self, op_mode: int, sub_mode: int=None, state:int=None, sub_state: int=None) -> Tuple[DialinEnum, DialinEnum, DialinEnum, DialinEnum]: + """ + Convert operation status values to enums. + + :param op_mode: (Integer) The operation mode value + :param sub_mode: (Integer) The operation sub mode value + :param state: (Integer) The operation state value + :param sub_state: (Integer) The operation sub state value + :return: Returns the DialinEnum for each provied mode/state + """ + op_mode_enum = fp_enum_repository.TDOpModes(op_mode) + sub_mode_enum = None + state_enum = None + sub_state_enum = None + if sub_mode is not None: + sub_mode_enum = self._op_mode_2_sub_mode[op_mode_enum.name](sub_mode) + if state is not None: + state_enum = self._sub_mode_2_states[sub_mode_enum.name](state) + if sub_state is not None: + sub_state_enum = self._state_2_sub_states[state_enum.name](sub_state) + + return op_mode_enum, sub_mode_enum, state_enum, sub_state_enum Index: leahi_dialin/td/modules/air_pump.py =================================================================== diff -u -r43f69b19f03145572d88f5f3c0cc739503c6d647 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/modules/air_pump.py (.../air_pump.py) (revision 43f69b19f03145572d88f5f3c0cc739503c6d647) +++ leahi_dialin/td/modules/air_pump.py (.../air_pump.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -151,3 +151,27 @@ override_text = f'{power_value}', logger = self.logger, can_interface = self.can_interface) + + + def cmd_air_pump_rpm_override(self, rpm: int, reset: int=NO_RESET) -> int: + """ + Constructs and sends the air pump RPM override command. + + Constraints: + Must be logged into TD. + @param rpm: (Integer) The desired RPM value + @return: 1 if successful, zero otherwise + """ + rst = integer_to_bytearray(reset) + spd = integer_to_bytearray(rpm) + payload = rst + spd + + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = CanChannels.dialin_to_td_ch_id, + msg_id = MsgIds.MSG_ID_TD_AIR_PUMP_RPM_OVERRIDE_REQUEST, + entity_name = f'TD Air Pump RPM', + override_text = f'{rpm}', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/td/modules/alarms.py =================================================================== diff -u -rba415df9f8e76d6b0f21e8f69ba99346e42f7b09 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/modules/alarms.py (.../alarms.py) (revision ba415df9f8e76d6b0f21e8f69ba99346e42f7b09) +++ leahi_dialin/td/modules/alarms.py (.../alarms.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -551,19 +551,20 @@ self.alarm_states[x] = False - def get_dialin_alarms(self): + def get_dialin_alarms(self) -> dict: """ Get the active alarms in Dialin. - @return: none + @return: (Dictionary) Active alarms in Dialin """ active_alarms = [] - for x in range(self.alarm_states): - if self.alarm_states[x]: - active_alarms.append(AlarmList(x)) + for alarm in AlarmList: + if self.alarm_states[alarm.value]: + active_alarms.append(alarm) return active_alarms + # ============================================================ Overrides and Requests ============================================================ def cmd_alarm_status_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): """ Index: leahi_dialin/td/modules/buttons.py =================================================================== diff -u -r313abfccbc36a4af235361c7a3961ccf7a74bd8d -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/modules/buttons.py (.../buttons.py) (revision 313abfccbc36a4af235361c7a3961ccf7a74bd8d) +++ leahi_dialin/td/modules/buttons.py (.../buttons.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -21,7 +21,7 @@ # 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.msg_ids import MsgIds from leahi_dialin.common.override_templates import cmd_generic_override from leahi_dialin.protocols.CAN import CanMessenger, CanChannels from leahi_dialin.utils.abstract_classes import AbstractSubSystem @@ -50,18 +50,25 @@ function = self._handler_poweroff_timeout_occurred) self.td_power_off_timestamp = 0.0 #: The timestamp of the last message - self.poweroff_timeout_expired = False #: The Power Off timeout value + self.poweroff_timeout_expired = False - def reset_poweroff_timeout_expired(self): - """ - Resets the dialin poweroff timeout flag to False - @return: None +# ============================================================ Properties ============================================================ + @property + def poweroff_timeout_expired(self) -> dict: """ - self.poweroff_timeout_expired = False + The Power Off timeout value + """ + return self._poweroff_timeout_expired + @poweroff_timeout_expired.setter + def poweroff_timeout_expired(self, value): + self._poweroff_timeout_expired = value + + +# ============================================================ Handlers ============================================================ @publish(['msg_id_off_button_press_request', 'poweroff_timeout_expired', 'td_power_off_timestamp']) def _handler_poweroff_timeout_occurred(self, message, timestamp=0.0): """ @@ -74,17 +81,27 @@ self.logger.debug("Poweroff message id detected, but was the wrong length.") return - msg_list = [] - msg_list.append(('mode', DataTypes.U16)) + msg_list =[] + msg_list.append((type(self).poweroff_timeout_expired, DataTypes.U16)) + + self.process_into_vars(decoder_list = msg_list, message = message) + self.poweroff_timeout_expired = bool(self.poweroff_timeout_expired) + self.td_power_off_timestamp = timestamp - result = self.process_into_vars(decoder_list = msg_list, - message = message) - if len(result['mode']) > 0: - self.poweroff_timeout_expired = bool(result['mode'][0]) - self.td_power_off_timestamp = timestamp +# ============================================================ Support ============================================================ + def reset_poweroff_timeout_expired(self): + """ + Resets the dialin poweroff timeout flag to False + @return: None + """ + self.poweroff_timeout_expired = False + + + +# ============================================================ Overrides and Requests ============================================================ def cmd_off_button_override(self, state: int, reset: int = NO_RESET) -> int: """ Constructs and sends the Off button override command Index: leahi_dialin/td/modules/dry_self_test.py =================================================================== diff -u --- leahi_dialin/td/modules/dry_self_test.py (revision 0) +++ leahi_dialin/td/modules/dry_self_test.py (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -0,0 +1,154 @@ +########################################################################### +# +# 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 buttons.py +# +# @author (last) Zoltan Miskolci +# @date (last) 26-May-2026 +# @author (original) Zoltan Miskolci +# @date (original) 26-May-2026 +# +############################################################################ + +# Module imports +from logging import Logger + +# Project imports +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.common.override_templates import cmd_generic_override +from leahi_dialin.protocols.CAN import CanMessenger, CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish +from leahi_dialin.utils.conversions import integer_to_bytearray + + +class TDDrySelfTest(AbstractSubSystem): + """ + Treatment Delivery (TD) Dialin API sub-class for dry self test related commands. + """ + + def __init__(self, can_interface: CanMessenger, logger: Logger): + """ + Dry Self Test constructor + + @param can_interface: the CAN interface object + """ + super().__init__() + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_TD_DRY_SELF_TEST_PROGRESS_DATA.value, + function = self._handler_progress_data_sync) + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_to_ui_ch_id, + message_id = MsgIds.MSG_ID_TD_TUBE_SET_AUTHENTICATION_REQUEST.value, + function = self._handler_tubing_set_barcode_authentication_request) + + self.td_dry_self_test_timestamp = 0.0 #: The timestamp of the last message + self.substate = 0 + self.timeout = 0 + self.countdown = 0 + + self.td_barcode_auth_request_sent_timestamp = 0.0 #: The timestamp when the TD requested Barcode Authentication from UI + + + +# ============================================================ Properties ============================================================ + @property + def substate(self) -> dict: + """ + The Substate of the Dry Self Test + """ + return self._substate + + @substate.setter + def substate(self, value): + self._substate = value + + @property + def timeout(self) -> dict: + """ + The Timeout value of the Dry Self Test + """ + return self._timeout + + @timeout.setter + def timeout(self, value): + self._timeout = value + + + @property + def countdown(self) -> dict: + """ + The Countdown value of the Dry Self Test + """ + return self._countdown + + @countdown.setter + def countdown(self, value): + self._countdown = value + + + +# ============================================================ Handlers ============================================================ + @publish(['msg_id_td_dry_self_test_progress_data', 'substate', 'timeout', 'countdown']) + def _handler_progress_data_sync(self, message, timestamp=0.0): + """ + Tubing Set Authentication response handler + + @param message: (Bytearray) The occurred message string + @param timestamp: (Float) The timestamp of the message + @return: None + """ + msg_list = [] + msg_list.append((type(self).substate, DataTypes.U32)) + msg_list.append((type(self).timeout, DataTypes.U32)) + msg_list.append((type(self).countdown, DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, message = message) + self.td_dry_self_test_timestamp = timestamp + + + @publish(['msg_id_tubing_set_authentication_request', 'valid_tubing_set', 'modality_match']) + def _handler_tubing_set_barcode_authentication_request(self, message, timestamp=0.0): + """ + Tubing Set Authentication request to UI handler + + @param message: (Bytearray) The occurred message string + @param timestamp: (Float) The timestamp of the message + @return: None + """ + # Send the response automatically to prevent timeout and system going to fault + self.cmd_send_ui_barcode_auth_response() + self.td_barcode_auth_request_sent_timestamp = timestamp + + + +# ============================================================ Overrides and Requests ============================================================ + def cmd_send_ui_barcode_auth_response(self, valid_tubing_set: bool=True, modality_match: bool=True) -> int: + """ + Constructs and sends the UI Barcode Authentication response + + @param valid_tubing_set: (Boolean) If the Tubing Set is valid or not + @param modality_match: (Boolean) If the Tubing Set's Modality is accepted or not + @return: 1 if successful, zero otherwise + """ + payload = integer_to_bytearray(1 if valid_tubing_set else 0) + payload += integer_to_bytearray(1 if modality_match else 0) + print(payload) + + return cmd_generic_override( + payload = payload, + reset = None, + channel_id = CanChannels.ui_to_td_ch_id, + msg_id = MsgIds.MSG_ID_UI_TUBE_SET_AUTHENTICATION_ACK_RESPONSE, + entity_name = f'UI Barcode Authentication Ack response', + override_text = f'Valid: {valid_tubing_set}, Accepted: {modality_match}', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/td/modules/events.py =================================================================== diff -u -r3f4937e339925dde0b95f08e49969f8983c5cba4 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/modules/events.py (.../events.py) (revision 3f4937e339925dde0b95f08e49969f8983c5cba4) +++ leahi_dialin/td/modules/events.py (.../events.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -17,6 +17,7 @@ # Module imports from logging import Logger from datetime import datetime +from typing import Tuple # Project imports from leahi_dialin.common import td_enum_repository @@ -25,6 +26,7 @@ from leahi_dialin.protocols.CAN import CanMessenger, CanChannels from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars from leahi_dialin.utils.base import publish +from leahi_dialin.utils.enums import DialinEnum class TDEvents(AbstractSubSystem): @@ -42,22 +44,46 @@ self.logger = logger if self.can_interface is not None: - self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_sync_broadcast_ch_id, + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.td_to_ui_ch_id, message_id = MsgIds.MSG_ID_TD_EVENT.value, function = self._handler_events_sync) self.events_timestamp = 0.0 #: The timestamp of the last Event message - # Dictionary of the mode as key and the sub mode states enum class as the valued + # Dictionary of the mode as key and the sub mode enum class as the value self._op_mode_2_sub_mode = {td_enum_repository.TDOpModes.MODE_FAUL.name: td_enum_repository.TDFaultStates, td_enum_repository.TDOpModes.MODE_SERV.name: td_enum_repository.TDServiceStates, td_enum_repository.TDOpModes.MODE_INIT.name: td_enum_repository.TDInitStates, td_enum_repository.TDOpModes.MODE_STAN.name: td_enum_repository.TDStandbyStates, td_enum_repository.TDOpModes.MODE_PRET.name: td_enum_repository.TDPreTreatmentModesStates, td_enum_repository.TDOpModes.MODE_TREA.name: td_enum_repository.TDTreatmentStates, td_enum_repository.TDOpModes.MODE_POST.name: td_enum_repository.TDPostTreatmentStates, - td_enum_repository.TDOpModes.MODE_NLEG.name: td_enum_repository.TDNotLegalStates} + td_enum_repository.TDOpModes.MODE_NLEG.name: td_enum_repository.TDNotLegalStates } + # Dictionary of the sub-mode as key and the state enum class as the value + self._sub_mode_2_states = {td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_WATER_SAMPLE_STATE.name: td_enum_repository.TDPreTreaSampleWaterStates, + td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_SELF_TEST_NO_CART_STATE.name: td_enum_repository.TDPreTreaNoCartSelfTestStates, + td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_SELF_TEST_DRY_STATE.name: td_enum_repository.TDPreTreaDrySelfTestStates, + td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_PRIME_STATE.name: td_enum_repository.TDPreTreaPrimeStates, + td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_RECIRCULATE_STATE.name: td_enum_repository.TDPreTreaRecircStates, + td_enum_repository.TDPreTreatmentModesStates.TD_PRE_TREATMENT_PATIENT_CONNECTION_STATE.name: td_enum_repository.TDPreTreaPatientConnectStates, + td_enum_repository.TDTreatmentStates.TREATMENT_BLOOD_PRIME_STATE.name: td_enum_repository.TDTreaBloodPrimeStates, + td_enum_repository.TDTreatmentStates.TREATMENT_DIALYSIS_STATE.name:td_enum_repository.TDTreaDialysisStates, + td_enum_repository.TDTreatmentStates.TREATMENT_PAUSED_STATE.name:td_enum_repository.TDTreaPausedStates, + td_enum_repository.TDTreatmentStates.TREATMENT_RINSEBACK_STATE.name:td_enum_repository.TDTreaRinsebackStates, + td_enum_repository.TDTreatmentStates.TREATMENT_RECIRC_STATE.name:td_enum_repository.TDTreaRecircStates, + td_enum_repository.TDTreatmentStates.TREATMENT_SALINE_BOLUS_STATE.name:td_enum_repository.TDTreaBolusStates, + td_enum_repository.TDTreatmentStates.TREATMENT_HEPARIN_STATE.name:td_enum_repository.TDTreaHeparinStates, + td_enum_repository.TDTreatmentStates.TREATMENT_END_STATE.name:td_enum_repository.TDTreaEndStates } + + # Dictionary of the state as key and the sub state enum class as the value + self._state_2_sub_states = {td_enum_repository.TDPreTreaSampleWaterStates.SAMPLE_WATER_STATE.name: td_enum_repository.TDPreTreaSamplWaterUserActionStates, + td_enum_repository.TDPreTreaPrimeStates.TD_PRIME_WET_SELF_TESTS_STATE.name: td_enum_repository.TDWetSelfTestsStates, + td_enum_repository.TDTreaBloodPrimeStates.BLOOD_PRIME_RUN_STATE.name: td_enum_repository.TDTreaBloodPrimeUserActionStates, + td_enum_repository.TDTreaRinsebackStates.RINSEBACK_RUN_STATE.name: td_enum_repository.TDTreaRinsebackUserActionStates, + td_enum_repository.TDTreaRecircStates.TREATMENT_RECIRC_RECIRC_STATE.name: td_enum_repository.TDTreaRecircUserActionStates, + td_enum_repository.TDTreaEndStates.TREATMENT_END_WAIT_FOR_RINSEBACK_STATE.name: td_enum_repository.TDTreaEndUserActionStates } + # Loop through the list of the TD events enums and initial the event dictionary. Each event is a key in the # dictionary and the value is a list. self._event_dictionary = dict() @@ -204,7 +230,8 @@ event_tuple = (current_timestamp, event_enum.name, data_1.value, data_2.value) elif event_enum is td_enum_repository.TDEventList.TD_EVENT_OPERATION_STATUS: - event_tuple = (current_timestamp, op_mode.value, sub_mode.value, state.value) + op_mode_enum, sub_mode_enum, state_enum, _ = self._operation_status_match(op_mode=op_mode, sub_mode=sub_mode, state=sub_state) + event_tuple = (current_timestamp, op_mode_enum, sub_mode_enum, state_enum) # Update event dictionary self._event_dictionary[event_enum.name].append(event_tuple) @@ -270,3 +297,27 @@ list_of_events = self._event_dictionary[td_enum_repository.TDEventList(event_id).name] return list_of_events + + + def _operation_status_match(self, op_mode: int, sub_mode: int=None, state:int=None, sub_state: int=None) -> Tuple[DialinEnum, DialinEnum, DialinEnum, DialinEnum]: + """ + Convert operation status values to enums. + + :param op_mode: (Integer) The operation mode value + :param sub_mode: (Integer) The operation sub mode value + :param state: (Integer) The operation state value + :param sub_state: (Integer) The operation sub state value + :return: Returns the DialinEnum for each provied mode/state + """ + op_mode_enum = td_enum_repository.TDOpModes(op_mode) + sub_mode_enum = None + state_enum = None + sub_state_enum = None + if sub_mode is not None: + sub_mode_enum = self._op_mode_2_sub_mode[op_mode_enum.name](sub_mode) + if state is not None: + state_enum = self._sub_mode_2_states[sub_mode_enum.name](state) + if sub_state is not None: + sub_state_enum = self._state_2_sub_states[state_enum.name](sub_state) + + return op_mode_enum, sub_mode_enum, state_enum, sub_state_enum Index: leahi_dialin/td/modules/syringe_pump.py =================================================================== diff -u -r43f69b19f03145572d88f5f3c0cc739503c6d647 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/modules/syringe_pump.py (.../syringe_pump.py) (revision 43f69b19f03145572d88f5f3c0cc739503c6d647) +++ leahi_dialin/td/modules/syringe_pump.py (.../syringe_pump.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -38,7 +38,7 @@ def __init__(self, can_interface: CanMessenger, logger: Logger): """ - @param can_interface: Denali Can Messenger object + @param can_interface: Can Messenger object """ super().__init__() self.can_interface = can_interface Index: leahi_dialin/td/proxies/ui_proxy.py =================================================================== diff -u -rba415df9f8e76d6b0f21e8f69ba99346e42f7b09 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/proxies/ui_proxy.py (.../ui_proxy.py) (revision ba415df9f8e76d6b0f21e8f69ba99346e42f7b09) +++ leahi_dialin/td/proxies/ui_proxy.py (.../ui_proxy.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -573,3 +573,35 @@ override_text = 'N/A', logger = self.logger, can_interface = self.can_interface) + + + def cmd_send_ui_cartridge_install_confirm_response (self) -> None: + """ + Constructs and sends a UI response for confirming cartridge installation. + + :return: none + """ + cmd_generic_override(payload = None, + reset = None, + channel_id = CanChannels.ui_to_td_ch_id, + msg_id = MsgIds.MSG_ID_UI_ADJUST_DISPOSABLES_CONFIRM_REQUEST, + entity_name = 'UI Confirm Cartridge Installation response', + override_text = 'N/A', + logger = self.logger, + can_interface = self.can_interface) + + + def cmd_send_ui_cartridge_removal_confirm_response (self) -> None: + """ + Constructs and sends a UI response for confirming cartridge removal. + + :return: none + """ + cmd_generic_override(payload = None, + reset = None, + channel_id = CanChannels.ui_to_td_ch_id, + msg_id = MsgIds.MSG_ID_UI_ADJUST_DISPOSABLES_REMOVAL_CONFIRM_REQUEST, + entity_name = 'UI Confirm Cartridge Removal response', + override_text = 'N/A', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/td/treatment_delivery.py =================================================================== diff -u -r43f69b19f03145572d88f5f3c0cc739503c6d647 -r862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f --- leahi_dialin/td/treatment_delivery.py (.../treatment_delivery.py) (revision 43f69b19f03145572d88f5f3c0cc739503c6d647) +++ leahi_dialin/td/treatment_delivery.py (.../treatment_delivery.py) (revision 862daa5b6357ddaba02aa7d1fb9d0952e4a16e6f) @@ -27,6 +27,7 @@ from .modules.blood_pressure import TDBloodPressure from .modules.bubble_detector import TDBubbleDetector from .modules.buttons import TDButtons +from .modules.dry_self_test import TDDrySelfTest from .modules.ejector import TDEjector from .modules.events import TDEvents from .modules.pressure_sensors import TDPressureSensors @@ -133,6 +134,7 @@ self.blood_pressure = TDBloodPressure(self.can_interface, self.logger) #: The Blood Pressure module self.bubbles = TDBubbleDetector(self.can_interface, self.logger) #: The Bubble Detector module self.buttons = TDButtons(self.can_interface, self.logger) #: The Buttons module + self.dry_self_test = TDDrySelfTest(self.can_interface, self.logger) #: The Dry Self Test module self.ejector = TDEjector(self.can_interface, self.logger) #: The Ejector module self.events = TDEvents(self.can_interface, self.logger) #: The Events module self.pressure_sensors = TDPressureSensors(self.can_interface, self.logger) #: The Pressure Sensors module