# 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" ;