diff --git a/can/interfaces/virtual.py b/can/interfaces/virtual.py index 5e24c6e1f..e84fa5853 100644 --- a/can/interfaces/virtual.py +++ b/can/interfaces/virtual.py @@ -85,18 +85,20 @@ def _recv_internal(self, timeout): def send(self, msg, timeout=None): self._check_if_open() - msg_copy = deepcopy(msg) - msg_copy.timestamp = time.time() - msg_copy.channel = self.channel_id - + timestamp = time.time() # Add message to all listening on this channel all_sent = True for bus_queue in self.channel: - if bus_queue is not self.queue or self.receive_own_messages: - try: - bus_queue.put(msg_copy, block=True, timeout=timeout) - except queue.Full: - all_sent = False + if bus_queue is self.queue and not self.receive_own_messages: + continue + msg_copy = deepcopy(msg) + msg_copy.timestamp = timestamp + msg_copy.channel = self.channel_id + msg_copy.is_rx = bus_queue is not self.queue + try: + bus_queue.put(msg_copy, block=True, timeout=timeout) + except queue.Full: + all_sent = False if not all_sent: raise CanError("Could not send message to one or more recipients") diff --git a/test/back2back_test.py b/test/back2back_test.py index b707988ec..8c1ded6c5 100644 --- a/test/back2back_test.py +++ b/test/back2back_test.py @@ -125,6 +125,66 @@ def test_dlc_less_than_eight(self): msg = can.Message(is_extended_id=False, arbitration_id=0x300, data=[4, 5, 6]) self._send_and_receive(msg) + def test_message_direction(self): + # Verify that own message received has is_rx set to False while message + # received on the other virtual interfaces have is_rx set to True + if self.INTERFACE_1 != "virtual": + raise unittest.SkipTest( + "Message direction not yet implemented for socketcan" + ) + bus3 = can.Bus( + channel=self.CHANNEL_2, + bustype=self.INTERFACE_2, + bitrate=self.BITRATE, + fd=TEST_CAN_FD, + single_handle=True, + receive_own_messages=True, + ) + try: + msg = can.Message( + is_extended_id=False, arbitration_id=0x300, data=[2, 1, 3] + ) + bus3.send(msg) + recv_msg_bus1 = self.bus1.recv(self.TIMEOUT) + recv_msg_bus2 = self.bus2.recv(self.TIMEOUT) + self_recv_msg_bus3 = bus3.recv(self.TIMEOUT) + + self.assertTrue(recv_msg_bus1.is_rx) + self.assertTrue(recv_msg_bus2.is_rx) + self.assertFalse(self_recv_msg_bus3.is_rx) + finally: + bus3.shutdown() + + def test_unique_message_instances(self): + # Verify that we have a different instances of message for each bus + if self.INTERFACE_1 != "virtual": + raise unittest.SkipTest("Not relevant for socketcan") + bus3 = can.Bus( + channel=self.CHANNEL_2, + bustype=self.INTERFACE_2, + bitrate=self.BITRATE, + fd=TEST_CAN_FD, + single_handle=True, + receive_own_messages=True, + ) + try: + msg = can.Message( + is_extended_id=False, arbitration_id=0x300, data=[2, 1, 3] + ) + bus3.send(msg) + recv_msg_bus1 = self.bus1.recv(self.TIMEOUT) + recv_msg_bus2 = self.bus2.recv(self.TIMEOUT) + self_recv_msg_bus3 = bus3.recv(self.TIMEOUT) + + self._check_received_message(recv_msg_bus1, recv_msg_bus2) + self._check_received_message(recv_msg_bus2, self_recv_msg_bus3) + + recv_msg_bus1.data[0] = 4 + self.assertNotEqual(recv_msg_bus1.data, recv_msg_bus2.data) + self.assertEqual(recv_msg_bus2.data, self_recv_msg_bus3.data) + finally: + bus3.shutdown() + @unittest.skipUnless(TEST_CAN_FD, "Don't test CAN-FD") def test_fd_message(self): msg = can.Message(