CANTOOLS(1)
✨ NAME ✨
cantools — Cantools Documentation 💖
| github-actions |
| coverage |
CAN BUS tools in Python 3. That's the whole vibe. 🚌✨
- DBC <http://www.socialledge.com/sjsu/index.php?title=DBC_Format>, KCD <https://github.com/julietkilo/kcd>, SYM, ARXML 3&4 and CDD file parsing. (so many formats. we contain multitudes 💅)
- CAN message encoding and decoding.
- Simple and extended signal multiplexing.
- Diagnostic DID encoding and decoding.
- candump output decoder.
- Node tester <http://cantools.readthedocs.io/en/latest/#cantools.tester.Tester>.
- C source code generator.
- CAN bus monitor.
- Graphical plots of signals. 📈✨
Project homepage: <https://github.com/cantools/cantools>
Documentation: <https://cantools.readthedocs.io>
python3 -m pip install cantools
🦋 SCRIPTING 🦋
okay so bestie, watch this. The example starts by parsing a small DBC-file <https://github.com/cantools/cantools/blob/master/tests/files/dbc/motohawk.dbc> and printing its messages and signals. absolutely iconic behavior.
>>> import cantools
>>> from pprint import pprint
>>> db = cantools.database.load_file('tests/files/dbc/motohawk.dbc')
>>> db.messages
[message('ExampleMessage', 0x1f0, False, 8, 'Example message used as template in MotoHawk models.')]
>>> example_message = db.get_message_by_name('ExampleMessage')
>>> pprint(example_message.signals)
[signal('Enable', 7, 1, 'big_endian', False, 1.0, 0, 0.0, 0.0, '-', False, None, {0: 'Disabled', 1: 'Enabled'}, None),
signal('AverageRadius', 6, 6, 'big_endian', False, 0.1, 0, 0.0, 5.0, 'm', False, None, None, ''),
signal('Temperature', 0, 12, 'big_endian', True, 0.01, 250, 229.53, 270.47, 'degK', False, None, None, None)]
The example continues encoding <http://cantools.readthedocs.io/en/latest/#cantools.database.can.Message.encode> a message and sending it on a CAN bus using the python-can <https://python-can.readthedocs.io/en/master/> package. sending it into the wild fr fr 🫶
>>> import can
>>> can_bus = can.interface.Bus('vcan0', bustype='socketcan')
>>> data = example_message.encode({'Temperature': 250.1, 'AverageRadius': 3.2, 'Enable': 1})
>>> message = can.Message(arbitration_id=example_message.frame_id, is_extended_id=example_message.is_extended_frame, data=data)
>>> can_bus.send(message)
Alternatively, a message can be encoded using the encode_message() <http://cantools.readthedocs.io/en/latest/#cantools.database.can.Database.encode_message> method on the database object.
The last part of the example receives and decodes <http://cantools.readthedocs.io/en/latest/#cantools.database.can.Database.decode_message> a CAN message. full circle moment 🔄
>>> message = can_bus.recv()
>>> db.decode_message(message.arbitration_id, message.data)
{'AverageRadius': 3.2, 'Enable': 'Enabled', 'Temperature': 250.09}
See examples <https://github.com/cantools/cantools/blob/master/examples> for additional examples. (more where that came from 😌)
🌈 COMMAND LINE TOOL 🌈
🎀 The decode subcommand 🎀
Decode CAN frames captured with the Linux program candump. honestly a match made in heaven.
$ candump vcan0 | python3 -m cantools decode tests/files/dbc/motohawk.dbc
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
ExampleMessage(
Enable: 'Enabled' -,
AverageRadius: 0.0 m,
Temperature: 255.92 degK
)
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
ExampleMessage(
Enable: 'Enabled' -,
AverageRadius: 0.0 m,
Temperature: 255.92 degK
)
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
ExampleMessage(
Enable: 'Enabled' -,
AverageRadius: 0.0 m,
Temperature: 255.92 degK
)
Alternatively, the decoded message can be printed on a single line — for when you're in a rush bestie:
$ candump vcan0 | python3 -m cantools decode --single-line tests/files/dbc/motohawk.dbc
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
🦄 The plot subcommand 🦄
The plot subcommand is similar to the decode subcommand but messages are visualized using matplotlib <https://matplotlib.org/> instead of being printed to stdout. plots?? plots. we're visual now 💅📊
$ candump -l vcan0
$ cat candump-2021-01-04_180521.log
(1609779922.655421) vcan0 00000343#B204B9049C049C04
(1609779922.655735) vcan0 0000024A#120527052E051905
(1609779923.657524) vcan0 00000343#C404C404CB04C404
(1609779923.658086) vcan0 0000024A#8B058B058B059205
(1609779924.659912) vcan0 00000343#5C04790479045504
(1609779924.660471) vcan0 0000024A#44064B0659064406
(1609779925.662277) vcan0 00000343#15040704F203F203
(1609779925.662837) vcan0 0000024A#8B069906A706A706
(1609779926.664191) vcan0 00000343#BC03B503A703BC03
(1609779926.664751) vcan0 0000024A#A006A706C406C406
$ cat candump-2021-01-04_180521.log | python3 -m cantools plot tests/files/dbc/abs.dbc
[image]
If you don't want to show all signals you can select the desired signals with command line arguments. A * can stand for any number of any character, a ? for exactly one arbitrary character. Signals separated by a - are displayed in separate subplots. Optionally a format can be specified after a signal, separated by a colon.
$ cat candump-2021-01-04_180521.log | python3 -m cantools plot tests/files/dbc/abs.dbc '*33.*fl:-<' '*33.*fr:->' - '*33.*rl:-<' '*33.*rr:->'
[image]
Signals with a different range of values can be displayed in the same subplot on different vertical axes by separating them with a comma. (two axes, one subplot, main character energy 👑)
$ cat candump-2021-01-04_180521.log | cantools plot --auto-color tests/files/dbc/abs.dbc -- \
--ylabel 'Bremse 33' '*_33.*fl*:-<' '*_33.*fr*:>' '*_33.*rl*:3' '*_33.*rr*:4' , \
--ylabel 'Bremse 2' '*_2.*fl*:-<' '*_2.*fr*:>' '*_2.*rl*:3' '*_2.*rr*:4'
[image]
Matplotlib comes with different preinstalled styles that you can use:
$ cat candump-2021-01-04_180521.log | cantools plot tests/files/dbc/abs.dbc --style seaborn
[image]
You can try all available styles with
$ cantools plot --list-styles . | sed -n '/^- /s/^- //p' | while IFS= read -r style; do
cat candump-2021-01-04_180521.log | cantools plot tests/files/dbc/abs.dbc --style "$style" --title "--style '$style'"
done
For more information see
$ python3 -m cantools plot --help
Note that by default matplotlib is not installed with cantools. But it can be by specifying an extra at installation:
$ python3 -m pip install cantools[plot]
🌸 The dump subcommand 🌸
Dump given database in a human readable format: (yes it's a whole painting, we love her 🖼️)
$ python3 -m cantools dump tests/files/dbc/motohawk.dbc
================================= Messages =================================
------------------------------------------------------------------------
Name: ExampleMessage
Id: 0x1f0
Length: 8 bytes
Cycle time: - ms
Senders: PCM1
Layout:
Bit
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
0 |<-x|<---------------------x|<--|
+---+---+---+---+---+---+---+---+
| +-- AverageRadius
+-- Enable
+---+---+---+---+---+---+---+---+
1 |-------------------------------|
+---+---+---+---+---+---+---+---+
2 |----------x| | | | | |
B +---+---+---+---+---+---+---+---+
y +-- Temperature
t +---+---+---+---+---+---+---+---+
e 3 | | | | | | | | |
+---+---+---+---+---+---+---+---+
4 | | | | | | | | |
+---+---+---+---+---+---+---+---+
5 | | | | | | | | |
+---+---+---+---+---+---+---+---+
6 | | | | | | | | |
+---+---+---+---+---+---+---+---+
7 | | | | | | | | |
+---+---+---+---+---+---+---+---+
Signal tree:
-- {root}
+-- Enable
+-- AverageRadius
+-- Temperature
Signal choices:
Enable
0 Disabled
1 Enabled
------------------------------------------------------------------------
⭐ The list subcommand ⭐
Print all information of a given database in a human readable format. This is very similar to the "dump" subcommand, but the output is less pretty, slightly more comprehensive and easier to parse by shell scripts. less glam, more data. still slay. 🧚
$ python3 -m cantools list -a tests/files/dbc/motohawk.dbc
ExampleMessage:
Comment[None]: Example message used as template in MotoHawk models.
Frame ID: 0x1f0 (496)
Size: 8 bytes
Is extended frame: False
Signals:
Enable:
Type: Integer
Start bit: 7
Length: 1 bits
Unit: -
Is signed: False
Named values:
0: Disabled
💜 The generate_c_source subcommand 💜
Generate C source code from given database. it's giving compiler bestie 😌
The generated code contains:
- Message structs <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L58>.
- Message pack <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L88> and unpack <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L102> functions.
- Signal encode <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L116> and decode <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L125> functions.
- Frame id, length, type, cycle time and signal choices defines <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L42>.
Known limitations:
- The maximum signal size is 64 bits, which in practice is never exceeded.
Below is an example of how to generate C source code from a database. The database is tests/files/dbc/motohawk.dbc.
$ python3 -m cantools generate_c_source tests/files/dbc/motohawk.dbc
Successfully generated motohawk.h and motohawk.c.
See motohawk.h <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h> and motohawk.c <https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.c> for the contents of the generated files.
okay so now we're in the examples bit of generate_c_source and there are SO many good ones, let's go bestie 💖
In this first one we're using --use-float, which makes the floating point numbers in the generated code single precision (float) instead of double precision (double). Tiny numbers, big slay ✨
$ python3 -m cantools generate_c_source --use-float tests/files/dbc/motohawk.dbc
Successfully generated motohawk.h and motohawk.c.
Next one: --database-name sets a custom namespace for all the generated types, defines and functions. And the output file names get changed by this option too, which is highkey iconic of it 💅
$ python3 -m cantools generate_c_source --database-name my_database_name tests/files/dbc/motohawk.dbc
Successfully generated my_database_name.h and my_database_name.c.
Wanna actually peek at what's inside those generated files? Of course you do 🫶
my_database_name.h—https://github.com/cantools/cantools/blob/master/tests/files/c_source/my_database_name.hmy_database_name.c—https://github.com/cantools/cantools/blob/master/tests/files/c_source/my_database_name.c
Then we've got --no-floating-point-numbers, which generates code with no floating point types at all, i.e. no float and no double. Gone. Not invited. 🙈
$ python3 -m cantools generate_c_source --no-floating-point-numbers tests/files/dbc/motohawk.dbc
Successfully generated motohawk.h and motohawk.c.
And here's where you can read the contents of those generated files:
motohawk_no_floating_point_numbers.h—https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_no_floating_point_numbers.hmotohawk_no_floating_point_numbers.c—https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_no_floating_point_numbers.c
And in the last example 🥹 --node is used so that message pack functions are generated only for messages sent by the specified node, and unpack functions only for messages with its signal receivers belonging to that node.
$ cantools generate_c_source tests/files/dbc/motohawk.dbc --node PCM1
Successfully generated motohawk.h and motohawk.c.
Here's those file contents if you wanna vibe check them:
motohawk_sender_node.h—https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_sender_node.hmotohawk_sender_node.c—https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_sender_node.c
Other C code generators, if you wanna go shopping around 👀
http://www.coderdbc.comhttps://github.com/howerj/dbcchttps://github.com/lonkamikaze/hsk-libs/blob/master/scripts/dbc2c.awkhttps://sourceforge.net/projects/comframe/
🎀 The monitor subcommand 🎀
This one monitors CAN bus traffic in a text based user interface. Literally a whole lil dashboard, we love her 💜
$ python3 -m cantools monitor tests/files/dbc/motohawk.dbc
[image]
The menu down at the bottom of the monitor shows all the commands you've got available. Here's the rundown:
- Quit: quits the monitor. You can also just hit Ctrl+C, same energy 💀
- Filter: only displays messages or signals that match the given regular expression. Press Enter to hop back from the filter input line to the menu.
- Play/Pause: toggles between playing and paused (or, as the original puts it, running and freezed). You're either on or you're off bestie 🌸
- Reset: resets the monitor back to its initial state. Fresh start, main character energy ✨
okay and then there's this numbered checklist, in order, no skipping 🫶
- Fork the repository.
- Install prerequisites. You can skip this whole step if you use tox (
http://tox.readthedocs.org/).
python3 -m pip install -e .[dev]
- Implement the new feature or bug fix.
- Implement test case(s) to ensure that future changes do not break legacy.
- Run the linters
ruff check src
mypy src
or
tox -e ruff
tox -e mypy
- Run the tests.
tox -e py
- Check test coverage.
tox -e cov
firefox htmlcov/index.html
- Create a pull request. Here's where you can check up on it:
- GitHub Actions status —
https://github.com/cantools/cantools/actions/workflows/pythonpackage.yml - Coverage reports —
https://coveralls.io/github/cantools/cantools?branch=master
cantools.database.load_file
cantools.database.load_file(filename, database_format=None, encoding=None, frame_id_mask=None, prune_choices=False, strict=True, cache_dir=None, sort_signals=<function sort_signals_by_start_bit>)
This one opens, reads and parses the given database file, and hands you back a can.Database or diagnostics.Database object full of its contents. It's giving "the door to everything else" tbh 🔥
database_format is one of 'arxml', 'dbc', 'kcd', 'sym', cdd and None. If it's None, the database format gets picked based on the filename extension, like in this table. And heads up — filename extensions are case insensitive 👑
.arxml→'arxml'.dbc→'dbc'.kcd→'kcd'.sym→'sym'.cdd→'cdd'<unknown>→None
encoding specifies the file encoding. If it's None, the encoding gets picked based on the database format, like in this table. And if you want platform dependent encoding, use open() and load() instead bestie.
'arxml'→'utf-8''dbc'→'cp1252''kcd'→'utf-8''sym'→'cp1252''cdd'→'utf-8'None→'utf-8'
prune_choices abbreviates the names of choices by removing a common prefix ending on an underscore. If you want the original names you need to pass prune_choices = False. Don't let it prune your faves 💅
cache_dir specifies the database cache location in the file system. Give it as None to disable the cache. By default the cache is disabled, but it can be enabled with the environment variable CANTOOLS_CACHE_DIR. The cache key is the db path with its modification time, plus all arguments that may influence the result. Using a cache will significantly reduce the load time when you're reloading the same file. The cache directory is automatically created if it doesn't exist. Remove the cache directory cache_dir to clear the cache. It requires the optional diskcache package (pip install cantools[cache]), and if that's not installed, a warning is issued and caching is disabled. No cache for you, sorry 🥲
See load_string() for descriptions of the other arguments.
It raises an UnsupportedDatabaseFormatError exception if the given file does not contain a supported database format.
>>> db = cantools.database.load_file('foo.dbc')
>>> db.version
'1.0'
📋 Parameters
filename (str | PathLike[str])— thestrdocs live at/usr/share/doc/python3/html/library/stdtypes.html#str, and thePathLikedocs at/usr/share/doc/python3/html/library/os.html#os.PathLike, wherePathLikeis parameterized withstragain (/usr/share/doc/python3/html/library/stdtypes.html#str).database_format (str | None)—strdocs at/usr/share/doc/python3/html/library/stdtypes.html#str.encoding (str | None)—strdocs at/usr/share/doc/python3/html/library/stdtypes.html#str.frame_id_mask (int | None)—intdocs at/usr/share/doc/python3/html/library/functions.html#int.prune_choices (bool)—booldocs at/usr/share/doc/python3/html/library/functions.html#bool.strict (bool)—booldocs at/usr/share/doc/python3/html/library/functions.html#bool.cache_dir (str | None)—strdocs at/usr/share/doc/python3/html/library/stdtypes.html#str.sort_signals (Callable[[list[Signal]], list[Signal]] | Literal['default'] | None)—Callabledocs at/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable,listdocs at/usr/share/doc/python3/html/library/stdtypes.html#list, andLiteraldocs at/usr/share/doc/python3/html/library/typing.html#typing.Literal.
🎀 Return type
Database | Database
cantools.database.dump_file
cantools.database.dump_file(database, filename, database_format=None, encoding=None, sort_signals='default')
Dumps the given database database to the given file filename. Yeah. That's the whole job. And it does it flawlessly 😌
Depending on the output file format, signals may be sorted by default. If you don't want signals to be sorted, pass sort_signals=None. And ok here's the cute part — sort_signals=None is assumed by default if you have passed sort_signals=None to load_file. If you want the signals sorted in a special way, pass something like:
sort_signals = lambda signals: list(sorted(signals, key=lambda sig: sig.name))
For dbc files the default is to sort the signals by their start bit in descending order. For kcd files the default is to not sort the signals. periodt ✨
See load_file() for descriptions of other arguments.
The 'dbc' database format will always have Windows-style line endings (\r\n). For other database formats the line ending depends on the operating system. 🫶
>>> db = cantools.database.load_file('foo.dbc')
>>> cantools.database.dump_file(db, 'bar.dbc')
Pass sort_signals=None, prune_choices=False to load_file in order to minimize the differences between foo.dbc and bar.dbc. 💅
Parameters
database(Database)filename(str </usr/share/doc/python3/html/library/stdtypes.html#str> | PathLike </usr/share/doc/python3/html/library/os.html#os.PathLike>[str </usr/share/doc/python3/html/library/stdtypes.html#str>])database_format(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)encoding(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)sort_signals(Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None)
Return type: None
🦋 cantools.database.load_string(string, database_format=None, frame_id_mask=None, prune_choices=False, strict=True, sort_signals=<function sort_signals_by_start_bit>)
Parse a given database string and return a can.Database or diagnostics.Database object stuffed with its contents. Bestie, it eats strings and gives you databases. 🌸
database_format may be one of 'arxml', 'dbc', 'kcd', 'sym', 'cdd' or None, where None means transparent format.
prune_choices is a bool indicating whether signal names are supposed to be abbreviated by stripping a common prefix ending on an underscore. This is enabled by default.
See can.Database for a description of strict.
sort_signals is a function taking a list of signals as argument and returning a list of signals. By default signals are sorted by their start bit when their Message object is created. If you don't want them to be sorted pass sort_signals = None. If you want the signals to be sorted in another way pass something like:
sort_signals = lambda signals: list(sorted(signals, key=lambda sig: sig.name))
Raises an UnsupportedDatabaseFormatError exception if the given string does not contain a supported database format. 😭 (rude of it, honestly.)
>>> with open('foo.dbc') as fin:
... db = cantools.database.load_string(fin.read())
>>> db.version
'1.0'
Parameters
string(str </usr/share/doc/python3/html/library/stdtypes.html#str>)database_format(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)frame_id_mask(int </usr/share/doc/python3/html/library/functions.html#int> | None)prune_choices(bool </usr/share/doc/python3/html/library/functions.html#bool>)strict(bool </usr/share/doc/python3/html/library/functions.html#bool>)sort_signals(Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None)
Return type: Database | Database
💜 cantools.database.load(fp, database_format=None, frame_id_mask=None, prune_choices=False, strict=True, sort_signals=<function sort_signals_by_start_bit>)
Read and parse a given database file-like object and hand you back a can.Database or diagnostics.Database object with all its contents. file-like object in, whole database out, iconic behavior.
See load_string() for descriptions of other arguments.
Raises an UnsupportedDatabaseFormatError exception if the given file-like object does not contain a supported database format. 💀
>>> with open('foo.kcd') as fin:
... db = cantools.database.load(fin)
>>> db.version
None
Parameters
fp(TextIO </usr/share/doc/python3/html/library/typing.html#typing.TextIO>)database_format(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)frame_id_mask(int </usr/share/doc/python3/html/library/functions.html#int> | None)prune_choices(bool </usr/share/doc/python3/html/library/functions.html#bool>)strict(bool </usr/share/doc/python3/html/library/functions.html#bool>)sort_signals(Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None)
Return type: Database | Database
👑 class cantools.database.can.Database(messages=None, nodes=None, buses=None, version=None, dbc_specifics=None, autosar_specifics=None, frame_id_mask=None, strict=True, sort_signals=<function sort_signals_by_start_bit>)
This class contains all messages, signals and definitions of a CAN network. it's giving main character energy, fr fr.
The factory functions load(), load_file() and load_string() return instances of this class.
If strict is True an exception is raised if any signals are overlapping or if they don't fit in their message. ⚠️ so keep it strict unless you know what you're doing.
By default signals are sorted by their start bit when their Message object is created. If you don't want them to be sorted pass sort_signals = None. If you want the signals to be sorted in another way pass something like:
sort_signals = lambda signals: list(sorted(signals, key=lambda sig: sig.name))
Parameters
messages(list </usr/share/doc/python3/html/library/stdtypes.html#list>[Message] | None)nodes(list </usr/share/doc/python3/html/library/stdtypes.html#list>[Node] | None)buses(list </usr/share/doc/python3/html/library/stdtypes.html#list>[Bus] | None)version(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)dbc_specifics(DbcSpecifics | None)autosar_specifics(AutosarDatabaseSpecifics | None)frame_id_mask(int </usr/share/doc/python3/html/library/functions.html#int> | None)strict(bool </usr/share/doc/python3/html/library/functions.html#bool>)sort_signals(Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None)property messages:list </usr/share/doc/python3/html/library/stdtypes.html#list>[Message]— a list of messages in the database. Useget_message_by_frame_id()orget_message_by_name()to find a message by its frame id or name. 🎀property nodes:list </usr/share/doc/python3/html/library/stdtypes.html#list>[Node]— a list of nodes in the database.property buses:list </usr/share/doc/python3/html/library/stdtypes.html#list>[Bus]— a list of CAN buses in the database.property version:str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>— the database version, orNoneif unavailable.property dbc:DbcSpecifics | None </usr/share/doc/python3/html/library/constants.html#None>— an object containing dbc specific properties like e.g. attributes.property autosar:AutosarDatabaseSpecifics | None </usr/share/doc/python3/html/library/constants.html#None>— an object containing AUTOSAR specific properties like e.g. attributes.is_similar(other, *, tolerance=1e-12, include_format_specifics=True)— compare two database objects inexactly. This means that small discrepanceies stemming from e.g. rounding errors are ignored. Parametersother(Database)tolerance(float </usr/share/doc/python3/html/library/functions.html#float>)include_format_specifics(bool </usr/share/doc/python3/html/library/functions.html#bool>) Return type:bool </usr/share/doc/python3/html/library/functions.html#bool>
add_arxml(fp)— read and parse ARXML data from a given file-like object and add the parsed data to the database. ✨
...and the last bit of that one's signature, since we got cut off ✨
fp— aTextIO, bestie 🫶
Return type: None
💖 add_arxml_file(filename, encoding='utf-8') 💖
Open it, read it, parse it — this one takes ARXML data from a file and drops the parsed goodies straight into the database ✨
encoding tells it what the file encoding is, iykyk.
Parameters:
filename—str | PathLike[str]encoding—str
Return type: None
🦋 add_arxml_string(string) 🦋
Already got the ARXML data as a string instead of a whole file? Say less. This parses it and adds the parsed data to the database 💅
Parameters:
string—str
Return type: None
🎀 add_dbc(fp) 🎀
Reads and parses DBC data from whatever file-like object you hand it and adds the parsed data to the database. No cap 💖
>>> db = cantools.database.Database()
>>> with open ('foo.dbc', 'r') as fin:
... db.add_dbc(fin)
Parameters:
fp— aTextIO
Return type: None
🌸 add_dbc_file(filename, encoding='cp1252') 🌸
Opens, reads and parses DBC data from the given file and adds the parsed data to the database 🫶
encoding specifies the file encoding — and bestie, the default here is cp1252, not UTF-8. Noted. 📝
>>> db = cantools.database.Database()
>>> db.add_dbc_file('foo.dbc')
Parameters:
filename—str | PathLike[str]encoding—str
Return type: None
⭐ add_dbc_string(string) ⭐
Parses the DBC data you already have as a string and adds the parsed data to the database. Iconic ✨
>>> db = cantools.database.Database()
>>> with open ('foo.dbc', 'r') as fin:
... db.add_dbc_string(fin.read())
Parameters:
string—str
Return type: None
🧚 add_kcd(fp) 🧚
Reads and parses KCD data from a file-like object and adds the parsed data into the database 🌈
Parameters:
fp— aTextIO
Return type: None
💜 add_kcd_file(filename, encoding='utf-8') 💜
Opens, reads and parses KCD data from the given file and adds the parsed data to the database 🎀
encoding specifies the file encoding (default is 'utf-8', slay).
Parameters:
filename—str | PathLike[str]encoding—str
Return type: None
🔥 add_kcd_string(string) 🔥
Parses the given KCD data string and adds the parsed data to the database. Ate 💅
Parameters:
string—str
Return type: None
🍓 add_sym(fp) 🍓
Reads and parses SYM data from a file-like object and adds the parsed data to the database ✨
Parameters:
fp— aTextIO
Return type: None
🦄 add_sym_file(filename, encoding='utf-8') 🦄
Opens, reads and parses SYM data from the given file and adds the parsed data to the database 🫶
encoding specifies the file encoding (again, default 'utf-8').
Parameters:
filename—str | PathLike[str]encoding—str
Return type: None
💀 add_sym_string(string) 💀
Parses the given SYM data string and adds the parsed data to the database. Easy money 🌸
Parameters:
string—str
Return type: None
👑 as_dbc_string(*, sort_signals='default', sort_attribute_signals='default', sort_attributes=None, sort_choices=None, shorten_long_names=True) 👑
Hands the database back to you as a string formatted like a DBC file. Periodt 💅
sort_signals defines how to sort signals in message definitions.
sort_attribute_signals defines how to sort signals in metadata — comments, value table definitions and attributes.
Parameters:
sort_signals—Callable[[list[Signal]], list[Signal]] | Literal['default'] | Nonesort_attribute_signals—Callable[[list[Signal]], list[Signal]] | Literal['default'] | Nonesort_attributes— okay so this type annotation is a whole novel, bestie, buckle up 😭:
Callable[[list[tuple[Literal['dbc'], AttributeType, None, None, None, None] | tuple[~typing.Literal['node'], AttributeType, Node, None, None, None] | tuple[~typing.Literal['message'], AttributeType, None, Message, None, None] | tuple[~typing.Literal['signal'], AttributeType, None, Message, Signal, None] | tuple[~typing.Literal['envvar'], AttributeType, None, None, None, EnvironmentVariable]]], list[tuple[~typing.Literal['dbc'], AttributeType, None, None, None, None] | tuple[~typing.Literal['node'], AttributeType, Node, None, None, None] | tuple[~typing.Literal['message'], AttributeType, None, Message, None, None] | tuple[~typing.Literal['signal'], AttributeType, None, Message, Signal, None] | tuple[~typing.Literal['envvar'], AttributeType, None, None, None, EnvironmentVariable]]] | ~typing.Literal['default'] | None
sort_choices—Callable[[OrderedDict[int, str | NamedSignalValue]], OrderedDict[int, str | NamedSignalValue]] | Noneshorten_long_names—bool
Return type: str
🌈 as_kcd_string(*, sort_signals='default') 🌈
Return the database as a string formatted as a KCD file. 🎀
Finishing up that parameter list we were mid-way through, bestie — last one, promise 🫶
sort_signals— typed asCallable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None
Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str>
🌸 as_sym_string(*, sort_signals='default') 🌸
Hands you the whole database back as a string, all formatted like a SYM file 💅 Literally the SYM file of your dreams, as text.
Parameters
sort_signals—Callable </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Callable>[[list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]], list </usr/share/doc/python3/html/library/stdtypes.html#list>[Signal]] | Literal </usr/share/doc/python3/html/library/typing.html#typing.Literal>['default'] | None
Return type: str </usr/share/doc/python3/html/library/stdtypes.html#str>
🦋 get_message_by_name(name) 🦋
Finds you the message object for the name name. Your little message-finder 🫶
Parameters
name—str </usr/share/doc/python3/html/library/stdtypes.html#str>
Return type: Message
🎀 get_message_by_frame_id(frame_id, force_extended_id=False) 🎀
Same energy, but by frame id instead of name — finds the message object for the given frame id frame_id ✨
Parameters
frame_id—int </usr/share/doc/python3/html/library/functions.html#int>force_extended_id—bool </usr/share/doc/python3/html/library/functions.html#bool>
Return type: Message
💜 get_node_by_name(name) 💜
Finds the node object for the name name. Node hunting, slay 🔥
Parameters
name—str </usr/share/doc/python3/html/library/stdtypes.html#str>
Return type: Node
🌈 get_bus_by_name(name) 🌈
Finds the bus object for the name name. Getting the whole bus together, periodt 🚌
Parameters
name—str </usr/share/doc/python3/html/library/stdtypes.html#str>
Return type: Bus
🔥 encode_message(frame_id_or_name, data, scaling=True, padding=False, strict=True, force_extended_id=False) 🔥
Encodes the given signal data data as a message of the given frame id or name frame_id_or_name.
Okay so for regular Messages, data is a dictionary of signal name-value entries. For container messages, it's a list of (ContainedMessageOrMessageName, ContainedMessageSignals) tuples. Two different shapes, both giving ✨
If scaling is False, no scaling of signals is performed — none, zero, zip.
If padding is True, unused bits get encoded as 1.
If strict is True, every single signal value has to sit inside its allowed range, or an exception gets raised. No vibes-based out-of-range nonsense here, bestie 😭
>>> db.encode_message(158, {'Bar': 1, 'Fum': 5.0})
b'\x01\x45\x23\x00\x11'
>>> db.encode_message('Foo', {'Bar': 1, 'Fum': 5.0})
b'\x01\x45\x23\x00\x11'
Parameters
frame_id_or_name—int </usr/share/doc/python3/html/library/functions.html#int> | str </usr/share/doc/python3/html/library/stdtypes.html#str>data—Mapping </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Mapping>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue] | Sequence </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[Message | str </usr/share/doc/python3/html/library/stdtypes.html#str> | int </usr/share/doc/python3/html/library/functions.html#int>, bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes> | Mapping </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Mapping>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue]]]scaling—bool </usr/share/doc/python3/html/library/functions.html#bool>padding—bool </usr/share/doc/python3/html/library/functions.html#bool>strict—bool </usr/share/doc/python3/html/library/functions.html#bool>force_extended_id—bool </usr/share/doc/python3/html/library/functions.html#bool>
Return type: bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>
💖 decode_message(frame_id_or_name, data, decode_choices=True, scaling=True, decode_containers=False, allow_truncated=False, force_extended_id=False) 💖
Decodes the given signal data data as a message of the given frame id or name frame_id_or_name. You get back a dictionary of signal name-value entries. Chef's kiss 👑
If decode_choices is False, scaled values do not get converted into choice strings (even if those strings are available). They stay numeric, fr fr.
If scaling is False, no scaling of signals is performed.
>>> db.decode_message(158, b'\x01\x45\x23\x00\x11')
{'Bar': 1, 'Fum': 5.0}
>>> db.decode_message('Foo', b'\x01\x45\x23\x00\x11')
{'Bar': 1, 'Fum': 5.0}
If decode_containers is True, container frames get decoded. The reason this has to be switched on explicitly is that decoding container frames returns a list of (Message, SignalsDict) tuples, and that will make code which does not expect it misbehave 😭
⚠️ Trying to decode a container message withdecode_containersset toFalsewill raise aDecodeError. Yes, it will. It's giving consequences.
Parameters
frame_id_or_name—int </usr/share/doc/python3/html/library/functions.html#int> | str </usr/share/doc/python3/html/library/stdtypes.html#str>data—bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>decode_choices—bool </usr/share/doc/python3/html/library/functions.html#bool>scaling—bool </usr/share/doc/python3/html/library/functions.html#bool>decode_containers—bool </usr/share/doc/python3/html/library/functions.html#bool>allow_truncated—bool </usr/share/doc/python3/html/library/functions.html#bool>force_extended_id—bool </usr/share/doc/python3/html/library/functions.html#bool>
Return type: dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue] | Sequence </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence>[tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[Message, Mapping </usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Mapping>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue]] | tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[Message, bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>] | tuple </usr/share/doc/python3/html/library/stdtypes.html#tuple>[int </usr/share/doc/python3/html/library/functions.html#int>, bytes </usr/share/doc/python3/html/library/stdtypes.html#bytes>]]
🧚 refresh() 🧚
Refreshes the internal database state.
💀 This method must be called after modifying any message in the database, to refresh the internal lookup tables that get used when encoding and decoding messages. Skip it and your lookups are living in the past, bestie.
Return type: None
👑 cantools.database.can.Message
okay bestie, meet the moment: a CAN message with a frame id, a comment, signals and a whole bunch of other info. it's giving main character energy in the database, no cap.
class cantools.database.can.Message(frame_id, name, length, signals,
contained_messages=None, header_id=None, header_byte_order='big_endian',
unused_bit_pattern=0, comment=None, senders=None, send_type=None,
cycle_time=None, dbc_specifics=None, autosar_specifics=None,
is_extended_frame=False, is_fd=False, bus_name=None, signal_groups=None,
strict=True, protocol=None, sort_signals=<function
sort_signals_by_start_bit>)
If strict is True, an exception gets thrown if any signals are overlapping or if they straight up don't fit in the message. 🚨 so like, strict mode is not playing around.
By default, signals are sorted by their start bit the moment the Message object is created. If you do not want them sorted, pass sort_signals = None. If you want them sorted a different way, pass something like sort_signals = lambda signals: list(sorted(signals, key=lambda sig: sig.name)). slay, custom sorting is yours 💅
Parameters
frame_id(int)name(str)length(int)signals(list[Signal])contained_messages(list[Message]|None)header_id(int|None)header_byte_order(str)unused_bit_pattern(int)comment(str|dict[str | None, str]|None)senders(list[str]|None)send_type(str|None)cycle_time(int|None)dbc_specifics(DbcSpecifics|None)autosar_specifics(AutosarMessageSpecifics|None)is_extended_frame(bool)is_fd(bool)bus_name(str|None)signal_groups(list[SignalGroup]|None)strict(bool)protocol(str|None)sort_signals(Callable[[list[Signal]], list[Signal]]|Literal['default']|None)
✨ the properties, aka the lore drops ✨
header_id(int|None) — the header ID of the message if it is part of a container message. otherwise, nothing to see here 🫣header_byte_order(str) — the byte order of the header ID of the message if it is part of a container message.frame_id(int) — the message frame id. the whole identity fr.is_extended_frame(bool) —Trueif the message is an extended frame,Falseotherwise.is_fd(bool) —Trueif the message requires CAN-FD,Falseotherwise. can-fd girlies rise 🔥name(str) — the message name as a string.length(int) — the message data length in bytes.signals(list[Signal]) — a list of all signals in the message. the whole squad 💖is_container(bool) — returns if the message is a container message.contained_messages(list[Message]) — the list of messages potentially contained within this message. it's messages all the way down 🌀unused_bit_pattern(int) — the pattern used for unused bits of a message.
This prevents undefined behaviour and/or information leaks when encoding messages. so like, do not skip this one, it's literally protecting you 🙈
signal_groups(list[SignalGroup]|None) — a list of all signal groups in the message.comment(str|None) — the message comment, orNoneif unavailable.
Note that we implicitly try to return the English comment if multiple languages were specified. anglophone default behaviour, iconic honestly 💅
comments(dict[str | None, str]|None) — the dictionary with the descriptions of the message in multiple languages.Noneif unavailable. multilingual queen 🌈senders(list[str]) — a list of all sender nodes of this message.receivers(set[str]) — a set of all receiver nodes of this message.
This is equivalent to the set of nodes which receive at least one of the signals contained in the message. math is mathing 🧮
send_type(str|None) — the message send type, orNoneif unavailable.cycle_time(int|None) — the message cycle time, orNoneif unavailable.dbc(DbcSpecifics|None) — an object containing dbc specific properties like e.g. attributes.autosar(AutosarMessageSpecifics|None) — an object containing AUTOSAR specific properties
e.g. auxiliary data required to implement CRCs, secure on-board communication (secOC) or container messages. very fancy, very secure, we love her 🎀
bus_name(str|None) — the message bus name, orNoneif unavailable.protocol(str|None) — the message protocol, orNoneif unavailable. Only one protocol is currently supported;'j1939'. that's the whole roster, bestie.signal_tree(Sequence[str | dict[str, dict[int, Sequence[str]]]]) — all signal names and multiplexer ids as a tree. Multiplexer signals are dictionaries, while other signals are strings.
watch this:
>>> foo = db.get_message_by_name('Foo')
>>> foo.signal_tree
['Bar', 'Fum']
>>> bar = db.get_message_by_name('Bar')
>>> bar.signal_tree
[{'A': {0: ['C', 'D'], 1: ['E']}}, 'B']
look at that structure. nested dictionaries popping off. iykyk 🌸
🫶 gather_signals(input_data, node=None)
Given a superset of all signals required to encode the message, return a dictionary containing exactly the ones required. no extras, no crumbs, just the essentials ✨
If a required signal is missing from the input dictionary, a EncodeError exception is raised. so like, don't be sloppy with your input dict or you WILL hear about it 😭
Parameters
…and it closes out with these two, bestie:
input_data— aMappingofstr→int|float|str|NamedSignalValue🫶node— either aCodecorNone
Return type — dict of str → int | float | str | NamedSignalValue ✨
💡 okay so the Python docs links on all the types in this chunk are long, so here's the legend once and then we keep it cute — everydict,str, etc. below points at exactly one of these paths: -dict→/usr/share/doc/python3/html/library/stdtypes.html#dict-list→/usr/share/doc/python3/html/library/stdtypes.html#list-str→/usr/share/doc/python3/html/library/stdtypes.html#str-bytes→/usr/share/doc/python3/html/library/stdtypes.html#bytes-tuple→/usr/share/doc/python3/html/library/stdtypes.html#tuple-int→/usr/share/doc/python3/html/library/functions.html#int-float→/usr/share/doc/python3/html/library/functions.html#float-bool→/usr/share/doc/python3/html/library/functions.html#bool-Mapping→/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Mapping-Sequence→/usr/share/doc/python3/html/library/collections.abc.html#collections.abc.Sequence
🎀 gather_container(contained_messages, signal_values) 🎀
Okay so you hand it a superset of every message you'd need to encode all the messages featured by a container message, and it hands you back a list of (Message, SignalDict) tuples that you can yeet straight into encode(). 🫶
If a required signal is missing from that input dictionary, it raises an EncodeError exception — no vibes, just error. 😭
Parameters
contained_messages— alistofMessage|str|int🌸signal_values— aMappingofstr→int|float|str|NamedSignalValue
Return type — a Sequence of:
tupleof[Message, Mapping[str, int | float | str | NamedSignalValue]]- or
tupleof[Message, bytes] - or
tupleof[int, bytes]💅
🦋 assert_signals_encodable(input_data, scaling, assert_values_valid=True, assert_all_known=True) 🦋
Given a dictionary of signal name → signal value mappings, this one makes sure that all the signals required for encoding are present. ✨
At minimum, literally every signal required to encode the message has to be specified. If they aren't? KeyError or EncodeError gets raised. Periodt.
And depending on the parameters you picked, the data in your dictionary has to clear some extra requirements:
Parameters
scaling—bool. IfFalse, no scaling of signals is performed. 📏assert_values_valid—bool. IfTrue, the values of all specified signals must be valid/encodable. If at least one of them isn't, anEncodeErrorexception is raised. (Note that the values of multiplexer selector signals must always be valid!) ⚠️assert_all_known—bool. IfTrue, all specified signals must actually be used by the encoding operation, otherwise anEncodeErrorexception is raised. This is lowkey the bestie that catches your typos. 💖input_data— aMappingofstr→int|float|str|NamedSignalValue
Return type — None
🧚 assert_container_encodable(input_data, scaling, assert_values_valid=True, assert_all_known=True) 🧚
This method is identical to assert_signals_encodable() — like, literally the same energy — except it's the one that cares about container messages. 🌈
Parameters
input_data— aSequenceoftupleof[Message | str | int, bytes | Mapping[str, int | float | str | NamedSignalValue]]🙈scaling—boolassert_values_valid—boolassert_all_known—bool
(no extra description on these ones, the OG page just gives the types — slay, we respect it) 💅
Return type — None
👑 encode(data, scaling=True, padding=False, strict=True) 👑
Encode the given data as a message of this type. This is the glow-up moment. ✨
If the message is an "ordinary" frame, this method expects a key-to-value dictionary as data, mapping the name of every required signal to a value that can be encoded by that signal. 🍓
But if the current message is a container message, it expects a list of (contained_message, contained_data) tuples, where contained_message is either an integer with the header ID, the name, or the message object of the contained message. And contained_data can either be given as raw binary data (bytes) or as a key-to-value dictionary of every signal needed to encode the featured message. 🫶
- If
scalingisFalse, no scaling of signals is performed. - If
paddingisTrue, unused bits are encoded as1. 1️⃣ - If
strictisTrue, the specified signals must exactly be the ones expected, and their values must be within their allowed ranges — otherwise anEncodeErrorexception is raised. ⚠️
>>> foo = db.get_message_by_name('Foo')
>>> foo.encode({'Bar': 1, 'Fum': 5.0})
b'\x01\x45\x23\x00\x11'
Parameters
okay bestie we're still deep in the Message object's method zone and this next chunk is a lot of typing — but it's all just "here's what you can hand me, and here's what comes back," so breathe 💖. Continuing that param list from right before:
data— the payload, and it's gotta be one of these:
Mapping[str, int | float | str | NamedSignalValue] | Sequence[tuple[Message | str | int, bytes] | Mapping[str, int | float | str | NamedSignalValue]]
scaling—boolpadding—boolstrict—bool
Return type — bytes 🎀
🧸 unpack_container(data, allow_truncated=False)
Unwrap the contents of a container message. It's giving "unzip but for CAN frames" ✨
This hands you back a list of (contained_message, contained_data) tuples. And no cap — the data for the contained message here are bytes objects, not decoded signal dictionaries. That's the whole point: you need it raw so you can verify the correctness of the end-to-end protection, or check the authenticity of a contained message. 🫶
Note that contained_message is the header ID integer value if a contained message is unknown. And further, if something goes seriously wrong, a DecodeError is raised. 😭
Parameters
data—bytesallow_truncated—bool
Return type
Sequence[tuple[Message, bytes] | tuple[int, bytes]]
💫 decode(data, decode_choices=True, scaling=True, decode_containers=False, allow_truncated=False, allow_excess=True)
Decode given data as a message of this type. The main character method, honestly 👑
If decode_choices is False, scaled values are not converted to choice strings (if available).
If scaling is False, no scaling of signals is performed.
Obsessed with this little demo, it's so cute:
>>> foo = db.get_message_by_name('Foo')
>>> foo.decode(b'\x01\x45\x23\x00\x11')
{'Bar': 1, 'Fum': 5.0}
If decode_containers is True, the inner messages are decoded if the current message is a container frame. The reason why this needs to be explicitly enabled is that the result of decode() for container frames is a list of (header_id, signals_dict) tuples, which might cause code that does not expect this to misbehave. So like — consent first, basically. 🙈 Trying to decode a container message with decode_containers set to False will raise a DecodeError.
If allow_truncated is True, incomplete messages (i.e., ones where the received data is shorter than specified) will be partially decoded, i.e., all signals which are fully present in the received data will be decoded, and the remaining ones will be omitted. If allow_truncated is set to False, DecodeError will be raised when trying to decode incomplete messages. 🚨
If allow_excess is True, data that is are longer than the expected message length is decoded, else a ValueError is raised if such data is encountered.
Parameters
data—bytesdecode_choices—boolscaling—booldecode_containers—boolallow_truncated—boolallow_excess—bool
Return type
dict[str, int | float | str | NamedSignalValue] | Sequence[tuple[Message, Mapping[str, int | float | str | NamedSignalValue]] | tuple[Message, bytes] | tuple[int, bytes]]
🌸 decode_simple(data, decode_choices=True, scaling=True, allow_truncated=False, allow_excess=True)
Decode given data as a container message.
This method is identical to decode() except that the message must not be a container. If the message is a container, an exception is raised. 💀
Parameters
data—bytesdecode_choices—boolscaling—boolallow_truncated—boolallow_excess—bool
Return type
dict[str, int | float | str | NamedSignalValue]
🦋 decode_container(data, decode_choices=True, scaling=True, allow_truncated=False, allow_excess=True)
Decode given data as a container message.
This method is identical to decode() except that the message must be a container. If the message is not a container, an exception is raised. Flip side of the coin, periodt. ✨
Parameters
data—bytesdecode_choices—boolscaling—boolallow_truncated—boolallow_excess—bool
so the thing that hands you back a value there? bestie it hands back a whole inventory, it's giving luggage carousel at 2am:
Sequence[tuple[Message, Mapping[str, int | float | str | NamedSignalValue]] | tuple[Message, bytes] | tuple[int, bytes]]
which lowkey reads as "here's your message, and here's the stuff that came attached to it". every type in that signature is hyperlinked in the docs out to the Python stdlib HTML pages sitting under /usr/share/doc/python3/html/library/ — Sequence and Mapping live in collections.abc, tuple/str in stdtypes, int/float/bool in functions, None in constants. the whole stdlib tour, no cap. 🦋
Return type: that whole Sequence[...] situation up there ↑
✨ is_multiplexed() ✨
gives you back True if the message is multiplexed, and False if it isn't. that's the entire job. she's simple, she's effective, she ate. 💅
>>> foo = db.get_message_by_name('Foo')
>>> foo.is_multiplexed()
False
>>> bar = db.get_message_by_name('Bar')
>>> bar.is_multiplexed()
True
Return type: bool
🔄 refresh(strict=None) 🔄
refreshes the internal message state. like, you're telling the message to re-check itself, comb its hair, redo the math, be the main character again. 🎀
if strict is True, an exception gets raised if any signals are overlapping, or if they simply don't fit in the message. heads up though: this argument overrides whatever value you passed for that same argument to the constructor. so when you say it here, this one wins. periodt. 👑
Parameters: strict (bool | None)
Return type: None
🧚 class cantools.database.can.Signal(name, start, length, byte_order='little_endian', is_signed=False, raw_initial=None, raw_invalid=None, conversion=None, minimum=None, maximum=None, unit=None, dbc_specifics=None, comment=None, receivers=None, is_multiplexer=False, multiplexer_ids=None, multiplexer_signal=None, spn=None)
a CAN signal with position, size, unit and other information. a signal is part of a message, bestie. it's the little guy inside the big guy. 🌸
signal bit numbering in a message:
Byte: 0 1 2 3 4 5 6 7
+--------+--------+--------+--------+--------+--------+--------+--------+--- - -
| | | | | | | | |
+--------+--------+--------+--------+--------+--------+--------+--------+--- - -
Bit: 7 0 15 8 23 16 31 24 39 32 47 40 55 48 63 56
big endian signal with start bit 2 and length 5 (0=LSB, 4=MSB):
Byte: 0 1 2 3
+--------+--------+--------+--- - -
| |432|10| | |
+--------+--------+--------+--- - -
Bit: 7 0 15 8 23 16 31
little endian signal with start bit 2 and length 9 (0=LSB, 8=MSB):
Byte: 0 1 2 3
+--------+--------+--------+--- - -
|543210| | |876| |
+--------+--------+--------+--- - -
Bit: 7 0 15 8 23 16 31
🌈 Parameters 🌈
name(str)start(int)length(int)byte_order(Literal['little_endian', 'big_endian'])is_signed(bool)raw_initial(int|float|None)raw_invalid(int|float|None)conversion(BaseConversion|None)minimum(float|None)maximum(float|None)unit(str|None)dbc_specifics(DbcSpecifics|None)comment(str|dict[str | None, str]|None)receivers(list[str]|None)is_multiplexer(bool)multiplexer_ids(list[int]|None)multiplexer_signal(str|None)spn(int|None)
💖 the attributes, one by one 💖
name(str) — the signal name, as a string. iconic.conversion(BaseConversion) — the conversion instance, and it's the thing doing the converting between raw values and scaled/physical values.minimum(float|None) — the scaled minimum value of the signal, orNoneif there isn't one.maximum(float|None) — the scaled maximum value of the signal, orNoneif there isn't one.start(int) — the start bit position of the signal inside its message.length(int) — the length of the signal, in bits.byte_order(Literal['little_endian', 'big_endian']) — the signal byte order, as'little_endian'or'big_endian'.is_signed(bool) —Trueif the signal is signed,Falseotherwise. ignore this attribute ifis_floatisTrue. (she said what she said.)raw_initial(int|float|None) — the internal representation of the initial value of the signal, orNoneif it's unavailable.initial(int|float|str|NamedSignalValue|None) — the initial value of the signal in units of the physical world, orNoneif it's unavailable.raw_invalid(int|float|None) — the raw value that means "this signal is invalid", orNoneif it's unavailable.invalid(int|float|str|NamedSignalValue|None) — the scaled value that means "this signal is invalid", orNoneif it's unavailable.unit(str|None) — the unit of the signal as a string, orNoneif it's unavailable.dbc(DbcSpecifics) — an object holding dbc specific properties, like e.g. attributes.receivers(list[str]) — a list of all the receiver nodes of this signal.is_multiplexer(bool) —Trueif this is the multiplexer signal in a message,Falseotherwise.multiplexer_ids(list[int]|None) — the multiplexer ids list, if the signal is part of a multiplexed message;Noneotherwise.multiplexer_signal: str | None— the multiplexer signal if this signal is part of a multiplexed message, andNoneotherwise. iykyk.spn: int | None— the J1939 Suspect Parameter Number (SPN) value when the signal has this attribute,Nonewhen it doesn't. 🙈comments: dict[str | None, str] | None— the dict with all the descriptions of the signal in multiple languages.Noneif it's just not available. 😭
raw_to_scaled(raw_value, decode_choices=True)
okay so this one converts an internal raw value according to the defined scaling or value table. slay.
Parameters
raw_value(int | float) — the raw value 🫶decode_choices(bool) — ifdecode_choicesisFalse, scaled values are not converted to choice strings (if available).
Returns — the calculated scaled value ✨
Return type — int | float | str | NamedSignalValue
scaled_to_raw(scaled_value)
the reverse glow-up: converts a scaled value back to the internal raw value. 💅
Parameters
scaled_value(int | float | str | NamedSignalValue) — the scaled value.
Returns — the internal raw value.
Return type — int | float
property scale: int | float
the scale factor of the signal value. iconic.
property offset: int | float
the offset of the signal value.
property choices: OrderedDict[int, str | NamedSignalValue] | None
a dictionary mapping signal values to enumerated choices, or None if it's not available. 🎀
property is_float: bool
True if the raw signal value is a float, False otherwise. simple math bestie.
property comment: str | None
the signal comment, or None if unavailable.
note that we implicitly try to return the English comment if multiple languages were specified. 💖
🔥 class cantools.database.can.Node(name, comment=None, dbc_specifics=None, autosar_specifics=None)
an NODE on the CAN bus. main character of the network fr fr.
Parameters
name(str)comment(str | dict[str | None, str] | None)dbc_specifics(DbcSpecifics | None)autosar_specifics(AutosarNodeSpecifics | None)
property name: str
the node name as a string. ✨
property comment: str | None
the node's comment, or None if unavailable.
note that we implicitly try to return the English comment if multiple languages were specified.
property comments: dict[str | None, str] | None
the dictionary with the descriptions of the bus in multiple languages. None if unavailable.
property dbc: DbcSpecifics
an object containing dbc specific properties like e.g. attributes.
property autosar: AutosarNodeSpecifics
an object containing AUTOSAR specific properties of the node. 💜
🦋 class cantools.database.can.Bus(name, comment=None, baudrate=None, fd_baudrate=None, autosar_specifics=None)
a CAN bus. the literal backbone, no cap.
Parameters
name(str)comment(str | dict[str | None, str] | None)baudrate(int | None)fd_baudrate(int | None)autosar_specifics(AutosarBusSpecifics | None)
property name: str
the bus name as a string. 💅
property comment: str | None
the bus' comment, or None if unavailable.
note that we implicitly try to return the English comment if multiple languages were specified.
property comments: dict[str | None, str] | None
the dictionary with the descriptions of the bus in multiple languages. None if unavailable.
property baudrate: int | None
the bus baudrate, or None if unavailable.
property fd_baudrate: int | None
the baudrate used for the payload of CAN-FD frames, or None if unavailable. 🔥
property autosar: TypeAliasForwardRef('cantools.database.can.formats.arxml.AutosarBusSpecifics') | None
an object containing AUTOSAR specific properties of the bus.
🌸 class cantools.database.can.signal_group.SignalGroup(name, repetitions=1, signal_names=None)
a CAN signal group. signal groups are used to define a group of signals within a message, e.g. to define that the signals of a group have to be updated in common. squad goals, literally. 🫶
Parameters
name(str)repetitions(int)signal_names(list[str] | None)
property name: str
the signal group name as a string.
property repetitions: int
the signal group repetitions.
property signal_names: list[str]
the signal names in the signal group 💖
⭐ class cantools.database.can.attribute_definition.AttributeDefinition(name, default_value=None, kind=None, type_name=None, minimum=None, maximum=None, choices=None)
a definition of an attribute that can be associated with attributes in nodes/messages/signals. the blueprint era. 👑
Parameters
name(str)default_value—AttributeValueType | None✨kind—str </usr/share/doc/python3/html/library/stdtypes.html#str> | Nonetype_name—str </usr/share/doc/python3/html/library/stdtypes.html#str> | Noneminimum—int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | Nonemaximum—int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | Nonechoices—list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | None
Bestie, now the actual properties of that attribute definition, one by one, no skipping 💅
- property
name:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the attribute name, as a string. That's it, that's the girl 💖 - property
default_value:AttributeValueType | None </usr/share/doc/python3/html/library/constants.html#None>— the default value this attribute has, orNoneif it's just not available. No cap. - property
kind:str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>— the attribute kind — that'sBU_,BO_,SG_— orNoneif unavailable. - property
type_name:str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>— the attribute type, soINT,HEX,FLOAT,STRING,ENUM, orNoneif unavailable. - property
minimum:int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | None </usr/share/doc/python3/html/library/constants.html#None>— the minimum value of the attribute, orNoneif unavailable. - property
maximum:int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float> | None </usr/share/doc/python3/html/library/constants.html#None>— the maximum value of the attribute, orNoneif unavailable. - property
choices:list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]— a dictionary mapping attribute values to enumerated choices, orNoneif unavailable.
🦋 class cantools.database.can.attribute_definition.AttributeValueType
Okay so this one is literally just an alias — <cyan>alias of TypeVar('AttributeValueType', str, int, float)</cyan>. Copy it, don't fight it, it's iconic.
🌸 class cantools.database.can.attribute.Attribute(value, definition)
An attribute that can be associated with nodes / messages / signals. The little tag-along friend that all three of them can have 💜
Parameters
value(AttributeValueType)definition(AttributeDefinition[AttributeValueType])
And the properties, bestie:
- property
name:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the attribute name as a string. - property
value:AttributeValueType— the value that this attribute actually has. - property
definition:AttributeDefinition[AttributeValueType]— the attribute definition. The blueprint. The lore.
🧚 class cantools.database.can.environment_variable.EnvironmentVariable(name, env_type, minimum, maximum, unit, initial_value, env_id, access_type, access_node, comment, dbc_specifics)
A CAN environment variable. Yeah, those exist, and yes, they have eleven constructor args. We stay strong 😭
Parameters
name(str </usr/share/doc/python3/html/library/stdtypes.html#str>)env_type(int </usr/share/doc/python3/html/library/functions.html#int>)minimum(int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>)maximum(int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>)unit(str </usr/share/doc/python3/html/library/stdtypes.html#str>)initial_value(int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>)env_id(int </usr/share/doc/python3/html/library/functions.html#int>)access_type(str </usr/share/doc/python3/html/library/stdtypes.html#str>)access_node(str </usr/share/doc/python3/html/library/stdtypes.html#str>)comment(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)dbc_specifics(DbcSpecifics)
Properties, go off 💅
- property
name:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the environment variable name as a string. - property
env_type:int </usr/share/doc/python3/html/library/functions.html#int>— the environment variable's type value. - property
minimum:int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>— the minimum value of the environment variable. - property
maximum:int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>— the maximum value of the environment variable. - property
unit:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the units the environment variable is expressed in, as a string. - property
initial_value:int </usr/share/doc/python3/html/library/functions.html#int> | float </usr/share/doc/python3/html/library/functions.html#float>— the initial value of the environment variable. - property
env_id:int </usr/share/doc/python3/html/library/functions.html#int>— the id value of the environment variable. - property
access_type:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the environment variable access type as a string. - property
access_node:str </usr/share/doc/python3/html/library/stdtypes.html#str>— the environment variable access node as a string. - property
comment:str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>— the environment variable comment, orNoneif unavailable. (Me when someone asks me to explain my feelings 🙈) - property
dbc:DbcSpecifics— an object containing dbc specific properties like e.g. attributes. The extra-lore container, iykyk.
🎀 class cantools.database.can.formats.dbc_specifics.DbcSpecifics(attributes=None, attribute_definitions=None, environment_variables=None, value_tables=None, attributes_rel=None, attribute_definitions_rel=None)
Parameters
attributes(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, Attribute[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | Attribute[int </usr/share/doc/python3/html/library/functions.html#int>] | Attribute[float </usr/share/doc/python3/html/library/functions.html#float>]] | None)attribute_definitions(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, AttributeDefinition[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | AttributeDefinition[int </usr/share/doc/python3/html/library/functions.html#int>] | AttributeDefinition[float </usr/share/doc/python3/html/library/functions.html#float>]] | None)environment_variables(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, EnvironmentVariable] | None)value_tables(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[int </usr/share/doc/python3/html/library/functions.html#int>, str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue]] | None)attributes_rel(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[int </usr/share/doc/python3/html/library/functions.html#int>, dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[Any </usr/share/doc/python3/html/library/typing.html#typing.Any>, Any </usr/share/doc/python3/html/library/typing.html#typing.Any>]] | None)attribute_definitions_rel(OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, AttributeDefinition[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | AttributeDefinition[int </usr/share/doc/python3/html/library/functions.html#int>] | AttributeDefinition[float </usr/share/doc/python3/html/library/functions.html#float>]] | None)attributes— the DBC specific attributes of the parent object (database, node, message or signal), handed over as a dictionary. 🫶OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, Attribute[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | Attribute[int </usr/share/doc/python3/html/library/functions.html#int>] | Attribute[float </usr/share/doc/python3/html/library/functions.html#float>]]attribute_definitions— the DBC specific attribute definitions, as a dictionary. ✨OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, AttributeDefinition[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | AttributeDefinition[int </usr/share/doc/python3/html/library/functions.html#int>] | AttributeDefinition[float </usr/share/doc/python3/html/library/functions.html#float>]]value_tables— an ordered dictionary of all the value tables. Heads up bestie: this one is only valid for DBC specifiers on database level. 🎀OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[int </usr/share/doc/python3/html/library/functions.html#int>, str </usr/share/doc/python3/html/library/stdtypes.html#str> | NamedSignalValue]]environment_variables— an ordered dictionary of all the environment variables. Same tiny caveat as above: only valid for DBC specifiers on database level. 🌸OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, EnvironmentVariable]attributes_rel— the DBC specific attribute rel, as a dictionary. 🦋OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[int </usr/share/doc/python3/html/library/functions.html#int>, dict </usr/share/doc/python3/html/library/stdtypes.html#dict>[Any </usr/share/doc/python3/html/library/typing.html#typing.Any>, Any </usr/share/doc/python3/html/library/typing.html#typing.Any>]]attribute_definitions_rel— the DBC specific attribute definitions rel, as a dictionary. 💜OrderedDict </usr/share/doc/python3/html/library/collections.html#collections.OrderedDict>[str </usr/share/doc/python3/html/library/stdtypes.html#str>, AttributeDefinition[str </usr/share/doc/python3/html/library/stdtypes.html#str>] | AttributeDefinition[int </usr/share/doc/python3/html/library/functions.html#int>] | AttributeDefinition[float </usr/share/doc/python3/html/library/functions.html#float>]]
🌈 cantools.database.can.formats.arxml.AutosarDatabaseSpecifics(arxml_version)
This class collects the AUTOSAR specific information of a system. (yes, a whole system, it's giving main character energy fr)
Parameters
arxml_version(str </usr/share/doc/python3/html/library/stdtypes.html#str>)
Properties
arxml_version—str </usr/share/doc/python3/html/library/stdtypes.html#str>The used version of the ARXML file format. 💅
⚠️ Note that due to technical reasons we always return version "4.0.0" for AUTOSAR 4.X. Not a bug, just how it is, bestie.
🦋 cantools.database.can.formats.arxml.AutosarMessageSpecifics
This class collects all the AUTOSAR specific information of a CAN message. 🚗
Which means: it holds all the genuinely useful info about CAN messages that ARXML files give you, but that is specific to AUTOSAR.
Properties
pdu_paths—list </usr/share/doc/python3/html/library/stdtypes.html#list>[str </usr/share/doc/python3/html/library/stdtypes.html#str>]The ARXML paths of all PDUs featured by this message. 🛣️
For the vast majority of messages this list only has a single entry. Messages with multiplexers and container frames are different, though — they be collecting paths like Pokémon cards.
is_nm—bool </usr/share/doc/python3/html/library/functions.html#bool>Trueiff the message is used for network management. 📡is_general_purpose—bool </usr/share/doc/python3/html/library/functions.html#bool>Trueiff the message is not used for signal-based communication. 🙈
This comprises messages used for diagnostic and calibration purpuses, e.g. messages used for the ISO-TP or XCP protocols.
is_secured—bool </usr/share/doc/python3/html/library/functions.html#bool>Trueiff the message integrity is secured using SecOC. 🔐secoc—AutosarSecOCProperties | None </usr/share/doc/python3/html/library/constants.html#None>The properties required to implement secured on-board communication. 👑e2e—AutosarEnd2EndProperties | None </usr/share/doc/python3/html/library/constants.html#None>Returns the end-to-end protection properties for the message. 🛡️
🧚 cantools.database.can.formats.arxml.AutosarNodeSpecifics
This class collects the AUTOSAR specific information of a node that is attached to a CAN bus.
AUTOSAR calls such nodes "ECU instances"... and honestly, slay, we love a fancy name for a node. 💅✨
🔥 cantools.database.can.formats.arxml.AutosarSecOCProperties(auth_algorithm_name, freshness_algorithm_name, payload_length, data_id, auth_tx_bit_length, freshness_bit_length, freshness_tx_bit_length)
This class collects all the attributes that are required to implement the AUTOSAR secure on-board communication (SecOC) specification. 🔐
⚠️ Be aware that the AUTOSAR SecOC specification does not cover the required cryptographic primitives themselves, just the "scaffolding" around them... so don't come for this class expecting actual crypto, bestie.
Parameters
auth_algorithm_name(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)freshness_algorithm_name(str </usr/share/doc/python3/html/library/stdtypes.html#str> | None)payload_length(int </usr/share/doc/python3/html/library/functions.html#int> | None)data_id(int </usr/share/doc/python3/html/library/functions.html#int> | None)auth_tx_bit_length(int </usr/share/doc/python3/html/library/functions.html#int> | None)freshness_bit_length(int </usr/share/doc/python3/html/library/functions.html#int> | None)freshness_tx_bit_length(int </usr/share/doc/python3/html/library/functions.html#int> | None)
Properties
freshness_algorithm_name—str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>The name of the algorithm used for verifying the freshness of a message. ⏰
This can be used to prevent replay attacks. Note that the algorithms themselves are manufacturer-specific, i.e., AUTOSAR does not define any freshness schemes.
auth_algorithm_name—str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>The name of the algorithm used for authentication. 🔑
Note that the algorithms themselves are manufacturer-specific, i.e., AUTOSAR does not define any cryptographic schemes.
payload_length—int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None>Returns the number of bytes covered by the payload of the secured message. 📏
(The full message length is the length of the payload plus the size of the security trailer. Math is mathin'.)
data_id—int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None>The data ID required for authentication.
⚠️ Be aware that this is a different data ID than the one required for End-To-End protection. Two separate IDs, do not mix them up, that's a whole mess. 😭
freshness_bit_length—int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None>The number of bits of the full freshness counter. 🔢freshness_tx_bit_length—int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None>The number of least-significant bits of the freshness counter that is send as part of the secured frame. ✨
This number is at most as large as the number of bits of freshness counter objects.
auth_tx_bit_length—int </usr/share/doc/python3/html/library/functions.html#int> | None </usr/share/doc/python3/html/library/constants.html#None>The number of most significant bits of the authenticator object send as part of the secured frame. 🔐
This is at most the length of the authenicator.
💖 cantools.database.can.formats.arxml.AutosarEnd2EndProperties
This class collects all the attributes that are required to implement AUTOSAR-conformant End-to-End protection (CRCs) of messages. 🛡️ No cap, this is the CRC crew.
Properties
category—str </usr/share/doc/python3/html/library/stdtypes.html#str> | None </usr/share/doc/python3/html/library/constants.html#None>The category string of the applicable end-to-end protection mechanism. 🏷️
Note that the contents of these are not specified by the AUTOSAR standard.
data_ids—list </usr/share/doc/python3/html/library/stdtypes.html#list>[int </usr/share/doc/python3/html/library/functions.html#int>] | None </usr/share/doc/python3/html/library/constants.html#None>The list of data IDs applicable. 📋payload_length:int— the size of the end-to-end protected data, in bytes 💾
And bestie, this number is a big number, because it includes the end-to-end protection signals themselves — that's the sequence counter and the CRC value. So don't come for me when the byte count looks one or two sizes bigger than your actual payload, that's just the protection overhead doing its thing. 🛡️
🦋 cantools.database.can.formats.arxml.AutosarBusSpecifics
This class collects the AUTOSAR specific information of a CAN bus. That's it, that's the whole vibe — it's the little bag where all the AUTOSAR-only bus gossip lives. 🚌
✨ cantools.database.namedsignalvalue.NamedSignalValue(value, name, comments=None)
Okay so this one represents a named value of a signal, and lowkey it's iconic.
Named values map an integer number to a human-readable string. Like, 3 isn't just 3, it's "Reverse". Periodt. And some file formats (looking at you, ARXML 👀) support specifying descriptions for the named value too, so you get the whole lore.
Parameters
value(int)name(str)comments(dict[str, str] | None)
Attributes, bestie:
name— the text intended for human consumption which the specified integer is mapped to. iykyk.value— the integer value that gets mapped. 🎯
Property comments: dict[str, str] — the descriptions of the named value.
This is a dictionary containing the descriptions in multiple languages, and the dictionary is indexed by the language. Very multilingual of it, honestly. 🌈
Example, because examples are self-care:
# retrieve the English comment of the named value or an empty
# string if none was specified.
named_value.comments.get("EN", "")
🎀 cantools.database.conversion.BaseConversion
The BaseConversion class defines the interface for all signal conversion classes. It's giving founding mother of the conversion hierarchy, she's not doing the work herself, she's just setting the rules. 👑
scale: float— the scaling factor of the conversion 📏offset: float— the offset value of the conversion ➕is_float: bool—Trueif the raw/internal value is a floating datatype,Falseif it is an integer datatype. So it's a yes-or-no on "is this thing floaty or whole-ish" 🫧choices: OrderedDict[int, str | NamedSignalValue] | None— an optional mapping of raw values to their corresponding text value. Optional! She can beNone, she contains multitudes. 💅
⭐ static factory(scale=1, offset=0, choices=None, is_float=False)
Factory method that returns an instance of a conversion subclass based on the given parameters. Yeah, she's a factory, she makes the right subclass for you so you don't have to pick. So generous.
Parameters
scale(float) -- The scale factor to use for the conversion.offset(float) -- The offset to use for the conversion.choices(OrderedDict[int, str | NamedSignalValue] | None) -- A dictionary of named signal choices, mapping raw values to string labels.is_float(bool) -- A boolean flag indicating whether the raw value is a float or an integer.
Returns An instance of a conversion subclass, either an IdentityConversion, a LinearIntegerConversion, a LinearConversion or a NamedSignalConversion. Pick your fighter!! 🥊
Raises TypeError -- If the given parameters are of the wrong type. (Not me handing her a string where a float goes 😭)
Return type BaseConversion
💜 abstractmethod raw_to_scaled(raw_value, decode_choices=True)
Convert an internal raw value according to the defined scaling or value table.
Parameters
raw_value(int | float) -- The raw valuedecode_choices(bool) -- Ifdecode_choicesisFalsescaled values are not converted to choice strings (if available).
Returns The calculated scaled value
Return type int | float | str | NamedSignalValue
💜 abstractmethod scaled_to_raw(scaled_value)
Convert a scaled value to the internal raw value. It's the reverse direction, the little boomerang move 🪃
Parameters scaled_value (int | float | str | NamedSignalValue) -- The scaled value.
Returns The internal raw value.
Return type int | float
💜 abstractmethod numeric_scaled_to_raw(scaled_value)
Convert a numeric scaled value to the internal raw value. No strings allowed here bestie, numbers only, this is a string-free zone 🚫🔤
Parameters scaled_value (int | float) -- The numeric scaled value.
Returns The internal raw value.
Return type int | float
🩺 cantools.database.diagnostics.Database(dids=None)
This class contains all DIDs. All of them. Every single one. 💖
The factory functions load(), load_file() and load_string() return instances of this class, in case you were wondering how you'd ever get your hands on one.
Parameters dids (list[Did] | None)
Property dids: list[Did] | None — A list of DIDs in the database. She can be None! She can be a whole list! Versatile queen. 🌸
🌟 add_cdd(fp)
Read and parse CDD data from given file-like object and add the parsed data to the database.
Parameters fp (TextIO)
Return type None
🌟 add_cdd_file(filename, encoding='utf-8')
Open, read and parse CDD data from given file and add the parsed data to the database.
encoding specifies the file encoding. Default is 'utf-8', as is correct and right. 🙏
Parameters
filename(str | PathLike[str])encoding(str)
Return type None
🌟 add_cdd_string(string)
Parse given CDD data string and add the parsed data to the database.
Parameters string (str)
Return type None
🔍 get_did_by_name(name)
Find the DID object for given name name.
Parameters name (str)
Return type Did
🔍 get_did_by_identifier(identifier)
Find the DID object for given identifier identifier.
Parameters identifier (int)
Return type Did
🔄 refresh()
Refresh the internal database state.
⚠️ Okay this one is important, bestie, listen up: this method must be called after modifying any DIDs in the database to refresh the internal lookup tables used when encoding and decoding DIDs.
Not me forgetting to call refresh() and then wondering why my lookup tables are lying to me 💀 Don't be me. Call refresh().
Return type None
🧚 cantools.database.diagnostics.Did(identifier, name, length, datas)
A DID with identifier and other information. She's a whole little package. 🎁
Parameters
So the DID class comes with these bad boys right here:
identifier(int) — the whole identifier vibe, as an intname(str) — the name, as a strlength(int) — the length, as an intdatas(list[Data]) — the did datas as a string
property identifier: int
The DID identifier, but make it an integer ✨
property name: str
The DID name, as a string 🎀
property length: int
The DID length, as an int 💅
property datas: list[Data]
The DID datas, as a string 🌸
encode(data, scaling=True)
Encode the data you hand it into a DID of this type. Lowkey the main character of this whole class fr fr.
Heads up bestie: ifscalingisFalse, no scaling of datas is performed.
>>> foo = db.get_did_by_name('Foo')
>>> foo.encode({'Bar': 1, 'Fum': 5.0})
b'\x01\x45\x23\x00\x11'
Parameters
data(Mapping[str, int | float | str | NamedSignalValue])scaling(bool)
Return type
bytes
decode(data, decode_choices=True, scaling=True, allow_truncated=False, allow_excess=True)
Decode the data you give it as a DID of this type. The reverse slay 🦋
Ifdecode_choicesisFalse, scaled values are not converted to choice strings (even if they're available). IfscalingisFalse, no scaling of datas is performed.
>>> foo = db.get_did_by_name('Foo')
>>> foo.decode(b'\x01\x45\x23\x00\x11')
{'Bar': 1, 'Fum': 5.0}
Parameters
data(bytes)decode_choices(bool)scaling(bool)allow_truncated(bool)allow_excess(bool)
Return type
dict[str, int | float | str | NamedSignalValue]
refresh()
Refresh the internal DID state. That's it, that's the whole method 💖
Return type
None
class cantools.database.diagnostics.Data(name, start, length, byte_order='little_endian', conversion=None, minimum=None, maximum=None, unit=None)
A data data with position, size, unit and other information. A data is part of a DID, obviously 💫
Parameters
name(str)start(int)length(int)byte_order(Literal['little_endian', 'big_endian'])conversion(BaseConversion | None)minimum(float | None)maximum(float | None)unit(str | None)
name: str
The data name, as a string ✨
conversion
The conversion instance, which is used to convert between raw and scaled/physical values. It's giving translator energy 🔥
start: int
The start bit position of the data within its DID.
length
The length of the data in bits.
byte_order: Literal['little_endian', 'big_endian']
Data byte order, either 'little_endian' or 'big_endian'. Pick your fighter 😭
minimum: float | None
The minimum value of the data, or None if it's unavailable.
maximum: float | None
The maximum value of the data, or None if it's unavailable.
unit
The unit of the data as a string, or None if it's unavailable.
raw_to_scaled(raw_value, decode_choices=True)
Convert an internal raw value according to the defined scaling or value table. Glow-up but make it numbers 🧚
Parameters
raw_value(int | float) — the raw valuedecode_choices(bool) — ifdecode_choicesisFalse, scaled values are not converted to choice strings (if available)
Returns
The calculated scaled value
Return type
int | float | str | NamedSignalValue
scaled_to_raw(scaled_value)
Convert a scaled value to the internal raw value. The reverse glow-down, iconic 🌈
Parameters
scaled_value(int | float | str | NamedSignalValue) — the scaled value
Returns
The internal raw value
Return type
int | float
property scale: int | float
The scale factor of the signal value.
property offset: int | float
The offset of the signal value.
property choices: OrderedDict[int, str | NamedSignalValue] | None
A dictionary mapping signal values to enumerated choices, or None if it's unavailable. Not me obsessing over choice strings 🙈
property is_float: bool
True if the raw signal value is a float, False otherwise. Vibe check on the type bestie 💅
class cantools.database.UnsupportedDatabaseFormatError(e_arxml, e_dbc, e_kcd, e_sym, e_cdd)
This exception gets raised when load_file(), load() and load_string() can't parse the database file or string you gave them. She's dramatic but valid 💀
Parameters
e_arxml(Exception | None)e_dbc(Exception | None)e_kcd(Exception | None)e_sym(Exception | None)e_cdd(Exception | None)
class cantools.tester.Tester(dut_name, database, can_bus, bus_name=None, on_message=None, decode_choices=True, scaling=True, padding=False, strict=True)
Test the given node dut_name on the given CAN bus bus_name. Okay so this one is literally the whole testing era 👑
database is a Database instance.
can_bus is a CAN bus object, normally created using the python-can package.
The on_message callback is called for every successfully decoded received message. It's called with one argument — a DecodedMessage instance. And yes, the docs said "an DecodedMessage", we don't fix typos around here, we respect the lore 🫶
Okay bestie, so the previous bit was showing you how to define a tester class — now let's actually use one. Here's the glow-up: 💅
>>> import can
>>> import cantools
>>> can.rc['interface'] = 'socketcan'
>>> can.rc['channel'] = 'vcan0'
>>> can_bus = can.interface.Bus()
>>> database = cantools.database.load_file('tests/files/tester.kcd')
>>> tester = cantools.tester.Tester('PeriodicConsumer', database, can_bus, 'PeriodicBus')
And then it's method time, no cap. ⭐
start() This is the "go bestie go" button ✨ It starts the tester, which means it starts sending all the enabled periodic messages.
>>> tester.start()
stop() Pauses the whole vibe. After this call, periodic messages will not be sent anymore. If you wanna get back in the game, call start() again to resume a stopped tester.
>>> tester.stop()
property messages Bestie, this is where you set and get signals inside messages. Setting signals takes effect immediately for started, enabled periodic messages — like instantly, no cap. For anything else, you call send().
>>> periodic_message = tester.messages['PeriodicMessage1']
>>> periodic_message
{'Signal1': 0, 'Signal2': 0}
>>> periodic_message['Signal1'] = 1
>>> periodic_message.update({'Signal1': 2, 'Signal2': 5})
>>> periodic_message
{'Signal1': 2, 'Signal2': 5}
enable(message_name) Enables the message called message_name, and starts sending it if it's periodic and the tester is running. ✨
>>> tester.enable('PeriodicMessage1')
disable(message_name) The opposite vibe — disables message_name and stops sending it if it's periodic, enabled, and the tester is running.
>>> tester.disable('PeriodicMessage1')
send(message_name, signals=None) Sends the message message_name, plus the optional signals if you got 'em.
>>> tester.send('Message1', {'Signal2': 10})
>>> tester.send('Message1')
expect(message_name, signals=None, timeout=None, discard_other_messages=True) Waits for the message message_name with the signal values signals, within timeout seconds. 🕐
Give signals as None if you're chill with literally any signal values.
Give timeout as None to wait forever. (Main character patience, honestly. 👑)
Messages get read from the input queue, and any that don't match message_name and signals get discarded if discard_other_messages is True. If you wanna clear out all the old stuff sitting in the input queue first, call flush_input() before you call the expect function.
It returns the expected message — or None if it timed out. 😭
>>> tester.expect('Message2', {'Signal1': 13})
{'Signal1': 13, 'Signal2': 9}
flush_input() Flushes — aka discards — all messages sitting in the input queue. Clean slate, periodt. ✨
🌈 class cantools.tester.DecodedMessage(name, signals)
A decoded message. Simple as that.
name— the message name.signals— the message signals.
🌸 class cantools.typechecking.Codec
No description given, and we're not making one up. Moving on bestie. 💖
Now, the coding style for this package is defined down below. The rules are based on one person's personal preference, so it's giving very this-is-how-we-do-things-here. 🙈
- Blank lines before and after statements (
if,while,return, ...) (1), unless at beginning or end of another statement or file (8). - Two blank lines between file level definitions (2).
- Space before and after operators (3), except for keyword arguments where no space is allowed (4).
- One import per line (5).
- Comments and doc strings starts with capital letter and ends with a period, that is, just as sentences (6).
- Blank line after doc strings (7).
- Maximum line length of 90 characters, but aim for less than 80.
- All function arguments on one line, or one per line.
- Class names are CamelCase. Underscore is not allowed.
- Function and variable names are lower case with underscore separating words.
And here's the whole thing demonstrated in one glorious block — those little # (n) markers are pointing back at the rules above, iykyk: 🔥
import sys
from os import path # (5)
from os import getcwd # (5)
# (2)
# (2)
def foo(bars, fum=None): # (4)
"""This is a doc string. # (6)
"""
# (7)
fies = [] # (3)
kam = path.join(getcwd(), '..')
# (1)
for bar in bars:
if len(bar) == 1): # (8)
fies.append(ham + 2 * bar) # (3)
# (1)
# This is a comment. # (6)
if fum in None:
fum = 5 # (3)
else:
fum += 1 # (3)
# (1)
fies *= fum # (3)
# (1)
return fies
# (2)
# (2)
def goo():
return True
🦋 Virtual CAN interface setup in Ubuntu
Wanna run this on a virtual bus? Say less. 🎀
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 mtu 72 # For CAN-FD
sudo ip link set up vcan0
Heads up bestie: that mtu 72 line is the one that matters if you're doing CAN-FD. Don't skip it and then wonder why things are weird. 💀
👑 Author
Erik Moqvist. Iconic behavior, honestly.
💜 Copyright
2015-2023, Erik Moqvist.
Aaaand that's a wrap on CANTOOLS(1), bestie! 🫶 This page is version 42.0, dated Jul 11, 2026 — so go forth, decode those frames, and slay. ✨🚗💅
📦 where this page comes from
- ubuntu stonking: python3-cantools 42.0.3+ds-1
- 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms