Index: dialin/hd/blood_flow.py =================================================================== diff -u -r50e6e3b5859850f154cbd59976f0f94565efcddc -rd134777c4f35ca58a14720a668c155bed3b0c124 --- dialin/hd/blood_flow.py (.../blood_flow.py) (revision 50e6e3b5859850f154cbd59976f0f94565efcddc) +++ dialin/hd/blood_flow.py (.../blood_flow.py) (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -18,6 +18,7 @@ DenaliChannels) from ..utils.conversions import integer_to_bytearray, float_to_bytearray from .constants import RESET, NO_RESET +from .constants import PUMP_CONTROL_MODE_CLOSED_LOOP, PUMP_CONTROL_MODE_OPEN_LOOP from ..utils.base import _AbstractSubSystem, _publish import struct @@ -174,21 +175,23 @@ self.measured_blood_pump_mc_current = mccurr[0] self.pwm_duty_cycle_pct = pwm[0] - def cmd_blood_flow_set_point_override(self, flow, reset=NO_RESET): + def cmd_blood_flow_set_point_override(self, flow, mode=PUMP_CONTROL_MODE_CLOSED_LOOP, reset=NO_RESET): """ Constructs and sends the blood flow set point override command Constraints: Must be logged into HD. - Given flow rate must be valid (<= 500 mL/min). + Given flow rate must be valid (<= +/-500 mL/min). @param flow: integer - flow set point (in mL/min) to override with (negative for reverse direction) + @param mode: integer - 0 for closed loop control mode or 1 for open loop control mode @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) flo = integer_to_bytearray(flow) - payload = rst + flo + mod = integer_to_bytearray(mode) + payload = rst + flo + mod message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_BLOOD_FLOW_SET_RATE_OVERRIDE, @@ -206,8 +209,12 @@ str_res = "reset back to normal" else: str_res = str(flow) + if mode == PUMP_CONTROL_MODE_OPEN_LOOP: + str_mode = " (open loop): " + else: + str_mode = " (closed loop): " print( - "Blood flow set point overridden to " + str_res + " mL/min: " + + "Blood flow set point overridden to " + str_res + " mL/min" + str_mode + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] Index: dialin/hd/constants.py =================================================================== diff -u -r05353eded4d42bb6db53eb398486254af20f7cf0 -rd134777c4f35ca58a14720a668c155bed3b0c124 --- dialin/hd/constants.py (.../constants.py) (revision 05353eded4d42bb6db53eb398486254af20f7cf0) +++ dialin/hd/constants.py (.../constants.py) (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -17,5 +17,9 @@ RESET = 1 NO_RESET = 0 + BUTTON_PRESSED = 1 BUTTON_RELEASED = 0 + +PUMP_CONTROL_MODE_CLOSED_LOOP = 0 +PUMP_CONTROL_MODE_OPEN_LOOP = 1 Index: dialin/hd/dialysate_inlet_flow.py =================================================================== diff -u -r50e6e3b5859850f154cbd59976f0f94565efcddc -rd134777c4f35ca58a14720a668c155bed3b0c124 --- dialin/hd/dialysate_inlet_flow.py (.../dialysate_inlet_flow.py) (revision 50e6e3b5859850f154cbd59976f0f94565efcddc) +++ dialin/hd/dialysate_inlet_flow.py (.../dialysate_inlet_flow.py) (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -19,6 +19,7 @@ DenaliChannels) from ..utils.conversions import integer_to_bytearray, float_to_bytearray from .constants import RESET, NO_RESET +from .constants import PUMP_CONTROL_MODE_CLOSED_LOOP, PUMP_CONTROL_MODE_OPEN_LOOP from ..utils.base import _AbstractSubSystem, _publish class HDDialysateInletFlow(_AbstractSubSystem): @@ -174,21 +175,23 @@ self.measured_dialysate_inlet_pump_mc_current = mccurr[0] self.pwm_duty_cycle_pct = pwm[0] - def cmd_dialysate_inlet_flow_set_point_override(self, flow, reset=NO_RESET): + def cmd_dialysate_inlet_flow_set_point_override(self, flow, mode=PUMP_CONTROL_MODE_CLOSED_LOOP, reset=NO_RESET): """ Constructs and sends the dialysate flow set point override command Constraints: Must be logged into HD. - Given flow must be valid (<= 600 mL/min). + Given flow must be valid (<= +/-600 mL/min). @param flow: integer - flow set point (in mL/min) to override with + @param mode: integer - 0 for closed loop control mode or 1 for open loop control mode @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ rst = integer_to_bytearray(reset) flo = integer_to_bytearray(flow) - payload = rst + flo + mod = integer_to_bytearray(mode) + payload = rst + flo + mod message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_HD_DIAL_IN_FLOW_SET_RATE_OVERRIDE, @@ -206,8 +209,12 @@ str_res = "reset back to normal" else: str_res = str(flow) + if mode == PUMP_CONTROL_MODE_OPEN_LOOP: + str_mode = " (open loop): " + else: + str_mode = " (closed loop): " print( - "Dialysate flow set point overridden to " + str_res + " mL/min: " + + "Dialysate flow set point overridden to " + str_res + " mL/min" + str_mode + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] Index: dialin/hd/dialysate_outlet_flow.py =================================================================== diff -u -rde84f2977320059c68913d3cd6bbeb7837433c0c -rd134777c4f35ca58a14720a668c155bed3b0c124 --- dialin/hd/dialysate_outlet_flow.py (.../dialysate_outlet_flow.py) (revision de84f2977320059c68913d3cd6bbeb7837433c0c) +++ dialin/hd/dialysate_outlet_flow.py (.../dialysate_outlet_flow.py) (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -19,6 +19,7 @@ DenaliChannels) from ..utils.conversions import integer_to_bytearray, float_to_bytearray from .constants import RESET, NO_RESET +from .constants import PUMP_CONTROL_MODE_CLOSED_LOOP, PUMP_CONTROL_MODE_OPEN_LOOP from ..utils.base import _AbstractSubSystem, _publish @@ -30,6 +31,7 @@ # 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_SET_RATE_OVERRIDE = 0x8001 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 @@ -171,6 +173,53 @@ self.measured_dialysate_outlet_pump_mc_current = mccurr[0] self.pwm_duty_cycle_pct = pwm[0] + def cmd_dialysate_outlet_flow_set_point_override(self, flow, mode=PUMP_CONTROL_MODE_CLOSED_LOOP, reset=NO_RESET): + """ + Constructs and sends the dialysate outlet pump 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 mode: integer - 0 for closed loop control mode or 1 for open loop control mode + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + rst = integer_to_bytearray(reset) + flo = integer_to_bytearray(flow) + mod = integer_to_bytearray(mode) + payload = rst + flo + mod + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_HD_DIAL_OUT_FLOW_SET_RATE_OVERRIDE, + payload=payload) + + print("override dialysate outlet pump set point") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # print(received_message) + if reset == RESET: + str_res = "reset back to stopped" + else: + str_res = str(flow) + if mode == PUMP_CONTROL_MODE_OPEN_LOOP: + str_mode = " (open loop): " + else: + str_mode = " (closed loop): " + print( + "Dialysate outlet pump set point overridden to " + str_res + " mL/min" + str_mode + + 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 cmd_dialysate_outlet_reference_uf_volume_override(self, refvol, reset=NO_RESET): """ Constructs and sends the UF reference volume override command Index: tests/hd_test_pumps_open_loop.py =================================================================== diff -u --- tests/hd_test_pumps_open_loop.py (revision 0) +++ tests/hd_test_pumps_open_loop.py (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -0,0 +1,95 @@ +########################################################################### +# +# 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 hd_pumps_open_loop.py +# +# @author (last) Peman Montazemi +# @date (last) 30-Jul-2020 +# @author (original) Peman Montazemi +# @date (original) 24-Jul-2020 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.hd.constants import RESET, NO_RESET +from dialin.hd.constants import PUMP_CONTROL_MODE_CLOSED_LOOP, PUMP_CONTROL_MODE_OPEN_LOOP +from dialin.hd.hemodialysis_device import HD +from time import sleep +import unittest + +class Test(unittest.TestCase): + def hd_test_pumps_open_loop(self): + """ + Sets the target flow rate for all HD pumps using + \returns None + """ + + # Create an instance of the HD Class called hd + hd = HD() + sleep(1) + + # Set HD open loop pumps flow rates in mL/min + HD_BLOOD_PUMP_FLOW_RATE = 200 + HD_DIALYSATE_PUMP_IN_FLOW_RATE = 200 + HD_DIALYSATE_PUMP_OUT_FLOW_RATE = 200 + + # Log in to HD as tester + if hd.cmd_log_in_to_hd() == 0: + print("HD login failed.") + exit(1) + sleep(1) + + # Reset all flow rate broadcast intervals + hd.bloodflow.cmd_blood_flow_broadcast_interval_override(RESET, 0) + sleep(1) + hd.dialysate_inlet_flow.cmd_dialysate_inlet_flow_broadcast_interval_override(RESET, 0) + sleep(1) + hd.dialysate_outlet_flow.cmd_dialysate_outlet_flow_broadcast_interval_override(RESET, 0) + sleep(1) + + # Reset all flow rate set points + hd.bloodflow.cmd_blood_flow_set_point_override(RESET, 0) + sleep(1) + hd.dialysate_inlet_flow.cmd_dialysate_inlet_flow_set_point_override(RESET, 0) + sleep(1) + hd.dialysate_outlet_flow.cmd_dialysate_outlet_flow_set_point_override(RESET, 0) + sleep(1) + + # Reset all flow rate measures + hd.bloodflow.cmd_blood_flow_measured_override(RESET, 0) + sleep(1) + hd.dialysate_inlet_flow.cmd_dialysate_inlet_flow_measured_override(RESET, 0) + sleep(1) + hd.dialysate_outlet_flow.cmd_dialysate_outlet_flow_measured_override(RESET, 0) + sleep(1) + + # Set HD pumps flow rates (open loop) + hd.bloodflow.cmd_blood_flow_set_point_override(HD_BLOOD_PUMP_FLOW_RATE, PUMP_CONTROL_MODE_OPEN_LOOP) + hd.dialysate_inlet_flow.cmd_dialysate_inlet_flow_set_point_override(HD_DIALYSATE_PUMP_IN_FLOW_RATE, PUMP_CONTROL_MODE_OPEN_LOOP) + hd.dialysate_outlet_flow.cmd_dialysate_outlet_flow_set_point_override(HD_DIALYSATE_PUMP_OUT_FLOW_RATE, PUMP_CONTROL_MODE_OPEN_LOOP) + sleep(5) + + print("Blood Flow Target = {}".format(hd.bloodflow.target_blood_flow_rate)) + print("Dialysate Flow In Target = {}".format(hd.dialysate_inlet_flow.target_dialysate_inlet_flow_rate)) + print("Dialysate Flow Out Target = {}".format(hd.dialysate_outlet_flow.target_dialysate_outlet_flow_rate)) + sleep(1) + + i = 0 + while True: + sleep(0.5) + print("Measured Blood Flow = {} mL/min".format(hd.bloodflow.measured_blood_flow_rate)) + print("Measured Dialysate Flow In = {} mL/min".format(hd.dialysate_inlet_flow.measured_dialysate_inlet_flow_rate)) + print("Measured Dialysate Flow Out = {} mL/min".format(hd.dialysate_outlet_flow.measured_dialysate_outlet_flow_rate)) + if i > 0 and i % 60 == 0: + resp = input("Press 'Enter' to continue or 'q' to quit: ") + if resp.lower() == "q": + break + i += 1 + + +if __name__ == '__main__': + unittest.main(verbosity=2) Index: tests/hd_test_script.py =================================================================== diff -u -r4cb37e8ec3d57576aea76c8aae84130d3adb3ab1 -rd134777c4f35ca58a14720a668c155bed3b0c124 --- tests/hd_test_script.py (.../hd_test_script.py) (revision 4cb37e8ec3d57576aea76c8aae84130d3adb3ab1) +++ tests/hd_test_script.py (.../hd_test_script.py) (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -76,10 +76,9 @@ # hd.bloodflow.cmd_blood_flow_broadcast_interval_override(RESET,0) - # FIXME: Update passing criteria + # TODO: Update passing criteria self.assertTrue(True) if __name__ == '__main__': unittest.main(verbosity=2) - Index: tests/set_RTCs.py =================================================================== diff -u --- tests/set_RTCs.py (revision 0) +++ tests/set_RTCs.py (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -0,0 +1,42 @@ +########################################################################### +# +# 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 set_RTCs.py +# +# @date 05-Aug-2020 +# @author S. Nash +# +# @brief This script sets the RTC (clock) for the HD and DG to the current +# date and time. +# +############################################################################ + +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD +from dialin.dg.dialysate_generator import DG +from time import sleep +from time import time +from time import localtime + +if __name__ == "__main__": + # create an HD object called hd + hd = HD() + # create a DG object called dg + dg = DG() + sleep(2) + + current_time_stamp = time() + current_time = localtime(current_time_stamp) + + hd.rtc.cmd_set_rtc_time_and_date(current_time.tm_sec, + current_time.tm_min, + current_time.tm_hour, + current_time.tm_mday, + current_time.tm_mon, + current_time.tm_year) + #TODO - set DG clock when supported Index: tests/set_accels_cal.py =================================================================== diff -u --- tests/set_accels_cal.py (revision 0) +++ tests/set_accels_cal.py (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -0,0 +1,59 @@ +########################################################################### +# +# 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 set_accels_cal.py +# +# @date 05-Aug-2020 +# @author S. Nash +# +# @brief This script calibrates the HD and DG accelerometers. The HD and DG +# sub-systems should be leveled prior to running this script. +# +############################################################################ + +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD +from dialin.dg.dialysate_generator import DG +from time import sleep + +if __name__ == "__main__": + # create an HD object called hd + hd = HD() + # create an DG object called hd + dg = DG() + sleep(2) + + # log in to HD and DG as tester + if hd.cmd_log_in_to_hd() == 0: + exit(1) + if dg.cmd_log_in_to_dg() == 0: + exit(1) + sleep(1) + + #reset calibrations + hd.accel.cmd_set_accel_calibration(0, 0, 0) + dg.accel.cmd_set_accel_calibration(0, 0, 0) + + #wait for new readings after calibration reset + sleep(5) + + #calculate offsets (assuming HD and DG systems are level) + hd_offsets = hd.accel.get_accel_vector() + dg_offsets = dg.accel.get_accel_vector() + hd_offsets.x *= -1 + hd_offsets.y *= -1 + hd_offsets.z -= 1 + hd_offsets.z *= -1 + dg_offsets.x *= -1 + dg_offsets.y *= -1 + dg_offsets.z -= 1 + dg_offsets.z *= -1 + + #set new offsets + hd.accel.cmd_set_accel_calibration(hd_offsets.x, hd_offsets.y, hd_offsets.z) + dg.accel.cmd_set_accel_calibration(dg_offsets.x, dg_offsets.y, dg_offsets.z) Index: tests/set_flow_sensors_cal.py =================================================================== diff -u --- tests/set_flow_sensors_cal.py (revision 0) +++ tests/set_flow_sensors_cal.py (revision d134777c4f35ca58a14720a668c155bed3b0c124) @@ -0,0 +1,36 @@ +########################################################################### +# +# 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 set_flow_sensors_cal.py +# +# @date 05-Aug-2020 +# @author S. Nash +# +# @brief This script sets the HD blood and dialysate flow sensor calibration +# factors (gain and offset). These calibration factors must be determined +# beforehand and typed in below prior to running this script. +# +############################################################################ + +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD +from time import sleep + +if __name__ == "__main__": + # create an HD object called hd + hd = HD() + sleep(2) + + # log in to HD as tester + if hd.cmd_log_in_to_hd() == 0: + exit(1) + sleep(1) + + #set calibrations ******** MUST PROVIDE GAIN/OFFSET FOR EACH SENSOR HERE ********* + hd.bloodflow.cmd_set_blood_flow_calibration(1.27, -50.0) + hd.dialysate_inlet_flow.cmd_set_dialysate_flow_calibration(1.14, -3.67)