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.
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: