Loading files
ece376249This file is pinned to the selected release. Download the original to open it in your design tool.
"""
Tinymovr Tee Module
Copyright Ioannis Chatzikonstantinou 2020-2023
Implements a Tee class to distribute incoming traffic according to rules
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""
import time
from enum import Enum
from threading import Thread, Lock
tee = None
class Client:
def __init__(self, filter_cb, recv_cb):
self.filter_cb = filter_cb
self.recv_cb = recv_cb
class TeeState(Enum):
INIT = 0
RUNNING = 1
STOPPING = 2
STOPPED = 3
class Tee:
"""
Distribute incoming messages based on the boolean result
of a filter callback.
python-can does not allow filtering messages per recipient therefore
this class.
Also implements a simple forwarding mechanism for sending messages, to
simplify interfacing with CAN bus objects.
"""
def __init__(self, bus, timeout):
self.bus = bus
self.flush_rx_buffer()
self.timeout = timeout
self.clients = []
self.state = TeeState.INIT
self.update_thread = Thread(target=self.update, daemon=True)
self.update_thread.start()
def add(self, filter_cb, recv_cb):
self.clients.append(Client(filter_cb, recv_cb))
def update(self):
"""
Continuously update the state of the Tee object, checking
for messages and distributing them to the appropriate clients
based on filter criteria until the state changes to STOPPING.
"""
self.state = TeeState.RUNNING
while TeeState.RUNNING == self.state:
self._update_once()
assert TeeState.STOPPING == self.state
self.state = TeeState.STOPPED
def _update_once(self):
"""
Try to receive a message from the bus object and if successful,
tests reception of each tee instance in the global index.
"""
frame = self.bus.recv(timeout=self.timeout)
if frame:
for client in self.clients:
if client.filter_cb(frame):
client.recv_cb(frame)
def send(self, frame):
"""
Send a frame by forwarding to the bus object
"""
self.bus.send(frame)
def stop(self):
self.state = TeeState.STOPPING
while TeeState.STOPPING == self.state:
time.sleep(0.01)
assert TeeState.STOPPED == self.state
def flush_rx_buffer(self, trials=100):
"""
Flush the RX buffer of a bus
"""
for i in range(trials):
if not self.bus.recv(timeout=0.001):
return
def init_tee(bus, timeout=0.1):
"""
Initializes a tee using a python-can bus instance
"""
global tee
assert None == tee
tee = Tee(bus, timeout)
return tee
def destroy_tee():
"""
Destroys the existing tee, stopping its thread.
"""
global tee
assert None != tee
tee.stop()
tee = None
def get_tee():
"""
Get the current tee object
"""
return tee