Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -r9d9105c7dc3379c2e14996522291b23a19e7ba46 -r42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b) @@ -16,6 +16,7 @@ import struct from time import sleep from .drain_pump import DGDrainPump +from .hd_proxy import DGHDProxy from .load_cells import DGLoadCells from .pressures import DGPressures from .reservoirs import DGReservoirs @@ -86,6 +87,7 @@ self.dg_operation_mode = self.DG_OP_MODE_INIT_POST # Create command groups + self.hd_proxy = DGHDProxy(self.can_interface) self.load_cells = DGLoadCells(self.can_interface) self.pressures = DGPressures(self.can_interface) self.reservoirs = DGReservoirs(self.can_interface) Index: dialin/dg/hd_proxy.py =================================================================== diff -u --- dialin/dg/hd_proxy.py (revision 0) +++ dialin/dg/hd_proxy.py (revision 42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b) @@ -0,0 +1,168 @@ +########################################################################### +# +# 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_proxy.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +from ..utils.conversions import integer_to_bytearray +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGHDProxy: + """ + \class DGHDProxy + + \brief Dialysate Generator (DG) Dialin API sub-class for HD proxy commands. + """ + + # Pressure/Occlusion message IDs + MSG_ID_HD_SWITCH_RESERVOIRS_CMD = 0x0021 + MSG_ID_HD_FILL_CMD = 0x0022 + MSG_ID_HD_DRAIN_CMD = 0x0023 + MSG_ID_HD_START_STOP_DG_CMD = 0x0026 + + # Reservoir IDs + RESERVOIR1 = 0 + RESERVOIR2 = 1 + + def __init__(self, can_interface=None): + """ + DGHDProxy constructor + + \param outer_instance: reference to the DG (outer) class. + + \returns DGHDProxy object. + """ + self.can_interface = can_interface + + def cmd_switch_reservoirs(self, reservoirID=RESERVOIR1): + """ + Constructs and sends the switch reservoirs command + + \param res: unsigned int - reservoir to set as active (HD will draw from this reservoir). + \returns 1 if successful, zero otherwise + + \details Reservoir IDs: \n + 0 = RESERVOIR 1 \n + 1 = RESERVOIR 2 \n + """ + + res = integer_to_bytearray(reservoirID) + payload = res + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_HD_SWITCH_RESERVOIRS_CMD, + payload=payload) + + print("switch reservoirs cmd sent to DG") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + print("Timeout!!!!") + return False + + def cmd_fill(self, volume=1500): + """ + Constructs and sends the fill command + + \param volume: unsigned int - volume (in mL) to fill inactive reservoir to. + \returns 1 if successful, zero otherwise + """ + + vol = integer_to_bytearray(volume) + payload = vol + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_HD_FILL_CMD, + payload=payload) + + print("fill cmd sent to DG") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + print("Timeout!!!!") + return False + + def cmd_drain(self, volume=200): + """ + Constructs and sends the drain command + + \param volume: unsigned int - volume (in mL) to drain the inactive reservoir to. + \returns 1 if successful, zero otherwise + """ + + vol = integer_to_bytearray(volume) + payload = vol + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_HD_DRAIN_CMD, + payload=payload) + + print("drain cmd sent to DG") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + print("Timeout!!!!") + return False + + def cmd_start_stop_dg(self, start=True): + """ + Constructs and sends the start/stop DG command + + \param start: boolean - True = start DG, False = stop DG. + \returns 1 if successful, zero otherwise + """ + + if start: + cmd = 1 + str = "start " + else: + cmd = 0 + str = "stop" + payload = integer_to_bytearray(cmd) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_HD_START_STOP_DG_CMD, + payload=payload) + + print(str+"DG cmd sent to DG") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + print("Timeout!!!!") + return False + Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -r9d9105c7dc3379c2e14996522291b23a19e7ba46 -r42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b) @@ -18,7 +18,7 @@ from time import sleep from .alarms import HDAlarms from .buttons import HDButtons -from .ui import HDUI +from .ui_proxy import HDUIProxy from .watchdog import HDWatchdog from .rtc import HDRTC from .blood_flow import HDBloodFlow @@ -90,7 +90,7 @@ # Create command groups self.alarms = HDAlarms(self.can_interface) self.buttons = HDButtons(self.can_interface) - self.ui = HDUI(self.can_interface) + self.ui = HDUIProxy(self.can_interface) self.rtc = HDRTC(self.can_interface) self.watchdog = HDWatchdog(self.can_interface) self.bloodflow = HDBloodFlow(self.can_interface) Fisheye: Tag 42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b refers to a dead (removed) revision in file `dialin/hd/ui.py'. Fisheye: No comparison available. Pass `N' to diff? Index: dialin/hd/ui_proxy.py =================================================================== diff -u --- dialin/hd/ui_proxy.py (revision 0) +++ dialin/hd/ui_proxy.py (revision 42feb8ffe3a0d7ab3a4de04ad0d58456afe2333b) @@ -0,0 +1,439 @@ +########################################################################### +# +# 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 ui.py +# +# @date 31-Mar-2020 +# @author P. Lucia +# +# @brief +# +# +############################################################################ +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) +from ..utils.conversions import integer_to_bytearray, float_to_bytearray +import struct + +class HDUIProxy: + """ + \class HDUIProxy + + \brief Hemodialysis Device (HD) Dialin API sub-class for ui commands. + """ + + # ui message IDs + MSG_ID_UI_CHECKIN_WITH_HD = 0x0007 + MSG_ID_HD_UF_PAUSE_RESUME_REQUEST = 0x0010 + MSG_ID_HD_TREATMENT_PARAMS_RANGES = 0x001A + MSG_ID_UF_SETTINGS_CHANGE_REQUEST_BY_USER = 0x0011 + MSG_ID_UF_SETTINGS_CHANGE_RESPONSE_FROM_HD = 0x0013 + MSG_ID_UF_SETTINGS_CHANGE_CONFIRMED_BY_USER = 0x0015 + MSG_ID_TREATMENT_DURATION_SETTING_CHANGE_REQUEST = 0x0016 + MSG_ID_TREATMENT_DURATION_SETTING_CHANGE_RESPONSE_FROM_HD = 0x001B + MSG_ID_BLOOD_DIALYSATE_FLOW_SETTING_CHANGE_REQUEST_BY_USER = 0x0017 + MSG_ID_BLOOD_DIALYSATE_FLOW_SETTING_CHANGE_RESPONSE_FROM_HD = 0x0018 + + LITER_TO_ML_CONVERSION_FACTOR = 1000.0 + UF_CMD_PAUSE = 0 + UF_CMD_RESUME = 1 + UF_CMD_CHANGE_TIME_TO_ADJUST = 0 + UF_CMD_CHANGE_RATE_TO_ADJUST = 1 + RESPONSE_REJECTED = 0 + RESPONSE_ACCEPTED = 1 + + # HD update on valid treatment parameter ranges message field positions + START_POS_MIN_TREAT_TIME = DenaliMessage.PAYLOAD_START_INDEX + END_POS_MIN_TREAT_TIME = START_POS_MIN_TREAT_TIME + 4 + START_POS_MAX_TREAT_TIME = END_POS_MIN_TREAT_TIME + END_POS_MAX_TREAT_TIME = START_POS_MAX_TREAT_TIME + 4 + START_POS_MIN_UF_VOL = END_POS_MAX_TREAT_TIME + END_POS_MIN_UF_VOL = START_POS_MIN_UF_VOL + 4 + START_POS_MAX_UF_VOL = END_POS_MIN_UF_VOL + END_POS_MAX_UF_VOL = START_POS_MAX_UF_VOL + 4 + START_POS_MIN_DIAL_RATE = END_POS_MAX_UF_VOL + END_POS_MIN_DIAL_RATE = START_POS_MIN_DIAL_RATE + 4 + START_POS_MAX_DIAL_RATE = END_POS_MIN_DIAL_RATE + END_POS_MAX_DIAL_RATE = START_POS_MAX_DIAL_RATE + 4 + + # HD response to treatment duration change request message field positions + START_POS_TIME_CHG_RSP_ACCEPTED = DenaliMessage.PAYLOAD_START_INDEX + END_POS_TIME_CHG_RSP_ACCEPTED = START_POS_TIME_CHG_RSP_ACCEPTED + 4 + START_POS_TIME_CHG_RSP_REASON = END_POS_TIME_CHG_RSP_ACCEPTED + END_POS_TIME_CHG_RSP_REASON = START_POS_TIME_CHG_RSP_REASON + 4 + START_POS_TIME_CHG_RSP_TIME = END_POS_TIME_CHG_RSP_REASON + END_POS_TIME_CHG_RSP_TIME = START_POS_TIME_CHG_RSP_TIME + 4 + START_POS_TIME_CHG_RSP_UF_VOL = END_POS_TIME_CHG_RSP_TIME + END_POS_TIME_CHG_RSP_UF_VOL = START_POS_TIME_CHG_RSP_UF_VOL + 4 + + # HD response to UF volume change request message field positions + START_POS_UF_CHG_RSP_RESP = DenaliMessage.PAYLOAD_START_INDEX + END_POS_UF_CHG_RSP_RESP = START_POS_UF_CHG_RSP_RESP + 4 + START_POS_UF_CHG_RSP_REJECT_REASON = END_POS_UF_CHG_RSP_RESP + END_POS_UF_CHG_RSP_REJECT_REASON = START_POS_UF_CHG_RSP_REJECT_REASON + 4 + START_POS_UF_CHG_RSP_VOL = END_POS_UF_CHG_RSP_RESP + END_POS_UF_CHG_RSP_VOL = START_POS_UF_CHG_RSP_VOL + 4 + START_POS_UF_CHG_RSP_TIME = END_POS_UF_CHG_RSP_VOL + END_POS_UF_CHG_RSP_TIME = START_POS_UF_CHG_RSP_TIME + 4 + START_POS_UF_CHG_RSP_TIME_DIFF = END_POS_UF_CHG_RSP_TIME + END_POS_UF_CHG_RSP_TIME_DIFF = START_POS_UF_CHG_RSP_TIME_DIFF + 4 + START_POS_UF_CHG_RSP_RATE = END_POS_UF_CHG_RSP_TIME_DIFF + END_POS_UF_CHG_RSP_RATE = START_POS_UF_CHG_RSP_RATE + 4 + START_POS_UF_CHG_RSP_RATE_DIFF = END_POS_UF_CHG_RSP_RATE + END_POS_UF_CHG_RSP_RATE_DIFF = START_POS_UF_CHG_RSP_RATE_DIFF + 4 + + # HD response to blood/dialysate flow change request message field positions + START_POS_BLD_DIAL_CHG_RSP_ACCEPTED = DenaliMessage.PAYLOAD_START_INDEX + END_POS_BLD_DIAL_CHG_RSP_ACCEPTED = START_POS_BLD_DIAL_CHG_RSP_ACCEPTED + 4 + START_POS_BLD_DIAL_CHG_RSP_REASON = END_POS_BLD_DIAL_CHG_RSP_ACCEPTED + END_POS_BLD_DIAL_CHG_RSP_REASON = START_POS_BLD_DIAL_CHG_RSP_REASON + 4 + START_POS_BLD_DIAL_CHG_RSP_BLD_RATE = END_POS_BLD_DIAL_CHG_RSP_REASON + END_POS_BLD_DIAL_CHG_RSP_BLD_RATE = START_POS_BLD_DIAL_CHG_RSP_BLD_RATE + 4 + START_POS_BLD_DIAL_CHG_RSP_DIAL_RATE = END_POS_BLD_DIAL_CHG_RSP_BLD_RATE + END_POS_BLD_DIAL_CHG_RSP_DIAL_RATE = START_POS_BLD_DIAL_CHG_RSP_DIAL_RATE + 4 + + def __init__(self, can_interface): + """ + HD_UI constructor + + \param can_interface: the denali can interface object + """ + self.can_interface = can_interface + + # register function to handle HD response to UF change requests + if self.can_interface is not None: + channel_id = DenaliChannels.hd_to_ui_ch_id + self.can_interface.register_receiving_publication_function(channel_id, + self.MSG_ID_UF_SETTINGS_CHANGE_RESPONSE_FROM_HD, + self.handler_uf_change_response) + self.can_interface.register_receiving_publication_function(channel_id, + self.MSG_ID_TREATMENT_DURATION_SETTING_CHANGE_RESPONSE_FROM_HD, + self.handler_treatment_duration_change_response) + self.can_interface.register_receiving_publication_function(channel_id, + self.MSG_ID_BLOOD_DIALYSATE_FLOW_SETTING_CHANGE_RESPONSE_FROM_HD, + self.handler_blood_and_dialysate_change_response) + self.can_interface.register_receiving_publication_function(channel_id, self.MSG_ID_HD_TREATMENT_PARAMS_RANGES, + self.handler_treatment_param_ranges) + + # initialize variables that will be populated by treatment parameter ranges message + self.min_treatment_duration_min = 0 + self.max_treatment_duration_min = 0 + self.min_uf_volume_ml = 0 + self.max_uf_volume_ml = 0 + self.min_dialysate_flow_rate_ml_min = 0 + self.max_dialysate_flow_rate_ml_min = 0 + # initialize variables that will be populated by response from HD to treatment duration change request + self.duration_change_succeeded = False + self.duration_change_reject_reason = 0 + self.duration_change_time_min = 0 + self.duration_change_uf_vol_ml = 0 + # initialize variables that will be populated by response from HD to UF change request + self.uf_change_succeeded = False + self.uf_change_reject_reason = 0 + self.uf_change_volume_ml = 0 + self.uf_change_time_min = 0 + self.uf_change_rate_ml_min = 0.0 + self.uf_change_time_diff = 0 + self.uf_change_rate_diff = 0.0 + # initialize variables that will be populated by response from HD to blood & dialysate flow rate change request + self.blood_and_dialysate_flow_rate_change_succeeded = False + self.blood_and_dialysate_flow_rate_change_reject_reason = 0 + self.target_blood_flow_rate = 0 + self.target_dialysate_flow_rate = 0 + + def handler_treatment_param_ranges(self, message): + """ + Handler for response from HD regarding valid treatment parameter ranges. + + \param message: response message from HD regarding valid treatment parameter ranges.\n + U32 Minimum treatment duration setting (in min.). \n + U32 Maximum treatment duration setting (in min.). \n + U32 Minimum ultrafiltration volume (in mL). \n + U32 Maximum ultrafiltration volume (in mL). \n + U32 Minimum dialysate flow rate (in mL/min). \n + U32 Maximum dialysate flow rate (in mL/min). + + \returns none + """ + mintime = struct.unpack('i', bytearray( + message['message'][self.START_POS_MIN_TREAT_TIME:self.END_POS_MIN_TREAT_TIME])) + maxtime = struct.unpack('i', bytearray( + message['message'][self.START_POS_MAX_TREAT_TIME:self.END_POS_MAX_TREAT_TIME])) + minufvol = struct.unpack('i', bytearray( + message['message'][self.START_POS_MIN_UF_VOL:self.END_POS_MIN_UF_VOL])) + maxufvol = struct.unpack('i', bytearray( + message['message'][self.START_POS_MAX_UF_VOL:self.END_POS_MAX_UF_VOL])) + mindialrt = struct.unpack('i', bytearray( + message['message'][self.START_POS_MIN_DIAL_RATE:self.END_POS_MIN_DIAL_RATE])) + maxdialrt = struct.unpack('i', bytearray( + message['message'][self.START_POS_MAX_DIAL_RATE:self.END_POS_MAX_DIAL_RATE])) + + self.min_treatment_duration_min = mintime[0] + self.max_treatment_duration_min = maxtime[0] + self.min_uf_volume_ml = minufvol[0] + self.max_uf_volume_ml = maxufvol[0] + self.min_dialysate_flow_rate_ml_min = mindialrt[0] + self.max_dialysate_flow_rate_ml_min = maxdialrt[0] + + def handler_treatment_duration_change_response(self, message): + """ + Handler for response from HD regarding treatment duration change request. + + \param message: response message from HD regarding treatment duration change.\n + BOOL Accepted \n + U32 Reject reason (if not accepted) \n + U32 treatment duration (min) \n + U32 UF volue (mL) \n + + \returns none + """ + rsp = struct.unpack('i', bytearray( + message['message'][self.START_POS_TIME_CHG_RSP_ACCEPTED:self.END_POS_TIME_CHG_RSP_ACCEPTED])) + rea = struct.unpack('i', bytearray( + message['message'][self.START_POS_TIME_CHG_RSP_REASON:self.END_POS_TIME_CHG_RSP_REASON])) + tim = struct.unpack('i', bytearray( + message['message'][self.START_POS_TIME_CHG_RSP_TIME:self.END_POS_TIME_CHG_RSP_TIME])) + vol = struct.unpack('i', bytearray( + message['message'][self.START_POS_TIME_CHG_RSP_UF_VOL:self.END_POS_TIME_CHG_RSP_UF_VOL])) + + self.duration_change_succeeded = rsp[0] + self.duration_change_reject_reason = rea[0] + self.duration_change_time_min = tim[0] + self.duration_change_uf_vol_ml = vol[0] + + def handler_blood_and_dialysate_change_response(self, message): + """ + Handler for response from HD regarding blood & dialysate flow rate change request. + + \param message: response message from HD regarding requested blood & dialysate flow rate settings change.\n + BOOL Accepted \n + U32 Reject reason (if not accepted) \n + U32 Blood flow rate (mL/min) \n + U32 Dialysate flow rate (mL/min) \n + + \returns none + """ + rsp = struct.unpack('i', bytearray( + message['message'][self.START_POS_BLD_DIAL_CHG_RSP_ACCEPTED:self.END_POS_BLD_DIAL_CHG_RSP_ACCEPTED])) + rea = struct.unpack('i', bytearray( + message['message'][self.START_POS_BLD_DIAL_CHG_RSP_REASON:self.END_POS_BLD_DIAL_CHG_RSP_REASON])) + bld = struct.unpack('i', bytearray( + message['message'][self.START_POS_BLD_DIAL_CHG_RSP_BLD_RATE:self.END_POS_BLD_DIAL_CHG_RSP_BLD_RATE])) + dil = struct.unpack('i', bytearray( + message['message'][self.START_POS_BLD_DIAL_CHG_RSP_DIAL_RATE:self.END_POS_BLD_DIAL_CHG_RSP_DIAL_RATE])) + + if rsp[0] == self.RESPONSE_REJECTED: + resp = False + else: + resp = True + self.blood_and_dialysate_flow_rate_change_succeeded = resp + self.blood_and_dialysate_flow_rate_change_reject_reason = rea[0] + self.target_blood_flow_rate = bld[0] + self.target_dialysate_flow_rate = dil[0] + + def handler_uf_change_response(self, message): + """ + Handler for response from HD regarding UF change request. + + \param message: response message from HD regarding requested ultrafiltration settings change.\n + BOOL Accepted \n + U32 RejectReason (if not accepted) + F32 UF Volume (mL) - converted to Liters \n + U32 treatment Time (min) \n + S32 treatment Time Change (min) \n + F32 UF Rate (mL/min) \n + F32 UF Rate Change (mL/min) + + \returns none + """ + rsp = struct.unpack('i', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_RESP:self.END_POS_UF_CHG_RSP_RESP])) + rea = struct.unpack('i', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_REJECT_REASON:self.END_POS_UF_CHG_RSP_REJECT_REASON])) + vol = struct.unpack('f', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_VOL:self.END_POS_UF_CHG_RSP_VOL])) + tim = struct.unpack('i', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_TIME:self.END_POS_UF_CHG_RSP_TIME])) + tmd = struct.unpack('i', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_TIME_DIFF:self.END_POS_UF_CHG_RSP_TIME_DIFF])) + rat = struct.unpack('f', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_RATE:self.END_POS_UF_CHG_RSP_RATE])) + rtd = struct.unpack('f', bytearray( + message['message'][self.START_POS_UF_CHG_RSP_RATE_DIFF:self.END_POS_UF_CHG_RSP_RATE_DIFF])) + + if rsp[0] == self.RESPONSE_REJECTED: + resp = False + else: + resp = True + self.uf_change_succeeded = resp + self.uf_change_reject_reason = rea[0] + self.UFChangeVolumeL = vol[0] / self.LITER_TO_ML_CONVERSION_FACTOR + self.uf_change_time_min = tim[0] + self.uf_change_time_diff = tmd[0] + self.uf_change_rate_ml_min = rat[0] + self.UFChangeRateDifff = rtd[0] + + def cmd_ui_checkin_with_hd(self): + """ + Constructs and sends the ui check-in message + + \returns 0 + """ + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_UI_CHECKIN_WITH_HD) + + print("Sending ui checkin w/ HD") + + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_uf_pause_resume(self, cmd=UF_CMD_PAUSE): + """ + Constructs and sends a ui UF command message + + \param cmd: 0 for pause, 1 for resume + + \returns none + """ + + payload = integer_to_bytearray(cmd) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_HD_UF_PAUSE_RESUME_REQUEST, + payload=payload) + + if cmd == self.UF_CMD_PAUSE: + str_cmd = "pause" + else: + str_cmd = "resume" + print("Sending UF " + str_cmd + " command.") + + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_uf_settings_change_request(self, vol=0.0): + """ + Constructs and sends a ui UF change settings command message + + \param vol (float): new ultrafiltration volume setting (in L) + + \returns none + """ + + # reset response to this command so we can tell when response is received + self.UFChangeResponse = None + # build command message + volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_UF_SETTINGS_CHANGE_REQUEST_BY_USER, + payload=volume) + + print("Sending UF settings change request.") + + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_uf_settings_change_confirm(self, vol=0.0, adj=UF_CMD_CHANGE_TIME_TO_ADJUST): + """ + Constructs and sends a ui UF change settings command message + + \param vol (float): new ultrafiltration volume setting (in L) + \param adj (int): 0 for adjust time, 1 for adjust rate + + \returns none + """ + + # reset response to this command so we can tell when response is received + self.UFChangeResponse = None + + # build command message + volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) + adjust = integer_to_bytearray(adj) + payload = volume + adjust + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_UF_SETTINGS_CHANGE_REQUEST_BY_USER, + payload=payload) + + print("Sending UF settings change request.") + + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_uf_change_settings_confirmed_by_user(self, response=RESPONSE_REJECTED, vol=0.0, tm=0, rate=0.0): + """ + Constructs and sends a ui UF change settings confirmed by user message + + \param response (int): 0 for rejected, 1 for confirmed + \param vol (float): volume (in L) that was confirmed + \param tm (int): treatment time (in min) that was confirmed + \param rate (float): ultrafiltration rate (in mL/min) that was confirmed + + \returns none + """ + + resp = integer_to_bytearray(response) + volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) + mins = integer_to_bytearray(tm) + ufrate = float_to_bytearray(rate) + payload = resp + volume + mins + ufrate + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_UF_SETTINGS_CHANGE_CONFIRMED_BY_USER, + payload=payload) + + print("Sending UF settings change confirmation.") + + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_treatment_duration_setting_change_request(self, timeMin=0): + """ + Constructs and sends a ui UF change settings confirmed by user message + + \param timeMin (int): treatment time (in min). + + \returns none + """ + + payload = integer_to_bytearray(timeMin) + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_TREATMENT_DURATION_SETTING_CHANGE_REQUEST, + payload=payload) + + print("Sending treatment duration setting change request.") + + # Send message + self.can_interface.send(message, 0) + + return 0 + + def cmd_ui_blood_and_dialysate_flow_settings_change_request(self, bloodFlow, dialFlow): + """ + Constructs and sends a ui blood & dialysate flow settings change request by user message + + \param bloodFlow (int): blood flow rate set point (in mL/min). + \param dialFlow (int): dialysate flow rate set point (in mL/min). + + \returns none + """ + + bld = integer_to_bytearray(bloodFlow) + dial = integer_to_bytearray(dialFlow) + payload = bld + dial + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=self.MSG_ID_BLOOD_DIALYSATE_FLOW_SETTING_CHANGE_REQUEST_BY_USER, + payload=payload) + + print("Sending blood & dialysate flow rate settings change request.") + + self.can_interface.send(message, 0) + + return 0