Skip to content

Commit c8c56e6

Browse files
authored
[WIP] fix dbc attributes with spaces and special characters (issue #330) (#332)
* Definition-Names can now contain spaces * add test for frame defines with special character * repair regexp for attributes extraction out of dbc #330 * cleanup some dbc regexps
1 parent 79ee9b1 commit c8c56e6

File tree

3 files changed

+88
-15
lines changed

3 files changed

+88
-15
lines changed

src/canmatrix/formats/dbc.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,8 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
471471
l = line.strip()
472472
if l.__len__() == 0:
473473
continue
474-
#try:
475-
if 1==1:
474+
try:
475+
# if 1==1:
476476
if followUp == FollowUps.signalComment:
477477
try:
478478
comment += "\n" + \
@@ -761,7 +761,7 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
761761
substring = decoded[7:].strip()
762762
define_type = substring[:3]
763763
substring = substring[3:].strip()
764-
pattern = r"^\"([A-Za-z0-9\-_]+)\" +(.+);"
764+
pattern = r"^\"(.+?)\" +(.+);"
765765
regexp = re.compile(pattern)
766766
regexp_raw = re.compile(pattern.encode(dbcImportEncoding))
767767
temp = regexp.match(substring)
@@ -778,7 +778,7 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
778778
db.add_env_defines(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding))
779779

780780
elif decoded.startswith("BA_DEF_ "):
781-
pattern = r"^BA_DEF_ +\"([A-Za-z0-9\-_]+)\" +(.+);"
781+
pattern = r"^BA_DEF_ +\"(.+?)\" +(.+);"
782782
regexp = re.compile(pattern)
783783
regexp_raw = re.compile(pattern.encode(dbcImportEncoding))
784784
temp = regexp.match(decoded)
@@ -788,35 +788,35 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
788788
temp_raw.group(2).decode(dbcImportEncoding))
789789

790790
elif decoded.startswith("BA_ "):
791-
regexp = re.compile(r"^BA_ +\"[A-Za-z0-9[\-_ .]+\" +(.+)")
791+
regexp = re.compile(r"^BA_ +\".+?\" +(.+)")
792792
tempba = regexp.match(decoded)
793793

794794
if tempba.group(1).strip().startswith("BO_ "):
795-
regexp = re.compile(r"^BA_ +\"(.*)\" +BO_ +(\w+) +(.+);")
795+
regexp = re.compile(r"^BA_ +\"(.+?)\" +BO_ +(\d+) +(.+);")
796796
temp = regexp.match(decoded)
797797
get_frame_by_id(canmatrix.ArbitrationId.from_compound_integer(int(temp.group(2)))).add_attribute(
798798
temp.group(1), temp.group(3))
799799
elif tempba.group(1).strip().startswith("SG_ "):
800-
regexp = re.compile(r"^BA_ +\"(.*)\" +SG_ +(\w+) +(\w+) +(.+);")
800+
regexp = re.compile(r"^BA_ +\"(.+?)\" +SG_ +(\d+) +(\w+) +(.+);")
801801
temp = regexp.match(decoded)
802802
if temp != None:
803803
get_frame_by_id(canmatrix.ArbitrationId.from_compound_integer(int(temp.group(2)))).signal_by_name(
804804
temp.group(3)).add_attribute(temp.group(1), temp.group(4))
805805
elif tempba.group(1).strip().startswith("EV_ "):
806-
regexp = re.compile(r"^BA_ +\"(.*)\" +EV_ +(.+) +(.+);")
806+
regexp = re.compile(r"^BA_ +\"(.+?)\" +EV_ +(\w+) +(.*);")
807807
temp = regexp.match(decoded)
808808
if temp != None:
809809
db.add_env_attribute(temp.group(2),temp.group(1),temp.group(3))
810810
elif tempba.group(1).strip().startswith("BU_ "):
811-
regexp = re.compile(r"^BA_ +\"(.*)\" +BU_ +(\w+) +(.+);")
811+
regexp = re.compile(r"^BA_ +\"(.*?)\" +BU_ +(\w+) +(.+);")
812812
temp = regexp.match(decoded)
813813
db.ecu_by_name(
814814
temp.group(2)).add_attribute(
815815
temp.group(1),
816816
temp.group(3))
817817
else:
818818
regexp = re.compile(
819-
r"^BA_ +\"([A-Za-z0-9\-_]+)\" +([\"A-Za-z0-9\-_\.]+);")
819+
r"^BA_ +\"([A-Za-z0-9\-_]+)\" +([\"\w\-\.]+);")
820820
temp = regexp.match(decoded)
821821
if temp:
822822
db.add_attribute(temp.group(1), temp.group(2))
@@ -839,7 +839,7 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
839839
# SIG_VALTYPE_ 0 float : 1;
840840

841841
elif decoded.startswith("BA_DEF_DEF_ "):
842-
pattern = r"^BA_DEF_DEF_ +\"([A-Za-z0-9\-_\.]+)\" +(.+)\;"
842+
pattern = r"^BA_DEF_DEF_ +\"(.+?)\" +(.+?)\;"
843843
regexp = re.compile(pattern)
844844
regexp_raw = re.compile(pattern.encode(dbcImportEncoding))
845845
temp = regexp.match(decoded)
@@ -848,7 +848,7 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
848848
db.add_define_default(temp.group(1),
849849
temp_raw.group(2).decode(dbcImportEncoding))
850850
elif decoded.startswith("SG_MUL_VAL_ "):
851-
pattern = r"^SG_MUL_VAL_ +([0-9]+) +([A-Za-z0-9\-_]+) +([A-Za-z0-9\-_]+) +([0-9]+)\-([0-9]+) *;"
851+
pattern = r"^SG_MUL_VAL_ +([0-9]+) +([\w\-]+) +([\w\-]+) +([0-9]+)\-([0-9]+) *;"
852852
regexp = re.compile(pattern)
853853
regexp_raw = re.compile(pattern.encode(dbcImportEncoding))
854854
temp = regexp.match(decoded)
@@ -867,7 +867,7 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
867867
signal.mux_val_min = muxValMin
868868
signal.mux_val_max = muxValMax
869869
elif decoded.startswith("EV_ "):
870-
pattern = r"^EV_ +([A-Za-z0-9\-_]+) *\: +([0-9]+) +\[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] +\"(\w*)\" +([0-9.+\-eE]+) +([0-9.+\-eE]+) +([A-Za-z0-9\-_]+) +(.*);"
870+
pattern = r"^EV_ +([\w\-\_]+?) *\: +([0-9]+) +\[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] +\"(.*?)\" +([0-9.+\-eE]+) +([0-9.+\-eE]+) +([\w\-]+?) +(.*);"
871871
regexp = re.compile(pattern)
872872
temp = regexp.match(decoded)
873873

@@ -885,8 +885,8 @@ def add_frame_by_id(frame): # type: (canmatrix.Frame) -> None
885885
"accessType" : accessType, "accessNodes" : accessNodes})
886886

887887

888-
else:
889-
# except:
888+
# else:
889+
except:
890890
print ("error with line no: %d" % i)
891891
print (line)
892892
# Backtracking

src/canmatrix/tests/test_copy.py

