Index: dialin/common/msg_defs.py =================================================================== diff -u -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/common/msg_defs.py (.../msg_defs.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) +++ dialin/common/msg_defs.py (.../msg_defs.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -14,7 +14,6 @@ # ############################################################################ from enum import unique -from ..protocols.CAN import DenaliMessage from ..utils.base import DialinEnum @unique @@ -247,7 +246,7 @@ class MsgFieldPositions: # Generic response msg field byte positions (where 32-bit data fields are used) - START_POS_FIELD_1 = DenaliMessage.PAYLOAD_START_INDEX + START_POS_FIELD_1 = 6 # Hardcoded for now to avoid cyclic import issue. See protocols.CAN.DenaliMessage class END_POS_FIELD_1 = START_POS_FIELD_1 + 4 START_POS_FIELD_2 = END_POS_FIELD_1 END_POS_FIELD_2 = START_POS_FIELD_2 + 4 @@ -287,3 +286,8 @@ END_POS_FIELD_19 = START_POS_FIELD_19 + 4 START_POS_FIELD_20 = END_POS_FIELD_19 END_POS_FIELD_20 = START_POS_FIELD_20 + 4 + + +ACK_NOT_REQUIRED = [ + MsgIds.MSG_ID_ALARM_CONDITION_CLEARED.value +] Index: dialin/protocols/CAN.py =================================================================== diff -u -r4e09b977d0165c359f66307e45db83b0a7e8e9c9 -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/protocols/CAN.py (.../CAN.py) (revision 4e09b977d0165c359f66307e45db83b0a7e8e9c9) +++ dialin/protocols/CAN.py (.../CAN.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -20,6 +20,8 @@ from time import sleep import sys from logging import Logger +import struct +from .. import common class DenaliMessage: @@ -55,6 +57,8 @@ 130, 179, 224, 209, 70, 119, 36, 21, 59, 10, 89, 104, 255, 206, 157, 172 ] + _seq_num = 1 + @staticmethod def build_basic_message(channel_id=0, message=None): """ @@ -68,14 +72,15 @@ message = [] return {'channel_id': channel_id, 'message': message} - @staticmethod - def build_message(channel_id=0, message_id=0, payload=None, seq=None): + @classmethod + def build_message(cls, channel_id=0, message_id=0, payload=None, seq=None): """ Builds a Denali message @param channel_id: (int) indicates the channel @param message_id: (int) indicating the request type @param payload: (list) contains the payload + @param seq: (int) Overrides current sequence number if set @return:: dictionary with channel_id and 8-byte padded message """ @@ -85,13 +90,18 @@ message_list = [DenaliCanMessenger.START_BYTE] if 0 <= message_id <= DenaliMessage.MAX_MSG_ID_NUMBER: - # Add a zero seq # for dialin messages for now - if seq is not None: - seq_no = seq - else: - seq_no = 0 - message_seq_in_bytes = seq_no.to_bytes(2, byteorder=DenaliMessage.BYTE_ORDER) + if seq is None: + # Wrap sequence number if it hits a max int16 + if cls._seq_num >= 32767: + cls._seq_num = 1 + seq = cls._seq_num + + if message_id not in common.msg_defs.ACK_NOT_REQUIRED: + seq *= -1 + + message_seq_in_bytes = seq.to_bytes(2, byteorder=DenaliMessage.BYTE_ORDER, signed=True) + message_list += [message_seq_in_bytes[0]] message_list += [message_seq_in_bytes[1]] @@ -101,6 +111,8 @@ message_list += [message_id_in_bytes[0]] message_list += [message_id_in_bytes[1]] + cls._seq_num += 1 + else: return [] @@ -206,6 +218,53 @@ return message['channel_id'] @staticmethod + def get_sequence_number(message): + """ + Returns sequence number from the message + + @param message: dictionary containing the message + @return:: (int) the sequence number + """ + seq = message['message'][DenaliMessage.MSG_SEQ_INDEX:DenaliMessage.MSG_ID_INDEX] + return int.from_bytes(seq, byteorder=DenaliMessage.BYTE_ORDER, signed=True) + + @staticmethod + def create_ack_message(message): + """ + 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 + @return: (dict) ACK message for the input message + """ + message = message.copy() + + seq = struct.unpack('h', bytearray( + message['message'][DenaliMessage.MSG_SEQ_INDEX:DenaliMessage.MSG_ID_INDEX]))[0] + + # send back empty payload since this is an ACK + 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 + + elif channel_id_rx == DenaliChannels.hd_to_dialin_ch_id: + channel_id_tx = DenaliChannels.dialin_to_hd_ch_id + + elif channel_id_rx == DenaliChannels.ui_to_dialin_ch_id: + channel_id_tx = DenaliChannels.dialin_to_ui_ch_id + + message = DenaliMessage.build_message(channel_id=channel_id_tx, + message_id=common.msg_defs.MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, + payload=payload, + seq=-seq) + + return message + + @staticmethod def get_message_id(message): """ Returns request ID from packet @@ -473,6 +532,11 @@ DenaliMessage.crc8(self.messages))) if message_valid: + # 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) + # 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: dialin/protocols/__init__.py =================================================================== diff -u -rb543d90a50cbef509d10f4c1412d87bf6eee2e4e -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/protocols/__init__.py (.../__init__.py) (revision b543d90a50cbef509d10f4c1412d87bf6eee2e4e) +++ dialin/protocols/__init__.py (.../__init__.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -1,4 +1,4 @@ from .CAN import DenaliCanMessenger from .CAN import DenaliChannels from .CAN import LongDenaliMessageBuilder -from .CAN import DenaliMessage +from .CAN import DenaliMessage \ No newline at end of file Index: dialin/ui/hd_simulator.py =================================================================== diff -u -rf7cd7cb24f34bc40f718ecd8824c600ee1565134 -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision f7cd7cb24f34bc40f718ecd8824c600ee1565134) +++ dialin/ui/hd_simulator.py (.../hd_simulator.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -335,11 +335,12 @@ self.logger.debug("Priming ...") state = 0 total_seconds = 100 - for seconds_remaining in range(total_seconds, -1, -1): - if seconds_remaining % (total_seconds // 3) == 0: - state += 1 - self.cmd_send_priming_time_remaining(state, seconds_remaining, total_seconds) - sleep(0.05) + # for seconds_remaining in range(total_seconds, -1, -1): + # if seconds_remaining % (total_seconds // 3) == 0: + # state += 1 + self.cmd_send_priming_time_remaining(state, 30, total_seconds) + sleep(1) + self.cmd_send_priming_time_remaining(state, 0, total_seconds) self.logger.debug("Finished priming.") def _handler_ui_pre_treatment_uf_request(self, message): @@ -355,31 +356,10 @@ uf_volume = struct.unpack('f', bytearray( message['message'][START_POS:END_POS]))[0] - print("Received UF Volume: {0} mL".format(uf_volume)) + self.logger.debug("Received UF Volume: {0} mL".format(uf_volume)) - self.cmd_send_acknowledge(message) self.cmd_send_uf_treatment_response(1, 0, uf_volume) - def cmd_send_acknowledge(self, message: dict): - """ - Sends a generic acknowledge - - @param message: (dict) The message that was sent we need to ACK - @return: None - """ - seq = struct.unpack('h', bytearray( - message['message'][DenaliMessage.MSG_SEQ_INDEX:DenaliMessage.MSG_ID_INDEX]))[0] - - # send back empty payload since this is an ACK - payload = bytearray() - - message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_to_ui_ch_id, - message_id=MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, - payload=payload, - seq=-seq) - - self.can_interface.send(message, 0) - def _handler_ui_start_treatment(self, message): """ Handler function to start a treatment Index: dialin/ui/hd_simulator_alarms.py =================================================================== diff -u -rb2598badc6854e9e78a551a09120c88227bc0059 -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision b2598badc6854e9e78a551a09120c88227bc0059) +++ dialin/ui/hd_simulator_alarms.py (.../hd_simulator_alarms.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -416,21 +416,3 @@ if self.clear_after_user_action: self.cmd_send_clear_alarms() - def cmd_send_acknowledge(self, message: dict): - """ - Sends a generic acknowledge - - @param message: (dict) The message that was sent we need to ACK - @return: None - """ - seq = struct.unpack('h', bytearray( - message['message'][DenaliMessage.MSG_SEQ_INDEX:DenaliMessage.MSG_ID_INDEX]))[0] - - # send back empty payload since this is an ACK - payload = bytearray() - - message = DenaliMessage.build_message(channel_id=DenaliChannels.hd_to_ui_ch_id, - message_id=MsgIds.MSG_ID_ACK_MESSAGE_THAT_REQUIRES_ACK.value, - payload=payload, - seq=-seq) - self.can_interface.send(message, 0) Index: dialin/utils/__init__.py =================================================================== diff -u -r8c39fe1f9affe360ee6a97c5e6243e58a5c27509 -r703231f83070516744deb638547eda07aa9d02a7 --- dialin/utils/__init__.py (.../__init__.py) (revision 8c39fe1f9affe360ee6a97c5e6243e58a5c27509) +++ dialin/utils/__init__.py (.../__init__.py) (revision 703231f83070516744deb638547eda07aa9d02a7) @@ -1 +1 @@ +from .base import DialinEnum \ No newline at end of file