from .. import CanlibException
from .message import Message
[docs]class SignalNotFound(CanlibException):
def __init__(self, text):
super(SignalNotFound, self).__init__(self, text)
[docs]class FrameBox(object):
"""Helper class for sending signals
This class allows sending signals without worrying about what message they
are defined in. It does this by binding a message and all its signals to
the same `canlib.Frame` object.
Objects are created by giving them a `Dbc` database, and optionally a list
of messages (either names or `Message` objects)::
db = Dbc(...)
framebox = FrameBox(db, messages=('Msg0','Msg1'))
Messages can also be added after instantiation with `add_message`::
framebox.add_message('Msg0', 'Msg1')
Then setting signal values for any added message is done with::
framebox.signal('Sig0').phys = 7
framebox.signal('Sig1').phys = 20
Once all values are set, they can easily be sent via the channel `channel` with::
for frame in framebox.frames():
channel.write(frame)
Any `Framebox` methods that return messages requires the message to have
been added to the framebox, either with the ``messages`` constructor
argument or with `add_message`. Likewise, any methods that return signals
require the signal's message to have been added.
"""
def __init__(self, db, messages=()):
self._db = db
self._bsigs = {}
self._bmsgs = {}
for message in messages:
self.add_message(message)
[docs] def add_message(self, message):
"""Add a message to the framebox
The message will be available for all future uses of `FrameBox.message`
and `FrameBox.messages`, and all its signals will be available for uses
of `FrameBox.signal` and `FrameBox.signals`.
The ``message`` argument can either be a message name, or a
`canlib.kvadblib.Message` object.
"""
if not isinstance(message, Message):
message = self._db.get_message_by_name(message)
self._add_msg(message)
[docs] def signal(self, name):
"""Retrieves a signal by name
Returns a `BoundSignal` that shares its `Frame` object with its parent
message and sibling signals.
"""
try:
return self._bsigs[name]
except KeyError:
raise SignalNotFound("Framebox has no signal named " + repr(name))
[docs] def signals(self):
"""Iterator over all signals that this `FrameBox` is aware of"""
return iter(self._bsigs.values())
[docs] def message(self, name):
"""Retrieves a message by name
Returns a `BoundMessage` that shares its `Frame` object with its child
signals.
"""
if name not in self._bmsgs:
self._add_msg(self._db.get_message_by_name(name))
return self._bmsgs[name]
[docs] def messages(self):
"""Iterator over all messages that this `FrameBox` is aware of"""
return iter(self._bmsgs.values())
[docs] def frames(self):
"""Iterate over all frames of the signals/messages from this `FrameBox`"""
return (bmsg._frame for bmsg in self._bmsgs.values())
def _add_msg(self, message):
assert message.name not in self._bmsgs
bmsg = message.bind()
self._bmsgs[message.name] = bmsg
for bsig in bmsg:
self._bsigs[bsig.name] = bsig