OVMS3/OVMS.V3/components/vehicle_dbc/docs/dbc-primer.rst

193 lines
7.8 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

================
DBC Introduction
================
DBC is a CAN data description file format introduced by `Vector Informatik GmbH <https://www.vector.com/>`_.
DBC files are text files so can be created and edited using a simple text editor like the one built into
the OVMS web UI.
DBC files can be used to support vehicles that don't have a dedicated native adaption yet. This is done
using the generic DBC vehicle type, which can use DBC files to translate CAN data into metrics.
This section tries to show you how to create and use a DBC specification on the OVMS. Of course
you'll need to know how to decode your vehicle's CAN frames first. You can use the OVMS RE (reverse
engineering) toolkit to identify which messages are on the bus and which changes correlate to
actions and status on the car.
There's also a very good general introduction to DBC from CSS Electronics including an explanatory video:
https://www.csselectronics.com/screen/page/can-dbc-file-database-intro/language/en
DBC files only specify the passive (reading) part, they don't provide a means to define transmissions.
If you need to send frames to request certain information, you can still use the OVMS DBC engine to
decode the results (instead of doing the decoding in C++ code). So a DBC file can be used as a base
for a real vehicle module. To request OBD2 data during development, you can use the ``re obdii``
commands.
-------------
Basic Example
-------------
.. warning::
The DBC support is usable, but considered to be an alpha release.
The way it works may change in the future.
This example is taken from the **Twizy**, which sends some primary BMS status data at CAN ID 0x155 (341).
Note: the Twizy module actually does not use DBC, this is just an example how you would decode this
message if using DBC.
**Message example**: ``05 96 E7 54 6D 58 00 6F``
- Byte 0: charge current limit [A], scaled by 5, no offset: ``05``**25A**
- Bytes 1+2: momentary battery current [A], big endian, lower 12 bits, scaled by -0.25, offset +500: ``_6 E7``**58.25A**
- Bytes 4+5: SOC [%], big endian, scaled by 0.0025, no offset: ``6D 58``**69.98%**
These can be translated to metrics directly:
- Charge current limit: ``v.c.climit``
- Momentary battery current: ``v.b.current``
- Battery SOC: ``v.b.soc``
---------------
Create DBC File
---------------
**Copy & paste** the following into a new editor window:
.. code-block:: none
VERSION "DBC Example 1.0"
BS_: 500000 : 0,0
BO_ 341 BMS_1: 8 Vector__XXX
SG_ v_c_climit : 7|8@0+ (5,0) [0|35] "A" Vector__XXX
SG_ v_b_current : 11|12@0+ (-0.25,500) [-500|1000] "A" Vector__XXX
SG_ v_b_soc : 39|16@0+ (0.0025,0) [0|100] "%" Vector__XXX
**What does this mean?**
- ``BS_`` defines the bus speed (500 kbit in this example) and bit timings (unused)
- ``BO_`` defines the data object, a CAN frame of length 8 with ID 341 (0x155) ("BMS_1" is just an arbitrary name)
- ``SG_`` lines define the signals (values) embedded in the object (see below)
- ``Vector__XXX`` is just a placeholder for any sender/receiver (currently unused by the OVMS)
**Signals** are defined by their…
- Name (= metric name with ``.`` replaced by ``_``)
- Start position (bit position) and bit length (``7|8``)
- Endianness: ``0`` = big endian (most significant byte first), ``1`` = little endian (least significant byte first) (Note: the DBC format documentation is wrong on this)
- Signedness: ``+`` = unsigned, ``-`` = signed
- Scaling and offset: ``(-0.25,500)`` => real value = raw value * -0.25 + 500
- Minimum/maximum: ``[-500|1000]`` = valid real values are in the range -500 to 1000
- Unit: e.g. ``"A"`` (ignored/irrelevant, defined by the metric)
The metric to set can be given as the name of the signal. You may use the metric name directly
on the OVMS, but to conform to the DBC standard, replace the dots by ``_``.
**Bit positions** are counted from byte 0 upwards by their significance, regardless of the endianness.
The first message byte has bits 0…7 with bit 7 being the most significant bit of the byte. The
second byte has bits 8…15 with bit 15 being the MSB, and so on:
.. code-block:: none
[ 7 6 5 4 3 2 1 0 ] [ 15 14 13 12 11 10 9 8 ] [ 23 22 21 20 …
`----- Byte 0 ----´ `------- Byte 1 --------´ `----- Byte 2 …
For big endian values, signal start bit positions are given for the most significant bit. For
little endian values, the start position is that of the least significant bit.
.. note::
**On endianness**: "big endian" means a byte sequence of ``0x12 0x34`` decodes into ``0x1234``
(most significant byte first), "little endian" means the same byte sequence decodes into ``0x3412``
(least significant byte first). "Big endian" is the natural way of writing numbers, i.e. with their
most significant digit coming first, "little endian" is vice versa. Endianness only applies
to values of multiple bytes, single byte values are always written naturally / "big endian".
------------
Use DBC File
------------
**Save** the DBC example as: ``/store/dbc/twizy1.dbc`` (the directory will be created by the editor)
**Open the shell**. To see debug logs, issue ``log level debug dbc-parser`` and ``log level debug v-dbc``.
Note: the DBC parser currently isn't graceful on errors, **a wrong DBC file may crash the module**.
So you should only enable automatic loading of DBC files on boot when you're done developing
and testing it.
So let's first try if the **DBC engine can parse** our file. The ``dbc autoload`` command loads all
DBC files from the ``/store/dbc`` directory:
.. code-block:: none
OVMS# dbc autoload
Auto-loading DBC files...
D (238062) dbc-parser: VERSION parsed as: DBC Example 1.0
D (238062) dbc-parser: BU_ parsed 1 nodes
D (238062) dbc-parser: BO_ parsed message 341
D (238072) dbc-parser: SG_ parsed signal v_c_climit
D (238072) dbc-parser: SG_ parsed signal v_b_current
D (238082) dbc-parser: SG_ parsed signal v_b_soc
Looks good. ``dbc list`` can tell us some statistics:
.. code-block:: none
OVMS# dbc list
twizy1: DBC Example 1.0: 1 message(s), 3 signal(s), 56% coverage, 1 lock(s)
The coverage tells us how much of our CAN data bits are covered by signal definitions.
Now let's **load the file into the DBC vehicle**:
.. code-block:: none
OVMS# config set vehicle dbc.can1 twizy1
Parameter has been set.
OVMS# vehicle module NONE
I (1459922) v-none: Generic NONE vehicle module
OVMS# vehicle module DBC
I (249022) v-dbc: Pure DBC vehicle module
I (249022) v-dbc: Registering can bus #1 as DBC twizy1
Nice. Let's **simulate receiving our test frame** and check the decoded metrics:
.. code-block:: none
OVMS# can can1 rx standard 155 05 96 E7 54 6D 58 00 6F
OVMS# me li v.b.soc
v.b.soc 69.98%
OVMS# me li v.b.current
v.b.current 58.25A
OVMS# me li v.c.climit
v.c.climit 25A
So the decoding apparently works.
**To configure DBC mode for autostart** we now just need to set the DBC vehicle mode to be
loaded on vehicle startup, and to enable autoloading of the DBC files from ``/store/dbc``. You can
do so either by using the user interface page Config → Autostart (check "Autoload DBC files" and
set the vehicle type to "DBC"), or from the shell by…
.. code-block:: none
OVMS# config set auto dbc yes
OVMS# config set auto vehicle.type DBC
Try a reboot to see if everything works.
You can now add more objects and signals to your DBC file.
.. note::
During development of a DBC file, you'll need to reload the file frequently. The DBC engine
locks the currently used vehicle, so you'll need to unload the DBC vehicle (``vehicle module NONE``),
then reload the DBC file (``dbc autoload``), then reactivate the DBC vehicle (``vehicle module DBC``).