diff --git a/can/interfaces/ics_neovi/neovi_bus.py b/can/interfaces/ics_neovi/neovi_bus.py index df4f5481f..30c9dd8c9 100644 --- a/can/interfaces/ics_neovi/neovi_bus.py +++ b/can/interfaces/ics_neovi/neovi_bus.py @@ -306,6 +306,7 @@ def _ics_msg_to_message(self, ics_msg): dlc=ics_msg.NumberBytesData, is_extended_id=bool(ics_msg.StatusBitField & ics.SPY_STATUS_XTD_FRAME), is_fd=is_fd, + is_rx=not bool(ics_msg.StatusBitField & ics.SPY_STATUS_TX_MSG), is_remote_frame=bool( ics_msg.StatusBitField & ics.SPY_STATUS_REMOTE_FRAME ), @@ -325,6 +326,7 @@ def _ics_msg_to_message(self, ics_msg): dlc=ics_msg.NumberBytesData, is_extended_id=bool(ics_msg.StatusBitField & ics.SPY_STATUS_XTD_FRAME), is_fd=is_fd, + is_rx=not bool(ics_msg.StatusBitField & ics.SPY_STATUS_TX_MSG), is_remote_frame=bool( ics_msg.StatusBitField & ics.SPY_STATUS_REMOTE_FRAME ), diff --git a/can/io/asc.py b/can/io/asc.py index 709230389..c8a2aada3 100644 --- a/can/io/asc.py +++ b/can/io/asc.py @@ -71,13 +71,15 @@ def __iter__(self): if not temp or not temp[0].isdigit(): continue is_fd = False + is_rx = True try: timestamp, channel, dummy = temp.split( None, 2 ) # , frameType, dlc, frameData if channel == "CANFD": - timestamp, _, channel, _, dummy = temp.split(None, 4) + timestamp, _, channel, direction, dummy = temp.split(None, 4) is_fd = True + is_rx = direction == "Rx" except ValueError: # we parsed an empty comment continue @@ -97,13 +99,14 @@ def __iter__(self): ): pass elif dummy[-1:].lower() == "r": - can_id_str, _ = dummy.split(None, 1) + can_id_str, direction, _ = dummy.split(None, 2) can_id_num, is_extended_id = self._extract_can_id(can_id_str, base) msg = Message( timestamp=timestamp, arbitration_id=can_id_num & CAN_ID_MASK, is_extended_id=is_extended_id, is_remote_frame=True, + is_rx=direction == "Rx", channel=channel, ) yield msg @@ -114,7 +117,8 @@ def __iter__(self): try: # this only works if dlc > 0 and thus data is available if not is_fd: - can_id_str, _, _, dlc, data = dummy.split(None, 4) + can_id_str, direction, _, dlc, data = dummy.split(None, 4) + is_rx = direction == "Rx" else: can_id_str, frame_name, brs, esi, dlc, data_length, data = dummy.split( None, 6 @@ -148,6 +152,7 @@ def __iter__(self): dlc=dlc, data=frame, is_fd=is_fd, + is_rx=is_rx, channel=channel, bitrate_switch=is_fd and brs == "1", error_state_indicator=is_fd and esi == "1", @@ -164,7 +169,7 @@ class ASCWriter(BaseIOHandler, Listener): It the first message does not have a timestamp, it is set to zero. """ - FORMAT_MESSAGE = "{channel} {id:<15} Rx {dtype} {data}" + FORMAT_MESSAGE = "{channel} {id:<15} {dir:<4} {dtype} {data}" FORMAT_MESSAGE_FD = " ".join( [ "CANFD", @@ -276,7 +281,7 @@ def on_message_received(self, msg): serialized = self.FORMAT_MESSAGE_FD.format( channel=channel, id=arb_id, - dir="Rx", + dir="Rx" if msg.is_rx else "Tx", symbolic_name="", brs=1 if msg.bitrate_switch else 0, esi=1 if msg.error_state_indicator else 0, @@ -294,6 +299,10 @@ def on_message_received(self, msg): ) else: serialized = self.FORMAT_MESSAGE.format( - channel=channel, id=arb_id, dtype=dtype, data=" ".join(data) + channel=channel, + id=arb_id, + dir="Rx" if msg.is_rx else "Tx", + dtype=dtype, + data=" ".join(data), ) self.log_event(serialized, msg.timestamp) diff --git a/can/io/blf.py b/can/io/blf.py index 8ac79ddb8..ca0b5bd38 100644 --- a/can/io/blf.py +++ b/can/io/blf.py @@ -91,6 +91,7 @@ class BLFParseError(Exception): EDL = 0x1 BRS = 0x2 ESI = 0x4 +DIR = 0x1 TIME_TEN_MICS = 0x00000001 TIME_ONE_NANS = 0x00000002 @@ -258,6 +259,7 @@ def _parse_data(self, data): arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), + is_rx=not bool(flags & DIR), dlc=dlc, data=can_data[:dlc], channel=channel - 1, @@ -288,6 +290,7 @@ def _parse_data(self, data): is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), is_fd=bool(fd_flags & 0x1), + is_rx=not bool(flags & DIR), bitrate_switch=bool(fd_flags & 0x2), error_state_indicator=bool(fd_flags & 0x4), dlc=dlc2len(dlc), @@ -399,6 +402,8 @@ def on_message_received(self, msg): if msg.is_extended_id: arb_id |= CAN_MSG_EXT flags = REMOTE_FLAG if msg.is_remote_frame else 0 + if not msg.is_rx: + flags |= DIR can_data = bytes(msg.data) if msg.is_error_frame: diff --git a/can/message.py b/can/message.py index 57e0109af..7ceaca489 100644 --- a/can/message.py +++ b/can/message.py @@ -42,6 +42,7 @@ class Message: "dlc", "data", "is_fd", + "is_rx", "bitrate_switch", "error_state_indicator", "__weakref__", # support weak references to messages @@ -58,6 +59,7 @@ def __init__( dlc: Optional[int] = None, data: Optional[typechecking.CanData] = None, is_fd: bool = False, + is_rx: bool = True, bitrate_switch: bool = False, error_state_indicator: bool = False, check: bool = False, @@ -81,6 +83,7 @@ def __init__( self.is_error_frame = is_error_frame self.channel = channel self.is_fd = is_fd + self.is_rx = is_rx self.bitrate_switch = bitrate_switch self.error_state_indicator = error_state_indicator @@ -114,6 +117,7 @@ def __str__(self) -> str: flag_string = " ".join( [ "X" if self.is_extended_id else "S", + "Rx" if self.is_rx else "Tx", "E" if self.is_error_frame else " ", "R" if self.is_remote_frame else " ", "F" if self.is_fd else " ", @@ -159,6 +163,9 @@ def __repr__(self) -> str: "is_extended_id={}".format(self.is_extended_id), ] + if not self.is_rx: + args.append("is_rx=False") + if self.is_remote_frame: args.append("is_remote_frame={}".format(self.is_remote_frame)) @@ -198,6 +205,7 @@ def __copy__(self) -> "Message": dlc=self.dlc, data=self.data, is_fd=self.is_fd, + is_rx=self.is_rx, bitrate_switch=self.bitrate_switch, error_state_indicator=self.error_state_indicator, ) @@ -214,6 +222,7 @@ def __deepcopy__(self, memo: dict) -> "Message": dlc=self.dlc, data=deepcopy(self.data, memo), is_fd=self.is_fd, + is_rx=self.is_rx, bitrate_switch=self.bitrate_switch, error_state_indicator=self.error_state_indicator, ) @@ -280,7 +289,10 @@ def _check(self): ) def equals( - self, other: "Message", timestamp_delta: Optional[Union[float, int]] = 1.0e-6 + self, + other: "Message", + timestamp_delta: Optional[Union[float, int]] = 1.0e-6, + check_direction: bool = True, ) -> bool: """ Compares a given message with this one. @@ -290,6 +302,8 @@ def equals( :param timestamp_delta: the maximum difference at which two timestamps are still considered equal or None to not compare timestamps + :param check_direction: do we compare the messages' directions (Tx/Rx) + :return: True iff the given message equals this one """ # see https://github.com/hardbyte/python-can/pull/413 for a discussion @@ -304,6 +318,7 @@ def equals( timestamp_delta is None or abs(self.timestamp - other.timestamp) <= timestamp_delta ) + and (self.is_rx == other.is_rx or not check_direction) and self.arbitration_id == other.arbitration_id and self.is_extended_id == other.is_extended_id and self.dlc == other.dlc diff --git a/doc/message.rst b/doc/message.rst index 921748cb9..e5745f6b5 100644 --- a/doc/message.rst +++ b/doc/message.rst @@ -145,6 +145,13 @@ Message Indicates that this message is a CAN FD message. + .. attribute:: is_rx + + :type: bool + + Indicates whether this message is a transmitted (Tx) or received (Rx) frame + + .. attribute:: bitrate_switch :type: bool