Index: dialin/dg/dialysate_generator.py =================================================================== diff -u -rbe97d97e1ddd765351cdc51cb75aee9e7e63ba58 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision be97d97e1ddd765351cdc51cb75aee9e7e63ba58) +++ dialin/dg/dialysate_generator.py (.../dialysate_generator.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -40,9 +40,9 @@ from .service_record import DGServiceNVRecord from .scheduled_runs_record import DGScheduledRunsNVRecord from .valves import DGValves -from ..utils.conversions import integer_to_bytearray -from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) +from ..utils import * from ..utils.base import _AbstractSubSystem, _publish, _LogManager +from ..protocols.CAN import (DenaliCanMessenger, DenaliMessage, DenaliChannels) from ..common.msg_defs import MsgIds, MsgFieldPositions Index: dialin/protocols/CAN.py =================================================================== diff -u -rdf58df8b4e8b8d3f0b0764deda9f15050a071d78 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/protocols/CAN.py (.../CAN.py) (revision df58df8b4e8b8d3f0b0764deda9f15050a071d78) +++ dialin/protocols/CAN.py (.../CAN.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -519,8 +519,8 @@ self.message_queue.append(message) else: # no new packets in receive buffer - # We have received nothing, let's sleep 1 msec and let's check again - sleep(0.001) + # Careful here, making this any shorter will start limiting CPU time for other threads + sleep(0.01) def handle_messages(self): """ @@ -531,7 +531,8 @@ while True: if not self.message_queue: - sleep(0.001) + # Careful here, making this any shorter will start limiting CPU time for other threads + sleep(0.01) else: message: dict = self.message_queue.popleft() Index: dialin/ui/__init__.py =================================================================== diff -u -rf053467ac7cfb9fe349e394342d3a9253a377403 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/ui/__init__.py (.../__init__.py) (revision f053467ac7cfb9fe349e394342d3a9253a377403) +++ dialin/ui/__init__.py (.../__init__.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -1,3 +1,2 @@ from .hd_simulator import HDSimulator from .dg_simulator import DGSimulator -from .hd_simulator_alarms import HDAlarmsSimulator Index: dialin/ui/dg_simulator.py =================================================================== diff -u -rdf58df8b4e8b8d3f0b0764deda9f15050a071d78 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/ui/dg_simulator.py (.../dg_simulator.py) (revision df58df8b4e8b8d3f0b0764deda9f15050a071d78) +++ dialin/ui/dg_simulator.py (.../dg_simulator.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -13,15 +13,12 @@ # @date (original) 15-Mar-2020 # ############################################################################ -import struct - -from ..utils import YES from ..common import * from ..protocols.CAN import (DenaliMessage, DenaliCanMessenger, DenaliChannels) +from ..utils import * from ..utils.base import _AbstractSubSystem, _LogManager -from ..utils.conversions import integer_to_bytearray, float_to_bytearray, byte_to_bytearray, short_to_bytearray from . import messageBuilder Index: dialin/ui/hd_simulator.py =================================================================== diff -u -rdf58df8b4e8b8d3f0b0764deda9f15050a071d78 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision df58df8b4e8b8d3f0b0764deda9f15050a071d78) +++ dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -14,21 +14,18 @@ # ############################################################################ import enum -import struct from time import sleep from typing import List import time -import subprocess from . import messageBuilder from .hd_simulator_alarms import HDAlarmsSimulator from ..common import * from ..protocols.CAN import (DenaliMessage, DenaliCanMessenger, DenaliChannels) +from ..utils import * from ..utils.base import _AbstractSubSystem, _LogManager -from ..utils.conversions import integer_to_bytearray, float_to_bytearray, byte_to_bytearray, short_to_bytearray -from ..utils import YES class HDSimulator(_AbstractSubSystem): Index: dialin/ui/hd_simulator_alarms.py =================================================================== diff -u -r0f311aec036eb4508cfa7dd4090c579101c348b1 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision 0f311aec036eb4508cfa7dd4090c579101c348b1) +++ dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -15,12 +15,14 @@ ############################################################################ import struct from time import sleep, time + +from ..utils import YES, NO from ..protocols.CAN import (DenaliMessage, DenaliCanMessenger, DenaliChannels) from logging import Logger from ..utils.base import _AbstractSubSystem -from ..utils.conversions import integer_to_bytearray, integer_to_bit_array +from ..utils.conversions import integer_to_bytearray, integer_to_bit_array, float_to_bytearray from ..common.msg_defs import MsgIds, MsgFieldPositions from ..common.alarm_defs import AlarmList @@ -113,6 +115,7 @@ self.logger = logger self.flags = 0 self.clear_after_user_action = False + self.current_alarm_volume = 5 if self.can_interface is not None: channel_id = DenaliChannels.ui_to_hd_ch_id @@ -122,7 +125,64 @@ self.can_interface.register_receiving_publication_function(channel_id, MsgIds.MSG_ID_UI_ALARM_USER_ACTION.value, self._handler_user_action) + self.can_interface.register_receiving_publication_function(DenaliChannels.ui_to_hd_ch_id, + MsgIds.MSG_ID_UI_SET_ALARM_AUDIO_VOLUME_LEVEL_CMD.value, + self._handler_request_override_alarm_volume) + self._start_broadcasts() + def _start_broadcasts(self): + """ + Starts broadcasting data messages + @return: None + """ + + # while True: + # self._send_alarm_volume_broadcast() + # sleep(1) + pass + + def _send_alarm_volume_broadcast(self): + """ + Sends the alarm volume broadcast message + @return: None + """ + + payload = integer_to_bytearray(5) # alarm volume + payload += float_to_bytearray(1.0) # alarm audio current high gain (mA) + payload += float_to_bytearray(1.0) # alarm audio current low gain (mA) + payload += float_to_bytearray(1.0) # alarm backup audio current (mA) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, + message_id=MsgIds.MSG_ID_HD_ALARM_INFORMATION.value, + payload=payload) + + self.can_interface.send(message, 0) + + def _handler_request_override_alarm_volume(self, message: dict) -> None: + """ + Handler for a UI request to override the alarm volume level + @param message: + @return: + """ + vol = struct.unpack('i', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.START_POS_FIELD_1 + 4]))[0] + + self.logger.debug("Received request to override alarm volume to {0}".format(vol)) + + if 1 <= vol <= 5: + self.current_alarm_volume = vol + payload = integer_to_bytearray(YES) + payload += integer_to_bytearray(0) + else: + payload = integer_to_bytearray(NO) + payload += integer_to_bytearray(1) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, + message_id=MsgIds.MSG_ID_HD_ALARM_AUDIO_VOLUME_SET_RESPONSE.value, + payload=payload) + + self.can_interface.send(message, 0) + def cmd_activate_alarm_id(self, state: int = HIGH, alarm: int = 0, escalates_in: int = 0, Index: dialin/utils/__init__.py =================================================================== diff -u -r82e32ae00355b2245a2660569935de152a883799 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/utils/__init__.py (.../__init__.py) (revision 82e32ae00355b2245a2660569935de152a883799) +++ dialin/utils/__init__.py (.../__init__.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -1,3 +1,7 @@ from .base import * +from .helpers import * +from .conversions import * +from .excel_ops import * +from .nv_ops_utils import * YES = 1 NO = 0 \ No newline at end of file Index: dialin/utils/base.py =================================================================== diff -u -r82e32ae00355b2245a2660569935de152a883799 -rbfb0c47181dc8a73d09825ab697a7799dd520417 --- dialin/utils/base.py (.../base.py) (revision 82e32ae00355b2245a2660569935de152a883799) +++ dialin/utils/base.py (.../base.py) (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -15,230 +15,11 @@ ############################################################################ import logging import os -import subprocess from abc import ABC, abstractmethod from datetime import datetime from enum import Enum -def setup_virtual_can_interface(): - """ - Convenience function to setup a virtual can interface using the most common settings - See the setup_can function to setup a can interface with custom settings. - - @return: True if successful, false otherwise - """ - bring_interface_down(interface="can0", delete=True) - is_present = is_interface_present("can0") - if not is_present: - setup_can(interface="can0", - is_virtual=True) - result = is_interface_up("can0") - if result: - print("Success") - return True - - print("Failure") - return False - - -def setup_real_can_interface(): - """ - Convenience function to setup a real can interface using the most common settings - See the setup_can function to setup a can interface with custom settings. - - @return: True if successful, False otherwise - """ - delete_virtual = input("Delete virtual can interface? (y,n)") - if delete_virtual.upper() in ["Y", "YES"]: - bring_interface_down(interface="can0", delete=True) - if is_interface_present("can0"): - print("Failure") - return False - else: - bring_interface_down(interface="can0", delete=False) - if not is_interface_present("can0") or is_interface_up("can0"): - print("Failure") - return False - input("Press 'Enter' after plugging in the PCAN-USB.") - setup_can(interface="can0", - is_virtual=False, - bitrate=250000, - restart_ms=100, - txqueue=10000) - - if is_interface_present("can0") and is_interface_up("can0"): - print("Success") - return True - else: - print("Failure") - return False - - -def bring_interface_down(interface: str = "can0", delete=False): - """ - Brings the specified can interface down - - @param interface: (str) the interface name - @param delete: (bool) whether to delete the interface after bringing it down - @return: None - """ - cmd_iface_down = "sudo ifconfig {0} down > /dev/null 2>&1".format(interface) - cmd_iface_delete = "sudo ip link delete dev {0} > /dev/null 2>&1".format(interface) - - success, info = run_cmd(cmd_iface_down) - if not success: - print("Warning: Could not bring interface down: {0}".format(info)) - if delete: - run_cmd(cmd_iface_delete) - if not success: - print("Warning: Could not delete the interface: {0}".format(info)) - - -def run_cmd(cmd: str): - """ - Runs the provided command, returns if it was successful and output or error information - - @param cmd: (str) the command to run - @return: tuple(bool, info) Whether the command was successful. If true info is the output, otherwise - info contains the error information - """ - try: - result = subprocess \ - .check_output(cmd, - shell=True).decode("utf-8").strip() - return True, result - except subprocess.CalledProcessError as e: - return False, str(e) - - -def is_interface_up(interface: str = "can0"): - """ - Checks if the specified interface is listed and up - - @param interface: - @return: (bool) True if up, False if not or if we can't tell - """ - cmd_check_interface = "ifconfig {0}".format(interface) - - success, info = run_cmd(cmd_check_interface) - if success: - if interface in info and "UP,RUNNING" in info: - return True - return False - - -def is_interface_present(interface: str = "can0"): - """ - Checks if the specified interface is listed - - @param interface: - @return: (bool) True if present, False if not or if we can't tell - """ - cmd_check_interface = "ip a" - - success, info = run_cmd(cmd_check_interface) - if success: - if interface in info: - return True - return False - - -def setup_can(interface: str = "can0", is_virtual=False, bitrate=250000, restart_ms=100, txqueue=10000): - """ - Convenience function to setup a can interface - - @param interface: (str) The interface name - @param is_virtual: (bool) If the interface is virtual or not - @param bitrate: (int) The desired bitrate (applies to non-virtual interfaces only) - @param restart_ms: (int) The desired restart_ms (applies to non-virtual interfaces only) - @param txqueue: (int) The desired txqueue length - @return: - """ - cmd_iface_up = "sudo ip link set {0} up type can bitrate {1} restart-ms {2}"\ - .format(interface, bitrate, restart_ms) - cmd_txqueue = "sudo ifconfig {0} txqueuelen {1}".format(interface, txqueue) - - cmd_iface_type_virtual = "sudo ip link add dev {0} type vcan".format(interface) - cmd_iface_up_virtual = "sudo ip link set {0} up".format(interface) - - if is_virtual: - success, info = run_cmd(cmd_iface_type_virtual) - if not success: - print("Warning: Could not set iface type to virtual: {0}".format(info)) - success, info = run_cmd(cmd_iface_up_virtual) - if not success: - print("Warning: Could not bring up virtual interface: {0}".format(info)) - else: - success, info = run_cmd(cmd_iface_up) - if not success: - print("Warning: Could not bring interface up: {0}".format(info)) - - success, info = run_cmd(cmd_txqueue) - if not success: - print("Warning: Could not set txtqueue length: {0}".format(cmd_txqueue)) - - -def create_logger(log_path: str = "/tmp/DialinScript.log", - level: str = "ERROR", - enable_metadata=True, - clear_before_write=False): - """ - Convenience function to create a logger for external Dialin scripts - - @param log_path: (str) The full path to the output log file. - @param level: (str) The logging level (e.g. INFO, WARN, DEBUG, ERROR, CRITICAL) - @param enable_metadata: (bool) if True, include metadata, otherwise, log only the message - @return: (logging.Logger) The logger object - """ - - numeric_level = getattr(logging, level, logging.ERROR) - - current_time = datetime.now() - - # create a new unique logger using current date and time - logger = logging.getLogger("DialinScript{0}{1}{2}".format(current_time.hour, - current_time.minute, - current_time.second)) - logger.setLevel(numeric_level) - - if clear_before_write: - fh = logging.FileHandler(log_path, mode='w') - else: - fh = logging.FileHandler(log_path) - fh.setLevel(numeric_level) - ch = logging.StreamHandler() - ch.setLevel(numeric_level) - if enable_metadata: - formatter = logging.Formatter(fmt=_LogManager.LOG_FMT, - datefmt=_LogManager.LOG_DT_FMT) - else: - formatter = logging.Formatter(fmt=_LogManager.LOG_FMT_NO_METADATA) - fh.setFormatter(formatter) - ch.setFormatter(formatter) - - logger.addHandler(fh) - logger.addHandler(ch) - return logger - - -def find_variables_in_object(obj, value, starts_with: str = ""): - """ - Returns a list of variable names that in the object that match the searched value - - @param obj: (object) The object to search through - @param value: (object) The value to lookup - @param starts_with: (str) The - @return: (List[str]) A list of variable names matching the searched value - """ - result = [] - for attr in dir(obj): - if not callable(getattr(obj, attr)) and attr.startswith(starts_with): - if value == getattr(obj, attr): - result.append(attr) - return result - - class AbstractObserver(ABC): """ Publicly accessible parent class for all observers. @@ -284,7 +65,7 @@ print("CRITICAL: {0}".format(msg)) -class _LogManager(ABC): +class _LogManager: LOG_FMT = '%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s' LOG_FMT_NO_METADATA = '%(message)s' @@ -487,7 +268,6 @@ return _decorator - class DialinEnum(Enum): @classmethod @@ -504,3 +284,4 @@ @classmethod def has_value(cls, value): return value in cls._value2member_map_ + Index: dialin/utils/helpers.py =================================================================== diff -u --- dialin/utils/helpers.py (revision 0) +++ dialin/utils/helpers.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,222 @@ +import logging +import subprocess +from datetime import datetime +from .base import _LogManager + + +def setup_virtual_can_interface(): + """ + Convenience function to setup a virtual can interface using the most common settings + See the setup_can function to setup a can interface with custom settings. + + @return: True if successful, false otherwise + """ + bring_interface_down(interface="can0", delete=True) + is_present = is_interface_present("can0") + if not is_present: + setup_can(interface="can0", + is_virtual=True) + result = is_interface_up("can0") + if result: + print("Success") + return True + + print("Failure") + return False + + +def setup_real_can_interface(): + """ + Convenience function to setup a real can interface using the most common settings + See the setup_can function to setup a can interface with custom settings. + + @return: True if successful, False otherwise + """ + delete_virtual = input("Delete virtual can interface? (y,n)") + if delete_virtual.upper() in ["Y", "YES"]: + bring_interface_down(interface="can0", delete=True) + if is_interface_present("can0"): + print("Failure") + return False + else: + bring_interface_down(interface="can0", delete=False) + if not is_interface_present("can0") or is_interface_up("can0"): + print("Failure") + return False + input("Press 'Enter' after plugging in the PCAN-USB.") + setup_can(interface="can0", + is_virtual=False, + bitrate=250000, + restart_ms=100, + txqueue=10000) + + if is_interface_present("can0") and is_interface_up("can0"): + print("Success") + return True + else: + print("Failure") + return False + + +def bring_interface_down(interface: str = "can0", delete=False): + """ + Brings the specified can interface down + + @param interface: (str) the interface name + @param delete: (bool) whether to delete the interface after bringing it down + @return: None + """ + cmd_iface_down = "sudo ifconfig {0} down > /dev/null 2>&1".format(interface) + cmd_iface_delete = "sudo ip link delete dev {0} > /dev/null 2>&1".format(interface) + + success, info = run_cmd(cmd_iface_down) + if not success: + print("Warning: Could not bring interface down: {0}".format(info)) + if delete: + run_cmd(cmd_iface_delete) + if not success: + print("Warning: Could not delete the interface: {0}".format(info)) + + +def run_cmd(cmd: str): + """ + Runs the provided command, returns if it was successful and output or error information + + @param cmd: (str) the command to run + @return: tuple(bool, info) Whether the command was successful. If true info is the output, otherwise + info contains the error information + """ + try: + result = subprocess \ + .check_output(cmd, + shell=True).decode("utf-8").strip() + return True, result + except subprocess.CalledProcessError as e: + return False, str(e) + + +def is_interface_up(interface: str = "can0"): + """ + Checks if the specified interface is listed and up + + @param interface: + @return: (bool) True if up, False if not or if we can't tell + """ + cmd_check_interface = "ifconfig {0}".format(interface) + + success, info = run_cmd(cmd_check_interface) + if success: + if interface in info and "UP,RUNNING" in info: + return True + return False + + +def is_interface_present(interface: str = "can0"): + """ + Checks if the specified interface is listed + + @param interface: + @return: (bool) True if present, False if not or if we can't tell + """ + cmd_check_interface = "ip a" + + success, info = run_cmd(cmd_check_interface) + if success: + if interface in info: + return True + return False + + +def setup_can(interface: str = "can0", is_virtual=False, bitrate=250000, restart_ms=100, txqueue=10000): + """ + Convenience function to setup a can interface + + @param interface: (str) The interface name + @param is_virtual: (bool) If the interface is virtual or not + @param bitrate: (int) The desired bitrate (applies to non-virtual interfaces only) + @param restart_ms: (int) The desired restart_ms (applies to non-virtual interfaces only) + @param txqueue: (int) The desired txqueue length + @return: + """ + cmd_iface_up = "sudo ip link set {0} up type can bitrate {1} restart-ms {2}" \ + .format(interface, bitrate, restart_ms) + cmd_txqueue = "sudo ifconfig {0} txqueuelen {1}".format(interface, txqueue) + + cmd_iface_type_virtual = "sudo ip link add dev {0} type vcan".format(interface) + cmd_iface_up_virtual = "sudo ip link set {0} up".format(interface) + + if is_virtual: + success, info = run_cmd(cmd_iface_type_virtual) + if not success: + print("Warning: Could not set iface type to virtual: {0}".format(info)) + success, info = run_cmd(cmd_iface_up_virtual) + if not success: + print("Warning: Could not bring up virtual interface: {0}".format(info)) + else: + success, info = run_cmd(cmd_iface_up) + if not success: + print("Warning: Could not bring interface up: {0}".format(info)) + + success, info = run_cmd(cmd_txqueue) + if not success: + print("Warning: Could not set txtqueue length: {0}".format(cmd_txqueue)) + + +def create_logger(log_path: str = "/tmp/DialinScript.log", + level: str = "ERROR", + enable_metadata=True, + clear_before_write=False): + """ + Convenience function to create a logger for external Dialin scripts + + @param log_path: (str) The full path to the output log file. + @param level: (str) The logging level (e.g. INFO, WARN, DEBUG, ERROR, CRITICAL) + @param enable_metadata: (bool) if True, include metadata, otherwise, log only the message + @return: (logging.Logger) The logger object + """ + + numeric_level = getattr(logging, level, logging.ERROR) + + current_time = datetime.now() + + # create a new unique logger using current date and time + logger = logging.getLogger("DialinScript{0}{1}{2}".format(current_time.hour, + current_time.minute, + current_time.second)) + logger.setLevel(numeric_level) + + if clear_before_write: + fh = logging.FileHandler(log_path, mode='w') + else: + fh = logging.FileHandler(log_path) + fh.setLevel(numeric_level) + ch = logging.StreamHandler() + ch.setLevel(numeric_level) + if enable_metadata: + formatter = logging.Formatter(fmt=_LogManager.LOG_FMT, + datefmt=_LogManager.LOG_DT_FMT) + else: + formatter = logging.Formatter(fmt=_LogManager.LOG_FMT_NO_METADATA) + fh.setFormatter(formatter) + ch.setFormatter(formatter) + + logger.addHandler(fh) + logger.addHandler(ch) + return logger + + +def find_variables_in_object(obj, value, starts_with: str = ""): + """ + Returns a list of variable names that in the object that match the searched value + + @param obj: (object) The object to search through + @param value: (object) The value to lookup + @param starts_with: (str) The + @return: (List[str]) A list of variable names matching the searched value + """ + result = [] + for attr in dir(obj): + if not callable(getattr(obj, attr)) and attr.startswith(starts_with): + if value == getattr(obj, attr): + result.append(attr) + return result Index: dialin/utils/singleton.py =================================================================== diff -u --- dialin/utils/singleton.py (revision 0) +++ dialin/utils/singleton.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,41 @@ +########################################################################### +# +# 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 base.py +# +# @author (last) Peter Lucia +# @date (last) 28-Apr-2020 +# @author (original) Peter Lucia +# @date (original) 28-Apr-2020 +# +############################################################################ +from threading import Lock + + +class SingletonMeta(type): + """ + Thread-safe implementation of Singleton. + """ + + _instances = {} + + _lock: Lock = Lock() + """ + Synchronizes threads during first access to the Singleton. + """ + + def __call__(cls, *args, **kwargs): + """ + Possible changes to the value of the `__init__` argument do not affect + the returned instance. + """ + # First thread acquires the lock + with cls._lock: + if cls not in cls._instances: + instance = super().__call__(*args, **kwargs) + cls._instances[cls] = instance + return cls._instances[cls] Index: tests/peter/set_RTCs.py =================================================================== diff -u --- tests/peter/set_RTCs.py (revision 0) +++ tests/peter/set_RTCs.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,40 @@ +########################################################################### +# +# 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 set_RTCs.py +# +# @author (last) Sean Nash +# @date (last) 14-Aug-2020 +# @author (original) Sean Nash +# @date (original) 05-Aug-2020 +# +############################################################################ + +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD +from dialin.dg.dialysate_generator import DG +from time import time +from time import localtime + +if __name__ == "__main__": + # create an HD object called hd + hd = HD(log_level="DEBUG") + + if hd.cmd_log_in_to_hd(): + current_time_stamp = time() + current_time = localtime(current_time_stamp) + print(current_time) + + hd.rtc.cmd_set_rtc_time_and_date(current_time.tm_sec, + current_time.tm_min, + current_time.tm_hour, + current_time.tm_mday, + current_time.tm_mon, + current_time.tm_year) + print("Successfully set HD rtc") + #TODO - set DG clock when supported Index: tests/peter/test_blood_flow.py =================================================================== diff -u --- tests/peter/test_blood_flow.py (revision 0) +++ tests/peter/test_blood_flow.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,55 @@ +########################################################################### +# +# 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 test_alarms.py +# +# @author (last) Peter Lucia +# @date (last) 02-Feb-2020 +# @author (original) Peter Lucia +# @date (original) 02-Feb-2020 +# +############################################################################ +import numpy as np +import sys +from time import sleep +sys.path.append("..") +from dialin import HDSimulator +from dialin.protocols.CAN import DenaliMessage, DenaliChannels +from dialin.common import MsgIds +from dialin.utils.conversions import integer_to_bytearray, float_to_bytearray +def run(): + hd_sim = HDSimulator(log_level="DEBUG") + + while True: + target_blood_flow_rate = np.random.randint(-500, 500) + measured_blood_flow_rate = np.random.uniform(-500, 500) + measured_blood_pump_rotor_speed = np.random.uniform(0, 150) + measured_blood_pump_speed = np.random.uniform(0, 3000) + measured_blood_pump_mc_speed = np.random.uniform(0, 3000) + measured_blood_pump_mc_current = np.random.uniform(0, 2000) + pwm_duty_cycle_pct = np.random.uniform(0, 100) + flow_signal_strength = np.random.uniform(0, 100) + + payload = integer_to_bytearray(target_blood_flow_rate) + payload += float_to_bytearray(measured_blood_flow_rate) + payload += float_to_bytearray(measured_blood_pump_rotor_speed) + payload += float_to_bytearray(measured_blood_pump_speed) + payload += float_to_bytearray(measured_blood_pump_mc_speed) + payload += float_to_bytearray(measured_blood_pump_mc_current) + payload += float_to_bytearray(pwm_duty_cycle_pct) + payload += float_to_bytearray(flow_signal_strength) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, + message_id=MsgIds.MSG_ID_BLOOD_FLOW_DATA.value, + payload=payload) + + hd_sim.can_interface.send(message, 0) + sleep(1) + + +if __name__ == '__main__': + run() Index: tests/peter/test_calibration.py =================================================================== diff -u --- tests/peter/test_calibration.py (revision 0) +++ tests/peter/test_calibration.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,222 @@ +import sys +import struct + +from dialin import HD, AbstractObserver + +sys.path.append("../") +from dialin.dg.dialysate_generator import DG +from dialin.utils.nv_ops_utils import NVOpsUtils +from time import sleep + + +def process_calibration_record(read=False): + + cal = dg.calibration_record + print(cal.tmp_record) + + try: + if read: + cal.cmd_request_dg_calibration_record() + while True: + sleep(0.5) + if cal.cal_data != 0: + if cal.is_reading_record_done(): + break + else: + cal.cmd_set_dg_calibration_record() + + print(cal.tmp_record) + + except KeyboardInterrupt: + pass + + +def process_system_record(read=False): + + sys = dg.system_record + print(sys.dg_system_record) + + try: + if read: + sys.get_dg_system_record() + while True: + sleep(0.5) + if sys.is_reading_record_done(): + if sys.is_reading_record_done(): + break + else: + sys.set_dg_system_record() + + print(sys.dg_system_record) + + except KeyboardInterrupt: + pass + + +def process_service_record(read=False): + + sys = dg.service_record + print(sys.dg_service_record) + + try: + if read: + sys.cmd_request_dg_service_record() + while True: + sleep(0.5) + if sys.is_reading_record_done(): + if sys.is_reading_record_done(): + break + else: + sys.set_dg_service_record() + + print(sys.dg_service_record) + + except KeyboardInterrupt: + pass + +def test_crc(): + val = NVOpsUtils.crc_16(b''.join([ + struct.pack(" 1: + delta = self.timestamps[-1] - self.timestamps[-2] + self.deltas.append(delta.microseconds*10**-3) + max_delta = timedelta(seconds = max_publish_rate_after_tolerance*10**(-3)) + print(delta) + assert(delta <= max_delta) + + if self.observations >= self.max_observations: + self.run = False + + +def test_monitor_dg_valve_state_rate_1(): + """ + Test if DG monitors valve states within every 500 ms + """ + dg = DG() + + valves_observer = Observer() + dg.valves.attach(valves_observer) + + while valves_observer.run: + time.sleep(0.010) + + # print("DG Valve State Updates (ms):") + # for ms in valves_observer.deltas: + # print(ms) + + +if __name__ == "__main__": + test_monitor_dg_valve_state_rate_1() Index: tests/peter/test_fw_controller.py =================================================================== diff -u --- tests/peter/test_fw_controller.py (revision 0) +++ tests/peter/test_fw_controller.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,46 @@ +########################################################################### +# +# 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 test_fw_controller.py +# +# @author (last) Peter Lucia +# @date (last) 28-Dec-2020 +# @author (original) Peter Lucia +# @date (original) 28-Dec-2020 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.ui.hd_simulator import HDSimulator +from time import sleep + + +def test_dg_valves(): + hd_simulator = HDSimulator(log_level="DEBUG") + states = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096 + ] + for _ in range(40): + for state in states: + hd_simulator.cmd_set_dg_valves_states(state) + sleep(0.05) + + +if __name__ == '__main__': + test_dg_valves() \ No newline at end of file Index: tests/peter/test_gen_requirements.py =================================================================== diff -u --- tests/peter/test_gen_requirements.py (revision 0) +++ tests/peter/test_gen_requirements.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,149 @@ +########################################################################### +# +# 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 test_gen_requirements.py +# +# @author (last) Peter Lucia +# @date (last) 10-Nov-2020 +# @author (original) Peter Lucia +# @date (original) 09-Jul-2020 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.dg.dialysate_generator import DG +from dialin.hd.hemodialysis_device import HD +from dialin.hd.constants import RESET, NO_RESET, BUTTON_PRESSED, BUTTON_RELEASED +import time +import pprint + + +def test_dg_version(): + """ + Prints the DG version. + + @return: None + """ + dg = DG() + if dg.cmd_log_in_to_dg(): + dg.cmd_ui_request_dg_version() + time.sleep(0.5) + print(dg.dg_version) + + +def gen_publish_requirements(modules): + result = {} + + for module in modules: + for attr in dir(module): + if not callable(getattr(module, attr)) and \ + not attr.startswith("MSG") and \ + not attr.startswith("START") and \ + not attr.startswith("END") and \ + not attr == "can_interface" and \ + not attr.startswith("_") and \ + not attr.isupper(): + result[module.__class__.__name__] = result.get(module.__class__.__name__, []) + [attr] + + # pp = pprint.PrettyPrinter(indent=4) + # pp.pprint(result) + + for module, attrs in result.items(): + print("\n{0} \n ".format(module)) + for attr in attrs: + print("The Dialin API shall publish the {0} to all observers upon HD messaging.".format(attr.replace("_", " "))) + + return result + +def gen_cmd_requirements(modules): + + result = {} + + for module in modules: + for attr in dir(module): + if callable(getattr(module, attr)) and attr.startswith("cmd"): + result[module.__class__.__name__] = result.get(module.__class__.__name__, []) + [attr] + + # pp = pprint.PrettyPrinter(indent=4) + # pp.pprint(result) + + for module, attrs in result.items(): + print("\n{0} \n ".format(module)) + for attr in attrs: + print("The Dialin API shall provide a command that constructs and sends the {0} command.".format(attr + .replace("_", " ") + .replace("cmd ", "") + .replace("uf", "UF") + .replace("ui", "UI") + )) + + return result + + +def generate_hd_requirements(): + """ + Generates requires for the HD + + @return: None + """ + hd = HD() + + modules = [ + hd.alarms, + hd.buttons, + hd.ui, + hd.rtc, + hd.watchdog, + hd.bloodflow, + hd.dialysate_inlet_flow, + hd.dialysate_outlet_flow, + hd.treatment, + hd.pressure_occlusion, + hd.valves, + hd.air_trap, + hd.accel + ] + gen_publish_requirements(modules) + gen_cmd_requirements(modules) + + +def generate_dg_requirements(): + """ + Generates requires for the DG + + @return: None + """ + + dg = DG() + + modules = [ + # hd.hd_proxy, + # hd.load_cells, + # hd.pressures, + # hd.reservoirs, + # hd.valves, + # hd.ro_pump, + # hd.drain_pump, + # hd.heaters, + # hd.temperature_sensors, + # hd.conductivity_sensors, + # hd.accel, + dg.alarms, + dg.concentrate_pumps, + dg.fans, + dg.heat_disinfect, + dg.thermistors, + dg.uv_reactors, + ] + + gen_publish_requirements(modules) + gen_cmd_requirements(modules) + + +if __name__ == '__main__': + generate_dg_requirements() + # generate_hd_requirements() Index: tests/peter/test_hd_dg_simulators.py =================================================================== diff -u --- tests/peter/test_hd_dg_simulators.py (revision 0) +++ tests/peter/test_hd_dg_simulators.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,39 @@ +########################################################################### +# +# 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 test_saline_bolus.py +# +# @author (last) Peter Lucia +# @date (last) 15-Mar-2021 +# @author (original) Peter Lucia +# @date (original) 15-Mar-2021 +# +############################################################################ +import sys +from time import sleep + +sys.path.append("..") +from dialin import HDSimulator, DGSimulator, AbstractObserver + + +class Observer(AbstractObserver): + + def update(self, result): + print(result) + + +hd_sim = HDSimulator(log_level="DEBUG") +dg_sim = DGSimulator(log_level="DEBUG") +observer = Observer() + +hd_sim.attach(observer) +dg_sim.attach(observer) + +while True: + sleep(1) + + Index: tests/peter/test_hd_reset.py =================================================================== diff -u --- tests/peter/test_hd_reset.py (revision 0) +++ tests/peter/test_hd_reset.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,31 @@ +########################################################################### +# +# 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 test_logging.py +# +# @author (last) Peter Lucia +# @date (last) 05-Jan-2021 +# @author (original) Peter Lucia +# @date (original) 05-Jan-2021 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.hd.hemodialysis_device import HD + +def test_reset(): + """ + Resets the HD + + @return: None + """ + hd = HD(log_level="DEBUG") + hd.cmd_log_in_to_hd() + hd.cmd_hd_software_reset_request() + +if __name__ == '__main__': + test_reset() Index: tests/peter/test_hd_simulator.py =================================================================== diff -u --- tests/peter/test_hd_simulator.py (revision 0) +++ tests/peter/test_hd_simulator.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,150 @@ +########################################################################### +# +# 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 test_hd_simulator.py +# +# @author (last) Peter Lucia +# @date (last) 28-Sep-2020 +# @author (original) Peter Lucia +# @date (original) 06-Aug-2020 +# +############################################################################ +import sys +sys.path.append("..") + +from dialin.ui.hd_simulator import HDSimulator, RequestRejectReasons +from dialin.hd.hemodialysis_device import HD +from dialin.utils.base import AbstractObserver +from time import sleep + + +def test_invalid_parameters(): + hd_simulator = HDSimulator(log_level="DEBUG") + + rejections = [ + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # overall response + RequestRejectReasons.REQUEST_REJECT_REASON_BLOOD_FLOW_OUT_OF_RANGE, # blood flow + RequestRejectReasons.REQUEST_REJECT_REASON_DIAL_FLOW_OUT_OF_RANGE, # dialysate flow + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # duration + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # heparin dispensing rate + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # heparin bolus volume + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # heparin stop time + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # saline bolus + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # acid concentrate + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # bicarbonate concentrate + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # dialyzer type + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # dialysate temperature + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # arterial pressure limit low + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # arterial pressure limit high + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # venous pressure limit low + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # venous pressure limit high + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE, # blood pressure measurement interval + RequestRejectReasons.REQUEST_REJECT_REASON_NOT_IN_TREATMENT_MODE # rinseback flow rate + ] + hd_simulator.cmd_send_treatment_parameter_validation_response(rejections) + + +class Observer(AbstractObserver): + def __init__(self): + self.timeout_expired = False + + def update(self, result): + print(result) + self.timeout_expired = result.get("poweroff_timeout_expired", False) + + +def test_poweroff(): + hd = HD() + + observer = Observer() + hd.buttons.attach(observer) + + hd_simulator = HDSimulator(log_level="DEBUG") + hd_simulator.cmd_send_poweroff_button_pressed() + sleep(1) + hd_simulator.cmd_send_poweroff_timeout() + sleep(1) + hd_simulator.cmd_send_broadcast_poweroff_imminent() + + while not observer.timeout_expired: + sleep(1) + + +def test_valid_parameters(): + hd_simulator = HDSimulator(log_level="DEBUG") + + rejections = [ + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # requestValid + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # bloodFlowRate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # dialysateFlowRate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # duration + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # heparinStopTime + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # salineBolus + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # acidConcentrate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # bicarbonateConcentrate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # dialyzerType + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # bloodPressureMeasureInterval + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # rinsebackFlowRate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # arterialPressureLimitLow + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # arterialPressureLimitHigh + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # venousPressureLimitLow + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # venousPressureLimitHigh + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # heparinDispensingRate + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # heparinBolusVolume + RequestRejectReasons.REQUEST_REJECT_REASON_NONE, # dialysateTemp + ] + hd_simulator.cmd_send_treatment_parameter_validation_response(rejections) + + +def test_invalid_parameters(): + hd_simulator = HDSimulator(log_level="DEBUG") + + param_count = 18 + + for i in range(param_count): + rejections = [0 for _ in range(param_count)] + rejections[i] = 1 + hd_simulator.cmd_send_treatment_parameter_manual_validation_response(rejections) + sleep(2) + + +def test_priming(): + hd_simulator = HDSimulator(log_level="DEBUG") + state = 0 + total_seconds = 100 + for seconds_remaining in range(total_seconds, -1, -1): + if seconds_remaining % (total_seconds // 3) == 0: + state += 1 + hd_simulator.cmd_send_priming_time_remaining(state, seconds_remaining, total_seconds) + sleep(0.05) + + +class StartTreatmentObserver(AbstractObserver): + def __init__(self): + self.received_response = False + + def update(self, result): + print(result) + self.received_response = True + + +def test_start_confirm_end_treatment(): + hd_simulator = HDSimulator(log_level="DEBUG") + hd_simulator.alarms_simulator.cmd_send_clear_alarms() + observer = StartTreatmentObserver() + hd_simulator.attach(observer) + + while not observer.received_response: + sleep(0.50) + + +if __name__ == '__main__': + test_start_confirm_end_treatment() + + + + Index: tests/peter/test_logging.py =================================================================== diff -u --- tests/peter/test_logging.py (revision 0) +++ tests/peter/test_logging.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,66 @@ +########################################################################### +# +# 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 test_logging.py +# +# @author (last) Peter Lucia +# @date (last) 27-Jul-2020 +# @author (original) Peter Lucia +# @date (original) 24-Jul-2020 +# +############################################################################ +import sys +import subprocess +sys.path.append("..") +from dialin.dg.dialysate_generator import DG +from dialin.hd.hemodialysis_device import HD +from dialin.utils.base import create_logger +import time +import logging +from logging import Logger + +def test_logging(): + """ + Prints the DG version. + + @return: None + """ + if False: + # hd = DG(log_level="INFO") + dg = DG() + if dg.cmd_log_in_to_dg(): + dg.cmd_ui_request_dg_version() + time.sleep(0.5) + print(dg.dg_version) + if True: + # hd = HD(log_level="CAN_ONLY") + hd = HD(log_level="CAN_ONLY") + if hd.cmd_log_in_to_hd(): + hd.ui.cmd_ui_request_hd_version() + + +class HDDevice(HD): + def __init__(self): + super().__init__() + self.vvlogger = create_logger("vvlogger.log", "NOT_SET", enable_metadata=False, clear_before_write=True) + self.vvlogger.debug("VVLOGGER: INITIALIZE") + self.logger.debug("TESTING123") + self.vvlogger.getEffectiveLevel() + + +def test_create_logger(): + subprocess.call("rm *.log", shell=True) + hd = HDDevice() + print(hd.vvlogger.getEffectiveLevel()) + hd.vvlogger.debug("VVLOGGER: TEST 1 (BEFORE DIALIN logger.debug() calls)") + hd.test_debug() + hd.vvlogger.debug("VVLOGGER: TEST 2 (AFTER DIALIN logger.debug() calls)") + # observe that no dialin logger.debug() messages appear in vvlogger.log + # and no dialin logger.debug() messages appear in the pycharm console (same behavior when running from terminal). + +if __name__ == '__main__': + test_create_logger() Index: tests/peter/test_print_version.py =================================================================== diff -u --- tests/peter/test_print_version.py (revision 0) +++ tests/peter/test_print_version.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,20 @@ +########################################################################### +# +# 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 test_print_version.py +# +# @author (last) Peter Lucia +# @date (last) 20-Aug-2020 +# @author (original) Peter Lucia +# @date (original) 20-Aug-2020 +# +############################################################################ +import sys +sys.path.append("..") + +import dialin +print(dialin.__version__) \ No newline at end of file Index: tests/peter/test_single_alarm.py =================================================================== diff -u --- tests/peter/test_single_alarm.py (revision 0) +++ tests/peter/test_single_alarm.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,45 @@ +########################################################################### +# +# 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 test_single_alarm.py +# +# @author (last) Peter Lucia +# @date (last) 28-Dec-2020 +# @author (original) Peter Lucia +# @date (original) 28-Dec-2020 +# +############################################################################ +import sys +sys.path.append("..") +from dialin.ui.hd_simulator import HDSimulator +from dialin.ui.hd_simulator_alarms import Alarms +from time import sleep + +hd_simulator = HDSimulator(log_level="DEBUG") +flags = hd_simulator.alarms_simulator.cmd_make_alarm_flags( + no_clear=1, + no_resume=1, + no_rinseback=1, + no_end_treatment=1, + no_new_treatment=1, + user_must_ack=1) +alarm = Alarms.ALARM_ID_ARTERIAL_PRESSURE_HIGH +state = alarm[0] +alarm_id = alarm[1] +escalates_in = alarm[2] +silence_expires = 10 +hd_simulator.alarms_simulator.flags = flags + +# simulate HD broadcasting an alarm every second +for silence_expires in range(10, -1, -1): + + hd_simulator.alarms_simulator.cmd_activate_alarm_id(state, + alarm_id, + escalates_in, + silence_expires, + hd_simulator.alarms_simulator.flags) + sleep(1) Index: tests/peter/test_temperature_sensors.py =================================================================== diff -u --- tests/peter/test_temperature_sensors.py (revision 0) +++ tests/peter/test_temperature_sensors.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,42 @@ +########################################################################### +# +# 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 test_alarms.py +# +# @author (last) Peter Lucia +# @date (last) 02-Feb-2020 +# @author (original) Peter Lucia +# @date (original) 02-Feb-2020 +# +############################################################################ +import numpy as np +import sys +from time import sleep +sys.path.append("..") +from dialin import HDSimulator +from dialin.protocols.CAN import DenaliMessage, DenaliChannels +from dialin.common import MsgIds +from dialin.utils.conversions import integer_to_bytearray, float_to_bytearray +def run(): + hd_sim = HDSimulator(log_level="DEBUG") + + while True: + vals = [np.random.uniform(0, 100) for _ in range(18)] + payload = bytearray() + for val in vals: + payload += float_to_bytearray(val) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dg_sync_broadcast_ch_id, + message_id=MsgIds.MSG_ID_DG_TEMPERATURE_DATA.value, + payload=payload) + + hd_sim.can_interface.send(message, 0) + sleep(1) + + +if __name__ == '__main__': + run() Index: tests/peter/test_ui_proxy.py =================================================================== diff -u --- tests/peter/test_ui_proxy.py (revision 0) +++ tests/peter/test_ui_proxy.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,71 @@ +########################################################################### +# +# 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 test_ui_proxy.py +# +# @author (last) Peter Lucia +# @date (last) 21-Aug-2020 +# @author (original) Peter Lucia +# @date (original) 21-Aug-2020 +# +############################################################################ +import sys +sys.path.append("../..") +from dialin.hd.hemodialysis_device import HD +from time import sleep +from dialin.utils.base import AbstractObserver + +IP_ADDRESS = "192.168.10.77" + +class Observer(AbstractObserver): + def __init__(self): + self.valid = False + + def update(self, message): + print(message) + self.valid = message.get("treatment_parameters_valid", False) + +def test_create_treatment(): + hd = HD(log_level="DEBUG") + hd.cmd_hd_software_reset_request() + observer = Observer() + hd.ui.attach(observer) + sleep(1) + if hd.cmd_log_in_to_hd(): + sleep(10) + print("Logged in") + hd.ui.cmd_ui_start_treatment_request(0) + sleep(4) + hd.ui.cmd_set_treatment_parameters(100, 100, 120, 0, 0, 0, 100, 1, 0, 1, 36, -200, -170, -100, 100, 30, 75) + while not observer.valid: + sleep(0.1) + hd.ui.cmd_ui_confirm_treatment_parameters() + sleep(4) + hd.ui.cmd_ui_start_treatment_request(2) + sleep(4) + +def test_reset_hd(): + hd = HD(log_level="DEBUG") + hd.cmd_hd_software_reset_request() + +def test_get_hd_operation_mode(): + hd = HD(log_level="DEBUG") + observer = Observer() + hd.ui.attach(observer) + if hd.cmd_log_in_to_hd(): + sleep(5) + print(hd.get_operation_mode()) + +def test_clear_all_alarms(): + hd = HD(log_level="DEBUG") + hd.alarms.cmd_clear_all_alarms() + +if __name__ == '__main__': + # test_reset_hd() + # test_create_treatment() + test_clear_all_alarms() + # test_get_hd_operation_mode() Index: tests/peter/test_valves.py =================================================================== diff -u --- tests/peter/test_valves.py (revision 0) +++ tests/peter/test_valves.py (revision bfb0c47181dc8a73d09825ab697a7799dd520417) @@ -0,0 +1,61 @@ +########################################################################### +# +# 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 test_alarms.py +# +# @author (last) Peter Lucia +# @date (last) 02-Feb-2020 +# @author (original) Peter Lucia +# @date (original) 02-Feb-2020 +# +############################################################################ +import numpy as np +import sys +from time import sleep +sys.path.append("..") +from dialin import HDSimulator +from dialin.protocols.CAN import DenaliMessage, DenaliChannels +from dialin.common import MsgIds +from dialin.utils.conversions import integer_to_bytearray, float_to_bytearray +def run(): + hd_sim = HDSimulator(log_level="DEBUG") + + while True: + vlv_id = np.random.randint(0, 5) + state_id = np.random.randint(0, 1) + pos_id = np.random.randint(0, 1) + pos_cnt = np.random.randint(0, 1) + next_pos = np.random.randint(0, 1) + current = np.random.uniform(0, 250) + pos_c = np.random.randint(0, 100) + pos_a = np.random.randint(0, 100) + pos_b = np.random.randint(0, 100) + pwm = np.random.randint(0, 100) + air_trap = np.random.randint(0, 100) + + payload = integer_to_bytearray(vlv_id) + payload += integer_to_bytearray(state_id) + payload += integer_to_bytearray(pos_id) + payload += integer_to_bytearray(pos_cnt) + payload += integer_to_bytearray(next_pos) + payload += float_to_bytearray(current) + payload += integer_to_bytearray(pos_c) + payload += integer_to_bytearray(pos_a) + payload += integer_to_bytearray(pos_b) + payload += integer_to_bytearray(pwm) + payload += integer_to_bytearray(air_trap) + + message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_sync_broadcast_ch_id, + message_id=MsgIds.MSG_ID_HD_VALVES_DATA.value, + payload=payload) + + hd_sim.can_interface.send(message, 0) + sleep(1) + + +if __name__ == '__main__': + run() Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/set_RTCs.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_blood_flow.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_calibration.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_can.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_can_protocol.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_debug_text.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_demo.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_dg_valves_observer.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_fw_controller.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_gen_requirements.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_hd_dg_simulators.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_hd_reset.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_hd_simulator.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_logging.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_print_version.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_single_alarm.py'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag bfb0c47181dc8a73d09825ab697a7799dd520417 refers to a dead (removed) revision in file `tests/test_ui_proxy.py'. Fisheye: No comparison available. Pass `N' to diff?