Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rd4c07268dfcb79727bf9516db309944635895a0b -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision d4c07268dfcb79727bf9516db309944635895a0b) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1,17 +1,17 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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. +# 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 DialysateGenerator.py +# @file dialysate_generator.py # -# @date 31-Mar-2019 -# @author P. Lucia +# @author (last) Peter Lucia +# @date (last) 20-Jul-2020 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # -# @brief This class allows sending to and receiving from the DG device. -# ############################################################################ import struct from .drain_pump import DGDrainPump @@ -63,6 +63,16 @@ START_POS_BUILD = END_POS_MICRO END_POS_BUILD = START_POS_BUILD + 2 + # FPGA + START_POS_FPGA_ID = END_POS_BUILD + END_POS_FPGA_ID = START_POS_FPGA_ID + 1 + START_POS_FPGA_MAJOR = END_POS_FPGA_ID + END_POS_FPGA_MAJOR = START_POS_FPGA_MAJOR + 1 + START_POS_FPGA_MINOR = END_POS_FPGA_MAJOR + END_POS_FPGA_MINOR = START_POS_FPGA_MINOR + 1 + START_POS_FPGA_LAB = END_POS_FPGA_MINOR + END_POS_FPGA_LAB = START_POS_FPGA_LAB + 1 + # DG operation modes DG_OP_MODE_FAULT = 0 DG_OP_MODE_SERVICE = 1 @@ -122,6 +132,7 @@ # initialize variables that will be populated by DG version response self.dg_version = None + self.fpga_version = None # create properties self.dg_operation_mode = self.DG_OP_MODE_INIT_POST self.dg_operation_sub_mode = 0 @@ -162,7 +173,7 @@ """ return self.dg_operation_sub_mode - @_publish(["dg_version"]) + @_publish(["dg_version", "fpga_version"]) def _handler_dg_version(self, message): """ Handler for response from DG regarding its version. @@ -184,11 +195,22 @@ build = struct.unpack('H', bytearray( message['message'][self.START_POS_BUILD:self.END_POS_BUILD])) - if len(major) > 0 and len(minor) > 0 and len(micro) > 0 and len(build) > 0: + fpga_id = struct.unpack('B', bytearray( + message['message'][self.START_POS_FPGA_ID:self.END_POS_FPGA_ID])) + fpga_major = struct.unpack('B', bytearray( + message['message'][self.START_POS_FPGA_MAJOR:self.END_POS_FPGA_MAJOR])) + fpga_minor = struct.unpack('B', bytearray( + message['message'][self.START_POS_FPGA_MINOR:self.END_POS_FPGA_MINOR])) + fpga_lab = struct.unpack('B', bytearray( + message['message'][self.START_POS_FPGA_LAB:self.END_POS_FPGA_LAB])) + + if all([len(each) > 0 for each in [major, minor, micro, build]]): self.dg_version = f"v{major[0]}.{minor[0]}.{micro[0]}-{build[0]}" - self.logger.debug(self.dg_version) + self.logger.debug(f"DG VERSION: {self.dg_version}") - return self.dg_version + if all([len(each) > 0 for each in [fpga_major, fpga_minor, fpga_id, fpga_lab]]): + 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"]) def _handler_dg_op_mode_sync(self, message): Index: dialin/dg/drain_pump.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/drain_pump.py (.../drain_pump.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/drain_pump.py (.../drain_pump.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -92,6 +92,8 @@ def cmd_drain_pump_speed_set_point_override(self, speed, reset=NO_RESET): """ Constructs and sends the drain pump speed set point override command + Constraints: + Must be logged into DG. @param speed: integer - speed set point (in RPM) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -128,7 +130,10 @@ def cmd_drain_pump_data_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends the drain pump speed set point override command + Constructs and sends the drain pump speed set point override command. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 ms). @param ms: integer - interval (in ms) to override with @param reset: integer - 1 to reset a previous override, 0 to override Index: dialin/dg/hd_proxy.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -48,9 +48,12 @@ def cmd_switch_reservoirs(self, reservoirID=RESERVOIR1): """ - Constructs and sends the switch reservoirs command + Constructs and sends the switch reservoirs command. + Constraints: + DG must be in re-circulate mode. + Given reservoirID must be in the reservoir list below. - @param res: unsigned int - reservoir to set as active (HD will draw from this reservoir). + @param reservoirID: unsigned int - reservoir to set as active (HD will draw from this reservoir). @return: 1 if successful, zero otherwise \details Reservoir IDs: \n @@ -80,7 +83,10 @@ def cmd_fill(self, volume=1500): """ - Constructs and sends the fill command + Constructs and sends the fill command. + Constraints: + DG must be in re-circulate water state of re-circulate mode. + Given fill to volume must be between 0 and 1950 mL. @param volume: unsigned int - volume (in mL) to fill inactive reservoir to. @return: 1 if successful, zero otherwise @@ -108,7 +114,10 @@ def cmd_drain(self, volume=200): """ - Constructs and sends the drain command + Constructs and sends the drain command. + Constraints: + DG must be in re-circulate mode. + Given drain to volume must be between 0 and 1950 mL. @param volume: unsigned int - volume (in mL) to drain the inactive reservoir to. @return: 1 if successful, zero otherwise @@ -137,6 +146,9 @@ def cmd_start_stop_dg(self, start=True): """ Constructs and sends the start/stop DG command + Constraints: + DG must be in idle state of standby mode if start command given. + DG must be in re-circulate mode if stop command given. @param start: boolean - True = start DG, False = stop DG. @return: 1 if successful, zero otherwise Index: dialin/dg/heaters.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/heaters.py (.../heaters.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/heaters.py (.../heaters.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -75,6 +75,8 @@ def cmd_start_primary_heater(self): """ Constructs and sends start primary heater command + Constraints: + A target temperature for primary heater between 10 and 90 deg C must have been given to DG previously. @returns none """ @@ -104,6 +106,8 @@ def cmd_start_trimmer_heater(self): """ Constructs and sends start trimmer heater command + Constraints: + A target temperature for trimmer heater between 10 and 90 deg C must have been given to DG previously. @returns none """ @@ -148,7 +152,10 @@ def cmd_heaters_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends broadcast time interval + Constructs and sends broadcast time interval. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG general task interval (50 ms). @param ms: Publish time interval in ms @param reset: integer - 1 to reset a previous override, 0 to override Index: dialin/dg/load_cells.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/load_cells.py (.../load_cells.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/load_cells.py (.../load_cells.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -105,6 +105,9 @@ def cmd_load_cell_override(self, grams, sensor, reset=NO_RESET): """ Constructs and sends the load cell override command + Constraints: + Must be logged into DG. + Given sensor must be one of the sensors listed below. @param grams: float - weight (in grams) to override sensor with @param sensor: unsigned int - sensor ID @@ -143,6 +146,9 @@ def cmd_load_cell_data_broadcast_interval_override(self, ms, reset=NO_RESET): """ Constructs and sends the load cell data broadcast interval override command + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 ms). @param ms: integer - interval (in ms) to override with @param reset: integer - 1 to reset a previous override, 0 to override Index: dialin/dg/pressures.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/pressures.py (.../pressures.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/pressures.py (.../pressures.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -111,7 +111,10 @@ def cmd_pressure_override(self, pressure, sensor, reset=NO_RESET): """ - Constructs and sends the pressure override command + Constructs and sends the pressure override command. + Constraints: + Must be logged into DG. + Given sensor must be one of the sensors listed below. @param pressure: unsigned int - pressure (in PSI) @param sensor: unsigned int - sensor ID @@ -149,7 +152,10 @@ def cmd_pressure_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends the pressure override command + Constructs and sends the pressure override command. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 ms). @param ms: unsigned int - broadcast interval (in ms) @param reset: integer - 1 to reset a previous override, 0 to override Index: dialin/dg/ro_pump.py =================================================================== diff -u -rd4c07268dfcb79727bf9516db309944635895a0b -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/ro_pump.py (.../ro_pump.py) (revision d4c07268dfcb79727bf9516db309944635895a0b) +++ dialin/dg/ro_pump.py (.../ro_pump.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1,18 +1,17 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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. +# 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 ro_pump.py +# @file ro_pump.py # -# @date 14-Apr-2020 -# @author S. Nash +# @author (last) Dara Navaei +# @date (last) 01-Jul-2020 +# @author (original) Sean +# @date (original) 14-Apr-2020 # -# @brief -# -# ############################################################################ import struct from ..utils.conversions import integer_to_bytearray, float_to_bytearray Index: dialin/dg/temperature_sensors.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/temperature_sensors.py (.../temperature_sensors.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/temperature_sensors.py (.../temperature_sensors.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -20,8 +20,24 @@ from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +import enum +class TemperatureSensorsEnum(enum.Enum): + PRIMARY_HEATER_INLET = 0 + PRIMARY_HEATER_OUTLET = 1 + CONDUCTIVITY_SENSOR_1 = 2 + CONDUCTIVITY_SENSOR_2 = 3 + DIALYSATE_REDUNDANT = 4 + DIALYSATE = 5 + PRIMARY_HEATER_THERMOCOUPLE = 6 + TRIMMER_HEATER_THERMOCOUPLE = 7 + PRIMARY_HEATER_COLD_JUNCTION = 8 + TRIMMER_HEATER_COLD_JUNCTION = 9 + PRIMARY_HEATER_INTERNAL = 10 + TRIMMER_HEATER_INTERNAL = 11 + + class TemperatureSensors(_AbstractSubSystem): MSG_ID_DG_TEMPERATURE_DATA = 0x2D @@ -148,7 +164,10 @@ def cmd_temperature_sensors_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends broadcast time interval + Constructs and sends broadcast time interval. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 ms). @param ms: Publish time interval in ms @param reset: integer - 1 to reset a previous override, 0 to override @@ -176,11 +195,28 @@ def cmd_temperature_sensors_override_value(self, sensor_index, sensor_value, reset=NO_RESET): """ - Constructs and sends the value override of a temperature sensor + Constructs and sends the value override of a temperature sensor. + Constraints: + Must be logged into DG. + Given sensor_index must be one of the sensors listed below. @param sensor_index : Index of the sensor - @param sensor_value: Value of the sensor to be overriden + @param sensor_value: Value of the sensor to override @returns 1 if successful, zero otherwise + + \details temperature sensor indexes: \n + 0 = Primary Heater Inlet + 1 = Primary Heater Outlet + 2 = Conductivity Sensor 1 + 3 = Conductivity Sensor 2 + 4 = Dialysate (Redundant) + 5 = Dialysate + 6 = Primary Heater Thermocouple + 7 = Trimmer Heater Thermocouple + 8 = Primary Heater Cold Junction + 9 = Trimmer Heater Cold Junction + 10= Primary Heater Internal + 11= Trimmer Heater Internal """ rst = integer_to_bytearray(reset) value = float_to_bytearray(sensor_value) Index: dialin/dg/valves.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/dg/valves.py (.../valves.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/dg/valves.py (.../valves.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -226,7 +226,10 @@ def cmd_valve_override(self, state, valve, reset=NO_RESET): """ - Constructs and sends the valve state override command + Constructs and sends the valve state override command. + Constraints: + Must be logged into DG. + Given valve ID must be one of the valve IDs listed below. @param state: bool - valve state @param valve: unsigned int - valve ID @@ -273,7 +276,10 @@ def cmd_valve_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends the valve state override command + Constructs and sends the valve state override command. + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG priority task interval (10 ms). @param ms: unsigned int - broadcast interval (in ms) @param reset: integer - 1 to reset a previous override, 0 to override Index: dialin/hd/alarms.py =================================================================== diff -u -rd4c07268dfcb79727bf9516db309944635895a0b -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/alarms.py (.../alarms.py) (revision d4c07268dfcb79727bf9516db309944635895a0b) +++ dialin/hd/alarms.py (.../alarms.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1,17 +1,17 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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. +# 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 alarms.py +# @file alarms.py # -# @date 2-Apr-2020 -# @author P. Lucia +# @author (last) Peter Lucia +# @date (last) 20-Jul-2020 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # -# @brief -# ############################################################################ from ..protocols.CAN import (DenaliMessage, DenaliChannels) @@ -21,6 +21,7 @@ from collections import OrderedDict import struct from logging import Logger +from ..common.alarm_defs import AlarmList class HDAlarms(_AbstractSubSystem): @@ -162,10 +163,10 @@ self.alarm_states = [False] * 500 self.ids = OrderedDict() - for attr in dir(self): - if not callable(getattr(self, attr)) and attr.startswith("ALARM_ID"): - self.ids[attr] = getattr(self, attr) - self.ids = OrderedDict(sorted(self.ids.items(), key=lambda key: key[1])) + for attr in dir(AlarmList): + if not callable(getattr(AlarmList, attr)) and attr.startswith("ALARM_ID"): + self.ids[attr] = getattr(AlarmList, attr) + self.ids = OrderedDict(sorted(self.ids.items(), key=lambda key: key[1].value)) def get_alarm_states(self): """ @@ -175,19 +176,6 @@ """ return self.alarm_states - def get_alarms_state(self): - """ - Gets the alarms state - - None = 0 \n - Low = 1 \n - Medium = 2 \n - High = 3 \n - - @return: The alarms state - """ - return self.alarms_state - def get_alarms_top(self): """ Gets the top alarm @@ -216,18 +204,31 @@ """ Gets the alarms flags + Extract each flag from the flags int using bit-masking. E.g. + + System Fault = result & 1 + Stop = result & 2 + No Clear = result & 4 + No Resume = result & 8 + No Rinseback = result & 16 + No End Treatment = result & 32 + No New Treatment = result & 64 + Bypass Dialyzer = result & 128 + Alarms to Escalate = result & 256 + Alarms Silenced = result & 512 + TBD = result & 1024 + TBD = result & 2048 + TBD = result & 4096 + TBD = result & 8192 + TBD = result & 16384 + TBD = result & 32768 + TBD = result & 65536 + + @return: (int) The alarms flags value """ return self.alarms_flags - def get_alarm_states(self): - """ - Alarm states based on received HD alarm activation and alarm clear messages - - @return: - """ - self.alarm_states = [False] * 500 - def get_alarm_ids(self): """ Returns a dictionary of the alarm short name and the corresponding id @@ -428,8 +429,9 @@ def get_current_alarms_state(self): """ Gets the current alarms state. + None, Low, Medium, or High - @return: the current alarms state in text form. + @return: (str) the current alarms state in text form. """ result = "" if self.alarms_state == self.HD_ALARM_STATE_NONE: Index: dialin/hd/blood_flow.py =================================================================== diff -u -rd4c07268dfcb79727bf9516db309944635895a0b -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/blood_flow.py (.../blood_flow.py) (revision d4c07268dfcb79727bf9516db309944635895a0b) +++ dialin/hd/blood_flow.py (.../blood_flow.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1,18 +1,17 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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. +# 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 bloodflow.py +# @file blood_flow.py # -# @date 31-Mar-2020 -# @author P. Lucia +# @author (last) Peter Lucia +# @date (last) 22-Jun-2020 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # -# @brief -# -# ############################################################################ from ..protocols.CAN import (DenaliMessage, DenaliChannels) @@ -115,17 +114,17 @@ def get_measured_blood_pump_mc_speed(self): """ - Gets the measured blood pump mc speed + Gets the measured blood pump motor controller speed - @return: The measured blood pump mc speed + @return: The measured blood pump motor controller speed """ return self.measured_blood_pump_mc_speed def get_measured_blood_pump_mc_current(self): """ - Gets the measured blood pump mc current + Gets the measured blood pump motor controller current - @return: the measured blood pump mc current + @return: the measured blood pump motor controller current """ return self.measured_blood_pump_mc_current @@ -296,9 +295,9 @@ self.logger.debug("Timeout!!!!") return False - def cmd_blood_pump_measured_current_override(self, curr, reset=NO_RESET): + def cmd_measured_blood_pump_mc_current_override(self, curr, reset=NO_RESET): """ - Constructs and sends the measured blood pump motor current override command + Constructs and sends the measured blood pump motor controller current override command Constraints: Must be logged into HD. @@ -375,7 +374,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_blood_pump_rotor_measured_speed_override(self, speed, reset=NO_RESET): + def cmd_blood_pump_measured_rotor_speed_override(self, speed, reset=NO_RESET): """ Constructs and sends the measured blood pump rotor speed override \n command. Index: dialin/hd/buttons.py =================================================================== diff -u -rd4c07268dfcb79727bf9516db309944635895a0b -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/buttons.py (.../buttons.py) (revision d4c07268dfcb79727bf9516db309944635895a0b) +++ dialin/hd/buttons.py (.../buttons.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1,36 +1,48 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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. +# 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 CAN.py +# @file buttons.py # -# @date 29-Apr-2020 -# @author P. Lucia +# @author (last) Peter Lucia +# @date (last) 29-Jun-2020 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # -# @brief Support for button related commands -# ############################################################################ from ..protocols.CAN import (DenaliMessage, + DenaliCanMessenger, DenaliChannels) from ..utils.conversions import integer_to_bytearray from .constants import RESET, NO_RESET from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +import struct class HDButtons(_AbstractSubSystem): """ Hemodialysis Device (HD) Dialin API sub-class for button related commands. """ + START_POS_POWEROFF = DenaliMessage.PAYLOAD_START_INDEX + END_POS_POWEROFF_STATUS = START_POS_POWEROFF + 2 + # buttons message IDs MSG_ID_HD_OFF_BUTTON_OVERRIDE = 0x8002 MSG_ID_HD_STOP_BUTTON_OVERRIDE = 0x8003 - def __init__(self, can_interface, logger: Logger): + MSG_ID_HD_POWEROFF_OPEN = 0x01 + MSG_ID_HD_POWEROFF_TIMEOUT = 0x01 + MSG_ID_HD_POWEROFF_BROADCAST = 0x000E + + PRESSED = 1 + RELEASED = 0 + + def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): """ HD_Buttons constructor @@ -40,7 +52,49 @@ super().__init__() self.can_interface = can_interface self.logger = logger + self.poweroff_timeout_expired = False + if self.can_interface is not None: + self.can_interface.register_receiving_publication_function(DenaliChannels.hd_to_ui_ch_id, + self.MSG_ID_HD_POWEROFF_TIMEOUT, + self._handler_poweroff_timeout_occurred) + + def get_power_timeout_expired(self): + """ + Gets the poweroff timeout expired status + + @return: True if expired, False otherwise + """ + + return self.poweroff_timeout_expired + + def reset_poweroff_timeout_expired(self): + """ + Resets the dialin poweroff timeout flag to False + + @return: None + """ + + self.poweroff_timeout_expired = False + + @_publish(["poweroff_timeout_expired"]) + def _handler_poweroff_timeout_occurred(self, message): + """ + Poweroff timeout occurred handler + + @param message: The poweroff timeout occurred message string + @return: None + """ + if len(message["message"]) < 16: + self.logger.debug("Poweroff message id detected, but was the wrong length.") + return + + mode = struct.unpack('h', bytearray( + message['message'][self.START_POS_POWEROFF:self.END_POS_POWEROFF_STATUS])) + + if len(mode) > 0: + self.poweroff_timeout_expired = bool(mode[0]) + def cmd_off_button_override(self, state, reset=NO_RESET): """ Constructs and sends the Off button override command Index: dialin/hd/dialysate_inlet_flow.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/dialysate_inlet_flow.py (.../dialysate_inlet_flow.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/hd/dialysate_inlet_flow.py (.../dialysate_inlet_flow.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -176,11 +176,14 @@ def cmd_dialysate_inlet_flow_set_point_override(self, flow, reset=NO_RESET): """ - Constructs and sends the dialysate flow set point override command + Constructs and sends the dialysate flow set point override command + Constraints: + Must be logged into HD. + Given flow must be valid (<= 600 mL/min). - @param flow: integer - flow set point (in mL/min) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param flow: integer - flow set point (in mL/min) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -214,11 +217,13 @@ def cmd_dialysate_inlet_flow_measured_override(self, flow, reset=NO_RESET): """ - Constructs and sends the measured dialysate flow override command + Constructs and sends the measured dialysate flow override command + Constraints: + Must be logged into HD. - @param flow: integer - measured flow (in mL/min) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param flow: integer - measured flow (in mL/min) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -251,12 +256,14 @@ def cmd_dialysate_inlet_pump_mc_measured_speed_override(self, speed, reset=NO_RESET): """ - Constructs and sends the measured dialysate inlet pump motor controller speed \n - override command. + Constructs and sends the measured dialysate inlet pump motor controller speed \n + override command. + Constraints: + Must be logged into HD. - @param speed: integer - speed (in RPM) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param speed: integer - speed (in RPM) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -289,11 +296,13 @@ def cmd_dialysate_inlet_pump_measured_current_override(self, curr, reset=NO_RESET): """ - Constructs and sends the measured dialysate inlet pump motor current override command + Constructs and sends the measured dialysate inlet pump motor current override command + Constraints: + Must be logged into HD. - @param curr: integer - current (in mA) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param curr: integer - current (in mA) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -326,12 +335,14 @@ def cmd_dialysate_inlet_pump_measured_speed_override(self, speed, reset=NO_RESET): """ - Constructs and sends the measured dialysate inlet pump motor speed override \n - command. + Constructs and sends the measured dialysate inlet pump motor speed override \n + command. + Constraints: + Must be logged into HD. - @param speed: integer - speed (in RPM) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param speed: integer - speed (in RPM) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -364,12 +375,14 @@ def cmd_dialysate_inlet_pump_rotor_measured_speed_override(self, speed, reset=NO_RESET): """ - Constructs and sends the measured dialysate inlet pump rotor speed override \n - command. + Constructs and sends the measured dialysate inlet pump rotor speed override \n + command. + Constraints: + Must be logged into HD. - @param speed: integer - speed (in RPM) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param speed: integer - speed (in RPM) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -402,11 +415,14 @@ def cmd_dialysate_inlet_flow_broadcast_interval_override(self, ms, reset=NO_RESET): """ - Constructs and sends the measured dialysate inlet flow broadcast interval override command + Constructs and sends the measured dialysate inlet flow broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD priority task interval (10 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 + @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 """ rst = integer_to_bytearray(reset) Index: dialin/hd/dialysate_outlet_flow.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/dialysate_outlet_flow.py (.../dialysate_outlet_flow.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/hd/dialysate_outlet_flow.py (.../dialysate_outlet_flow.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -175,6 +175,8 @@ def cmd_dialysate_outlet_reference_uf_volume_override(self, refvol, reset=NO_RESET): """ Constructs and sends the UF reference volume override command + Constraints: + Must be logged into HD. @param refvol: float - reference UF volume (in mL) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -213,6 +215,8 @@ def cmd_dialysate_outlet_measured_uf_volume_override(self, measvol, reset=NO_RESET): """ Constructs and sends the measured UF volume override command + Constraints: + Must be logged into HD. @param measvol: float - measured UF volume (in mL) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -249,12 +253,14 @@ def cmd_dialysate_outlet_pump_mc_measured_speed_override(self, speed, reset=NO_RESET): """ - Constructs and sends the measured dialysate outlet pump motor controller speed \n - override command. + Constructs and sends the measured dialysate outlet pump motor controller speed \n + override command. + Constraints: + Must be logged into HD. - @param speed: float - speed (in RPM) to override with - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param speed: float - speed (in RPM) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) @@ -288,6 +294,8 @@ def cmd_dialysate_outlet_pump_measured_current_override(self, curr, reset=NO_RESET): """ Constructs and sends the measured dialysate outlet pump motor current override command + Constraints: + Must be logged into HD. @param curr: float - current (in mA) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -326,6 +334,8 @@ """ Constructs and sends the measured dialysate outlet pump motor speed override \n command. + Constraints: + Must be logged into HD. @param speed: float - speed (in RPM) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -364,6 +374,8 @@ """ Constructs and sends the measured dialysate outlet pump rotor speed override \n command. + Constraints: + Must be logged into HD. @param speed: float - speed (in RPM) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -401,6 +413,9 @@ def cmd_dialysate_outlet_flow_broadcast_interval_override(self, ms, reset=NO_RESET): """ Constructs and sends the measured dialysate outlet flow broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD priority task interval (10 ms). @param ms: integer - interval (in ms) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -438,6 +453,9 @@ def cmd_dialysate_outlet_pump_load_cell_weight_override(self, weight, sensor, reset=NO_RESET): """ Constructs and sends the measured load cell weight override command. + Constraints: + Must be logged into HD. + Given sensor must be one of the sensors listed below. @param weight: float - weight (in g) to override with @param sensor: integer - ID of load cell to override Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -28,6 +28,7 @@ DenaliCanMessenger, DenaliChannels) from ..utils.base import _AbstractSubSystem, _publish, _LogManager +from .constants import NO_RESET class HD(_AbstractSubSystem): @@ -162,20 +163,31 @@ self.logger.debug("Login Timeout!!!!") return False - def cmd_hd_safety_shutdown_override(self): + def cmd_hd_safety_shutdown_override(self, active=True, reset=NO_RESET): """ Constructs and sends an HD safety shutdown override command via CAN bus. + Constraints: + Must be logged into HD. \returns response message if received, False if no response received - @param msg: byte array - properly formatted HD message to insert - + @param active: boolean - True to activate safety shutdown, False to deactivate + @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ + if active: + sft=1 + else: + sft=0 + rst = integer_to_bytearray(reset) + saf = integer_to_bytearray(sft) + payload = rst + saf + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=self.MSG_ID_HD_SAFETY_SHUTDOWN_OVERRIDE) + message_id=self.MSG_ID_HD_SAFETY_SHUTDOWN_OVERRIDE, + payload=payload) self.logger.debug("overriding HD safety shutdown") Index: dialin/hd/pressure_occlusion.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/pressure_occlusion.py (.../pressure_occlusion.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/hd/pressure_occlusion.py (.../pressure_occlusion.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -144,6 +144,8 @@ def cmd_arterial_pressure_measured_override(self, pres, reset=NO_RESET): """ Constructs and sends the measured arterial pressure override command + Constraints: + Must be logged into HD. @param pres: float - measured arterial pressure (in mmHg) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -181,6 +183,8 @@ """ Constructs and sends the measured venous pressure \n override command. + Constraints: + Must be logged into HD. @param pres: float - venous pressure (in mmHg) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -217,6 +221,8 @@ def cmd_blood_pump_measured_occlusion_override(self, occl, reset=NO_RESET): """ Constructs and sends the measured blood pump occlusion pressure override command + Constraints: + Must be logged into HD. @param occl: float - pressure (in mmHg) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -254,6 +260,8 @@ """ Constructs and sends the measured dialysate inlet pump occlusion pressure override \n command. + Constraints: + Must be logged into HD. @param occl: float - pressure (in mmHg) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -291,6 +299,8 @@ """ Constructs and sends the measured dialysate outlet pump occlusion pressure override \n command. + Constraints: + Must be logged into HD. @param occl: float - pressure (in mmHg) to override with @param reset: integer - 1 to reset a previous override, 0 to override @@ -327,6 +337,9 @@ def cmd_pressure_occlusion_broadcast_interval_override(self, ms, reset=NO_RESET): """ Constructs and sends the pressure/occlusion broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the DG 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 Index: dialin/hd/watchdog.py =================================================================== diff -u -r8d1f61499650e23dac6f857e48daad42180db949 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/hd/watchdog.py (.../watchdog.py) (revision 8d1f61499650e23dac6f857e48daad42180db949) +++ dialin/hd/watchdog.py (.../watchdog.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -42,6 +42,10 @@ def cmd_watchdog_task_check_in_override(self, state, task, reset=NO_RESET): """ Constructs and sends the watchdog task check-in override command + Constraints: + Must be logged into HD. + Given task must be valid. + Given state must be a 0 or 1. @param state: integer - 1 for task checked in, 0 for task not checked in @param task: integer - ID of task to override Index: dialin/version.py =================================================================== diff -u -r4bdb012848d1b59be5edc31d677b77b9d95f6190 -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- dialin/version.py (.../version.py) (revision 4bdb012848d1b59be5edc31d677b77b9d95f6190) +++ dialin/version.py (.../version.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -15,28 +15,55 @@ ############################################################################ import subprocess +VERSION = "0.6.0" + def get_branch(): """ Gets the current branch name in the current git repository - @return: The current branch name + @return: The current branch name, None if it can't be determined """ - return subprocess.check_output("git rev-parse --abbrev-ref HEAD", shell=True).decode("utf-8").strip() + try: + subprocess.check_output("git rev-parse --abbrev-ref HEAD", shell=True).decode("utf-8").strip() + except subprocess.CalledProcessError: + return None def get_last_commit(): """ Gets the latest commit in the current git repository - @return: (str) the latest commit in the current git repository + @return: (str) the latest commit in the current git repository, None if it can't be determined """ - return subprocess.check_output("git rev-parse --short=7 HEAD", shell=True).decode("utf-8").strip() + try: + return subprocess.check_output("git rev-parse --short=7 HEAD", shell=True).decode("utf-8").strip() + except subprocess.CalledProcessError: + return None -VERSION = "0.5.0-{0}-{1}".format(get_branch(), get_last_commit()) +def check_if_git_repo(): + """ + Checks if we're in a git repo or not to know if we can get the git branch and commit + @return: True if in a git repo, False otherwise + """ + return subprocess.call(["git", "branch"], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0 + + +branch = None +commit = None + +DEV_VERSION = VERSION + +if check_if_git_repo(): + branch = get_branch() + commit = get_last_commit() + DEV_VERSION += "-{0}".format(branch) + DEV_VERSION += "-{0}".format(commit) + + if __name__ == '__main__': print(VERSION) Index: version.py =================================================================== diff -u -r5818c70699fbe02a31d136f440baee0d9f2cb39d -r900f99812cee2e022fbbd46cd916b08a1397dda7 --- version.py (.../version.py) (revision 5818c70699fbe02a31d136f440baee0d9f2cb39d) +++ version.py (.../version.py) (revision 900f99812cee2e022fbbd46cd916b08a1397dda7) @@ -1 +1,42 @@ -dialin/version.py \ No newline at end of file +########################################################################### +# +# Copyright (c) 2019-2020 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 version.py +# +# @author (last) Peter Lucia +# @date (last) 18-Jun-2020 +# @author (original) Peter Lucia +# @date (original) 16-Jun-2020 +# +############################################################################ +import subprocess + + +def get_branch(): + """ + Gets the current branch name in the current git repository + + @return: The current branch name + """ + + return subprocess.check_output("git rev-parse --abbrev-ref HEAD", shell=True).decode("utf-8").strip() + + +def get_last_commit(): + """ + Gets the latest commit in the current git repository + + @return: (str) the latest commit in the current git repository + """ + return subprocess.check_output("git rev-parse --short=7 HEAD", shell=True).decode("utf-8").strip() + + +VERSION = "0.5.0-{0}-{1}".format(get_branch(), get_last_commit()) + + +if __name__ == '__main__': + print(VERSION)