1

So i made a python script which can convert a DBC in an Excel and back using the library cantools. Turning the DBC-file into an Excel is no problem, but if i want to create a DBC out of the Excel-file and i assign the J1939 standard to a message, it won't show up in the DBC-file. Instead it only shows CAN extended.

I gave the message with the J1939 standard the attribute protocol="j1939" and save the DBC-file with dumpfile(db, "__.dbc"). Does anyone know if there is a special setting how i have to save the DBC-file, or if it is possible at all with cantools?

Here a short code example:

signal1 = cantools.db.can.Signal(name="signal1", start=1, length=8,
                                 is_signed=True, scale=1, offset=0, unit=None, spn=1586)

frame1 = cantools.db.can.Message(name="Msg1", frame_id=0x16fd3b09, protocol="j1939",
                                 is_extended_frame=True, length=8, signals=[signal1],
                                 cycle_time=50, senders=["A"])

db_cantools = cantools.db.can.Database(messages=[frame1])

cantools.db.dump_file(db_cantools, "test_db.dbc")

Picture of the DBC file in Vector CANdb (ID-Format is CAN Extended and not J1939).

For a different DBC file (which contains J1939 messages) i found with

db.dbc.attributes

a dict of attributes in my database:

OrderedDict([('ProtocolType', attribute('ProtocolType', J1939)),...)

I don't know if that would be the key, to create this attribute, but I also don't know how i do that. Also in the attributes of the messages i find j1939 but same problem (don't know how to create them).

Edit: I tried to create a J1939 template DBC file and added the messages there. It works, but messages which use the ID-Format CAN Standard or CAN Extended also turn into the ID-Format J1939.

1 Answers1

1

The quality of the documentation is unfortunately quite poor.

But looking into it, you will find that Database can take dbc_specifics as kwarg, which in turn should be of type DBCSpecifics.

In order to set the Database Protocol to J1939, you should create a key ProtocolType in _attribute_definitions with value of type AttributeDefinition.

I don't know if there is an easier way in the API to reach the same result (this one is extremely verbose), but the following will work:

import cantools.database as candb

dbc_spec = candb.can.formats.dbc_specifics.DbcSpecifics(
    attribute_definitions = {
        "ProtocolType": candb.can.attribute_definition.AttributeDefinition(
                            name = "ProtocolType",
                            default_value = 'J1939',
                            type_name = 'STRING'
                        )
    }
)

signal1 = candb.can.Signal(name="signal1", start=0, length=8,
                                 is_signed=True, unit=None, spn=1586)

frame1 = candb.can.Message(name="Msg1", frame_id=0x16fd3b09, protocol="j1939",
                                 is_extended_frame=True, length=8, signals=[signal1],
                                 cycle_time=50, senders=["A"])

db_cantools = candb.can.Database(messages=[frame1], dbc_specifics=dbc_spec)

candb.dump_file(db_cantools, "test_db.dbc")

Note that the current version of Signal doesn't seem to take scale and offset as kwarg but rather a conversion object.

Edit: you can set the protocol of messages individually with the attribute VFrameFormat. This should be first added to the attribute definitions of your dbc file. Then as attribute for the desired messages:

import cantools.database as candb

vframe_format = candb.can.attribute_definition.AttributeDefinition(
                            name = "VFrameFormat",
                            default_value = 3, # 0: CAN Standard; 1: CAN Extended; 3: J1939
                            type_name = 'INT',
                            kind='BO_'
                        )

dbc_spec = candb.can.formats.dbc_specifics.DbcSpecifics(
    attribute_definitions = {
        "ProtocolType": candb.can.attribute_definition.AttributeDefinition(
                            name = "ProtocolType",
                            default_value = 'J1939',
                            type_name = 'STRING'
                        ),
        'VFrameFormat': vframe_format
    }
)

signal1 = candb.can.Signal(name="signal1", start=0, length=8,
                                 is_signed=True, unit=None, spn=1586)


msg_spec_ext = candb.can.formats.dbc_specifics.DbcSpecifics(
    attributes = {'VFrameFormat': candb.can.attribute.Attribute(
                            value = 1,  # 0: CAN Standard; 1: CAN Extended; 3: J1939
                            definition = vframe_format
                        )}
)

frame1 = candb.can.Message(name="Msg1", frame_id=0x16fd3b09, protocol="j1939",
                                 is_extended_frame=True, length=8, signals=[signal1],
                                 cycle_time=50, senders=["A"], dbc_specifics=msg_spec_ext)

db_cantools = candb.can.Database(messages=[frame1], dbc_specifics=dbc_spec)

candb.dump_file(db_cantools, "test_db.dbc")

If you edit a DBC File with Vector CANdb++, you will see that VFrameFormat is an ENUM with the following values:

  • 0: StandardCAN
  • 1: ExtendedCAN
  • 3: J1939PG
  • 14: StandardCAN_FD
  • 15: ExtendedCAN_FD
Tranbi
  • 11,407
  • 6
  • 16
  • 33
  • Thanks for your answer @Tranbi! I tried it and it works, but if i want to import other messages (for example an Extended message without J1939) it turns it also into a J1939 message. CAN Standard still works. Do you have any idea how this could be fixed? – Sebastian Tramposch Aug 17 '23 at 10:17
  • 1
    @SebastianTramposch check my edited answer – Tranbi Aug 17 '23 at 10:47
  • Thanks again @Tranbi. It works but i receive an error in the dbc file for CAN extended or CAN standard messages: `Value of VFrameFormat attribute is below the minimum value` but i think it is not such a big deal. For J1939 messages everthing is fine. – Sebastian Tramposch Aug 30 '23 at 07:22