Index: dialin/hd/hemodialysis_device.py =================================================================== diff -u -r4e09b977d0165c359f66307e45db83b0a7e8e9c9 -ra7d070474341dfa2f6012fc0acb000e14f413979 --- dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision 4e09b977d0165c359f66307e45db83b0a7e8e9c9) +++ dialin/hd/hemodialysis_device.py (.../hemodialysis_device.py) (revision a7d070474341dfa2f6012fc0acb000e14f413979) @@ -204,7 +204,7 @@ self.logger.debug("Logging in...") # Send message - received_message = self.can_interface.send(message, resend=True) + received_message = self.can_interface.send(message) if received_message is not None: if received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] == 1: Index: dialin/protocols/CAN.py =================================================================== diff -u -r703231f83070516744deb638547eda07aa9d02a7 -ra7d070474341dfa2f6012fc0acb000e14f413979 --- dialin/protocols/CAN.py (.../CAN.py) (revision 703231f83070516744deb638547eda07aa9d02a7) +++ dialin/protocols/CAN.py (.../CAN.py) (revision a7d070474341dfa2f6012fc0acb000e14f413979) @@ -229,11 +229,12 @@ return int.from_bytes(seq, byteorder=DenaliMessage.BYTE_ORDER, signed=True) @staticmethod - def create_ack_message(message): + def create_ack_message(message: dict, passive_mode: bool=False): """ Negates the sequence number and replaces the original message's sequence number with the negated sequence number to create the ACK message. @param message: (dict) a complete dialin message + @param passive_mode: (dict) true if in passive mode, false otherwise @return: (dict) ACK message for the input message """ message = message.copy() @@ -245,17 +246,46 @@ payload = bytearray() channel_id_rx = DenaliMessage.get_channel_id(message) - if channel_id_rx == DenaliChannels.ui_to_hd_ch_id: - channel_id_tx = DenaliChannels.hd_to_ui_ch_id - elif channel_id_rx == DenaliChannels.hd_to_ui_ch_id: - channel_id_tx = DenaliChannels.ui_to_hd_ch_id + if passive_mode: + channel_rx_tx_pairs = { + DenaliChannels.hd_alarm_broadcast_ch_id : None, + DenaliChannels.dg_alarm_broadcast_ch_id : None, + DenaliChannels.ui_alarm_broadcast_ch_id : None, + DenaliChannels.hd_to_dg_ch_id : None, + DenaliChannels.dg_to_hd_ch_id : None, + DenaliChannels.hd_to_ui_ch_id : None, + DenaliChannels.hd_sync_broadcast_ch_id : None, + DenaliChannels.dg_to_ui_ch_id : None, + DenaliChannels.dg_sync_broadcast_ch_id : None, + DenaliChannels.ui_to_hd_ch_id : None, + DenaliChannels.ui_sync_broadcast_ch_id : None, + DenaliChannels.hd_to_dialin_ch_id : DenaliChannels.dialin_to_hd_ch_id, + DenaliChannels.dg_to_dialin_ch_id : DenaliChannels.dialin_to_dg_ch_id, + DenaliChannels.ui_to_dialin_ch_id : DenaliChannels.dialin_to_ui_ch_id + } + else: + channel_rx_tx_pairs = { + DenaliChannels.hd_alarm_broadcast_ch_id : None, + DenaliChannels.dg_alarm_broadcast_ch_id : None, + DenaliChannels.ui_alarm_broadcast_ch_id : None, + DenaliChannels.hd_to_dg_ch_id : DenaliChannels.dialin_to_hd_ch_id, + DenaliChannels.dg_to_hd_ch_id : DenaliChannels.dialin_to_dg_ch_id, + DenaliChannels.hd_to_ui_ch_id : DenaliChannels.dialin_to_hd_ch_id, + DenaliChannels.hd_sync_broadcast_ch_id : None, + DenaliChannels.dg_to_ui_ch_id : DenaliChannels.dialin_to_dg_ch_id, + DenaliChannels.dg_sync_broadcast_ch_id : None, + DenaliChannels.ui_to_hd_ch_id : DenaliChannels.dialin_to_ui_ch_id, + DenaliChannels.ui_sync_broadcast_ch_id : None, + DenaliChannels.hd_to_dialin_ch_id : DenaliChannels.dialin_to_hd_ch_id, + DenaliChannels.dg_to_dialin_ch_id : DenaliChannels.dialin_to_dg_ch_id, + DenaliChannels.ui_to_dialin_ch_id : DenaliChannels.dialin_to_ui_ch_id + } - elif channel_id_rx == DenaliChannels.hd_to_dialin_ch_id: - channel_id_tx = DenaliChannels.dialin_to_hd_ch_id + channel_id_tx = channel_rx_tx_pairs.get(channel_id_rx, None) - elif channel_id_rx == DenaliChannels.ui_to_dialin_ch_id: - channel_id_tx = DenaliChannels.dialin_to_ui_ch_id + if channel_id_tx is None: + return None message = DenaliMessage.build_message(channel_id=channel_id_tx, message_id=common.msg_defs.MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, @@ -402,7 +432,7 @@ START_BYTE = DenaliMessage.START_BYTE DIALIN_MSG_RESP_TO = 0.1 # number of seconds to wait for a response to a sent command - def __init__(self, can_interface: str, logger: Logger, log_can=False): + def __init__(self, can_interface: str, logger: Logger, log_can=False, passive_mode=False): """ DenaliCanMessenger constructor @@ -415,6 +445,7 @@ self.bus = can.interfaces.socketcan.SocketcanBus(channel=can_interface) self.logger = logger self.log_can = log_can + self.passive_mode = passive_mode self.listener_buffer = can.BufferedReader() self.notifier = can.Notifier(self.bus, [self.listener_buffer]) self.send_packet_request_id = -1 @@ -535,7 +566,10 @@ # Send an ack if required if DenaliMessage.get_sequence_number(complete_dialin_message) < 0: # ACK required. Send back the received message with the sequence sign bit flipped - self.send(DenaliMessage.create_ack_message(complete_dialin_message), 0) + msg = DenaliMessage.create_ack_message(message=complete_dialin_message, + passive_mode=self.passive_mode) + if msg is not None: + self.send(msg, 0) # We first check if this is a response to a send request that is pending if dialin_msg_id == self.send_packet_request_id: Index: tests/test_blood_flow.py =================================================================== diff -u --- tests/test_blood_flow.py (revision 0) +++ tests/test_blood_flow.py (revision a7d070474341dfa2f6012fc0acb000e14f413979) @@ -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/test_fw_controller.py =================================================================== diff -u --- tests/test_fw_controller.py (revision 0) +++ tests/test_fw_controller.py (revision a7d070474341dfa2f6012fc0acb000e14f413979) @@ -0,0 +1,69 @@ +########################################################################### +# +# 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) + + +def test_dg_pumps(): + 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(1) + + +if __name__ == '__main__': + test_dg_valves() \ No newline at end of file