Index: HemodialysisDevice.py =================================================================== diff -u -r2a04f65829931c2e7dc62c6722a53da935cc32fb -r31b7863514f8099122a029151172cda9d1880d90 --- HemodialysisDevice.py (.../HemodialysisDevice.py) (revision 2a04f65829931c2e7dc62c6722a53da935cc32fb) +++ HemodialysisDevice.py (.../HemodialysisDevice.py) (revision 31b7863514f8099122a029151172cda9d1880d90) @@ -46,9 +46,10 @@ self.can_interface.start() # Create command groups self._Basics = HD.HD__Basics(self) - self.Alarms = HD.HD_Alarms(self) + self.Alarms = HD.HD_Alarms(self, self.can_interface) self.Buttons = HD.HD_Buttons(self) self.BloodFlow = HD.HD_BloodFlow(self, self.can_interface) + self.DialysateInletFlow = HD.HD_DialysateInletFlow(self, self.can_interface) self.Watchdog = HD.HD_Watchdog(self) class HD__Basics: @@ -316,7 +317,9 @@ 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_ALARMS_FLAGS = END_POS_ALARM_SILENCE_EXPIRES_IN + 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): @@ -330,14 +333,15 @@ self.outer_instance = outer_instance if can_interface is not None: - channel_id = DenaliChannels.hd_sync_broadcast_ch_id + 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): @@ -358,6 +362,9 @@ 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) @@ -552,7 +559,7 @@ self.MeasuredBloodPumpRotorSpeed = 0.0 self.MeasuredBloodPumpSpeed = 0.0 self.MeasuredBloodPumpMCSpeed = 0.0 - self.MeasuredBloodPumpMCurrent = 0.0 + self.MeasuredBloodPumpMCCurrent = 0.0 self.PWMDutyCyclePct = 0.0 def handlerBloodFlowSyncFunction(self, message): @@ -662,9 +669,6 @@ print("Timeout!!!!") return False - # TODO - add override command for blood pump motor speed (motor hall sensor via FPGA) - # TODO - add override command for blood pump speed (pump hall sensor via NHET?) - def CmdBloodPumpMCMeasuredSpeedOverride(self, reset, speed): """ Constructs and sends the measured blood pump motor controller speed \n @@ -818,7 +822,7 @@ def CmdBloodFlowBroadcastIntervalOverride(self, reset, ms): """ - Constructs and sends the measured flow broadcast interval override command + 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 @@ -853,6 +857,359 @@ 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.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_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.integer2ByteArray(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.integer2ByteArray(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.integer2ByteArray(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.integer2ByteArray(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 + def integer2ByteArray(self, val): """ Converts an integer value into a byte array (little endian) @@ -882,6 +1239,8 @@ sleep(2) hd._Basics.CmdLogInToHD() + hd.BloodFlow.CmdBloodPumpMeasuredCurrentOverride(hd.NO_RESET,149) + tgtRate = 0 hd.BloodFlow.CmdBloodFlowBroadcastIntervalOverride(hd.NO_RESET, 2000)