########################################################################### # # Copyright (c) 2019-2019 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 HemodialysisDevice.py # # @date 16-Oct-2019 # @author S. Nash # # @brief This class provides the basic interface to communicate with # the HD board. # ############################################################################ from DialityCoreCanProtocol import DenaliCanMessenger from DialityCoreCanProtocol import DenaliMessage from DialityCoreCanProtocol import DenaliChannels from time import sleep from binascii import unhexlify #from HD_DialOutFlow import HD_DialOut #from HD_DialOutFlow import DialOutStates import struct import ctypes class HD: # for reset param in override commands NO_RESET = 0 RESET = 1 def __init__(self, can__interface="can0"): """ HD constructor using can bus \param bus: can bus, e.g. "can0" \returns HD object provides test/service commands for the HD sub-system. \details For example: hd_object = HD(can__interface='can0') or hd_object = HD('can0') """ # Create listener self.can_interface = DenaliCanMessenger(can_interface=can__interface) self.can_interface.start() # Create command groups self._Basics = HD.HD__Basics(self) self.Alarms = HD.HD_Alarms(self, self.can_interface) self.BloodFlow = HD.HD_BloodFlow(self, self.can_interface) self.Buttons = HD.HD_Buttons(self) self.DialysateInletFlow = HD.HD_DialysateInletFlow(self, self.can_interface) self.DialysateOutletFlow = HD.HD_DialysateOutletFlow(self, self.can_interface) self.Pressure_Occlusion = HD.HD_Pressure_Occlusion(self, self.can_interface) self.RTC = HD.HD_RTC(self, self.can_interface) self.Treatment = HD.HD_Treatment(self, self.can_interface) self.Watchdog = HD.HD_Watchdog(self) ## DialOut is an HD_DialOutFlow object # self.DialOut = HD_DialOut(self.can_interface) class HD__Basics: """ \class HD__Basics \brief Hemodialysis Device (HD) Dialin API sub-class for basic HD commands. """ # Basic message IDs MSG_ID_LOGIN_TO_HD = 0x8000 MSG_ID_HD_MSG = 0x8001 # HD login password HD_LOGIN_PASSWORD = '123' def __init__(self, outer_instance): self.outer_instance = outer_instance """ HD__Basics constructor \param outer_instance: reference to the HD (outer) class. \returns HD__Basics object. """ def CmdLogInToHD(self): """ Constructs and sends a login command via CAN bus. Login required before \n other commands can be sent to the HD. \returns 1 if logged in, 0 if log in failed """ message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_LOGIN_TO_HD, payload=list(map(int, map(ord, self.HD_LOGIN_PASSWORD)))) print("login") # Send message received_message = self.outer_instance.can_interface.send(message) if received_message is not None: #print(received_message) if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: print("Logged In") else: print("Log In Failed.") #print("Logged In: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdHDMessageInsert(self, msg): """ Constructs and sends the insert HD message command. Given message will \n be inserted into the HD's received message queue for processing. \param msg: byte array - properly formatted HD message to insert \returns 1 if successful, zero otherwise """ message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_MSG, payload=msg) print("insert HD message") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) print("Inserted message: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False class HD_Buttons: """ \class HD_Buttons \brief Hemodialysis Device (HD) Dialin API sub-class for button related commands. """ # Buttons message IDs MSG_ID_HD_OFF_BUTTON_OVERRIDE = 0x8002 MSG_ID_HD_STOP_BUTTON_OVERRIDE = 0x8003 def __init__(self, outer_instance): self.outer_instance = outer_instance """ HD_Buttons constructor \param outer_instance: reference to the HD (outer) class. \returns HD_Buttons object. """ def CmdOffButtonOverride(self, reset, state): """ Constructs and sends the Off button override command \param reset: integer - 1 to reset a previous override, 0 to override \param state: integer - 1 to override off button to "pressed", 0 to "released" \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) sta = self.outer_instance.integer2ByteArray(state) payload = rst + sta message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_OFF_BUTTON_OVERRIDE, payload=payload) print("override off button") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = ("pressed" if state != 0 else "released") print("Off button 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: print("Timeout!!!!") return False def CmdStopButtonOverride(self, reset, state): """ Constructs and sends the Stop button override command \param reset: integer - 1 to reset a previous override, 0 to override \param state: integer - 1 to override stop button to "pressed", 0 to "released" \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) sta = self.outer_instance.integer2ByteArray(state) payload = rst + sta message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_STOP_BUTTON_OVERRIDE, payload=payload) print("override stop button") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = ("pressed" if state != 0 else "released") print("Stop button 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: print("Timeout!!!!") return False class HD_Watchdog: """ \class HD_Watchdog \brief Hemodialysis Device (HD) Dialin API sub-class for watchdog related commands. """ # Watchdog message IDs MSG_ID_HD_WD_CHECKIN_OVERRIDE = 0x8005 def __init__(self, outer_instance): self.outer_instance = outer_instance """ HD_Watchdog constructor \param outer_instance: reference to the HD (outer) class. \returns HD_Watchdog object. """ def CmdWatchdogTaskCheckinOverride(self, reset, state, task): """ Constructs and sends the watchdog task check-in override command \param reset: integer - 1 to reset a previous override, 0 to override \param state: integer - 1 for task checked in, 0 for task not checked in \param task: integer - ID of task to override \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) sta = self.outer_instance.integer2ByteArray(state) tsk = self.outer_instance.integer2ByteArray(task) payload = rst + sta + tsk message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_WD_CHECKIN_OVERRIDE, payload=payload) print("override watchdog task check-in state") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = ("checked in" if state != 0 else "not checked in") print("Watchdog task check-in 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: print("Timeout!!!!") return False class HD_Alarms: """ \class HD_Alarms \brief Hemodialysis Device (HD) Dialin API sub-class for alarm related commands. """ # Alarms message IDs MSG_ID_HD_ALARMS_PUBLISHED_STATUS = 0x0002 MSG_ID_HD_ALARM_LAMP_OVERRIDE = 0x8004 MSG_ID_HD_ALARM_STATE_OVERRIDE = 0x8006 MSG_ID_HD_ALARM_TIME_OVERRIDE = 0x8007 # Alarm lamp patterns HD_ALARM_LAMP_PATTERN_OFF = 0 HD_ALARM_LAMP_PATTERN_OK = 1 HD_ALARM_LAMP_PATTERN_FAULT = 2 HD_ALARM_LAMP_PATTERN_HIGH = 3 HD_ALARM_LAMP_PATTERN_MEDIUM = 4 HD_ALARM_LAMP_PATTERN_LOW = 5 HD_ALARM_LAMP_PATTERN_MANUAL = 6 # Alarm status message field positions START_POS_ALARM_STATE = DenaliMessage.PAYLOAD_START_INDEX END_POS_ALARM_STATE = START_POS_ALARM_STATE + 4 START_POS_ALARM_TOP = END_POS_ALARM_STATE END_POS_ALARM_TOP = START_POS_ALARM_TOP + 4 START_POS_ALARM_SILENCE_EXPIRES_IN = END_POS_ALARM_TOP END_POS_ALARM_SILENCE_EXPIRES_IN = START_POS_ALARM_SILENCE_EXPIRES_IN + 4 START_POS_ALARM_ESCALATES_IN = END_POS_ALARM_SILENCE_EXPIRES_IN END_POS_ALARM_ESCALATES_IN = START_POS_ALARM_ESCALATES_IN + 4 START_POS_ALARMS_FLAGS = END_POS_ALARM_ESCALATES_IN END_POS_ALARMS_FLAGS = START_POS_ALARMS_FLAGS + 2 def __init__(self, outer_instance, can_interface=None): """ HD_Alarms constructor \param outer_instance: reference to the HD (outer) class. \returns HD_Alarms object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_alarm_broadcast_ch_id msg_id = self.MSG_ID_HD_ALARMS_PUBLISHED_STATUS can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerAlarmsStatusSyncFunction) self.alarmsState = 0 self.alarmTop = 0 self.alarmsSilenceExpiresIn = 0 self.alarmsEscalatesIn = 0 self.alarmsFlags = 0 def handlerAlarmsStatusSyncFunction(self, message): """ Handles published alarms status messages. Alarms status data are captured for reference. \param message: published blood flow data message \returns none """ self.alarmsState = int.from_bytes(bytearray( message['message'][self.START_POS_ALARM_STATE:self.END_POS_ALARM_STATE]), byteorder=DenaliMessage.BYTE_ORDER) self.alarmTop = int.from_bytes(bytearray( message['message'][self.START_POS_ALARM_TOP:self.END_POS_ALARM_TOP]), byteorder=DenaliMessage.BYTE_ORDER) self.alarmsSilenceExpiresIn = int.from_bytes(bytearray( message['message'][self.START_POS_ALARM_SILENCE_EXPIRES_IN:self.END_POS_ALARM_SILENCE_EXPIRES_IN]), byteorder=DenaliMessage.BYTE_ORDER) self.alarmsEscalatesIn = int.from_bytes(bytearray( message['message'][self.START_POS_ALARM_ESCALATES_IN:self.END_POS_ALARM_ESCALATES_IN]), byteorder=DenaliMessage.BYTE_ORDER) self.alarmsFlags = int.from_bytes(bytearray( message['message'][self.START_POS_ALARMS_FLAGS:self.END_POS_ALARMS_FLAGS]), byteorder=DenaliMessage.BYTE_ORDER) def CmdAlarmStateOverride(self, reset, state, alarm): """ Constructs and sends the alarm state override command \param reset: integer - 1 to reset a previous override, 0 to override \param state: integer - 1 for alarm active, 0 for alarm inactive \param alarm: integer - ID of alarm to override \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) sta = self.outer_instance.integer2ByteArray(state) alm = self.outer_instance.integer2ByteArray(alarm) payload = rst + sta + alm message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_ALARM_STATE_OVERRIDE, payload=payload) print("override alarm state") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = ("active" if state != 0 else "inactive") print("Alarm state 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: print("Timeout!!!!") return False def CmdAlarmTimeOverride(self, reset, time_ms, alarm): """ Constructs and sends the alarm time override command \param reset: integer - 1 to reset a previous override, 0 to override \param time_ms: integer - time (in ms) since alarm was activated \param alarm: integer - ID of alarm to override \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) ms = self.outer_instance.integer2ByteArray(time_ms) alm = self.outer_instance.integer2ByteArray(alarm) payload = rst + ms + alm message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_ALARM_TIME_OVERRIDE, payload=payload) print("override alarm time since activated") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(time_ms) print("Alarm time since activated overridden to " + str_res + " ms: " + str( received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdAlarmLampPatternOverride(self, reset, pattern): """ Constructs and sends the alarm lamp pattern override command. \param reset: integer - 1 to reset a previous override, 0 to override \param pattern: integer - ID of alarm lamp pattern to override with \returns 1 if successful, zero otherwise \details Patterns: \n 0 = off \n 1 = ok \n 2 = fault \n 3 = high \n 4 = medium \n 5 = low \n 6 = manual """ rst = self.outer_instance.integer2ByteArray(reset) pat = self.outer_instance.integer2ByteArray(pattern) payload = rst + pat message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.CmdAlarmLampPatternOverride(), payload=payload) print("override alarm lamp pattern") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: print(received_message) if reset == HD.RESET: str_pat = "reset back to normal" elif pattern == self.HD_ALARM_LAMP_PATTERN_OFF: str_pat = "off" elif pattern == self.HD_ALARM_LAMP_PATTERN_OK: str_pat = "ok" elif pattern == self.HD_ALARM_LAMP_PATTERN_FAULT: str_pat = "fault" elif pattern == self.HD_ALARM_LAMP_PATTERN_HIGH: str_pat = "high" elif pattern == self.HD_ALARM_LAMP_PATTERN_MEDIUM: str_pat = "medium" elif pattern == self.HD_ALARM_LAMP_PATTERN_LOW: str_pat = "low" else: str_pat = "manual" print("Alarm lamp pattern overridden to " + str_pat + ":" + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False class HD_RTC: MSG_ID_SET_RTC_DATE_TIME = 0x801D MSG_ID_RTC_EPOCH = 0x000A START_POS_SET_PT = DenaliMessage.PAYLOAD_START_INDEX END_POS_SET_PT = START_POS_SET_PT + 4 def __init__(self, outer_instance, can_interface=None): """ HD_BloodFlow constructor \param outer_instance: reference to the HD (outer) class. \returns HD_BloodFlow object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_RTC_EPOCH can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerRTCEpoch) self.RTCEpoch = 0 def handlerRTCEpoch(self, message): """ Publishes the RTC time in epoch \param message: published RTC epoch message \returns none """ epoch = int.from_bytes(bytearray( message['message'][self.START_POS_SET_PT:self.END_POS_SET_PT]), byteorder=DenaliMessage.BYTE_ORDER) self.RTCEpoch = ctypes.c_uint32(epoch) def CmdSetRTCTimeAndDate(self, secs, mins, hours, days, months, years): """ Constructs and sends the time and date to be written to RTC \returns 1 if successful, zero otherwise """ sec = bytes([secs]) min = bytes([mins]) hour = bytes([hours]) day = bytes([days]) month = bytes([months]) year = self.outer_instance.integer2ByteArray(years) payload = sec + min + hour + day + month + year message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_SET_RTC_DATE_TIME, payload=payload) print("Setting time and date to RTC") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: print(received_message) #str_res = str(flow) print("Time and Date in RTC set to seconds: " + str(sec) + " minutes: " + str(min) + " hours: " + str(hour) + " days: " + str(day) + " months: " + str(month) + " years: " + str(year) + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False class HD_BloodFlow: """ \class HD_BloodFlow \brief Hemodialysis Device (HD) Dialin API sub-class for blood-flow related commands. """ # BloodFlow message IDs MSG_ID_HD_BLOOD_FLOW_PUBLISHED_DATA = 0x0005 MSG_ID_HD_BLOOD_FLOW_SET_RATE_OVERRIDE = 0x8008 MSG_ID_HD_BLOOD_FLOW_MEAS_RATE_OVERRIDE = 0x8009 MSG_ID_HD_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE = 0x800A MSG_ID_HD_BLOOD_PUMP_MC_MEAS_CURRENT_OVERRIDE = 0x800B MSG_ID_HD_BLOOD_FLOW_PUBLISH_INTERVAL_OVERRIDE = 0x800C MSG_ID_HD_BLOOD_PUMP_MEAS_SPEED_OVERRIDE = 0x800E MSG_ID_HD_BLOOD_PUMP_ROTOR_MEAS_SPEED_OVERRIDE = 0x800F # BloodFlow broadcast message field positions START_POS_SET_PT = DenaliMessage.PAYLOAD_START_INDEX END_POS_SET_PT = START_POS_SET_PT + 4 START_POS_MEAS_FLOW = END_POS_SET_PT END_POS_MEAS_FLOW = START_POS_MEAS_FLOW + 4 START_POS_MEAS_ROT_SPEED = END_POS_MEAS_FLOW END_POS_MEAS_ROT_SPEED = START_POS_MEAS_ROT_SPEED + 4 START_POS_MEAS_SPEED = END_POS_MEAS_ROT_SPEED END_POS_MEAS_SPEED = START_POS_MEAS_SPEED + 4 START_POS_MEAS_MC_SPEED = END_POS_MEAS_SPEED END_POS_MEAS_MC_SPEED = START_POS_MEAS_MC_SPEED + 4 START_POS_MEAS_MC_CURR = END_POS_MEAS_MC_SPEED END_POS_MEAS_MC_CURR = START_POS_MEAS_MC_CURR + 4 START_POS_PWM_DC = END_POS_MEAS_MC_CURR END_POS_PWM_DC = START_POS_PWM_DC + 4 def __init__(self, outer_instance, can_interface=None): """ HD_BloodFlow constructor \param outer_instance: reference to the HD (outer) class. \returns HD_BloodFlow object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_HD_BLOOD_FLOW_PUBLISHED_DATA can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerBloodFlowSyncFunction) self.TargetBloodFlowRate = 0 self.MeasuredBloodFlowRate = 0.0 self.MeasuredBloodPumpRotorSpeed = 0.0 self.MeasuredBloodPumpSpeed = 0.0 self.MeasuredBloodPumpMCSpeed = 0.0 self.MeasuredBloodPumpMCCurrent = 0.0 self.PWMDutyCyclePct = 0.0 def handlerBloodFlowSyncFunction(self, message): """ Handles published blood flow data messages. Blood flow data are captured for reference. \param message: published blood flow data message \returns none """ #self.TargetBloodFlowRate = int.from_bytes(bytearray( # message['message'][self.START_POS_SET_PT:self.END_POS_SET_PT]), # byteorder=DenaliMessage.BYTE_ORDER) tgt = struct.unpack('i',bytearray( message['message'][self.START_POS_SET_PT:self.END_POS_SET_PT])) flow = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_FLOW:self.END_POS_MEAS_FLOW])) rotor = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_ROT_SPEED:self.END_POS_MEAS_ROT_SPEED])) speed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_SPEED:self.END_POS_MEAS_SPEED])) mcspeed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_SPEED:self.END_POS_MEAS_MC_SPEED])) mccurr = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_CURR:self.END_POS_MEAS_MC_CURR])) pwm = struct.unpack('f', bytearray( message['message'][self.START_POS_PWM_DC:self.END_POS_PWM_DC])) self.TargetBloodFlowRate = tgt[0] self.MeasuredBloodFlowRate = flow[0] self.MeasuredBloodPumpRotorSpeed = rotor[0] self.MeasuredBloodPumpSpeed = speed[0] self.MeasuredBloodPumpMCSpeed = mcspeed[0] self.MeasuredBloodPumpMCCurrent = mccurr[0] self.PWMDutyCyclePct = pwm[0] def CmdBloodFlowSetPointOverride(self, reset, flow): """ Constructs and sends the blood flow set point override command \param reset: integer - 1 to reset a previous override, 0 to override \param flow: integer - flow set point (in mL/min) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) flo = self.outer_instance.integer2ByteArray(flow) payload = rst + flo message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_FLOW_SET_RATE_OVERRIDE, payload=payload) print("override blood flow set point") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(flow) print( "Blood flow set point overridden to " + str_res + " mL/min: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodFlowMeasuredOverride(self, reset, flow): """ Constructs and sends the measured blood flow override command \param reset: integer - 1 to reset a previous override, 0 to override \param flow: integer - measured flow (in mL/min) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) flo = self.outer_instance.float2ByteArray(flow) payload = rst + flo message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_FLOW_MEAS_RATE_OVERRIDE, payload=payload) print("override measured blood flow") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(flow) print("Blood flow (measured)) overridden to " + str_res + " mL/min: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodPumpMCMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured blood pump motor controller speed \n override command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_PUMP_MC_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured blood pump motor controller speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Blood pump MC speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodPumpMeasuredCurrentOverride(self, reset, curr): """ Constructs and sends the measured blood pump motor current override command \param reset: integer - 1 to reset a previous override, 0 to override \param curr: float - current (in mA) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) cur = self.outer_instance.float2ByteArray(curr) payload = rst + cur message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_PUMP_MC_MEAS_CURRENT_OVERRIDE, payload=payload) print("override measured blood pump motor controller current") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(curr) print("Blood pump MC current (measured) overridden to " + str_res + " mA: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodPumpMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured blood pump motor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_PUMP_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured blood pump speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Blood pump speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodPumpRotorMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured blood pump rotor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_PUMP_ROTOR_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured blood pump rotor speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Blood pump rotor speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdBloodFlowBroadcastIntervalOverride(self, reset, ms): """ Constructs and sends the measured blood flow broadcast interval override command \param reset: integer - 1 to reset a previous override, 0 to override \param ms: integer - interval (in ms) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) mis = self.outer_instance.integer2ByteArray(ms) payload = rst + mis message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_FLOW_PUBLISH_INTERVAL_OVERRIDE, payload=payload) print("override blood flow broadcast interval") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal: " else: str_res = str(ms) + " ms: " print("Blood flow 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: print("Timeout!!!!") return False class HD_DialysateInletFlow: """ \class HD_DialysateInletFlow \brief Hemodialysis Device (HD) Dialin API sub-class for dialysate inlet pump related commands. """ # DialysateFlow message IDs MSG_ID_HD_DIAL_IN_FLOW_PUBLISHED_DATA = 0x0006 MSG_ID_HD_DIAL_IN_FLOW_SET_RATE_OVERRIDE = 0x8010 MSG_ID_HD_DIAL_IN_FLOW_MEAS_RATE_OVERRIDE = 0x8011 MSG_ID_HD_DIAL_IN_PUMP_MC_MEAS_SPEED_OVERRIDE = 0x8012 MSG_ID_HD_DIAL_IN_PUMP_MC_MEAS_CURRENT_OVERRIDE = 0x8013 MSG_ID_HD_DIAL_IN_FLOW_PUBLISH_INTERVAL_OVERRIDE = 0x8014 MSG_ID_HD_DIAL_IN_PUMP_MEAS_SPEED_OVERRIDE = 0x8015 MSG_ID_HD_DIAL_IN_PUMP_ROTOR_MEAS_SPEED_OVERRIDE = 0x8016 # BloodFlow broadcast message field positions START_POS_SET_PT = DenaliMessage.PAYLOAD_START_INDEX END_POS_SET_PT = START_POS_SET_PT + 4 START_POS_MEAS_FLOW = END_POS_SET_PT END_POS_MEAS_FLOW = START_POS_MEAS_FLOW + 4 START_POS_MEAS_ROT_SPEED = END_POS_MEAS_FLOW END_POS_MEAS_ROT_SPEED = START_POS_MEAS_ROT_SPEED + 4 START_POS_MEAS_SPEED = END_POS_MEAS_ROT_SPEED END_POS_MEAS_SPEED = START_POS_MEAS_SPEED + 4 START_POS_MEAS_MC_SPEED = END_POS_MEAS_SPEED END_POS_MEAS_MC_SPEED = START_POS_MEAS_MC_SPEED + 4 START_POS_MEAS_MC_CURR = END_POS_MEAS_MC_SPEED END_POS_MEAS_MC_CURR = START_POS_MEAS_MC_CURR + 4 START_POS_PWM_DC = END_POS_MEAS_MC_CURR END_POS_PWM_DC = START_POS_PWM_DC + 4 def __init__(self, outer_instance, can_interface=None): """ HD_DialysateFlow constructor \param outer_instance: reference to the HD (outer) class. \returns HD_DialysateFlow object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_HD_DIAL_IN_FLOW_PUBLISHED_DATA can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerDialysateInletFlowSyncFunction) self.TargetDialysateInletFlowRate = 0 self.MeasuredDialysateInletFlowRate = 0.0 self.MeasuredDialysateInletPumpRotorSpeed = 0.0 self.MeasuredDialysateInletPumpSpeed = 0.0 self.MeasuredDialysateInletPumpMCSpeed = 0.0 self.MeasuredDialysateInletPumpMCCurrent = 0.0 self.PWMDutyCyclePct = 0.0 def handlerDialysateInletFlowSyncFunction(self, message): """ Handles published dialysate inlet flow data messages. Dialysate flow data are captured for reference. \param message: published dialysate flow data message \returns none """ self.TargetDialysateInletFlowRate = int.from_bytes(bytearray( message['message'][self.START_POS_SET_PT:self.END_POS_SET_PT]), byteorder=DenaliMessage.BYTE_ORDER) flow = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_FLOW:self.END_POS_MEAS_FLOW])) rotor = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_ROT_SPEED:self.END_POS_MEAS_ROT_SPEED])) speed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_SPEED:self.END_POS_MEAS_SPEED])) mcspeed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_SPEED:self.END_POS_MEAS_MC_SPEED])) mccurr = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_CURR:self.END_POS_MEAS_MC_CURR])) pwm = struct.unpack('f', bytearray( message['message'][self.START_POS_PWM_DC:self.END_POS_PWM_DC])) self.MeasuredDialysateInletFlowRate = flow[0] self.MeasuredDialysateInletPumpRotorSpeed = rotor[0] self.MeasuredDialysateInletPumpSpeed = speed[0] self.MeasuredDialysateInletPumpMCSpeed = mcspeed[0] self.MeasuredDialysateInletPumpMCCurrent = mccurr[0] self.PWMDutyCyclePct = pwm[0] def CmdDialysateInletFlowSetPointOverride(self, reset, flow): """ Constructs and sends the dialysate flow set point override command \param reset: integer - 1 to reset a previous override, 0 to override \param flow: integer - flow set point (in mL/min) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) flo = self.outer_instance.integer2ByteArray(flow) payload = rst + flo message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_FLOW_SET_RATE_OVERRIDE, payload=payload) print("override dialysate flow set point") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(flow) print( "Dialysate flow set point overridden to " + str_res + " mL/min: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletFlowMeasuredOverride(self, reset, flow): """ Constructs and sends the measured dialysate flow override command \param reset: integer - 1 to reset a previous override, 0 to override \param flow: integer - measured flow (in mL/min) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) flo = self.outer_instance.float2ByteArray(flow) payload = rst + flo message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_FLOW_MEAS_RATE_OVERRIDE, payload=payload) print("override measured dialysate flow") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(flow) print("Dialysate flow (measured)) overridden to " + str_res + " mL/min: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletPumpMCMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate inlet pump motor controller speed \n override command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_PUMP_MC_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured dialysate inlet pump motor controller speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Dialysate pump MC speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletPumpMeasuredCurrentOverride(self, reset, curr): """ Constructs and sends the measured dialysate inlet pump motor current override command \param reset: integer - 1 to reset a previous override, 0 to override \param curr: integer - current (in mA) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) cur = self.outer_instance.float2ByteArray(curr) payload = rst + cur message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_PUMP_MC_MEAS_CURRENT_OVERRIDE, payload=payload) print("override measured dialysate inlet pump motor controller current") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(curr) print("Dialysate inlet pump MC current (measured) overridden to " + str_res + " mA: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletPumpMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate inlet pump motor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_PUMP_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured dialysate inlet pump speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Dialysate inlet pump speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletPumpRotorMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate inlet pump rotor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: integer - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_PUMP_ROTOR_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured dialysate inlet pump rotor speed") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal" else: str_res = str(speed) print("Dialysate inlet pump rotor speed (measured) overridden to " + str_res + " RPM: " + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False def CmdDialysateInletFlowBroadcastIntervalOverride(self, reset, ms): """ Constructs and sends the measured dialysate inlet flow broadcast interval override command \param reset: integer - 1 to reset a previous override, 0 to override \param ms: integer - interval (in ms) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) mis = self.outer_instance.integer2ByteArray(ms) payload = rst + mis message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_FLOW_PUBLISH_INTERVAL_OVERRIDE, payload=payload) print("override dialysate inlet flow broadcast interval") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal: " else: str_res = str(ms) + " ms: " print("Dialysate inlet flow 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: print("Timeout!!!!") return False class HD_DialysateOutletFlow: """ \class HD_DialysateOutletFlow \brief Hemodialysis Device (HD) Dialin API sub-class for dialysate outlet pump related commands. """ # DialysateFlow message IDs MSG_ID_HD_DIAL_OUT_FLOW_PUBLISHED_DATA = 0x000B MSG_ID_HD_LOAD_CELL_READINGS = 0x000C MSG_ID_HD_DIAL_OUT_FLOW_PUBLISH_INTERVAL_OVERRIDE = 0x801E MSG_ID_HD_DIAL_OUT_UF_REF_VOLUME_OVERRIDE = 0x801F MSG_ID_HD_DIAL_OUT_UF_MEAS_VOLUME_OVERRIDE = 0x8020 MSG_ID_HD_DIAL_OUT_PUMP_MC_MEAS_SPEED_OVERRIDE = 0x8021 MSG_ID_HD_DIAL_OUT_PUMP_MC_MEAS_CURRENT_OVERRIDE = 0x8022 MSG_ID_HD_DIAL_OUT_PUMP_MEAS_SPEED_OVERRIDE = 0x8023 MSG_ID_HD_DIAL_OUT_PUMP_ROTOR_MEAS_SPEED_OVERRIDE = 0x8024 MSG_ID_HD_DIAL_OUT_LOAD_CELL_WEIGHT_OVERRIDE = 0x8025 # BloodFlow broadcast message field positions START_POS_REF_VOL = DenaliMessage.PAYLOAD_START_INDEX END_POS_REF_VOL = START_POS_REF_VOL + 4 START_POS_MEAS_VOL = END_POS_REF_VOL END_POS_MEAS_VOL = START_POS_MEAS_VOL + 4 START_POS_MEAS_ROT_SPEED = END_POS_MEAS_VOL END_POS_MEAS_ROT_SPEED = START_POS_MEAS_ROT_SPEED + 4 START_POS_MEAS_SPEED = END_POS_MEAS_ROT_SPEED END_POS_MEAS_SPEED = START_POS_MEAS_SPEED + 4 START_POS_MEAS_MC_SPEED = END_POS_MEAS_SPEED END_POS_MEAS_MC_SPEED = START_POS_MEAS_MC_SPEED + 4 START_POS_MEAS_MC_CURR = END_POS_MEAS_MC_SPEED END_POS_MEAS_MC_CURR = START_POS_MEAS_MC_CURR + 4 START_POS_PWM_DC = END_POS_MEAS_MC_CURR END_POS_PWM_DC = START_POS_PWM_DC + 4 def __init__(self, outer_instance, can_interface=None): """ HD_DialysateFlow constructor \param outer_instance: reference to the HD (outer) class. \returns HD_DialysateFlow object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_HD_DIAL_OUT_FLOW_PUBLISHED_DATA can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerDialysateOutletFlowSyncFunction) self.ReferenceDialysateOutletUFVolume = 0.0 self.MeasuredDialysateOutletUFVolume = 0.0 self.MeasuredDialysateOutletPumpRotorSpeed = 0.0 self.MeasuredDialysateOutletPumpSpeed = 0.0 self.MeasuredDialysateOutletPumpMCSpeed = 0.0 self.MeasuredDialysateOutletPumpMCCurrent = 0.0 self.PWMDutyCyclePct = 0.0 def handlerDialysateOutletFlowSyncFunction(self, message): """ Handles published dialysate outlet flow data messages. Dialysate flow data are captured for reference. \param message: published dialysate outlet flow data message \returns none """ refVol = struct.unpack('f', bytearray( message['message'][self.START_POS_REF_VOL:self.END_POS_REF_VOL])) measVol = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_VOL:self.END_POS_MEAS_VOL])) rotor = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_ROT_SPEED:self.END_POS_MEAS_ROT_SPEED])) speed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_SPEED:self.END_POS_MEAS_SPEED])) mcspeed = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_SPEED:self.END_POS_MEAS_MC_SPEED])) mccurr = struct.unpack('f', bytearray( message['message'][self.START_POS_MEAS_MC_CURR:self.END_POS_MEAS_MC_CURR])) pwm = struct.unpack('f', bytearray( message['message'][self.START_POS_PWM_DC:self.END_POS_PWM_DC])) self.ReferenceDialysateOutletUFVolume = refVol[0] self.MeasuredDialysateOutletUFVolume = measVol[0] self.MeasuredDialysateOutletPumpRotorSpeed = rotor[0] self.MeasuredDialysateOutletPumpSpeed = speed[0] self.MeasuredDialysateOutletPumpMCSpeed = mcspeed[0] self.MeasuredDialysateOutletPumpMCCurrent = mccurr[0] self.PWMDutyCyclePct = pwm[0] def CmdDialysateOutletReferenceUFVolumeOverride(self, reset, refVol): """ Constructs and sends the UF reference volume override command \param reset: integer - 1 to reset a previous override, 0 to override \param refVol: float - reference UF volume (in mL) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) vol = self.outer_instance.float2ByteArray(refVol) payload = rst + vol message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_UF_REF_VOLUME_OVERRIDE, payload=payload) print("override UF reference volume with " + str(refVol) + "mL.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(refVol) + " mL. " print( "UF reference volume " + 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: print("Timeout!!!!") return False def CmdDialysateOutletMeasuredUFVolumeOverride(self, reset, measVol): """ Constructs and sends the measured UF volume override command \param reset: integer - 1 to reset a previous override, 0 to override \param measVol: float - measured UF volume (in mL) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) vol = self.outer_instance.float2ByteArray(measVol) payload = rst + vol message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_UF_MEAS_VOLUME_OVERRIDE, payload=payload) print("override measured UF volume with " + str(measVol) + " mL.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(measVol) + " mL. " print("UF measured volume " + 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpMCMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate outlet pump motor controller speed \n override command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: float - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MeasuredDialysateOutletPumpMCSpeed, payload=payload) print("override measured dialysate outlet pump motor controller speed to " + str(spd) + " RPM.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(speed) + " RPM. " print("Dialysate outlet pump MC speed (measured) " + 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpMeasuredCurrentOverride(self, reset, curr): """ Constructs and sends the measured dialysate outlet pump motor current override command \param reset: integer - 1 to reset a previous override, 0 to override \param curr: float - current (in mA) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) cur = self.outer_instance.float2ByteArray(curr) payload = rst + cur message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_PUMP_MC_MEAS_CURRENT_OVERRIDE, payload=payload) print("override measured dialysate outlet pump motor controller current") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(curr) + " mA. " print("Dialysate outlet pump MC current (measured) " + 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate outlet pump motor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: float - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_PUMP_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured dialysate outlet pump speed to " + str(speed) + " RPM.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(speed) + " RPM. " print("Dialysate outlet pump speed (measured) " + 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpRotorMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured dialysate outlet pump rotor speed override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param speed: float - speed (in RPM) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(speed) payload = rst + spd message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_PUMP_ROTOR_MEAS_SPEED_OVERRIDE, payload=payload) print("override measured dialysate outlet pump rotor speed to " + str(speed) + " RPM.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(speed) + " RPM. " print("Dialysate outlet pump rotor speed (measured) " + 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: print("Timeout!!!!") return False def CmdDialysateOutletFlowBroadcastIntervalOverride(self, reset, ms): """ Constructs and sends the measured dialysate outlet flow broadcast interval override command \param reset: integer - 1 to reset a previous override, 0 to override \param ms: integer - interval (in ms) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) mis = self.outer_instance.integer2ByteArray(ms) payload = rst + mis message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_FLOW_PUBLISH_INTERVAL_OVERRIDE, payload=payload) print("override dialysate outlet flow broadcast interval to " + str(ms) + " ms.") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: #print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(ms) + " ms. " print("Dialysate outlet flow broadcast interval " + 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpLoadCellWeightOverride(self, reset, weight, sensor): """ Constructs and sends the measured load cell weight override command. \param reset: integer - 1 to reset a previous override, 0 to override \param weight: float - weight (in g) to override with \param sensor: integer - ID of load cell to override \returns 1 if successful, zero otherwise \details Load Cells: \n 0 = reservoir 1 primary \n 1 = reservoir 1 backup \n 2 = reservoir 2 primary \n 3 = reservoir 2 backup \n """ rst = self.outer_instance.integer2ByteArray(reset) spd = self.outer_instance.float2ByteArray(weight) sen = self.outer_instance.integer2ByteArray(sensor) payload = rst + spd + sen message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_OUT_LOAD_CELL_WEIGHT_OVERRIDE, payload=payload) print("override measured load cell weight to " + str(weight) + " grams for load cell # " + str(sensor)) # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: # print(received_message) if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = "overridden to " + str(weight) + " grams. " print("Load cell # " + str(sensor) + " " + 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: print("Timeout!!!!") return False def CmdSetLoadCellWeights(self, r1p, r1b, r2p, r2b): """ Constructs and sends the set load cell weights command. \param r1p: float - weight (in g) for reservoir 1 primary load cell \param r1b: float - weight (in g) for reservoir 1 backup load cell \param r2p: float - weight (in g) for reservoir 2 primary load cell \param r2b: float - weight (in g) for reservoir 2 backup load cell \returns 0 - no response will come from HD for this message """ r1pb = self.outer_instance.float2ByteArray(r1p) r1bb = self.outer_instance.float2ByteArray(r1b) r2pb = self.outer_instance.float2ByteArray(r2p) r2bb = self.outer_instance.float2ByteArray(r2b) payload = r1pb + r1bb + r2pb + r2bb message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_LOAD_CELL_READINGS, payload=payload) print("measured load cell weights set.") # Send message received_message = self.outer_instance.can_interface.send(message, 0) return 0 class HD_Treatment: """ \class HD_Treatment \brief Hemodialysis Device (HD) Dialin API sub-class for treatment related commands. """ # BloodFlow message IDs MSG_ID_HD_TREATMENT_TIME_PUBLISHED_DATA = 0x000D # BloodFlow broadcast message field positions START_POS_TIME_PRES = DenaliMessage.PAYLOAD_START_INDEX END_POS_TIME_PRES = START_POS_TIME_PRES + 4 START_POS_TIME_ELAPSED = END_POS_TIME_PRES END_POS_TIME_ELAPSED = START_POS_TIME_ELAPSED + 4 START_POS_TIME_REMAINING = END_POS_TIME_ELAPSED END_POS_TIME_REMAINING = START_POS_TIME_REMAINING + 4 def __init__(self, outer_instance, can_interface=None): """ HD_Treatment constructor \param outer_instance: reference to the HD (outer) class. \returns HD_Treatment object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_HD_TREATMENT_TIME_PUBLISHED_DATA can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerTreatmentTimeSyncFunction) self.TreatmentTimePrescribed = 0 self.TreatmentTimeElapsed = 0 self.TreatmentTimeRemaining = 0 def handlerTreatmentTimeSyncFunction(self, message): """ Handles published treatment time data messages. Treatment time data are captured for reference. \param message: published treatment time data message \returns none """ tot = struct.unpack('i',bytearray( message['message'][self.START_POS_TIME_PRES:self.END_POS_TIME_PRES])) ela = struct.unpack('i',bytearray( message['message'][self.START_POS_TIME_ELAPSED:self.END_POS_TIME_ELAPSED])) rem = struct.unpack('i',bytearray( message['message'][self.START_POS_TIME_REMAINING:self.END_POS_TIME_REMAINING])) self.TreatmentTimePrescribed = tot[0] self.TreatmentTimeElapsed = ela[0] self.TreatmentTimeRemaining = rem[0] class HD_Pressure_Occlusion: """ \class HD_Pressure_Occlusion \brief Hemodialysis Device (HD) Dialin API sub-class for pressure related commands. """ # Pressure/Occlusion message IDs MSG_ID_HD_PRESSURE_OCCLUSION_DATA = 0x0009 MSG_ID_HD_PRESSURE_ARTERIAL_OVERRIDE = 0x8017 MSG_ID_HD_PRESSURE_VENOUS_OVERRIDE = 0x8018 MSG_ID_HD_OCCLUSION_BLOOD_PUMP_OVERRIDE = 0x8019 MSG_ID_HD_OCCLUSION_DIAL_IN_PUMP_OVERRIDE = 0x801A MSG_ID_HD_OCCLUSION_DIAL_OUT_PUMP_OVERRIDE = 0x801B MSG_ID_HD_PRES_OCCL_SEND_INTERVAL_OVERRIDE = 0x801C # Pressure/Occlusion broadcast message field positions START_POS_ART_PRES = DenaliMessage.PAYLOAD_START_INDEX END_POS_ART_PRES = START_POS_ART_PRES + 4 START_POS_VEN_PRES = END_POS_ART_PRES END_POS_VEN_PRES = START_POS_VEN_PRES + 4 START_POS_BP_OCCL = END_POS_VEN_PRES END_POS_BP_OCCL = START_POS_BP_OCCL + 4 START_POS_DIP_OCCL = END_POS_BP_OCCL END_POS_DIP_OCCL = START_POS_DIP_OCCL + 4 START_POS_DOP_OCCL = END_POS_DIP_OCCL END_POS_DOP_OCCL = START_POS_DOP_OCCL + 4 def __init__(self, outer_instance, can_interface=None): """ HD_Pressure_Occlusion constructor \param outer_instance: reference to the HD (outer) class. \returns HD_Pressure_Occlusion object. """ self.outer_instance = outer_instance if can_interface is not None: channel_id = DenaliChannels.hd_sync_broadcast_ch_id msg_id = self.MSG_ID_HD_PRESSURE_OCCLUSION_DATA can_interface.registerReceivingPublicationFunction(channel_id, msg_id, self.handlerPresOcclSyncFunction) self.arterialPressure = 0 self.venousPressure = 0.0 self.bloodPumpOcclusion = 0.0 self.dialysateInletPumpOcclusion = 0.0 self.dialysateOutletPumpOcclusion = 0.0 def handlerPresOcclSyncFunction(self, message): """ Handles published pressure & occlusion data messages. Pressure data are captured for reference. \param message: published pressure & occlusion data message \returns none """ art = struct.unpack('f', bytearray( message['message'][self.START_POS_ART_PRES:self.END_POS_ART_PRES])) ven = struct.unpack('f', bytearray( message['message'][self.START_POS_VEN_PRES:self.END_POS_VEN_PRES])) bp = struct.unpack('f', bytearray( message['message'][self.START_POS_BP_OCCL:self.END_POS_BP_OCCL])) dpi = struct.unpack('f', bytearray( message['message'][self.START_POS_DIP_OCCL:self.END_POS_DIP_OCCL])) dpo = struct.unpack('f', bytearray( message['message'][self.START_POS_DOP_OCCL:self.END_POS_DOP_OCCL])) self.arterialPressure = art[0] self.venousPressure = ven[0] self.bloodPumpOcclusion = bp[0] self.dialysateInletPumpOcclusion = dpi[0] self.dialysateOutletPumpOcclusion = dpo[0] def CmdArterialPressureMeasuredOverride(self, reset, pres): """ Constructs and sends the measured arterial pressure override command \param reset: integer - 1 to reset a previous override, 0 to override \param pres: float - measured arterial pressure (in mmHg) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) prs = self.outer_instance.float2ByteArray(pres) payload = rst + prs message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_PRESSURE_ARTERIAL_OVERRIDE, payload=payload) print("override measured arterial pressure") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = str(pres) + " mmHg. " print("Arterial pressure (measured)) 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: print("Timeout!!!!") return False def CmdVenousPressureMeasuredOverride(self, reset, pres): """ Constructs and sends the measured venous pressure \n override command. \param reset: integer - 1 to reset a previous override, 0 to override \param pres: float - venous pressure (in mmHg) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) prs = self.outer_instance.float2ByteArray(pres) payload = rst + prs message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_PRESSURE_VENOUS_OVERRIDE, payload=payload) print("override measured venous pressure") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = str(pres) + " mmHg. " print("Venous pressure (measured) 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: print("Timeout!!!!") return False def CmdBloodPumpMeasuredOcclusionOverride(self, reset, occl): """ Constructs and sends the measured blood pump occlusion pressure override command \param reset: integer - 1 to reset a previous override, 0 to override \param occl: float - pressure (in mmHg) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) occ = self.outer_instance.float2ByteArray(occl) payload = rst + occ message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_OCCLUSION_BLOOD_PUMP_OVERRIDE, payload=payload) print("override measured blood pump occlusion pressure") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = str(occl) + " mmHg. " print("Blood pump occlusion pressure (measured) 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: print("Timeout!!!!") return False def CmdDialysateInletPumpMeasuredOcclusionOverride(self, reset, occl): """ Constructs and sends the measured dialysate inlet pump occlusion pressure override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param occl: float - pressure (in mmHg) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) occ = self.outer_instance.float2ByteArray(occl) payload = rst + occ message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_OCCLUSION_DIAL_IN_PUMP_OVERRIDE, payload=payload) print("override measured dialysate inlet pump occlusion pressure") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = str(occl) + " mmHg. " print("Dialysate inlet pump occlusion pressure (measured) 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: print("Timeout!!!!") return False def CmdDialysateOutletPumpMeasuredOcclusionOverride(self, reset, occl): """ Constructs and sends the measured dialysate outlet pump occlusion pressure override \n command. \param reset: integer - 1 to reset a previous override, 0 to override \param occl: float - pressure (in mmHg) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) occ = self.outer_instance.float2ByteArray(occl) payload = rst + occ message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_OCCLUSION_DIAL_OUT_PUMP_OVERRIDE, payload=payload) print("override measured dialysate outlet pump occlusion pressure") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal. " else: str_res = str(occl) + " mmHg. " print("Dialysate outlet pump occlusion pressure (measured) 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: print("Timeout!!!!") return False def CmdPressureOcclusionBroadcastIntervalOverride(self, reset, ms): """ Constructs and sends the pressure/occlusion broadcast interval override command \param reset: integer - 1 to reset a previous override, 0 to override \param ms: integer - interval (in ms) to override with \returns 1 if successful, zero otherwise """ rst = self.outer_instance.integer2ByteArray(reset) mis = self.outer_instance.integer2ByteArray(ms) payload = rst + mis message = DenaliMessage.buildMessage(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_PRES_OCCL_SEND_INTERVAL_OVERRIDE, payload=payload) print("override pressure/occlusion broadcast interval") # Send message received_message = self.outer_instance.can_interface.send(message) # If there is content... if received_message is not None: if reset == HD.RESET: str_res = "reset back to normal: " else: str_res = str(ms) + " ms: " print("Pressure/occlusion 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: print("Timeout!!!!") return False def integer2ByteArray(self, val): """ Converts an integer value into a byte array (little endian) \param val: integer to convert to byte array \returns byte array """ fmt = '%08x' # integer to hex string formatter b = unhexlify(fmt % val) # convert int to byte array b = b[::-1] # little endian byte order return b def float2ByteArray(self, val): """ Converts a float value into a byte array (little endian) \param val: float to convert to byte array \returns byte array """ #s = hex(struct.unpack(' After STOP:{} <---".format(hd.DialOut.DialOutBroadcast)) sleep(3) hd.DialOut.setUFState(DialOutStates.RUN) sleep(2) state_stop = hd.DialOut.DialOutBroadcast['state'] print("After RUN again: {}".format(hd.DialOut.DialOutBroadcast)) sleep(3) hd.DialOut.setUFState(DialOutStates.STOP) sleep(2) state_stop = hd.DialOut.DialOutBroadcast['state'] print("After STOP: {}".format(hd.DialOut.DialOutBroadcast)) sleep(5) hd.DialOut.plotBroadCastSignals() exit() tgtRate = 0 hd.BloodFlow.CmdBloodFlowBroadcastIntervalOverride(hd.NO_RESET, 2000) while True: if hd.BloodFlow.TargetBloodFlowRate == 0: if tgtRate != 0: hd.BloodFlow.CmdBloodFlowBroadcastIntervalOverride(hd.NO_RESET, 2000) tgtRate = 0 else: if tgtRate == 0: hd.BloodFlow.CmdBloodFlowBroadcastIntervalOverride(hd.NO_RESET, 200) tgtRate = hd.BloodFlow.TargetBloodFlowRate sleep(1) print(hd.BloodFlow.MeasuredBloodFlowRate) # hd.BloodFlow.CmdBloodFlowBroadcastIntervalOverride(hd.RESET,0) """