Skip to content

Commit

Permalink
Allow permissive DBC parsing
Browse files Browse the repository at this point in the history
If multiple frames have the same name, add the frame ID as a suffix
  • Loading branch information
hefroy committed Feb 14, 2024
1 parent a0bc7ef commit 36597aa
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 31 deletions.
71 changes: 55 additions & 16 deletions tools/cloud/dbc-to-decoders.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,70 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

import argparse
import json
import sys

import cantools

if len(sys.argv) < 2:
print("Usage: python3 " + sys.argv[0] + " <INPUT_DBC_FILE> [<OUTPUT_JSON_FILE>]")
exit(-1)
default_interface_id = "1"
parser = argparse.ArgumentParser(
description=(
"Converts a DBC file to AWS IoT FleetWise 'decoders' format for use with "
"CreateDecoderManifest"
)
)
parser.add_argument(
"-p",
"--permissive",
action="store_true",
help="Apply the cantools strict=False option when loading the DBC file",
)
parser.add_argument(
"-i",
"--interface-id",
default=default_interface_id,
help=(
f'Network interface ID, default "{default_interface_id}". This must match the ID used in '
"the static config file."
),
)
parser.add_argument(
"infile",
nargs="?",
type=argparse.FileType("r"),
default=sys.stdin,
help="Input DBC file, default stdin",
)
parser.add_argument(
"outfile",
nargs="?",
type=argparse.FileType("w"),
default=sys.stdout,
help="Output filename, default stdout",
)
args = parser.parse_args()

db = cantools.database.load_file(sys.argv[1])

with open("network-interfaces.json") as f:
network_interfaces = json.load(f)
for interface in network_interfaces:
if interface["type"] == "CAN_INTERFACE":
interface_id = interface["interfaceId"]
db = cantools.database.load(args.infile, strict=not args.permissive)

signal_decoders_to_add = []

processed_messages = set()
for message in db.messages:
message_text = message.name if message.name else message.frame_id
if message_text in processed_messages:
message_text = f"{message_text}_{message.frame_id}"
processed_messages.add(message_text)
processed_signals = set()
for signal in message.signals:
if signal.name in processed_signals:
print(
f"Signal {signal.name} occurs multiple times in the message {message_text}, only"
" the first occurrence will be used",
file=sys.stderr,
)
continue
processed_signals.add(signal.name)
signal_to_add = {}
signal_to_add["name"] = signal.name
signal_to_add["factor"] = signal.scale
Expand Down Expand Up @@ -52,14 +95,10 @@
"type": "CAN_SIGNAL",
"canSignal": signal_to_add,
"fullyQualifiedName": f"Vehicle.{message.name}.{signal.name}",
"interfaceId": interface_id,
"interfaceId": args.interface_id,
}
)

out = json.dumps(signal_decoders_to_add, indent=4, sort_keys=True)

if len(sys.argv) < 3:
print(out)
else:
with open(sys.argv[2], "w") as fp:
fp.write(out)
args.outfile.write(out)
54 changes: 39 additions & 15 deletions tools/cloud/dbc-to-nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,65 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

import argparse
import json
import sys

import cantools

FQN_KEY = "fullyQualifiedName"

if len(sys.argv) < 2:
print("Usage: python3 " + sys.argv[0] + " <INPUT_DBC_FILE> [<OUTPUT_JSON_FILE>]")
exit(-1)
parser = argparse.ArgumentParser(
description=(
"Converts a DBC file to AWS IoT FleetWise 'nodes' format for use with "
"CreateSignalCatalog"
)
)
parser.add_argument(
"-p",
"--permissive",
action="store_true",
help="Apply the cantools strict=False option when loading the DBC file",
)
parser.add_argument(
"infile",
nargs="?",
type=argparse.FileType("r"),
default=sys.stdin,
help="Input DBC file, default stdin",
)
parser.add_argument(
"outfile",
nargs="?",
type=argparse.FileType("w"),
default=sys.stdout,
help="Output filename, default stdout",
)
args = parser.parse_args()

db = cantools.database.load_file(sys.argv[1])
db = cantools.database.load(args.infile, strict=not args.permissive)

vehicle_branch = {FQN_KEY: "Vehicle"}
nodes = []

signals = {}
processed_messages = set()
for message in db.messages:
message_text = message.name if message.name else message.frame_id
if message_text in processed_messages:
message_text = f"{message_text}_{message.frame_id}"
processed_messages.add(message_text)
message_branch = {FQN_KEY: f"{vehicle_branch[FQN_KEY]}.{message_text}"}
nodes.append({"branch": message_branch})
processed_signals = set()
for signal in message.signals:
if message_text not in signals:
signals[message_text] = set()
if signal.name in signals[message_text]:
if signal.name in processed_signals:
print(
f"Signal {signal.name} occurs multiple times in the message {message_text}, only"
" the first occurrence will be used"
" the first occurrence will be used",
file=sys.stderr,
)
continue
signals[message_text].add(signal.name)
processed_signals.add(signal.name)
if (
signal.choices
and len(signal.choices) <= 2
Expand Down Expand Up @@ -70,8 +98,4 @@

out = json.dumps(nodes, indent=4, sort_keys=True)

if len(sys.argv) < 3:
print(out)
else:
with open(sys.argv[2], "w") as fp:
fp.write(out)
args.outfile.write(out)

0 comments on commit 36597aa

Please sign in to comment.