oresat / CANopen-monitor

An NCurses-based TUI application for tracking activity over the CAN bus and decoding messages with provided EDS/OD files.
https://canopen-monitor.readthedocs.io/
GNU General Public License v3.0
25 stars 6 forks source link

Interface monitoring does not recover after interface restart #76

Closed nickembrey closed 2 years ago

nickembrey commented 2 years ago

When an interface goes offline and comes back online again, CANopen-monitor sometimes does not detect the return of that interface and does not display it or its messages.

This issue can be simulated by:

  1. Running CANopen-monitor and adding an interface.
  2. Use the socketcan-dev.py script to begin sending messages on that interface.
  3. Confirm that CANopen-monitor reads the interface as up and is receiving messages.
  4. After a few seconds, stop the socketcan-dev.py script.
  5. Confirm that CANopen-monitor reads the interface as down and no longer receives messages.
  6. Start the socketcan-dev.py script again; CANopen-monitor will not read the interface as back up and will not receive messages.
nickembrey commented 2 years ago

EDIT: this was an incorrect diagnosis of the issue and the below is intentional, expected behavior.

The issue appears to stem from a mutual dependency between Interface.is_up and Interface.last_activity:

An interface is only marked as is_up if its age is less than a constant: _STALE_INTERFACE (1 minute):

@property
    def is_up(self: Interface) -> bool:
        ...
            return if_dev.isup and self.age < _STALE_INTERFACE
        ...

interface.py lines 131-141

Its age is a property dependent on its last_activity:

@property
def age(self: Interface) -> dt.timedelta:
    ...
    return dt.datetime.now() - self.last_activity

interface.py lines 177-184

Its last_activity is only updated if is_up is true for the interface:

    def handler(self: MagicCANBus, iface: Interface) -> None:
        ...
                while (iface.is_up and iface.running and
                       self.keep_alive_list[iface.name].is_set()):
                    frame = iface.recv()

magic_can_bus.py lines 109-138

So, if an interface goes stale, it will never be able to come back up.