Skip to content

Commit

Permalink
[WIP] cycle_time as generic signal and frame attribute (#405)
Browse files Browse the repository at this point in the history
* implement cycle_time as generic signal and frame attribute / remove
Gen[Msg/Sig]cycle from attributes  #146
* use effective frame cycle time for export
use gcd of singnal-cycletimes for calculating effective cycle time

This removes one (of many) dbc specific parts from canmatrix and other formats
  • Loading branch information
ebroecker committed Oct 18, 2019
1 parent b32f64a commit 60f09ed
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 51 deletions.
2 changes: 2 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ ____________________


* yaml
* scapy
* lua
* json:

--jsonExportCanard
Expand Down
4 changes: 2 additions & 2 deletions examples/BusmasterRestbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ def ticker_ecus(db, dbcname):
bu._cycles = {}
for frame in db.frames:
if bu.name in frame.transmitters:
if "GenMsgCycleTime" in frame.attributes and "GenMsgStartValue" in frame.attributes:
if frame.effective_cycle_time != 0 and "GenMsgStartValue" in frame.attributes:
data = frame.attributes["GenMsgStartValue"][1:-2]
dlc = (math.floor(len(data) / 2))
cycleTime = int(frame.attributes["GenMsgCycleTime"])
cycleTime = frame.effective_cycle_time
if float(cycleTime) > 0:
if cycleTime in bu._cycles:
bu._cycles[cycleTime].append(frame.arbitration_id.id)
Expand Down
4 changes: 2 additions & 2 deletions examples/createccl.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ def main():
txDict[frame] = sendIndex
sendIndex += 1
# print frame.name
# if "GenMsgCycleTime" in frame.attributes and int(frame.attributes["GenMsgCycleTime"]) != 0:
# if frame.effective_cycletime != 0:
# print frame.name,
# print frame.attributes["GenMsgCycleTime"]
# print frame.effective_cycletime
# ccl_h += createStoreMacrosForFrame(frame, "_" + frame.name + "_")

tempStr = ""
Expand Down
32 changes: 20 additions & 12 deletions src/canmatrix/canmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import itertools
import logging
import math
import fractions
import struct
import typing
from builtins import *
Expand Down Expand Up @@ -165,6 +166,8 @@ class Signal(object):
calc_min_for_none = attr.ib(default=True) # type: bool
calc_max_for_none = attr.ib(default=True) # type: bool

cycle_time = attr.ib(default=0) # type: int

min = attr.ib(
converter=lambda value, float_factory=float_factory: (
float_factory(value)
Expand Down Expand Up @@ -754,6 +757,8 @@ class Frame(object):
receivers = attr.ib(factory=list) # type: typing.MutableSequence[str]
signalGroups = attr.ib(factory=list) # type: typing.MutableSequence[SignalGroup]

cycle_time = attr.ib(default=0) # type: int

is_j1939 = attr.ib(default=False) # type: bool
# ('cycleTime', '_cycleTime', int, None),
# ('sendType', '_sendType', str, None),
Expand Down Expand Up @@ -828,27 +833,30 @@ def source(self, value): # type: (int) -> None
self.arbitration_id.j1939_source = value


# @property
# def cycleTime(self):
# if self._cycleTime is None:
# self._cycleTime = self.attribute("GenMsgCycleTime")
# return self._cycleTime
#
@property
def effective_cycle_time(self):
"""Calculate effective cycle time for frame, depending on singal cycle times"""
min_cycle_time_list = [y for y in [x.cycle_time for x in self.signals] + [self.cycle_time] if y != 0]
if len(min_cycle_time_list) == 0:
return 0
elif len(min_cycle_time_list) == 1:
return min_cycle_time_list[0]
else:
gcd = fractions.gcd(min_cycle_time_list[0],min_cycle_time_list[1])
for i in range(2,len(min_cycle_time_list)):
gcd = fractions.gcd(gcd, min_cycle_time_list[i])
return gcd
# return min(min_cycle_time_list)

# @property
# def sendType(self, db = None):
# if self._sendType is None:
# self._sendType = self.attribute("GenMsgSendType")
# return self._sendType
#
# @cycleTime.setter
# def cycleTime(self, value):
# self._cycleTime = value
# self.attributes["GenMsgCycleTime"] = value
#
# @sendType.setter
# def sendType(self, value):
# self._sendType = value
# self.attributes["GenMsgCycleTime"] = value

def attribute(self, attribute_name, db=None, default=None):
# type: (str, typing.Optional[CanMatrix], typing.Any) -> typing.Any
Expand Down
4 changes: 2 additions & 2 deletions src/canmatrix/cli/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_formats():
@click.option('--deleteSignal', 'deleteSignal', help="delete Signal form databases. (comma separated list)\nSyntax: --deleteSignal=mySignal1,mySecondSignal")
@click.option('--renameSignal', 'renameSignal', help="rename Signal form databases. (comma separated list)\nSyntax: --renameSignal=myOldSignal:myNewSignal,mySecondSignal:mySecondNewSignal")
@click.option('--deleteZeroSignals/--no-deleteZeroSignals', 'deleteZeroSignals', default=False, help="delete zero length signals (signals with 0 bit length) from matrix\ndefault False")
@click.option('--deleteSignalAttributes', 'deleteSignalAttributes', help="delete attributes from all signals\nExample --deleteSignalAttributes GenMsgCycle,CycleTime")
@click.option('--deleteSignalAttributes', 'deleteSignalAttributes', help="delete attributes from all signals\nExample --deleteSignalAttributes GenMsgSomeVar,CycleTime")
@click.option('--deleteFrame', 'deleteFrame', help="delete Frame form databases. (comma separated list)\nSyntax: --deleteFrame=myFrame1,mySecondFrame")
@click.option('--renameFrame', 'renameFrame', help="increment each frame.id in database by increment\nSyntax: --frameIdIncrement=increment")
@click.option('--addFrameReceiver', 'addFrameReceiver', help="add receiver Ecu to frame(s) (comma separated list)\nSyntax: --addFrameReceiver=framename:myNewEcu,mySecondEcu:myNEWEcu")
Expand All @@ -69,7 +69,7 @@ def get_formats():
@click.option('--recalcDLC', 'recalcDLC', help="recalculate dlc; max: use maximum of stored and calculated dlc; force: force new calculated dlc")
@click.option('--skipLongDlc', 'skipLongDlc', help="skip all Frames with dlc bigger than given threshold")
@click.option('--cutLongFrames', 'cutLongFrames', help="cut all signals out of Frames with dlc bigger than given threshold")
@click.option('--deleteFrameAttributes', 'deleteFrameAttributes', help="delete attributes from all frames\nExample --deleteFrameAttributes GenMsgCycle,CycleTime")
@click.option('--deleteFrameAttributes', 'deleteFrameAttributes', help="delete attributes from all frames\nExample --deleteFrameAttributes GenMsgSomeVar,CycleTime")
@click.option('--ecus', help="Copy only given ECUs (comma separated list) to target matrix")
@click.option('--frames', help="Copy only given Frames (comma separated list) to target matrix")
@click.option('--signals', help="Copy only given Signals (comma separated list) to target matrix just as 'free' signals without containing frame")
Expand Down
5 changes: 2 additions & 3 deletions src/canmatrix/formats/arxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1316,11 +1316,11 @@ def store_frame_timings(target_frame, cyclic_timing, event_timing, minimum_delay

value = get_child(repeating_time, "VALUE", root_or_cache, ns)
if value is not None:
target_frame.add_attribute("GenMsgCycleTime", str(int(float_factory(value.text) * 1000)))
target_frame.cycle_time = int(float_factory(value.text) * 1000)
elif cyclic_timing is not None:
value = get_child(time_period, "VALUE", root_or_cache, ns)
if value is not None:
target_frame.add_attribute("GenMsgCycleTime", str(int(float_factory(value.text) * 1000)))
target_frame.cycle_time = int(float_factory(value.text) * 1000)


def get_frame(frame_triggering, root_or_cache, multiplex_translation, ns, float_factory):
Expand Down Expand Up @@ -1659,7 +1659,6 @@ def load(file, **options):
db.add_ecu_defines("NWM-Stationsadresse", 'HEX 0 63')
db.add_ecu_defines("NWM-Knoten", 'ENUM "nein","ja"')
db.add_signal_defines("LongName", 'STRING')
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
db.add_frame_defines("GenMsgDelayTime", 'INT 0 65535')
db.add_frame_defines("GenMsgNrOfRepetitions", 'INT 0 65535')
db.add_frame_defines("GenMsgStartValue", 'STRING')
Expand Down
22 changes: 21 additions & 1 deletion src/canmatrix/formats/dbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,12 @@ def dump(in_db, f, **options):

numbered_names = collections.OrderedDict() # type: ignore

if frame.cycle_time != 0:
frame.add_attribute("GenMsgCycleTime", frame.cycle_time)

for signal in frame.signals:
if signal.cycle_time != 0:
signal.add_attribute("GenSigCycleTime", signal.cycle_time)
name = normalized_names[signal]
if compatibility:
name = re.sub("[^A-Za-z0-9]", whitespace_replacement, name)
Expand All @@ -238,6 +243,13 @@ def dump(in_db, f, **options):
name += str(duplicate_signal_counter[name] - 1)
output_names[frame][signal] = name

if max([x.cycle_time for x in db.frames]) > 0:
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
if max([x.cycle_time for y in db.frames for x in y.signals]) > 0:
db.add_signal_defines("GenSigCycleTime", 'INT 0 65535')



# Frames
for frame in db.frames:
multiplex_written = False
Expand Down Expand Up @@ -905,6 +917,7 @@ def add_frame_by_id(new_frame): # type: (canmatrix.Frame) -> None
ecu.name = ecu.attributes.get("SystemNodeLongSymbol")[1:-1]
ecu.del_attribute("SystemNodeLongSymbol")
for frame in db.frames:
frame.cycle_time = int(frame.attributes.get("GenMsgCycleTime", 0))
if frame.attributes.get("SystemMessageLongSymbol", None) is not None:
frame.name = frame.attributes.get("SystemMessageLongSymbol")[1:-1]
frame.del_attribute("SystemMessageLongSymbol")
Expand All @@ -917,6 +930,7 @@ def add_frame_by_id(new_frame): # type: (canmatrix.Frame) -> None
# frame.extended = 1

for signal in frame.signals:
signal.cycle_time = int(signal.attributes.get("GenSigCycleTime", 0))
if signal.attribute("SystemSignalLongSymbol") is not None:
signal.name = signal.attribute("SystemSignalLongSymbol")[1:-1]
signal.del_attribute("SystemSignalLongSymbol")
Expand Down Expand Up @@ -947,9 +961,15 @@ def add_frame_by_id(new_frame): # type: (canmatrix.Frame) -> None
frame.is_fd = True
if "J1939PG" in frame.attributes.get("VFrameFormat", ""):
frame.is_j1939 = True

db.update_ecu_list()
db.del_ecu("Vector__XXX")
db.del_frame_attributes(["GenMsgCycleTime"])
db.del_signal_attributes(["GenSigCycleTime"])
if "GenMsgCycleTime" in db.frame_defines:
del (db.frame_defines["GenMsgCycleTime"])
if "GenSigCycleTime" in db.signal_defines:
del (db.signal_defines["GenSigCycleTime"])

free_signals_dummy_frame = db.frame_by_name("VECTOR__INDEPENDENT_SIG_MSG")
if free_signals_dummy_frame is not None and free_signals_dummy_frame.arbitration_id.id == 0x40000000:
db.signals = free_signals_dummy_frame.signals
Expand Down
11 changes: 4 additions & 7 deletions src/canmatrix/formats/kcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,9 @@ def dump(dbs, f, **_options):

if frame.arbitration_id.extended == 1:
message.set("format", "extended")
if "GenMsgCycleTime" in db.frame_defines:
cycle_time = frame.attribute("GenMsgCycleTime", db=db)
if cycle_time is not None and int(cycle_time) > 0:
message.set("triggered", "true")
message.set("interval", "%d" % int(cycle_time))
if frame.effective_cycle_time != 0:
message.set("triggered", "true")
message.set("interval", "%d" % int(frame.effective_cycle_time))

comment_elem = lxml.etree.Element('Notes')
if frame.comment is not None:
Expand Down Expand Up @@ -357,7 +355,6 @@ def load(f, **options):
counter = 0
for bus in buses:
db = canmatrix.CanMatrix()
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
for node in nodes:
db.ecus.append(canmatrix.Ecu(node.get('name')))
node_list[node.get('id')] = node.get('name')
Expand All @@ -370,7 +367,7 @@ def load(f, **options):
new_frame = canmatrix.Frame(message.get('name'))

if 'triggered' in message.attrib:
new_frame.add_attribute("GenMsgCycleTime", message.get('interval'))
new_frame.cycle_time = int(message.get('interval'))

if 'length' in message.attrib:
dlc = int(message.get('length'))
Expand Down
17 changes: 5 additions & 12 deletions src/canmatrix/formats/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,8 @@ def send_receive(for_frame):
mux_out += id_type
first = 1
mux_out += "DLC=%d\n" % frame.size
if "GenMsgCycleTime" in db.frame_defines:
cycle_time = frame.attribute("GenMsgCycleTime", db=db)
if cycle_time is not None:
mux_out += "CycleTime=" + str(cycle_time) + "\n"
if frame.cycle_time != 0:
mux_out += "CycleTime=" + str(frame.effective_cycle_time) + "\n"

mux_name = frame.mux_names.get(i, mux_signal.name + "%d" % i)

Expand Down Expand Up @@ -299,10 +297,8 @@ def send_receive(for_frame):
output += name
output += id_type
output += "DLC=%d\n" % frame.size
if "GenMsgCycleTime" in db.frame_defines:
cycle_time = frame.attribute("GenMsgCycleTime", db=db)
if cycle_time is not None:
output += "CycleTime=" + str(cycle_time) + "\n"
if frame.cycle_time != 0:
output += "CycleTime=" + str(frame.effective_cycle_time) + "\n"
for signal in frame.signals:
output += create_signal(db, signal)
output += "\n"
Expand Down Expand Up @@ -330,7 +326,6 @@ class Mode(object):
frame = None

db = canmatrix.CanMatrix()
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
db.add_frame_defines("Receivable", 'BOOL False True')
db.add_frame_defines("Sendable", 'BOOL False True')
db.add_signal_defines("GenSigStartValue", 'FLOAT -3.4E+038 3.4E+038')
Expand Down Expand Up @@ -605,9 +600,7 @@ class Mode(object):
frame.size = int(line.split('=')[1])

elif line.startswith('CycleTime'):
frame.add_attribute(
"GenMsgCycleTime",
line.split('=')[1].strip())
frame.cycle_time = int(line.split('=')[1].strip())
# else:
# print line
# else:
Expand Down
3 changes: 1 addition & 2 deletions src/canmatrix/formats/xls.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ def load(file, **options):
# Defines not imported...
# db.add_ecu_defines("NWM-Stationsadresse", 'HEX 0 63')
# db.add_ecu_defines("NWM-Knoten", 'ENUM "nein","ja"')
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
db.add_frame_defines("GenMsgDelayTime", 'INT 0 65535')
db.add_frame_defines("GenMsgCycleTimeActive", 'INT 0 65535')
db.add_frame_defines("GenMsgNrOfRepetitions", 'INT 0 65535')
Expand Down Expand Up @@ -452,7 +451,7 @@ def load(file, **options):
cycle_time = int(cycle_time)
except:
cycle_time = 0
new_frame.add_attribute("GenMsgCycleTime", str(int(cycle_time)))
new_frame.cycle_time = cycle_time

for additional_index in additional_inputs:
if "frame" in additional_inputs[additional_index]:
Expand Down
4 changes: 1 addition & 3 deletions src/canmatrix/formats/xls_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ def get_frame_info(db, frame):
# frame-Name
ret_array.append(frame.name)

if "GenMsgCycleTime" in db.frame_defines:
# determine cycle-time
ret_array.append(frame.attribute("GenMsgCycleTime", db=db))
ret_array.append(frame.effective_cycle_time)

# determine send-type
if "GenMsgSendType" in db.frame_defines:
Expand Down
3 changes: 1 addition & 2 deletions src/canmatrix/formats/xlsx.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,6 @@ def load(filename, **options):
letter_index += ["%s%s" % (a, b) for a in all_letters for b in all_letters]

# Defines not imported...
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
db.add_frame_defines("GenMsgDelayTime", 'INT 0 65535')
db.add_frame_defines("GenMsgCycleTimeActive", 'INT 0 65535')
db.add_frame_defines("GenMsgNrOfRepetitions", 'INT 0 65535')
Expand Down Expand Up @@ -465,7 +464,7 @@ def load(filename, **options):
if launch_type not in launch_types:
launch_types.append(launch_type)

new_frame.add_attribute("GenMsgCycleTime", cycle_time)
new_frame.cycle_time = cycle_time

# new signal detected
if 'Signal Name' in row and row['Signal Name'] != signal_name:
Expand Down
24 changes: 24 additions & 0 deletions src/canmatrix/tests/test_canmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,3 +985,27 @@ def test_canmatrix_del_frame_by_instance(empty_matrix):
empty_matrix.del_frame(f1)
assert empty_matrix.frames == [f2]

def test_effective_cycle_time():
frame = canmatrix.Frame()
sig1 = canmatrix.Signal(name = "s1", cycle_time=1)
sig2 = canmatrix.Signal(name = "s2", cycle_time=0)
frame.add_signal(sig1)
frame.add_signal(sig2)
assert frame.effective_cycle_time == 1

sig2.cycle_time = 2
assert frame.effective_cycle_time == 1

sig1.cycle_time = 4
assert frame.effective_cycle_time == 2

sig1.cycle_time = 3
assert frame.effective_cycle_time == 1

frame.cycle_time = 1
assert frame.effective_cycle_time == 1

frame.cycle_time = 0
sig1.cycle_time = 0
sig2.cycle_time = 0
assert frame.effective_cycle_time == 0
2 changes: 1 addition & 1 deletion src/canmatrix/tests/test_cli_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def create_dbc_with_special_char():

db = canmatrix.CanMatrix()
db.add_frame(myFrame)
db.add_frame_defines("GenMsgCycleTime", 'INT 0 65535')
db.add_frame_defines("SomeUnneededDefine", 'INT 0 65535')
canmatrix.formats.dumpp({"": db}, outFile, dbcExportEncoding='iso-8859-1',
dbcExportCommentEncoding='iso-8859-1')
return outFile
Expand Down
Loading

0 comments on commit 60f09ed

Please sign in to comment.