+23
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,26 @@ def test_copy_ecu_without_frames():
5151
assert len(matrix1.frames) == 1
5252
assert len(matrix1.ecus) == 1
5353
assert matrix1.ecu_by_name("ECU") is not None
54+
55+
56+
def test_copy_ecu_with_attributes():
57+
matrix1 = canmatrix.canmatrix.CanMatrix()
58+
frame1 = canmatrix.canmatrix.Frame("Frame1", arbitration_id=1)
59+
frame1.add_signal(canmatrix.canmatrix.Signal("SomeSignal"))
60+
matrix1.add_frame(frame1)
61+
62+
matrix2 = canmatrix.canmatrix.CanMatrix()
63+
frame2 = canmatrix.canmatrix.Frame("Frame2", arbitration_id=2, transmitters= ["ECU"])
64+
matrix2.add_frame(frame2)
65+
matrix2.update_ecu_list()
66+
matrix2.add_ecu_defines("Node Address", "INT 0 255")
67+
matrix2.add_ecu_defines("attrib", "STRING")
68+
matrix2.ecu_by_name("ECU").add_attribute("attrib", "attribValue")
69+
matrix2.ecu_by_name("ECU").add_attribute("Node Address", 42)
70+
71+
canmatrix.copy.copy_ecu("ECU", matrix2, matrix1)
72+
73+
assert len(matrix1.frames) == 1
74+
assert len(matrix1.ecus) == 1
75+
assert matrix1.ecu_by_name("ECU") is not None
76+
assert matrix1.ecu_by_name("ECU").attribute("Node Address") == 42

src/canmatrix/tests/test_dbc.py

+50
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,53 @@ def test_export_of_unknown_defines():
217217
assert line.endswith("STRING;")
218218
if line.startswith("BA_ "):
219219
assert line.endswith('";')
220+
221+
def test_braces_in_attributes():
222+
dbc = io.BytesIO(textwrap.dedent(u'''\
223+
BO_ 20 frameName: 1 someEcu
224+
SG_ sometext: 1|2@0+ (1,0) [0|0] "" someOtherEcu
225+
226+
BA_ "Signal Age [ms]" SG_ 20 sometext 5000;
227+
''').encode('utf-8'))
228+
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
229+
230+
def test_defines_with_spaces():
231+
dbc = io.BytesIO(textwrap.dedent(u'''\
232+
BU_: someOtherEcu
233+
234+
BO_ 123 someFrame: 1 someOtherEcu
235+
236+
EV_ someEnvVar: 0 [0|0] "" 0 2 DUMMY_NODE_VECTOR0 Vector__XXX;
237+
238+
BA_DEF_ BU_ "Node Address" INT 0 255;
239+
BA_DEF_ BO_ "Period [ms]" INT 0 5000;
240+
BA_DEF_ BU_ "Description X" STRING;
241+
BA_DEF_ EV_ "some attrib" STRING;
242+
BA_ "Node Address" BU_ someOtherEcu 42;
243+
BA_ "Description X" BU_ someOtherEcu "Some Some Text";
244+
BA_ "Period [ms]" BO_ 123 3000;
245+
BA_ "some attrib" EV_ someEnvVar "some space";
246+
''').encode('utf-8'))
247+
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
248+
assert matrix.ecu_defines["Node Address"].type == "INT"
249+
assert matrix.ecu_defines["Node Address"].min == 0
250+
assert matrix.ecu_defines["Node Address"].max == 255
251+
assert matrix.frame_defines["Period [ms]"].min == 0
252+
assert matrix.frame_defines["Period [ms]"].max == 5000
253+
assert matrix.frames[0].attributes["Period [ms]"] == '3000'
254+
assert matrix.env_vars["someEnvVar"]["attributes"]["some attrib"] == '"some space"'
255+
assert matrix.ecus[0].attributes["Description X"] == "Some Some Text"
256+
257+
258+
def test_defines_with_special_cars():
259+
dbc = io.BytesIO(textwrap.dedent(u'''\
260+
BU_: someOtherEcu
261+
262+
BO_ 123 someFrame: 1 someOtherEcu
263+
SG_ someSignal: 1|2@0+ (1,0) [0|0] "" CCL_TEST
264+
265+
BA_DEF_ SG_ "Accuracy" STRING;
266+
BA_ "Accuracy" SG_ 123 someSignal "+/- 10.2 at 55.1%";
267+
''').encode('utf-8'))
268+
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
269+
assert matrix.frames[0].signals[0].attributes["Accuracy"] == "+/- 10.2 at 55.1%"

0 commit comments

Comments
 (0)