# 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.

## Extending the `BusABC` class

Concrete implementations must implement the following:

  - `send()` to send individual messages

  - `_recv_internal()` to receive individual messages (see note below!)

  - set the `channel_info` attribute to a string describing the underlying bus and/or channel

They might implement the following:

  - `flush_tx_buffer()` to allow discarding any messages yet to be sent

  - `shutdown()` to override how the bus should shut down

  - `_send_periodic_internal()` to override the software based periodic sending and push it down to the kernel or hardware.

  - `_apply_filters()` to apply efficient filters to lower level systems like the OS kernel or hardware.

  - `_detect_available_configs()` to allow the interface to report which configurations are currently available for new connections.

  - `state()` property to allow reading and/or changing the bus state.

Note

TL;DR: Only override `_recv_internal()`, never `recv()` directly.

Previously, concrete bus classes had to override `recv()` directly instead of `_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 `can.Bus` which takes the users configuration into account.

### Bus Internals

Several methods are not documented in the main `can.BusABC` as they are primarily useful for library developers as opposed to library users. This is the entire ABC bus class with all internal methods:

class can.BusABC(channel, can_filters=None, **kwargs)

  The CAN Bus Abstract Base Class that serves as the basis for all concrete interfaces.

  This class may be used as an iterator over the received messages.

  Construct and open a CAN bus instance of the specified type.

  Subclasses should call though this method with all given parameters as it handles generic tasks like applying filters.

  Parameters

    - channel – The can interface identifier. Expected type is backend dependent.

    - can_filters (list) – See `set_filters()` for details.

    - kwargs (dict) – Any backend dependent configurations are passed in this dictionary

## 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 `can.io.generic.BaseIOHandler`, while the writer often additionally extends `can.Listener`, to be able to be passed directly to a `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 `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 `can.io.generic.BaseIOHandler` and `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

Contains a generic class for file IO.

class can.io.generic.BaseIOHandler(file, mode='rt')

  A generic file handler that can be used for reading and writing.

  Can be used as a context manager.

  Attr file-like file

    the file-like object that is kept internally, or None if none was opened

  Parameters

    - file – a path-like object to open a file, a file-like object to be used as a file or None to not use a file at all

    - mode (str) – the mode that should be used to open the file, see `open()`, ignored if file is None

## Other Utilities

Utilities and configuration file parsing.

can.util.channel2int(channel)

  Try to convert the channel to an integer.

  Parameters

    channel – Channel string (e.g. can0, CAN1) or integer

  Returns

    Channel integer or None if unsuccessful

  Return type

    int

can.util.dlc2len(dlc)

  Calculate the data length from DLC.

  Parameters

    dlc (int) – DLC (0-15)

  Returns

    Data length in number of bytes (0-64)

  Return type

    int

can.util.len2dlc(length)

  Calculate the DLC from data length.

  Parameters

    length (int) – Length in number of bytes (0-64)

  Returns

    DLC (0-15)

  Return type

    int

can.util.load_config(path=None, config=None, context=None)

  Returns a dict with configuration details which is loaded from (in this order):

  - config

  - can.rc

  - Environment variables CAN_INTERFACE, CAN_CHANNEL, CAN_BITRATE

  - Config files `/etc/can.conf` or `~/.can` or `~/.canrc` where the latter may add or replace values of the former.

  Interface can be any of the strings from `can.VALID_INTERFACES` for example: kvaser, socketcan, pcan, usb2can, ixxat, nican, virtual.

  Note

  The key `bustype` is copied to `interface` if that one is missing and does never appear in the result.

  Parameters

    - path – Optional path to config file.

    - config – A dict which may set the ‘interface’, and/or the ‘channel’, or neither. It may set other values that are passed through.

    - context – Extra ‘context’ pass to config sources. This can be use to section other than ‘default’ in the configuration file.

  Returns

    A config dictionary that should contain ‘interface’ & ‘channel’:

        {
            'interface': 'python-can backend interface to use',
            'channel': 'default channel to use',
            # possibly more
        }

    Note `None` will be used if all the options are exhausted without finding a value.

    All unused values are passed from `config` over to this.

  Raises

    NotImplementedError if the `interface` isn’t recognized

can.util.load_environment_config()

  Loads config dict from environmental variables (if set):

  - CAN_INTERFACE

  - CAN_CHANNEL

  - CAN_BITRATE

can.util.load_file_config(path=None, section=None)

  Loads configuration from file with following content:

      [default]
      interface = socketcan
      channel = can0

  Parameters

    - path – path to config file. If not specified, several sensible default locations are tried depending on platform.

    - section – name of the section to read configuration from.

can.util.set_logging_level(level_name=None)

  Set the logging level for the “can” logger. Expects one of: ‘critical’, ‘error’, ‘warning’, ‘info’, ‘debug’, ‘subdebug’