Fisheye: Tag 9d9105c7dc3379c2e14996522291b23a19e7ba46 refers to a dead (removed) revision in file `Doxyfile'. Fisheye: No comparison available. Pass `N' to diff? Index: dialin/dg/constants.py =================================================================== diff -u --- dialin/dg/constants.py (revision 0) +++ dialin/dg/constants.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,19 @@ +########################################################################### +# +# 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 constants.py +# +# @date 1-Apr-2020 +# @author P. Lucia +# +# @brief +# +# +############################################################################ + +RESET = 1 +NO_RESET = 0 Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -13,30 +13,51 @@ # @brief This class allows sending to and receiving from the DG device. # ############################################################################ +import struct +from time import sleep +from .drain_pump import DGDrainPump +from .load_cells import DGLoadCells +from .pressures import DGPressures +from .reservoirs import DGReservoirs +from .ro_pump import DGROPump from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) -from ..utils.conversions import integer_to_bytearray, float_to_bytearray -from time import sleep -import unittest - class DG: """ \class DG Dialysate Generator (DG) Dialin object API. It provides the basic interface to communicate with - the DG board + the DG firmware. """ - DG_MSG_ID_FILL_COMMAND = 0x2000 - DG_MSG_ID_BROADCAST = 0X2100 - MSG_ID_LOAD_CELL_A1_OVERRIDE = 0xA005 - MSG_ID_LOAD_CELL_A2_OVERRIDE = 0xA006 - MSG_ID_LOAD_CELL_B1_OVERRIDE = 0xA007 - MSG_ID_LOAD_CELL_B2_OVERRIDE = 0xA008 + # DG message IDs + MSG_ID_DG_OPERATION_MODE_BROADCAST = 0x0027 + MSG_ID_LOGIN_TO_DG = 0xA000 + MSG_ID_DG_MSG = 0xA001 + # HD login password + DG_LOGIN_PASSWORD = '123' + + # broadcast message field positions + START_POS_DG_OP_MODE = DenaliMessage.PAYLOAD_START_INDEX + END_POS_DG_OP_MODE = START_POS_DG_OP_MODE + 4 + + # DG operation modes + DG_OP_MODE_FAULT = 0 + DG_OP_MODE_SERVICE = 1 + DG_OP_MODE_INIT_POST = 2 + DG_OP_MODE_STANDBY = 3 + DG_OP_MODE_STANDBY_SOLO = 4 + DG_OP_MODE_RECIRCULATE = 5 + DG_OP_MODE_FILL = 6 + DG_OP_MODE_DRAIN = 7 + DG_OP_MODE_FLUSH = 8 + DG_OP_MODE_DISINFECT = 9 + DG_OP_MODE_CHEMICAL_DISINFECT = 10 + def __init__(self, can_interface="can0"): """ DG constructor using can bus @@ -52,204 +73,100 @@ """ # Create listener self.can_interface = DenaliCanMessenger(can_interface=can_interface) - self.can_interface.register_receiving_publication_function(channel_id=DenaliChannels.dg_sync_broadcast_ch_id, - message_id=self.DG_MSG_ID_BROADCAST, - function=( - lambda message: print(".", end='', flush=True))) self.can_interface.start() - def fill(self, start_or_stop='start'): - """ - Request the DG board to 'start' or to 'stop' fill + # register handler for HD operation mode broadcast messages + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_OPERATION_MODE_BROADCAST + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_dg_op_mode_sync) - \param start_or_stop is a string indicating which action to take, e.g., 'start' or 'stop' + # create properties + self.dg_operation_mode = self.DG_OP_MODE_INIT_POST - \returns True if ran the command, False otherwise, returns None if timeout - """ - payload = [1] if start_or_stop == 'start' else [0] + # Create command groups + self.load_cells = DGLoadCells(self.can_interface) + self.pressures = DGPressures(self.can_interface) + self.reservoirs = DGReservoirs(self.can_interface) + self.ro_pump = DGROPump(self.can_interface) + self.drain_pump = DGDrainPump(self.can_interface) - msg = DenaliMessage.build_message(channel_id=DenaliChannels.hd_to_dg_ch_id, - message_id=self.DG_MSG_ID_FILL_COMMAND, - payload=payload) - - # Send message - received_msg = self.can_interface.send(msg) - return_value = None - - if received_msg is not None: - return_value = True if DenaliMessage.get_payload(received_msg)[0] == 1 else False - - return return_value - - def cmd_load_cell_a1_override(self, reset, adc_raw): + def handler_dg_op_mode_sync(self, message): """ - Constructs and sends the load cell A1 override command + Handles published DG operation mode messages. Current DG operation mode + is captured for reference. - \param reset: integer - 1 to reset a previous override, 0 to override - \param adc_raw: unsigned int - raw adc value. 0.0894 per gram. 1000 ml = 11,186 - \returns 1 if successful, zero otherwise - - TODO: This is built based on HD but needs more infrastructure made for DG before being operational + \param message: published DG operation mode broadcast message + \returns none """ - raise NotImplementedError - """ - rst = integer_to_bytearray(reset) - cur = float_to_bytearray(adc_raw) - payload = rst + cur + mode = struct.unpack('i', bytearray( + message['message'][self.START_POS_DG_OP_MODE:self.END_POS_DG_OP_MODE])) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=self.MSG_ID_LOAD_CELL_A1_OVERRIDE, - payload=payload) + self.dg_operation_mode = mode[0] - print("override load cell A1 raw adc value") - - # Send message - received_message = self.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("Load cell A1 raw adc (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 cmd_log_in_to_dg(self): """ + Constructs and sends a login command via CAN bus. Login required before \n + other commands can be sent to the DG. - - def cmd_load_cell_a2_override(self, reset, adc_raw): + \returns 1 if logged in, 0 if log in failed """ - Constructs and sends the load cell A2 override command - \param reset: integer - 1 to reset a previous override, 0 to override - \param adc_raw: unsigned int - raw adc value. 0.0894 per gram. 1000 ml = 11,186 - \returns 1 if successful, zero otherwise + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_LOGIN_TO_DG, + payload=list(map(int, map(ord, self.DG_LOGIN_PASSWORD)))) - TODO: This is built based on HD but needs more infrastructure made for DG before being operational - """ - raise NotImplementedError + print("login") - """ - rst = integer_to_bytearray(reset) - cur = float_to_bytearray(adc_raw) - payload = rst + cur - - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=self.MSG_ID_LOAD_CELL_A2_OVERRIDE, - payload=payload) - - print("override load cell A2 raw adc value") - # Send message received_message = self.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" + if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: + print("Logged In") else: - str_res = str(curr) - print("Load cell A2 raw adc (measured) overridden to " + str_res + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) - # response payload is OK or not OK + print("Log In Failed.") return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: print("Timeout!!!!") return False - """ - - def cmd_load_cell_b1_override(self, reset, adc_raw): + def cmd_dg_message_insert(self, msg): """ - Constructs and sends the load cell B1 override command + Constructs and sends the insert DG message command. Given message will \n + be inserted into the DG's received message queue for processing. - \param reset: integer - 1 to reset a previous override, 0 to override - \param adc_raw: unsigned int - raw adc value. 0.0894 per gram. 1000 ml = 11,186 - \returns 1 if successful, zero otherwise + \param msg: byte array - properly formatted DG message to insert - TODO: This is built based on HD but needs more infrastructure made for DG before being operational - """ - raise NotImplementedError - - """ - rst = self.outer_instance.integer_to_bytearray(reset) - cur = self.outer_instance.float_to_bytearray(adc_raw) - payload = rst + cur - - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=self.MSG_ID_LOAD_CELL_B1_OVERRIDE, - payload=payload) - - print("override load cell B1 raw adc value") - - # 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("Load cell B1 raw adc (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 cmd_load_cell_b2_override(self, reset, adc_raw): - """ - Constructs and sends the load cell B2 override command - - \param reset: integer - 1 to reset a previous override, 0 to override - \param adc_raw: unsigned int - raw adc value. 0.0894 per gram. 1000 ml = 11,186 \returns 1 if successful, zero otherwise - - TODO: This is built based on HD but needs more infrastructure made for DG before being operational """ - raise NotImplementedError - """ - rst = self.outer_instance.integer_to_bytearray(reset) - cur = self.outer_instance.float_to_bytearray(adc_raw) - payload = rst + cur + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_MSG, + payload=msg) - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=self.MSG_ID_LOAD_CELL_B2_OVERRIDE, - payload=payload) + print("insert DG message") - print("override load cell B2 raw adc value") - # Send message - received_message = self.outer_instance.can_interface.send(message) + received_message = self.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("Load cell B2 raw adc (measured) overridden to " + str_res + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + 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 - """ +if __name__ == "__main__": + # create an DG object called dg + dg = DG() + # wait 2 seconds and then login to DG as a tester + sleep(2) + dg.cmd_log_in_to_dg() + + # add test code below Index: dialin/dg/drain_pump.py =================================================================== diff -u --- dialin/dg/drain_pump.py (revision 0) +++ dialin/dg/drain_pump.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,111 @@ +########################################################################### +# +# 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 drain_pump.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +import struct +from ..utils.conversions import integer_to_bytearray +from .constants import RESET, NO_RESET +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGDrainPump: + """ + \class DGDrainPump + + \brief Dialysate Generator (DG) Dialin API sub-class for drain pump related commands. + + """ + + # Drain pump message IDs + MSG_ID_DG_DRAIN_PUMP_PUBLISHED_DATA = 0x0024 + MSG_ID_DG_DRAIN_PUMP_SET_SPEED_OVERRIDE = 0xA008 + + # Drain pump broadcast message field positions + START_POS_SET_SPD = DenaliMessage.PAYLOAD_START_INDEX + END_POS_SET_SPD = START_POS_SET_SPD + 4 + START_POS_PWM = END_POS_SET_SPD + END_POS_PWM = START_POS_PWM + 4 + + def __init__(self, can_interface=None): + """ + DGDrainPump constructor + + \param outer_instance: reference to the DG (outer) class. + """ + self.can_interface = can_interface + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_DRAIN_PUMP_PUBLISHED_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_drain_pump_sync) + + self.target_drain_pump_speed_RPM = 0 + self.pwm_duty_cycle_pct = 0.0 + + def handler_drain_pump_sync(self, message): + """ + Handles published drain pump data messages. Drain pump data are captured + for reference. + + \param message: published drain pump data message + \returns none + """ + + tgt = struct.unpack('i', bytearray( + message['message'][self.START_POS_SET_SPD:self.END_POS_SET_SPD])) + pwm = struct.unpack('f', bytearray( + message['message'][self.START_POS_PWM:self.END_POS_PWM])) + + self.target_drain_pump_speed_RPM = tgt[0] + self.pwm_duty_cycle_pct = pwm[0] + + def cmd_drain_pump_speed_set_point_override(self, speed, reset=NO_RESET): + """ + Constructs and sends the drain pump speed set point override command + + \param speed: integer - speed set point (in RPM) to override with + \param reset: integer - 1 to reset a previous override, 0 to override + \returns 1 if successful, zero otherwise + """ + + rst = integer_to_bytearray(reset) + spd = integer_to_bytearray(speed) + payload = rst + spd + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_DRAIN_PUMP_SET_SPEED_OVERRIDE, + payload=payload) + + print("override drain pump speed 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 normal" + else: + str_res = str(speed) + print( + "Drain pump set point 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 Index: dialin/dg/load_cells.py =================================================================== diff -u --- dialin/dg/load_cells.py (revision 0) +++ dialin/dg/load_cells.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,131 @@ +########################################################################### +# +# 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 load_cells.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +import struct +from ..utils.conversions import integer_to_bytearray +from .constants import NO_RESET +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGLoadCells: + """ + \class DGLoadCells + + \brief Dialysate Generator (DG) Dialin API sub-class for load cell related commands. + """ + + # Pressure/Occlusion message IDs + MSG_ID_DG_LOAD_CELL_DATA = 0x000C + MSG_ID_DG_LOAD_CELL_OVERRIDE = 0xA005 + + # Load cell broadcast message field positions + START_POS_LC_A1 = DenaliMessage.PAYLOAD_START_INDEX + END_POS_LC_A1 = START_POS_LC_A1 + 4 + START_POS_LC_A2 = END_POS_LC_A1 + END_POS_LC_A2 = START_POS_LC_A2 + 4 + START_POS_LC_B1 = END_POS_LC_A2 + END_POS_LC_B1 = START_POS_LC_B1 + 4 + START_POS_LC_B2 = END_POS_LC_B1 + END_POS_LC_B2 = START_POS_LC_B2 + 4 + + # Load Cell IDs + LOAD_CELL_A1 = 0 + LOAD_CELL_A2 = 1 + LOAD_CELL_B1 = 2 + LOAD_CELL_B2 = 3 + + def __init__(self, can_interface=None): + """ + DGLoadCells constructor + + \param outer_instance: reference to the DG (outer) class. + + \returns DGLoadCells object. + """ + self.can_interface = can_interface + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_LOAD_CELL_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_load_cells_sync) + + self.load_cell_A1 = 0.0 + self.load_cell_A2 = 0.0 + self.load_cell_B1 = 0.0 + self.load_cell_B2 = 0.0 + + def handler_load_cells_sync(self, message): + """ + Handles published load cell data messages. Load cell data are captured + for reference. + + \param message: published load cell data message + \returns none + """ + + a1 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LC_A1:self.END_POS_LC_A1])) + a2 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LC_A2:self.END_POS_LC_A2])) + b1 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LC_B1:self.END_POS_LC_B1])) + b2 = struct.unpack('f', bytearray( + message['message'][self.START_POS_LC_B2:self.END_POS_LC_B2])) + + self.load_cell_A1 = a1[0] + self.load_cell_A2 = a2[0] + self.load_cell_B1 = b1[0] + self.load_cell_B2 = b2[0] + + def cmd_load_cell_override(self, adc_raw, sensor, reset=NO_RESET): + """ + Constructs and sends the load cell override command + + \param adc_raw: unsigned int - raw adc value. 0.0894 per gram. 1000 ml = 11,186 + \param sensor: unsigned int - sensor ID + \param reset: integer - 1 to reset a previous override, 0 to override + \returns 1 if successful, zero otherwise + + \details Load Cell sensor IDs: \n + 0 = A1 \n + 1 = A2 \n + 2 = B1 \n + 3 = B2 \n + """ + + rst = integer_to_bytearray(reset) + adc = integer_to_bytearray(adc_raw) + idx = integer_to_bytearray(sensor) + payload = rst + adc + idx + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_LOAD_CELL_OVERRIDE, + payload=payload) + + print("override load cell raw adc value") + + # 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/dg/pressures.py =================================================================== diff -u --- dialin/dg/pressures.py (revision 0) +++ dialin/dg/pressures.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,131 @@ +########################################################################### +# +# 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 pressures.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +import struct +from ..utils.conversions import integer_to_bytearray, float_to_bytearray +from .constants import NO_RESET +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGPressures: + """ + \class DGPressures + + \brief Dialysate Generator (DG) Dialin API sub-class for pressure related commands. + """ + + # Pressure message IDs + MSG_ID_DG_PRESSURES_DATA = 0x0020 + MSG_ID_DG_PRESSURE_OVERRIDE = 0xA006 + + # Pressure broadcast message field positions + START_POS_RO_INLET_PRES = DenaliMessage.PAYLOAD_START_INDEX + END_POS_RO_INLET_PRES = START_POS_RO_INLET_PRES + 4 + START_POS_RO_OUTLET_PRES = END_POS_RO_INLET_PRES + END_POS_RO_OUTLET_PRES = START_POS_RO_OUTLET_PRES + 4 + START_POS_DRAIN_INLET_PRES = END_POS_RO_OUTLET_PRES + END_POS_DRAIN_INLET_PRES = START_POS_DRAIN_INLET_PRES + 4 + START_POS_DRAIN_OUTLET_PRES = END_POS_DRAIN_INLET_PRES + END_POS_DRAIN_OUTLET_PRES = START_POS_DRAIN_OUTLET_PRES + 4 + + # Pressure Sensor IDs + PRESSURE_SENSOR_RO_PUMP_INLET = 0 + PRESSURE_SENSOR_RO_PUMP_OUTLET = 1 + PRESSURE_SENSOR_DRAIN_PUMP_INLET = 2 + PRESSURE_SENSOR_DRAIN_PUMP_OUTLET = 3 + + def __init__(self, can_interface=None): + """ + DGPressures constructor + + \param outer_instance: reference to the DG (outer) class. + + \returns HDPressureOcclusion object. + """ + self.can_interface = can_interface + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_PRESSURES_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_pressures_sync) + + self.ro_pump_inlet_pressure = 0.0 + self.ro_pump_outlet_pressure = 0.0 + self.drain_pump_inlet_pressure = 0.0 + self.drain_pump_outlet_pressure = 0.0 + + def handler_pressures_sync(self, message): + """ + Handles published pressure data messages. Pressure data are captured + for reference. + + \param message: published pressure data message + \returns none + """ + + roi = struct.unpack('f', bytearray( + message['message'][self.START_POS_RO_INLET_PRES:self.END_POS_RO_INLET_PRES])) + roo = struct.unpack('f', bytearray( + message['message'][self.START_POS_RO_OUTLET_PRES:self.END_POS_RO_OUTLET_PRES])) + dri = struct.unpack('f', bytearray( + message['message'][self.START_POS_DRAIN_INLET_PRES:self.END_POS_DRAIN_INLET_PRES])) + dro = struct.unpack('f', bytearray( + message['message'][self.START_POS_DRAIN_OUTLET_PRES:self.END_POS_DRAIN_OUTLET_PRES])) + + self.ro_pump_inlet_pressure = roi[0] + self.ro_pump_outlet_pressure = roo[0] + self.drain_pump_inlet_pressure = dri[0] + self.drain_pump_outlet_pressure = dro[0] + + def cmd_pressure_override(self, pressure, sensor, reset=NO_RESET): + """ + Constructs and sends the pressure override command + + \param pressure: unsigned int - pressure (in PSI) + \param sensor: unsigned int - sensor ID + \param reset: integer - 1 to reset a previous override, 0 to override + \returns 1 if successful, zero otherwise + + \details pressure sensor IDs: \n + 0 = RO Pump Inlet \n + 1 = RO Pump Outlet \n + 2 = Drain Pump Inlet \n + 3 = Drain Pump Outlet \n + """ + + rst = integer_to_bytearray(reset) + prs = float_to_bytearray(pressure) + idx = integer_to_bytearray(sensor) + payload = rst + prs + idx + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_PRESSURE_OVERRIDE, + payload=payload) + + print("override pressure sensor") + + # 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/dg/reservoirs.py =================================================================== diff -u --- dialin/dg/reservoirs.py (revision 0) +++ dialin/dg/reservoirs.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,82 @@ +########################################################################### +# +# 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 reservoirs.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +import struct +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGReservoirs: + """ + \class DGReservoirs + + \brief Dialysate Generator (DG) Dialin API sub-class for reservoir related commands. + """ + + # Reservoir message IDs + MSG_ID_DG_RESERVOIR_DATA = 0x0028 + + # Reservoir broadcast message field positions + START_POS_ACT_RES = DenaliMessage.PAYLOAD_START_INDEX + END_POS_ACT_RES = START_POS_ACT_RES + 4 + START_POS_FILL_TO_VOL = END_POS_ACT_RES + END_POS_FILL_TO_VOL = START_POS_FILL_TO_VOL + 4 + START_POS_DRAIN_TO_VOL = END_POS_FILL_TO_VOL + END_POS_DRAIN_TO_VOL = START_POS_DRAIN_TO_VOL + 4 + + # Reservoir IDs + RESERVOIR1 = 0 + RESERVOIR2 = 1 + + def __init__(self, can_interface=None): + """ + DGReservoirs constructor + + \param outer_instance: reference to the DG (outer) class. + + \returns HDPressureOcclusion object. + """ + self.can_interface = can_interface + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_RESERVOIR_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_reservoirs_sync) + + self.active_reservoir = self.RESERVOIR1 + self.fill_to_vol_ml = 0 + self.drain_to_vol_ml = 0 + + def handler_reservoirs_sync(self, message): + """ + Handles published reservoir data messages. Reservoir data are captured + for reference. + + \param message: published reservoir data message + \returns none + """ + + res = struct.unpack('i', bytearray( + message['message'][self.START_POS_ACT_RES:self.END_POS_ACT_RES])) + fil = struct.unpack('i', bytearray( + message['message'][self.START_POS_FILL_TO_VOL:self.END_POS_FILL_TO_VOL])) + dra = struct.unpack('i', bytearray( + message['message'][self.START_POS_DRAIN_TO_VOL:self.END_POS_DRAIN_TO_VOL])) + + self.active_reservoir = res[0] + self.fill_to_vol_ml = fil[0] + self.drain_to_vol_ml = dra[0] + Index: dialin/dg/ro_pump.py =================================================================== diff -u --- dialin/dg/ro_pump.py (revision 0) +++ dialin/dg/ro_pump.py (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -0,0 +1,118 @@ +########################################################################### +# +# 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 ro_pump.py +# +# @date 14-Apr-2020 +# @author S. Nash +# +# @brief +# +# +############################################################################ +import struct +from ..utils.conversions import integer_to_bytearray +from .constants import RESET, NO_RESET +from ..protocols.CAN import (DenaliMessage, + DenaliChannels) + +class DGROPump: + """ + \class DGROPump + + \brief Dialysate Generator (DG) Dialin API sub-class for RO pump related commands. + + """ + + # RO pump message IDs + MSG_ID_DG_RO_PUMP_PUBLISHED_DATA = 0x001F + MSG_ID_DG_RO_PUMP_PRESSURE_SET_PT_OVERRIDE = 0xA007 + + # RO pump broadcast message field positions + START_POS_PRES_SET_PT = DenaliMessage.PAYLOAD_START_INDEX + END_POS_PRES_SET_PT = START_POS_PRES_SET_PT + 4 + START_POS_MEAS_FLOW = END_POS_PRES_SET_PT + END_POS_MEAS_FLOW = START_POS_MEAS_FLOW + 4 + START_POS_PWM = END_POS_MEAS_FLOW + END_POS_PWM = START_POS_PWM + 4 + + def __init__(self, can_interface=None): + """ + DGROPump constructor + + \param outer_instance: reference to the DG (outer) class. + """ + self.can_interface = can_interface + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = self.MSG_ID_DG_RO_PUMP_PUBLISHED_DATA + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self.handler_ro_pump_sync) + + self.target_pressure = 0 + self.measured_flow_rate = 0.0 + self.pwm_duty_cycle_pct = 0.0 + + def handler_ro_pump_sync(self, message): + """ + Handles published ro pump data messages. RO pump data are captured + for reference. + + \param message: published RO pump data message + \returns none + """ + + tgt = struct.unpack('i', bytearray( + message['message'][self.START_POS_PRES_SET_PT:self.END_POS_PRES_SET_PT])) + flow = struct.unpack('f', bytearray( + message['message'][self.START_POS_MEAS_FLOW:self.END_POS_MEAS_FLOW])) + pwm = struct.unpack('f', bytearray( + message['message'][self.START_POS_PWM:self.END_POS_PWM])) + + self.target_pressure = tgt[0] + self.measured_blood_flow_rate = flow[0] + self.pwm_duty_cycle_pct = pwm[0] + + def cmd_ro_pump_set_point_override(self, pressure, reset=NO_RESET): + """ + Constructs and sends the RO pump set point override command + + \param pressure: integer - pressure set point (in PSI) to override with + \param reset: integer - 1 to reset a previous override, 0 to override + \returns 1 if successful, zero otherwise + """ + + rst = integer_to_bytearray(reset) + prs = integer_to_bytearray(pressure) + payload = rst + prs + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=self.MSG_ID_DG_RO_PUMP_PRESSURE_SET_PT_OVERRIDE, + payload=payload) + + print("override RO pump pressure 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 normal" + else: + str_res = str(prs) + print( + "RO pump pressure set point overridden to " + str_res + " PSI: " + + 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 + Index: dialin/hd/alarms.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/alarms.py (.../alarms.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/hd/alarms.py (.../alarms.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -16,7 +16,7 @@ from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray -from .constants import RESET +from .constants import RESET, NO_RESET import struct @@ -141,13 +141,13 @@ alarm_id = struct.unpack(' After STOP:{} <---".format(hd.DialOut.DialOutBroadcast)) + hd.cmd_log_in_to_hd() - sleep(3) - hd.DialOut.set_uf_state(DialOutStates.RUN) - sleep(2) - state_stop = hd.DialOut.DialOutBroadcast['state'] - print("After RUN again: {}".format(hd.DialOut.DialOutBroadcast)) + # add test code below - sleep(3) - hd.DialOut.set_uf_state(DialOutStates.STOP) - sleep(2) - state_stop = hd.DialOut.DialOutBroadcast['state'] - print("After STOP: {}".format(hd.DialOut.DialOutBroadcast)) - - sleep(5) - hd.DialOut.plot_broadcast_signals() - - exit() - tgtRate = 0 - hd.bloodflow.cmd_blood_flow_broadcast_interval_override(NO_RESET, 2000) - - while True: - if hd.bloodflow.target_blood_flow_rate == 0: - if tgtRate != 0: - hd.bloodflow.cmd_blood_flow_broadcast_interval_override(NO_RESET, 2000) - tgtRate = 0 - else: - if tgtRate == 0: - hd.bloodflow.cmd_blood_flow_broadcast_interval_override(NO_RESET, 200) - tgtRate = hd.bloodflow.target_blood_flow_rate - - sleep(1) - - print(hd.bloodflow.measured_blood_flow_rate) - -# hd.bloodflow.cmd_blood_flow_broadcast_interval_override(RESET,0) -""" Index: dialin/hd/pressure_occlusion.py =================================================================== diff -u -r4cb37e8ec3d57576aea76c8aae84130d3adb3ab1 -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/pressure_occlusion.py (.../pressure_occlusion.py) (revision 4cb37e8ec3d57576aea76c8aae84130d3adb3ab1) +++ dialin/hd/pressure_occlusion.py (.../pressure_occlusion.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -14,13 +14,12 @@ # # ############################################################################ +import struct from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray, float_to_bytearray -from .constants import RESET -import struct +from .constants import RESET, NO_RESET - class HDPressureOcclusion: """ \class HDPressureOcclusion @@ -97,12 +96,12 @@ self.dialysateInletPumpOcclusion = dpi[0] self.dialysateOutletPumpOcclusion = dpo[0] - def cmd_arterial_pressure_measured_override(self, reset, pres): + def cmd_arterial_pressure_measured_override(self, pres, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ @@ -133,13 +132,13 @@ print("Timeout!!!!") return False - def cmd_venous_pressure_measured_override(self, reset, pres): + def cmd_venous_pressure_measured_override(self, pres, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ @@ -170,12 +169,12 @@ print("Timeout!!!!") return False - def cmd_blood_pump_measured_occlusion_override(self, reset, occl): + def cmd_blood_pump_measured_occlusion_override(self, occl, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ @@ -206,13 +205,13 @@ print("Timeout!!!!") return False - def cmd_dialysate_inlet_pump_measured_occlusion_override(self, reset, occl): + def cmd_dialysate_inlet_pump_measured_occlusion_override(self, occl, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ @@ -243,13 +242,13 @@ print("Timeout!!!!") return False - def cmd_dialysate_outlet_pump_measured_occlusion_override(self, reset, occl): + def cmd_dialysate_outlet_pump_measured_occlusion_override(self, occl, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ @@ -280,12 +279,12 @@ print("Timeout!!!!") return False - def cmd_pressure_occlusion_broadcast_interval_override(self, reset, ms): + def cmd_pressure_occlusion_broadcast_interval_override(self, ms, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ Index: dialin/hd/rtc.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/rtc.py (.../rtc.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/hd/rtc.py (.../rtc.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -14,12 +14,11 @@ # # ############################################################################ +import ctypes from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray -import ctypes - class HDRTC: """ \class HDRTC @@ -69,12 +68,12 @@ \returns 1 if successful, zero otherwise """ sec = bytes([secs]) - min = bytes([mins]) + mint = bytes([mins]) hour = bytes([hours]) day = bytes([days]) month = bytes([months]) year = integer_to_bytearray(years) - payload = sec + min + hour + day + month + year + payload = sec + mint + hour + day + month + year message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=self.MSG_ID_SET_RTC_DATE_TIME, Index: dialin/hd/treatment.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/treatment.py (.../treatment.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/hd/treatment.py (.../treatment.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -14,11 +14,10 @@ # # ############################################################################ +import struct from ..protocols.CAN import (DenaliMessage, DenaliChannels) -import struct - class HDTreatment: """ \class HD_Treatment Index: dialin/hd/ui.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/ui.py (.../ui.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/hd/ui.py (.../ui.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -19,7 +19,6 @@ from ..utils.conversions import integer_to_bytearray, float_to_bytearray import struct - class HDUI: """ \class HD_UI @@ -160,25 +159,25 @@ \returns none """ - minTime = struct.unpack('i', bytearray( + mintime = struct.unpack('i', bytearray( message['message'][self.START_POS_MIN_TREAT_TIME:self.END_POS_MIN_TREAT_TIME])) - maxTime = struct.unpack('i', bytearray( + maxtime = struct.unpack('i', bytearray( message['message'][self.START_POS_MAX_TREAT_TIME:self.END_POS_MAX_TREAT_TIME])) - minUFVol = struct.unpack('i', bytearray( + minufvol = struct.unpack('i', bytearray( message['message'][self.START_POS_MIN_UF_VOL:self.END_POS_MIN_UF_VOL])) - maxUFVol = struct.unpack('i', bytearray( + maxufvol = struct.unpack('i', bytearray( message['message'][self.START_POS_MAX_UF_VOL:self.END_POS_MAX_UF_VOL])) - minDialRt = struct.unpack('i', bytearray( + mindialrt = struct.unpack('i', bytearray( message['message'][self.START_POS_MIN_DIAL_RATE:self.END_POS_MIN_DIAL_RATE])) - maxDialRt = struct.unpack('i', bytearray( + 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] + 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): """ @@ -382,9 +381,9 @@ resp = integer_to_bytearray(response) volume = float_to_bytearray(vol * self.LITER_TO_ML_CONVERSION_FACTOR) - min = integer_to_bytearray(tm) - ufRate = float_to_bytearray(rate) - payload = resp + volume + min + ufRate + 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) Index: dialin/hd/watchdog.py =================================================================== diff -u -r3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- dialin/hd/watchdog.py (.../watchdog.py) (revision 3c6e1e61afe606f16e0e0300f4d93d5e0e8b001a) +++ dialin/hd/watchdog.py (.../watchdog.py) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -17,9 +17,8 @@ from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray -from .constants import RESET +from .constants import RESET, NO_RESET - class HDWatchdog: """ \class HD_Watchdog @@ -41,13 +40,13 @@ self.can_interface = can_interface - def cmd_watchdog_task_check_in_override(self, reset, state, task): + def cmd_watchdog_task_check_in_override(self, state, task, reset=NO_RESET): """ 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 + \param reset: integer - 1 to reset a previous override, 0 to override \returns 1 if successful, zero otherwise """ Fisheye: Tag 68137f3ef7ad8dac0e1209b50272ba613543e2d9 refers to a dead (removed) revision in file `document/Doxyfile'. Fisheye: No comparison available. Pass `N' to diff? Index: tools/document.sh =================================================================== diff -u -r619cd8f345bf168dc37bb12befef3db0290e5329 -r9d9105c7dc3379c2e14996522291b23a19e7ba46 --- tools/document.sh (.../document.sh) (revision 619cd8f345bf168dc37bb12befef3db0290e5329) +++ tools/document.sh (.../document.sh) (revision 9d9105c7dc3379c2e14996522291b23a19e7ba46) @@ -1,7 +1,7 @@ #!/bin/bash cd ../ export PROJECT_DIRECTORY=$(pwd) -rm -rf html -doxygen Doxyfile +rm -rf document/html +doxygen document/Doxyfile cd html -xdg-open index.html +xdg-open document/index.html