1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
.. _internalapi:
Internal API
============
Here we document the odds and ends that are more helpful for creating your own interfaces
or listeners but generally shouldn't be required to interact with python-can.
BusABC
------
The :class:`~can.BusABC` class, as the name suggests, provides an abstraction of a CAN bus.
The bus provides a wrapper around a physical or virtual CAN Bus.
An interface specific instance of the :class:`~can.BusABC` is created by the :class:`~can.Bus`
class, see :ref:`bus` for the user facing API.
.. _businternals:
Extending the ``BusABC`` class
------------------------------
Concrete implementations **must** implement the following:
* :meth:`~can.BusABC.send` to send individual messages
* :meth:`~can.BusABC._recv_internal` to receive individual messages
(see note below!)
* set the :attr:`~can.BusABC.channel_info` attribute to a string describing
the underlying bus and/or channel
They **might** implement the following:
* :meth:`~can.BusABC.flush_tx_buffer` to allow discarding any
messages yet to be sent
* :meth:`~can.BusABC.shutdown` to override how the bus should
shut down
* :meth:`~can.BusABC._send_periodic_internal` to override the software based
periodic sending and push it down to the kernel or hardware.
* :meth:`~can.BusABC._apply_filters` to apply efficient filters
to lower level systems like the OS kernel or hardware.
* :meth:`~can.BusABC._detect_available_configs` to allow the interface
to report which configurations are currently available for new
connections.
* :meth:`~can.BusABC.state` property to allow reading and/or changing
the bus state.
.. note::
*TL;DR*: Only override :meth:`~can.BusABC._recv_internal`,
never :meth:`~can.BusABC.recv` directly.
Previously, concrete bus classes had to override :meth:`~can.BusABC.recv`
directly instead of :meth:`~can.BusABC._recv_internal`, but that has
changed to allow the abstract base class to handle in-software message
filtering as a fallback. All internal interfaces now implement that new
behaviour. Older (custom) interfaces might still be implemented like that
and thus might not provide message filtering:
Concrete instances are usually created by :func:`can.Bus` which takes the users
configuration into account.
Bus Internals
~~~~~~~~~~~~~
Several methods are not documented in the main :class:`can.BusABC`
as they are primarily useful for library developers as opposed to
library users.
.. automethod:: can.BusABC.__init__
.. automethod:: can.BusABC.__iter__
.. automethod:: can.BusABC.__str__
.. autoattribute:: can.BusABC.__weakref__
.. automethod:: can.BusABC._recv_internal
.. automethod:: can.BusABC._apply_filters
.. automethod:: can.BusABC._send_periodic_internal
.. automethod:: can.BusABC._detect_available_configs
About the IO module
-------------------
Handling of the different file formats is implemented in ``can.io``.
Each file/IO type is within a separate module and ideally implements both a *Reader* and a *Writer*.
The reader usually extends :class:`can.io.generic.BaseIOHandler`, while
the writer often additionally extends :class:`can.Listener`,
to be able to be passed directly to a :class:`can.Notifier`.
Adding support for new file formats
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This assumes that you want to add a new file format, called *canstore*.
Ideally add both reading and writing support for the new file format, although this is not strictly required.
1. Create a new module: *can/io/canstore.py*
(*or* simply copy some existing one like *can/io/csv.py*)
2. Implement a reader ``CanstoreReader`` (which often extends :class:`can.io.generic.BaseIOHandler`, but does not have to).
Besides from a constructor, only ``__iter__(self)`` needs to be implemented.
3. Implement a writer ``CanstoreWriter`` (which often extends :class:`can.io.generic.BaseIOHandler` and :class:`can.Listener`, but does not have to).
Besides from a constructor, only ``on_message_received(self, msg)`` needs to be implemented.
4. Add a case to ``can.io.player.LogReader``'s ``__new__()``.
5. Document the two new classes (and possibly additional helpers) with docstrings and comments.
Please mention features and limitations of the implementation.
6. Add a short section to the bottom of *doc/listeners.rst*.
7. Add tests where appropriate, for example by simply adding a test case called
`class TestCanstoreFileFormat(ReaderWriterTest)` to *test/logformats_test.py*.
That should already handle all of the general testing.
Just follow the way the other tests in there do it.
8. Add imports to *can/__init__py* and *can/io/__init__py* so that the
new classes can be simply imported as *from can import CanstoreReader, CanstoreWriter*.
IO Utilities
~~~~~~~~~~~~
.. automodule:: can.io.generic
:members:
:member-order: bysource
Other Utilities
---------------
.. automodule:: can.util
:members:
|