Create a Database

"""create_db.py -- Creating a .dbc database from scratch

This script will use canlib.kvadblib to create a new database file filled with
arbitrary data.

"""

import argparse
from collections import namedtuple

from canlib import kvadblib

Message = namedtuple('Message', 'name id dlc signals')
Signal = namedtuple('Signal', 'name size scaling limits unit')
EnumSignal = namedtuple('EnumSignal', 'name size scaling limits unit enums')

_messages = [
    Message(
        name='EngineData',
        id=100,
        dlc=8,
        signals=[
            Signal(
                name='PetrolLevel',
                size=(24, 8),
                scaling=(1, 0),
                limits=(0, 255),
                unit="l",
            ),
            Signal(
                name='EngPower',
                size=(48, 16),
                scaling=(0.01, 0),
                limits=(0, 150),
                unit="kW",
            ),
            Signal(
                name='EngForce',
                size=(32, 16),
                scaling=(1, 0),
                limits=(0, 0),
                unit="N",
            ),
            EnumSignal(
                name='IdleRunning',
                size=(23, 1),
                scaling=(1, 0),
                limits=(0, 0),
                unit="",
                enums={'Running': 0, 'Idle': 1},
            ),
            Signal(
                name='EngTemp',
                size=(16, 7),
                scaling=(2, -50),
                limits=(-50, 150),
                unit="degC",
            ),
            Signal(
                name='EngSpeed',
                size=(0, 16),
                scaling=(1, 0),
                limits=(0, 8000),
                unit="rpm",
            ),
        ],
    ),
    Message(
        name='GearBoxInfo',
        id=1020,
        dlc=1,
        signals=[
            Signal(
                name='EcoMode',
                size=(6, 2),
                scaling=(1, 0),
                limits=(0, 1),
                unit="",
            ),
            EnumSignal(
                name='ShiftRequest',
                size=(3, 1),
                scaling=(1, 0),
                limits=(0, 0),
                unit="",
                enums={'Shift_Request_On': 1, 'Shift_Request_Off': 0},
            ),
            EnumSignal(
                name='Gear',
                size=(0, 3),
                scaling=(1, 0),
                limits=(0, 5),
                unit="",
                enums={
                    'Idle': 0,
                    'Gear_1': 1,
                    'Gear_2': 2,
                    'Gear_3': 3,
                    'Gear_4': 4,
                    'Gear_5': 5,
                },
            ),
        ],
    ),
]


def create_database(name, filename):
    db = kvadblib.Dbc(name=name)

    for _msg in _messages:
        message = db.new_message(
            name=_msg.name,
            id=_msg.id,
            dlc=_msg.dlc,
        )

        for _sig in _msg.signals:
            if isinstance(_sig, EnumSignal):
                _type = kvadblib.SignalType.ENUM_UNSIGNED
                _enums = _sig.enums
            else:
                _type = kvadblib.SignalType.UNSIGNED
                _enums = {}
            message.new_signal(
                name=_sig.name,
                type=_type,
                byte_order=kvadblib.SignalByteOrder.INTEL,
                mode=kvadblib.SignalMultiplexMode.MUX_INDEPENDENT,
                size=kvadblib.ValueSize(*_sig.size),
                scaling=kvadblib.ValueScaling(*_sig.scaling),
                limits=kvadblib.ValueLimits(*_sig.limits),
                unit=_sig.unit,
                enums=_enums,
            )

    db.write_file(filename)
    db.close()


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Create a database from scratch.")
    parser.add_argument('filename', help=("The filename to save the database to."))
    parser.add_argument(
        '-n',
        '--name',
        default='Engine example',
        help=("The name of the database (not the filename, the internal name."),
    )
    args = parser.parse_args()

    create_database(args.name, args.filename)

Description

While the name of the created database and the filename it is saved as is passed as arguments to create_database, the contents of the database is defined in the variable _messages. This is a list of Message namedtuples that describes all the messages to be put in the database:

  • Their name, id, and dlc fields are passed to canlib.kvadblib.Dbc.new_message.

  • Their signals attribute is a list of Signal or EnumSignal namedtuples. All their fields will be passed to canlib.kvadblib.Dbc.new_signal.

Sample Output

With the _messages variable as shown above, the following .dbc file is created:

VERSION "HIPBNYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY/4/%%%/4/'%**4YYY///"


NS_ :
     NS_DESC_
     CM_
     BA_DEF_
     BA_
     VAL_
     CAT_DEF_
     CAT_
     FILTER
     BA_DEF_DEF_
     EV_DATA_
     ENVVAR_DATA_
     SGTYPE_
     SGTYPE_VAL_
     BA_DEF_SGTYPE_
     BA_SGTYPE_
     SIG_TYPE_REF_
     VAL_TABLE_
     SIG_GROUP_
     SIG_VALTYPE_
     SIGTYPE_VALTYPE_
     BO_TX_BU_
     BA_DEF_REL_
     BA_REL_
     BA_DEF_DEF_REL_
     BU_SG_REL_
     BU_EV_REL_
     BU_BO_REL_
     SG_MUL_VAL_

BS_:

BU_:


BO_ 100 EngineData: 8 Vector__XXX
 SG_ PetrolLevel : 24|8@1+ (1,0) [0|255] "l" Vector__XXX
 SG_ EngPower : 48|16@1+ (0.01,0) [0|150] "kW" Vector__XXX
 SG_ EngForce : 32|16@1+ (1,0) [0|0] "N" Vector__XXX
 SG_ IdleRunning : 23|1@1+ (1,0) [0|0] "" Vector__XXX
 SG_ EngTemp : 16|7@1+ (2,-50) [-50|150] "°C" Vector__XXX
 SG_ EngSpeed : 0|16@1+ (1,0) [0|8000] "rpm" Vector__XXX

BO_ 1020 GearBoxInfo: 1 Vector__XXX
 SG_ EcoMode : 6|2@1+ (1,0) [0|1] "" Vector__XXX
 SG_ ShiftRequest : 3|1@1+ (1,0) [0|0] "" Vector__XXX
 SG_ Gear : 0|3@1+ (1,0) [0|5] "" Vector__XXX


BA_DEF_  "BusType" STRING ;
BA_DEF_DEF_  "BusType" "";
BA_ "BusType" "CAN";
VAL_ 100 IdleRunning 0 "Running" 1 "Idle" ;
VAL_ 1020 ShiftRequest 1 "Shift_Request_On" 0 "Shift_Request_Off" ;
VAL_ 1020 Gear 0 "Idle" 2 "Gear_2" 1 "Gear_1" 5 "Gear_5" 3 "Gear_3" 4 "Gear_4" ;