| | |
| | | # reference: https://github.com/ebroecker/canmatrix |
| | | |
| | | # this script translates dbc-files to list data |
| | | from pickle import FALSE |
| | | import sys |
| | | import os |
| | | import logging |
| | |
| | | UNSIGNED = 0 |
| | | SIGNED = 1 |
| | | |
| | | |
| | | def normalizeValueTable(table): |
| | | return {int(k): v for k, v in table.items()} |
| | | |
| | | |
| | | @attr.s(cmp=False) |
| | | class Frame: |
| | |
| | | if sig.getStartbit() + int(sig.size) > maxBit: |
| | | maxBit = sig.getStartbit() + int(sig.size) |
| | | self.size = max(self.size, int(math.ceil(maxBit / 8))) |
| | | |
| | | |
| | | def setFdType(self): |
| | | """Try to guess and set the CAN type for every frame. |
| | | If a Frame is longer than 8 bytes, it must be Flexible Data Rate frame (CAN-FD). |
| | |
| | | bitfieldLe = [] |
| | | bitfieldBe = [] |
| | | |
| | | for i in range(0,64): |
| | | for i in range(0, 64): |
| | | bitfieldBe.append(0) |
| | | bitfieldLe.append(0) |
| | | bitfield.append(0) |
| | |
| | | |
| | | for sig in self.signals: |
| | | i += 1 |
| | | for bit in range(sig.getStartbit(), sig.getStartbit() + int(sig.size)): |
| | | for bit in range(sig.getStartbit(), |
| | | sig.getStartbit() + int(sig.size)): |
| | | 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): |
| | | 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] |
| | | |
| | | 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 |
| | | |
| | |
| | | * _multiplex ('Multiplexor' or Number of Multiplex) |
| | | """ |
| | | |
| | | name = attr.ib(default = "") |
| | | name = attr.ib(default="") |
| | | # float_factory = attr.ib(default=defaultFloatFactory) |
| | | float_factory = defaultFloatFactory |
| | | startBit = attr.ib(type=int, default=0) |
| | | size = attr.ib(type=int, default = 0) |
| | | is_little_endian = attr.ib(type=bool, default = True) |
| | | is_signed = attr.ib(type=bool, default = True) |
| | | offset = attr.ib(converter = float_factory, default = float_factory(0.0)) |
| | | factor = attr.ib(converter = float_factory, default = float_factory(1.0)) |
| | | size = attr.ib(type=int, default=0) |
| | | is_little_endian = attr.ib(type=bool, default=FALSE) |
| | | is_signed = attr.ib(type=bool, default=True) |
| | | offset = attr.ib(converter=float_factory, default=float_factory(0.0)) |
| | | factor = attr.ib(converter=float_factory, default=float_factory(1.0)) |
| | | |
| | | # offset = attr.ib(converter = float_factory, default = 0.0) |
| | | |
| | | min = attr.ib(converter=float_factory) |
| | | min = attr.ib(converter=float_factory) |
| | | |
| | | @min.default |
| | | def setDefaultMin(self): |
| | | return self.calcMin() |
| | | return self.calcMin() |
| | | |
| | | max = attr.ib(converter = float_factory) |
| | | max = attr.ib(converter=float_factory) |
| | | |
| | | @max.default |
| | | def setDefaultMax(self): |
| | | return self.calcMax() |
| | | return self.calcMax() |
| | | |
| | | unit = attr.ib(type=str, default ="") |
| | | receiver = attr.ib(default = attr.Factory(list)) |
| | | comment = attr.ib(default = None) |
| | | multiplex = attr.ib(default = None) |
| | | unit = attr.ib(type=str, default="") |
| | | receiver = attr.ib(default=attr.Factory(list)) |
| | | comment = attr.ib(default=None) |
| | | multiplex = attr.ib(default=None) |
| | | |
| | | mux_value = attr.ib(default = None) |
| | | mux_value = attr.ib(default=None) |
| | | is_float = attr.ib(type=bool, default=False) |
| | | enumeration = attr.ib(type=str, default = None) |
| | | comments = attr.ib(type=dict, default = attr.Factory(dict)) |
| | | attributes = attr.ib(type=dict, default = attr.Factory(dict)) |
| | | values = attr.ib(type=dict, converter=normalizeValueTable, default = attr.Factory(dict)) |
| | | calc_min_for_none = attr.ib(type=bool, default = True) |
| | | calc_max_for_none = attr.ib(type=bool, default = True) |
| | | muxValMax = attr.ib(default = 0) |
| | | muxValMin = attr.ib(default = 0) |
| | | muxerForSignal= attr.ib(type=str, default = None) |
| | | enumeration = attr.ib(type=str, default=None) |
| | | comments = attr.ib(type=dict, default=attr.Factory(dict)) |
| | | attributes = attr.ib(type=dict, default=attr.Factory(dict)) |
| | | values = attr.ib(type=dict, |
| | | converter=normalizeValueTable, |
| | | default=attr.Factory(dict)) |
| | | calc_min_for_none = attr.ib(type=bool, default=True) |
| | | calc_max_for_none = attr.ib(type=bool, default=True) |
| | | muxValMax = attr.ib(default=0) |
| | | muxValMin = attr.ib(default=0) |
| | | muxerForSignal = attr.ib(type=str, default=None) |
| | | |
| | | def __attrs_post_init__(self): |
| | | self.multiplex = self.multiplexSetter(self.multiplex) |
| | | |
| | | |
| | | @property |
| | | def spn(self): |
| | |
| | | startBitInternal = startBitInternal + self.size - 1 |
| | | # bit numbering not consistent with byte order. reverse |
| | | if bitNumbering is not None and bitNumbering != self.is_little_endian: |
| | | startBitInternal = startBitInternal - (startBitInternal % 8) + 7 - (startBitInternal % 8) |
| | | startBitInternal = startBitInternal - ( |
| | | startBitInternal % 8) + 7 - (startBitInternal % 8) |
| | | return int(startBitInternal) |
| | | |
| | | def calculateRawRange(self): |
| | |
| | | :return: Signal range, i.e. (0, 15) for unsigned 4 bit Signal or (-8, 7) for signed one. |
| | | :rtype: tuple |
| | | """ |
| | | rawRange = 2 ** (self.size - (1 if self.is_signed else 0)) |
| | | rawRange = 2**(self.size - (1 if self.is_signed else 0)) |
| | | return (self.float_factory(-rawRange if self.is_signed else 0), |
| | | self.float_factory(rawRange - 1)) |
| | | |
| | |
| | | value = value_key |
| | | break |
| | | else: |
| | | raise ValueError( |
| | | "{} is invalid value choice for {}".format(value, self) |
| | | ) |
| | | raise ValueError("{} is invalid value choice for {}".format( |
| | | value, self)) |
| | | |
| | | if not (self.min <= value <= self.max): |
| | | print( |
| | | "Value {} is not valid for {}. Min={} and Max={}".format( |
| | | value, self, self.min, self.max) |
| | | ) |
| | | print("Value {} is not valid for {}. Min={} and Max={}".format( |
| | | value, self, self.min, self.max)) |
| | | raw_value = (value - self.offset) / self.factor |
| | | |
| | | if not self.is_float: |
| | |
| | | def __str__(self): |
| | | return self.name |
| | | |
| | | |
| | | class DBC: |
| | | |
| | | def __init__(self, dbcfile=None): |
| | | self.filePath = dbcfile |
| | | self.frames = self.__load() |
| | |
| | | frameList = [] |
| | | i = 0 |
| | | frame = None |
| | | with open(self.filePath, mode='r', encoding='gb2312') as f: |
| | | with open(self.filePath, mode='r', encoding=dbcImportEncoding) as f: |
| | | for line in f.readlines(): |
| | | i = i + 1 |
| | | l = line.strip() |
| | |
| | | # logging.info(l) |
| | | if l.startswith('BO_ '): |
| | | # frames |
| | | regexp = re.compile("^BO\_ ([^\ ]+) ([^\ ]+) *: ([^\ ]+) ([^\ ]+)") |
| | | regexp = re.compile( |
| | | "^BO\_ ([^\ ]+) ([^\ ]+) *: ([^\ ]+) ([^\ ]+)") |
| | | temp = regexp.match(l) |
| | | # name, id, dlc, transmitters |
| | | frame = Frame( |
| | | temp.group(2), |
| | | id=int(temp.group(1)), |
| | | size=int(temp.group(3)), |
| | | transmitters=temp.group(4).split()) |
| | | frame = Frame(temp.group(2), |
| | | id=int(temp.group(1)), |
| | | size=int(temp.group(3)), |
| | | transmitters=temp.group(4).split()) |
| | | frameList.append(frame) |
| | | pass |
| | | elif l.startswith('SG_ '): |
| | |
| | | temp = regexp.match(l) |
| | | if temp: |
| | | extras = {} |
| | | receiver = list(map(str.strip, temp.group(11).split(','))) |
| | | tempSig = Signal( |
| | | temp.group(1), |
| | | startBit=int(temp.group(2)), |
| | | size=int(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.group(10), |
| | | receiver=receiver, |
| | | **extras |
| | | ) |
| | | receiver = list( |
| | | map(str.strip, |
| | | temp.group(11).split(','))) |
| | | tempSig = Signal(temp.group(1), |
| | | startBit=int(temp.group(2)), |
| | | size=int(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.group(10), |
| | | receiver=receiver, |
| | | **extras) |
| | | print(temp.group(4), temp.group(2)) |
| | | if not tempSig.is_little_endian: |
| | | # startbit of motorola coded signals are MSB in dbc |
| | | tempSig.setStartbit(int(temp.group(2)), bitNumbering=1) |
| | | tempSig.setStartbit(int(temp.group(2)), |
| | | bitNumbering=1) |
| | | frame.signals.append(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) |
| | | temp = regexp.match(l) |
| | | receiver = list(map(str.strip, temp.group(12).split(','))) |
| | | receiver = list( |
| | | map(str.strip, |
| | | temp.group(12).split(','))) |
| | | multiplex = temp.group(2) |
| | | |
| | | is_complex_multiplexed = False |
| | |
| | | try: |
| | | multiplex = int(multiplex[1:]) |
| | | except: |
| | | raise Exception('error decoding line',line) |
| | | raise Exception('error decoding line', line) |
| | | |
| | | extras = {} |
| | | |
| | | tempSig = Signal( |
| | | temp.group(1), |
| | | startBit=int(temp.group(3)), |
| | | size=int(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(11), |
| | | receiver=receiver, |
| | | multiplex=multiplex, |
| | | **extras |
| | | ) |
| | | tempSig = Signal(temp.group(1), |
| | | startBit=int(temp.group(3)), |
| | | size=int(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(11), |
| | | receiver=receiver, |
| | | multiplex=multiplex, |
| | | **extras) |
| | | |
| | | if is_complex_multiplexed: |
| | | tempSig.is_multiplexer = True |
| | |
| | | |
| | | if not tempSig.is_little_endian: |
| | | # startbit of motorola coded signals are MSB in dbc |
| | | tempSig.setStartbit(int(temp.group(3)), bitNumbering=1) |
| | | tempSig.setStartbit(int(temp.group(3)), |
| | | bitNumbering=1) |
| | | frame.addSignal(tempSig) |
| | | |
| | | if is_complex_multiplexed: |
| | |
| | | if testF.id == int(tmpId): |
| | | for signal in testF.signals: |
| | | if signal.name == signalName: |
| | | for i in range(math.floor(len(tempList) / 2)): |
| | | signal.values[tempList[i * 2].strip()] = tempList[i * 2 + 1].strip() |
| | | for i in range( |
| | | math.floor(len(tempList) / 2)): |
| | | signal.values[tempList[i * 2].strip( |
| | | )] = tempList[i * 2 + 1].strip() |
| | | break |
| | | break |
| | | elif l.startswith("VAL_TABLE_ "): |
| | |
| | | regexp = re.compile("^BA\_ +\"[A-Za-z0-9[\-_ .]+\" +(.+)") |
| | | tempba = regexp.match(l) |
| | | if tempba.group(1).strip().startswith("BO_ "): |
| | | regexp = re.compile(r"^BA_ +\"(.*)\" +BO_ +(\w+) +(.+);") |
| | | regexp = re.compile( |
| | | r"^BA_ +\"(.*)\" +BO_ +(\w+) +(.+);") |
| | | temp = regexp.match(l) |
| | | tempId = temp.group(2) |
| | | for testF in frameList: |
| | |
| | | tempCys = temp.group(3) |
| | | frame.cycle = int(tempCys) |
| | | elif l.startswith("SIG_GROUP_ "): |
| | | regexp = re.compile("^SIG\_GROUP\_ +(\w+) +(\w+) +(\w+) +\:(.*);") |
| | | regexp = re.compile( |
| | | "^SIG\_GROUP\_ +(\w+) +(\w+) +(\w+) +\:(.*);") |
| | | temp = regexp.match(l) |
| | | elif l.startswith("SIG_VALTYPE_ "): |
| | | regexp = re.compile("^SIG\_VALTYPE\_ +(\w+) +(\w+)\s*\:(.*);") |
| | | regexp = re.compile( |
| | | "^SIG\_VALTYPE\_ +(\w+) +(\w+)\s*\:(.*);") |
| | | temp = regexp.match(l) |
| | | elif l.startswith("BA_DEF_DEF_ "): |
| | | pattern = "^BA\_DEF\_DEF\_ +\"([A-Za-z0-9\-_\.]+)\" +(.+)\;" |
| | |
| | | pattern = "^EV_ +([A-Za-z0-9\-_]+) *\: +([0-9]+) +\[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] +\"(\w*)\" +([0-9.+\-eE]+) +([0-9.+\-eE]+) +([A-Za-z0-9\-_]+) +(.*);" |
| | | regexp = re.compile(pattern) |
| | | temp = regexp.match(l) |
| | | |
| | | |
| | | return frameList |
| | | |
| | | def __setFdType(self): |
| | |
| | | for frame in self.frames: |
| | | # if frame.size == 0: |
| | | frame.calcDLC() |
| | | print(frame.id, frame.size) |
| | | # print(frame.id, frame.size) |
| | | if frame.size > 8: |
| | | frame.is_fd = True |
| | | |
| | | |
| | | def __setExtended(self): |
| | | for frame in self.frames: |
| | | # extended-flag is implicite in canid, thus repair this: |
| | | # extended-flag is implicite in canid, thus repair this: |
| | | if frame.id > 0x80000000: |
| | | frame.id -= 0x80000000 |
| | | frame.extended = 1 |
| | |
| | | return test |
| | | return None |
| | | |
| | | def __getSignalVal(self, signal:Signal, data='00 01 02 03 04 05 06 07'): |
| | | def __getSignalVal(self, signal: Signal, data='00 01 02 03 04 05 06 07'): |
| | | dataList = data.strip().split(' ') |
| | | _startbit = signal.startBit |
| | | _bitsize = signal.size |
| | | _little = signal.is_little_endian # (1: Intel, 0: Motorola) |
| | | _byteSize = math.ceil((signal.size + _startbit%8)/8) |
| | | _startByte = math.floor(_startbit/8) |
| | | _little = 0 #signal.is_little_endian # (1: Intel, 0: Motorola) |
| | | _byteSize = math.ceil((signal.size + _startbit % 8) / 8) |
| | | _startByte = math.floor(_startbit / 8) |
| | | phyvalue = 0 |
| | | rawvalue = '' |
| | | base = int('{0:0>8}'.format('1'*_bitsize+'0'*(_startbit%8)), 2) |
| | | base = int('{0:0>8}'.format('1' * _bitsize + '0' * (_startbit % 8)), 2) |
| | | _byteNum = 0 |
| | | _byteList= [] |
| | | _byteList = [] |
| | | while _byteNum < _byteSize: |
| | | # tmpbase = (base >> (8*_byteNum)) & 0xff |
| | | _byteList.append(dataList[_startByte+_byteNum]) |
| | | _byteList.append(dataList[_startByte + _byteNum]) |
| | | _byteNum += 1 |
| | | if _little == 1: |
| | | _byteList.reverse() |
| | | for _byte in _byteList: |
| | | rawvalue += _byte |
| | | rawvalue = ((int(rawvalue,16) & base) >> (_startbit%8)) |
| | | rawvalue = ((int(rawvalue, 16) & base) >> (_startbit % 8)) |
| | | return {"phy": signal.raw2phys(rawvalue), "raw": rawvalue} |
| | | # print(_startByte, _byteSize, _bitsize, int(dataList[_startByte], 16), int('{0:0>8}'.format('1'*_bitsize+'0'*(_startbit%8)), 2)) |
| | | |
| | | |
| | | def analyzer(self, msgid=None, data='00 01 02 03 04 05 06 07'): |
| | | '''analysis given data |
| | | |
| | | '''analysis given data |
| | | |
| | | Keyword Arguments: |
| | | msgid {int} -- msg id (base 10) (default: {None}) |
| | | data {str} -- given data (default: {'00 01 02 03 04 05 06 07'}) |
| | | |
| | | |
| | | Returns: |
| | | dict -- key sorted by signal index |
| | | ''' |
| | |
| | | break |
| | | return ret |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | testDbc = DBC("data/SX7H.dbc") |
| | | abc=testDbc.analyzer(msgid=1056, data='40 01 C8 00 FF 00 00 00') |
| | | print(abc) |
| | | testDbc = DBC("DBC/DFLZM.dbc") |
| | | abc = testDbc.analyzer(msgid=1056, data='00 0A 30 C0 00 00 00 00') |
| | | print(abc) |
| | | print(abc[5]["name"], abc[5]["value"]['raw']) |
| | | print(abc[7]["name"], abc[7]["value"]['raw']) |
| | | print(abc[4]["name"], abc[4]["value"]['raw']) |