canmatrix-0.6/0000775000175000017500000000000013166743513012734 5ustar eduedu00000000000000canmatrix-0.6/setup.cfg0000664000175000017500000000007313166743513014555 0ustar eduedu00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 canmatrix-0.6/test/0000775000175000017500000000000013166743513013713 5ustar eduedu00000000000000canmatrix-0.6/test/test.py0000775000175000017500000000475413001475401015243 0ustar eduedu00000000000000#!/usr/bin/env python3 from __future__ import print_function from __future__ import absolute_import import sys sys.path.append('..') import canmatrix.convert import canmatrix.formats import copy import os import re import shutil import subprocess from canmatrix.log import setup_logger, set_log_level logger = setup_logger('root') set_log_level(logger, -1) export_types = [] import_types = [] for canFormat, features in canmatrix.formats.supportedFormats.items(): if "dump" in features: export_types.append(canmatrix.formats.extensionMapping[canFormat]) if "load" in features: import_types.append(canmatrix.formats.extensionMapping[canFormat]) # for f in os.listdir('../canmatrix'): # m = re.match('^export(.*).py$', f) # if m is not None and m.group(1) != 'all': # export_types.append(m.group(1)) # m = re.match('^import(.*).py$', f) # if m is not None and m.group(1) != 'all' and m.group(1) != 'any': # import_types.append(m.group(1)) export_types.sort() # TODO: support testing of xlsx # export_types.remove('xlsx') if "fibex" in export_types: export_types.remove('fibex') import_types.sort() test_file_base = 'test' converted_path = 'converted' try: shutil.rmtree(converted_path) except OSError: # it's already not there... pass for i in import_types: in_file = test_file_base + '.' + i.lower() if not os.path.isfile(in_file): print('Skipping conversion from missing file ' + in_file) else: to = copy.copy(export_types) try: to.remove(i) except ValueError: # TODO: support testing of xlsx pass print('{} -> {}'.format(i, to)) for t in to: out_file = os.path.basename(test_file_base) # out_file = os.path.splitext(out_file)[0] out_file += '.' + t.lower() directory = os.path.join(converted_path, 'from_' + i) try: os.makedirs(directory) except OSError: # TODO: be more specific: OSError: [Errno 17] File exists: # 'converted/from_arxml' pass out_file = os.path.join(directory, out_file) canmatrix.convert.convert(in_file, out_file) exit_code = subprocess.call(['diff', '-r', 'reference', 'converted']) if exit_code: # difference found message = 'difference found' else: # no difference found message = 'no difference' print('\n\n Testing completed: {message}'.format(**locals())) canmatrix-0.6/canmatrix.egg-info/0000775000175000017500000000000013166743513016414 5ustar eduedu00000000000000canmatrix-0.6/canmatrix.egg-info/SOURCES.txt0000664000175000017500000000121413166743513020276 0ustar eduedu00000000000000setup.py canmatrix/__init__.py canmatrix/arxml.py canmatrix/autosarhelper.py canmatrix/cancluster.py canmatrix/canmatrix.py canmatrix/cmcsv.py canmatrix/cmjson.py canmatrix/compare.py canmatrix/convert.py canmatrix/copy.py canmatrix/dbc.py canmatrix/dbf.py canmatrix/fibex.py canmatrix/formats.py canmatrix/join.py canmatrix/kcd.py canmatrix/log.py canmatrix/sym.py canmatrix/version.py canmatrix/xls.py canmatrix/xlsx.py canmatrix/yaml.py canmatrix.egg-info/PKG-INFO canmatrix.egg-info/SOURCES.txt canmatrix.egg-info/dependency_links.txt canmatrix.egg-info/entry_points.txt canmatrix.egg-info/requires.txt canmatrix.egg-info/top_level.txt test/test.pycanmatrix-0.6/canmatrix.egg-info/dependency_links.txt0000664000175000017500000000000113166743512022461 0ustar eduedu00000000000000 canmatrix-0.6/canmatrix.egg-info/requires.txt0000664000175000017500000000017713166743512021020 0ustar eduedu00000000000000future [arxml] lxml [dbc] [dbf] [fibex] lxml [json] [kcd] lxml [sym] [xls] xlrd xlwt [xlsx] xlsxwriter [yaml] pyyaml canmatrix-0.6/canmatrix.egg-info/PKG-INFO0000664000175000017500000000370313166743512017513 0ustar eduedu00000000000000Metadata-Version: 1.1 Name: canmatrix Version: 0.6 Summary: Support and convert several CAN (Controller Area Network) database formats .arxml .dbc .dbf .kcd .sym fibex xls(x) ... Home-page: http://github.com/ebroecker/canmatrix Author: Eduard Broecker Author-email: eduard@gmx.de License: BSD Description: Canmatrix implements a "Python Can Matrix Object" which describes the can-communication and the needed objects (Boardunits, Frames, Signals, Values, ...) Canmatrix also includes two Tools (canconvert and cancompare) for converting and comparing CAN databases. There are also some extract and merge options for dealing with can databases. supported file formats for import: .dbc candb / Vector .dbf Busmaster (open source!) .kcd kayak (open source!) .arxml autosar system description .yaml dump of the python object .xls(x) excel xls-import, works with .xls-file generated by this lib .sym peak pcan can description supported file formats for export: .dbc .dbf .kcd .xls(x) .json Canard (open source!) .arxml (very basic implementation) .yaml (dump of the python object) .sym .xml (fibex) Keywords: CAN dbc arxml kcd dbf sym Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: License :: OSI Approved :: BSD License Classifier: Topic :: Scientific/Engineering canmatrix-0.6/canmatrix.egg-info/entry_points.txt0000664000175000017500000000013313166743512021706 0ustar eduedu00000000000000[console_scripts] cancompare = canmatrix.compare:main canconvert = canmatrix.convert:main canmatrix-0.6/canmatrix.egg-info/top_level.txt0000664000175000017500000000001213166743512021136 0ustar eduedu00000000000000canmatrix canmatrix-0.6/setup.py0000664000175000017500000000463313166743467014464 0ustar eduedu00000000000000"""Support and convert several CAN (Controller Area Network) database formats .arxml .dbc .dbf .kcd .sym fibex xls(x) ... Canmatrix implements a "Python Can Matrix Object" which describes the can-communication and the needed objects (Boardunits, Frames, Signals, Values, ...) Canmatrix also includes two Tools (canconvert and cancompare) for converting and comparing CAN databases. There are also some extract and merge options for dealing with can databases. supported file formats for import: .dbc candb / Vector .dbf Busmaster (open source!) .kcd kayak (open source!) .arxml autosar system description .yaml dump of the python object .xls(x) excel xls-import, works with .xls-file generated by this lib .sym peak pcan can description supported file formats for export: .dbc .dbf .kcd .xls(x) .json Canard (open source!) .arxml (very basic implementation) .yaml (dump of the python object) .sym .xml (fibex) """ classifiers = """\ Development Status :: 4 - Beta Environment :: Console License :: OSI Approved :: BSD License Topic :: Scientific/Engineering """ import sys from setuptools import setup, find_packages from canmatrix.version import version doclines = __doc__.split("\n") setup( name = "canmatrix", version = version, maintainer = "Eduard Broecker", maintainer_email = "eduard@gmx.de", url = "http://github.com/ebroecker/canmatrix", classifiers = filter(None, classifiers.split("\n")), description = doclines[0], keywords = "CAN dbc arxml kcd dbf sym", long_description = "\n".join(doclines[2:]), license = "BSD", platforms = ["any"], install_requires = ["future"], extras_require = { "arxml": ["lxml"], "kcd": ["lxml"], "fibex": ["lxml"], "xls": ["xlrd", "xlwt"], "xlsx": ["xlsxwriter"], "yaml": ["pyyaml"], "dbc": [], "dbf": [], "json": [], "sym": [] }, packages = find_packages(), entry_points={'console_scripts': ['cancompare = canmatrix.compare:main', 'canconvert = canmatrix.convert:main']} ) canmatrix-0.6/canmatrix/0000775000175000017500000000000013166743513014722 5ustar eduedu00000000000000canmatrix-0.6/canmatrix/copy.py0000664000175000017500000001241613166737333016255 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. from __future__ import absolute_import from .canmatrix import * def copyBU(buId, sourceDb, targetDb): """ This function copys a Boardunit identified by Name or as Object from source-Canmatrix to target-Canmatrix while copying is easy, this function additionally copys all relevant Defines """ # check wether buId is object or symbolic name if type(buId).__name__ == 'BoardUnit': bu = buId else: bu = sourceDb.boardUnits.byName(buId) targetDb.boardUnits.add(bu) # copy all bu-defines for attribute in bu.attributes: targetDb.addBUDefines( attribute, sourceDb.buDefines[attribute].definition) targetDb.addDefineDefault( attribute, sourceDb.buDefines[attribute].defaultValue) def copyBUwithFrames(buId, sourceDb, targetDb): """ This function copys a Boardunit identified by Name or as Object from source-Canmatrix to target-Canmatrix while copying is easy, this function additionally copys all relevant Frames and Defines """ # check wether buId is object or symbolic name if type(buId).__name__ == 'instance': bu = buId else: bu = sourceDb.boardUnits.byName(buId) targetDb.boardUnits.add(bu) # copy tx-frames for frame in sourceDb.frames: if bu.name in frame.transmitter: copyFrame(frame, sourceDb, targetDb) # copy rx-frames for frame in sourceDb.frames: for signal in frame.signals: if bu.name in signal.receiver: copyFrame(frame, sourceDb, targetDb) break # copy all bu-defines for attribute in bu.attributes: targetDb.addBUDefines( attribute, sourceDb.buDefines[attribute].definition) targetDb.addDefineDefault( attribute, sourceDb.buDefines[attribute].defaultValue) def copyFrame(frameId, sourceDb, targetDb): """ This function copys a Frame identified by frameId from soruce-Canmatrix to target-Canmatrix while copying is easy, this function additionally copys all relevant Boardunits, and Defines """ # check wether frameId is object, id or symbolic name if 'int' in type(frameId).__name__ or 'long' in type(frameId).__name__: frame = sourceDb.frameById(frameId) elif type(frameId).__name__ == 'Frame': frame = frameId else: frame = sourceDb.frameByName(frameId) if targetDb.frameById(frame._Id) is not None: # frame already in targetdb... return # copy Frame-Object: targetDb.frames.addFrame(frame) # Boardunits: # each transmitter of Frame could be ECU that is not listed already for transmitter in frame.transmitter: targetBU = targetDb.boardUnits.byName(transmitter) sourceBU = sourceDb.boardUnits.byName(transmitter) if sourceBU is not None and targetBU is None: copyBU(sourceBU, sourceDb, targetDb) # trigger all signals of Frame for sig in frame.signals: # each receiver of Signal could be ECU that is not listed already for receiver in sig.receiver: targetBU = targetDb.boardUnits.byName(transmitter) sourceBU = sourceDb.boardUnits.byName(transmitter) if sourceBU is not None and targetBU is None: copyBU(sourceBU, sourceDb, targetDb) # copy all frame-defines attributes = frame.attributes for attribute in attributes: targetDb.addFrameDefines( attribute, sourceDb.frameDefines[attribute].definition) targetDb.addDefineDefault( attribute, sourceDb.frameDefines[attribute].defaultValue) # trigger all signals of Frame for sig in frame.signals: # delete all 'unknown' attributes for attribute in sig.attributes: targetDb.addSignalDefines( attribute, sourceDb.signalDefines[attribute].definition) targetDb.addDefineDefault( attribute, sourceDb.signalDefines[attribute].defaultValue) canmatrix-0.6/canmatrix/compare.py0000664000175000017500000004201213166737333016724 0ustar eduedu00000000000000#!/usr/bin/env python3 # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. from __future__ import print_function from __future__ import absolute_import from .log import setup_logger, set_log_level logger = setup_logger('root') import types import sys class compareResult(object): def __init__(self, result=None, mtype=None, ref=None, changes=None): # equal, added, deleted, changed self._result = result # db, bu, frame, signal, attribute self._type = mtype # reference to related object self._ref = ref self._changes = changes self._children = [] def addChild(self, child): self._children.append(child) def propagateChanges(res): change = 0 for child in res._children: change += propagateChanges(child) if change != 0: res._result = "changed" if res._result != "equal": return 1 else: return 0 def compareDb(db1, db2, ignore=None): result = compareResult() for f1 in db1.frames: f2 = db2.frameById(f1._Id) if f2 is None: result.addChild(compareResult("deleted", "FRAME", f1)) else: result.addChild(compareFrame(f1, f2, ignore)) for f2 in db2.frames: f1 = db1.frameById(f2._Id) if f1 is None: result.addChild(compareResult("added", "FRAME", f2)) if ignore is not None and "ATTRIBUTE" in ignore and ignore[ "ATTRIBUTE"] == "*": pass else: result.addChild(compareAttributes(db1, db2, ignore)) for bu1 in db1.boardUnits: bu2 = db2.boardUnitByName(bu1.name) if bu2 is None: result.addChild(compareResult("deleted", "ecu", bu1)) else: result.addChild(compareBu(bu1, bu2, ignore)) for bu2 in db2.boardUnits: bu1 = db1.boardUnitByName(bu2.name) if bu1 is None: result.addChild(compareResult("added", "ecu", bu2)) if ignore is not None and "DEFINE" in ignore and ignore["DEFINE"] == "*": pass else: result.addChild( compareDefineList( db1.globalDefines, db2.globalDefines)) temp = compareDefineList(db1.buDefines, db2.buDefines) temp._type = "ECU Defines" result.addChild(temp) temp = compareDefineList(db1.frameDefines, db2.frameDefines) temp._type = "Frame Defines" result.addChild(temp) temp = compareDefineList(db1.signalDefines, db2.signalDefines) temp._type = "Signal Defines" result.addChild(temp) for vt1 in db1.valueTables: if vt1 not in db2.valueTables: result.addChild( compareResult( "deleted", "valuetable " + vt1, db1._valueTables)) else: result.addChild( compareValueTable( db1._valueTables[vt1], db2._valueTables[vt1])) for vt2 in db2.valueTables: if vt2 not in db1.valueTables: result.addChild( compareResult( "added", "valuetable " + vt2, db2._valueTables)) propagateChanges(result) return result def compareValueTable(vt1, vt2): result = compareResult("equal", "Valuetable", vt1) for value in vt1: if value not in vt2: result.addChild( compareResult( "removed", "Value " + str(value), vt1[value])) elif vt1[value] != vt2[value]: result.addChild(compareResult("changed", "Value " + str(value) + " " + str(vt1[value].encode('ascii', 'ignore')), [vt1[value], vt2[value]])) for value in vt2: if value not in vt1: result.addChild( compareResult( "added", "Value " + str(value), vt2[value])) return result def compareSignalGroup(sg1, sg2): result = compareResult("equal", "SignalGroup", sg1) if sg1.name != sg2.name: result.addChild( compareResult( "changed", "SignalName", [ sg1.name, sg2.name])) if sg1.id != sg2.id: result.addChild(compareResult( "changed", "SignalName", [str(sg1.id), str(sg2.id)])) if sg1.signals is None or sg2.signals is None: logger.debug("Strange - sg wo members???") return result for member in sg1.signals: if sg2.byName(member.name) is None: result.addChild(compareResult("deleted", str(member.name), member)) for member in sg2.signals: if sg1.byName(member.name) is None: result.addChild(compareResult("added", str(member.name), member)) return result def compareDefineList(d1list, d2list): result = compareResult("equal", "DefineList", d1list) for definition in d1list: if definition not in d2list: result.addChild( compareResult( "deleted", "Define" + str(definition), d1list)) else: d2 = d2list[definition] d1 = d1list[definition] if d1.definition != d2.definition: result.addChild( compareResult( "changed", "Definition", d1.definition, [ d1.definition, d2.definition])) if d1.defaultValue != d2.defaultValue: result.addChild( compareResult( "changed", "DefaultValue", d1.definition, [ d1.defaultValue, d2.defaultValue])) for definition in d2list: if definition not in d1list: result.addChild( compareResult( "added", "Define" + str(definition), d2list)) return result def compareAttributes(ele1, ele2, ignore=None): result = compareResult("equal", "ATTRIBUTES", ele1) if ignore is not None and "ATTRIBUTE" in ignore and ( ignore["ATTRIBUTE"] == "*" or ignore["ATTRIBUTE"] == ele1): return result for attribute in ele1.attributes: if attribute not in ele2.attributes: result.addChild( compareResult( "deleted", str(attribute), ele1.attributes[attribute])) elif ele1.attributes[attribute] != ele2.attributes[attribute]: result.addChild( compareResult( "changed", str(attribute), ele1.attributes[attribute], [ ele1.attributes[attribute], ele2.attributes[attribute]])) for attribute in ele2.attributes: if attribute not in ele1.attributes: result.addChild( compareResult( "added", str(attribute), ele2.attributes[attribute])) return result def compareBu(bu1, bu2, ignore=None): result = compareResult("equal", "ECU", bu1) if bu1.comment != bu2.comment: result.addChild( compareResult( "changed", "ECU", bu1, [ bu1.comment, bu2.comment])) if ignore is not None and "ATTRIBUTE" in ignore and ignore[ "ATTRIBUTE"] == "*": pass else: result.addChild(compareAttributes(bu1, bu2, ignore)) return result def compareFrame(f1, f2, ignore=None): result = compareResult("equal", "FRAME", f1) for s1 in f1: s2 = f2.signalByName(s1.name) if not s2: result.addChild(compareResult("deleted", "SIGNAL", s1)) else: result.addChild(compareSignal(s1, s2, ignore)) if f1.name != f2.name: result.addChild( compareResult( "changed", "Name", f1, [ f1.name, f2.name])) if f1.size != f2.size: result.addChild( compareResult( "changed", "dlc", f1, [ "dlc: %d" % f1.size, "dlc: %d" % f2.size])) if f1.extended != f2.extended: result.addChild( compareResult( "changed", "FRAME", f1, [ "extended-Flag: %d" % f1._extended, "extended-Flag: %d" % f2._extended])) if f2.comment is None: f2.addComment("") if f1.comment is None: f1.addComment("") if f1.comment != f2.comment: result.addChild( compareResult( "changed", "FRAME", f1, [ "comment: " + f1.comment, "comment: " + f2.comment])) for s2 in f2._signals: s1 = f1.signalByName(s2.name) if not s1: result.addChild(compareResult("added", "SIGNAL", s2)) if ignore is not None and "ATTRIBUTE" in ignore and ignore[ "ATTRIBUTE"] == "*": pass else: result.addChild(compareAttributes(f1, f2, ignore)) for transmitter in f1.transmitter: if transmitter not in f2.transmitter: result.addChild(compareResult("removed", "Frame-Transmitter", f1)) for transmitter in f2.transmitter: if transmitter not in f1.transmitter: result.addChild(compareResult("added", "Frame-Transmitter", f2)) for sg1 in f1.SignalGroups: sg2 = f2.signalGroupbyName(sg1.name) if sg2 is None: result.addChild(compareResult("removed", "Signalgroup", sg1)) else: result.addChild(compareSignalGroup(sg1, sg2)) for sg2 in f2._SignalGroups: if f1.signalGroupbyName(sg2.name) is None: result.addChild(compareResult("added", "Signalgroup", sg2)) return result def compareSignal(s1, s2, ignore=None): result = compareResult("equal", "SIGNAL", s1) if s1._startbit != s2._startbit: result.addChild( compareResult( "changed", "startbit", s1, [ " %d" % s1._startbit, " %d" % s2._startbit])) if s1._signalsize != s2._signalsize: result.addChild( compareResult( "changed", "signalsize", s1, [ " %d" % s1._signalsize, " %d" % s2._signalsize])) if float(s1._factor) != float(s2._factor): result.addChild( compareResult( "changed", "factor", s1, [ s1._factor, s2._factor])) if float(s1._offset) != float(s2._offset): result.addChild( compareResult( "changed", "offset", s1, [ s1._offset, s2._offset])) if float(s1._min) != float(s2._min): result.addChild( compareResult( "changed", "min", s1, [ s1._min, s2._min])) if float(s1._max) != float(s2._max): result.addChild( compareResult( "changed", "max", s1, [ s1._max, s2._max])) if s1._is_little_endian != s2._is_little_endian: result.addChild( compareResult( "changed", "is_little_endian", s1, [ " %d" % s1._is_little_endian, " %d" % s2._is_little_endian])) if s1._is_signed != s2._is_signed: result.addChild( compareResult( "changed", "sign", s1, [ " %d" % s1._is_signed, " %d" % s2._is_signed])) if s1._multiplex != s2._multiplex: result.addChild(compareResult("changed", "multiplex", s1, [ str(s1._multiplex), str(s2._multiplex)])) if s1._unit != s2._unit: result.addChild( compareResult( "changed", "unit", s1, [ s1._unit, s2._unit])) if s1.comment is not None and s2.comment is not None and s1.comment != s2.comment: if s1.comment.replace("\n", " ") != s2.comment.replace("\n", " "): result.addChild( compareResult( "changed", "comment", s1, [ s1.comment, s2.comment])) else: result.addChild( compareResult( "changed", "comment", s1, [ "only whitespaces differ", ""])) for receiver in s1._receiver: if receiver not in s2._receiver: result.addChild( compareResult( "removed", "receiver " + receiver, s1._receiver)) for receiver in s2._receiver: if receiver not in s1._receiver: result.addChild( compareResult( "added", "receiver " + receiver, s1._receiver)) if ignore is not None and "ATTRIBUTE" in ignore and ignore[ "ATTRIBUTE"] == "*": pass else: result.addChild(compareAttributes(s1, s2, ignore)) result.addChild(compareValueTable(s1._values, s2._values)) return result def dumpResult(res, depth=0): if res._type is not None and res._result != "equal": for _ in range(0, depth): print(" ", end=' ') print(res._type + " " + res._result + " ", end=' ') if hasattr(res._ref, 'name'): print(res._ref.name) else: print(" ") if res._changes is not None and res._changes[ 0] is not None and res._changes[1] is not None: for _ in range(0, depth): print(" ", end=' ') if type(res._changes[0]) == types.UnicodeType: res._changes[0] = res._changes[0].encode('ascii', 'ignore') if type(res._changes[1]) == types.UnicodeType: res._changes[1] = res._changes[1].encode('ascii', 'ignore') print("old: " + str(res._changes[0]) + " new: " + str(res._changes[1])) for child in res._children: dumpResult(child, depth + 1) def main(): from optparse import OptionParser usage = """ %prog [options] cancompare matrix1 matrix2 matrixX can be any of *.dbc|*.dbf|*.kcd|*.arxml """ parser = OptionParser(usage=usage) parser.add_option( "-s", dest="silent", action="store_true", help="don't print status messages to stdout. (only errors)", default=False) parser.add_option( "-v", dest="verbosity", action="count", help="Output verbosity", default=0) (cmdlineOptions, args) = parser.parse_args() if len(args) < 2: parser.print_help() sys.exit(1) matrix1 = args[0] matrix2 = args[1] verbosity = cmdlineOptions.verbosity if cmdlineOptions.silent: # Only print ERROR messages (ignore import warnings) verbosity = -1 set_log_level(logger, verbosity) # import only after setting log level, to also disable warning messages in # silent mode. import canmatrix.formats logger.info("Importing " + matrix1 + " ... ") db1 = next(iter(canmatrix.formats.loadp(matrix1).values())) logger.info("%d Frames found" % (db1._fl._list.__len__())) logger.info("Importing " + matrix2 + " ... ") db2 = next(iter(canmatrix.formats.loadp(matrix2).values())) logger.info("%d Frames found" % (db2._fl._list.__len__())) ignore = {} #ignore["ATTRIBUTE"] = "*" #ignore["DEFINE"] = "*" obj = compareDb(db1, db2, ignore) dumpResult(obj) if __name__ == '__main__': sys.exit(main()) canmatrix-0.6/canmatrix/yaml.py0000664000175000017500000001026613166737333016246 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports yaml-files from a canmatrix-object # yaml-files are just object-dumps human readable. # This export is complete, no information lost from __future__ import absolute_import from builtins import * from .canmatrix import * import copy import codecs import yaml try: from yaml.representer import SafeRepresenter except ImportError: yaml = None representers = False try: yaml.add_representer(int, SafeRepresenter.represent_int) yaml.add_representer(long, SafeRepresenter.represent_long) yaml.add_representer(unicode, SafeRepresenter.represent_unicode) yaml.add_representer(str, SafeRepresenter.represent_unicode) yaml.add_representer(list, SafeRepresenter.represent_list) representers = True except: representers = False # some error with representers ... continue anyway def dump(db, f, **options): newdb = copy.deepcopy(db) for i, frame in enumerate(newdb.frames): for j, signal in enumerate(frame.signals): if signal.is_little_endian == False: signal._startbit = signal.getStartbit( bitNumbering=1, startLittle=True) # newdb.frames[i].signals[j]._startbit = signal._startbit # f = open(filename, "w") if representers: f.write(unicode(yaml.dump(newdb))) else: f.write(yaml.dump(newdb).encode('utf8')) def load(f, **options): db = yaml.load(f) # TODO: don't close here. someone else opened, they should close. f.close() return db def constructor(loader, node, cls, mapping={}): d = {k.lstrip('_'): v for k, v in loader.construct_mapping(node).items()} name = d.pop('name') for old, new in mapping.items(): d[new] = d.pop(old) return cls(name, **d) def frame_constructor(loader, node): return constructor( loader=loader, node=node, cls=Frame, mapping={ 'Transmitter': 'transmitter', 'Size': 'dlc', }, ) def signal_constructor(loader, node): mapping = { 'startbit': 'startBit', 'signalsize': 'signalSize', } signal = constructor( loader=loader, node=node, cls=Signal, mapping={ 'startbit': 'startBit', 'signalsize': 'signalSize', }, ) if signal.is_little_endian == False: signal.setStartbit( loader.construct_mapping(node)['_startbit'], bitNumbering=1, startLittle=False) return signal def frame_representer(dumper, data): node = yaml.representer.Representer.represent_object(dumper, data) node.tag = '{}:Frame'.format(node.tag.partition(':python/object:')[0]) return node yaml.add_constructor(u'tag:yaml.org,2002:Frame', frame_constructor) yaml.add_constructor(u'tag:yaml.org,2002:Signal', signal_constructor) yaml.add_representer(Frame, frame_representer) canmatrix-0.6/canmatrix/arxml.py0000664000175000017500000021205513166737333016427 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script axports arxml-files from a canmatrix-object # arxml-files are the can-matrix-definitions and a lot more in AUTOSAR-Context # currently Support for Autosar 3.2 and 4.0-4.3 is planned from __future__ import division from __future__ import print_function from __future__ import absolute_import import logging logger = logging.getLogger('root') import math import os from builtins import * from lxml import etree from .canmatrix import * from .autosarhelper import * clusterExporter = 1 clusterImporter = 1 def createSubElement(parent, elementName, strName=None): sn = etree.SubElement(parent, elementName) if strName is not None: sn.text = str(strName) return sn def getBaseTypeOfSignal(signal): if signal.is_float: if signal.signalsize > 32: createType = "double" size = 64 else: createType = "single" size = 32 else: if signal.signalsize > 32: if signal.is_signed: createType = "sint64" else: createType = "uint64" size = 64 elif signal.signalsize > 16: if signal.is_signed: createType = "sint32" else: createType = "uint32" size = 32 elif signal.signalsize > 8: if signal.is_signed: createType = "sint16" else: createType = "uint16" size = 16 else: if signal.is_signed: createType = "sint8" else: createType = "uint8" size = 8 return createType, size def dump(dbs, f, **options): if 'arVersion' in options: arVersion = options["arVersion"] else: arVersion = "3.2.3" for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: for rec in signal.receiver: if rec.strip() not in frame.receiver: frame.receiver.append(rec.strip()) if arVersion[0] == "3": xsi = 'http://www.w3.org/2001/XMLSchema-instance' root = etree.Element( 'AUTOSAR', nsmap={ None: 'http://autosar.org/' + arVersion, 'xsi': xsi}) root.attrib['{{{pre}}}schemaLocation'.format( pre=xsi)] = 'http://autosar.org/' + arVersion + ' AUTOSAR_' + arVersion.replace('.', '') + '.xsd' toplevelPackages = createSubElement(root, 'TOP-LEVEL-PACKAGES') else: xsi = 'http://www.w3.org/2001/XMLSchema-instance' root = etree.Element( 'AUTOSAR', nsmap={ None: "http://autosar.org/schema/r4.0", 'xsi': xsi}) root.attrib['{{{pre}}}schemaLocation'.format( pre=xsi)] = 'http://autosar.org/schema/r4.0 AUTOSAR_' + arVersion.replace('.', '-') + '.xsd' toplevelPackages = createSubElement(root, 'AR-PACKAGES') # # AR-PACKAGE Cluster # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'Cluster') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] # if len(name) == 0: # (path, ext) = os.path.splitext(filename) # busName = path # else: if len(name) > 0: busName = name else: busName = "CAN" cancluster = createSubElement(elements, 'CAN-CLUSTER') createSubElement(cancluster, 'SHORT-NAME', busName) if arVersion[0] == "3": # createSubElement(cancluster, 'SPEED', '50000') physicalChannels = createSubElement( cancluster, 'PHYSICAL-CHANNELS') physicalChannel = createSubElement( physicalChannels, 'PHYSICAL-CHANNEL') createSubElement(physicalChannel, 'SHORT-NAME', 'CAN') frameTriggering = createSubElement( physicalChannel, 'FRAME-TRIGGERINGSS') else: canClusterVaraints = createSubElement( cancluster, 'CAN-CLUSTER-VARIANTS') canClusterConditional = createSubElement( canClusterVaraints, 'CAN-CLUSTER-CONDITIONAL') physicalChannels = createSubElement( canClusterConditional, 'PHYSICAL-CHANNELS') physicalChannel = createSubElement( physicalChannels, 'CAN-PHYSICAL-CHANNEL') createSubElement(physicalChannel, 'SHORT-NAME', 'CAN') frameTriggering = createSubElement( physicalChannel, 'FRAME-TRIGGERINGS') for frame in db.frames: canFrameTriggering = createSubElement( frameTriggering, 'CAN-FRAME-TRIGGERING') createSubElement(canFrameTriggering, 'SHORT-NAME', frame.name) framePortRefs = createSubElement( canFrameTriggering, 'FRAME-PORT-REFS') for transmitter in frame.transmitter: framePortRef = createSubElement( framePortRefs, 'FRAME-PORT-REF') framePortRef.set('DEST', 'FRAME-PORT') framePortRef.text = "/ECU/" + transmitter + \ "/CN_" + transmitter + "/" + frame.name for rec in frame.receiver: framePortRef = createSubElement( framePortRefs, 'FRAME-PORT-REF') framePortRef.set('DEST', 'FRAME-PORT') framePortRef.text = "/ECU/" + rec + "/CN_" + rec + "/" + frame.name frameRef = createSubElement(canFrameTriggering, 'FRAME-REF') if arVersion[0] == "3": frameRef.set('DEST', 'FRAME') frameRef.text = "/Frame/FRAME_" + frame.name pduTriggeringRefs = createSubElement( canFrameTriggering, 'I-PDU-TRIGGERING-REFS') pduTriggeringRef = createSubElement( pduTriggeringRefs, 'I-PDU-TRIGGERING-REF') pduTriggeringRef.set('DEST', 'I-PDU-TRIGGERING') else: frameRef.set('DEST', 'CAN-FRAME') frameRef.text = "/CanFrame/FRAME_" + frame.name pduTriggering = createSubElement( canFrameTriggering, 'PDU-TRIGGERINGS') pduTriggeringRefConditional = createSubElement( pduTriggering, 'PDU-TRIGGERING-REF-CONDITIONAL') pduTriggeringRef = createSubElement( pduTriggeringRefConditional, 'PDU-TRIGGERING-REF') pduTriggeringRef.set('DEST', 'PDU-TRIGGERING') if frame.extended == 0: createSubElement( canFrameTriggering, 'CAN-ADDRESSING-MODE', 'STANDARD') else: createSubElement( canFrameTriggering, 'CAN-ADDRESSING-MODE', 'EXTENDED') createSubElement(canFrameTriggering, 'IDENTIFIER', str(frame.id)) pduTriggeringRef.text = "/Cluster/CAN/IPDUTRIGG_" + frame.name if arVersion[0] == "3": ipduTriggerings = createSubElement( physicalChannel, 'I-PDU-TRIGGERINGS') for frame in db.frames: ipduTriggering = createSubElement( ipduTriggerings, 'I-PDU-TRIGGERING') createSubElement( ipduTriggering, 'SHORT-NAME', "IPDUTRIGG_" + frame.name) ipduRef = createSubElement(ipduTriggering, 'I-PDU-REF') ipduRef.set('DEST', 'SIGNAL-I-PDU') ipduRef.text = "/PDU/PDU_" + frame.name isignalTriggerings = createSubElement( physicalChannel, 'I-SIGNAL-TRIGGERINGS') for frame in db.frames: for signal in frame.signals: isignalTriggering = createSubElement( isignalTriggerings, 'I-SIGNAL-TRIGGERING') createSubElement(isignalTriggering, 'SHORT-NAME', signal.name) iSignalPortRefs = createSubElement( isignalTriggering, 'I-SIGNAL-PORT-REFS') for receiver in signal.receiver: iSignalPortRef = createSubElement( iSignalPortRefs, 'I-SIGNAL-PORT-REF', '/ECU/' + receiver + '/CN_' + receiver + '/' + signal.name) iSignalPortRef.set('DEST', 'SIGNAL-PORT') isignalRef = createSubElement( isignalTriggering, 'SIGNAL-REF') isignalRef.set('DEST', 'I-SIGNAL') isignalRef.text = "/ISignal/" + signal.name else: isignalTriggerings = createSubElement( physicalChannel, 'I-SIGNAL-TRIGGERINGS') for frame in db.frames: for signal in frame.signals: isignalTriggering = createSubElement( isignalTriggerings, 'I-SIGNAL-TRIGGERING') createSubElement(isignalTriggering, 'SHORT-NAME', signal.name) iSignalPortRefs = createSubElement( isignalTriggering, 'I-SIGNAL-PORT-REFS') for receiver in signal.receiver: iSignalPortRef = createSubElement( iSignalPortRefs, 'I-SIGNAL-PORT-REF', '/ECU/' + receiver + '/CN_' + receiver + '/' + signal.name) iSignalPortRef.set('DEST', 'I-SIGNAL-PORT') isignalRef = createSubElement( isignalTriggering, 'I-SIGNAL-REF') isignalRef.set('DEST', 'I-SIGNAL') isignalRef.text = "/ISignal/" + signal.name ipduTriggerings = createSubElement( physicalChannel, 'PDU-TRIGGERINGS') for frame in db.frames: ipduTriggering = createSubElement( ipduTriggerings, 'PDU-TRIGGERING') createSubElement( ipduTriggering, 'SHORT-NAME', "IPDUTRIGG_" + frame.name) # missing: I-PDU-PORT-REFS ipduRef = createSubElement(ipduTriggering, 'I-PDU-REF') ipduRef.set('DEST', 'I-SIGNAL-I-PDU') ipduRef.text = "/PDU/PDU_" + frame.name # missing: I-SIGNAL-TRIGGERINGS # TODO # ipduTriggerings = createSubElement(physicalChannel, 'PDU-TRIGGERINGS') # for frame in db.frames: # ipduTriggering = createSubElement(ipduTriggerings, 'PDU-TRIGGERING') # createSubElement(ipduTriggering, 'SHORT-NAME', "PDUTRIGG_" + frame.name) # ipduRef = createSubElement(ipduTriggering, 'I-PDU-REF') # ipduRef.set('DEST','SIGNAL-I-PDU') # ipduRef.text = "/PDU/PDU_" + frame.name # # AR-PACKAGE FRAME # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') if arVersion[0] == "3": createSubElement(arPackage, 'SHORT-NAME', 'Frame') else: createSubElement(arPackage, 'SHORT-NAME', 'CanFrame') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] # TODO: reused frames will be paced multiple times in file for frame in db.frames: if arVersion[0] == "3": frameEle = createSubElement(elements, 'FRAME') else: frameEle = createSubElement(elements, 'CAN-FRAME') createSubElement(frameEle, 'SHORT-NAME', "FRAME_" + frame.name) if frame.comment: desc = createSubElement(frameEle, 'DESC') l2 = createSubElement(desc, 'L-2') l2.set("L", "FOR-ALL") l2.text = frame.comment createSubElement(frameEle, 'FRAME-LENGTH', "%d" % frame.size) pdumappings = createSubElement(frameEle, 'PDU-TO-FRAME-MAPPINGS') pdumapping = createSubElement(pdumappings, 'PDU-TO-FRAME-MAPPING') createSubElement(pdumapping, 'SHORT-NAME', frame.name) createSubElement( pdumapping, 'PACKING-BYTE-ORDER', "MOST-SIGNIFICANT-BYTE-LAST") pduRef = createSubElement(pdumapping, 'PDU-REF') createSubElement(pdumapping, 'START-POSITION', '0') pduRef.text = "/PDU/PDU_" + frame.name if arVersion[0] == "3": pduRef.set('DEST', 'SIGNAL-I-PDU') else: pduRef.set('DEST', 'I-SIGNAL-I-PDU') # # AR-PACKAGE PDU # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'PDU') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for frame in db.frames: if arVersion[0] == "3": signalIpdu = createSubElement(elements, 'SIGNAL-I-PDU') createSubElement(signalIpdu, 'SHORT-NAME', "PDU_" + frame.name) createSubElement(signalIpdu, 'LENGTH', "%d" % int(frame.size * 8)) else: signalIpdu = createSubElement(elements, 'I-SIGNAL-I-PDU') createSubElement(signalIpdu, 'SHORT-NAME', "PDU_" + frame.name) createSubElement(signalIpdu, 'LENGTH', "%d" % int(frame.size)) # I-PDU-TIMING-SPECIFICATION if arVersion[0] == "3": signalToPduMappings = createSubElement( signalIpdu, 'SIGNAL-TO-PDU-MAPPINGS') else: signalToPduMappings = createSubElement( signalIpdu, 'I-SIGNAL-TO-PDU-MAPPINGS') for signal in frame.signals: signalToPduMapping = createSubElement( signalToPduMappings, 'I-SIGNAL-TO-I-PDU-MAPPING') createSubElement(signalToPduMapping, 'SHORT-NAME', signal.name) if arVersion[0] == "3": if signal.is_little_endian == 1: # Intel createSubElement( signalToPduMapping, 'PACKING-BYTE-ORDER', 'MOST-SIGNIFICANT-BYTE-LAST') else: # Motorola createSubElement( signalToPduMapping, 'PACKING-BYTE-ORDER', 'MOST-SIGNIFICANT-BYTE-FIRST') signalRef = createSubElement( signalToPduMapping, 'SIGNAL-REF') else: signalRef = createSubElement( signalToPduMapping, 'I-SIGNAL-REF') if signal.is_little_endian == 1: # Intel createSubElement( signalToPduMapping, 'PACKING-BYTE-ORDER', 'MOST-SIGNIFICANT-BYTE-LAST') else: # Motorola createSubElement( signalToPduMapping, 'PACKING-BYTE-ORDER', 'MOST-SIGNIFICANT-BYTE-FIRST') signalRef.text = "/ISignal/" + signal.name signalRef.set('DEST', 'I-SIGNAL') createSubElement(signalToPduMapping, 'START-POSITION', str(signal.getStartbit(bitNumbering=1))) # missing: TRANSFER-PROPERTY: PENDING/... for group in frame.SignalGroups: signalToPduMapping = createSubElement( signalToPduMappings, 'I-SIGNAL-TO-I-PDU-MAPPING') createSubElement(signalToPduMapping, 'SHORT-NAME', group.name) signalRef = createSubElement(signalToPduMapping, 'SIGNAL-REF') signalRef.text = "/ISignal/" + group.name signalRef.set('DEST', 'I-SIGNAL') # TODO: TRANSFER-PROPERTY: PENDING??? # # AR-PACKAGE ISignal # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'ISignal') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: signalEle = createSubElement(elements, 'I-SIGNAL') createSubElement(signalEle, 'SHORT-NAME', signal.name) if arVersion[0] == "4": createSubElement(signalEle, 'LENGTH', str(signal.signalsize)) networkRepresentProps = createSubElement( signalEle, 'NETWORK-REPRESENTATION-PROPS') swDataDefPropsVariants = createSubElement( networkRepresentProps, 'SW-DATA-DEF-PROPS-VARIANTS') swDataDefPropsConditional = createSubElement( swDataDefPropsVariants, 'SW-DATA-DEF-PROPS-CONDITIONAL') baseTypeRef = createSubElement(swDataDefPropsConditional, 'BASE-TYPE-REF') baseTypeRef.set('DEST', 'SW-BASE-TYPE') createType, size = getBaseTypeOfSignal(signal) baseTypeRef.text = "/DataType/" + createType compuMethodRef = createSubElement( swDataDefPropsConditional, 'COMPU-METHOD-REF', '/DataType/Semantics/' + signal.name) compuMethodRef.set('DEST', 'COMPU-METHOD') unitRef = createSubElement( swDataDefPropsConditional, 'UNIT-REF', '/DataType/Unit/' + signal.name) unitRef.set('DEST', 'UNIT') sysSigRef = createSubElement(signalEle, 'SYSTEM-SIGNAL-REF') sysSigRef.text = "/Signal/" + signal.name sysSigRef.set('DEST', 'SYSTEM-SIGNAL') for group in frame.SignalGroups: signalEle = createSubElement(elements, 'I-SIGNAL') createSubElement(signalEle, 'SHORT-NAME', group.name) sysSigRef = createSubElement(signalEle, 'SYSTEM-SIGNAL-REF') sysSigRef.text = "/Signal/" + group.name sysSigRef.set('DEST', 'SYSTEM-SIGNAL-GROUP') # # AR-PACKAGE Signal # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'Signal') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: signalEle = createSubElement(elements, 'SYSTEM-SIGNAL') createSubElement(signalEle, 'SHORT-NAME', signal.name) if signal.comment: desc = createSubElement(signalEle, 'DESC') l2 = createSubElement(desc, 'L-2') l2.set("L", "FOR-ALL") l2.text = signal.comment if arVersion[0] == "3": dataTypeRef = createSubElement(signalEle, 'DATA-TYPE-REF') if signal.is_float: dataTypeRef.set('DEST', 'REAL-TYPE') else: dataTypeRef.set('DEST', 'INTEGER-TYPE') dataTypeRef.text = "/DataType/" + signal.name createSubElement(signalEle, 'LENGTH', str(signal.signalsize)) for group in frame.SignalGroups: groupEle = createSubElement(elements, 'SYSTEM-SIGNAL-GROUP') createSubElement(signalEle, 'SHORT-NAME', group.name) if arVersion[0] == "3": dataTypeRef.set('DEST', 'INTEGER-TYPE') sysSignalRefs = createSubElement( groupEle, 'SYSTEM-SIGNAL-REFS') for member in group.signals: memberEle = createSubElement( sysSignalRefs, 'SYSTEM-SIGNAL-REF') memberEle.set('DEST', 'SYSTEM-SIGNAL') memberEle.text = "/Signal/" + member.name # initValueRef = createSubElement(signalEle, 'INIT-VALUE-REF') # initValueRef.set('DEST','INTEGER-LITERAL') # initValueRef.text = "/CONSTANTS/" + signal.name # # AR-PACKAGE Datatype # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'DataType') elements = createSubElement(arPackage, 'ELEMENTS') if arVersion[0] == "3": for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: if signal.is_float: typeEle = createSubElement(elements, 'REAL-TYPE') else: typeEle = createSubElement(elements, 'INTEGER-TYPE') createSubElement(typeEle, 'SHORT-NAME', signal.name) swDataDefProps = createSubElement( typeEle, 'SW-DATA-DEF-PROPS') if signal.is_float: encoding = createSubElement(typeEle, 'ENCODING') if signal.signalsize > 32: encoding.text = "DOUBLE" else: encoding.text = "SINGLE" compuMethodRef = createSubElement( swDataDefProps, 'COMPU-METHOD-REF') compuMethodRef.set('DEST', 'COMPU-METHOD') compuMethodRef.text = "/DataType/Semantics/" + signal.name else: createdTypes = [] for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: createType, size = getBaseTypeOfSignal(signal) if createType not in createdTypes: createdTypes.append(createType) swBaseType = createSubElement(elements, 'SW-BASE-TYPE') sname = createSubElement(swBaseType, 'SHORT-NAME') sname.text = createType cat = createSubElement(swBaseType, 'CATEGORY') cat.text = "FIXED_LENGTH" baseTypeSize = createSubElement(swBaseType, 'BASE-TYPE-SIZE') baseTypeSize.text = str(size) if signal.is_float: enc = createSubElement(swBaseType, 'BASE-TYPE-ENCODING') enc.text = "IEEE754" if arVersion[0] == "3": subpackages = createSubElement(arPackage, 'SUB-PACKAGES') else: subpackages = createSubElement(arPackage, 'AR-PACKAGES') arPackage = createSubElement(subpackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'Semantics') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: compuMethod = createSubElement(elements, 'COMPU-METHOD') createSubElement(compuMethod, 'SHORT-NAME', signal.name) # missing: UNIT-REF compuIntToPhys = createSubElement( compuMethod, 'COMPU-INTERNAL-TO-PHYS') compuScales = createSubElement(compuIntToPhys, 'COMPU-SCALES') for value in sorted(signal.values, key=lambda x: int(x)): compuScale = createSubElement(compuScales, 'COMPU-SCALE') desc = createSubElement(compuScale, 'DESC') l2 = createSubElement(desc, 'L-2') l2.set('L', 'FOR-ALL') l2.text = signal.values[value] createSubElement(compuScale, 'LOWER-LIMIT', str(value)) createSubElement(compuScale, 'UPPER-LIMIT', str(value)) compuConst = createSubElement(compuScale, 'COMPU-CONST') createSubElement(compuConst, 'VT', signal.values[value]) else: compuScale = createSubElement(compuScales, 'COMPU-SCALE') # createSubElement(compuScale, 'LOWER-LIMIT', str(#TODO)) # createSubElement(compuScale, 'UPPER-LIMIT', str(#TODO)) compuRationslCoeff = createSubElement( compuScale, 'COMPU-RATIONAL-COEFFS') compuNumerator = createSubElement( compuRationslCoeff, 'COMPU-NUMERATOR') createSubElement(compuNumerator, 'V', "%g" % signal.offset) createSubElement(compuNumerator, 'V', "%g" % signal.factor) compuDenomiator = createSubElement( compuRationslCoeff, 'COMPU-DENOMINATOR') createSubElement(compuDenomiator, 'V', "1") arPackage = createSubElement(subpackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'Unit') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for frame in db.frames: for signal in frame.signals: unit = createSubElement(elements, 'UNIT') createSubElement(unit, 'SHORT-NAME', signal.name) createSubElement(unit, 'DISPLAY-NAME', signal.unit) txIPduGroups = {} rxIPduGroups = {} # # AR-PACKAGE ECU # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'ECU') elements = createSubElement(arPackage, 'ELEMENTS') for name in dbs: db = dbs[name] for ecu in db.boardUnits: ecuInstance = createSubElement(elements, 'ECU-INSTANCE') createSubElement(ecuInstance, 'SHORT-NAME', ecu.name) if ecu.comment: desc = createSubElement(ecuInstance, 'DESC') l2 = createSubElement(desc, 'L-2') l2.set('L', 'FOR-ALL') l2.text = ecu.comment if arVersion[0] == "3": assoIpduGroupRefs = createSubElement( ecuInstance, 'ASSOCIATED-I-PDU-GROUP-REFS') connectors = createSubElement(ecuInstance, 'CONNECTORS') commConnector = createSubElement( connectors, 'COMMUNICATION-CONNECTOR') else: assoIpduGroupRefs = createSubElement( ecuInstance, 'ASSOCIATED-COM-I-PDU-GROUP-REFS') connectors = createSubElement(ecuInstance, 'CONNECTORS') commConnector = createSubElement( connectors, 'CAN-COMMUNICATION-CONNECTOR') createSubElement(commConnector, 'SHORT-NAME', 'CN_' + ecu.name) ecuCommPortInstances = createSubElement( commConnector, 'ECU-COMM-PORT-INSTANCES') recTemp = None sendTemp = None for frame in db.frames: if ecu.name in frame.transmitter: frameport = createSubElement( ecuCommPortInstances, 'FRAME-PORT') createSubElement(frameport, 'SHORT-NAME', frame.name) createSubElement( frameport, 'COMMUNICATION-DIRECTION', 'OUT') sendTemp = 1 if ecu.name + "_Tx" not in txIPduGroups: txIPduGroups[ecu.name + "_Tx"] = [] txIPduGroups[ecu.name + "_Tx"].append(frame.name) # missing I-PDU-PORT for signal in frame.signals: if arVersion[0] == "3": signalPort = createSubElement( ecuCommPortInstances, 'SIGNAL-PORT') else: signalPort = createSubElement( ecuCommPortInstances, 'I-SIGNAL-PORT') createSubElement(signalPort, 'SHORT-NAME', signal.name) createSubElement( signalPort, 'COMMUNICATION-DIRECTION', 'OUT') if ecu.name in frame.receiver: frameport = createSubElement( ecuCommPortInstances, 'FRAME-PORT') createSubElement(frameport, 'SHORT-NAME', frame.name) createSubElement( frameport, 'COMMUNICATION-DIRECTION', 'IN') recTemp = 1 if ecu.name + "_Tx" not in rxIPduGroups: rxIPduGroups[ecu.name + "_Rx"] = [] rxIPduGroups[ecu.name + "_Rx"].append(frame.name) # missing I-PDU-PORT for signal in frame.signals: if ecu.name in signal.receiver: if arVersion[0] == "3": signalPort = createSubElement( ecuCommPortInstances, 'SIGNAL-PORT') else: signalPort = createSubElement( ecuCommPortInstances, 'I-SIGNAL-PORT') createSubElement( signalPort, 'SHORT-NAME', signal.name) createSubElement( signalPort, 'COMMUNICATION-DIRECTION', 'IN') if recTemp is not None: if arVersion[0] == "3": assoIpduGroupRef = createSubElement( assoIpduGroupRefs, 'ASSOCIATED-I-PDU-GROUP-REF') assoIpduGroupRef.set('DEST', "I-PDU-GROUP") else: assoIpduGroupRef = createSubElement( assoIpduGroupRefs, 'ASSOCIATED-COM-I-PDU-GROUP-REF') assoIpduGroupRef.set('DEST', "I-SIGNAL-I-PDU-GROUP") assoIpduGroupRef.text = "/IPDUGroup/" + ecu.name + "_Rx" if sendTemp is not None: if arVersion[0] == "3": assoIpduGroupRef = createSubElement( assoIpduGroupRefs, 'ASSOCIATED-I-PDU-GROUP-REF') assoIpduGroupRef.set('DEST', "I-PDU-GROUP") else: assoIpduGroupRef = createSubElement( assoIpduGroupRefs, 'ASSOCIATED-COM-I-PDU-GROUP-REF') assoIpduGroupRef.set('DEST', "I-SIGNAL-I-PDU-GROUP") assoIpduGroupRef.text = "/IPDUGroup/" + ecu.name + "_Tx" # # AR-PACKAGE IPDUGroup # arPackage = createSubElement(toplevelPackages, 'AR-PACKAGE') createSubElement(arPackage, 'SHORT-NAME', 'IPDUGroup') elements = createSubElement(arPackage, 'ELEMENTS') for pdugrp in txIPduGroups: if arVersion[0] == "3": ipduGrp = createSubElement(elements, 'I-PDU-GROUP') else: ipduGrp = createSubElement(elements, 'I-SIGNAL-I-PDU-GROUP') createSubElement(ipduGrp, 'SHORT-NAME', pdugrp) createSubElement(ipduGrp, 'COMMUNICATION-DIRECTION', "OUT") if arVersion[0] == "3": ipduRefs = createSubElement(ipduGrp, 'I-PDU-REFS') for frame in txIPduGroups[pdugrp]: ipduRef = createSubElement(ipduRefs, 'I-PDU-REF') ipduRef.set('DEST', "SIGNAL-I-PDU") ipduRef.text = "/PDU/PDU_" + frame else: isignalipdus = createSubElement(ipduGrp, 'I-SIGNAL-I-PDUS') for frame in txIPduGroups[pdugrp]: isignalipdurefconditional = createSubElement( isignalipdus, 'I-SIGNAL-I-PDU-REF-CONDITIONAL') ipduRef = createSubElement( isignalipdurefconditional, 'I-SIGNAL-I-PDU-REF') ipduRef.set('DEST', "I-SIGNAL-I-PDU") ipduRef.text = "/PDU/PDU_" + frame if arVersion[0] == "3": for pdugrp in rxIPduGroups: ipduGrp = createSubElement(elements, 'I-PDU-GROUP') createSubElement(ipduGrp, 'SHORT-NAME', pdugrp) createSubElement(ipduGrp, 'COMMUNICATION-DIRECTION', "IN") ipduRefs = createSubElement(ipduGrp, 'I-PDU-REFS') for frame in rxIPduGroups[pdugrp]: ipduRef = createSubElement(ipduRefs, 'I-PDU-REF') ipduRef.set('DEST', "SIGNAL-I-PDU") ipduRef.text = "/PDU/PDU_" + frame else: for pdugrp in rxIPduGroups: ipduGrp = createSubElement(elements, 'I-SIGNAL-I-PDU-GROUP') createSubElement(ipduGrp, 'SHORT-NAME', pdugrp) createSubElement(ipduGrp, 'COMMUNICATION-DIRECTION', "IN") isignalipdus = createSubElement(ipduGrp, 'I-SIGNAL-I-PDUS') for frame in rxIPduGroups[pdugrp]: isignalipdurefconditional = createSubElement( isignalipdus, 'I-SIGNAL-I-PDU-REF-CONDITIONAL') ipduRef = createSubElement( isignalipdurefconditional, 'I-SIGNAL-I-PDU-REF') ipduRef.set('DEST', "I-SIGNAL-I-PDU") ipduRef.text = "/PDU/PDU_" + frame f.write(etree.tostring(root, pretty_print=True, xml_declaration=True)) ################################### # read ARXML ################################### class arTree(object): def __init__(self, name="", ref=None): self._name = name self._ref = ref self._array = [] def new(self, name, child): temp = arTree(name, child) self._array.append(temp) return temp def getChild(self, path): for tem in self._array: if tem._name == path: return tem def arParseTree(tag, ardict, namespace): for child in tag: name = child.find('./' + namespace + 'SHORT-NAME') # namel = child.find('./' + namespace + 'LONG-NAME') if name is not None and child is not None: arParseTree(child, ardict.new(name.text, child), namespace) if name is None and child is not None: arParseTree(child, ardict, namespace) # # some sort of X-Path in autosar-xml-files: # def arGetXchildren(root, path, arDict, ns): pathElements = path.split('/') ptr = root for element in pathElements[:-1]: ptr = arGetChild(ptr, element, arDict, ns) ptr = arGetChildren(ptr, pathElements[-1], arDict, ns) return ptr # # get path in tranlation-dictionary # def arGetPath(ardict, path): ptr = ardict for p in path.split('/'): if p.strip(): if ptr is not None: ptr = ptr.getChild(p) else: return None if ptr is not None: return ptr._ref else: return None def arGetChild(parent, tagname, arTranslationTable, namespace): # logger.debug("getChild: " + tagname) if parent is None: return None ret = parent.find('.//' + namespace + tagname) if ret is None: ret = parent.find('.//' + namespace + tagname + '-REF') if ret is not None: ret = arGetPath(arTranslationTable, ret.text) return ret def arGetChildren(parent, tagname, arTranslationTable, namespace): if parent is None: return [] ret = parent.findall('.//' + namespace + tagname) if ret.__len__() == 0: retlist = parent.findall('.//' + namespace + tagname + '-REF') rettemp = [] for ret in retlist: rettemp.append(arGetPath(arTranslationTable, ret.text)) ret = rettemp return ret def arGetName(parent, ns): name = parent.find('./' + ns + 'SHORT-NAME') if name is not None: if name.text is not None: return name.text return "" pduFrameMapping = {} signalRxs = {} def getSysSignals(syssignal, syssignalarray, Bo, Id, ns): members = [] for signal in syssignalarray: members.append(arGetName(signal, ns)) Bo.addSignalGroup(arGetName(syssignal, ns), 1, members) def getSignals(signalarray, Bo, arDict, ns, multiplexId): GroupId = 1 if signalarray is None: # Empty signalarray - nothing to do return for signal in signalarray: values = {} motorolla = arGetChild(signal, "PACKING-BYTE-ORDER", arDict, ns) startBit = arGetChild(signal, "START-POSITION", arDict, ns) isignal = arGetChild(signal, "SIGNAL", arDict, ns) if isignal is None: isignal = arGetChild(signal, "I-SIGNAL", arDict, ns) if isignal is None: isignal = arGetChild(signal, "I-SIGNAL-GROUP", arDict, ns) if isignal is not None: logger.debug("getSignals: found I-SIGNAL-GROUP ") isignalarray = arGetXchildren(isignal, "I-SIGNAL", arDict, ns) getSysSignals(isignal, isignalarray, Bo, GroupId, ns) GroupId = GroupId + 1 continue if isignal is None: logger.debug( 'Frame %s, no isignal for %s found', Bo.name, arGetChild( signal, "SHORT-NAME", arDict, ns).text) syssignal = arGetChild(isignal, "SYSTEM-SIGNAL", arDict, ns) if syssignal is None: logger.debug( 'Frame %s, signal %s has no systemsignal', isignal.tag, Bo.name) if "SYSTEM-SIGNAL-GROUP" in syssignal.tag: syssignalarray = arGetXchildren( syssignal, "SYSTEM-SIGNAL-REFS/SYSTEM-SIGNAL", arDict, ns) getSysSignals(syssignal, syssignalarray, Bo, GroupId, ns) GroupId = GroupId + 1 continue length = arGetChild(isignal, "LENGTH", arDict, ns) if length is None: length = arGetChild(syssignal, "LENGTH", arDict, ns) name = arGetChild(syssignal, "SHORT-NAME", arDict, ns) unitElement = arGetChild(isignal, "UNIT", arDict, ns) displayName = arGetChild(unitElement, "DISPLAY-NAME", arDict, ns) if displayName is not None: Unit = displayName.text else: Unit = "" Min = None Max = None factor = 1.0 offset = 0 receiver = [] signalDescription = getDesc(syssignal, arDict, ns) datatype = arGetChild(syssignal, "DATA-TYPE", arDict, ns) if datatype is None: # AR4? dataConstr = arGetChild(isignal,"DATA-CONSTR", arDict, ns) compuMethod = arGetChild(isignal,"COMPU-METHOD", arDict, ns) baseType = arGetChild(isignal,"BASE-TYPE", arDict, ns) lower = arGetChild(dataConstr, "LOWER-LIMIT", arDict, ns) upper = arGetChild(dataConstr, "UPPER-LIMIT", arDict, ns) # if lower is None: # data-constr has no limits defined - use limit from compu-method # lower = arGetChild(compuMethod, "LOWER-LIMIT", arDict, ns) # if upper is None: # data-constr has no limits defined - use limit from compu-method # upper = arGetChild(compuMethod, "UPPER-LIMIT", arDict, ns) encoding = None # TODO - find encoding in AR4 else: lower = arGetChild(datatype, "LOWER-LIMIT", arDict, ns) upper = arGetChild(datatype, "UPPER-LIMIT", arDict, ns) encoding = arGetChild(datatype, "ENCODING", arDict, ns) if encoding is not None and (encoding.text == "SINGLE" or encoding.text == "DOUBLE"): is_float = True else: is_float = False if lower is not None and upper is not None: Min = float(lower.text) Max = float(upper.text) datdefprops = arGetChild(datatype, "SW-DATA-DEF-PROPS", arDict, ns) compmethod = arGetChild(datdefprops, "COMPU-METHOD", arDict, ns) if compmethod is None: # AR4 compmethod = arGetChild(isignal, "COMPU-METHOD", arDict, ns) baseType = arGetChild(isignal, "BASE-TYPE", arDict, ns) encoding = arGetChild(baseType, "BASE-TYPE-ENCODING", arDict, ns) if encoding is not None and encoding.text == "IEEE754": is_float = True ##################################################################################################### # Modification to support sourcing the COMPU_METHOD info from the Vector NETWORK-REPRESENTATION-PROPS # keyword definition. 06Jun16 ##################################################################################################### if compmethod == None: logger.debug('No Compmethod found!! - try alternate scheme.') networkrep = arGetChild(isignal, "NETWORK-REPRESENTATION-PROPS", arDict, ns) datdefpropsvar = arGetChild(networkrep, "SW-DATA-DEF-PROPS-VARIANTS", arDict, ns) datdefpropscond = arGetChild(datdefpropsvar, "SW-DATA-DEF-PROPS-CONDITIONAL", arDict ,ns) if datdefpropscond != None: try: compmethod = arGetChild(datdefpropscond, "COMPU-METHOD", arDict, ns) except: logger.debug('No valid compu method found for this - check ARXML file!!') compmethod = None ##################################################################################################### ##################################################################################################### unit = arGetChild(compmethod, "UNIT", arDict, ns) if unit is not None: longname = arGetChild(unit, "LONG-NAME", arDict, ns) ##################################################################################################### # Modification to support obtaining the Signals Unit by DISPLAY-NAME. 07June16 ##################################################################################################### try: displayname = arGetChild(unit, "DISPLAY-NAME", arDict, ns) except: logger.debug('No Unit Display name found!! - using long name') if displayname is not None: Unit = displayname.text else: ##################################################################################################### ##################################################################################################### l4 = arGetChild(longname, "L-4", arDict, ns) if l4 is not None: Unit = l4.text compuscales = arGetXchildren( compmethod, "COMPU-INTERNAL-TO-PHYS/COMPU-SCALES/COMPU-SCALE", arDict, ns) initvalue = arGetXchildren(syssignal, "INIT-VALUE/VALUE", arDict, ns) if initvalue is None or initvalue.__len__() == 0: initvalue = arGetXchildren(isignal, "INIT-VALUE/NUMERICAL-VALUE-SPECIFICATION/VALUE", arDict, ns) ##AR4.2 if initvalue is not None and initvalue.__len__() >= 1: initvalue = initvalue[0] else: initvalue = None for compuscale in compuscales: ll = arGetChild(compuscale, "LOWER-LIMIT", arDict, ns) ul = arGetChild(compuscale, "UPPER-LIMIT", arDict, ns) sl = arGetChild(compuscale, "SHORT-LABEL", arDict, ns) if sl is None: desc = getDesc(compuscale, arDict, ns) else: desc = sl.text ##################################################################################################### # Modification to support sourcing the COMPU_METHOD info from the Vector NETWORK-REPRESENTATION-PROPS # keyword definition. 06Jun16 ##################################################################################################### if ll is not None and desc is not None and int(float(ul.text)) == int(float(ll.text)): ##################################################################################################### ##################################################################################################### values[ll.text] = desc scaleDesc = getDesc(compuscale, arDict, ns) rational = arGetChild( compuscale, "COMPU-RATIONAL-COEFFS", arDict, ns) if rational is not None: numerator = arGetChild(rational, "COMPU-NUMERATOR", arDict, ns) zaehler = arGetChildren(numerator, "V", arDict, ns) denominator = arGetChild( rational, "COMPU-DENOMINATOR", arDict, ns) nenner = arGetChildren(denominator, "V", arDict, ns) factor = float(zaehler[1].text) / float(nenner[0].text) offset = float(zaehler[0].text) / float(nenner[0].text) if Min is not None: Min *= factor Min += offset if Max is not None: Max *= factor Max += offset else: const = arGetChild(compuscale, "COMPU-CONST", arDict, ns) # value hinzufuegen if const is None: logger.warn( "unknown Compu-Method: " + compmethod.get('UUID')) is_little_endian = False if motorolla.text == 'MOST-SIGNIFICANT-BYTE-LAST': is_little_endian = True is_signed = False # unsigned if name is None: logger.debug('no name for signal given') if startBit is None: logger.debug('no startBit for signal given') if length is None: logger.debug('no length for signal given') if startBit is not None: newSig = Signal(name.text, startBit=startBit.text, signalSize=length.text, is_little_endian=is_little_endian, is_signed=is_signed, factor=factor, offset=offset, min=Min, max=Max, unit=Unit, receiver=receiver, multiplex=multiplexId, comment=signalDescription, is_float=is_float) if newSig.is_little_endian == 0: # startbit of motorola coded signals are MSB in arxml newSig.setStartbit(int(startBit.text), bitNumbering=1) signalRxs[syssignal] = newSig basetype = arGetChild(datdefprops, "BASE-TYPE", arDict, ns) if basetype is not None: temp = arGetChild(basetype, "SHORT-NAME", arDict, ns) if temp is not None and "boolean" == temp.text: newSig.addValues(1, "TRUE") newSig.addValues(0, "FALSE") if initvalue is not None and initvalue.text is not None: if initvalue.text == "false": initvalue.text = "0" elif initvalue.text == "true": initvalue.text = "1" newSig._initValue = int(initvalue.text) newSig.addAttribute("GenSigStartValue", str(newSig._initValue)) else: newSig._initValue = 0 for key, value in list(values.items()): newSig.addValues(key, value) Bo.addSignal(newSig) def getFrame(frameTriggering, arDict, multiplexTranslation, ns): extEle = arGetChild(frameTriggering, "CAN-ADDRESSING-MODE", arDict, ns) idele = arGetChild(frameTriggering, "IDENTIFIER", arDict, ns) frameR = arGetChild(frameTriggering, "FRAME", arDict, ns) sn = arGetChild(frameTriggering, "SHORT-NAME", arDict, ns) logger.debug("processing Frame: %s", sn.text) idNum = int(idele.text) if None != frameR: dlc = arGetChild(frameR, "FRAME-LENGTH", arDict, ns) pdumappings = arGetChild(frameR, "PDU-TO-FRAME-MAPPINGS", arDict, ns) pdumapping = arGetChild( pdumappings, "PDU-TO-FRAME-MAPPING", arDict, ns) pdu = arGetChild(pdumapping, "PDU", arDict, ns) # SIGNAL-I-PDU # newFrame = Frame(idNum, arGetName(frameR, ns), int(dlc.text), None) if 'SECURED-I-PDU' in pdu.tag: logger.info("found secured pdu - no signal extraction possible: %s", arGetName(pdu,ns)) pduFrameMapping[pdu] = arGetName(frameR, ns) newFrame = Frame(arGetName(frameR, ns), Id=idNum, dlc=int(dlc.text)) comment = getDesc(frameR, arDict, ns) if comment is not None: newFrame.addComment(comment) else: # without frameinfo take short-name of frametriggering and dlc = 8 logger.debug("Frame %s has no FRAME-REF" % (sn)) ipduTriggeringRefs = arGetChild( frameTriggering, "I-PDU-TRIGGERING-REFS", arDict, ns) ipduTriggering = arGetChild( ipduTriggeringRefs, "I-PDU-TRIGGERING", arDict, ns) pdu = arGetChild(ipduTriggering, "I-PDU", arDict, ns) if pdu is None: pdu = arGetChild(ipduTriggering, "I-SIGNAL-I-PDU", arDict, ns) ## AR4.2 dlc = arGetChild(pdu, "LENGTH", arDict, ns) # newFrame = Frame(idNum, sn.text, int(int(dlc.text)/8), None) newFrame = Frame(sn.text, Id=idNum, dlc=int(dlc.text) / 8) if pdu is None: logger.error("ERROR: pdu") else: logger.debug(arGetName(pdu, ns)) if "MULTIPLEXED-I-PDU" in pdu.tag: selectorByteOrder = arGetChild( pdu, "SELECTOR-FIELD-BYTE-ORDER", arDict, ns) selectorLen = arGetChild(pdu, "SELECTOR-FIELD-LENGTH", arDict, ns) selectorStart = arGetChild( pdu, "SELECTOR-FIELD-START-POSITION", arDict, ns) is_little_endian = False if selectorByteOrder.text == 'MOST-SIGNIFICANT-BYTE-LAST': is_little_endian = True is_signed = False # unsigned multiplexor = Signal("Multiplexor", startBit=selectorStart.text, signalSize=selectorLen.text, is_little_endian=is_little_endian, multiplex="Multiplexor") multiplexor._initValue = 0 newFrame.addSignal(multiplexor) staticPart = arGetChild(pdu, "STATIC-PART", arDict, ns) ipdu = arGetChild(staticPart, "I-PDU", arDict, ns) if ipdu is not None: pdusigmappings = arGetChild( ipdu, "SIGNAL-TO-PDU-MAPPINGS", arDict, ns) pdusigmapping = arGetChildren( pdusigmappings, "I-SIGNAL-TO-I-PDU-MAPPING", arDict, ns) getSignals(pdusigmapping, newFrame, arDict, ns, None) multiplexTranslation[arGetName(ipdu, ns)] = arGetName(pdu, ns) dynamicPart = arGetChild(pdu, "DYNAMIC-PART", arDict, ns) # segmentPositions = arGetChild(dynamicPart, "SEGMENT-POSITIONS", arDict, ns) # segmentPosition = arGetChild(segmentPositions, "SEGMENT-POSITION", arDict, ns) # byteOrder = arGetChild(segmentPosition, "SEGMENT-BYTE-ORDER", arDict, ns) # segLength = arGetChild(segmentPosition, "SEGMENT-LENGTH", arDict, ns) # segPos = arGetChild(segmentPosition, "SEGMENT-POSITION", arDict, ns) dynamicPartAlternatives = arGetChild( dynamicPart, "DYNAMIC-PART-ALTERNATIVES", arDict, ns) dynamicPartAlternativeList = arGetChildren( dynamicPartAlternatives, "DYNAMIC-PART-ALTERNATIVE", arDict, ns) for alternative in dynamicPartAlternativeList: selectorId = arGetChild( alternative, "SELECTOR-FIELD-CODE", arDict, ns) ipdu = arGetChild(alternative, "I-PDU", arDict, ns) multiplexTranslation[arGetName(ipdu, ns)] = arGetName(pdu, ns) if ipdu is not None: pdusigmappings = arGetChild( ipdu, "SIGNAL-TO-PDU-MAPPINGS", arDict, ns) pdusigmapping = arGetChildren( pdusigmappings, "I-SIGNAL-TO-I-PDU-MAPPING", arDict, ns) getSignals( pdusigmapping, newFrame, arDict, ns, selectorId.text) if newFrame.comment is None: newFrame.addComment(getDesc(pdu, arDict, ns)) if extEle is not None: if extEle.text == 'EXTENDED': newFrame.extended = 1 timingSpec = arGetChild(pdu, "I-PDU-TIMING-SPECIFICATION", arDict, ns) cyclicTiming = arGetChild(timingSpec, "CYCLIC-TIMING", arDict, ns) repeatingTime = arGetChild(cyclicTiming, "REPEATING-TIME", arDict, ns) eventTiming = arGetChild(timingSpec, "EVENT-CONTROLLED-TIMING", arDict, ns) repeats = arGetChild(eventTiming, "NUMBER-OF-REPEATS", arDict, ns) minimumDelay = arGetChild(timingSpec, "MINIMUM-DELAY", arDict, ns) startingTime = arGetChild(timingSpec, "STARTING-TIME", arDict, ns) if cyclicTiming is not None and eventTiming is not None: newFrame.addAttribute("GenMsgSendType", "5") # CycleAndSpontan if minimumDelay is not None: newFrame.addAttribute("GenMsgDelayTime", str( int(float(minimumDelay.text) * 1000))) if repeats is not None: newFrame.addAttribute("GenMsgNrOfRepetitions", repeats.text) elif cyclicTiming is not None: newFrame.addAttribute("GenMsgSendType", "0") # CycleX if minimumDelay is not None: newFrame.addAttribute("GenMsgDelayTime", str( int(float(minimumDelay.text) * 1000))) if repeats is not None: newFrame.addAttribute("GenMsgNrOfRepetitions", repeats.text) else: newFrame.addAttribute("GenMsgSendType", "1") # Spontan if minimumDelay is not None: newFrame.addAttribute("GenMsgDelayTime", str( int(float(minimumDelay.text) * 1000))) if repeats is not None: newFrame.addAttribute("GenMsgNrOfRepetitions", repeats.text) if startingTime is not None: value = arGetChild(startingTime, "VALUE", arDict, ns) newFrame.addAttribute("GenMsgStartDelayTime", str(int(float(value.text) * 1000))) value = arGetChild(repeatingTime, "VALUE", arDict, ns) if value is not None: newFrame.addAttribute("GenMsgCycleTime", str(int(float(value.text) * 1000))) # pdusigmappings = arGetChild(pdu, "SIGNAL-TO-PDU-MAPPINGS", arDict, ns) # if pdusigmappings is None or pdusigmappings.__len__() == 0: # logger.debug("DEBUG: Frame %s no SIGNAL-TO-PDU-MAPPINGS found" % (newFrame.name)) pdusigmapping = arGetChildren(pdu, "I-SIGNAL-TO-I-PDU-MAPPING", arDict, ns) if pdusigmapping is not None and pdusigmapping.__len__() > 0: getSignals(pdusigmapping, newFrame, arDict, ns, None) # Seen some pdusigmapping being [] and not None with some arxml 4.2 else: ##AR 4.2 pdutrigs = arGetChildren(frameTriggering, "PDU-TRIGGERINGS", arDict, ns) if pdutrigs is not None: for pdutrig in pdutrigs: trigrefcond = arGetChild(pdutrig, "PDU-TRIGGERING-REF-CONDITIONAL", arDict, ns) trigs = arGetChild(trigrefcond, "PDU-TRIGGERING", arDict, ns) ipdus = arGetChild(trigs, "I-PDU", arDict, ns) signaltopdumaps = arGetChild(ipdus, "I-SIGNAL-TO-PDU-MAPPINGS", arDict, ns) if signaltopdumaps is None: logger.debug("DEBUG: AR4.x PDU %s no SIGNAL-TO-PDU-MAPPINGS found - no signal extraction!" % (arGetName(ipdus, ns))) # signaltopdumap = arGetChild(signaltopdumaps, "I-SIGNAL-TO-I-PDU-MAPPING", arDict, ns) getSignals(signaltopdumaps, newFrame, arDict, ns, None) else: logger.debug( "DEBUG: Frame %s (assuming AR4.2) no PDU-TRIGGERINGS found" % (newFrame.name)) return newFrame def getDesc(element, arDict, ns): desc = arGetChild(element, "DESC", arDict, ns) txt = arGetChild(desc, 'L-2[@L="DE"]', arDict, ns) if txt is None: txt = arGetChild(desc, 'L-2[@L="EN"]', arDict, ns) if txt is None: txt = arGetChild(desc, 'L-2', arDict, ns) if txt is not None: return txt.text else: return "" def processEcu(ecu, db, arDict, multiplexTranslation, ns): connectors = arGetChild(ecu, "CONNECTORS", arDict, ns) diagAddress = arGetChild(ecu, "DIAGNOSTIC-ADDRESS", arDict, ns) diagResponse = arGetChild(ecu, "RESPONSE-ADDRESSS", arDict, ns) # TODO: use diagAddress for frame-classification commconnector = arGetChild( connectors, "COMMUNICATION-CONNECTOR", arDict, ns) if commconnector is None: commconnector = arGetChild( connectors, "CAN-COMMUNICATION-CONNECTOR", arDict, ns) frames = arGetXchildren( commconnector, "ECU-COMM-PORT-INSTANCES/FRAME-PORT", arDict, ns) nmAddress = arGetChild(commconnector, "NM-ADDRESS", arDict, ns) assocRefs = arGetChild(ecu, "ASSOCIATED-I-PDU-GROUP-REFS", arDict, ns) if assocRefs is not None: assoc = arGetChildren(assocRefs, "ASSOCIATED-I-PDU-GROUP", arDict, ns) else: # AR4 assocRefs = arGetChild( ecu, "ASSOCIATED-COM-I-PDU-GROUP-REFS", arDict, ns) assoc = arGetChildren( assocRefs, "ASSOCIATED-COM-I-PDU-GROUP", arDict, ns) inFrame = [] outFrame = [] # get direction of frames (is current ECU sender/receiver/...?) for ref in assoc: direction = arGetChild(ref, "COMMUNICATION-DIRECTION", arDict, ns) groupRefs = arGetChild(ref, "CONTAINED-I-PDU-GROUPS-REFS", arDict, ns) pdurefs = arGetChild(ref, "I-PDU-REFS", arDict, ns) if pdurefs is not None: # AR3 # local defined pdus pdus = arGetChildren(pdurefs, "I-PDU", arDict, ns) for pdu in pdus: if pdu in pduFrameMapping: if direction.text == "IN": inFrame.append(pduFrameMapping[pdu]) else: outFrame.append(pduFrameMapping[pdu]) else: # AR4 isigpdus = arGetChild(ref, "I-SIGNAL-I-PDUS", arDict, ns) isigconds = arGetChildren( isigpdus, "I-SIGNAL-I-PDU-REF-CONDITIONAL", arDict, ns) for isigcond in isigconds: pdus = arGetChildren(isigcond, "I-SIGNAL-I-PDU", arDict, ns) for pdu in pdus: if pdu in pduFrameMapping: if direction.text == "IN": inFrame.append(pduFrameMapping[pdu]) else: outFrame.append(pduFrameMapping[pdu]) # grouped pdus group = arGetChildren(groupRefs, "CONTAINED-I-PDU-GROUPS", arDict, ns) for t in group: if direction is None: direction = arGetChild( t, "COMMUNICATION-DIRECTION", arDict, ns) pdurefs = arGetChild(t, "I-PDU-REFS", arDict, ns) pdus = arGetChildren(pdurefs, "I-PDU", arDict, ns) for pdu in pdus: if direction.text == "IN": inFrame.append(arGetName(pdu, ns)) else: outFrame.append(arGetName(pdu, ns)) for out in outFrame: if out in multiplexTranslation: out = multiplexTranslation[out] frame = db.frameByName(out) if frame is not None: frame.addTransmitter(arGetName(ecu, ns)) else: pass # for inf in inFrame: # if inf in multiplexTranslation: # inf = multiplexTranslation[inf] # frame = db.frameByName(inf) # if frame is not None: # for signal in frame.signals: # recname = arGetName(ecu, ns) # if recname not in signal.receiver: # signal.receiver.append(recname) # else: # print "in not found: " + inf bu = BoardUnit(arGetName(ecu, ns)) if nmAddress is not None: bu.addAttribute("NWM-Stationsadresse", nmAddress.text) bu.addAttribute("NWM-Knoten", "1") else: bu.addAttribute("NWM-Stationsadresse", "0") bu.addAttribute("NWM-Knoten", "0") return bu def load(file, **options): pduFrameMapping = {} signalRxs = {} if 'arxmlIgnoreClusterInfo' in options: ignoreClusterInfo = options["arxmlIgnoreClusterInfo"] else: ignoreClusterInfo = False result = {} logger.debug("Read arxml ...") tree = etree.parse(file) root = tree.getroot() logger.debug(" Done\n") ns = "{" + tree.xpath('namespace-uri(.)') + "}" nsp = tree.xpath('namespace-uri(.)') topLevelPackages = root.find('./' + ns + 'TOP-LEVEL-PACKAGES') if None == topLevelPackages: # no "TOP-LEVEL-PACKAGES found, try root topLevelPackages = root logger.debug("Build arTree ...") arDict = arTree() arParseTree(topLevelPackages, arDict, ns) logger.debug(" Done\n") frames = root.findall('.//' + ns + 'CAN-FRAME') ## AR4.2 if frames is None: frames = root.findall('.//' + ns + 'FRAME') ## AR3.2-4.1? logger.debug("DEBUG %d frames in arxml..." % (frames.__len__())) canTriggers = root.findall('.//' + ns + 'CAN-FRAME-TRIGGERING') logger.debug( "DEBUG %d can-frame-triggering in arxml..." % (canTriggers.__len__())) sigpdumap = root.findall('.//' + ns + 'SIGNAL-TO-PDU-MAPPINGS') logger.debug( "DEBUG %d SIGNAL-TO-PDU-MAPPINGS in arxml..." % (sigpdumap.__len__())) sigIpdu = root.findall('.//' + ns + 'I-SIGNAL-TO-I-PDU-MAPPING') logger.debug( "DEBUG %d I-SIGNAL-TO-I-PDU-MAPPING in arxml..." % (sigIpdu.__len__())) if ignoreClusterInfo == True: ccs = {"ignoreClusterInfo"} else: ccs = root.findall('.//' + ns + 'CAN-CLUSTER') for cc in ccs: db = CanMatrix() # Defines not jet imported... db.addBUDefines("NWM-Stationsadresse", 'HEX 0 63') db.addBUDefines("NWM-Knoten", 'ENUM "nein","ja"') db.addFrameDefines("GenMsgCycleTime", 'INT 0 65535') db.addFrameDefines("GenMsgDelayTime", 'INT 0 65535') db.addFrameDefines("GenMsgNrOfRepetitions", 'INT 0 65535') db.addFrameDefines("GenMsgStartValue", 'STRING') db.addFrameDefines("GenMsgStartDelayTime", 'INT 0 65535') db.addFrameDefines( "GenMsgSendType", 'ENUM "cyclicX","spontanX","cyclicIfActiveX","spontanWithDelay","cyclicAndSpontanX","cyclicAndSpontanWithDelay","spontanWithRepitition","cyclicIfActiveAndSpontanWD","cyclicIfActiveFast","cyclicWithRepeatOnDemand","none"') db.addSignalDefines("GenSigStartValue", 'HEX 0 4294967295') if ignoreClusterInfo == True: canframetrig = root.findall('.//' + ns + 'CAN-FRAME-TRIGGERING') busname = "" else: speed = arGetChild(cc, "SPEED", arDict, ns) logger.debug("Busname: " + arGetName(cc, ns)) if speed is not None: logger.debug(" Speed: " + speed.text) busname = arGetName(cc, ns) if speed is not None: logger.debug(" Speed: " + speed.text) physicalChannels = cc.find('.//' + ns + "PHYSICAL-CHANNELS") if physicalChannels is None: logger.error("Error - PHYSICAL-CHANNELS not found") nmLowerId = arGetChild(cc, "NM-LOWER-CAN-ID", arDict, ns) physicalChannel = arGetChild( physicalChannels, "PHYSICAL-CHANNEL", arDict, ns) if physicalChannel is None: physicalChannel = arGetChild( physicalChannels, "CAN-PHYSICAL-CHANNEL", arDict, ns) if physicalChannel is None: logger.debug("Error - PHYSICAL-CHANNEL not found") canframetrig = arGetChildren( physicalChannel, "CAN-FRAME-TRIGGERING", arDict, ns) if canframetrig is None: logger.error("Error - CAN-FRAME-TRIGGERING not found") else: logger.debug( "%d frames found in arxml\n" % (canframetrig.__len__())) multiplexTranslation = {} for frameTrig in canframetrig: db._fl.addFrame( getFrame( frameTrig, arDict, multiplexTranslation, ns)) if ignoreClusterInfo == True: pass # no support for signal direction else: isignaltriggerings = arGetXchildren( physicalChannel, "I-SIGNAL-TRIGGERING", arDict, ns) for sigTrig in isignaltriggerings: isignal = arGetChild(sigTrig, 'SIGNAL', arDict, ns) if isignal is None: isignal = arGetChild(sigTrig, 'I-SIGNAL', arDict, ns) if isignal is None: sigTrig_text = arGetName(sigTrig, ns) if sigTrig is not None else "None" logger.debug("load: no isignal for %s" % sigTrig_text) continue portRef = arGetChildren(sigTrig, "I-SIGNAL-PORT", arDict, ns) for port in portRef: comDir = arGetChild( port, "COMMUNICATION-DIRECTION", arDict, ns) if comDir is not None and comDir.text == "IN": sysSignal = arGetChild( isignal, "SYSTEM-SIGNAL", arDict, ns) ecuName = arGetName( port.getparent().getparent().getparent().getparent(), ns) # port points in ECU; probably more stable to go up # from each ECU than to go down in XML... if sysSignal in signalRxs: if ecuName not in signalRxs[sysSignal].receiver: signalRxs[sysSignal].receiver.append(ecuName) # find ECUs: nodes = root.findall('.//' + ns + 'ECU-INSTANCE') for node in nodes: bu = processEcu(node, db, arDict, multiplexTranslation, ns) desc = arGetChild(node, "DESC", arDict, ns) l2 = arGetChild(desc, "L-2", arDict, ns) if l2 is not None: bu.addComment(l2.text) db._BUs.add(bu) for bo in db.frames: frame = 0 for sig in bo.signals: if sig._initValue != 0: stbit = sig.getStartbit(bitNumbering=1, startLittle=True) frame |= computeSignalValueInFrame( sig.getStartbit( bitNumbering=1, startLittle=True), sig.signalsize, sig.is_little_endian, sig._initValue) fmt = "%0" + "%d" % bo.size + "X" bo.addAttribute("GenMsgStartValue", fmt % frame) result[busname] = db return result canmatrix-0.6/canmatrix/cancluster.py0000664000175000017500000000446513001475401017432 0ustar eduedu00000000000000class canCluster(dict): def __init__(self, *arg, **kw): super(canCluster, self).__init__(*arg, **kw) self.update() def updateFrames(self): frameArray = [] frameArrayName = [] for matrixName in self: for frame in self[matrixName].frames: if frame._name not in frameArrayName: frameArrayName.append(frame._name) frameArray.append(frame) else: index = frameArrayName.index(frame._name) for transmitter in frame.transmitter: frameArray[index].addTransmitter(transmitter) for receiver in frame.receiver: frameArray[index].addReceiver(receiver) self._frames = frameArray return frameArray def updateSignals(self): signalArray = [] signalArrayName = [] for matrixName in self: for frame in self[matrixName].frames: for signal in frame.signals: if signal._name not in signalArrayName: signalArrayName.append(signal._name) signalArray.append(signal) else: index = signalArrayName.index(signal._name) for receiver in signal.receiver: signalArray[index].addReceiver(receiver) self._signals = signalArray def updateECUs(self): ECUArray = [] ECUArrayName = [] for matrixName in self: for ecu in self[matrixName].boardUnits: if ecu._name not in ECUArrayName: ECUArrayName.append(ecu._name) ECUArray.append(ecu) self._ecus = ECUArray def update(self): self.updateFrames() self.updateSignals() self.updateECUs() @property def ecus(self): if not self._ecus: self.updateECUs() return self._ecus @property def boardUnits(self): return self.ecus @property def frames(self): if not self._frames: self.updateFrames() return self._frames @property def signals(self): if not self._signals: self.updateSignals() return self._signals canmatrix-0.6/canmatrix/formats.py0000664000175000017500000000754313166737333016763 0ustar eduedu00000000000000#!env python from importlib import import_module import sys import logging logger = logging.getLogger('root') import canmatrix import os moduleList = ["arxml", "cmcsv", "dbc", "dbf", "cmjson", "kcd", "fibex", "sym", "xls", "xlsx", "yaml"] loadedFormats = [] supportedFormats = {} extensionMapping = {} for module in moduleList: try: import_module("canmatrix." + module) loadedFormats.append(module) except ImportError: logger.info("%s is not supported", module) for loadedModule in loadedFormats: supportedFormats[loadedModule] = [] moduleInstance = sys.modules["canmatrix." + loadedModule] if "load" in dir(moduleInstance): supportedFormats[loadedModule].append("load") if "dump" in dir(moduleInstance): supportedFormats[loadedModule].append("dump") if "clusterImporter" in dir(moduleInstance): supportedFormats[loadedModule].append("clusterImporter") if "clusterExporter" in dir(moduleInstance): supportedFormats[loadedModule].append("clusterExporter") if "extension" in dir(moduleInstance): supportedFormats[loadedModule].append("extension") extensionMapping[loadedModule] = moduleInstance.extension else: extensionMapping[loadedModule] = loadedModule def loads(string, importType=None, key="", flatImport=None, **options): fileObject = StringIO.StringIO[string] return load(fileObject, importType, key, flatImport, **options) def loadp(path, importType=None, key="", flatImport=None, **options): fileObject = open(path, "rb") if not importType: for key, extension in extensionMapping.items(): if path.endswith(extension) and "load" in supportedFormats[key]: importType = key break if importType: return load(fileObject, importType, **options) else: logger.error("This file format is not supported for reading") return None def load(fileObject, importType, key="", flatImport=None, **options): dbs = {} moduleInstance = sys.modules["canmatrix." + importType] if "clusterImporter" in supportedFormats[importType]: dbs = moduleInstance.load(fileObject, **options) else: dbs[key] = moduleInstance.load(fileObject, **options) if flatImport: for key in dbs: return dbs[key] else: return dbs def dump(canMatrixOrCluster, fileObject, exportType, **options): moduleInstance = sys.modules["canmatrix." + exportType] if (sys.version_info > (3, 0) and type(canmatrix.canmatrix.CanMatrix()) == type(canMatrixOrCluster)) or \ (sys.version_info < (3, 0) and type(canmatrix.CanMatrix()) == type(canMatrixOrCluster)): moduleInstance.dump(canMatrixOrCluster, fileObject, **options) elif "clusterExporter" in supportedFormats[exportType]: moduleInstance.dump(canMatrixOrCluster, fileObject, **options) def dumpp(canCluster, path, exportType=None, **options): if not exportType: for key, extension in extensionMapping.items(): if path.endswith("." + extension) and "dump" in supportedFormats[key]: exportType = key break if exportType: if "clusterExporter" in supportedFormats[exportType]: fileObject = open(path, "wb") dump(canCluster, fileObject, exportType, **options) else: for name in canCluster: if len(name) > 0: (filepath, ext) = os.path.splitext(path) outfile = filepath + "_" + name + ext else: outfile = path db = canCluster[name] fileObject = open(outfile, "wb") dump(db, fileObject, exportType, **options) fileObject.close() else: logger.error("This file format is not supported for writing") return None canmatrix-0.6/canmatrix/convert.py0000664000175000017500000003351313166737333016764 0ustar eduedu00000000000000#!/usr/bin/env python3 # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. from __future__ import print_function from __future__ import absolute_import #from .log import setup_logger, set_log_level from canmatrix.log import setup_logger, set_log_level logger = setup_logger('root') import sys import os sys.path.append('..') import canmatrix.formats import canmatrix.canmatrix as cm import canmatrix.copy as cmcp def convert(infile, outfileName, **options): dbs = {} logger.info("Importing " + infile + " ... ") dbs = canmatrix.formats.loadp(infile, **options) logger.info("done\n") logger.info("Exporting " + outfileName + " ... ") outdbs = {} for name in dbs: db = None if 'ecus' in options and options['ecus'] is not None: ecuList = options['ecus'].split(',') db = cm.CanMatrix() for ecu in ecuList: logger.info("Copying ECU " + ecu) cmcp.copyBUwithFrames(ecu, dbs[name], db) if 'frames' in options and options['frames'] is not None: frameList = options['frames'].split(',') db = cm.CanMatrix() for frame in frameList: logger.info("Copying Frame " + frame) cmcp.copyFrame(frame, dbs[name], db) if db is None: db = dbs[name] if 'merge' in options and options['merge'] is not None: mergeFiles = options['merge'].split(',') for database in mergeFiles: mergeString = database.split(':') dbTempList = canmatrix.formats.loadp(mergeString[0]) for dbTemp in dbTempList: if mergeString.__len__() == 1: print ("merge complete: " + mergeString[0]) for frame in dbTempList[dbTemp].frames: cmcp.copyFrame(frame.id, dbTempList[dbTemp], db) for mergeOpt in mergeString[1:]: if mergeOpt.split('=')[0] == "ecu": cmcp.copyBUwithFrames( mergeOpt.split('=')[1], dbTempList[dbTemp], db) if mergeOpt.split('=')[0] == "frame": cmcp.copyFrame( mergeOpt.split('=')[1], dbTempList[dbTemp], db) if 'renameEcu' in options and options['renameEcu'] is not None: renameTuples = options['renameEcu'].split(',') for renameTuple in renameTuples: old, new = renameTuple.split(':') db.renameEcu(old, new) if 'deleteEcu' in options and options['deleteEcu'] is not None: deleteEcuList = options['deleteEcu'].split(',') for ecu in deleteEcuList: db.delEcu(ecu) if 'renameFrame' in options and options['renameFrame'] is not None: renameTuples = options['renameFrame'].split(',') for renameTuple in renameTuples: old, new = renameTuple.split(':') db.renameFrame(old, new) if 'deleteFrame' in options and options['deleteFrame'] is not None: deleteFrameList = options['deleteFrame'].split(',') for frame in deleteFrameList: db.delFrame(frame) if 'renameSignal' in options and options['renameSignal'] is not None: renameTuples = options['renameSignal'].split(',') for renameTuple in renameTuples: old, new = renameTuple.split(':') db.renameSignal(old, new) if 'deleteSignal' in options and options['deleteSignal'] is not None: deleteSignalList = options['deleteSignal'].split(',') for signal in deleteSignalList: db.delSignal(signal) if 'deleteZeroSignals' in options and options['deleteZeroSignals']: db.deleteZeroSignals() if 'deleteSignalAttributes' in options and options[ 'deleteSignalAttributes']: unwantedAttributes = options['deleteSignalAttributes'].split(',') db.delSignalAttributes(unwantedAttributes) if 'deleteFrameAttributes' in options and options[ 'deleteFrameAttributes']: unwantedAttributes = options['deleteFrameAttributes'].split(',') db.delFrameAttributes(unwantedAttributes) if 'deleteObsoleteDefines' in options and options[ 'deleteObsoleteDefines']: db.deleteObsoleteDefines() if 'recalcDLC' in options and options['recalcDLC']: db.recalcDLC(options['recalcDLC']) logger.info(name) logger.info("%d Frames found" % (db.frames.__len__())) outdbs[name] = db if 'force_output' in options and options['force_output'] is not None: canmatrix.formats.dumpp(outdbs, outfileName, exportType=options[ 'force_output'], **options) else: canmatrix.formats.dumpp(outdbs, outfileName, **options) logger.info("done") def main(): from optparse import OptionParser usage = """ %prog [options] import-file export-file import-file: *.dbc|*.dbf|*.kcd|*.arxml|*.json|*.xls(x)|*.sym export-file: *.dbc|*.dbf|*.kcd|*.arxml|*.json|*.xls(x)|*.sym following formats are available at this installation: \n""" for suppFormat, features in canmatrix.formats.supportedFormats.items(): usage += suppFormat + "\t" if 'load' in features: usage += "import" usage += "\t" if 'dump' in features: usage += "export" usage += "\n" parser = OptionParser(usage=usage) # parser.add_option("-d", "--debug", # dest="debug", default=False, # help="print debug messages to stdout") parser.add_option( "-v", dest="verbosity", action="count", help="Output verbosity", default=0) parser.add_option( "-s", dest="silent", action="store_true", help="don't print status messages to stdout. (only errors)", default=False) parser.add_option( "-f", dest="force_output", help="enforce output format, ignoring output file extension (e.g., -f csv") parser.add_option("", "--deleteZeroSignals", action="store_true", dest="deleteZeroSignals", default=False, help="delete zero length signals (signals with 0 bit length) from matrix\ndefault False") parser.add_option("", "--deleteSignalAttributes", dest="deleteSignalAttributes", default=None, help="delete attributes from all signals\nExample --deleteSignalAttributes GenMsgCycle,CycleTime") parser.add_option("", "--deleteFrameAttributes", dest="deleteFrameAttributes", default=None, help="delete attributes from all frames\nExample --deleteFrameAttributes GenMsgCycle,CycleTime") parser.add_option("", "--deleteObsoleteDefines", action="store_true", dest="deleteObsoleteDefines", default=False, help="delete defines from all Boardunits, frames and Signals\nExample --deleteObsoleteDefines") parser.add_option("", "--recalcDLC", dest="recalcDLC", default=False, help="recalculate dlc; max: use maximum of stored and calculated dlc; force: force new calculated dlc") parser.add_option("", "--arxmlIgnoreClusterInfo", action="store_true", dest="arxmlIgnoreClusterInfo", default=False, help="Ignore any can cluster info from arxml; Import all frames in one matrix\ndefault 0") parser.add_option("", "--arxmlExportVersion", dest="arVersion", default="3.2.3", help="Set output AUTOSAR version\ncurrently only 3.2.3 and 4.1.0 are supported\ndefault 3.2.3") parser.add_option("", "--dbcImportEncoding", dest="dbcImportEncoding", default="iso-8859-1", help="Import charset of dbc (relevant for units), maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--dbcImportCommentEncoding", dest="dbcImportCommentEncoding", default="iso-8859-1", help="Import charset of Comments in dbc\ndefault iso-8859-1") parser.add_option("", "--dbcExportEncoding", dest="dbcExportEncoding", default="iso-8859-1", help="Export charset of dbc (relevant for units), maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--dbcExportCommentEncoding", dest="dbcExportCommentEncoding", default="iso-8859-1", help="Export charset of comments in dbc\ndefault iso-8859-1") parser.add_option("", "--dbfImportEncoding", dest="dbfImportEncoding", default="iso-8859-1", help="Import charset of dbf, maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--dbfExportEncoding", dest="dbfExportEncoding", default="iso-8859-1", help="Export charset of dbf, maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--symImportEncoding", dest="symImportEncoding", default="iso-8859-1", help="Import charset of sym format, maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--symExportEncoding", dest="symExportEncoding", default="iso-8859-1", help="Export charset of sym format, maybe utf-8\ndefault iso-8859-1") parser.add_option("", "--xlsMotorolaBitFormat", dest="xlsMotorolaBitFormat", default="msbreverse", help="Excel format for startbit of motorola codescharset signals\nValid values: msb, lsb, msbreverse\n default msbreverse") parser.add_option("", "--jsonExportCanard", dest="jsonCanard", action="store_true", default=False, help="Export Canard compatible json format") parser.add_option("", "--jsonExportAll", dest="jsonAll", action="store_true", default=False, help="Export more data to json format") parser.add_option("", "--ecus", dest="ecus", default=None, help="Copy only given ECUs (comma separated list) to target matrix") parser.add_option("", "--frames", dest="frames", default=None, help="Copy only given Frames (comma separated list) to target matrix") parser.add_option("", "--merge", dest="merge", default=None, help="merge additional can databases.\nSyntax: --merge filename[:ecu=SOMEECU][:frame=FRAME1][:frame=FRAME2],filename2") parser.add_option("", "--deleteEcu", dest="deleteEcu", default=None, help="delete Ecu form databases. (comma separated list)\nSyntax: --deleteEcu=myEcu,mySecondEcu") parser.add_option("", "--renameEcu", dest="renameEcu", default=None, help="rename Ecu form databases. (comma separated list)\nSyntax: --renameEcu=myOldEcu:myNewEcu,mySecondEcu:mySecondNewEcu") parser.add_option("", "--deleteFrame", dest="deleteFrame", default=None, help="delete Frame form databases. (comma separated list)\nSyntax: --deleteFrame=myFrame1,mySecondFrame") parser.add_option("", "--renameFrame", dest="renameFrame", default=None, help="rename Frame form databases. (comma separated list)\nSyntax: --renameFrame=myOldFrame:myNewFrame,mySecondFrame:mySecondNewFrame") parser.add_option("", "--deleteSignal", dest="deleteSignal", default=None, help="delete Signal form databases. (comma separated list)\nSyntax: --deleteSignal=mySignal1,mySecondSignal") parser.add_option("", "--renameSignal", dest="renameSignal", default=None, help="rename Signal form databases. (comma separated list)\nSyntax: --renameSignal=myOldSignal:myNewSignal,mySecondSignal:mySecondNewSignal") (cmdlineOptions, args) = parser.parse_args() if len(args) < 2: parser.print_help() sys.exit(1) infile = args[0] outfileName = args[1] verbosity = cmdlineOptions.verbosity if cmdlineOptions.silent: # only print error messages, ignore verbosity flag verbosity = -1 set_log_level(logger, verbosity) convert(infile, outfileName, **cmdlineOptions.__dict__) if __name__ == '__main__': sys.exit(main()) canmatrix-0.6/canmatrix/xls.py0000664000175000017500000006570013001475401016074 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the aframeve copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the aframeve copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports xls-files from a canmatrix-object # xls-files are the can-matrix-definitions displayed in Excel from __future__ import division from __future__ import absolute_import from __future__ import print_function from builtins import * import math import sys import os.path import codecs import xlwt import logging logger = logging.getLogger('root') from .canmatrix import * import xlrd # Font Size : 8pt * 20 = 160 #font = 'font: name Arial Narrow, height 160' font = 'font: name Verdana, height 160' if xlwt is not None: sty_header = xlwt.easyxf(font + ', bold on; align: rota 90, vertical center, horizontal center', 'pattern: pattern solid, fore-colour rose') sty_norm = xlwt.easyxf(font + ', colour black') sty_first_frame = xlwt.easyxf(font + ', colour black; borders: top thin') sty_white = xlwt.easyxf(font + ', colour white') # BUMatrix-Styles sty_green = xlwt.easyxf('pattern: pattern solid, fore-colour light_green') sty_green_first_frame = xlwt.easyxf( 'pattern: pattern solid, fore-colour light_green; borders: top thin') sty_sender = xlwt.easyxf('pattern: pattern 0x04, fore-colour gray25') sty_sender_first_frame = xlwt.easyxf( 'pattern: pattern 0x04, fore-colour gray25; borders: top thin') sty_sender_green = xlwt.easyxf( 'pattern: pattern 0x04, fore-colour gray25, back-colour light_green') sty_sender_green_first_frame = xlwt.easyxf( 'pattern: pattern 0x04, fore-colour gray25, back-colour light_green; borders: top thin') def writeFrame(frame, worksheet, row, mystyle): # frame-id worksheet.write(row, 0, label="%3Xh" % frame.id, style=mystyle) # frame-Name worksheet.write(row, 1, label=frame.name, style=mystyle) # determin cycle-time if "GenMsgCycleTime" in frame.attributes: worksheet.write( row, 2, label=int( frame.attributes["GenMsgCycleTime"]), style=mystyle) else: worksheet.write(row, 2, label="", style=mystyle) # determin send-type if "GenMsgSendType" in frame.attributes: if frame.attributes["GenMsgSendType"] == "5": worksheet.write(row, 3, label="Cyclic+Change", style=mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgDelayTime"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "0": worksheet.write(row, 3, label="Cyclic", style=mystyle) worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "2": worksheet.write(row, 3, label="BAF", style=mystyle) if "GenMsgNrOfRepetitions" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgNrOfRepetitions"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "8": worksheet.write(row, 3, label="DualCycle", style=mystyle) if "GenMsgCycleTimeActive" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgCycleTimeActive"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "10": worksheet.write(row, 3, label="None", style=mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgDelayTime"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "9": worksheet.write(row, 3, label="OnChange", style=mystyle) if "GenMsgNrOfRepetitions" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgNrOfRepetitions"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) elif frame.attributes["GenMsgSendType"] == "1": worksheet.write(row, 3, label="Spontaneous", style=mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, label=int( frame.attributes["GenMsgDelayTime"]), style=mystyle) else: worksheet.write(row, 4, label="", style=mystyle) else: worksheet.write(row, 3, label="", style=mystyle) worksheet.write(row, 4, label="", style=mystyle) else: worksheet.write(row, 3, label="", style=mystyle) worksheet.write(row, 4, label="", style=mystyle) def writeSignal(db, sig, worksheet, row, mystyle, rearCol, motorolaBitFormat): if motorolaBitFormat == "msb": startBit = sig.getStartbit(bitNumbering=1) elif motorolaBitFormat == "msbreverse": startBit = sig.getStartbit() else: # motorolaBitFormat == "lsb" startBit = sig.getStartbit(bitNumbering=1, startLittle=True) # startbyte worksheet.write(row, 5, label=math.floor(startBit / 8) + 1, style=mystyle) # startbit worksheet.write(row, 6, label=(startBit) % 8, style=mystyle) # signalname worksheet.write(row, 7, label=sig.name, style=mystyle) # eval comment: if sig.comment is None: comment = "" else: comment = sig.comment # eval multiplex-info if sig.multiplex == 'Multiplexor': comment = "Mode Signal: " + comment elif sig.multiplex is not None: comment = "Mode " + str(sig.multiplex) + ":" + comment # write comment and size of signal in sheet worksheet.write(row, 8, label=comment, style=mystyle) worksheet.write(row, 9, label=sig.signalsize, style=mystyle) # startvalue of signal available if "GenSigStartValue" in sig.attributes: if db.signalDefines["GenSigStartValue"].definition == "STRING": worksheet.write(row, 10, label=sig.attributes[ "GenSigStartValue"], style=mystyle) elif db.signalDefines["GenSigStartValue"].definition == "INT" or db.signalDefines["GenSigStartValue"].definition == "HEX": worksheet.write(row, 10, label="%Xh" % int(sig.attributes["GenSigStartValue"]), style=mystyle) else: worksheet.write(row, 10, label=" ", style=mystyle) else: worksheet.write(row, 10, label=" ", style=mystyle) # SNA-value of signal available if "GenSigSNA" in sig.attributes: sna = sig.attributes["GenSigSNA"][1:-1] worksheet.write(row, 11, label=sna, style=mystyle) # no SNA-value of signal available / just for correct style: else: worksheet.write(row, 11, label=" ", style=mystyle) # eval byteorder (little_endian: intel == True / motorola == 0) if sig.is_little_endian: worksheet.write(row, 12, label="i", style=mystyle) else: worksheet.write(row, 12, label="m", style=mystyle) # is a unit defined for signal? if sig.unit.strip().__len__() > 0: # factor not 1.0 ? if float(sig.factor) != 1: worksheet.write( row, rearCol + 2, label="%g" % float( sig.factor) + " " + sig.unit, style=mystyle) #factor == 1.0 else: worksheet.write(row, rearCol + 2, label=sig.unit, style=mystyle) # no unit defined else: # factor not 1.0 ? if float(sig.factor) != 1: worksheet.write( row, rearCol + 2, label="%g" % float( sig.factor), style=mystyle) #factor == 1.0 else: worksheet.write(row, rearCol + 2, label="", style=mystyle) def writeValue(label, value, worksheet, row, rearCol, mystyle): # write value and lable in sheet worksheet.write(row, rearCol, label=label, style=mystyle) worksheet.write(row, rearCol + 1, label=value, style=mystyle) def writeBuMatrix(buList, sig, frame, worksheet, row, col, firstframe): # first-frame - style with borders: if firstframe == sty_first_frame: norm = sty_first_frame sender = sty_sender_first_frame norm_green = sty_green_first_frame sender_green = sty_sender_green_first_frame # consecutive-frame - style without borders: else: norm = sty_norm sender = sty_sender norm_green = sty_green sender_green = sty_sender_green # iterate over boardunits: for bu in buList: # every second Boardunit with other style if col % 2 == 0: locStyle = norm locStyleSender = sender # every second Boardunit with other style else: locStyle = norm_green locStyleSender = sender_green # write "s" "r" "r/s" if signal is sent, recieved or send and recived # by boardunit if bu in sig.receiver and bu in frame.transmitter: worksheet.write(row, col, label="r/s", style=locStyleSender) elif bu in sig.receiver: worksheet.write(row, col, label="r", style=locStyle) elif bu in frame.transmitter: worksheet.write(row, col, label="s", style=locStyleSender) else: worksheet.write(row, col, label="", style=locStyle) col += 1 # loop over boardunits ends here return col def dump(db, file, **options): head_top = ['ID', 'Frame Name', 'Cycle Time [ms]', 'Launch Type', 'Launch Parameter', 'Signal Byte No.', 'Signal Bit No.', 'Signal Name', 'Signal Function', 'Signal Length [Bit]', 'Signal Default', ' Signal Not Available', 'Byteorder'] head_tail = ['Value', 'Name / Phys. Range', 'Function / Increment Unit'] if 'xlsMotorolaBitFormat' in options: motorolaBitFormat = options["xlsMotorolaBitFormat"] else: motorolaBitFormat = "msbreverse" workbook = xlwt.Workbook(encoding='utf8') # wsname = os.path.basename(filename).replace('.xls', '') # worksheet = workbook.add_sheet('K-Matrix ' + wsname[0:22]) worksheet = workbook.add_sheet('K-Matrix ') col = 0 # write first row (header) cols before frameardunits: for head in head_top: worksheet.write(0, col, label=head, style=sty_header) worksheet.col(col).width = 1111 col += 1 # write frameardunits in first row: buList = [] for bu in db.boardUnits: worksheet.write(0, col, label=bu.name, style=sty_header) worksheet.col(col).width = 1111 buList.append(bu.name) col += 1 head_start = col # write first row (header) cols after frameardunits: for head in head_tail: worksheet.write(0, col, label=head, style=sty_header) worksheet.col(col).width = 3333 col += 1 # set width of selected Cols worksheet.col(1).width = 5555 worksheet.col(3).width = 3333 worksheet.col(7).width = 5555 worksheet.col(8).width = 7777 worksheet.col(head_start).width = 1111 worksheet.col(head_start + 1).width = 5555 frameHash = {} for frame in db.frames: frameHash[int(frame.id)] = frame # set row to first Frame (row = 0 is header) row = 1 # iterate over the frames for idx in sorted(frameHash.keys()): frame = frameHash[idx] framestyle = sty_first_frame # sort signals: sigHash = {} for sig in frame.signals: sigHash["%02d" % int(sig.getStartbit()) + sig.name] = sig # set style for first line with border sigstyle = sty_first_frame # iterate over signals for sig_idx in sorted(sigHash.keys()): sig = sigHash[sig_idx] # if not first Signal in Frame, set style if sigstyle != sty_first_frame: sigstyle = sty_norm # valuetable available? if sig.values.__len__() > 0: valstyle = sigstyle # iterate over values in valuetable for val in sorted(sig.values.keys()): writeFrame(frame, worksheet, row, framestyle) if framestyle != sty_first_frame: worksheet.row(row).level = 1 col = head_top.__len__() col = writeBuMatrix( buList, sig, frame, worksheet, row, col, framestyle) # write Value writeValue( val, sig.values[val], worksheet, row, col, valstyle) writeSignal( db, sig, worksheet, row, sigstyle, col, motorolaBitFormat) # no min/max here, because min/max has same col as values... # next row row += 1 # set style to normal - without border sigstyle = sty_white framestyle = sty_white valstyle = sty_norm # loop over values ends here # no valuetable available else: writeFrame(frame, worksheet, row, framestyle) if framestyle != sty_first_frame: worksheet.row(row).level = 1 col = head_top.__len__() col = writeBuMatrix( buList, sig, frame, worksheet, row, col, framestyle) writeSignal( db, sig, worksheet, row, sigstyle, col, motorolaBitFormat) if float(sig.min) != 0 or float(sig.max) != 1.0: worksheet.write( row, col + 1, label=str( "%g..%g" % (sig.min, sig.max)), style=sigstyle) else: worksheet.write(row, col + 1, label="", style=sigstyle) # just for border worksheet.write(row, col, label="", style=sigstyle) # next row row += 1 # set style to normal - without border sigstyle = sty_white framestyle = sty_white # reset signal-Array signals = [] # loop over signals ends here # loop over frames ends here # frozen headings instead of split panes worksheet.set_panes_frozen(True) # in general, freeze after last heading row worksheet.set_horz_split_pos(1) worksheet.set_remove_splits(True) # save file workbook.save(file) def load(file, **options): if 'xlsMotorolaBitFormat' in options: motorolaBitFormat = options["xlsMotorolaBitFormat"] else: motorolaBitFormat = "msbreverse" wb = xlrd.open_workbook(file_contents=file.read()) sh = wb.sheet_by_index(0) db = CanMatrix() # Defines not imported... # db.addBUDefines("NWM-Stationsadresse", 'HEX 0 63') # db.addBUDefines("NWM-Knoten", 'ENUM "nein","ja"') db.addFrameDefines("GenMsgCycleTime", 'INT 0 65535') db.addFrameDefines("GenMsgDelayTime", 'INT 0 65535') db.addFrameDefines("GenMsgCycleTimeActive", 'INT 0 65535') db.addFrameDefines("GenMsgNrOfRepetitions", 'INT 0 65535') # db.addFrameDefines("GenMsgStartValue", 'STRING') db.addFrameDefines( "GenMsgSendType", 'ENUM "cyclicX","spontanX","cyclicIfActiveX","spontanWithDelay","cyclicAndSpontanX","cyclicAndSpontanWithDelay","spontanWithRepitition","cyclicIfActiveAndSpontanWD","cyclicIfActiveFast","cyclicWithRepeatOnDemand","none"') # db.addSignalDefines("GenSigStartValue", 'HEX 0 4294967295') db.addSignalDefines("GenSigSNA", 'STRING') # eval search for correct collums: index = {} for i in range(sh.ncols): value = sh.cell(0, i).value if value == "ID": index['ID'] = i elif "Frame Name" in value: index['frameName'] = i elif "Cycle" in value: index['cycle'] = i elif "Launch Type" in value: index['launchType'] = i elif "Launch Parameter" in value: index['launchParam'] = i elif "Signal Byte No." in value: index['startbyte'] = i elif "Signal Bit No." in value: index['startbit'] = i elif "Signal Name" in value: index['signalName'] = i elif "Signal Function" in value: index['signalComment'] = i elif "Signal Length" in value: index['signalLength'] = i elif "Signal Default" in value: index['signalDefault'] = i elif "Signal Not Ava" in value: index['signalSNA'] = i elif "Value" in value: index['Value'] = i elif "Name / Phys" in value: index['ValueName'] = i elif "Function /" in value: index['function'] = i elif "Byteorder" in value: index['byteorder'] = i if "byteorder" in index: index['BUstart'] = index['byteorder'] + 1 else: index['BUstart'] = index['signalSNA'] + 1 index['BUend'] = index['Value'] # BoardUnits: for x in range(index['BUstart'], index['BUend']): db._BUs.add(BoardUnit(sh.cell(0, x).value)) # initialize: frameId = None signalName = "" newBo = None for rownum in range(1, sh.nrows): # ignore empty row if sh.cell(rownum, index['ID']).value.__len__() == 0: break # new frame detected if sh.cell(rownum, index['ID']).value != frameId: sender = [] # new Frame frameId = sh.cell(rownum, index['ID']).value frameName = sh.cell(rownum, index['frameName']).value cycleTime = sh.cell(rownum, index['cycle']).value launchType = sh.cell(rownum, index['launchType']).value dlc = 8 launchParam = sh.cell(rownum, index['launchParam']).value if type(launchParam).__name__ != "float": launchParam = 0.0 launchParam = str(int(launchParam)) # newBo = Frame(int(frameId[:-1], 16), frameName, dlc, None) newBo = Frame(frameName, Id=int(frameId[:-1], 16), dlc=dlc) db._fl.addFrame(newBo) # eval launctype if launchType is not None: if "Cyclic+Change" == launchType: newBo.addAttribute("GenMsgSendType", "5") newBo.addAttribute("GenMsgDelayTime", launchParam) elif "Cyclic" == launchType: newBo.addAttribute("GenMsgSendType", "0") elif "BAF" == launchType: newBo.addAttribute("GenMsgSendType", "2") newBo.addAttribute("GenMsgNrOfRepetitions", launchParam) elif "DualCycle" == launchType: newBo.addAttribute("GenMsgSendType", "8") newBo.addAttribute("GenMsgCycleTimeActive", launchParam) elif "None" == launchType: newBo.addAttribute("GenMsgSendType", "10") newBo.addAttribute("GenMsgDelayTime", launchParam) elif "OnChange" == launchType: newBo.addAttribute("GenMsgSendType", "9") newBo.addAttribute("GenMsgNrOfRepetitions", launchParam) elif "Spontaneous" == launchType: newBo.addAttribute("GenMsgSendType", "1") newBo.addAttribute("GenMsgDelayTime", launchParam) # eval cycletime if type(cycleTime).__name__ != "float": cycleTime = 0.0 newBo.addAttribute("GenMsgCycleTime", str(int(cycleTime))) # new signal detected if sh.cell(rownum, index['signalName']).value != signalName: # new Signal receiver = [] startbyte = int(sh.cell(rownum, index['startbyte']).value) startbit = int(sh.cell(rownum, index['startbit']).value) signalName = sh.cell(rownum, index['signalName']).value signalComment = sh.cell( rownum, index['signalComment']).value.strip() signalLength = int(sh.cell(rownum, index['signalLength']).value) signalDefault = sh.cell(rownum, index['signalDefault']).value signalSNA = sh.cell(rownum, index['signalSNA']).value multiplex = None if signalComment.startswith('Mode Signal:'): multiplex = 'Multiplexor' signalComment = signalComment[12:] elif signalComment.startswith('Mode '): mux, signalComment = signalComment[4:].split(':', 1) multiplex = int(mux.strip()) if "byteorder" in index: signalByteorder = sh.cell(rownum, index['byteorder']).value if 'i' in signalByteorder: is_little_endian = True else: is_little_endian = False else: is_little_endian = True # Default Intel is_signed = False if signalName != "-": for x in range(index['BUstart'], index['BUend']): if 's' in sh.cell(rownum, x).value: newBo.addTransmitter(sh.cell(0, x).value.strip()) if 'r' in sh.cell(rownum, x).value: receiver.append(sh.cell(0, x).value.strip()) # if signalLength > 8: newSig = Signal(signalName, startBit=(startbyte - 1) * 8 + startbit, signalSize=signalLength, is_little_endian=is_little_endian, is_signed=is_signed, receiver=receiver, multiplex=multiplex) # else: # newSig = Signal(signalName, (startbyte-1)*8+startbit, signalLength, is_little_endian, is_signed, 1, 0, 0, 1, "", receiver, multiplex) if not is_little_endian: # motorola if motorolaBitFormat == "msb": newSig.setStartbit( (startbyte - 1) * 8 + startbit, bitNumbering=1) elif motorolaBitFormat == "msbreverse": newSig.setStartbit((startbyte - 1) * 8 + startbit) else: # motorolaBitFormat == "lsb" newSig.setStartbit( (startbyte - 1) * 8 + startbit, bitNumbering=1, startLittle=True) newBo.addSignal(newSig) newSig.addComment(signalComment) function = sh.cell(rownum, index['function']).value value = str(sh.cell(rownum, index['Value']).value) valueName = sh.cell(rownum, index['ValueName']).value if valueName == 0: valueName = "0" elif valueName == 1: valueName = "1" test = valueName #.encode('utf-8') factor = 0 unit = "" factor = sh.cell(rownum, index['function']).value if type(factor).__name__ == "unicode" or type( factor).__name__ == "str": factor = factor.strip() if " " in factor and factor[0].isdigit(): (factor, unit) = factor.strip().split(" ", 1) factor = factor.strip() unit = unit.strip() newSig.unit = unit try: newSig.factor = float(factor) except: logger.warn( "Some error occurred while decoding scale: Signal: %s; \"%s\"" % (signalName, sh.cell( rownum, index['function']).value)) else: unit = factor.strip() newSig.unit = unit newSig.factor = 1 if ".." in test: (mini, maxi) = test.strip().split("..", 2) unit = "" try: newSig.offset = float(mini) newSig.min = float(mini) newSig.max = float(maxi) except: newSig.offset = 0 elif valueName.__len__() > 0: if value.strip().__len__() > 0: value = int(float(value)) newSig.addValues(value, valueName) maxi = pow(2, signalLength) - 1 newSig.max = float(maxi) else: newSig.offset = 0 for frame in db.frames: frame.updateReceiver() frame.calcDLC() return db canmatrix-0.6/canmatrix/canmatrix.py0000664000175000017500000007632013166737333017275 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # TODO: Definitions should be disassembled from __future__ import division import math import logging logger = logging.getLogger('root') class FrameList(object): """ Keeps all Frames of a Canmatrix """ def __init__(self): self._list = [] def addSignalToLastFrame(self, signal): """ Adds a Signal to the last addes Frame, this is mainly for importers """ self._list[len(self._list) - 1].addSignal(signal) def addFrame(self, frame): """ Adds a Frame """ self._list.append(frame) return self._list[len(self._list) - 1] def remove(self, frame): """ Adds a Frame """ self._list.remove(frame) def byId(self, Id): """ returns a Frame-Object by given Frame-ID """ for test in self._list: if test._Id == int(Id): return test return None def byName(self, Name): """ returns a Frame-Object by given Frame-Name """ for test in self._list: if test._name == Name: return test return None def __iter__(self): return iter(self._list) def __len__(self): return len(self._list) class BoardUnit(object): """ Contains one Boardunit/ECU """ def __init__(self, name): self._name = name.strip() self._attributes = {} self._comment = None def addAttribute(self, attribute, value): """ adds some Attribute to current Boardunit/ECU """ self._attributes[attribute] = value def addComment(self, comment): """ Set comment of Signal """ self._comment = comment def __str__(self): return self._name @property def name(self): return self._name @name.setter def name(self, value): self._name = value @property def attributes(self): return self._attributes @property def comment(self): return self._comment class BoardUnitList(object): """ Contains all Boardunits/ECUs of a canmatrix in a list """ def __init__(self): self._list = [] def add(self, BU): """ add Boardunit/ECU to list """ if BU._name.strip() not in self._list: self._list.append(BU) def remove(self, BU): """ remove Boardunit/ECU to list """ if BU._name.strip() not in self._list: self._list.remove(BU) def byName(self, name): """ returns Boardunit-Object of list by Name """ for test in self._list: if test._name == name: return test return None def __iter__(self): return iter(self._list) def __len__(self): return len(self._list) def normalizeValueTable(table): return {int(k): v for k, v in table.items()} class Signal(object): """ contains on Signal of canmatrix-object with following attributes: _name, _startbit,_signalsize (in Bits) _is_little_endian (1: Intel, 0: Motorola) _is_signed () _factor, _offset, _min, _max _receiver (Boarunit/ECU-Name) _attributes, _values, _unit, _comment _multiplex ('Multiplexor' or Number of Multiplex) """ def __init__(self, name, **kwargs): def multiplex(value): if value is not None and value != 'Multiplexor': multiplex = int(value) else: multiplex = value return multiplex args = [ ('startBit', '_startbit', int, 0), ('signalSize', '_signalsize', int, 0), ('is_little_endian', '_is_little_endian', bool, True), ('is_signed', '_is_signed', bool, True), ('factor', '_factor', float, 1), ('offset', '_offset', float, 0), ('min', '_min', float, None), ('max', '_max', float, None), ('unit', '_unit', None, ""), ('receiver', '_receiver', None, []), ('comment', '_comment', None, None), ('multiplex', '_multiplex', multiplex, None), ('is_float', '_is_float', bool, False), ('enumeration', 'enumeration', str, None), ('comments', 'comments', None, {}), ('attributes', '_attributes', None, {}), ('values', '_values', None, {}), ] for arg_name, destination, function, default in args: try: value = kwargs[arg_name] except KeyError: value = default else: kwargs.pop(arg_name) if function is not None and value is not None: value = function(value) setattr(self, destination, value) if len(kwargs) > 0: raise TypeError('{}() got unexpected argument{} {}'.format( self.__class__.__name__, 's' if len(kwargs) > 1 else '', ', '.join(kwargs.keys()) )) # be shure to calc min/max after parsing all arguments if self._min is None: self.setMin() if self._max is None: self.setMax() self._name = name @property def name(self): return self._name @name.setter def name(self, value): self._name = value @property def attributes(self): return self._attributes @property def comment(self): return self._comment @property def multiplex(self): return self._multiplex @property def values(self): return self._values @values.setter def values(self, valueTable): self._values = normalizeValueTable(valueTable) @property def comment(self): return self._comment @property def receiver(self): return self._receiver @property def unit(self): return self._unit @unit.setter def unit(self, unit): self._unit = unit @property def offset(self): return self._offset @offset.setter def offset(self, value): self._offset = value @property def factor(self): return self._factor @factor.setter def factor(self, factor): self._factor = factor @property def is_float(self): return self._is_float @is_float.setter def is_float(self, value): self._is_float = value @property def is_signed(self): return self._is_signed @property def is_little_endian(self): return self._is_little_endian @property def signalsize(self): return self._signalsize @property def min(self): return self._min @min.setter def min(self, value): self._min = value @property def max(self): return self._max @max.setter def max(self, value): self._max = value def addComment(self, comment): """ Set comment of Signal """ self._comment = comment def addReceiver(self, receiver): """ add receiver Boardunit/ECU-Name to Signal """ if receiver not in self._receiver: self._receiver.append(receiver) def addAttribute(self, attribute, value): """ Add Attribute to Signal """ if attribute not in self._attributes: self._attributes[attribute] = value def delAttribute(self, attribute): """ Remove Attribute to Signal """ if attribute in self._attributes: del self._attributes[attribute] def addValues(self, value, valueName): """ Add Value/Description to Signal """ self._values[int(value)] = valueName def setStartbit(self, startBit, bitNumbering=None, startLittle=None): """ set startbit. bitNumbering is 1 for LSB0/LSBFirst, 0 for MSB0/MSBFirst. If bit numbering is consistent with byte order (little=LSB0, big=MSB0) (KCD, SYM), start bit unmodified. Otherwise reverse bit numbering. For DBC, ArXML (OSEK), both little endian and big endian use LSB0. If bitNumbering is None, assume consistent with byte order. If startLittle is set, given startBit is assumed start from lsb bit rather than the start of the signal data in the message data """ # bit numbering not consistent with byte order. reverse if bitNumbering is not None and bitNumbering != self._is_little_endian: startBit = startBit - (startBit % 8) + 7 - (startBit % 8) # if given startbit is for the end of signal data (lsbit), # convert to start of signal data (msbit) if startLittle is True and self._is_little_endian is False: startBit = startBit + 1 - self._signalsize if startBit < 0: print("wrong startbit found Signal: %s Startbit: %d" % (self.name, startBit)) raise Exception("startbit lower zero") self._startbit = startBit def getStartbit(self, bitNumbering=None, startLittle=None): startBit = self._startbit # convert from big endian start bit at # start bit(msbit) to end bit(lsbit) if startLittle is True and self._is_little_endian is False: startBit = startBit + self._signalsize - 1 # bit numbering not consistent with byte order. reverse if bitNumbering is not None and bitNumbering != self._is_little_endian: startBit = startBit - (startBit % 8) + 7 - (startBit % 8) return int(startBit) def calculateRawRange(self): rawRange = 2 ** self._signalsize if self._is_signed: rawRange /= 2 return (-rawRange if self._is_signed else 0, rawRange - 1) def setMin(self, min=None): self._min = min if self._min is None: self._min = self.calcMin() return self._min def calcMin(self): rawMin = self.calculateRawRange()[0] return self._offset + (rawMin * self._factor) def setMax(self, max=None): self._max = max if self._max is None: self._max = self.calcMax() return self._max def calcMax(self): rawMax = self.calculateRawRange()[1] return self._offset + (rawMax * self._factor) def __str__(self): return self._name class SignalGroup(object): """ contains Signals, which belong to signal-group """ def __init__(self, name, Id): self._members = [] self._name = name self._Id = Id def addSignal(self, signal): if signal not in self._members: self._members.append(signal) def delSignal(self, signal): if signal in self._members: self._members[signal].remove() def byName(self, name): """ returns Signalobject-Object of list by Name """ for test in self._members: if test._name == name: return test return None @property def signals(self): return self._members @property def id(self): return self._Id @property def name(self): return self._name @name.setter def name(self, value): self._name = value def __str__(self): return self._name def __iter__(self): return iter(self._members) class Frame(object): """ contains one Frame with following attributes _Id, _name, _Transmitter (list of boardunits/ECU-names), _Size (= DLC), _signals (list of signal-objects), _attributes (list of attributes), _receiver (list of boardunits/ECU-names), _extended (Extended Frame = 1), _comment """ def __init__(self, name, **kwargs): self._name = name args = [ ('Id', '_Id', int, 0), ('dlc', '_Size', int, 0), ('transmitter', '_Transmitter', None, []), ('extended', '_extended', bool, False), ('comment', '_comment', str, None), ('signals', '_signals', None, []), ('mux_names', '_mux_names', None, {}), ('attributes', '_attributes', None, {}), ('receiver', '_receiver', None, []), ('SignalGroups', '_SignalGroups', None, []), ] for arg_name, destination, function, default in args: try: value = kwargs[arg_name] except KeyError: value = default else: kwargs.pop(arg_name) if function is not None and value is not None: value = function(value) setattr(self, destination, value) if len(kwargs) > 0: raise TypeError('{}() got unexpected argument{} {}'.format( self.__class__.__name__, 's' if len(kwargs) > 1 else '', ', '.join(kwargs.keys()) )) @property def attributes(self): return self._attributes @property def receiver(self): return self._receiver @property def SignalGroups(self): return self._SignalGroups @property def signals(self): return self._signals @property def transmitter(self): return self._Transmitter @transmitter.setter def transmitter(self, value): self._Transmitter = value @property def size(self): return self._Size @size.setter def size(self, value): self._Size = value @property def id(self): return self._Id @id.setter def id(self, value): self._Id = value @property def comment(self): return self._comment @property def extended(self): return self._extended @extended.setter def extended(self, value): self._extended = value @property def mux_names(self): return self._mux_names @mux_names.setter def mux_names(self, value): self._mux_names = value @property def name(self): return self._name @name.setter def name(self, value): self._name = value def __iter__(self): return iter(self._signals) def addSignalGroup(self, Name, Id, signalNames): newGroup = SignalGroup(Name, Id) self._SignalGroups.append(newGroup) for signal in signalNames: signal = signal.strip() if signal.__len__() == 0: continue signalId = self.signalByName(signal) if signalId is not None: newGroup.addSignal(signalId) def signalGroupbyName(self, name): """ returns signalGroup-object by signalname """ for signalGroup in self._SignalGroups: if signalGroup._name == name: return signalGroup return None def addSignal(self, signal): """ add Signal to Frame """ self._signals.append(signal) return self._signals[len(self._signals) - 1] def addTransmitter(self, transmitter): """ add transmitter Boardunit/ECU-Name to Frame """ if transmitter not in self._Transmitter: self._Transmitter.append(transmitter) def addReceiver(self, receiver): """ add receiver Boardunit/ECU-Name to Frame """ if receiver not in self._receiver: self._receiver.append(receiver) def signalByName(self, name): """ returns signal-object by signalname """ for signal in self._signals: if signal._name == name: return signal return None def addAttribute(self, attribute, value): """ add attribute to attribute-list of frame """ if attribute not in self._attributes: self._attributes[attribute] = str(value) def delAttribute(self, attribute): """ Remove attribute to attribute-list of frame """ if attribute in self._attributes: del self._attributes[attribute] def addComment(self, comment): """ set comment of frame """ self._comment = comment def calcDLC(self): """ calc minimal DLC/length for frame (using signal information) """ maxBit = 0 for sig in self._signals: if sig.getStartbit() + int(sig._signalsize) > maxBit: maxBit = sig.getStartbit() + int(sig._signalsize) self._Size = max(self._Size, int(math.ceil(maxBit / 8))) def findNotUsedBits(self): """ find unused bits in frame return dict with position and length-tuples """ bitfield = [] bitfieldLe = [] bitfieldBe = [] for i in range(0,64): bitfieldBe.append(0) bitfieldLe.append(0) bitfield.append(0) i = 0 for sig in self._signals: i += 1 for bit in range(sig.getStartbit(), sig.getStartbit() + int(sig._signalsize)): if sig._is_little_endian: bitfieldLe[bit] = i else: bitfieldBe[bit] = i for i in range(0,8): for j in range(0,8): bitfield[i*8+j] = bitfieldLe[i*8+(7-j)] for i in range(0,8): for j in range(0,8): if bitfield[i*8+j] == 0: bitfield[i*8+j] = bitfieldBe[i*8+j] return bitfield def createDummySignals(self): bitfield = self.findNotUsedBits() # for i in range(0,8): # print (bitfield[(i)*8:(i+1)*8]) startBit = -1 sigCount = 0 for i in range(0,64): if bitfield[i] == 0 and startBit == -1: startBit = i if (i == 63 or bitfield[i] != 0) and startBit != -1: if i == 63: i = 64 self.addSignal(Signal("_Dummy_%s_%d" % (self.name,sigCount),signalSize=i-startBit, startBit=startBit, is_little_endian = False)) startBit = -1 sigCount +=1 # bitfield = self.findNotUsedBits() # for i in range(0,8): # print (bitfield[(i)*8:(i+1)*8]) def updateReceiver(self): """ collect receivers of frame out of receiver given in each signal """ for sig in self._signals: for receiver in sig._receiver: self.addReceiver(receiver) def __str__(self): return self._name class Define(object): """ these objects hold the defines and default-values """ def __init__(self, definition): definition = definition.strip() self.definition = definition self.type = None # for any known type: if definition[0:3] == 'INT': self._type = 'INT' min, max = definition[4:].split(' ', 2) self.min = int(min) self.max = int(max) elif definition[0:6] == 'STRING': self.type = 'STRING' self.min = None self.max = None elif definition[0:4] == 'ENUM': self.type = 'ENUM' self.values = definition[5:].split(',') elif definition[0:3] == 'HEX': self.type = 'HEX' min, max = definition[4:].split(' ', 2) self.min = int(min) self.max = int(max) elif definition[0:5] == 'FLOAT': self.type = 'FLOAT' min, max = definition[6:].split(' ', 2) self.min = float(min) self.max = float(max) self._defaultValue = None def addDefault(self, default): self._defaultValue = default @property def defaultValue(self): return self._defaultValue class CanMatrix(object): """ The Can-Matrix-Object _attributes (global canmatrix-attributes), _BUs (list of boardunits/ECUs), _fl (list of Frames) _signalDefines (list of signal-attribute types) _frameDefines (list of frame-attribute types) _buDefines (list of BoardUnit-attribute types) _globalDefines (list of global attribute types) _valueTables (global defined values) """ def __init__(self): self._attributes = {} self._BUs = BoardUnitList() self._fl = FrameList() self._signalDefines = {} self._frameDefines = {} self._globalDefines = {} self._buDefines = {} self._valueTables = {} @property def attributes(self): return self._attributes @property def boardUnits(self): return self._BUs @property def frames(self): return self._fl @property def signalDefines(self): return self._signalDefines @property def frameDefines(self): return self._frameDefines @property def globalDefines(self): return self._globalDefines @property def buDefines(self): return self._buDefines @property def valueTables(self): return self._valueTables def __iter__(self): return iter(self._fl) def addValueTable(self, name, valueTable): self._valueTables[name] = normalizeValueTable(valueTable) def addAttribute(self, attribute, value): """ add attribute to attribute-list of canmatrix """ if attribute not in self._attributes: self._attributes[attribute] = value def addSignalDefines(self, type, definition): """ add signal-attribute definition to canmatrix """ if type not in self._signalDefines: self._signalDefines[type] = Define(definition) def addFrameDefines(self, type, definition): """ add frame-attribute definition to canmatrix """ if type not in self._frameDefines: self._frameDefines[type] = Define(definition) def addBUDefines(self, type, definition): """ add Boardunit-attribute definition to canmatrix """ if type not in self._buDefines: self._buDefines[type] = Define(definition) def addGlobalDefines(self, type, definition): """ add global-attribute definition to canmatrix """ if type not in self._globalDefines: self._globalDefines[type] = Define(definition) def addDefineDefault(self, name, value): if name in self._signalDefines: self._signalDefines[name].addDefault(value) if name in self._frameDefines: self._frameDefines[name].addDefault(value) if name in self._buDefines: self._buDefines[name].addDefault(value) if name in self._globalDefines: self._globalDefines[name].addDefault(value) def deleteObsoleteDefines(self): toBeDeleted = [] for frameDef in self.frameDefines: found = False for frame in self.frames: if frameDef in frame.attributes: found = True break if found is False and found not in toBeDeleted: toBeDeleted.append(frameDef) for element in toBeDeleted: del self.frameDefines[element] toBeDeleted = [] for buDef in self.buDefines: found = False for ecu in self.boardUnits: if buDef in ecu.attributes: found = True break if found is False and found not in toBeDeleted: toBeDeleted.append(buDef) for element in toBeDeleted: del self.buDefines[element] toBeDeleted = [] for signalDef in self.signalDefines: found = False for frame in self.frames: for signal in frame.signals: if signalDef in signal.attributes: found = True break if found is False and found not in toBeDeleted: toBeDeleted.append(signalDef) for element in toBeDeleted: del self.signalDefines[element] def frameById(self, Id): return self._fl.byId(Id) def frameByName(self, name): return self._fl.byName(name) def boardUnitByName(self, name): return self._BUs.byName(name) def deleteZeroSignals(self): for frame in self.frames: for signal in frame.signals: if 0 == signal.signalsize: frame.signals.remove(signal) def delSignalAttributes(self, unwantedAttributes): for frame in self.frames: for signal in frame.signals: for attrib in unwantedAttributes: signal.delAttribute(attrib) def delFrameAttributes(self, unwantedAttributes): for frame in self.frames: for attrib in unwantedAttributes: frame.delAttribute(attrib) def recalcDLC(self, strategy): for frame in self.frames: originalDlc = frame.size if "max" == strategy: frame.calcDLC() if "force" == strategy: maxBit = 0 for sig in frame.signals: if sig.getStartbit() + int(sig._signalsize) > maxBit: maxBit = sig.getStartbit() + int(sig._signalsize) frame._Size = math.ceil(maxBit / 8) def renameEcu(self, old, newName): if type(old).__name__ == 'instance': pass else: old = self.boardUnitByName(old) oldName = old.name old.name = newName for frame in self.frames: if oldName in frame.transmitter: frame.transmitter.remove(oldName) frame.addTransmitter(newName) for signal in frame.signals: if oldName in signal.receiver: signal.receiver.remove(oldName) signal.addReceiver(newName) frame.updateReceiver() def delEcu(self, ecu): if type(ecu).__name__ == 'instance': pass else: ecu = self.boardUnitByName(ecu) self.boardUnits.remove(ecu) for frame in self.frames: if ecu.name in frame.transmitter: frame.transmitter.remove(ecu.name) for signal in frame.signals: if ecu.name in signal.receiver: signal.receiver.remove(ecu.name) frame.updateReceiver() def renameFrame(self, old, newName): if type(old).__name__ == 'instance': pass else: old = self.frameByName(old) oldName = old.name old.name = newName for frame in self.frames: if frame.name == oldName: frame.name = newName def delFrame(self, frame): if type(frame).__name__ == 'instance': pass else: frame = self.frameByName(frame) self.frames.remove(frame) def renameSignal(self, old, newName): if type(old).__name__ == 'instance': old.name = newName else: for frame in self.frames: signal = frame.signalByName(old) if signal is not None: signal.name = newName def delSignal(self, signal): if type(signal).__name__ == 'instance': for frame in self.frames: if signal in frame.signals: frame.signals.remove(sig) else: for frame in self.frames: sig = frame.signalByName(signal) if sig is not None: frame.signals.remove(sig) # # # def computeSignalValueInFrame(startbit, ln, fmt, value): """ compute the signal value in the frame """ import pprint frame = 0 if fmt == 1: # Intel # using "sawtooth bit counting policy" here pos = ((7 - (startbit % 8)) + 8*(int(startbit/8))) while ln > 0: # How many bits can we stuff in current byte? # (Should be 8 for anything but the first loop) availbitsInByte = 1 + (pos % 8) # extract relevant bits from value valueInByte = value & ((1<> availbitsInByte # reduce length by how many bits we consumed ln -= availbitsInByte else: # Motorola # Work this out in "sequential bit counting policy" # Compute the LSB position in "sequential" lsbpos = ((7 - (startbit % 8)) + 8*(int(startbit/8))) # deduce the MSB position msbpos = 1 + lsbpos - ln # "reverse" the value cvalue = int(format(value, 'b')[::-1],2) # shift the value to the proper position in the frame frame = cvalue << msbpos # Return frame, to be accumulated by caller return frame class CanId(object): """ Split Id into Global source addresses (source, destination) off ECU and PGN """ # TODO link to BoardUnit/ECU source = None # Source Address destination = None # Destination Address pgn = None # PGN def __init__(self, id, extended=True): if extended: self.source = id & int('0xFF', 16) self.pgn = (id >> 8) & int('0xFFFF', 16) self.destination = id >> 8 * 3 & int('0xFF', 16) else: # TODO implement for standard Id pass def tuples(self): return self.destination, self.pgn, self.source def __str__(self): return "DA:{da:#02X} PGN:{pgn:#04X} SA:{sa:#02X}".format( da=self.destination, pgn=self.pgn, sa=self.source) canmatrix-0.6/canmatrix/sym.py0000664000175000017500000005125213166737333016114 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports sym-files from a canmatrix-object # sym-files are the can-matrix-definitions of the Peak Systems Tools from __future__ import division from __future__ import absolute_import import logging logger = logging.getLogger('root') from builtins import * import collections import math import shlex from .canmatrix import * import re import codecs import sys enumDict = {} enums = "{ENUMS}\n" def format_float(f): s = str(f).upper() if s.endswith('.0'): s = s[:-2] if 'E' in s: s = s.split('E') s = '%sE%s%s' % (s[0], s[1][0], s[1][1:].rjust(3, '0')) return s.upper() def createSignal(signal): global enums global enumDict output = "" output += "Var=%s " % (signal.name) if not signal.is_signed: output += "unsigned " else: output += "signed " startBit = signal.getStartbit() if signal.is_little_endian == 0: # Motorola output += "%d,%d -m " % (startBit, signal.signalsize) else: output += "%d,%d " % (startBit, signal.signalsize) if signal.attributes.get('HexadecimalOutput', False): output += "-h " if len(signal.unit) > 0: output += "/u:%s " % (signal.unit[0:16]) if float(signal.factor) != 1: output += "/f:%s " % (format_float(signal.factor)) if float(signal.offset) != 0: output += "/o:%s " % (format_float(signal.offset)) if signal.calcMin() != signal.min: output += "/min:{} ".format(format_float(signal.min)) if signal.calcMax() != signal.max: output += "/max:{} ".format(format_float(signal.max)) displayDecimalPlaces = signal.attributes.get('DisplayDecimalPlaces') if displayDecimalPlaces is not None: output += "/p:%d " % (int(displayDecimalPlaces)) if len(signal.values) > 0: valTabName = signal.enumeration if valTabName is None: valTabName = signal.name output += "/e:%s " % (valTabName) if valTabName not in enumDict: enumDict[valTabName] = "enum " + valTabName + "(" + ', '.join( '%s="%s"' % (key, val) for ( key, val) in sorted( signal.values.items())) + ")" if "GenSigStartValue" in signal.attributes: default = float(signal.attributes[ "GenSigStartValue"]) * float(signal.factor) if default >= float( signal.min) and default <= float(signal.max): output += "/d:%g " % (default) long_name = signal.attributes.get('LongName') if long_name is not None: output += '/ln:"{}" '.format(long_name) output = output.rstrip() if signal.comment is not None and len(signal.comment) > 0: output += "\t// " + signal.comment.replace('\n', ' ').replace('\r', ' ') output += "\n" return output def dump(db, f, **options): """ export canmatrix-object as .sym file (compatible to PEAK-Systems) """ global enumDict global enums if 'symExportEncoding' in options: symEncoding = options["symExportEncoding"] else: symEncoding = 'iso-8859-1' enumDict = {} enums = "{ENUMS}\n" header = """FormatVersion=5.0 // Do not edit this line! Title=\"canmatrix-Export\" """ f.write(header.encode(symEncoding)) def sendreceive(f): return ( f.attributes.get('Sendable', 'True') == 'True', f.attributes.get('Receivable', 'True') == 'True', ) sections = collections.OrderedDict(( ('SEND', tuple(f for f in db.frames if sendreceive(f) == (True, False))), ('RECEIVE', tuple(f for f in db.frames if sendreceive(f) == (False, True))), ('SENDRECEIVE', tuple(f for f in db.frames if sendreceive(f) == (True, True))), )) output = '\n' for name, frames in sections.items(): if len(frames) == 0: continue # Frames output += "{{{}}}\n\n".format(name) # trigger all frames for frame in frames: name = "[" + frame.name + "]\n" idType = "ID=%08Xh" % (frame.id) if frame.comment is not None and len(frame.comment) > 0: idType += "\t// " + \ frame.comment.replace('\n', ' ').replace('\r', ' ') idType += "\n" if frame.extended == 1: idType += "Type=Extended\n" else: idType += "Type=Standard\n" # check if frame has multiplexed signals multiplex = 0 for signal in frame.signals: if signal.multiplex is not None: multiplex = 1 if multiplex == 1: # search for multiplexor in frame: for signal in frame.signals: if signal.multiplex == 'Multiplexor': muxSignal = signal # ticker all possible mux-groups as i (0 - 2^ (number of bits of # multiplexor)) first = 0 for i in range(0, 1 << int(muxSignal.signalsize)): found = 0 muxOut = "" # ticker all signals for signal in frame.signals: # if signal is in mux-group i if signal.multiplex == i: muxOut = name if first == 0: muxOut += idType first = 1 muxOut += "DLC=%d\n" % (frame.size) if "GenMsgCycleTime" in frame.attributes: muxOut += "CycleTime=" + \ frame.attributes[ "GenMsgCycleTime"] + "\n" muxName = frame.mux_names.get( i, muxSignal.name + "%d" % i) muxOut += "Mux=" + muxName startBit = muxSignal.getStartbit() s = str(i) if len(s) > 1: s = '{:04X}h'.format(i) if signal.is_little_endian == 0: # Motorola muxOut += " %d,%d %s -m" % (startBit, muxSignal.signalsize, s) else: muxOut += " %d,%d %s" % (startBit, muxSignal.signalsize, s) if not muxOut.endswith('h'): muxOut += ' ' if i in muxSignal.comments: comment = muxSignal.comments.get(i) if len(comment) > 0: muxOut += '\t// ' + comment muxOut += "\n" found = 1 break if found == 1: for signal in frame.signals: if signal.multiplex == i or signal.multiplex is None: muxOut += createSignal(signal) output += muxOut + "\n" else: # no multiplex signals in frame, just 'normal' signals output += name output += idType output += "DLC=%d\n" % (frame.size) if "GenMsgCycleTime" in frame.attributes: output += "CycleTime=" + \ frame.attributes["GenMsgCycleTime"] + "\n" for signal in frame.signals: output += createSignal(signal) output += "\n" enums += '\n'.join(sorted(enumDict.values())) # write outputfile f.write((enums + '\n').encode(symEncoding)) f.write(output.encode(symEncoding)) def load(f, **options): if 'symImportEncoding' in options: symImportEncoding = options["symImportEncoding"] else: symImportEncoding = 'iso-8859-1' class Mode(object): glob, enums, send, sendReceive, receive = list(range(5)) mode = Mode.glob frameName = "" frame = None db = CanMatrix() db.addFrameDefines("GenMsgCycleTime", 'INT 0 65535') db.addFrameDefines("Receivable", 'BOOL False True') db.addFrameDefines("Sendable", 'BOOL False True') db.addSignalDefines("GenSigStartValue", 'FLOAT -3.4E+038 3.4E+038') db.addSignalDefines("HexadecimalOutput", 'BOOL False True') db.addSignalDefines("DisplayDecimalPlaces", 'INT 0 65535') db.addSignalDefines("LongName", 'STR') for line in f: line = line.decode(symImportEncoding).strip() # ignore emty line: if line.__len__() == 0: continue # switch mode: if line[0:7] == "{ENUMS}": mode = Mode.enums continue if line[0:6] == "{SEND}": mode = Mode.send continue if line[0:13] == "{SENDRECEIVE}": mode = Mode.sendReceive continue if line[0:9] == "{RECEIVE}": mode = Mode.receive continue if mode == Mode.glob: # just ignore headers... continue elif mode == Mode.enums: line = line.strip() if line.startswith('enum'): while not line[5:].strip().endswith(')'): line = line.split('//')[0] if sys.version_info > (3, 0): # is there a clean way to to it? line += ' ' + f.readline().decode(symImportEncoding).strip() else: line += ' ' + f.next().decode(symImportEncoding).strip() line = line.split('//')[0] tempArray = line[5:].replace(')', '').split('(') valtabName = tempArray[0] split = shlex.split(tempArray[1]) tempArray = [s.rstrip(',') for s in split] tempValTable = {} for entry in tempArray: tempValTable[entry.split('=')[0].strip()] = entry.split('=')[ 1].replace('"', '').strip() db.addValueTable(valtabName, tempValTable) elif mode in {Mode.send, Mode.sendReceive, Mode.receive}: if line.startswith('['): multiplexor = None # found new frame: if frameName != line.replace('[', '').replace(']', '').strip(): frameName = line.replace('[', '').replace(']', '').strip() # TODO: CAMPid 939921818394902983238 if frame is not None: if len(frame.mux_names) > 0: frame.signalByName( frame.name + "_MUX").values = frame.mux_names db._fl.addFrame(frame) frame = Frame(frameName) frame.addAttribute( 'Receivable', mode in {Mode.receive, Mode.sendReceive} ) frame.addAttribute( 'Sendable', mode in {Mode.send, Mode.sendReceive} ) # key value: elif line.startswith('Var') or line.startswith('Mux'): tmpMux = line[:3] line = line[4:] comment = "" indexOffset = 1 if tmpMux == "Mux": indexOffset = 0 comment = "" if '//' in line: comment = line.split('//')[1].strip() line = line.split('//')[0] line = line.replace(' ', ' "" ') tempArray = shlex.split(line.strip()) sigName = tempArray[0] is_float = False if indexOffset != 1: is_signed = True else: is_signed = False if tempArray[1] == 'unsigned': pass elif tempArray[1] == 'bit': # TODO: actually support bit instead of interpreting as # an unsigned pass elif tempArray[1] == 'signed': is_signed = True elif tempArray[1] == 'float': is_float = True elif tempArray[1] in ['string']: # TODO: actually support these variable types instead # of skipping print('Variable type \'{}\' found and skipped' .format(tempArray[1])) continue else: raise ValueError( 'Unknown type \'{}\' found'.format( tempArray[1])) startBit = int(tempArray[indexOffset + 1].split(',')[0]) signalLength = int(tempArray[indexOffset + 1].split(',')[1]) intel = 1 unit = "" factor = 1 max = None min = None longName = None startValue = None offset = 0 valueTableName = None hexadecimal_output = False displayDecimalPlaces = None if tmpMux == "Mux": multiplexor = tempArray[2] if multiplexor[-1] == 'h': multiplexor = int(multiplexor[:-1], 16) else: multiplexor = int(multiplexor) frame.mux_names[multiplexor] = sigName indexOffset = 2 for switch in tempArray[indexOffset + 2:]: if switch == "-m": intel = 0 elif switch == "-h": hexadecimal_output = True elif switch.startswith('/'): s = switch[1:].split(':') if s[0] == 'u': unit = s[1] elif s[0] == 'f': factor = s[1] elif s[0] == 'd': startValue = s[1] elif s[0] == 'p': displayDecimalPlaces = s[1] elif s[0] == 'o': offset = s[1] elif s[0] == 'e': valueTableName = s[1] elif s[0] == 'max': max = s[1] elif s[0] == 'min': min = s[1] elif s[0] == 'ln': longName = s[1] # else: # print switch # else: # print switch if tmpMux == "Mux": signal = frame.signalByName(frameName + "_MUX") if signal is None: signal = Signal(frameName + "_MUX", startBit=startBit, signalSize=signalLength, is_little_endian=intel, is_signed=is_signed, is_float=is_float, factor=factor, offset=offset, min=min, max=max, unit=unit, multiplex='Multiplexor', comment=comment) # signal.addComment(comment) if intel == 0: # motorola set/convert startbit signal.setStartbit(startBit) frame.addSignal(signal) signal.comments[multiplexor] = comment else: # signal = Signal(sigName, startBit, signalLength, intel, is_signed, factor, offset, min, max, unit, "", multiplexor) signal = Signal(sigName, startBit=startBit, signalSize=signalLength, is_little_endian=intel, is_signed=is_signed, is_float=is_float, factor=factor, offset=offset, min=min, max=max, unit=unit, multiplex=multiplexor, comment=comment) # if intel == 0: # motorola set/convert startbit signal.setStartbit(startBit) if valueTableName is not None: signal.values = db.valueTables[valueTableName] signal.enumeration = valueTableName # signal.addComment(comment) # ... (1 / ...) because this somehow made 59.8/0.1 be 598.0 rather than 597.9999999999999 if startValue is not None: startValue = float(startValue) * (1 / float(factor)) signal.addAttribute("GenSigStartValue", str(startValue)) frame.addSignal(signal) if longName is not None: signal.addAttribute("LongName", longName) if hexadecimal_output: signal.addAttribute("HexadecimalOutput", str(True)) if displayDecimalPlaces is not None: signal.addAttribute( "DisplayDecimalPlaces", displayDecimalPlaces) # variable processing elif line.startswith('ID'): comment = "" if '//' in line: comment = line.split('//')[1].strip() line = line.split('//')[0] frame.id = int(line.split('=')[1].strip()[:-1], 16) frame.addComment(comment) elif line.startswith('Type'): if line.split('=')[1][:8] == "Extended": frame.extended = 1 elif line.startswith('DLC'): frame.size = int(line.split('=')[1]) elif line.startswith('CycleTime'): frame.addAttribute( "GenMsgCycleTime", line.split('=')[1].strip()) # else: # print line # else: # print "Unrecocniced line: " + l + " (%d) " % i # TODO: CAMPid 939921818394902983238 if frame is not None: if len(frame.mux_names) > 0: frame.signalByName(frame.name + "_MUX").values = frame.mux_names db._fl.addFrame(frame) return db canmatrix-0.6/canmatrix/join.py0000664000175000017500000000607013001475401016220 0ustar eduedu00000000000000import canmatrix.formats from canmatrix.canmatrix import CanId def list_pgn(db): """ :param db: :return: pgn and id """ id = [x._Id for x in db._fl._list] r = [CanId(t).tuples() for t in id] return [t[1] for t in r], id def ids_sharing_same_pgn(id_x, pgn_x, id_y, pgn_y): for idx, pgnx in zip(id_x, pgn_x): for idy, pgny in zip(id_y, pgn_y): if pgnx == pgny: yield (idx, idy) def join_frame_by_signal_startbit(files): targetDb = next(iter(canmatrix.formats.loadp(files.pop(0)).values())) pgn_x, id_x = list_pgn(db=targetDb) for f in files: sourceDb = next(iter(canmatrix.formats.loadp(f).values())) pgn_y, id_y = list_pgn(db=sourceDb) same_pgn = ids_sharing_same_pgn(id_x, pgn_x, id_y, pgn_y) for idx, idy in same_pgn: # print("{0:#x} {1:#x}".format(idx, idy)) targetFr = targetDb.frameById(idx) sourceFr = sourceDb.frameById(idy) to_add = [] for sig_t in targetFr._signals: for sig_s in sourceFr._signals: # print(sig._name) if sig_t._startbit == sig_s._startbit: # print("\t{0} {1}".format(sig_t._name, sig_s._name)) to_add.append(sig_s) for s in to_add: targetFr.addSignal(s) return targetDb def renameFrameWithID(sourceDb): for frameSc in sourceDb._fl._list: _, pgn, sa = CanId(frameSc._Id).tuples() exten = "__{pgn:#04X}_{sa:#02X}_{sa:03d}d".format(pgn=pgn, sa=sa) new_name = frameSc._name + exten # print(new_name) frameSc._name = new_name def renameFrameWithSAEacronyme(sourceDb, targetDb): pgn_x, id_x = list_pgn(db=targetDb) pgn_y, id_y = list_pgn(db=sourceDb) same_pgn = ids_sharing_same_pgn(id_x, pgn_x, id_y, pgn_y) for idx, idy in same_pgn: targetFr = targetDb.frameById(idx) sourceFr = sourceDb.frameById(idy) new_name = sourceFr._name + "__" + targetFr._name targetFr._name = new_name def join_frame_for_manufacturer(db, files): #targetDb = next(iter(im.importany(files.pop(0)).values())) pgn_x, id_x = list_pgn(db=db) for f in files: sourceDb = next(iter(canmatrix.formats.loadp(f).values())) pgn_y, id_y = list_pgn(db=sourceDb) same_pgn = ids_sharing_same_pgn(id_x, pgn_x, id_y, pgn_y) for idx, idy in same_pgn: # print("{0:#x} {1:#x}".format(idx, idy)) targetFr = db.frameById(idx) sourceFr = sourceDb.frameById(idy) _, pgn, sa = CanId(targetFr._Id).tuples() if(sa < 128): print('less', targetFr._name) to_add = [] for sig_s in sourceFr._signals: new_name = "{name}_{pgn:#04x}_{sa:03}".format( name=sig_s._name, pgn=pgn, sa=sa) sig_s._name = new_name to_add.append(sig_s) for s in to_add: targetFr.addSignal(s) canmatrix-0.6/canmatrix/kcd.py0000664000175000017500000004156413166737333016052 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports kcd-files from a canmatrix-object # kcd-files are the can-matrix-definitions of the kayak # (http://kayak.2codeornot2code.org/) from __future__ import absolute_import from __future__ import division from builtins import * from lxml import etree from .canmatrix import * from .cancluster import * import os import re import math clusterExporter = 1 clusterImporter = 1 def createSignal(signal, nodeList, typeEnums): sig = etree.Element( 'Signal', name=signal.name, offset=str( signal.getStartbit())) if signal.signalsize > 1: sig.set("length", str(signal.signalsize)) if signal.is_little_endian == 0: sig.set('endianess', "big") comment = signal.comment if len(signal.attributes.items()) > 0: if comment is None: comment = '' else: comment += '\n' for attrib, val in sorted(signal.attributes.items()): try: if attrib in typeEnums and int(val) < len(typeEnums[attrib]): val = typeEnums[attrib][int(val)] comment += ("\n" + attrib + ': ' + val) except: pass if comment is not None: notes = etree.Element('Notes') notes.text = comment sig.append(notes) value = etree.Element('Value') if signal.is_float: if signal.signalsize > 32: value.set('type', "double") else: value.set('type', "single") elif signal.is_signed: value.set('type', "signed") if float(signal.factor) != 1: value.set('slope', str("%g" % signal.factor)) if float(signal.offset) != 0: value.set('intercept', str("%g" % signal.offset)) if float(signal.min) != 0: value.set('min', str("{:.16g}".format(signal.min))) if float(signal.max) != 1 and float(signal.max) != 0: value.set('max', str("{:.16g}".format(signal.max))) if len(signal.unit) > 0: value.set('unit', signal.unit) if len(value.attrib) > 0: sig.append(value) if len(signal.values) > 0: labelset = etree.Element('LabelSet') for valueVal, valName in sorted( signal.values.items(), key=lambda x: int(x[0])): label = etree.Element( 'Label', name=valName.replace( '"', ''), value=str(valueVal)) labelset.append(label) sig.append(labelset) consumer = etree.Element('Consumer') for receiver in signal.receiver: if receiver in nodeList and len(receiver) > 1: noderef = etree.Element('NodeRef', id=str(nodeList[receiver])) consumer.append(noderef) if consumer.__len__() > 0: sig.append(consumer) return sig def dump(dbs, f, **options): signalTypeEnums = {} canClust = canCluster(dbs) for name in canClust: db = canClust[name] for (typename, define) in list(db.signalDefines.items()): defines = re.split(r"\s+", define.definition) define_type = defines[0] if define_type != 'ENUM': continue defines = defines[1].strip('"') defines = defines.split('","') signalTypeEnums[typename] = defines # create XML root = etree.Element('NetworkDefinition') root.set("xmlns", "http://kayak.2codeornot2code.org/1.0") NS_XSI = "{http://www.w3.org/2001/XMLSchema-instance}" root.set(NS_XSI + "schemaLocation", "Definition.xsd") # root.append(etree.Element('Document')) # another child with text child = etree.Element('Document') child.set("name", "Some Document Name") child.text = 'some text' root.append(child) # Nodes: id = 1 nodeList = {} # for name in dbs: # db = dbs[name] for bu in canClust.boardUnits: node = etree.Element('Node', name=bu.name, id="%d" % id) root.append(node) nodeList[bu.name] = id id += 1 for name in canClust: db = canClust[name] # Bus if 'Baudrate' in db.attributes: bus = etree.Element('Bus', baudrate=db.attributes['Baudrate']) else: bus = etree.Element('Bus') if len(name) == 0: (path, ext) = os.path.splitext(f.name) name = path if len(name) > 0: bus.set("name", name) for frame in db.frames: message = etree.Element('Message', id="0x%03X" % frame.id, name=frame.name, length=str(int(frame.size))) if frame.extended == 1: message.set("format", "extended") if "GenMsgCycleTime" in frame.attributes: cycleTime = int(frame.attributes["GenMsgCycleTime"]) if cycleTime > 0: message.set("triggered", "true") message.set("interval", "%d" % cycleTime) producer = etree.Element('Producer') for transmitter in frame.transmitter: if transmitter in nodeList and len(transmitter) > 1: noderef = etree.Element( 'NodeRef', id=str( nodeList[transmitter])) producer.append(noderef) if producer.__len__() > 0: message.append(producer) comment = etree.Element('Notes') if frame.comment is not None: comment.text = frame.comment message.append(comment) # standard-signals: for signal in frame.signals: if signal.multiplex is None: sig = createSignal(signal, nodeList, signalTypeEnums) message.append(sig) # check Multiplexor if present: multiplexor = None for signal in frame.signals: if signal.multiplex is not None and signal.multiplex == 'Multiplexor': multiplexor = etree.Element('Multiplex', name=signal.name, offset=str( signal.getStartbit()), length=str(int(signal.signalsize))) value = etree.Element('Value') if float(signal.min) != 0: value.set('min', "%g" % signal.min) if float(signal.max) != 1: value.set('max', "%g" % signal.max) multiplexor.append(value) labelset = etree.Element('LabelSet') for valueVal, valName in sorted( signal.values.items(), key=lambda x: int(x[0])): label = etree.Element( 'Label', name=valName.replace( '"', ''), value=str(valueVal)) labelset.append(label) multiplexor.append(labelset) # multiplexor found if multiplexor is not None: # ticker all potential muxgroups for i in range(0, 1 << int(multiplexor.get('length'))): empty = 0 muxgroup = etree.Element('MuxGroup', count=str(i)) for signal in frame.signals: if signal.multiplex is not None and signal.multiplex == i: sig = createSignal( signal, nodeList, signalTypeEnums) muxgroup.append(sig) empty = 1 if empty == 1: multiplexor.append(muxgroup) message.append(multiplexor) bus.append(message) root.append(bus) f.write(etree.tostring(root, pretty_print=True)) def parseSignal(signal, mux, namespace, nodelist): startbit = 0 if 'offset' in signal.attrib: startbit = signal.get('offset') signalsize = 1 if 'length' in signal.attrib: signalsize = signal.get('length') is_little_endian = True if 'endianess' in signal.attrib: if signal.get('endianess') == 'big': is_little_endian = False unit = "" offset = 0 factor = 1 min = None max = None is_signed = False is_float = False values = signal.find('./' + namespace + 'Value') if values is not None: if 'type' in values.attrib: valuetype = values.get('type') if valuetype == "single" or valuetype == "double": is_float = True elif valuetype == "unsigned": is_signed = False else: is_signed = True if 'slope' in values.attrib: factor = values.get('slope') if 'intercept' in values.attrib: offset = values.get('intercept') if 'unit' in values.attrib: unit = values.get('unit') if 'min' in values.attrib: min = values.get('min') if 'max' in values.attrib: max = values.get('max') receiver = [] consumers = signal.findall('./' + namespace + 'Consumer') for consumer in consumers: noderefs = consumer.findall('./' + namespace + 'NodeRef') for noderef in noderefs: receiver.append(nodelist[noderef.get('id')]) newSig = Signal(signal.get('name'), startBit=startbit, signalSize=signalsize, is_little_endian=is_little_endian, is_signed=is_signed, factor=factor, offset=offset, min=min, max=max, unit=unit, receiver=receiver, is_float = is_float, multiplex=mux) newSig.setStartbit(int(startbit)) notes = signal.findall('./' + namespace + 'Notes') comment = "" for note in notes: if note.text is not None: comment += note.text newSig.addComment(comment) labelsets = signal.findall('./' + namespace + 'LabelSet') for labelset in labelsets: labels = labelset.findall('./' + namespace + 'Label') for label in labels: name = label.get('name') value = label.get('value') newSig.addValues(value, name) return newSig def load(f, **options): dbs = {} tree = etree.parse(f) root = tree.getroot() namespace = "{" + tree.xpath('namespace-uri(.)') + "}" nodelist = {} nodes = root.findall('./' + namespace + 'Node') busses = root.findall('./' + namespace + 'Bus') counter = 0 for bus in busses: db = CanMatrix() db.addFrameDefines("GenMsgCycleTime", 'INT 0 65535') for node in nodes: db._BUs.add(BoardUnit(node.get('name'))) nodelist[node.get('id')] = node.get('name') messages = bus.findall('./' + namespace + 'Message') for message in messages: dlc = None #newBo = Frame(int(message.get('id'), 16), message.get('name'), 1, None) newBo = Frame(message.get('name'), Id=int(message.get('id'), 16)) if 'triggered' in message.attrib: newBo.addAttribute("GenMsgCycleTime", message.get('interval')) if 'length' in message.attrib: dlc = int(message.get('length')) newBo.size = dlc if 'format' in message.attrib: if message.get('format') == "extended": newBo.extended = 1 multiplex = message.find('./' + namespace + 'Multiplex') if multiplex is not None: startbit = 0 if 'offset' in multiplex.attrib: startbit = multiplex.get('offset') signalsize = 1 if 'length' in multiplex.attrib: signalsize = multiplex.get('length') is_little_endian = True min = None max = None values = multiplex.find('./' + namespace + 'Value') if values is not None: if 'min' in values.attrib: min = values.get('min') if 'max' in values.attrib: max = values.get('max') unit = "" offset = 0 factor = 1 is_signed = False if 'type' in multiplex.attrib: if multiplex.get('type') == 'signed': is_signed = True receiver = [] consumers = multiplex.findall('./' + namespace + 'Consumer') for consumer in consumers: noderefs = consumer.findall('./' + namespace + 'NodeRef') for noderef in noderefs: receiver.append(nodelist[noderef.get('id')]) newSig = Signal(multiplex.get('name'), startBit=startbit, signalSize=signalsize, is_little_endian=is_little_endian, is_signed=is_signed, factor=factor, offset=offset, min=min, max=max, unit=unit, receiver=receiver, multiplex='Multiplexor') if is_little_endian == False: # motorola/big_endian set/convert startbit newSig.setStartbit(startbit) notes = multiplex.findall('./' + namespace + 'Notes') comment = "" for note in notes: comment += note.text newSig.addComment(comment) labelsets = multiplex.findall('./' + namespace + 'LabelSet') for labelset in labelsets: labels = labelset.findall('./' + namespace + 'Label') for label in labels: name = label.get('name') value = label.get('value') newSig.addValues(value, name) newBo.addSignal(newSig) muxgroups = multiplex.findall('./' + namespace + 'MuxGroup') for muxgroup in muxgroups: mux = muxgroup.get('count') signales = muxgroup.findall('./' + namespace + 'Signal') for signal in signales: newSig = parseSignal(signal, mux, namespace, nodelist) newBo.addSignal(newSig) signales = message.findall('./' + namespace + 'Signal') producers = message.findall('./' + namespace + 'Producer') for producer in producers: noderefs = producer.findall('./' + namespace + 'NodeRef') for noderef in noderefs: newBo.addTransmitter(nodelist[noderef.get('id')]) for signal in signales: newSig = parseSignal(signal, None, namespace, nodelist) newBo.addSignal(newSig) notes = message.findall('./' + namespace + 'Notes') comment = "" for note in notes: if note.text is not None: comment += note.text newBo.addComment(comment) if dlc is None: newBo.calcDLC() else: newBo.size = dlc newBo.updateReceiver() db._fl.addFrame(newBo) name = bus.get('name') if not name: name = "CAN%d" % counter counter += 1 dbs[name] = db return dbs canmatrix-0.6/canmatrix/xlsx.py0000664000175000017500000007336613001475401016273 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the aframeve copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the aframeve copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports xls-files from a canmatrix-object # xls-files are the can-matrix-definitions displayed in Excel from __future__ import division from __future__ import absolute_import from builtins import * import math import sys from .canmatrix import * import os.path import xlsxwriter # Font Size : 8pt * 20 = 160 #font = 'font: name Arial Narrow, height 160' font = 'font: name Verdana, height 160' sty_header = 0 sty_norm = 0 sty_first_frame = 0 sty_white = 0 sty_green = 0 sty_green_first_frame = 0 sty_sender = 0 sty_sender_first_frame = 0 sty_sender_green = 0 sty_sender_green_first_frame = 0 def writeFramex(frame, worksheet, row, mystyle): # frame-id worksheet.write(row, 0, "%3Xh" % frame.id, mystyle) # frame-Name worksheet.write(row, 1, frame.name, mystyle) # determin cycle-time if "GenMsgCycleTime" in frame.attributes: worksheet.write( row, 2, int( frame.attributes["GenMsgCycleTime"]), mystyle) else: worksheet.write(row, 2, "", mystyle) # determin send-type if "GenMsgSendType" in frame.attributes: if frame.attributes["GenMsgSendType"] == "5": worksheet.write(row, 3, "Cyclic+Change", mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgDelayTime"]), mystyle) else: worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "0": worksheet.write(row, 3, "Cyclic", mystyle) worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "2": worksheet.write(row, 3, "BAF", mystyle) if "GenMsgNrOfRepetitions" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgNrOfRepetitions"]), mystyle) else: worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "8": worksheet.write(row, 3, "DualCycle", mystyle) if "GenMsgCycleTimeActive" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgCycleTimeActive"]), mystyle) else: worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "10": worksheet.write(row, 3, "None", mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgDelayTime"]), mystyle) else: worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "9": worksheet.write(row, 3, "OnChange", mystyle) if "GenMsgNrOfRepetitions" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgNrOfRepetitions"]), mystyle) else: worksheet.write(row, 4, "", mystyle) elif frame.attributes["GenMsgSendType"] == "1": worksheet.write(row, 3, "Spontaneous", mystyle) if "GenMsgDelayTime" in frame.attributes: worksheet.write( row, 4, int( frame.attributes["GenMsgDelayTime"]), mystyle) else: worksheet.write(row, 4, "", mystyle) else: worksheet.write(row, 3, "", mystyle) worksheet.write(row, 4, "", mystyle) else: worksheet.write(row, 3, "", mystyle) worksheet.write(row, 4, "", mystyle) def writeSignalx(db, sig, worksheet, row, rearCol, mystyle, motorolaBitFormat): if motorolaBitFormat == "msb": startBit = sig.getStartbit(bitNumbering=1) elif motorolaBitFormat == "msbreverse": startBit = sig.getStartbit() else: # motorolaBitFormat == "lsb" startBit = sig.getStartbit(bitNumbering=1, startLittle=True) # startbyte worksheet.write(row, 5, math.floor(startBit / 8) + 1, mystyle) # startbit worksheet.write(row, 6, (startBit) % 8, mystyle) # signalname worksheet.write(row, 7, sig.name, mystyle) # eval comment: if sig.comment is None: comment = "" else: comment = sig.comment # eval multiplex-info if sig.multiplex == 'Multiplexor': comment = "Mode Signal: " + comment elif sig.multiplex is not None: comment = "Mode " + str(sig.multiplex) + ":" + comment # write comment and size of signal in sheet worksheet.write(row, 8, comment, mystyle) worksheet.write(row, 9, sig.signalsize, mystyle) # startvalue of signal available if "GenSigStartValue" in sig.attributes: if db.signalDefines["GenSigStartValue"].definition == "STRING": worksheet.write(row, 10, sig.attributes[ "GenSigStartValue"], mystyle) elif db.signalDefines["GenSigStartValue"].definition == "INT" or db.signalDefines["GenSigStartValue"].definition == "HEX": worksheet.write(row, 10, "%Xh" % int(sig.attributes["GenSigStartValue"]), mystyle) else: worksheet.write(row, 10, " ", mystyle) else: worksheet.write(row, 10, " ", mystyle) # SNA-value of signal available if "GenSigSNA" in sig.attributes: sna = sig.attributes["GenSigSNA"][1:-1] worksheet.write(row, 11, sna, mystyle) # no SNA-value of signal available / just for correct style: else: worksheet.write(row, 11, " ", mystyle) # eval byteorder (intel == True / motorola == False) if sig.is_little_endian: worksheet.write(row, 12, "i", mystyle) else: worksheet.write(row, 12, "m", mystyle) # is a unit defined for signal? if sig.unit.strip().__len__() > 0: # factor not 1.0 ? if float(sig.factor) != 1: worksheet.write( row, rearCol + 2, "%g" % float( sig.factor) + " " + sig.unit, mystyle) #factor == 1.0 else: worksheet.write(row, rearCol + 2, sig.unit, mystyle) # no unit defined else: # factor not 1.0 ? if float(sig.factor) != 1: worksheet.write( row, rearCol + 2, "%g" % float( sig.factor), mystyle) #factor == 1.0 else: worksheet.write(row, rearCol + 2, "", mystyle) def writeValuex(label, value, worksheet, row, rearCol, mystyle): # write value and lable in sheet worksheet.write(row, rearCol, label, mystyle) worksheet.write(row, rearCol + 1, value, mystyle) def writeBuMatrixx(buList, sig, frame, worksheet, row, col, firstframe): # first-frame - style with borders: if firstframe == sty_first_frame: norm = sty_first_frame sender = sty_sender_first_frame norm_green = sty_green_first_frame sender_green = sty_sender_green_first_frame # consecutive-frame - style without borders: else: norm = sty_norm sender = sty_sender norm_green = sty_green sender_green = sty_sender_green # iterate over boardunits: for bu in buList: # every second Boardunit with other style if col % 2 == 0: locStyle = norm locStyleSender = sender # every second Boardunit with other style else: locStyle = norm_green locStyleSender = sender_green # write "s" "r" "r/s" if signal is sent, recieved or send and recived # by boardunit if bu in sig.receiver and bu in frame.transmitter: worksheet.write(row, col, "r/s", locStyleSender) elif bu in sig.receiver: worksheet.write(row, col, "r", locStyle) elif bu in frame.transmitter: worksheet.write(row, col, "s", locStyleSender) else: worksheet.write(row, col, "", locStyle) col += 1 # loop over boardunits ends here return col def dump(db, filename, **options): if 'xlsMotorolaBitFormat' in options: motorolaBitFormat = options["xlsMotorolaBitFormat"] else: motorolaBitFormat = "msbreverse" head_top = [ 'ID', 'Frame Name', 'Cycle Time [ms]', 'Launch Type', 'Launch Parameter', 'Signal Byte No.', 'Signal Bit No.', 'Signal Name', 'Signal Function', 'Signal Length [Bit]', 'Signal Default', ' Signal Not Available', 'Byteorder'] head_tail = ['Value', 'Name / Phys. Range', 'Function / Increment Unit'] workbook = xlsxwriter.Workbook(filename) # wsname = os.path.basename(filename).replace('.xlsx', '') # worksheet = workbook.add_worksheet('K-Matrix ' + wsname[0:22]) worksheet = workbook.add_worksheet('K-Matrix ') col = 0 global sty_header sty_header = workbook.add_format({'bold': True, 'rotation': 90, 'font_name': 'Verdana', 'font_size': 8, 'align': 'center', 'valign': 'center'}) global sty_first_frame sty_first_frame = workbook.add_format({'font_name': 'Verdana', 'font_size': 8, 'font_color': 'black', 'top': 1}) global sty_white sty_white = workbook.add_format({'font_name': 'Verdana', 'font_size': 8, 'font_color': 'white'}) global sty_norm sty_norm = workbook.add_format({'font_name': 'Verdana', 'font_size': 8, 'font_color': 'black'}) # BUMatrix-Styles global sty_green sty_green = workbook.add_format({'pattern': 1, 'fg_color': '#CCFFCC'}) global sty_green_first_frame sty_green_first_frame = workbook.add_format( {'pattern': 1, 'fg_color': '#CCFFCC', 'top': 1}) global sty_sender sty_sender = workbook.add_format({'pattern': 0x04, 'fg_color': '#C0C0C0'}) global sty_sender_first_frame sty_sender_first_frame = workbook.add_format( {'pattern': 0x04, 'fg_color': '#C0C0C0', 'top': 1}) global sty_sender_green sty_sender_green = workbook.add_format( {'pattern': 0x04, 'fg_color': '#C0C0C0', 'bg_color': '#CCFFCC'}) global sty_sender_green_first_frame sty_sender_green_first_frame = workbook.add_format( {'pattern': 0x04, 'fg_color': '#C0C0C0', 'bg_color': '#CCFFCC', 'top': 1}) # write first row (header) cols before frameardunits: for head in head_top: worksheet.write(0, col, head, sty_header) worksheet.set_column(col, col, 3.57) col += 1 # write frameardunits in first row: buList = [] for bu in db.boardUnits: worksheet.write(0, col, bu.name, sty_header) worksheet.set_column(col, col, 3.57) buList.append(bu.name) col += 1 head_start = col # write first row (header) cols after frameardunits: for head in head_tail: worksheet.write(0, col, head, sty_header) worksheet.set_column(col, col, 6) col += 1 # set width of selected Cols worksheet.set_column(0, 0, 3.57) worksheet.set_column(1, 1, 21) worksheet.set_column(3, 3, 12.29) worksheet.set_column(7, 7, 21) worksheet.set_column(8, 8, 30) worksheet.set_column(head_start + 1, head_start + 1, 21) worksheet.set_column(head_start + 2, head_start + 2, 12) frameHash = {} for frame in db.frames: frameHash[int(frame.id)] = frame # set row to first Frame (row = 0 is header) row = 1 # iterate over the frames for idx in sorted(frameHash.keys()): frame = frameHash[idx] framestyle = sty_first_frame # sort signals: sigHash = {} for sig in frame.signals: sigHash["%02d" % int(sig.getStartbit()) + sig.name] = sig # set style for first line with border sigstyle = sty_first_frame # iterate over signals for sig_idx in sorted(sigHash.keys()): sig = sigHash[sig_idx] # if not first Signal in Frame, set style if sigstyle != sty_first_frame: sigstyle = sty_norm # valuetable available? if sig.values.__len__() > 0: valstyle = sigstyle # iterate over values in valuetable for val in sorted(sig.values.keys()): writeFramex(frame, worksheet, row, framestyle) if framestyle != sty_first_frame: worksheet.set_row(row, None, None, {'level': 1}) col = head_top.__len__() col = writeBuMatrixx( buList, sig, frame, worksheet, row, col, framestyle) # write Value writeValuex( val, sig.values[val], worksheet, row, col, valstyle) writeSignalx(db, sig, worksheet, row, col, sigstyle, motorolaBitFormat) # no min/max here, because min/max has same col as values... # next row row += 1 # set style to normal - without border sigstyle = sty_white framestyle = sty_white valstyle = sty_norm # loop over values ends here # no valuetable available else: writeFramex(frame, worksheet, row, framestyle) if framestyle != sty_first_frame: worksheet.set_row(row, None, None, {'level': 1}) col = head_top.__len__() col = writeBuMatrixx( buList, sig, frame, worksheet, row, col, framestyle) writeSignalx(db, sig, worksheet, row, col, sigstyle, motorolaBitFormat) if float(sig.min) != 0 or float(sig.max) != 1.0: worksheet.write(row, col + 1, str("%g..%g" % (sig.min, sig.max)), sigstyle) else: worksheet.write(row, col + 1, "", sigstyle) # just for border worksheet.write(row, col, "", sigstyle) # next row row += 1 # set style to normal - without border sigstyle = sty_white framestyle = sty_white # reset signal-Array signals = [] # loop over signals ends here # loop over frames ends here worksheet.autofilter(0, 0, row, len(head_top) + len(head_tail) + len(db.boardUnits)) worksheet.freeze_panes(1, 0) # save file workbook.close() import codecs import zipfile from xml.etree.ElementTree import iterparse def readXlsx(file, **args): # from: Hooshmand zandi http://stackoverflow.com/a/16544219 import zipfile from xml.etree.ElementTree import iterparse if "sheet" in args: sheet = args["sheet"] else: sheet = 1 if "header" in args: isHeader = args["header"] else: isHeader = False rows = [] row = {} header = {} z = zipfile.ZipFile(file) # Get shared strings strings = [el.text for e, el in iterparse(z.open('xl/sharedStrings.xml')) if el.tag.endswith('}t') ] value = '' # Open specified worksheet for e, el in iterparse(z.open('xl/worksheets/sheet%d.xml' % (sheet))): # get value or index to shared strings if el.tag.endswith('}v'): # 84 value = el.text if el.tag.endswith( '}c'): # 84 # If value is a shared string, use value as an index if el.attrib.get('t') == 's': value = strings[int(value)] # split the row/col information so that the row leter(s) can be # separate letter = el.attrib['r'] # AZ22 while letter[-1].isdigit(): letter = letter[:-1] # if it is the first row, then create a header hash for the names # that COULD be used if rows == []: header[letter] = value.strip() else: if value != '': # if there is a header row, use the first row's names as # the row hash index if isHeader == True and letter in header: row[header[letter]] = value else: row[letter] = value value = '' if el.tag.endswith('}row'): rows.append(row) row = {} z.close() return [header, rows] def getIfPossible(row, value): if value in row: return row[value].strip() else: return None def load(filename, **options): from sys import modules # use xlrd excel reader if available, because its more robust try: import canmatrix.xls return canmatrix.xls.load(filename, **options) except: pass # else use this hack to read xlsx if 'xlsMotorolaBitFormat' in options: motorolaBitFormat = options["xlsMotorolaBitFormat"] else: motorolaBitFormat = "msbreverse" sheet = readXlsx(filename, sheet=1, header=True) db = CanMatrix() letterIndex = [] for a in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': letterIndex.append(a) for a in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': for b in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': letterIndex.append("%s%s" % (a, b)) # Defines not imported... # db.addBUDefines("NWM-Stationsadresse", 'HEX 0 63') # db.addBUDefines("NWM-Knoten", 'ENUM "nein","ja"') db.addFrameDefines("GenMsgCycleTime", 'INT 0 65535') db.addFrameDefines("GenMsgDelayTime", 'INT 0 65535') db.addFrameDefines("GenMsgCycleTimeActive", 'INT 0 65535') db.addFrameDefines("GenMsgNrOfRepetitions", 'INT 0 65535') # db.addFrameDefines("GenMsgStartValue", 'STRING') db.addFrameDefines( "GenMsgSendType", 'ENUM "cyclicX","spontanX","cyclicIfActiveX","spontanWithDelay","cyclicAndSpontanX","cyclicAndSpontanWithDelay","spontanWithRepitition","cyclicIfActiveAndSpontanWD","cyclicIfActiveFast","cyclicWithRepeatOnDemand","none"') # db.addSignalDefines("GenSigStartValue", 'HEX 0 4294967295') db.addSignalDefines("GenSigSNA", 'STRING') # eval search for correct collums: # index = {} # for i in range(sh.ncols): # value = sh.cell(0,i).value # if value == "ID": # index['ID'] = i # elif "Frame Name" in value: # index['frameName'] = i # elif "Cycle" in value: # index['cycle'] = i # elif "Launch Type" in value: # index['launchType'] = i # elif "Launch Parameter" in value: # index['launchParam'] = i # elif "Signal Byte No." in value: # index['startbyte'] = i # elif "Signal Bit No." in value: # index['startbit'] = i # elif "Signal Name" in value: # index['signalName'] = i # elif "Signal Function" in value: # index['signalComment'] = i # elif "Signal Length" in value: # index['signalLength'] = i # elif "Signal Default" in value: # index['signalDefault'] = i # elif "Signal Not Ava" in value: # index['signalSNA'] = i # elif "Value" in value: # index['Value'] = i # elif "Name / Phys" in value: # index['ValueName'] = i # elif "Function /" in value: # index['function'] = i # elif "Byteorder" in value: # index['byteorder'] = i if 'Byteorder' in list(sheet[0].values()): for key in sheet[0]: if sheet[0][key].strip() == 'Byteorder': _BUstart = letterIndex.index(key) + 1 break else: for key in sheet[0]: if sheet[0][key].strip() == 'Signal Not Available': _BUstart = letterIndex.index(key) + 1 for key in sheet[0]: if sheet[0][key].strip() == 'Value': _BUend = letterIndex.index(key) # BoardUnits: for x in range(_BUstart, _BUend): db._BUs.add(BoardUnit(sheet[0][letterIndex[x]])) # initialize: frameId = None signalName = "" newBo = None for row in sheet[1]: # ignore empty row if not 'ID' in row: continue # new frame detected if row['ID'] != frameId: sender = [] # new Frame frameId = row['ID'] frameName = row['Frame Name'] cycleTime = getIfPossible(row, "Cycle Time [ms]") launchType = getIfPossible(row, 'Launch Type') dlc = 8 launchParam = getIfPossible(row, 'Launch Parameter') if type(launchParam).__name__ != "float": launchParam = 0.0 launchParam = str(int(launchParam)) # newBo = Frame(int(frameId[:-1], 16), frameName, dlc, None) newBo = Frame(frameName, Id=int(frameId[:-1], 16), dlc=dlc) db._fl.addFrame(newBo) # eval launchtype if launchType is not None: if "Cyclic+Change" == launchType: newBo.addAttribute("GenMsgSendType", "5") newBo.addAttribute("GenMsgDelayTime", launchParam) elif "Cyclic" == launchType: newBo.addAttribute("GenMsgSendType", "0") elif "BAF" == launchType: newBo.addAttribute("GenMsgSendType", "2") newBo.addAttribute("GenMsgNrOfRepetitions", launchParam) elif "DualCycle" == launchType: newBo.addAttribute("GenMsgSendType", "8") newBo.addAttribute("GenMsgCycleTimeActive", launchParam) elif "None" == launchType: newBo.addAttribute("GenMsgSendType", "10") newBo.addAttribute("GenMsgDelayTime", launchParam) elif "OnChange" == launchType: newBo.addAttribute("GenMsgSendType", "9") newBo.addAttribute("GenMsgNrOfRepetitions", launchParam) elif "Spontaneous" == launchType: newBo.addAttribute("GenMsgSendType", "1") newBo.addAttribute("GenMsgDelayTime", launchParam) # #eval cycletime if type(cycleTime).__name__ != "float": cycleTime = 0.0 newBo.addAttribute("GenMsgCycleTime", str(int(cycleTime))) # new signal detected if row['Signal Name'] != signalName: # new Signal receiver = [] startbyte = int(row["Signal Byte No."]) startbit = int(row['Signal Bit No.']) signalName = row['Signal Name'] signalComment = getIfPossible(row, 'Signal Function') signalLength = int(row['Signal Length [Bit]']) signalDefault = getIfPossible(row, 'Signal Default') signalSNA = getIfPossible(row, 'Signal Not Available') multiplex = None if signalComment is not None and signalComment.startswith( 'Mode Signal:'): multiplex = 'Multiplexor' signalComment = signalComment[12:] elif signalComment is not None and signalComment.startswith('Mode '): mux, signalComment = signalComment[4:].split(':', 1) multiplex = int(mux.strip()) signalByteorder = getIfPossible(row, 'Byteorder') if signalByteorder is not None: if 'i' in signalByteorder: is_little_endian = True else: is_little_endian = False else: is_little_endian = True # Default Intel is_signed = False if signalName != "-": for x in range(_BUstart, _BUend): buName = sheet[0][letterIndex[x]].strip() buSenderReceiver = getIfPossible(row, buName) if buSenderReceiver is not None: if 's' in buSenderReceiver: newBo.addTransmitter(buName) if 'r' in buSenderReceiver: receiver.append(buName) # if signalLength > 8: # newSig = Signal(signalName, (startbyte-1)*8+startbit, signalLength, is_little_endian, is_signed, 1, 0, 0, 1, "", receiver, multiplex) newSig = Signal(signalName, startBit=(startbyte - 1) * 8 + startbit, signalSize=signalLength, is_little_endian=is_little_endian, is_signed=is_signed, receiver=receiver, multiplex=multiplex) # else: # newSig = Signal(signalName, (startbyte-1)*8+startbit, signalLength, is_little_endian, is_signed, 1, 0, 0, 1, "", receiver, multiplex) if is_little_endian == False: # motorola if motorolaBitFormat == "msb": newSig.setStartbit( (startbyte - 1) * 8 + startbit, bitNumbering=1) elif motorolaBitFormat == "msbreverse": newSig.setStartbit((startbyte - 1) * 8 + startbit) else: # motorolaBitFormat == "lsb" newSig.setStartbit( (startbyte - 1) * 8 + startbit, bitNumbering=1, startLittle=True) newBo.addSignal(newSig) newSig.addComment(signalComment) function = getIfPossible(row, 'Function / Increment Unit') value = getIfPossible(row, 'Value') valueName = getIfPossible(row, 'Name / Phys. Range') if valueName == 0 or valueName is None: valueName = "0" elif valueName == 1: valueName = "1" test = valueName #.encode('utf-8') factor = 0 unit = "" factor = getIfPossible(row, 'Function / Increment Unit') if type(factor).__name__ == "unicode" or type( factor).__name__ == "str": factor = factor.strip() if " " in factor and factor[0].isdigit(): (factor, unit) = factor.strip().split(" ", 1) factor = factor.strip() unit = unit.strip() newSig.unit = unit newSig.factor = float(factor) else: unit = factor.strip() newSig.unit = unit newSig.factor = 1 if ".." in test: (mini, maxi) = test.strip().split("..", 2) unit = "" try: newSig.offset = float(mini) newSig.min = float(mini) newSig.max = float(maxi) except: newSig.offset = 0 newSig.min = None newSig.max = None elif valueName.__len__() > 0: if value is not None and value.strip().__len__() > 0: value = int(float(value)) newSig.addValues(value, valueName) maxi = pow(2, signalLength) - 1 newSig.max = float(maxi) else: newSig.offset = 0 newSig.min = None newSig.max = None # dlc-estimation / dlc is not in xls, thus calculate a minimum-dlc: for frame in db.frames: frame.updateReceiver() frame.calcDLC() return db canmatrix-0.6/canmatrix/cmcsv.py0000664000175000017500000002373213001475401016400 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the aframeve copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the aframeve copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports canmatrix-objects to a CSV file. (Based on exportxlsx) # Author: Martin Hoffmann (m8ddin@gmail.com) from collections import defaultdict import sys import csv if (sys.version_info > (3, 0)): import codecs extension = 'csv' class csvRow: def __init__(self): self._rowdict = defaultdict(str) def __getitem__(self, key): return self._rowdict[key] def __setitem__(self, key, item): if (sys.version_info <= (3, 0)): if type(item).__name__ == "unicode": item = item.encode('utf-8') self._rowdict[key] = item def write(self, column, value): self._rowdict[column] = value @property def as_list(self): # Generate list of single cells in the row till highest index (dictionary key) # Empty cells (non-existent keys) are generated as empty string return [str(self._rowdict[x]) for x in range(0, max(self._rowdict) + 1)] def toCSV(self, delimiter=','): text = delimiter.join(self.as_list) return text.replace('\n', ' ') def __str__(self): return self.toCSV() def writeFramex(frame, row): # frame-id row[0] = "%3Xh" % frame.id # frame-Name row[1] = frame.name # determine cycle-time if "GenMsgCycleTime" in frame.attributes: row[2] = int(frame.attributes["GenMsgCycleTime"]) # determine send-type if "GenMsgSendType" in frame.attributes: if frame.attributes["GenMsgSendType"] == "5": row[3] = "Cyclic+Change" if "GenMsgDelayTime" in frame.attributes: row[4] = int(frame.attributes["GenMsgDelayTime"]) elif frame.attributes["GenMsgSendType"] == "0": row[3] = "Cyclic" elif frame.attributes["GenMsgSendType"] == "2": row[3] = "BAF" if "GenMsgNrOfRepetitions" in frame.attributes: row[4] = int(frame.attributes["GenMsgNrOfRepetitions"]) elif frame.attributes["GenMsgSendType"] == "8": row[3] = "DualCycle" if "GenMsgCycleTimeActive" in frame.attributes: row[4] = int(frame.attributes["GenMsgCycleTimeActive"]) elif frame.attributes["GenMsgSendType"] == "10": row[3] = "None" if "GenMsgDelayTime" in frame.attributes: row[3] = int(frame.attributes["GenMsgDelayTime"]) elif frame.attributes["GenMsgSendType"] == "9": row[3] = "OnChange" if "GenMsgNrOfRepetitions" in frame.attributes: row[4] = int(frame.attributes["GenMsgNrOfRepetitions"]) elif frame.attributes["GenMsgSendType"] == "1": row[3] = "Spontaneous" if "GenMsgDelayTime" in frame.attributes: row[4] = int(frame.attributes["GenMsgDelayTime"]) else: pass def writeBuMatrixx(buList, sig, frame, row, col): # iterate over boardunits: for bu in buList: # write "s" "r" "r/s" if signal is sent, received or send and received # by boardunit if bu in sig.receiver and bu in frame.transmitter: row[col] = "r/s" elif bu in sig.receiver: row[col] = "r" elif bu in frame.transmitter: row[col] = "s" else: pass col += 1 return col def writeValuex(label, value, row, rearCol): row[rearCol] = value row[rearCol + 1] = label def writeSignalx(db, sig, row, rearCol): # startbyte row[5] = int((sig.getStartbit()) / 8 + 1) # startbit row[6] = (sig.getStartbit()) % 8 # signalname row[7] = sig.name # eval comment: if sig.comment is None: comment = "" else: comment = sig.comment # eval multiplex-info if sig.multiplex == 'Multiplexor': comment = "Mode Signal: " + comment elif sig.multiplex is not None: comment = "Mode " + str(sig.multiplex) + ":" + comment # write comment and size of signal in sheet row[8] = comment row[9] = sig.signalsize # startvalue of signal available if "GenSigStartValue" in sig.attributes: if db.signalDefines["GenSigStartValue"].definition == "STRING": row[10] = sig.attributes["GenSigStartValue"] elif db.signalDefines["GenSigStartValue"].definition == "INT" or db.signalDefines["GenSigStartValue"].definition == "HEX": row[10] = "%Xh" % int(sig.attributes["GenSigStartValue"]) # SNA-value of signal available if "GenSigSNA" in sig.attributes: row[11] = sig.attributes["GenSigSNA"][1:-1] # eval byteorder (intel == 1 / motorola == 0) if sig.is_little_endian == True: row[12] = "i" else: row[12] = "m" # signed / unsigned if sig.is_signed == True: row[13] = "s" else: row[13] = "u" # is a unit defined for signal? if sig.unit.strip().__len__() > 0: # factor not 1.0 ? if float(sig.factor) != 1: row[rearCol + 2] = "%g" % float(sig.factor) + " " + sig.unit #factor == 1.0 else: row[rearCol + 2] = sig.unit # no unit defined else: # factor not 1.0 ? if float(sig.factor) != 1: row[rearCol + 2] = float(sig.factor) def dump(db, thefile, delimiter=',', **options): head_top = [ 'ID', 'Frame Name', 'Cycle Time [ms]', 'Launch Type', 'Launch Parameter', 'Signal Byte No.', 'Signal Bit No.', 'Signal Name', 'Signal Function', 'Signal Length [Bit]', 'Signal Default', ' Signal Not Available', 'Byteorder', 'is signed'] head_tail = ['Value', 'Name / Phys. Range', 'Function / Increment Unit'] csvtable = list() # List holding all csv rows col = 0 # Column counter # -- headers start: headerrow = csvRow() # write first row (header) cols before frameardunits: for head in head_top: headerrow.write(col, head) col += 1 # write frameardunits in first row: buList = [] for bu in db.boardUnits: headerrow.write(col, bu.name) buList.append(bu.name) col += 1 # write first row (header) cols after frameardunits: for head in head_tail: headerrow.write(col, head) col += 1 csvtable.append(headerrow) # -- headers end... frameHash = {} for frame in db.frames: frameHash[int(frame.id)] = frame # set row to first Frame (row = 0 is header) row = 1 # iterate over the frames for idx in sorted(frameHash.keys()): frame = frameHash[idx] # sort signals: sigHash = {} for sig in frame.signals: sigHash["%02d" % int(sig.getStartbit()) + sig.name] = sig # iterate over signals for sig_idx in sorted(sigHash.keys()): sig = sigHash[sig_idx] # value table available? if sig.values.__len__() > 0: # iterate over values in valuetable for val in sorted(sig.values.keys()): signalRow = csvRow() writeFramex(frame, signalRow) col = head_top.__len__() col = writeBuMatrixx(buList, sig, frame, signalRow, col) # write Value writeValuex(val, sig.values[val], signalRow, col) writeSignalx(db, sig, signalRow, col) # no min/max here, because min/max has same col as values. # next row row += 1 csvtable.append(signalRow) # loop over values ends here # no value table available else: signalRow = csvRow() writeFramex(frame, signalRow) col = head_top.__len__() col = writeBuMatrixx(buList, sig, frame, signalRow, col) writeSignalx(db, sig, signalRow, col) if sig.min is not None or sig.max is not None: signalRow[col + 1] = str("{}..{}".format(sig.min, sig.max)) # next row row += 1 csvtable.append(signalRow) # set style to normal - without border # loop over signals ends here # loop over frames ends here if (sys.version_info > (3, 0)): import io temp = io.TextIOWrapper(thefile, encoding='UTF-8') else: temp = thefile writer = csv.writer(temp, delimiter=delimiter) for row in csvtable: writer.writerow(row.as_list) # else: # # just print to stdout # finalTableString = "\n".join( # [row.toCSV(delimiter) for row in csvtable]) # print(finalTableString) canmatrix-0.6/canmatrix/cmjson.py0000664000175000017500000001644013166737333016575 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports json-files from a canmatrix-object # json-files are the can-matrix-definitions of the CANard-project # (https://github.com/ericevenchick/CANard) from builtins import * from .canmatrix import * import codecs import json import sys extension = 'json' def dump(db, f, **options): if 'jsonCanard' in options: exportCanard = options['jsonCanard'] else: exportCanard = False if 'jsonAll' in options: exportAll = options['jsonAll'] else: exportAll = False if (sys.version_info > (3, 0)): mode = 'w' else: mode = 'wb' exportArray = [] if exportCanard: for frame in db.frames: signals = {} for signal in frame.signals: signals[ signal.getStartbit( bitNumbering=1, startLittle=True)] = { "name": signal.name, "bit_length": signal.signalsize, "factor": signal.factor, "offset": signal.offset} exportArray.append( {"name": frame.name, "id": hex(frame.id), "signals": signals}) elif exportAll == False: for frame in db.frames: signals = [] for signal in frame.signals: signals.append({ "name": signal.name, "start_bit": signal.getStartbit(bitNumbering=1, startLittle=True), "bit_length": signal.signalsize, "factor": float(signal.factor), "offset": float(signal.offset), "is_big_endian": signal.is_little_endian == 0, "is_signed": signal.is_signed, "is_float": signal.is_float }) exportArray.append({"name": frame.name, "id": int(frame.id), "is_extended_frame": frame.extended == 1, "signals": signals}) else: # exportall for frame in db.frames: frameattribs = {} for attribute in frame.attributes: frameattribs[attribute] = frame.attributes[attribute] signals = [] for signal in frame.signals: attribs = {} for attribute in signal.attributes: attribs[attribute] = signal.attributes[attribute] signalDict = { "name": signal.name, "start_bit": signal.getStartbit(bitNumbering=1, startLittle=True), "bit_length": signal.signalsize, "factor": float(signal.factor), "offset": float(signal.offset), "is_big_endian": signal.is_little_endian == 0, "is_signed": signal.is_signed, "is_float": signal.is_float, "comment": signal.comment, "attributes": attribs, } if signal.multiplex is not None: signalDict["multiplex"] = signal.multiplex signals.append(signalDict) if signal.unit is not None: signalDict["unit"] = signal.unit signals.append(signalDict) exportArray.append( {"name": frame.name, "id": int(frame.id), "is_extended_frame": frame.extended == 1, "signals": signals, "attributes": frameattribs, "comment": frame.comment}) if (sys.version_info > (3, 0)): import io temp = io.TextIOWrapper(f, encoding='UTF-8') else: temp = f json.dump({"messages": exportArray}, temp, sort_keys=True, indent=4, separators=(',', ': ')) def load(f, **options): db = CanMatrix() if (sys.version_info > (3, 0)): import io jsonData = json.load(io.TextIOWrapper(f, encoding='UTF-8')) else: jsonData = json.load(f) if "messages" in jsonData: for frame in jsonData["messages"]: # newframe = Frame(frame["id"],frame["name"],8,None) newframe = Frame(frame["name"], Id=frame["id"], dlc=8) if "is_extended_frame" in frame and frame["is_extended_frame"]: newframe.extended = 1 else: newframe.extended = 0 for signal in frame["signals"]: if "is_big_endian" in signal and signal["is_big_endian"]: is_little_endian = False else: is_little_endian = True if "is_float" in signal and signal["is_float"]: is_float = True else: is_float = False if "is_signed" in signal and signal["is_signed"]: is_signed = True else: is_signed = False newsignal = Signal(signal["name"], startBit=signal["start_bit"], signalSize=signal["bit_length"], is_little_endian=is_little_endian, is_signed=is_signed, factor=signal["factor"], offset=signal["offset"]) if "unit" in signal and signal["unit"]: newsignal.unit = signal["unit"] if "multiplex" in signal and signal["multiplex"]: newsignal.unit = signal["multiplex"] if newsignal.is_little_endian == False: newsignal.setStartbit( newsignal._startbit, bitNumbering=1, startLittle=True) newframe.addSignal(newsignal) db._fl.addFrame(newframe) f.close() return db canmatrix-0.6/canmatrix/autosarhelper.py0000664000175000017500000000774713001475401020153 0ustar eduedu00000000000000from __future__ import absolute_import from builtins import * #!/usr/bin/env python import logging logger = logging.getLogger('root') from .canmatrix import * # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script supplys some helperfunctions to parse arxml-files # arxml-files are the can-matrix-definitions and a lot more in AUTOSAR-Context # class arTree(object): def __init__(self, name="", ref=None): self._name = name self._ref = ref self._array = [] def new(self, name, child): temp = arTree(name, child) self._array.append(temp) return temp def getChild(self, path): for tem in self._array: if tem._name == path: return tem def arParseTree(tag, ardict, namespace): for child in tag: name = child.find('./' + namespace + 'SHORT-NAME') # namel = child.find('./' + namespace + 'LONG-NAME') if name is not None and child is not None: arParseTree(child, ardict.new(name.text, child), namespace) if name is None and child is not None: arParseTree(child, ardict, namespace) # # some sort of X-Path in autosar-xml-files: # def arGetXchildren(root, path, arDict, ns): pathElements = path.split('/') ptr = root for element in pathElements[:-1]: ptr = arGetChild(ptr, element, arDict, ns) ptr = arGetChildren(ptr, pathElements[-1], arDict, ns) return ptr # # get path in tranlation-dictionary # def arGetPath(ardict, path): ptr = ardict for p in path.split('/'): if p.strip(): if ptr is not None: ptr = ptr.getChild(p) else: return None if ptr is not None: return ptr._ref else: return None def arGetChild(parent, tagname, arTranslationTable, namespace): # logger.debug("getChild: " + tagname) if parent is None: return None ret = parent.find('.//' + namespace + tagname) if ret is None: ret = parent.find('.//' + namespace + tagname + '-REF') if ret is not None: ret = arGetPath(arTranslationTable, ret.text) return ret def arGetChildren(parent, tagname, arTranslationTable, namespace): if parent is None: return [] ret = parent.findall('.//' + namespace + tagname) if ret.__len__() == 0: retlist = parent.findall('.//' + namespace + tagname + '-REF') rettemp = [] for ret in retlist: rettemp.append(arGetPath(arTranslationTable, ret.text)) ret = rettemp return ret def arGetName(parent, ns): name = parent.find('./' + ns + 'SHORT-NAME') if name is not None: if name.text is not None: return name.text return "" canmatrix-0.6/canmatrix/log.py0000664000175000017500000000412513001475401016041 0ustar eduedu00000000000000from __future__ import absolute_import #!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # Configurable logging # Author: Martin Hoffmann (m8ddin@gmail.com) import logging def setup_logger(name): """Setup a project wide logger singleton""" formatter = logging.Formatter( fmt='%(levelname)s - %(module)s - %(message)s') handler = logging.StreamHandler() handler.setFormatter(formatter) logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.addHandler(handler) return logger def set_log_level(logger, level): """Dynamic reconfiguration of the log level""" if level > 2: level = 2 if level < -1: level = -1 lvls = {-1: logging.ERROR, 0: logging.WARN, 1: logging.INFO, 2: logging.DEBUG} logger.setLevel(lvls[level]) canmatrix-0.6/canmatrix/__init__.py0000664000175000017500000000000012773545340017022 0ustar eduedu00000000000000canmatrix-0.6/canmatrix/dbf.py0000664000175000017500000004414213166737333016037 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script imports dbf-files in a canmatrix-object # dbf-files are the can-matrix-definitions of the busmaster-project (http://rbei-etas.github.io/busmaster/) # from __future__ import division from __future__ import absolute_import from __future__ import print_function from builtins import * import math import logging logger = logging.getLogger('root') from .canmatrix import * import re import codecs # TODO support for [START_PARAM_NODE_RX_SIG] # TODO support for [START_PARAM_NODE_TX_MSG] def decodeDefine(line): (define, valueType, value) = line.split(',', 2) valueType = valueType.strip() if valueType == "INT" or valueType == "HEX": (Min, Max, default) = value.split(',', 2) myDef = valueType + ' ' + Min.strip() + ' ' + Max.strip() default = default.strip() elif valueType == "ENUM": (enums, default) = value.rsplit(',', 1) myDef = valueType + " " + enums[1:] elif valueType == "STRING": myDef = valueType default = value else: logger.debug(line) return define[1:-1], myDef, default def load(f, **options): if 'dbfImportEncoding' in options: dbfImportEncoding = options["dbfImportEncoding"] else: dbfImportEncoding = 'iso-8859-1' db = CanMatrix() mode = '' for line in f: line = line.decode(dbfImportEncoding).strip() if mode == 'SignalDescription': if line.startswith( "[END_DESC_SIG]") or line.startswith("[END_DESC]"): mode = '' else: (boId, temS, SignalName, comment) = line.split(' ', 3) comment = comment.replace('"', '').replace(';', '') db.frameById(int(boId)).signalByName( SignalName).addComment(comment) if mode == 'BUDescription': if line.startswith( "[END_DESC_NODE]") or line.startswith("[END_DESC]"): mode = '' else: (BUName, comment) = line.split(' ', 1) comment = comment.replace('"', '').replace(';', '') db._BUs.byName(BUName).addComment(comment) if mode == 'FrameDescription': if line.startswith( "[END_DESC_MSG]") or line.startswith("[END_DESC]"): mode = '' else: (boId, temS, comment) = line.split(' ', 2) comment = comment.replace('"', '').replace(';', '') frame = db.frameById(int(boId)) if frame: frame.addComment(comment) elif mode == 'ParamMsgVal': if line.startswith("[END_PARAM_MSG_VAL]"): mode = '' else: (boId, temS, attrib, value) = line.split(',', 3) db.frameById( int(boId)).addAttribute( attrib.replace( '"', ''), value.replace( '"', '')) elif mode == 'ParamNodeVal': if line.startswith("[END_PARAM_NODE_VAL]"): mode = '' else: (bu, attrib, value) = line.split(',', 2) db._BUs.byName(bu).addAttribute( attrib.replace('"', ''), value[1:-1]) elif mode == 'ParamNetVal': if line.startswith("[END_PARAM_NET_VAL]"): mode = '' else: (attrib, value) = line.split(',', 1) db.addAttribute(attrib.replace('"', ''), value[1:-1]) elif mode == 'ParamSigVal': if line.startswith("[END_PARAM_SIG_VAL]"): mode = '' else: (boId, temS, SignalName, attrib, value) = line.split(',', 4) db.frameById( int(boId)).signalByName(SignalName).addAttribute( attrib.replace( '"', ''), value[ 1:-1]) elif mode == 'ParamSig': if line.startswith("[END_PARAM_SIG]"): mode = '' else: (name, define, default) = decodeDefine(line) db.addSignalDefines(name, define) db.addDefineDefault(name, default) elif mode == 'ParamMsg': if line.startswith("[END_PARAM_MSG]"): mode = '' else: (name, define, default) = decodeDefine(line) db.addFrameDefines(name, define) db.addDefineDefault(name, default) elif mode == 'ParamNode': if line.startswith("[END_PARAM_NODE]"): mode = '' else: (name, define, default) = decodeDefine(line) db.addBUDefines(name, define) db.addDefineDefault(name, default) elif mode == 'ParamNet': if line.startswith("[END_PARAM_NET]"): mode = '' else: (name, define, default) = decodeDefine(line) db.addGlobalDefines(name, define) db.addDefineDefault(name, default) else: if line.startswith("[START_DESC_SIG]"): mode = 'SignalDescription' if line.startswith("[START_DESC_MSG]"): mode = 'FrameDescription' if line.startswith("[START_DESC_NODE]"): mode = 'BUDescription' if line.startswith("[START_PARAM_NODE_VAL]"): mode = 'ParamNodeVal' if line.startswith("[START_PARAM_NET_VAL]"): mode = 'ParamNetVal' if line.startswith("[START_PARAM_MSG_VAL]"): mode = 'ParamMsgVal' if line.startswith("[START_PARAM_SIG_VAL]"): mode = 'ParamSigVal' if line.startswith("[START_PARAM_SIG]"): mode = 'ParamSig' if line.startswith("[START_PARAM_MSG]"): mode = 'ParamMsg' if line.startswith("[START_PARAM_NODE]"): mode = 'ParamNode' if line.startswith("[START_PARAM_NET]"): mode = 'ParamNet' if line.startswith("[START_MSG]"): temstr = line.strip()[11:].strip() temparray = temstr.split(',') (name, Id, size, nSignals, dummy) = temparray[0:5] if len(temparray) > 5: extended = temparray[5] else: extended = None if len(temparray) > 6: transmitter = temparray[6].split() else: transmitter = None newBo = db._fl.addFrame( Frame(name, Id=int(Id), dlc=size, transmitter=transmitter)) # Frame(int(Id), name, size, transmitter)) if extended == 'X': logger.debug("Extended") newBo.extended = 1 if line.startswith("[NODE]"): temstr = line.strip()[6:].strip() boList = temstr.split(',') for bo in boList: db._BUs.add(BoardUnit(bo)) if line.startswith("[START_SIGNALS]"): temstr = line.strip()[15:].strip() temparray = temstr.split(',') (name, size, startbyte, startbit, sign, Max, Min, byteorder, offset, factor, unit, multiplex) = temparray[0:12] if len(temparray) > 12: receiver = temparray[12].split(',') else: receiver = [] if multiplex == 'M': multiplex = 'Multiplexor' elif multiplex.strip().__len__() > 0: multiplex = int(multiplex[1:]) else: multiplex = None is_float = False is_signed = False if sign == "U": is_signed = False elif sign == "F" or sign == "D": is_float = True else: is_signed = True startbit = int(startbit) startbit += (int(startbyte) - 1) * 8 newSig = newBo.addSignal(Signal(name, startBit=startbit, signalSize=size, is_little_endian=( int(byteorder) == 1), is_signed=is_signed, factor=factor, offset=offset, min=float(Min) * float(factor), max=float(Max) * float(factor), unit=unit, receiver=receiver, is_float=is_float, multiplex=multiplex)) if int(byteorder) == 0: # this is dummy here, because internal lsb is default - for # now newSig.setStartbit( startbit, bitNumbering=1, startLittle=True) if line.startswith("[VALUE_DESCRIPTION]"): temstr = line.strip()[19:].strip() regexp = re.compile("\"(.+)\" *, *(.+)") temp = regexp.match(temstr) if temp: name = temp.group(1) value = temp.group(2) newSig.addValues(value, name) for frame in db.frames: # receiver is only given in the signals, so do propagate the # receiver to the frame: frame.updateReceiver() return db def dump(db, f, **options): if 'dbfExportEncoding' in options: dbfExportEncoding = options["dbfExportEncoding"] else: dbfExportEncoding = 'iso-8859-1' outstr = """//******************************BUSMASTER Messages and signals Database ******************************// [DATABASE_VERSION] 1.3 [PROTOCOL] CAN [BUSMASTER_VERSION] [1.7.2] [NUMBER_OF_MESSAGES] """ outstr += str(len(db.frames)) + "\n" # Frames for frame in db.frames: # Name unMsgId m_ucLength m_ucNumOfSignals m_cDataFormat m_cFrameFormat? m_txNode # m_cDataFormat If 1 dataformat Intel, 0- Motorola -- immer 1 original Converter macht das nach anzahl entsprechender Signale # cFrameFormat Standard 'S' Extended 'X' extended = 'S' if frame.extended == 1: extended = 'X' outstr += "[START_MSG] " + frame.name + \ ",%d,%d,%d,1,%c," % (frame.id, frame.size, len(frame.signals), extended) if frame.transmitter.__len__() == 0: frame.addTransmitter("Vector__XXX") # DBF does not support multiple Transmitters outstr += frame.transmitter[0] + "\n" for signal in frame.signals: # m_acName ucLength m_ucWhichByte m_ucStartBit # m_ucDataFormat m_fOffset m_fScaleFactor m_acUnit m_acMultiplex m_rxNode # m_ucDataFormat whichbyte = int( math.floor( signal.getStartbit( bitNumbering=1, startLittle=True) / 8) + 1) sign = 'S' if not signal.is_signed: sign = 'U' if signal.is_float: if signal.signalsize > 32: sign = 'D' else: sign = 'F' outstr += "[START_SIGNALS] " + signal.name + ",%d,%d,%d,%c," % (signal.signalsize, whichbyte, int(signal.getStartbit(bitNumbering=1, startLittle=True)) % 8, sign) + '{},{}'.format(float(signal.max) / float(signal.factor), float(signal.min) / float(signal.factor)) outstr += ",%d,%s,%s" % (signal.is_little_endian, signal.offset, signal.factor) multiplex = "" if signal.multiplex is not None: if signal.multiplex == 'Multiplexor': multiplex = 'M' else: multiplex = 'm' + str(signal.multiplex) outstr += "," + signal.unit + ",%s," % multiplex + \ ','.join(signal.receiver) + "\n" if len(signal.values) > 0: for attrib, val in sorted(list(signal.values.items())): outstr += '[VALUE_DESCRIPTION] "' + \ val + '",' + str(attrib) + '\n' outstr += "[END_MSG]\n\n" # Boardunits outstr += "[NODE] " count = 1 for bu in db.boardUnits: outstr += bu.name if count < len(db.boardUnits): outstr += "," count += 1 outstr += "\n" outstr += "[START_DESC]\n\n" # BU-descriptions outstr += "[START_DESC_MSG]\n" for frame in db.frames: if frame.comment is not None: comment = frame.comment.replace("\n", " ") outstr += str(frame.id) + ' S "' + comment + '";\n' outstr += "[END_DESC_MSG]\n" # Frame descriptions outstr += "[START_DESC_NODE]\n" for bu in db.boardUnits: if bu.comment is not None: comment = bu.comment.replace("\n", " ") outstr += bu.name + ' "' + comment + '";\n' outstr += "[END_DESC_NODE]\n" # signal descriptions outstr += "[START_DESC_SIG]\n" for frame in db.frames: for signal in frame.signals: if signal.comment is not None: comment = signal.comment.replace("\n", " ") outstr += "%d S " % frame.id + signal.name + ' "' + comment + '";\n' outstr += "[END_DESC_SIG]\n" outstr += "[END_DESC]\n\n" outstr += "[START_PARAM]\n" # db-parameter outstr += "[START_PARAM_NET]\n" for (type, define) in list(db.globalDefines.items()): if define.defaultValue is not None: outstr += '"' + type + '",' + \ define.definition.replace( ' ', ',') + ',' + define.defaultValue + '\n' outstr += "[END_PARAM_NET]\n" # bu-parameter outstr += "[START_PARAM_NODE]\n" for (type, define) in list(db.buDefines.items()): if define.defaultValue is not None: outstr += '"' + type + '",' + \ define.definition.replace( ' ', ',') + ',' + define.defaultValue + '\n' outstr += "[END_PARAM_NODE]\n" # frame-parameter outstr += "[START_PARAM_MSG]\n" for (type, define) in list(db.frameDefines.items()): if define.defaultValue is not None: outstr += '"' + type + '",' + \ define.definition.replace( ' ', ',') + ',' + define.defaultValue + '\n' outstr += "[END_PARAM_MSG]\n" # signal-parameter outstr += "[START_PARAM_SIG]\n" for (type, define) in list(db.signalDefines.items()): if define.defaultValue is not None: outstr += '"' + type + '",' + \ define.definition.replace( ' ', ',') + ',' + define.defaultValue + '\n' outstr += "[END_PARAM_SIG]\n" outstr += "[START_PARAM_VAL]\n" # boardunit-attributes: outstr += "[START_PARAM_NODE_VAL]\n" for bu in db.boardUnits: for attrib, val in sorted(list(bu.attributes.items())): outstr += bu.name + ',"' + attrib + '","' + val + '"\n' outstr += "[END_PARAM_NODE_VAL]\n" # messages-attributes: outstr += "[START_PARAM_MSG_VAL]\n" for frame in db.frames: for attrib, val in sorted(list(frame.attributes.items())): outstr += str(frame.id) + ',S,"' + attrib + '","' + val + '"\n' outstr += "[END_PARAM_MSG_VAL]\n" # signal-attributes: outstr += "[START_PARAM_SIG_VAL]\n" for frame in db.frames: for signal in frame.signals: for attrib, val in sorted(list(signal.attributes.items())): outstr += str(frame.id) + ',S,' + signal.name + \ ',"' + attrib + '","' + val + '"\n' outstr += "[END_PARAM_SIG_VAL]\n" outstr += "[END_PARAM_VAL]\n" f.write(outstr.encode(dbfExportEncoding)) canmatrix-0.6/canmatrix/dbc.py0000664000175000017500000010132413166737333016030 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports dbc-files from a canmatrix-object # dbc-files are the can-matrix-definitions of the CanOe (Vector Informatic) from __future__ import division from __future__ import print_function from __future__ import absolute_import import collections import logging logger = logging.getLogger('root') from builtins import * import math from .canmatrix import * import re import codecs #dbcExportEncoding = 'iso-8859-1' # CP1253 def normalizeName(name, whitespaceReplacement): name = re.sub('\s+', whitespaceReplacement, name) if ' ' in name: name = '"' + name + '"' return name def format_float(f): s = str(f).upper() if s.endswith('.0'): s = s[:-2] if 'E' in s: s = s.split('E') s = '%sE%s%s' % (s[0], s[1][0], s[1][1:].rjust(3, '0')) return s.upper() def dump(db, f, **options): if 'dbcExportEncoding' in options: dbcExportEncoding = options["dbcExportEncoding"] else: dbcExportEncoding = 'iso-8859-1' if 'dbcExportCommentEncoding' in options: dbcExportCommentEncoding = options["dbcExportCommentEncoding"] else: dbcExportCommentEncoding = dbcExportEncoding if 'whitespaceReplacement' in options: whitespaceReplacement = options["whitespaceReplacement"] if whitespaceReplacement in ['', None] or set( [' ', '\t']).intersection(whitespaceReplacement): print("Warning: Settings may result in whitespace in DBC variable names. This is not supported by the DBC format.") else: whitespaceReplacement = '_' if 'writeValTable' in options: writeValTable = options["writeValTable"] else: writeValTable = True f.write("VERSION \"created by canmatrix\"\n\n".encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) f.write("NS_ :\n\nBS_:\n\n".encode(dbcExportEncoding)) # Boardunits f.write("BU_: ".encode(dbcExportEncoding)) id = 1 nodeList = {} for bu in db.boardUnits: f.write((bu.name + " ").encode(dbcExportEncoding)) f.write("\n\n".encode(dbcExportEncoding)) if writeValTable: # ValueTables for table in db.valueTables: f.write(("VAL_TABLE_ " + table).encode(dbcExportEncoding)) for row in db.valueTables[table]: f.write( (' ' + str(row) + ' "' + db.valueTables[table][row] + '"').encode(dbcExportEncoding)) f.write(";\n".encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) output_names = collections.defaultdict(dict) for frame in db.frames: normalized_names = collections.OrderedDict(( (s, normalizeName(s.name, whitespaceReplacement)) for s in frame.signals )) duplicate_signal_totals = collections.Counter(normalized_names.values()) duplicate_signal_counter = collections.Counter() numbered_names = collections.OrderedDict() for signal in frame.signals: name = normalized_names[signal] duplicate_signal_counter[name] += 1 if duplicate_signal_totals[name] > 1: # TODO: pad to 01 in case of 10+ instances, for example? name += str(duplicate_signal_counter[name] - 1) output_names[frame][signal] = name # Frames for bo in db.frames: multiplex_written = False if bo.transmitter.__len__() == 0: bo.addTransmitter("Vector__XXX") if bo.extended == 1: bo.id += 0x80000000 f.write( ("BO_ %d " % bo.id + bo.name + ": %d " % bo.size + bo.transmitter[0] + "\n").encode(dbcExportEncoding)) duplicate_signal_totals = collections.Counter( normalizeName(s.name, whitespaceReplacement) for s in bo.signals ) duplicate_signal_counter = collections.Counter() for signal in bo.signals: if signal.multiplex == 'Multiplexor' and multiplex_written: continue f.write((" SG_ " + output_names[bo][signal]).encode(dbcExportEncoding)) if signal.multiplex == 'Multiplexor': f.write(' M '.encode(dbcExportEncoding)) multiplex_written = True elif signal.multiplex is not None: f.write((" m%d " % int(signal.multiplex)).encode(dbcExportEncoding)) startbit = signal.getStartbit(bitNumbering=1) if signal.is_signed: sign = '-' else: sign = '+' f.write( (" : %d|%d@%d%c" % (startbit, signal.signalsize, signal.is_little_endian, sign)).encode(dbcExportEncoding)) f.write( (" (%s,%s)" % (format_float(signal.factor), format_float(signal.offset))).encode(dbcExportEncoding)) f.write( (" [{}|{}]".format( format_float(signal.min), format_float(signal.max))).encode(dbcExportEncoding)) f.write(' "'.encode(dbcExportEncoding)) if signal.unit is None: signal.unit = "" f.write(signal.unit.encode(dbcExportEncoding)) f.write('" '.encode(dbcExportEncoding)) if signal.receiver.__len__() == 0: signal.addReceiver('Vector__XXX') f.write((','.join(signal.receiver) + "\n").encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # second Sender: for bo in db.frames: if bo.transmitter.__len__() > 1: f.write( ("BO_TX_BU_ %d : %s;\n" % (bo.id, ','.join( bo.transmitter))).encode(dbcExportEncoding)) # frame comments for bo in db.frames: if bo.comment is not None and bo.comment.__len__() > 0: f.write( ("CM_ BO_ " + "%d " % bo.id + ' "').encode(dbcExportEncoding)) f.write( bo.comment.replace( '"', '\\"').encode(dbcExportCommentEncoding, 'ignore')) f.write('";\n'.encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # signal comments for bo in db.frames: for signal in bo.signals: if signal.comment is not None and signal.comment.__len__() > 0: name = output_names[bo][signal] f.write( ("CM_ SG_ " + "%d " % bo.id + name + ' "').encode(dbcExportEncoding, 'ignore')) f.write( signal.comment.replace( '"', '\\"').encode(dbcExportCommentEncoding, 'ignore')) f.write('";\n'.encode(dbcExportEncoding, 'ignore')) f.write("\n".encode(dbcExportEncoding)) # boarUnit comments for bu in db.boardUnits: if bu.comment is not None and bu.comment.__len__() > 0: f.write( ("CM_ BU_ " + bu.name + ' "' + bu.comment.replace( '"', '\\"') + '";\n').encode(dbcExportCommentEncoding,'ignore')) f.write("\n".encode(dbcExportEncoding)) defaults = {} for (dataType, define) in sorted(list(db.frameDefines.items())): f.write( ('BA_DEF_ BO_ "' + dataType + '" ').encode(dbcExportEncoding) + define.definition.encode( dbcExportEncoding, 'replace') + ';\n'.encode(dbcExportEncoding)) if dataType not in defaults and define.defaultValue is not None: defaults[dataType] = define.defaultValue for (dataType, define) in sorted(list(db.signalDefines.items())): f.write( ('BA_DEF_ SG_ "' + dataType + '" ').encode(dbcExportEncoding) + define.definition.encode( dbcExportEncoding, 'replace') + ';\n'.encode(dbcExportEncoding)) if dataType not in defaults and define.defaultValue is not None: defaults[dataType] = define.defaultValue for (dataType, define) in sorted(list(db.buDefines.items())): f.write( ('BA_DEF_ BU_ "' + dataType + '" ').encode(dbcExportEncoding) + define.definition.encode( dbcExportEncoding, 'replace') + ';\n'.encode(dbcExportEncoding)) if dataType not in defaults and define.defaultValue is not None: defaults[dataType] = define.defaultValue for (dataType, define) in sorted(list(db.globalDefines.items())): f.write( ('BA_DEF_ "' + dataType + '" ').encode(dbcExportEncoding) + define.definition.encode( dbcExportEncoding, 'replace') + ';\n'.encode(dbcExportEncoding)) if dataType not in defaults and define.defaultValue is not None: defaults[dataType] = define.defaultValue for define in sorted(defaults): f.write( ('BA_DEF_DEF_ "' + define + '" ').encode(dbcExportEncoding) + defaults[define].encode( dbcExportEncoding, 'replace') + ';\n'.encode(dbcExportEncoding)) # boardunit-attributes: for bu in db.boardUnits: for attrib, val in sorted(bu.attributes.items()): if db.buDefines[attrib].type == "STRING": val = '"' + val + '"' elif not val: val = '""' f.write( ('BA_ "' + attrib + '" BU_ ' + bu.name + ' ' + str(val) + ';\n').encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # global-attributes: for attrib, val in sorted(db.attributes.items()): if db.globalDefines[attrib].type == "STRING": val = '"' + val + '"' elif not val: val = '""' f.write(('BA_ "' + attrib + '" ' + val + ';\n').encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # messages-attributes: for frame in db.frames: for attrib, val in sorted(frame.attributes.items()): if db.frameDefines[attrib].type == "STRING": val = '"' + val + '"' elif not val: val = '""' f.write(('BA_ "' + attrib + '" BO_ %d ' % frame.id + val + ';\n').encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # signal-attributes: for frame in db.frames: for signal in frame.signals: for attrib, val in sorted(signal.attributes.items()): name = output_names[frame][signal] if db.signalDefines[attrib].type == "STRING": val = '"' + val + '"' elif not val: val = '""' elif isinstance(val, float): val = format_float(val) f.write( ('BA_ "' + attrib + '" SG_ %d ' % frame.id + name + ' ' + val + ';\n').encode(dbcExportEncoding)) if signal.is_float: if int(signal.signalsize) > 32: f.write(('SIG_VALTYPE_ %d %s : 2;\n' % (frame.id, output_names[bo][signal])).encode(dbcExportEncoding)) else: f.write(('SIG_VALTYPE_ %d %s : 1;\n' % (frame.id, output_names[bo][signal])).encode(dbcExportEncoding)) f.write("\n".encode(dbcExportEncoding)) # signal-values: for bo in db.frames: multiplex_written = False for signal in bo.signals: if signal.multiplex == 'Multiplexor' and multiplex_written: continue multiplex_written = True if signal.values: f.write( ('VAL_ %d ' % bo.id + output_names[bo][signal]).encode(dbcExportEncoding)) for attrib, val in sorted( signal.values.items(), key=lambda x: int(x[0])): f.write( (' ' + str(attrib) + ' "' + val + '"').encode(dbcExportEncoding)) f.write(";\n".encode(dbcExportEncoding)) # signal-groups: for bo in db.frames: for sigGroup in bo.SignalGroups: f.write(("SIG_GROUP_ " + str(bo.id) + " " + sigGroup.name + " " + str(sigGroup.id) + " :").encode(dbcExportEncoding)) for signal in sigGroup.signals: f.write((" " + output_names[bo][signal]).encode(dbcExportEncoding)) f.write(";\n".encode(dbcExportEncoding)) def load(f, **options): if 'dbcImportEncoding' in options: dbcImportEncoding = options["dbcImportEncoding"] else: dbcImportEncoding = 'iso-8859-1' if 'dbcImportCommentEncoding' in options: dbcCommentEncoding = options["dbcImportCommentEncoding"] else: dbcCommentEncoding = dbcImportEncoding i = 0 class FollowUps(object): nothing, signalComment, frameComment, boardUnitComment, globalComment = list( range(5)) followUp = FollowUps.nothing comment = "" signal = None frame = None boardUnit = None db = CanMatrix() for line in f: i = i + 1 l = line.strip() if l.__len__() == 0: continue if followUp == FollowUps.signalComment: try: comment += "\n" + \ l.decode(dbcCommentEncoding).replace('\\"', '"') except: logger.error("Error decoding line: %d (%s)" % (i, line)) if l.endswith(b'";'): followUp = FollowUps.nothing if signal is not None: signal.addComment(comment[0:-2]) continue elif followUp == FollowUps.frameComment: try: comment += "\n" + \ l.decode(dbcCommentEncoding).replace('\\"', '"') except: logger.error("Error decoding line: %d (%s)" % (i, line)) if l.endswith(b'";'): followUp = FollowUps.nothing if frame is not None: frame.addComment(comment[0:-2]) continue elif followUp == FollowUps.boardUnitComment: try: comment += "\n" + \ l.decode(dbcCommentEncoding).replace('\\"', '"') except: logger.error("Error decoding line: %d (%s)" % (i, line)) if l.endswith(b'";'): followUp = FollowUps.nothing if boardUnit is not None: boardUnit.addComment(comment[0:-2]) continue decoded = l.decode(dbcImportEncoding) if decoded.startswith("BO_ "): regexp = re.compile("^BO\_ (\w+) (\w+) *: (\w+) (\w+)") temp = regexp.match(decoded) # db._fl.addFrame(Frame(temp.group(1), temp.group(2), temp.group(3), temp.group(4))) db._fl.addFrame(Frame(temp.group(2), Id=temp.group(1), dlc=temp.group(3), transmitter=temp.group(4).split())) elif decoded.startswith("SG_ "): pattern = "^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)" regexp = re.compile(pattern) temp = regexp.match(decoded) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp_raw = regexp_raw.match(l) if temp: receiver = list(map(str.strip, temp.group(11).split(','))) tempSig = Signal(temp.group(1), startBit=temp.group(2), signalSize=temp.group(3), is_little_endian=(int(temp.group(4)) == 1), is_signed=(temp.group(5) == '-'), factor=temp.group(6), offset=temp.group(7), min=temp.group(8), max=temp.group(9), unit=temp_raw.group(10).decode( dbcImportEncoding), receiver=receiver) if not tempSig.is_little_endian: # startbit of motorola coded signals are MSB in dbc tempSig.setStartbit(int(temp.group(2)), bitNumbering=1) db._fl.addSignalToLastFrame(tempSig) else: pattern = "^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) receiver = list(map(str.strip, temp.group(12).split(','))) multiplex = temp.group(2) if multiplex == 'M': multiplex = 'Multiplexor' else: multiplex = int(multiplex[1:]) tempSig = Signal(temp.group(1), startBit=temp.group(3), signalSize=temp.group(4), is_little_endian=(int(temp.group(5)) == 1), is_signed=(temp.group(6) == '-'), factor=temp.group(7), offset=temp.group(8), min=temp.group(9), max=temp.group(10), unit=temp_raw.group(11).decode( dbcImportEncoding), receiver=receiver, multiplex=multiplex) if not tempSig.is_little_endian: # startbit of motorola coded signals are MSB in dbc tempSig.setStartbit(int(temp.group(3)), bitNumbering=1) db._fl.addSignalToLastFrame(tempSig) elif decoded.startswith("BO_TX_BU_ "): regexp = re.compile("^BO_TX_BU_ ([0-9]+) *: *(.+);") temp = regexp.match(decoded) botschaft = db.frameById(temp.group(1)) for bu in temp.group(2).split(','): botschaft.addTransmitter(bu) elif decoded.startswith("CM_ SG_ "): pattern = "^CM\_ SG\_ *(\w+) *(\w+) *\"(.*)\";" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: botschaft = db.frameById(temp.group(1)) signal = botschaft.signalByName(temp.group(2)) if signal: try: signal.addComment(temp_raw.group(3).decode( dbcCommentEncoding).replace('\\"', '"')) except: logger.error( "Error decoding line: %d (%s)" % (i, line)) else: pattern = "^CM\_ SG\_ *(\w+) *(\w+) *\"(.*)" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: botschaft = db.frameById(temp.group(1)) signal = botschaft.signalByName(temp.group(2)) try: comment = temp_raw.group(3).decode( dbcCommentEncoding).replace('\\"', '"') except: logger.error( "Error decoding line: %d (%s)" % (i, line)) followUp = FollowUps.signalComment elif decoded.startswith("CM_ BO_ "): pattern = "^CM\_ BO\_ *(\w+) *\"(.*)\";" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: frame = db.frameById(temp.group(1)) if frame: try: frame.addComment(temp_raw.group(2).decode( dbcCommentEncoding).replace('\\"', '"')) except: logger.error( "Error decoding line: %d (%s)" % (i, line)) else: pattern = "^CM\_ BO\_ *(\w+) *\"(.*)" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: frame = db.frameById(temp.group(1)) try: comment = temp_raw.group(2).decode( dbcCommentEncoding).replace('\\"', '"') except: logger.error( "Error decoding line: %d (%s)" % (i, line)) followUp = FollowUps.frameComment elif decoded.startswith("CM_ BU_ "): pattern = "^CM\_ BU\_ *(\w+) *\"(.*)\";" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: boardUnit = db.boardUnitByName(temp.group(1)) if boardUnit: try: boardUnit.addComment(temp_raw.group(2).decode( dbcCommentEncoding).replace('\\"', '"')) except: logger.error( "Error decoding line: %d (%s)" % (i, line)) else: pattern = "^CM\_ BU\_ *(\w+) *\"(.*)" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: boardUnit = db.boardUnitByName(temp.group(1)) if boardUnit: try: comment = temp_raw.group(2).decode( dbcCommentEncoding).replace('\\"', '"') except: logger.error( "Error decoding line: %d (%s)" % (i, line)) followUp = FollowUps.boardUnitComment elif decoded.startswith("BU_:"): pattern = "^BU\_\:(.*)" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) if temp: myTempListe = temp.group(1).split(' ') for ele in myTempListe: if len(ele.strip()) > 1: db._BUs.add(BoardUnit(ele)) elif decoded.startswith("VAL_ "): regexp = re.compile("^VAL\_ (\w+) (\w+) (.*);") temp = regexp.match(decoded) if temp: botschaftId = temp.group(1) signal = temp.group(2) tempList = temp.group(3).split('"') if botschaftId.isnumeric(): # value for Frame try: bo = db.frameById(botschaftId) sg = bo.signalByName(signal) for i in range(math.floor(len(tempList) / 2)): val = tempList[i * 2 + 1] if sg: sg.addValues(tempList[i * 2], val) except: logger.error("Error with Line: " + str(tempList)) else: logger.info("Warning: enviroment variables currently not supported") elif decoded.startswith("VAL_TABLE_ "): regexp = re.compile("^VAL\_TABLE\_ (\w+) (.*);") temp = regexp.match(decoded) if temp: tableName = temp.group(1) tempList = temp.group(2).split('"') try: valHash = {} for i in range(math.floor(len(tempList) / 2)): val = tempList[i * 2 + 1] valHash[tempList[i * 2].strip()] = val.strip() except: logger.error("Error with Line: " + str(tempList)) db.addValueTable(tableName, valHash) else: logger.debug(l) elif decoded.startswith("BA_DEF_ SG_ "): pattern = "^BA\_DEF\_ SG\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: db.addSignalDefines(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding)) elif decoded.startswith("BA_DEF_ BO_ "): pattern = "^BA\_DEF\_ BO\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: db.addFrameDefines(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding)) elif decoded.startswith("BA_DEF_ BU_ "): pattern = "^BA\_DEF\_ BU\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: db.addBUDefines(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding)) elif decoded.startswith("BA_DEF_ "): pattern = "^BA\_DEF\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: db.addGlobalDefines(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding)) elif decoded.startswith("BA_ "): regexp = re.compile("^BA\_ +\"[A-Za-z0-9[\-_ .]+\" +(.+)") tempba = regexp.match(decoded) if tempba.group(1).strip().startswith("BO_ "): regexp = re.compile("^BA\_ \"(.*)\" BO\_ (\w+) (.+);") temp = regexp.match(decoded) db.frameById(int(temp.group(2))).addAttribute( temp.group(1), temp.group(3)) elif tempba.group(1).strip().startswith("SG_ "): regexp = re.compile("^BA\_ \"(.*)\" SG\_ (\w+) (\w+) (.+);") temp = regexp.match(decoded) db.frameById(int(temp.group(2))).signalByName( temp.group(3)).addAttribute(temp.group(1), temp.group(4)) elif tempba.group(1).strip().startswith("BU_ "): regexp = re.compile("^BA\_ \"(.*)\" BU\_ (\w+) (.+);") temp = regexp.match(decoded) db._BUs.byName( temp.group(2)).addAttribute( temp.group(1), temp.group(3)) else: regexp = re.compile( "^BA\_ \"([A-Za-z0-9\-\_]+)\" +([\"A-Za-z0-9\-\_]+);") temp = regexp.match(decoded) if temp: db.addAttribute(temp.group(1), temp.group(2)) elif decoded.startswith("SIG_GROUP_ "): regexp = re.compile("^SIG\_GROUP\_ +(\w+) +(\w+) +(\w+) +\:(.*);") temp = regexp.match(decoded) frame = db.frameById(temp.group(1)) if frame is not None: signalArray = temp.group(4).split(' ') frame.addSignalGroup(temp.group(2), temp.group(3), signalArray) elif decoded.startswith("SIG_VALTYPE_ "): regexp = re.compile("^SIG\_VALTYPE\_ +(\w+) +(\w+) +\:(.*);") temp = regexp.match(decoded) frame = db.frameById(temp.group(1)) if frame: signal = frame.signalByName(temp.group(2)) signal.is_float = True # SIG_VALTYPE_ 0 float : 1; elif decoded.startswith("BA_DEF_DEF_ "): pattern = "^BA\_DEF\_DEF\_ +\"([A-Za-z0-9\-_]+)\" +(.+)\;" regexp = re.compile(pattern) regexp_raw = re.compile(pattern.encode(dbcImportEncoding)) temp = regexp.match(decoded) temp_raw = regexp_raw.match(l) if temp: db.addDefineDefault(temp.group(1), temp_raw.group(2).decode(dbcImportEncoding)) # else: # print "Unrecocniced line: " + l + " (%d) " % i # Backtracking for frame in db.frames: # receiver is only given in the signals, so do propagate the receiver # to the frame: frame.updateReceiver() # extended-flag is implicite in canid, thus repair this: if frame.id > 0x80000000: frame.id -= 0x80000000 frame.extended = 1 for define in db.globalDefines: if db.globalDefines[define].type == "STRING": if define in db.attributes: db.attributes[define] = db.attributes[define][1:-1] for define in db.buDefines: if db.buDefines[define].type == "STRING": for ecu in db.boardUnits: if define in ecu.attributes: ecu.attributes[define] = ecu.attributes[define][1:-1] for define in db.frameDefines: if db.frameDefines[define].type == "STRING": for frame in db.frames: if define in frame.attributes: frame.attributes[define] = frame.attributes[define][1:-1] for define in db.signalDefines: if db.signalDefines[define].type == "STRING": for frame in db.frames: for signal in frame.signals: if define in signal.attributes: signal.attributes[define] = signal.attributes[define][1:-1] return db canmatrix-0.6/canmatrix/fibex.py0000664000175000017500000002766313001475401016371 0ustar eduedu00000000000000#!/usr/bin/env python # Copyright (c) 2013, Eduard Broecker # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that # the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this list of conditions and the # following disclaimer. # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the # following disclaimer in the documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. # # this script exports fibex-files from a canmatrix-object # gibex-files are the network-matrix-definitions; Canmatrix exports CAN # only (fibex: Field Bus Exchange Format // # https://de.wikipedia.org/wiki/Field_Bus_Exchange_Format) from __future__ import absolute_import from builtins import * from lxml import etree from .canmatrix import * import os.path fx = "http://www.asam.net/xml/fbx" ho = "http://www.asam.net/xml" can = "http://www.asam.net/xml/fbx/can" xsi = "http://www.w3.org/2001/XMLSchema-instance" ns_ho = "{%s}" % ho ns_fx = "{%s}" % fx ns_can = "{%s}" % can ns_xsi = "{%s}" % xsi extension = "xml" def createShortNameDesc(parent, shortname, desc): ShortName = etree.SubElement(parent, ns_ho + "SHORT-NAME") ShortName.text = shortname Desc = etree.SubElement(parent, ns_ho + "DESC") Desc.text = desc def createSubElementFx(parent, elementName, elementText=None): new = etree.SubElement(parent, ns_fx + elementName) if elementText is not None: new.text = elementText return new def createSubElementHo(parent, elementName, elementText=None): new = etree.SubElement(parent, ns_ho + elementName) if elementText is not None: new.text = elementText return new def dump(db, f, **options): nsmap = {"fx": fx, "ho": ho, "can": can, "xsi": xsi} root = etree.Element(ns_fx + "FIBEX", nsmap=nsmap) root.attrib[ '{{{pre}}}schemaLocation'.format( pre=xsi)] = 'http://www.asam.net/xml/fbx ..\\..\\xml_schema\\fibex.xsd http://www.asam.net/xml/fbx/can ..\\..\\xml_schema\\fibex4can.xsd' # # PROJECT # project = createSubElementFx(root, "PROJECT") project.set('ID', 'canmatrixExport') createShortNameDesc(project, "CAN", "Canmatrix Export") # # ELEMENTS # elements = createSubElementFx(root, "ELEMENTS") # # CLUSTERS # clusters = createSubElementFx(elements, "CLUSTERS") cluster = etree.SubElement(clusters, ns_fx + "CLUSTER") cluster.set('ID', 'canCluster1') createShortNameDesc(cluster, "clusterShort", "clusterDesc") createSubElementFx(cluster, "SPEED", "500") createSubElementFx(cluster, "IS-HIGH-LOW-BIT-ORDER", "false") createSubElementFx(cluster, "BIT-COUNTING-POLICY", "MONOTONE") protocol = createSubElementFx(cluster, "PROTOCOL", "CAN") protocol.attrib['{{{pre}}}type'.format(pre=xsi)] = "can:PROTOCOL-TYPE" createSubElementFx(cluster, "PROTOCOL-VERSION", "20") channelRefs = createSubElementFx(cluster, "CHANNEL-REFS") # for each channel channelRef = createSubElementFx(channelRefs, "CHANNEL-REF") channelRef.set("ID-REF", "CANCHANNEL01") # # CHANNELS # channels = createSubElementFx(elements, "CHANNELS") channel = createSubElementFx(channels, "CHANNEL") # for each channel createShortNameDesc(channel, "CANCHANNEL01", "Can Channel Description") frameTriggerings = createSubElementFx(channel, "FRAME-TRIGGERINGS") for frame in db.frames: frameTriggering = createSubElementFx( frameTriggerings, "FRAME-TRIGGERING") frameTriggering.set("ID", "FT_" + frame.name) identifier = createSubElementFx(frameTriggering, "IDENTIFIER") createSubElementFx(identifier, "IDENTIFIER-VALUE", str(frame.id)) frameRef = createSubElementFx(frameTriggering, "FRAME-REF") frameRef.set("ID-REF", "FRAME_" + frame.name) # # ECUS # ecus = createSubElementFx(elements, "ECUS") for bu in db.boardUnits: ecu = createSubElementFx(ecus, "ECU") ecu.set("ID", bu.name) createShortNameDesc(ecu, bu.name, bu.comment) functionRefs = createSubElementFx(ecu, "FUNCTION-REFS") funcRef = createSubElementFx(functionRefs, "FUNCTION-REF") funcRef.set("ID-REF", "FCT_" + bu.name) # ignore CONTROLERS/CONTROLER # # PDUS # pdus = createSubElementFx(elements, "PDUS") for frame in db.frames: pdu = createSubElementFx(pdus, "PDU") pdu.set("ID", "PDU_" + frame.name) createShortNameDesc(pdu, "PDU_" + frame.name, frame.comment) createSubElementFx(pdu, "BYTE-LENGTH", str(frame.size)) # DLC createSubElementFx(pdu, "PDU-TYPE", "APPLICATION") signalInstances = createSubElementFx(pdu, "SIGNAL-INSTANCES") for signal in frame.signals: signalInstance = createSubElementFx( signalInstances, "SIGNAL-INSTANCE") signalInstance.set("ID", "PDUINST_" + signal.name) # startBit: TODO - find out correct BYTEORDER ... createSubElementFx(signalInstance, "BIT-POSITION", str(signal._startbit)) if signal.is_little_endian: createSubElementFx( signalInstance, "IS-HIGH-LOW-BYTE-ORDER", "false") # true:big endian; false:littele endian else: createSubElementFx( signalInstance, "IS-HIGH-LOW-BYTE-ORDER", "true") signalRef = createSubElementFx(signalInstance, "SIGNAL-REF") signalRef.set("ID-REF", signal.name) # FRAMES # frames = createSubElementFx(elements, "FRAMES") for frame in db.frames: frameEle = createSubElementFx(frames, "FRAME") frameEle.set("ID", "FRAME_" + frame.name) createShortNameDesc(frameEle, "FRAME_" + frame.name, frame.comment) createSubElementFx(frameEle, "BYTE-LENGTH", str(frame.size)) # DLC createSubElementFx(frameEle, "PDU-TYPE", "APPLICATION") pduInstances = createSubElementFx(frameEle, "PDU-INSTANCES") pduInstance = createSubElementFx(pduInstances, "PDU-INSTANCE") pduInstance.set("ID", "PDUINSTANCE_" + frame.name) pduref = createSubElementFx(pduInstance, "PDU-REF") pduref.set("ID-REF", "PDU_" + frame.name) createSubElementFx(pduInstance, "BIT-POSITION", "0") createSubElementFx(pduInstance, "IS-HIGH-LOW-BYTE-ORDER", "false") # # FUNCTIONS # functions = createSubElementFx(elements, "FUNCTIONS") for bu in db.boardUnits: function = createSubElementFx(functions, "FUNCTION") function.set("ID", "FCT_" + bu.name) createShortNameDesc(function, "FCT_" + bu.name, bu.comment) inputPorts = createSubElementFx(function, "INPUT-PORTS") for frame in db.frames: for signal in frame.signals: if bu.name in signal.receiver: inputPort = createSubElementFx(inputPorts, "INPUT-PORT") inputPort.set("ID", "INP_" + signal.name) desc = etree.SubElement(inputPort, ns_ho + "DESC") desc.text = signal.comment signalRef = createSubElementFx(inputPort, "SIGNAL-REF") signalRef.set("ID-REF", "SIG_" + signal.name) for frame in db.frames: if bu.name in frame.transmitter: for signal in frame.signals: outputPort = createSubElementFx(inputPorts, "OUTPUT-PORT") outputPort.set("ID", "OUTP_" + signal.name) desc = etree.SubElement(outputPort, ns_ho + "DESC") desc.text = "signalcomment" signalRef = createSubElementFx(outputPort, "SIGNAL-REF") signalRef.set("ID-REF", "SIG_" + signal.name) # # SIGNALS # for frame in db.frames: signals = createSubElementFx(elements, "SIGNALS") for signal in frame.signals: signalEle = createSubElementFx(signals, "SIGNAL") signalEle.set("ID", "SIG_" + signal.name) createShortNameDesc(signalEle, signal.name, signal.comment) codingRef = createSubElementFx(signalEle, "CODING-REF") codingRef.set("ID-REF", "CODING_" + signal.name) # # PROCESSING-INFORMATION # procInfo = etree.SubElement(elements, ns_fx + "PROCESSING-INFORMATION", nsmap={"ho": ho}) unitSpec = createSubElementHo(procInfo, "UNIT-SPEC") for frame in db.frames: for signal in frame.signals: unit = createSubElementHo(unitSpec, "UNIT") unit.set("ID", "UNIT_" + signal.name) createSubElementHo(unit, "SHORT-NAME", signal.name) createSubElementHo(unit, "DISPLAY-NAME", signal.unit) codings = createSubElementFx(procInfo, "CODINGS") for frame in db.frames: for signal in frame.signals: coding = createSubElementFx(codings, "CODING") coding.set("ID", "CODING_" + signal.name) createShortNameDesc( coding, "CODING_" + signal.name, "Coding for " + signal.name) # ignore CODE-TYPE compumethods = createSubElementHo(coding, "COMPU-METHODS") compumethod = createSubElementHo(compumethods, "COMPU-METHOD") createSubElementHo( compumethod, "SHORT-NAME", "COMPUMETHOD_" + signal.name) createSubElementHo(compumethod, "CATEGORY", "LINEAR") unitRef = createSubElementHo(compumethod, "UNIT-REF") unitRef.set("ID-REF", "UNIT_" + signal.name) compuInternalToPhys = createSubElementHo( compumethod, "COMPU-INTERNAL-TO-PHYS") compuscales = createSubElementHo( compuInternalToPhys, "COMPU-SCALES") compuscale = createSubElementHo(compuscales, "COMPU-SCALE") lowerLimit = createSubElementHo( compuscale, "LOWER-LIMIT", str(signal.min)) # Min lowerLimit.set("INTERVAL-TYPE", "CLOSED") upperLimit = createSubElementHo( compuscale, "UPPER-LIMIT", str(signal.max)) # Max upperLimit.set("INTERVAL-TYPE", "CLOSED") compuRationalCoeffs = createSubElementHo( compuscale, "COMPU-RATIONAL-COEFFS") compuNumerator = createSubElementHo( compuRationalCoeffs, "COMPU-NUMERATOR") createSubElementHo( compuNumerator, "V", str( signal.offset)) # offset createSubElementHo( compuNumerator, "V", str( signal.factor)) # factor compuDenomiator = createSubElementHo( compuRationalCoeffs, "COMPU-DENOMINATOR") createSubElementHo(compuDenomiator, "V", "1") # nenner #defaultValue = createSubElementHo(compuInternalToPhys,"COMPU-DEFAULT-VALUE") # # REQUIREMENTS # #requirements = createSubElementFx(elements, "REQUIREMENTS") f.write(etree.tostring(root, pretty_print=True)) canmatrix-0.6/canmatrix/version.py0000664000175000017500000000006413166742041016754 0ustar eduedu00000000000000version = "0.6" major = 0 minor = 6 patchlevlel = 0 canmatrix-0.6/PKG-INFO0000664000175000017500000000370313166743513014034 0ustar eduedu00000000000000Metadata-Version: 1.1 Name: canmatrix Version: 0.6 Summary: Support and convert several CAN (Controller Area Network) database formats .arxml .dbc .dbf .kcd .sym fibex xls(x) ... Home-page: http://github.com/ebroecker/canmatrix Author: Eduard Broecker Author-email: eduard@gmx.de License: BSD Description: Canmatrix implements a "Python Can Matrix Object" which describes the can-communication and the needed objects (Boardunits, Frames, Signals, Values, ...) Canmatrix also includes two Tools (canconvert and cancompare) for converting and comparing CAN databases. There are also some extract and merge options for dealing with can databases. supported file formats for import: .dbc candb / Vector .dbf Busmaster (open source!) .kcd kayak (open source!) .arxml autosar system description .yaml dump of the python object .xls(x) excel xls-import, works with .xls-file generated by this lib .sym peak pcan can description supported file formats for export: .dbc .dbf .kcd .xls(x) .json Canard (open source!) .arxml (very basic implementation) .yaml (dump of the python object) .sym .xml (fibex) Keywords: CAN dbc arxml kcd dbf sym Platform: any Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: License :: OSI Approved :: BSD License Classifier: Topic :: Scientific/Engineering