hardbyte / python-can

The can package provides controller area network support for Python developers
https://python-can.readthedocs.io
GNU Lesser General Public License v3.0
1.31k stars 604 forks source link

Unexpected behavior with multiple notifiers #1888

Open bessman opened 2 weeks ago

bessman commented 2 weeks ago

Describe the bug

When there is more than one active Notifier, only one instance receives an incoming message. Which notifier gets the message seems random.

To Reproduce

# Do this first to set up two virtual can buses with bidirectional gating:
# sudo modprobe vcan
# sudo ip link add dev vcan0 type vcan
# sudo ip link add dev vcan1 type vcan
# sudo ip link set vcan0 up
# sudo ip link set vcan1 up
# sudo modprobe can-gw
# sudo cangw -A -s vcan0 -d vcan1 -e
# sudo cangw -A -s vcan1 -d vcan0 -e

import can

class NamedPrinter(can.Printer):
    def __init__(self, name: str, *args, **kwargs) -> None:
        self.name = name
        super().__init__(*args, **kwargs)

    def on_message_received(self, msg: can.Message) -> None:
        print(f"Printer {self.name}")
        super().on_message_received(msg)

vbus0 = can.Bus(interface="socketcan", channel="vcan0")
vbus1 = can.Bus(interface="socketcan", channel="vcan1")

not1 = can.Notifier(vbus1, [NamedPrinter("A")])
not2 = can.Notifier(vbus1, [NamedPrinter("B")])

msg = can.Message(arbitration_id=0x11, data=b"hello")

for i in range(4):
    vbus0.send(msg)

# Output:
# Printer A
# Timestamp: 1730815787.280445    ID: 00000011    X Rx                DL:  5    68 65 6c 6c 6f              'hello'    Channel: vcan1
# Printer B
# Timestamp: 1730815787.280519    ID: 00000011    X Rx                DL:  5    68 65 6c 6c 6f              'hello'    Channel: vcan1
# Printer A
# Timestamp: 1730815787.280466    ID: 00000011    X Rx                DL:  5    68 65 6c 6c 6f              'hello'    Channel: vcan1
# Printer B
# Timestamp: 1730815787.280531    ID: 00000011    X Rx                DL:  5    68 65 6c 6c 6f              'hello'    Channel: vcan1

Expected behavior

I expected all notifiers to receive all incoming messages.

If multiple simultaneous notifiers on the same bus is not supported, the documentation should mention this. Ideally, a warning or error should be raised if an additional notifier is created on a bus with an already active notifier.

Additional context

OS and version: Ubuntu 20.04 Python version: 3.13.0 python-can version: 4.4.2 python-can interface/s (if applicable): socketcan

zariiii9003 commented 2 weeks ago

A single notifier can handle multiple bus instances and multiple listeners:

notifier = can.Notifier([vbus1, vbus2], [NamedPrinter("A"), NamedPrinter("B")])
bessman commented 2 weeks ago

Yes, I know, but I still find this behavior surprising. Wouldn't it make sense to make note of it in the documentation, at least?

On a related note, is there any way to clean up orphaned notifiers? For example:

notifier = can.Notifier(vbus1, [NamedPrinter("A")])
notifier = can.Notifier(vbus1, [NamedPrinter("B")])
notifier.stop()
vbus0.send(msg)
# Output:
# Printer A
# Timestamp: 1730841762.033267    ID: 00000011    X Rx                DL:  5    68 65 6c 6c 6f              'hello'    Channel: vcan1
zariiii9003 commented 2 weeks ago

Take a look at #1890