Index: dialin/common/dg_defs.py =================================================================== diff -u -r82f60d6de5414db96b1c44c3d6fdb12a56e39880 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/common/dg_defs.py (.../dg_defs.py) (revision 82f60d6de5414db96b1c44c3d6fdb12a56e39880) +++ dialin/common/dg_defs.py (.../dg_defs.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,16 +1,16 @@ -################################################################ +########################################################################### # -# Copyright (c) 2021 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2021 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 dg_defs.py +# @file dg_defs.py # -# @author (last) Peter Lucia -# @date (last) 22-Jun-2021 -# @author (original) Peter Lucia -# @date (original) 22-Jun-2021 +# @author (last) Quang Nguyen +# @date (last) 04-Aug-2021 +# @author (original) Peter Lucia +# @date (original) 22-Jun-2021 # ############################################################################ from enum import unique @@ -154,4 +154,5 @@ CHEM_DISINFECT_UI_STATE_DISINFECT_DEVICE = 4 CHEM_DISINFECT_UI_STATE_FLUSH_AFTER_DISINFECT = 5 CHEM_DISINFECT_UI_STATE_CANCEL_DISINFECT = 6 - CHEM_DISINFECT_UI_STATE_COMPLETE = 7 \ No newline at end of file + CHEM_DISINFECT_UI_STATE_COMPLETE = 7 + Index: dialin/common/msg_ids.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -184,6 +184,8 @@ MSG_ID_DG_SWITCHES_DATA = 0XA1 MSG_ID_HD_SWITCHES_DATA = 0XA2 MSG_ID_HD_FANS_DATA = 0XA3 + MSG_ID_HD_EVENT = 0xA4 + MSG_ID_DG_EVENT = 0xA5 MSG_ID_CAN_ERROR_COUNT = 0X999 MSG_ID_TESTER_LOGIN_REQUEST = 0X8000 MSG_ID_DIAL_OUT_FLOW_SET_PT_OVERRIDE = 0X8001 @@ -302,7 +304,6 @@ MSG_ID_HD_PRE_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8073 MSG_ID_HD_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8074 MSG_ID_HD_POST_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE = 0x8075 - MSG_ID_DG_TESTER_LOGIN_REQUEST = 0XA000 MSG_ID_DG_ALARM_STATE_OVERRIDE = 0XA001 MSG_ID_DG_WATCHDOG_TASK_CHECKIN_OVERRIDE = 0XA002 @@ -349,7 +350,7 @@ MSG_ID_DG_THERMISTORS_VALUE_OVERRIDE = 0XA02E MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE = 0XA02F MSG_ID_DG_RO_FLOW_RATE_OVERRIDE = 0XA030 - MSG_ID_DG_RO_PUMP_TARGET_FLOW_OVERRIDE = 0XA031 + MSG_ID_DG_SET_RO_PUMP_TARGET_FLOW = 0XA031 MSG_ID_DG_RO_PUMP_TARGET_PRESSURE_OVERRIDE = 0XA032 MSG_ID_DG_SET_CALIBRATION_RECORD = 0XA033 MSG_ID_DG_GET_CALIBRATION_RECORD = 0XA034 @@ -367,6 +368,7 @@ MSG_ID_DG_FLUID_LEAK_STATE_DETECTOR_OVERRIDE = 0XA040 MSG_ID_DG_FLUSH_PUBLISH_INTERVAL_OVERRIDE = 0XA041 MSG_ID_FILTER_FLUSH_TIME_PERIOD_OVERRIDE = 0XA042 + MSG_ID_DG_FANS_RPM_OVERRIDE = 0xA043 MSG_ID_HD_DEBUG_EVENT = 0XFFF1 MSG_ID_DG_DEBUG_EVENT = 0XFFF2 MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK = 0XFFFF Index: dialin/dg/calibration_record.py =================================================================== diff -u -r5a634c567871a6855667341464bac9e057cd2b93 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/calibration_record.py (.../calibration_record.py) (revision 5a634c567871a6855667341464bac9e057cd2b93) +++ dialin/dg/calibration_record.py (.../calibration_record.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,15 +1,30 @@ - +########################################################################### +# +# Copyright (c) 2019-2021 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 calibration_record.py +# +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 12-Feb-2021 +# +############################################################################ import struct import time from collections import OrderedDict +from logging import Logger + from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish from ..utils.nv_ops_utils import NVOpsUtils -from logging import Logger -class DGCalibrationNVRecord(_AbstractSubSystem): +class DGCalibrationNVRecord(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for calibration commands. @@ -57,7 +72,6 @@ self.dg_calibration_record = self._prepare_dg_calibration_record() if self.can_interface is not None: - channel_id = DenaliChannels.dg_to_dialin_ch_id msg_id = MsgIds.MSG_ID_DG_SEND_CALIBRATION_RECORD.value self.can_interface.register_receiving_publication_function(channel_id, msg_id, @@ -143,7 +157,7 @@ self._utilities.process_received_record_from_fw(self.dg_calibration_record, self._raw_cal_record) self._handler_received_complete_dg_calibration_record() - @_publish(["dg_calibration_record"]) + @publish(["dg_calibration_record"]) def _handler_received_complete_dg_calibration_record(self): """ Publishes the received calibration record @@ -251,7 +265,6 @@ hardware = OrderedDict() for i in hardware_names: - hardware[i] = {'fourth_order': [' int: """ Index: dialin/dg/events.py =================================================================== diff -u --- dialin/dg/events.py (revision 0) +++ dialin/dg/events.py (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -0,0 +1,64 @@ + +import struct +from enum import unique +from logging import Logger + +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from datetime import datetime + + +#TODO add events enum + +class DGEvents(AbstractSubSystem): + """ + Dialysate Generator (DG) Dialin API sub-class for events related commands. + """ + + _LENGTH_OF_DG_EVENTS_LIST = 20 + + def __init__(self, can_interface, logger: Logger): + """ + + @param can_interface: Denali CAN Messenger object + """ + + super().__init__() + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_DG_EVENT.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_events_sync) + + self._dg_events_list = [] + self._current_event_index = 0 + + @publish(['_dg_events_list']) + def _handler_events_sync(self, message): + """ + Handles published events message + + @param message: published DG events data message + @returns none + """ + event_id = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + event_data_type_1 = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + event_data_1 = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + event_data_type_2 = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + event_data_2 = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + + local_event = [datetime.now(), event_id, event_data_type_1, event_data_1, event_data_type_2, event_data_2] + self._dg_events_list.insert(self._current_event_index, local_event) + + if self._current_event_index >= self._LENGTH_OF_DG_EVENTS_LIST - 1: + self._current_event_index = 0 + else: + self._current_event_index += 1 Index: dialin/dg/fans.py =================================================================== diff -u -r82f60d6de5414db96b1c44c3d6fdb12a56e39880 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/fans.py (.../fans.py) (revision 82f60d6de5414db96b1c44c3d6fdb12a56e39880) +++ dialin/dg/fans.py (.../fans.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,18 +1,32 @@ - +########################################################################### +# +# Copyright (c) 2019-2021 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 fans.py +# +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 18-Nov-2020 +# +############################################################################ import struct -from ..utils.conversions import integer_to_bytearray, float_to_bytearray -from ..utils.checks import check_broadcast_interval_override_ms +from enum import unique +from logging import Logger + from .constants import NO_RESET, RESET from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish, DialinEnum -from logging import Logger -from enum import unique +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray, float_to_bytearray @unique class FansNames(DialinEnum): - FAN_INLET_1 = 0 FAN_INLET_2 = 1 FAN_INLET_3 = 2 @@ -21,7 +35,7 @@ FAN_OUTLET_3 = 5 -class Fans(_AbstractSubSystem): +class Fans(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for fans related commands. """ @@ -115,8 +129,8 @@ """ return self.dg_fans_target_rpm - @_publish(['target_duty_cycle', 'dg_fans_target_rpm', 'inlet_1_rpm', 'inlet_2_rpm', 'inlet_3_rpm', 'outlet_1_rpm', - 'outlet_2_rpm', 'outlet_3_rpm']) + @publish(['target_duty_cycle', 'inlet_1_rpm', 'inlet_2_rpm', 'inlet_3_rpm', 'outlet_1_rpm', 'outlet_2_rpm', + 'outlet_3_rpm']) def _handler_fans_sync(self, message): """ Handles published thermistors message. Index: dialin/dg/hd_proxy.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ dialin/dg/hd_proxy.py (.../hd_proxy.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,27 +1,27 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2021 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 +# @file hd_proxy.py # -# @author (last) Peter Lucia -# @date (last) 10-Nov-2020 -# @author (original) Sean -# @date (original) 15-Apr-2020 +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Sean +# @date (original) 15-Apr-2020 # ############################################################################ -from ..utils.conversions import integer_to_bytearray -from ..common.msg_defs import MsgIds -from ..protocols.CAN import (DenaliMessage, - DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish from logging import Logger +from ..common.msg_defs import MsgIds +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem +from ..utils.conversions import integer_to_bytearray -class DGHDProxy(_AbstractSubSystem): + +class DGHDProxy(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for HD proxy commands. """ @@ -39,22 +39,22 @@ self.can_interface = can_interface self.logger = logger - def cmd_switch_reservoirs(self, reservoirID=RESERVOIR1): + def cmd_switch_reservoirs(self, reservoir_id: int = RESERVOIR1) -> int: """ Constructs and sends the switch reservoirs command. Constraints: DG must be in re-circulate mode. Given reservoirID must be in the reservoir list below. - @param reservoirID: unsigned int - reservoir to set as active (HD will draw from this reservoir). + @param reservoir_id: unsigned int - reservoir to set as active (HD will draw from this reservoir). @return: 1 if successful, zero otherwise - \details Reservoir IDs: \n + @details Reservoir IDs: \n 0 = RESERVOIR 1 \n 1 = RESERVOIR 2 \n """ - res = integer_to_bytearray(reservoirID) + res = integer_to_bytearray(reservoir_id) payload = res message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, @@ -105,7 +105,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_drain(self, volume:int=0, tare_load_cell:bool=False) -> int: + def cmd_drain(self, volume: int = 0, tare_load_cell: bool = False) -> int: """ Constructs and sends the drain command. Constraints: @@ -151,17 +151,17 @@ if start: cmd = 1 - str = "start " + cmd_str = "start " else: cmd = 0 - str = "stop" + cmd_str = "stop " payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_STARTING_STOPPING_TREATMENT_CMD.value, payload=payload) - self.logger.debug(str+" DG cmd sent to DG") + self.logger.debug(cmd_str + "DG cmd sent to DG") # Send message received_message = self.can_interface.send(message) @@ -184,17 +184,17 @@ if start: cmd = 1 - str = "start " + cmd_str = "start " else: cmd = 0 - str = "stop" + cmd_str = "stop " payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_DG_START_STOP_TRIMMER_HEATER_CMD.value, payload=payload) - self.logger.debug(str+"DG trimmer heater cmd sent to DG") + self.logger.debug(cmd_str + "DG trimmer heater cmd sent to DG") # Send message received_message = self.can_interface.send(message) @@ -235,7 +235,7 @@ self.logger.debug("Sending sample water command") self.can_interface.send(message, 0) - def cmd_start_stop_heat_disinfect(self, start:bool=True) -> int: + def cmd_start_stop_heat_disinfect(self, start: bool = True) -> int: """ Constructs and sends the start/stop DG heat disinfect command @@ -245,16 +245,16 @@ # 1 is to start if start: cmd = 1 - str = "Starting" + cmd_str = "Starting" else: cmd = 0 - str = "Stopping" + cmd_str = "Stopping" payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_DG_START_STOP_HEAT_DISINFECT.value, payload=payload) - self.logger.debug(str + " DG heat disinfect") + self.logger.debug(cmd_str + " DG heat disinfect") received_message = self.can_interface.send(message) @@ -266,7 +266,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_start_stop_dg_flush(self, start:bool=True) -> int: + def cmd_start_stop_dg_flush(self, start: bool = True) -> int: """ Constructs and sends the start/stop DG flush command @@ -276,16 +276,16 @@ # 1 is to start if start: cmd = 1 - str = "Starting" + cmd_str = "Starting" else: cmd = 0 - str = "Stopping" + cmd_str = "Stopping" payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_DG_START_STOP_FLUSH.value, payload=payload) - self.logger.debug(str + " DG flush") + self.logger.debug(cmd_str + " DG flush") received_message = self.can_interface.send(message) @@ -297,7 +297,7 @@ self.logger.debug("Timeout!!!!") return False - def cmd_start_stop_dg_chemical_disinfect(self, start:bool=True) -> int: + def cmd_start_stop_dg_chemical_disinfect(self, start: bool = True) -> int: """ Constructs and sends the start/stop DG chemical disinfect command @@ -307,16 +307,16 @@ # 1 is to start if start: cmd = 1 - str = "Starting" + str_text = "Starting" else: cmd = 0 - str = "Stopping" + str_text = "Stopping" payload = integer_to_bytearray(cmd) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_DG_START_STOP_CHEM_DISINFECT.value, payload=payload) - self.logger.debug(str + " DG chemical disinfect") + self.logger.debug(str_text + " DG chemical disinfect") received_message = self.can_interface.send(message) @@ -326,4 +326,4 @@ return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: self.logger.debug("Timeout!!!!") - return False \ No newline at end of file + return False Index: dialin/dg/heaters.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/heaters.py (.../heaters.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ dialin/dg/heaters.py (.../heaters.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,47 +1,46 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2021 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 heaters.py +# @file heaters.py # -# @author (last) Peter Lucia -# @date (last) 10-Nov-2020 -# @author (original) Dara Navaei -# @date (original) 29-May-2020 +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 29-May-2020 # ############################################################################ import struct -from ..utils.conversions import integer_to_bytearray -from ..utils.conversions import float_to_bytearray -from ..utils.checks import check_broadcast_interval_override_ms -from ..common.msg_defs import MsgIds, MsgFieldPositions -from .constants import NO_RESET -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish, DialinEnum -from logging import Logger from enum import unique +from logging import Logger +from .constants import NO_RESET +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray, float_to_bytearray + @unique class HeatersStartStop(DialinEnum): - STOP = 0 START = 1 @unique class HeatersState(DialinEnum): - HEATER_EXEC_STATE_NOT_RUNNING = 0 + HEATER_EXEC_STATE_OFF = 0 HEATER_EXEC_STATE_RAMP_UP_TO_TARGET = 1 HEATER_EXEC_STATE_CONTROL_TO_TARGET = 2 -class Heaters(_AbstractSubSystem): +class Heaters(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for heaters related commands. @@ -110,8 +109,8 @@ """ return self.trimmer_heater_target_temperature - @_publish(["main_primary_heater_duty_cycle", "small_primary_heater_duty_cycle", "trimmer_heater_duty_cycle", - "primary_heaters_target_temperature", "trimmer_heater_target_temperature", "primary_heater_state"]) + @publish(["main_primary_heater_duty_cycle", "small_primary_heater_duty_cycle", "trimmer_heater_duty_cycle", + "primary_heaters_target_temperature", "trimmer_heater_target_temperature"]) def _handler_heaters_sync(self, message): """ Handles published heaters message @@ -219,9 +218,9 @@ if not check_broadcast_interval_override_ms(ms): return False - resetValue = integer_to_bytearray(reset) - intervalValue = integer_to_bytearray(ms) - payload = resetValue + intervalValue + reset_value = integer_to_bytearray(reset) + interval_value = integer_to_bytearray(ms) + payload = reset_value + interval_value message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, message_id=MsgIds.MSG_ID_HEATERS_PUBLISH_INTERVAL_ORVERRIDE.value, Index: dialin/dg/ro_pump.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/ro_pump.py (.../ro_pump.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ dialin/dg/ro_pump.py (.../ro_pump.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -62,6 +62,8 @@ self.ro_pump_state = 0.0 self.target_flow_lpm = 0.0 + self.temporary_flow_value = 0.0 + def get_target_pressure(self): """ Gets the target pressure @@ -115,118 +117,117 @@ tgt_flow = struct.unpack('f', bytearray( message['message'][MsgFieldPositions.START_POS_FIELD_5:MsgFieldPositions.END_POS_FIELD_5]))[0] + temp_current_flow = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_6:MsgFieldPositions.END_POS_FIELD_6]))[0] + self.temporary_flow_value = temp_current_flow + self.target_pressure_psi = tgt_pres self.measured_flow_rate_lpm = flow self.pwm_duty_cycle_pct = pwm self.ro_pump_state = ROPumpStates(ro_state).name if ROPumpStates.has_value(ro_state) else 'State Unknown' self.target_flow_lpm = tgt_flow - def cmd_ro_pump_set_point_override(self, pressure: int, reset: int = NO_RESET) -> int: + def cmd_ro_pump_duty_cycle_pct(self, duty: float) -> int: """ - Constructs and sends the RO pump set point override command. + Constructs and sends the set RO pump duty cycle message Constraints: Must be logged into DG. - @param pressure: integer - pressure set point (in PSI) to override with - @param reset: integer - 1 to reset a previous override, 0 to override + @param duty: integer - 1 percentage for duty cycle between 0 and 100 @return: 1 if successful, zero otherwise """ + dc = float_to_bytearray(duty/100) + payload = dc - 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=MsgIds.MSG_ID_RO_PUMP_SEND_INTERVAL_OVERRIDE.value, + message_id=MsgIds.MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE.value, payload=payload) - self.logger.debug("Override RO pump pressure set point") + self.logger.debug("RO pump duty cycle set") # Send message received_message = self.can_interface.send(message) # If there is content... if received_message is not None: - # self.logger.debug(received_message) - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(pressure) + self.logger.debug( - "RO pump pressure set point overridden to " + str_res + " PSI: " + + "RO pump duty cycle set to " + str(duty) + " %" + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: self.logger.debug("Timeout!!!!") return False - def cmd_ro_pump_duty_cycle_pct(self, duty: float) -> int: + def cmd_ro_pump_measured_flow_rate_override(self, flow: float, reset: int = NO_RESET) -> int: """ - Constructs and sends the set RO pump duty cycle message + Constructs and sends the RO flow rate override command. Constraints: Must be logged into DG. - @param duty: integer - 1 percentage for duty cycle between 0 and 100 + @param flow: float - flow rate (in L/min) to override with + @param reset: integer - 1 to reset a previous override, 0 to override @return: 1 if successful, zero otherwise """ - dc = float_to_bytearray(duty / 100) - payload = dc + rst = integer_to_bytearray(reset) + flo = float_to_bytearray(flow) + payload = rst + flo + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, - message_id=MsgIds.MSG_ID_DG_RO_PUMP_DUTY_CYCLE_OVERRIDE.value, + message_id=MsgIds.MSG_ID_DG_RO_FLOW_RATE_OVERRIDE.value, payload=payload) - self.logger.debug("RO pump duty cycle set") + self.logger.debug("Override RO pump measured flow rate") # Send message received_message = self.can_interface.send(message) # If there is content... if received_message is not None: - + # self.logger.debug(received_message) + if reset == RESET: + str_res = "Reset back to normal" + else: + str_res = str(flo) self.logger.debug( - "RO pump duty cycle set to " + str(duty) + " %" + + "Measured RO flow rate overridden to " + str_res + " L/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: self.logger.debug("Timeout!!!!") return False - def cmd_ro_flow_rate_measured_override(self, flow: float, reset: int = NO_RESET) -> int: + def cmd_set_ro_flow_rate(self, flow: float) -> int: """ - Constructs and sends the RO measured rate override command. + Constructs and sends the RO rate set command. + Constraints: Must be logged into DG. - @param flow: float - flow rate (in L/min) to override with - @param reset: integer - 1 to reset a previous override, 0 to override + @param flow: float - flow rate (in L/min) to set @return: 1 if successful, zero otherwise """ - rst = integer_to_bytearray(reset) flo = float_to_bytearray(flow) - payload = rst + flo + payload = flo message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, - message_id=MsgIds.MSG_ID_DG_RO_PUMP_TARGET_FLOW_OVERRIDE.value, + message_id=MsgIds.MSG_ID_DG_SET_RO_PUMP_TARGET_FLOW.value, payload=payload) - self.logger.debug("override RO pump pressure set point") + self.logger.debug("Set RO pump target flow rate") # Send message received_message = self.can_interface.send(message) # If there is content... if received_message is not None: - # self.logger.debug(received_message) - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(flo) + str_res = str(flo) self.logger.debug( - "RO flow rate overridden to " + str_res + " L/min: " + + "Target RO flow rate set to " + str_res + " L/min: " + 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/dg/rtc.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/rtc.py (.../rtc.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ dialin/dg/rtc.py (.../rtc.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -5,23 +5,25 @@ # 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 rtc.py +# @file rtc.py # -# @author (last) Quang Nguyen -# @date (last) 13-May-2021 -# @author (original) Quang Nguyen -# @date (original) 13-May-2021 +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Quang Nguyen +# @date (original) 13-May-2021 # ############################################################################ import struct -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.conversions import integer_to_bytearray -from ..utils.base import _AbstractSubSystem, _publish from ..common.msg_defs import MsgIds, MsgFieldPositions from logging import Logger +from ..common.msg_defs import MsgIds +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish +from ..utils.conversions import integer_to_bytearray -class DGRTC(_AbstractSubSystem): + +class DGRTC(AbstractSubSystem): """ Dialysate Generator (DG) Dialin API sub-class for rtc commands. @@ -52,7 +54,7 @@ """ return self.rtc_epoch - @_publish(["rtc_epoch"]) + @publish(["rtc_epoch"]) def _handler_rtc_epoch(self, message): """ Publishes the rtc time in epoch @@ -97,10 +99,10 @@ if received_message is not None: self.logger.debug(received_message) - # str_res = str(flow) - self.logger.debug("Time and Date in rtc set to seconds: " + str(sec) + " minutes: " + str(min) + " hours: " - + str(hour) + " days: " + str(day) + " months: " + str(month) + " years: " + str(year) + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + self.logger.debug( + "Time and Date in rtc set to seconds: " + str(sec) + " minutes: " + str(min) + " hours: " + + str(hour) + " days: " + str(day) + " months: " + str(month) + " years: " + str(year) + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: Index: dialin/dg/service_record.py =================================================================== diff -u -r5a634c567871a6855667341464bac9e057cd2b93 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/service_record.py (.../service_record.py) (revision 5a634c567871a6855667341464bac9e057cd2b93) +++ dialin/dg/service_record.py (.../service_record.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,12 +1,28 @@ +########################################################################### +# +# Copyright (c) 2019-2021 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 service_record.py +# +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 12-Feb-2021 +# +############################################################################ import struct import time from collections import OrderedDict +from enum import unique +from logging import Logger + from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, DialinEnum, _publish +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, DialinEnum, publish from ..utils.nv_ops_utils import NVOpsUtils -from logging import Logger -from enum import unique @unique @@ -15,7 +31,7 @@ SERVICE_LOCATION_FIELD = 1 -class DGServiceNVRecord(_AbstractSubSystem): +class DGServiceNVRecord(AbstractSubSystem): """ Hemodialysis Device (HD) Dialin API sub-class for service record commands. @@ -139,7 +155,7 @@ self._utilities.process_received_record_from_fw(self.dg_service_record, self._raw_service_record) self._handler_received_complete_dg_service_record() - @_publish(["dg_service_record"]) + @publish(["dg_service_record"]) def _handler_received_complete_dg_service_record(self): """ Publishes the received service record @@ -234,4 +250,3 @@ groups_byte_size += self._utilities.calculate_group_byte_size(service_records[record]) return service_records, groups_byte_size - Index: dialin/dg/switches.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/switches.py (.../switches.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ dialin/dg/switches.py (.../switches.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -27,8 +27,8 @@ @unique class DGSwitchStatus(DialinEnum): - OFF = 0 - ON = 1 + CLOSED = 0 + OPEN = 1 @unique @@ -58,9 +58,9 @@ msg_id = MsgIds.MSG_ID_DG_SWITCHES_DATA.value self.can_interface.register_receiving_publication_function(channel_id, msg_id, self._handler_switches_sync) - self.dg_switches_status = {DGSwitchesName.CONCENTRATE_CAP.name: DGSwitchStatus.OFF.value, - DGSwitchesName.DIALYSATE_CAP.name: DGSwitchStatus.OFF.value, - DGSwitchesName.FLUID_DOOR.name: DGSwitchStatus.OFF.value} + self.dg_switches_status = {DGSwitchesName.CONCENTRATE_CAP.name: DGSwitchStatus.CLOSED.value, + DGSwitchesName.DIALYSATE_CAP.name: DGSwitchStatus.CLOSED.value, + DGSwitchesName.FLUID_DOOR.name: DGSwitchStatus.CLOSED.value} def get_switches_status(self) -> dict: """ Index: dialin/dg/system_record.py =================================================================== diff -u -r5a634c567871a6855667341464bac9e057cd2b93 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/dg/system_record.py (.../system_record.py) (revision 5a634c567871a6855667341464bac9e057cd2b93) +++ dialin/dg/system_record.py (.../system_record.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,21 +1,36 @@ - +########################################################################### +# +# Copyright (c) 2019-2021 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 system_record.py +# +# @author (last) Quang Nguyen +# @date (last) 05-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 10-Feb-2021 +# +############################################################################ import struct import time from collections import OrderedDict +from enum import unique +from logging import Logger + from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, DialinEnum, _publish +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, DialinEnum, publish from ..utils.nv_ops_utils import NVOpsUtils -from logging import Logger -from enum import unique @unique class MFGLocation(DialinEnum): MFG_LOCATION_FACTORY = 0 -class DGSystemNVRecord(_AbstractSubSystem): +class DGSystemNVRecord(AbstractSubSystem): """ Hemodialysis Device (HD) Dialin API sub-class for system record commands. @@ -142,7 +157,7 @@ self._utilities.process_received_record_from_fw(self.dg_system_record, self._raw_system_record) self._handler_received_complete_dg_system_record() - @_publish(["dg_system_record"]) + @publish(["dg_system_record"]) def _handler_received_complete_dg_system_record(self): """ Publishes the received system record @@ -228,14 +243,14 @@ @return: system record dictionary and the byte size of this group """ groups_byte_size = 0 - system_records = OrderedDict({'system_record': - {'top_level_pn': [' int: + def cmd_hd_set_operation_mode(self, new_mode: int = 0) -> int: """ Constructs and sends a set operation mode request command via CAN bus. Constraints: Must be logged into HD. Transition from current to requested op mode must be legal. - @param newMode: ID of operation mode to transition to + @param new_mode: ID of operation mode to transition to HD_OP_MODE_FAULT = 0 HD_OP_MODE_SERVICE = 1 HD_OP_MODE_INIT_POST = 2 @@ -244,13 +248,13 @@ """ - payload = integer_to_bytearray(newMode) + payload = integer_to_bytearray(new_mode) message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, message_id=MsgIds.MSG_ID_HD_SET_OP_MODE_REQUEST.value, payload=payload) - self.logger.debug("Requesting HD mode change to " + str(newMode)) + self.logger.debug("Requesting HD mode change to " + str(new_mode)) # Send message received_message = self.can_interface.send(message) @@ -280,9 +284,9 @@ """ if active: - sft=1 + sft = 1 else: - sft=0 + sft = 0 rst = integer_to_bytearray(reset) saf = integer_to_bytearray(sft) payload = rst + saf @@ -324,3 +328,214 @@ self.can_interface.send(message, 0) self.logger.debug("Sent request to HD to reset...") self.hd_set_logged_in_status(False) + + def cmd_op_mode_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the HD operation mode broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_OP_MODE_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override operation mode data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Operation mode data 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: + self.logger.debug("Timeout!!!!") + return False + + def cmd_standby_mode_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the standby mode broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_STANDBY_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override standby mode data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Standby mode data 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: + self.logger.debug("Timeout!!!!") + return False + + def cmd_pre_treatment_mode_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the pre-treatment mode broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_PRE_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override pre-treatment mode broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Pre-treatment mode data 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: + self.logger.debug("Timeout!!!!") + return False + + def cmd_treatment_mode_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the treatment mode broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override treatment mode data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Treatment mode data 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: + self.logger.debug("Timeout!!!!") + return False + + def cmd_post_treatment_mode_broadcast_interval_override(self, ms: int = 250, reset: int = NO_RESET): + """ + Constructs and sends the post-treatment mode broadcast interval override command + Constraints: + Must be logged into HD. + Given interval must be non-zero and a multiple of the HD general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + rst = integer_to_bytearray(reset) + mis = integer_to_bytearray(ms) + payload = rst + mis + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, + message_id=MsgIds.MSG_ID_HD_POST_TREATMENT_DATA_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override post-treatment mode data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + if reset == RESET: + str_res = "reset back to normal: " + else: + str_res = str(ms) + " ms: " + self.logger.debug("Post-treatment mode data 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: + self.logger.debug("Timeout!!!!") + return False + Index: dialin/hd/rtc.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/hd/rtc.py (.../rtc.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ dialin/hd/rtc.py (.../rtc.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,28 +1,33 @@ ########################################################################### # -# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2021 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 rtc.py +# @file rtc.py # -# @author (last) Peter Lucia -# @date (last) 03-Nov-2020 -# @author (original) Peter Lucia -# @date (original) 02-Apr-2020 +# @author (last) Quang Nguyen +# @date (last) 11-Aug-2021 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # ############################################################################ + import struct from ..protocols.CAN import (DenaliMessage, DenaliChannels) from ..utils.conversions import integer_to_bytearray -from ..utils.base import _AbstractSubSystem, _publish from ..common.msg_defs import MsgIds, MsgFieldPositions from logging import Logger +from ..common.msg_defs import MsgIds +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish +from ..utils.conversions import integer_to_bytearray -class HDRTC(_AbstractSubSystem): + +class HDRTC(AbstractSubSystem): """ Hemodialysis Delivery (HD) Dialin API sub-class for rtc commands. @@ -53,7 +58,7 @@ """ return self.rtc_epoch - @_publish(["rtc_epoch"]) + @publish(["rtc_epoch"]) def _handler_rtc_epoch(self, message): """ Publishes the rtc time in epoch @@ -99,9 +104,10 @@ self.logger.debug(received_message) # str_res = str(flow) - self.logger.debug("Time and Date in rtc set to seconds: " + str(sec) + " minutes: " + str(min) + " hours: " + - str(hour) + " days: " + str(day) + " months: " + str(month) + " years: " + str(year) + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) + self.logger.debug( + "Time and Date in rtc set to seconds: " + str(sec) + " minutes: " + str(min) + " hours: " + + str(hour) + " days: " + str(day) + " months: " + str(month) + " years: " + str(year) + + str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) # response payload is OK or not OK return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] else: Index: dialin/hd/service_record.py =================================================================== diff -u -r5a634c567871a6855667341464bac9e057cd2b93 -ra901fe931c08daea69337c1f44135637a764ce7a --- dialin/hd/service_record.py (.../service_record.py) (revision 5a634c567871a6855667341464bac9e057cd2b93) +++ dialin/hd/service_record.py (.../service_record.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,13 +1,28 @@ +########################################################################### +# +# Copyright (c) 2019-2021 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 service_record.py +# +# @author (last) Quang Nguyen +# @date (last) 11-Aug-2021 +# @author (original) Dara Navaei +# @date (original) 14-Feb-2021 +# +############################################################################ import struct -import datetime import time from collections import OrderedDict +from enum import unique +from logging import Logger + from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import (DenaliMessage, DenaliChannels) -from ..utils.base import _AbstractSubSystem, _publish, DialinEnum +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum from ..utils.nv_ops_utils import NVOpsUtils -from logging import Logger -from enum import unique @unique @@ -16,7 +31,7 @@ SERVICE_LOCATION_FIELD = 1 -class HDServiceNVRecords(_AbstractSubSystem): +class HDServiceNVRecords(AbstractSubSystem): """ Hemodialysis Device (HD) Dialin API sub-class for service record commands. @@ -141,7 +156,7 @@ self._utilities.process_received_record_from_fw(self.hd_service_record, self._raw_service_record) self._handler_received_complete_hd_service_record() - @_publish(["hd_service_record"]) + @publish(["hd_service_record"]) def _handler_received_complete_hd_service_record(self): """ Publishes the received service record @@ -229,11 +244,11 @@ groups_byte_size = 0 service_records = OrderedDict({'service_record': {'service_location': [' 3 and dg.dg_operation_sub_mode == 2: + if run_number > 7 and dg.dg_operation_sub_mode == 2: dg.hd_proxy.cmd_start_stop_dg(start=False) f.close() break elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ dg.dg_operation_sub_mode == 2 and counter == 1: - if timer == 1: - dg.hd_proxy.cmd_switch_reservoirs(reservoirID=1) - timer += 1 + if recirc_delay < 5: + recirc_delay += 1 + else: + if timer == 1: + dg.hd_proxy.cmd_switch_reservoirs(reservoirID=1) + timer += 1 - if timer > ((1/sleep_time) * 1): - timer = 1 + if timer > ((1/sleep_time) * 1): + timer = 1 + recirc_delay = 1 + counter += 1 + + elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ + dg.dg_operation_sub_mode == 2 and counter == 2: + dg.hd_proxy.cmd_drain(tare_load_cell=True) + counter += 1 + timer = 1 + + elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ + dg.dg_operation_sub_mode == 2 and counter == 3: + + timer += 1 + if timer > 4: + dg.hd_proxy.cmd_fill(volume=1700) counter += 1 elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ + dg.dg_operation_sub_mode == 2 and counter == 4: + counter = 1 + run_number += 1 + + sleep(sleep_time) + + except KeyboardInterrupt: + dg.hd_proxy.cmd_start_stop_dg(start=False) + f.close() + pass + + +def run_ro_pump_duty_cycles(): + + counter = 1 + timer = 0.1 + sleep_time = 1 + run_number = 1 + recirc_delay = 1 + ro_dc = 20 + ro_dc_step = 5 + f = open("/home/fw/projects/dialin/tests/run_ro_pump.log", "w") + + dg.hd_proxy.cmd_start_stop_dg() + sleep(0.1) + dg.ro_pump.cmd_ro_pump_duty_cycle_pct(ro_dc) + sleep(0.1) + + try: + while True: + dg_run = get_dg_run_info() + temperature = get_temperature_sensors_info() + heaters = get_heaters_with_no_temp_info() + load_cell = get_load_cells_info() + drain = get_drain_states_info() + ro = get_ro_info() + uv_reactors = get_uv_reactors_info() + fans = get_dg_fans_info() + valves = get_dg_valves_states() + + var = str(datetime.now()) + ', ' + str(run_number) + ', ' + str(ro_dc) + ', ' + dg_run + \ + temperature + heaters + load_cell + drain + ro + uv_reactors + fans + valves + '\r' + + print(var) + f.write(var) + + if ro_dc > 95 and dg.dg_operation_sub_mode == 2: + dg.hd_proxy.cmd_start_stop_dg(start=False) + f.close() + break + + elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ + dg.dg_operation_sub_mode == 2 and counter == 1: + + if recirc_delay < 1: + recirc_delay += 1 + else: + if timer == 1: + dg.hd_proxy.cmd_switch_reservoirs(reservoirID=1) + + timer += 1 + + if timer > ((1/sleep_time) * 1): + timer = 1 + recirc_delay = 1 + counter += 1 + + elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ dg.dg_operation_sub_mode == 2 and counter == 2: dg.hd_proxy.cmd_drain(tare_load_cell=True) counter += 1 timer = 1 elif DGOperationModes(dg.dg_operation_mode).name == DGOperationModes.DG_OP_MODE_RECIRCULATE.name and\ - dg.dg_operation_sub_mode == 2 and counter == 3: #and tpo > 39.0: + dg.dg_operation_sub_mode == 2 and counter == 3: timer += 1 if timer > 4: @@ -241,12 +423,15 @@ dg.dg_operation_sub_mode == 2 and counter == 4: counter = 1 run_number += 1 + ro_dc += ro_dc_step + dg.ro_pump.cmd_ro_pump_duty_cycle_pct(ro_dc) sleep(sleep_time) except KeyboardInterrupt: dg.hd_proxy.cmd_start_stop_dg(start=False) f.close() + pass def run_heat_disinfect(): @@ -265,9 +450,10 @@ ro = get_ro_info() temp = get_temperature_sensors_info() heaters = get_heaters_info() - fans = get_fans_info() + dg_fans = get_dg_fans_info() + hd_fans = get_hd_fans_info() - var = disinfect + load_cell + drain + ro + temp + heaters + fans + valves + '\r' + var = disinfect + load_cell + drain + ro + temp + heaters + dg_fans + hd_fans + valves + '\r' print(var) f.write(var) @@ -309,7 +495,7 @@ ro = get_ro_info() temp = get_temperature_sensors_info() heaters = get_heaters_info() - fans = get_fans_info() + fans = get_dg_fans_info() var = disinfect + load_cell + conc + drain + ro + temp + heaters + fans + valves + '\r' @@ -353,13 +539,16 @@ hd.cmd_log_in_to_hd() sleep(1) - run_heat_disinfect() + #run_heat_disinfect() #run_chemical_disinfect() #run_dg() + run_ro_pump_duty_cycles() + #cmd_set_disinfect_ui_screen() + #cmd_test_heaters() Index: tests/hd_valves_test.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- tests/hd_valves_test.py (.../hd_valves_test.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ tests/hd_valves_test.py (.../hd_valves_test.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -22,18 +22,11 @@ from dialin.hd.valves import ValvesPositions from time import sleep -if __name__ == "__main__": - # Create an instance of the DG Class - hd = HD(log_level='DEBUG') - if hd.cmd_log_in_to_hd() == 0: - exit(1) +def cycle_valves(): + # valves.cmd_open_hd_air_trap_valve(AirTrapState.STATE_OPEN) + # sleep(2) - valves = hd.valves - - #valves.cmd_open_hd_air_trap_valve(AirTrapState.STATE_OPEN) - #sleep(2) - overall_counter = 0 sleep_time = 0.05 overall_time_seconds = 4 @@ -45,17 +38,17 @@ valves.cmd_hd_valves_broadcast_interval_override(100) sleep(3) - #valves.cmd_set_hd_valve_position(0, 2) - #sleep(3) + # valves.cmd_set_hd_valve_position(0, 2) + # sleep(3) valves.cmd_home_hd_valve(valve.value) sleep(3) - #valves.cmd_set_hd_valve_current_override(valve.value, 0.85, reset=1) - #sleep(3) + # valves.cmd_set_hd_valve_current_override(valve.value, 0.85, reset=1) + # sleep(3) - #valves.cmd_set_hd_valve_position_count_override(valve.value, 5000, reset=1) - #sleep(2) + # valves.cmd_set_hd_valve_position_count_override(valve.value, 5000, reset=1) + # sleep(2) f = open("Valves_Test_200.log", "w") @@ -65,7 +58,7 @@ overall_counter = 0 valves.cmd_set_hd_valve_position(valve.value, ValvesPositions.VALVE_POSITION_B_OPEN.value) - while overall_counter < (overall_time_seconds/sleep_time): + while overall_counter < (overall_time_seconds / sleep_time): sleep(sleep_time) status = ('ID, {}, Pos, {}, PosCnt, {}, Cmd, {}, State, {}, Current, {}, PosA, {}, PosB, {}, PosC, {} \r' @@ -90,34 +83,46 @@ sleep(sleep_time) print('done') - """ - print("Reset") - #valves.cmd_set_hd_valve_pwm(2, 50, 0) - sleep(2) - valves.cmd_set_hd_valve_position(2, 3) +def change_valves_position(): - counter = 0 - overall_counter = 0 - overall_time_seconds = 3 - while overall_counter < (overall_time_seconds/sleep_time): + valve = ValvesEnum.VDI + valves.cmd_home_hd_valve(valve.value) + sleep(0.5) - if counter >= 10: - #print("Valve, {}, State, {}, Curr_Pos_ID, {}, Curr_Pos_Cnt, {}, Next_Pos_Cnt, {}, " - # "Current, {}, Pos_C, {}, Pos_A, {}, Pos_B, {}" - # .format(valves.hd_valve_ID, valves.hd_valve_state, valves.hd_valve_curr_pos_ID, - # valves.hd_valve_curr_pos_cnt, valves.hd_valve_next_pos_cnt, valves.hd_valve_current, - # valves.hd_valves_pos_c, valves.hd_valves_pos_a, valves.hd_valves_pos_b)) - counter = 0 + valves.cmd_set_hd_valve_position(valve.value, ValvesPositions.VALVE_POSITION_B_OPEN.value) + sleep(0.05) + valves.cmd_set_hd_valve_position(valve.value, ValvesPositions.VALVE_POSITION_A_INSERT_EJECT.value) - print("Pos, {}, Cmd, {}, Curr, {}, PosA, {}, PosB, {}, PosC, {}, State, {}, PWM, {}".format(valves.hd_valve_fast_pos, - valves.hd_valves_fast_cmd, valves.hd_valve_fast_current, - valves.hd_valves_pos_a, valves.hd_valves_pos_b, - valves.hd_valves_pos_c, valves.hd_valve_state, - valves.hd_valves_pwm)) + while True: - counter = counter + 1 - overall_counter = overall_counter + 1 + try: + status = ('ID, {}, Pos, {}, PosCnt, {}, Cmd, {}, State, {}, Current, {}, PosA, {}, PosB, {}, PosC, {} \r' + .format(valves.valves_status[valve.name]['Valve'], + valves.valves_status[valve.name]['PosID'], + valves.valves_status[valve.name]['PosCnt'], + valves.valves_status[valve.name]['Cmd'], + valves.valves_status[valve.name]['State'], + valves.valves_status[valve.name]['Current'], + valves.valves_status[valve.name]['PosA'], + valves.valves_status[valve.name]['PosB'], + valves.valves_status[valve.name]['PosC'])) + print(status) + except: + pass - sleep(sleep_time) - """"" \ No newline at end of file + sleep(1) + + +if __name__ == "__main__": + # Create an instance of the DG Class + hd = HD(log_level='DEBUG') + + if hd.cmd_log_in_to_hd() == 0: + exit(1) + + valves = hd.valves + + #cycle_valves() + change_valves_position() + Index: tests/peter/test_dg_records.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- tests/peter/test_dg_records.py (.../test_dg_records.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ tests/peter/test_dg_records.py (.../test_dg_records.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -183,6 +183,12 @@ print(dg.calibration_record.dg_calibration_record) + dg.calibration_record.dg_calibration_record['flow_sensors']['flow_sensor']['offset'][1] = 0.011 + dg.calibration_record.dg_calibration_record['flow_sensors']['flow_sensor']["cal_time"][1] = \ + NVOpsUtils.get_current_time_in_epoch() + dg.calibration_record.dg_calibration_record['flow_sensors']['flow_sensor']["crc"][1] = \ + NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record['flow_sensors']['flow_sensor']) + """ # Change the value(s) you are planning to change directly to the dictionary dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppi"]["fourth_order"][1] = 0.0 @@ -204,7 +210,7 @@ dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]) """ - #dg.calibration_record.cmd_set_dg_calibration_record(dg.calibration_record.dg_calibration_record) + dg.calibration_record.cmd_set_dg_calibration_record(dg.calibration_record.dg_calibration_record) print(dg.calibration_record.dg_calibration_record) @@ -222,10 +228,13 @@ if dg.cmd_log_in_to_dg(): dg.calibration_record.cmd_reset_dg_calibration_record() + sleep(0.25) print(dg.calibration_record.dg_calibration_record) #dg.scheduled_runs_record.cmd_reset_dg_calibration_record() - #dg.system_record.cmd_reset_dg_system_record() - #dg.service_record.cmd_reset_dg_service_record() + #sleep(0.25) + dg.system_record.cmd_reset_dg_system_record() + sleep(0.25) + dg.service_record.cmd_reset_dg_service_record() def test_dg_service_record(): @@ -280,8 +289,8 @@ if __name__ == "__main__": - #test_dg_reset_record() + test_dg_reset_record() #test_dg_calibration_record() # test_dg_service_record() - test_dg_system_record() + #test_dg_system_record() # test_dg_scheduled_runs_record() Index: tests/peter/test_hd_records.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- tests/peter/test_hd_records.py (.../test_hd_records.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ tests/peter/test_hd_records.py (.../test_hd_records.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,3 +1,18 @@ +########################################################################### +# +# Copyright (c) 2019-2021 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 test_hd_records.py +# +# @author (last) Dara Navaei +# @date (last) 29-Jul-2021 +# @author (original) Dara Navaei +# @date (original) 20-Jul-2021 +# +############################################################################ import copy import pprint import subprocess Index: tests/test_dg_records.py =================================================================== diff -u -r6b5600f056eff25cbb365fa6a5eefc4f5fad9360 -ra901fe931c08daea69337c1f44135637a764ce7a --- tests/test_dg_records.py (.../test_dg_records.py) (revision 6b5600f056eff25cbb365fa6a5eefc4f5fad9360) +++ tests/test_dg_records.py (.../test_dg_records.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -1,3 +1,18 @@ +########################################################################### +# +# Copyright (c) 2019-2021 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 test_dg_records.py +# +# @author (last) Dara Navaei +# @date (last) 01-Jun-2021 +# @author (original) Dara Navaei +# @date (original) 01-Mar-2021 +# +############################################################################ from dialin.dg.dialysate_generator import DG from time import sleep Index: tests/test_flush.py =================================================================== diff -u -r8474f8e345f165187d4dde17840575ee4e98a9b4 -ra901fe931c08daea69337c1f44135637a764ce7a --- tests/test_flush.py (.../test_flush.py) (revision 8474f8e345f165187d4dde17840575ee4e98a9b4) +++ tests/test_flush.py (.../test_flush.py) (revision a901fe931c08daea69337c1f44135637a764ce7a) @@ -17,22 +17,27 @@ import sys sys.path.append("..") from dialin.dg.dialysate_generator import DG +from dialin.hd.hemodialysis_device import HD from dialin.dg.drain_pump import DrainPumpStates from time import sleep def get_flush_mode_info(): - info = ('State, {}, Overall_elapsed_time, {}, State_elapsed_time, {}, Drain_vol, {:5.3f}, ' + info = ('State, {}, Overall_elapsed_time, {}, State_elapsed_time, {}, Drain_vol, {:5.3f}, Top_alarm, {}, ' .format(dg.flush.flush_state, dg.flush.overall_elapsed_time, dg.flush.state_elapsed_time, - dg.flush.flush_drain_line_volume_l)) + dg.flush.flush_drain_line_volume_l, hd.alarms.alarm_top)) return info + def get_concentrate_pumps_info(): - info = ('Bicarb_tgt_speed, {:5.3f}, Bicarb_speed, {:5.3f}, CPo, {:5.3f}, CD1, {:5.3f}, CD2, {:5.3f}, ' + info = ('Bicarb_tgt_speed, {:5.3f}, Bicarb_speed, {:5.3f}, Acid_tgt_speed, {:5.3f}, Acid_speed, {:5.3f}, ' + 'CPo, {:5.3f}, CD1, {:5.3f}, CD2, {:5.3f}, ' .format(dg.concentrate_pumps.concentrate_pump_cp2_current_set_speed, dg.concentrate_pumps.concentrate_pump_cp2_measured_speed, + dg.concentrate_pumps.concentrate_pump_cp1_current_set_speed, + dg.concentrate_pumps.concentrate_pump_cp1_measured_speed, dg.conductivity_sensors.conductivity_sensor_cpo, dg.conductivity_sensors.conductivity_sensor_cd1, dg.conductivity_sensors.conductivity_sensor_cd2)) return info @@ -85,6 +90,13 @@ return info +def get_uv_reactors_info(): + + info = ('Inlet_status, {}, Outlet_status, {}, ' + .format(dg.uv_reactors.inlet_uv_reactor_state, dg.uv_reactors.outlet_uv_reactor_state)) + return info + + def run_flush_mode(): complete_counter = 1 @@ -97,9 +109,10 @@ drain = get_drain_states_info() ro = get_ro_info() conc = get_concentrate_pumps_info() + uv_reactors = get_uv_reactors_info() valves = get_dg_valves_states() - var = flush + load_cell + drain + ro + conc + valves + '\r' + var = flush + load_cell + drain + ro + conc + uv_reactors + valves + '\r' print(var) f.write(var) @@ -123,7 +136,10 @@ if __name__ == "__main__": dg = DG(log_level='DEBUG') + hd = HD(log_level='DEBUG') dg.cmd_log_in_to_dg() sleep(1) + hd.cmd_log_in_to_hd() + sleep(1) run_flush_mode()