Index: dialin/common/msg_ids.py =================================================================== diff -u -r717213478a1176cd315e5f4006ce8aeacbc4c0dc -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 717213478a1176cd315e5f4006ce8aeacbc4c0dc) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -282,12 +282,27 @@ MSG_ID_HD_BLOOD_PRIME_VOLUME_OVERRIDE = 0X805F MSG_ID_HD_BUBBLE_SELF_TEST_REQUEST = 0X8060 MSG_ID_HD_BLOOD_PRIME_SAFETY_VOLUME_OVERRIDE = 0X8061 - MSG_ID_HD_SWITCHES_STATUS_OVERRIDE = 0X8062 - MSG_ID_HD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE = 0X8063 - MSG_ID_HD_BATTERY_REMAINING_PERCENT_OVERRIDE = 0X8064 - MSG_ID_HD_TEMPERATURES_VALUE_OVERRIDE = 0X8065 - MSG_ID_HD_TEMPERATURES_PUBLISH_INTERVAL_OVERRIDE = 0X8066 - MSG_ID_HD_FANS_PUBLISH_INTERVAL_OVERRIDE = 0X8067 + MSG_ID_HD_SWITCHES_STATUS_OVERRIDE = 0x8062 + MSG_ID_HD_SWITCHES_PUBLISH_INTERVAL_OVERRIDE = 0x8063 + MSG_ID_HD_BATTERY_REMAINING_PERCENT_OVERRIDE = 0x8064 + MSG_ID_HD_TEMPERATURES_VALUE_OVERRIDE = 0x8065 + MSG_ID_HD_TEMPERATURES_PUBLISH_INTERVAL_OVERRIDE = 0x8066 + MSG_ID_HD_FANS_PUBLISH_INTERVAL_OVERRIDE = 0x8067 + MSG_ID_HD_FANS_RPM_OVERRIDE = 0x8068 + MSG_ID_HD_RINSEBACK_VOLUME_OVERRIDE = 0x8069 + MSG_ID_HD_RINSEBACK_SAFETY_VOLUME_OVERRIDE = 0x806A + MSG_ID_HD_ALARM_STATUS_PUBLISH_INTERVAL_OVERRIDE = 0x806B + MSG_ID_HD_TREATMENT_TIME_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x806C + MSG_ID_HD_TREATMENT_RANGES_PUBLISH_INTERVAL_OVERRIDE = 0x806D + MSG_ID_HD_TREATMENT_STOP_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x806E + MSG_ID_HD_BLOOD_PRIME_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x806F + MSG_ID_HD_RINSEBACK_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8070 + MSG_ID_HD_STANDBY_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8071 + MSG_ID_HD_OP_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8072 + MSG_ID_HD_PRE_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8073 + MSG_ID_HD_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8074 + MSG_ID_HD_POST_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8075 + MSG_ID_DG_TESTER_LOGIN_REQUEST = 0XA000 MSG_ID_DG_ALARM_STATE_OVERRIDE = 0XA001 MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE = 0XA002 @@ -317,7 +332,7 @@ MSG_ID_DRAIN_PUMP_SET_DELTA_PRESSURE_OVERRIDE = 0XA01C MSG_ID_DG_SWITCHES_STATUS_OVERRIDE = 0XA01D MSG_ID_DG_SWITCHES_PUBLISH_INTERVAL_OVERRIDE = 0XA01E - MSG_ID___AVAILABLE_14 = 0XA01F + MSG_ID_DG_OP_MODE_PUBLISH_INTERVAL_OVERRIDE = 0XA01F MSG_ID___AVAILABLE_15 = 0XA020 MSG_ID___AVAILABLE_16 = 0XA021 MSG_ID_DG_SOFTWARE_RESET_REQUEST = 0XA022 Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rd6a2e3e1821b5c78f81ad71b10f0809eff1181ae -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision d6a2e3e1821b5c78f81ad71b10f0809eff1181ae) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -13,45 +13,46 @@ # @date (original) 02-Apr-2020 # ############################################################################ + +from enum import unique + from .accelerometer import DGAccelerometer from .alarms import DGAlarms +from .calibration_record import DGCalibrationNVRecord +from .chemical_disinfect import ChemicalDisinfect from .concentrate_pumps import ConcentratePumps from .conductivity_sensors import ConductivitySensors from .constants import RESET, NO_RESET from .drain_pump import DGDrainPump -from .fluid_leak import DGFluidLeak from .fans import Fans +from .fluid_leak import DGFluidLeak +from .flush import FlushMode from .hd_proxy import DGHDProxy +from .heat_disinfect import HeatDisinfect from .heaters import Heaters from .load_cells import DGLoadCells from .pressures import DGPressures from .reservoirs import DGReservoirs from .ro_pump import DGROPump +from .rtc import DGRTC from .samplewater import DGSampleWater +from .scheduled_runs_record import DGScheduledRunsNVRecord +from .service_record import DGServiceNVRecord +from .switches import DGSwitches +from .system_record import DGSystemNVRecord from .temperature_sensors import TemperatureSensors from .thermistors import Thermistors from .uv_reactors import UVReactors -from .calibration_record import DGCalibrationNVRecord -from .system_record import DGSystemNVRecord -from .service_record import DGServiceNVRecord -from .scheduled_runs_record import DGScheduledRunsNVRecord from .valves import DGValves from .voltages import DGVoltages -from ..utils import * -from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish, _LogManager, DialinEnum from ..common.msg_defs import MsgIds, MsgFieldPositions -from .flush import FlushMode -from .chemical_disinfect import ChemicalDisinfect -from .heat_disinfect import HeatDisinfect -from .rtc import DGRTC -from .switches import DGSwitches -from enum import unique +from ..protocols.CAN import DenaliCanMessenger, DenaliMessage, DenaliChannels +from ..utils import * +from ..utils.base import AbstractSubSystem, publish, LogManager, DialinEnum @unique class DGOperationModes(DialinEnum): - # DG operation modes DG_OP_MODE_FAULT = 0 DG_OP_MODE_SERVICE = 1 @@ -66,7 +67,7 @@ DG_OP_MODE_CHEMICAL_DISINFECT = 10 -class DG(_AbstractSubSystem): +class DG(AbstractSubSystem): """ Dialysate Generator (DG) Dialin object API. It provides the basic interface to communicate with the DG firmware. @@ -96,14 +97,14 @@ END_POS_FPGA_LAB = START_POS_FPGA_LAB + 1 # DG sub_modes - DG_POST_STATE_START = 0 # Start initialize & POST mode state - DG_POST_STATE_FPGA = 1 # FPGA POST test state - DG_POST_STATE_WATCHDOG = 2 # Watchdog POST test state - DG_POST_STATE_TEMPERATURE_SENSORS = 3 # Temperature Sensors POST state - DG_POST_STATE_HEATERS = 4 # Heaters POST state - DG_POST_STATE_COMPLETED = 5 # POST completed successfully state - DG_POST_STATE_FAILED = 6 # POST failed state - NUM_OF_DG_POST_STATES = 7 # Number of initialize & POST mode states + DG_POST_STATE_START = 0 # Start initialize & POST mode state + DG_POST_STATE_FPGA = 1 # FPGA POST test state + DG_POST_STATE_WATCHDOG = 2 # Watchdog POST test state + DG_POST_STATE_TEMPERATURE_SENSORS = 3 # Temperature Sensors POST state + DG_POST_STATE_HEATERS = 4 # Heaters POST state + DG_POST_STATE_COMPLETED = 5 # POST completed successfully state + DG_POST_STATE_FAILED = 6 # POST failed state + NUM_OF_DG_POST_STATES = 7 # Number of initialize & POST mode states def __init__(self, can_interface="can0", log_level=None): """ @@ -120,7 +121,7 @@ @param can_interface: string with can bus name, e.g. "can0" """ super().__init__() - self._log_manager = _LogManager(log_level=log_level, log_filepath=self.__class__.__name__+".log") + self._log_manager = LogManager(log_level=log_level, log_filepath=self.__class__.__name__ + ".log") self.logger = self._log_manager.logger # Create listener @@ -143,43 +144,40 @@ self.dg_version = None self.fpga_version = None # create properties - self.dg_operation_mode = 0 #self.DG_OP_MODE_INIT_POST + self.dg_operation_mode = 0 # self.DG_OP_MODE_INIT_POST self.dg_operation_sub_mode = 0 self.dg_logged_in = False self.dg_set_logged_in_status(False) # Create command groups self.accel = DGAccelerometer(self.can_interface, self.logger) - self.fluid_leak = DGFluidLeak(self.can_interface, self.logger) self.alarms = DGAlarms(self.can_interface, self.logger) + self.calibration_record = DGCalibrationNVRecord(self.can_interface, self.logger) + self.chemical_disinfect = ChemicalDisinfect(self.can_interface, self.logger) self.concentrate_pumps = ConcentratePumps(self.can_interface, self.logger) self.conductivity_sensors = ConductivitySensors(self.can_interface, self.logger) self.drain_pump = DGDrainPump(self.can_interface, self.logger) self.fans = Fans(self.can_interface, self.logger) + self.fluid_leak = DGFluidLeak(self.can_interface, self.logger) + self.flush = FlushMode(self.can_interface, self.logger) self.hd_proxy = DGHDProxy(self.can_interface, self.logger) + self.heat_disinfect = HeatDisinfect(self.can_interface, self.logger) self.heaters = Heaters(self.can_interface, self.logger) self.load_cells = DGLoadCells(self.can_interface, self.logger) self.pressures = DGPressures(self.can_interface, self.logger) self.reservoirs = DGReservoirs(self.can_interface, self.logger) self.ro_pump = DGROPump(self.can_interface, self.logger) + self.rtc = DGRTC(self.can_interface, self.logger) self.samplewater = DGSampleWater(self.can_interface, self.logger) + self.scheduled_runs_record = DGScheduledRunsNVRecord(self.can_interface, self.logger) + self.service_record = DGServiceNVRecord(self.can_interface, self.logger) + self.switches = DGSwitches(self.can_interface, self.logger) + self.system_record = DGSystemNVRecord(self.can_interface, self.logger) self.temperature_sensors = TemperatureSensors(self.can_interface, self.logger) - self.conductivity_sensors = ConductivitySensors(self.can_interface, self.logger) - self.concentrate_pumps = ConcentratePumps(self.can_interface, self.logger) - self.alarms = DGAlarms(self.can_interface, self.logger) - self.heat_disinfect = HeatDisinfect(self.can_interface, self.logger) self.thermistors = Thermistors(self.can_interface, self.logger) self.uv_reactors = UVReactors(self.can_interface, self.logger) - self.calibration_record = DGCalibrationNVRecord(self.can_interface, self.logger) - self.system_record = DGSystemNVRecord(self.can_interface, self.logger) - self.service_record = DGServiceNVRecord(self.can_interface, self.logger) - self.scheduled_runs_record = DGScheduledRunsNVRecord(self.can_interface, self.logger) self.valves = DGValves(self.can_interface, self.logger) self.voltages = DGVoltages(self.can_interface, self.logger) - self.flush = FlushMode(self.can_interface, self.logger) - self.chemical_disinfect = ChemicalDisinfect(self.can_interface, self.logger) - self.rtc = DGRTC(self.can_interface, self.logger) - self.switches = DGSwitches(self.can_interface, self.logger) def get_version(self): """ @@ -221,16 +219,16 @@ """ return self.dg_logged_in - @_publish(["dg_logged_in"]) - def dg_set_logged_in_status(self, logged_in:bool=False): + @publish(["dg_logged_in"]) + def dg_set_logged_in_status(self, logged_in: bool = False): """ Callback for DG logged in status change. @param logged_in boolean logged in status for DG @return: none """ self.dg_logged_in = logged_in - @_publish(["dg_version", "fpga_version"]) + @publish(["dg_version", "fpga_version"]) def _handler_dg_version(self, message): """ Handler for response from DG regarding its version. @@ -265,7 +263,7 @@ self.fpga_version = f"ID: {fpga_id[0]} v{fpga_major[0]}.{fpga_minor[0]}.{fpga_lab[0]}" self.logger.debug(f"DG FPGA VERSION: {self.fpga_version}") - @_publish(["dg_operation_mode", "dg_operation_sub_mode"]) + @publish(["dg_operation_mode", "dg_operation_sub_mode"]) def _handler_dg_op_mode_sync(self, message): """ Handles published DG operation mode messages. Current DG operation mode Index: dialin/dg/voltages.py =================================================================== diff -u -r5ac4d7d984a093a2e76df9ecef4b3753f76b6abd -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/dg/voltages.py (.../voltages.py) (revision 5ac4d7d984a093a2e76df9ecef4b3753f76b6abd) +++ dialin/dg/voltages.py (.../voltages.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -195,7 +195,7 @@ mis = integer_to_bytearray(ms) payload = rst + mis - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_DG_MONITORED_VOLTAGES_SEND_INTERVAL_OVERRIDE.value, payload=payload) Index: dialin/hd/alarms.py =================================================================== diff -u -r78f3b6100f792682a26f87f6333a1d7243767fb6 -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/hd/alarms.py (.../alarms.py) (revision 78f3b6100f792682a26f87f6333a1d7243767fb6) +++ dialin/hd/alarms.py (.../alarms.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -612,6 +612,48 @@ self.logger.debug("Timeout!!!!") return False + def cmd_alarm_status_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the alarm status broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_ALARM_STATUS_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override alarm status broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Alarm status broadcast interval overridden to " + str_res + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.debug("Timeout!!!!") + return False + def cmd_alarm_audio_volume_override(self, volume: int = 5, reset: int = NO_RESET): """ Constructs and sends the alarm audio volume override command Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -rd6a2e3e1821b5c78f81ad71b10f0809eff1181ae -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision d6a2e3e1821b5c78f81ad71b10f0809eff1181ae) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -14,42 +14,40 @@ # ############################################################################ import struct + from .accelerometer import HDAccelerometer from .air_bubbles import HDAirBubbles from .air_trap import HDAirTrap from .alarms import HDAlarms +from .blood_flow import HDBloodFlow from .blood_leak import HDBloodLeak from .buttons import HDButtons -from .fluid_leak import HDFluidLeak -from .ui_proxy import HDUIProxy -from .watchdog import HDWatchdog -from .rtc import HDRTC -from .blood_flow import HDBloodFlow +from .calibration_record import HDCalibrationNVRecord +from .constants import NO_RESET from .dialysate_inlet_flow import HDDialysateInletFlow from .dialysate_outlet_flow import HDDialysateOutletFlow -from .treatment import HDTreatment -from .valves import HDValves -from .voltages import HDVoltages -from .calibration_record import HDCalibrationNVRecord -from .system_record import HDSystemNVRecords -from .service_record import HDServiceNVRecords +from .fluid_leak import HDFluidLeak from .pressure_occlusion import HDPressureOcclusion from .pretreatment import HDPreTreatment -from .syringe_pump import HDSyringePump +from .rtc import HDRTC +from .service_record import HDServiceNVRecords from .switches import HDSwitches -from ..protocols.CAN import (DenaliMessage, - DenaliCanMessenger, - DenaliChannels) - -from ..utils.conversions import integer_to_bytearray -from ..utils.base import _AbstractSubSystem, _publish, _LogManager -from ..utils.checks import check_broadcast_interval_override_ms -from .constants import RESET, NO_RESET -from ..common.msg_defs import MsgIds, MsgFieldPositions +from .syringe_pump import HDSyringePump +from .system_record import HDSystemNVRecords +from .treatment import HDTreatment +from .ui_proxy import HDUIProxy +from .valves import HDValves +from .voltages import HDVoltages +from .watchdog import HDWatchdog from ..common.hd_defs import HDOpModes +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, LogManager +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray -class HD(_AbstractSubSystem): +class HD(AbstractSubSystem): """ Hemodialysis Device (HD) Dialin object API. It provides the basic interface to communicate with the HD firmware. @@ -73,7 +71,7 @@ """ super().__init__() - self._log_manager = _LogManager(log_level=log_level, log_filepath=self.__class__.__name__+".log") + self._log_manager = LogManager(log_level=log_level, log_filepath=self.__class__.__name__ + ".log") self.logger = self._log_manager.logger # Create listener @@ -97,28 +95,28 @@ # Create command groups self.accel = HDAccelerometer(self.can_interface, self.logger) - self.air_trap = HDAirTrap(self.can_interface, self.logger) self.air_bubbles = HDAirBubbles(self.can_interface, self.logger) + self.air_trap = HDAirTrap(self.can_interface, self.logger) self.alarms = HDAlarms(self.can_interface, self.logger) - self.buttons = HDButtons(self.can_interface, self.logger) self.blood_leak = HDBloodLeak(self.can_interface, self.logger) - self.fluid_leak = HDFluidLeak(self.can_interface, self.logger) - self.ui = HDUIProxy(self.can_interface, self.logger) - self.rtc = HDRTC(self.can_interface, self.logger) - self.watchdog = HDWatchdog(self.can_interface, self.logger) self.bloodflow = HDBloodFlow(self.can_interface, self.logger) + self.buttons = HDButtons(self.can_interface, self.logger) + self.calibration_record = HDCalibrationNVRecord(self.can_interface, self.logger) self.dialysate_inlet_flow = HDDialysateInletFlow(self.can_interface, self.logger) self.dialysate_outlet_flow = HDDialysateOutletFlow(self.can_interface, self.logger) - self.treatment = HDTreatment(self.can_interface, self.logger) - self.pretreatment = HDPreTreatment(self.can_interface, self.logger) + self.fluid_leak = HDFluidLeak(self.can_interface, self.logger) self.pressure_occlusion = HDPressureOcclusion(self.can_interface, self.logger) + self.pretreatment = HDPreTreatment(self.can_interface, self.logger) + self.rtc = HDRTC(self.can_interface, self.logger) + self.service_record = HDServiceNVRecords(self.can_interface, self.logger) + self.switches = HDSwitches(self.can_interface, self.logger) self.syringe_pump = HDSyringePump(self.can_interface, self.logger) + self.system_record = HDSystemNVRecords(self.can_interface, self.logger) + self.treatment = HDTreatment(self.can_interface, self.logger) + self.ui = HDUIProxy(self.can_interface, self.logger) self.valves = HDValves(self.can_interface, self.logger) self.voltages = HDVoltages(self.can_interface, self.logger) - self.calibration_record = HDCalibrationNVRecord(self.can_interface, self.logger) - self.system_record = HDSystemNVRecords(self.can_interface, self.logger) - self.service_record = HDServiceNVRecords(self.can_interface, self.logger) - self.switches = HDSwitches(self.can_interface, self.logger) + self.watchdog = HDWatchdog(self.can_interface, self.logger) def get_operation_mode(self): """ @@ -136,16 +134,16 @@ """ return self.hd_logged_in - @_publish(["hd_logged_in"]) - def hd_set_logged_in_status(self, logged_in:bool=False): + @publish(["hd_logged_in"]) + def hd_set_logged_in_status(self, logged_in: bool = False): """ Callback for HD logged in status change. @param logged_in boolean logged in status for HD @return: none """ self.hd_logged_in = logged_in - @_publish(["hd_operation_mode"]) + @publish(["hd_operation_mode"]) def _handler_hd_op_mode_sync(self, message): """ Handles published HD operation mode messages. Current HD operation mode @@ -220,14 +218,14 @@ self.logger.debug("Timeout!!!!") return False - def cmd_hd_set_operation_mode(self, newMode: int = 0) -> int: + def cmd_hd_set_operation_mode(self, new_mode: int = 0) -> int: """ Constructs and sends a set operation mode request command via CAN bus. Constraints: Must be logged into HD. Transition from current to requested op mode must be legal. - @param newMode: ID of operation mode to transition to + @param new_mode: ID of operation mode to transition to HD_OP_MODE_FAULT = 0 HD_OP_MODE_SERVICE = 1 HD_OP_MODE_INIT_POST = 2 @@ -241,13 +239,13 @@ """ - payload = integer_to_bytearray(newMode) + payload = integer_to_bytearray(new_mode) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_HD_SET_OP_MODE_REQUEST.value, payload=payload) - self.logger.debug("Requesting HD mode change to " + str(newMode)) + self.logger.debug("Requesting HD mode change to " + str(new_mode)) # Send message received_message = self.can_interface.send(message) @@ -277,9 +275,9 @@ """ if active: - sft=1 + sft = 1 else: - sft=0 + sft = 0 rst = integer_to_bytearray(reset) saf = integer_to_bytearray(sft) payload = rst + saf Index: dialin/hd/treatment.py =================================================================== diff -u -rd6a2e3e1821b5c78f81ad71b10f0809eff1181ae -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/hd/treatment.py (.../treatment.py) (revision d6a2e3e1821b5c78f81ad71b10f0809eff1181ae) +++ dialin/hd/treatment.py (.../treatment.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -14,17 +14,17 @@ # ############################################################################ import struct -from ..protocols.CAN import (DenaliMessage, - DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish -from ..common.msg_defs import MsgIds, MsgFieldPositions from logging import Logger + +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish from ..utils.conversions import integer_to_bytearray, float_to_bytearray from ..utils.checks import check_broadcast_interval_override_ms from .constants import RESET, NO_RESET -class HDTreatment(_AbstractSubSystem): +class HDTreatment(AbstractSubSystem): """ Hemodialysis Delivery (HD) Dialin API sub-class for treatment related commands. @@ -105,6 +105,9 @@ msg_id = MsgIds.MSG_ID_HD_RECIRC_PROGRESS.value self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_recirculate_data_sync) + msg_id = MsgIds.MSG_ID_HD_TREATMENT_STOP_TIMER_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_treatment_stop_timer_data_sync) # treatment duration data self.treatment_time_prescribed = 0 @@ -120,6 +123,46 @@ self.blood_prime_state = 0 self.treatment_end_state = 0 self.treatment_stop_state = 0 + # saline bolus status + self.saline_bolus_max_vol = 0 + self.saline_bolus_cum_vol = 0.0 + self.saline_bolus_bol_vol = 0.0 + # blood prime status + self.blood_prime_tgt_vol = 0.0 + self.blood_prime_cum_vol = 0.0 + # rinseback status + self.rinseback_tgt_vol = 0.0 + self.rinseback_cum_vol = 0.0 + self.rinseback_cur_rate = 0 + self.rinseback_timeout_secs = 0 + self.rinseback_countdown_secs = 0 + # re-circulation status + self.recirc_timeout_secs = 0 + self.recirc_countdown_secs = 0 + # treatment stop status + self.treatment_stop_timeout_secs = 0 + self.treatment_stop_timeout_coundown_secs = 0 + + def reset(self) -> None: + """ + Reset all treatment variables + + @return: None + """ + # treatment duration data + self.treatment_time_prescribed = 0 + self.treatment_time_elapsed = 0 + self.treatment_time_remaining = 0 + # treatment state data + self.treatment_state = 0 + self.treatment_uf_state = 0 + self.saline_bolus_state = 0 + self.heparin_state = 0 + self.rinseback_state = 0 + self.treatment_recirculate_state = 0 + self.blood_prime_state = 0 + self.treatment_end_state = 0 + self.treatment_stop_state = 0 self.dialysis_state = 0 # saline bolus status self.saline_bolus_max_vol = 0 @@ -140,199 +183,223 @@ self.recirc_timeout_secs = 0 self.recirc_countdown_secs = 0 - def get_treatment_time_prescribed(self): + def get_treatment_time_prescribed(self) -> int: """ Gets the prescribed treatment time @return: The prescribed treatment time """ return self.treatment_time_prescribed - def get_treatment_time_elapsed(self): + def get_treatment_time_elapsed(self) -> int: """ Gets the elapsed treatment time @return: The elapsed treatment time """ return self.treatment_time_elapsed - def get_treatment_time_remaining(self): + def get_treatment_time_remaining(self) -> int: """ Gets the remaining treatment time @return: The remaining treatment time """ return self.treatment_time_remaining - def get_treatment_state(self): + def get_treatment_state(self) -> int: """ Gets the current treatment state @return: The current treatment state ID """ return self.treatment_state - def get_treatment_UF_state(self): + def get_treatment_UF_state(self) -> int: """ Gets the current treatment ultrafiltration state @return: The current treatment ultrafiltration state ID """ return self.treatment_uf_state - def get_treatment_saline_bolus_state(self): + def get_treatment_saline_bolus_state(self) -> int: """ Gets the current treatment saline bolus state @return: The current treatment saline bolus state ID """ return self.saline_bolus_state - def get_treatment_heparin_state(self): + def get_treatment_heparin_state(self) -> int: """ Gets the current treatment Heparin state @return: The current treatment Heparin state ID """ return self.heparin_state - def get_treatment_rinseback_state(self): + def get_treatment_rinseback_state(self) -> int: """ Gets the current treatment rinseback state @return: The current treatment rinseback state ID """ return self.rinseback_state - def get_treatment_recirculate_state(self): + def get_treatment_recirculate_state(self) -> int: """ Gets the current treatment recirculate state @return: The current treatment recirculate state ID """ return self.treatment_recirculate_state - def get_treatment_blood_prime_state(self): + def get_treatment_blood_prime_state(self) -> int: """ Gets the current treatment blood prime state @return: The current treatment blood prime state ID """ return self.blood_prime_state - def get_treatment_end_state(self): + def get_treatment_end_state(self) -> int: """ Gets the current treatment end state @return: The current treatment end state ID """ return self.treatment_end_state - def get_treatment_stop_state(self): + def get_treatment_stop_state(self) -> int: """ Gets the current treatment stop state @return: The current treatment stop state ID """ return self.treatment_stop_state - def get_dialysis_state(self): + def get_dialysis_state(self) -> int: """ Gets the current treatment dialysis state @return: The current treatment dialysis state ID """ return self.dialysis_state - def get_saline_bolus_max_volume(self): + def get_saline_bolus_max_volume(self) -> int: """ Returns maximum volume (in mL) saline that can be delivered to a patient @return: The maximum saline bolus volume """ return self.saline_bolus_max_vol - def get_saline_bolus_cumulative_volume_delivered(self): + def get_saline_bolus_cumulative_volume_delivered(self) -> float: """ Returns cumulative volume (in mL) of saline delivered @return: The cumulative saline volume delivered """ return self.saline_bolus_cum_vol - def get_saline_bolus_volume_delivered(self): + def get_saline_bolus_volume_delivered(self) -> float: """ Returns bolus volume (in mL) of saline delivered @return: The bolus saline volume delivered """ return self.saline_bolus_bol_vol - def get_blood_prime_target_volume(self): + def get_blood_prime_target_volume(self) -> float: """ Returns blood prime target volume (in mL) @return: The blood prime target volume """ return self.blood_prime_tgt_vol - def get_blood_prime_volume_delivered(self): + def get_blood_prime_volume_delivered(self) -> float: """ Returns blood prime volume (in mL) delivered @return: The blood prime volume delivered """ return self.blood_prime_cum_vol - def get_blood_prime_safety_volume_delivered(self): + def get_blood_prime_safety_volume_delivered(self) -> float: """ Returns blood prime safety volume (in mL) delivered @return: The blood prime safety volume delivered """ return self.blood_prime_ind_cum_vol - def get_rinseback_target_volume(self): + def get_rinseback_target_volume(self) -> float: """ Returns rinseback target volume (in mL) @return: The rinseback target volume """ return self.rinseback_tgt_vol - def get_rinseback_volume_delivered(self): + def get_rinseback_volume_delivered(self) -> float: """ Returns rinseback volume (in mL) delivered @return: The rinseback volume delivered """ return self.rinseback_cum_vol - def get_rinseback_safety_volume_delivered(self): + def get_rinseback_safety_volume_delivered(self) -> float: """ Returns rinseback safety volume (in mL) delivered @return: The rinseback safety volume delivered """ return self.rinseback_safety_cum_vol - def get_rinseback_timeout(self): + def get_rinseback_current_rate(self) -> int: """ + Returns rinseback current rate (in mL/min) + + @return: The rinseback current rate + """ + return self.rinseback_cur_rate + + def get_rinseback_timeout(self) -> int: + """ Returns rinseback timeout period (in seconds) @return: The rinseback timeout period """ return self.rinseback_timeout_secs - def get_rinseback_timeout_countdown(self): + def get_rinseback_timeout_countdown(self) -> int: """ Returns rinseback timeout countdown (in seconds) @return: The rinseback timeout countdown """ return self.rinseback_countdown_secs - @_publish([ + def get_recirc_timeout(self) -> int: + """ + Returns recirc timeout (in seconds) + + @return: The recirc timeout + """ + return self.recirc_timeout_secs + + def get_recirc_timeout_countdown(self) -> int: + """ + Returns recirc timeout countdown (in seconds) + + @return: The recirc timeout countdown + """ + return self.recirc_countdown_secs + + @publish([ "treatment_time_prescribed", "treatment_time_elapsed", "treatment_time_remaining" @@ -357,7 +424,7 @@ self.treatment_time_elapsed = ela[0] self.treatment_time_remaining = rem[0] - @_publish([ + @publish([ "treatment_state", "treatment_uf_state", "saline_bolus_state", @@ -410,7 +477,7 @@ self.treatment_stop_state = txs[0] self.dialysis_state = dia[0] - @_publish([ + @publish([ "saline_bolus_max_vol", "saline_bolus_cum_vol", "saline_bolus_bol_vol" @@ -435,7 +502,7 @@ self.saline_bolus_cum_vol = cum[0] self.saline_bolus_bol_vol = bol[0] - @_publish([ + @publish([ "rinseback_tgt_vol", "rinseback_cum_vol", "rinseback_cur_rate", @@ -471,7 +538,7 @@ self.rinseback_countdown_secs = cdn[0] self.rinseback_safety_cum_vol = rsv[0] - @_publish([ + @publish([ "blood_prime_tgt_vol", "blood_prime_cum_vol", "blood_prime_ind_cum_vol" @@ -496,7 +563,7 @@ self.blood_prime_cum_vol = cum[0] self.blood_prime_ind_cum_vol = ind[0] - @_publish([ + @publish([ "recirc_timeout_secs", "recirc_countdown_secs" ]) @@ -517,6 +584,23 @@ self.recirc_timeout_secs = tmo[0] self.recirc_countdown_secs = cdn[0] + @publish(["treatment_stop_timeout_secs", "treatment_stop_timeout_coundown_secs"]) + def _handler_treatment_stop_timer_data_sync(self, message) -> None: + """ + Handles published treatment stop progress data messages. + + @param message: published treatment stop progress data message + @return: None + """ + + tmo = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1])) + cnd = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2])) + + self.treatment_stop_timeout_secs = tmo[0] + self.treatment_stop_timeout_coundown_secs = cnd[0] + def cmd_set_treatment_param_blood_flow_rate(self, flow: int) -> int: """ Constructs and sends the set blood flow rate treatment parameter command. @@ -547,7 +631,7 @@ if received_message is not None: str_flo = str(flow) self.logger.debug("Blood flow rate parameter set to " + str_flo + " mL/min: " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -585,7 +669,7 @@ # self.logger.debug(received_message) str_flo = str(flow) self.logger.debug("Dialysate flow rate parameter set to " + str_flo + " mL/min: " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -621,7 +705,7 @@ # self.logger.debug(received_message) str_dur = str(duration) self.logger.debug("Treatment duration parameter set to " + str_dur + " min: " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -657,7 +741,7 @@ # self.logger.debug(received_message) str_sto = str(pre_stop) self.logger.debug("Heparin pre-stop time parameter set to " + str_sto + " min: " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -693,7 +777,7 @@ # self.logger.debug(received_message) str_vol = str(volume) self.logger.debug("Saline bolus volume parameter set to " + str_vol + " mL: " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -732,7 +816,7 @@ # self.logger.debug(received_message) str_acd = str(acid) self.logger.debug("Acid concentrate parameter set to " + str_acd + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -769,7 +853,7 @@ # self.logger.debug(received_message) str_bic = str(bicarb) self.logger.debug("Bicarbonate concentrate parameter set to " + str_bic + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -809,7 +893,7 @@ # self.logger.debug(received_message) str_dia = str(dialyzer) self.logger.debug("Dialyzer type parameter set to " + str_dia + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -845,7 +929,7 @@ # self.logger.debug(received_message) str_bpi = str(intvl) self.logger.debug("BP measurement interval parameter set to " + str_bpi + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -881,7 +965,7 @@ # self.logger.debug(received_message) str_flo = str(flow) self.logger.debug("Rinseback flow rate parameter set to " + str_flo + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -917,7 +1001,7 @@ # self.logger.debug(received_message) str_pre = str(pres) self.logger.debug("Arterial pressure lower alarm limit parameter set to " + str_pre + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -953,7 +1037,7 @@ # self.logger.debug(received_message) str_pre = str(pres) self.logger.debug("Arterial pressure upper alarm limit parameter set to " + str_pre + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -989,7 +1073,7 @@ # self.logger.debug(received_message) str_pre = str(pres) self.logger.debug("Venous pressure lower alarm limit parameter set to " + str_pre + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1025,7 +1109,7 @@ # self.logger.debug(received_message) str_pre = str(pres) self.logger.debug("Venous pressure upper alarm limit parameter set to " + str_pre + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1061,7 +1145,7 @@ # self.logger.debug(received_message) str_rat = str(rate) self.logger.debug("Heparin dispense rate parameter set to " + str_rat + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1097,7 +1181,7 @@ # self.logger.debug(received_message) str_vol = str(volume) self.logger.debug("Heparin bolus volume parameter set to " + str_vol + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1133,7 +1217,7 @@ # self.logger.debug(received_message) str_tmp = str(temp) self.logger.debug("Dialysate temperature parameter set to " + str_tmp + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1169,7 +1253,7 @@ # self.logger.debug(received_message) str_vol = str(volume) self.logger.debug("Ultrafiltration volume parameter set to " + str_vol + ": " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: @@ -1200,7 +1284,7 @@ # If there is content... if received_message is not None: self.logger.debug("Treatment time remaining overridden to " + str(secs_remaining) + " seconds. " + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: Index: dialin/hd/voltages.py =================================================================== diff -u -r4304dd7449eee937f9a7f1f9687a616258c2c0bc -recfaee3ad071edb368488eb750692f16a91ddbad --- dialin/hd/voltages.py (.../voltages.py) (revision 4304dd7449eee937f9a7f1f9687a616258c2c0bc) +++ dialin/hd/voltages.py (.../voltages.py) (revision ecfaee3ad071edb368488eb750692f16a91ddbad) @@ -15,15 +15,14 @@ ############################################################################ import struct from enum import unique -from ..utils.base import DialinEnum -from ..utils.checks import check_broadcast_interval_override_ms -from ..protocols.CAN import (DenaliMessage, - DenaliChannels) -from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from logging import Logger + from .constants import RESET, NO_RESET -from ..utils.base import _AbstractSubSystem, _publish +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from ..utils.checks import check_broadcast_interval_override_ms from ..common.msg_defs import MsgIds, MsgFieldPositions -from logging import Logger # Monitored voltages @@ -42,7 +41,7 @@ MONITORED_LINE_FPGA_PVN_V = 10 # FPGA Vpvn (1V) NUM_OF_MONITORED_VOLTAGE_LINES = 11 # Number of HD operation modes -class HDVoltages(_AbstractSubSystem): +class HDVoltages(AbstractSubSystem): """ Hemodialysis Delivery (HD) Dialin API sub-class for voltage monitor related commands and data. """ @@ -71,9 +70,7 @@ """ return self.monitored_voltages - @_publish([ - "monitored_voltages" - ]) + @publish(["monitored_voltages"]) def _handler_monitored_voltages_sync(self, message): """ Handles published HD monitored voltages data messages. Voltage data are captured @@ -118,7 +115,7 @@ self.monitored_voltages[HDMonitoredVoltages.MONITORED_LINE_FPGA_AUX_V.value] = vfa[0] self.monitored_voltages[HDMonitoredVoltages.MONITORED_LINE_FPGA_PVN_V.value] = vfp[0] - def cmd_monitored_voltage_override(self, signal:int=0, volts:float=0.0, reset:int=NO_RESET) -> int: + def cmd_monitored_voltage_override(self, signal: int = 0, volts: float = 0.0, reset: int = NO_RESET) -> int: """ Constructs and sends the HD monitored voltage override command Constraints: @@ -152,14 +149,14 @@ else: str_res = str(volts) + " V. " self.logger.debug("Monitored HD voltage overridden to " + str_res + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: self.logger.debug("Timeout!!!!") return False - def cmd_monitored_voltages_broadcast_interval_override(self, ms:int=1000, reset:int=NO_RESET) -> int: + def cmd_monitored_voltages_broadcast_interval_override(self, ms: int = 1000, reset: int = NO_RESET) -> int: """ Constructs and sends the monitored HD voltages broadcast interval override command Constraints: @@ -194,7 +191,7 @@ else: str_res = str(ms) + " ms: " self.logger.debug("HD monitored voltages broadcast interval overridden to " + str_res + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: