From 698b17133dd304fe293f495aa3b96c4274ccdd50 Mon Sep 17 00:00:00 2001 From: tao_z <tzj0429@163.com> Date: Wed, 22 Jun 2022 23:03:00 +0800 Subject: [PATCH] 新增换挡逻辑功能 --- widgets/ShifterTool.py | 52 ++ Shifter.py | 136 ++++++- /dev/null | 641 ----------------------------------- test.py | 32 + .qt_for_python/uic/main.py | 2 USBCAN.py | 2 DBC/DFLZM.dbc | 16 DBC/SX7H.dbc | 21 ShifterDefine.py | 136 ++++++ main.ui | 2 styleSheet.py | 4 11 files changed, 351 insertions(+), 693 deletions(-) diff --git a/.qt_for_python/uic/main.py b/.qt_for_python/uic/main.py index 42eb70c..846f6cc 100644 --- a/.qt_for_python/uic/main.py +++ b/.qt_for_python/uic/main.py @@ -1278,7 +1278,7 @@ self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(1) + self.tabWidget.setCurrentIndex(2) self.tabWidget_2.setCurrentIndex(0) diff --git a/DBC/DFLZM.dbc b/DBC/DFLZM.dbc index 1f4873b..4c7c4ae 100644 --- a/DBC/DFLZM.dbc +++ b/DBC/DFLZM.dbc @@ -189,22 +189,22 @@ BA_ "GenMsgCycleTime" BO_ 329 10; BA_ "GenMsgCycleTime" BO_ 534 10; BA_ "GenMsgCycleTime" BO_ 530 10; -BA_ "GenMsgDelayTime" BO_ 1056 20; -BA_ "GenMsgNrOfRepetition" BO_ 1056 3; -BA_ "GenMsgCycleTimeFast" BO_ 1056 20; BA_ "GenMsgCycleTime" BO_ 1056 100; +BA_ "GenMsgCycleTimeFast" BO_ 1056 20; +BA_ "GenMsgNrOfRepetition" BO_ 1056 3; +BA_ "GenMsgDelayTime" BO_ 1056 20; BA_ "GenMsgCycleTime" BO_ 16 10; BA_ "GenMsgCycleTime" BO_ 512 20; -BA_ "GenMsgSendType" BO_ 1858 8; BA_ "GenMsgCycleTime" BO_ 1858 0; -BA_ "GenMsgILSupport" BO_ 1914 1; -BA_ "GenMsgSendType" BO_ 1914 1; +BA_ "GenMsgSendType" BO_ 1858 8; BA_ "GenMsgCycleTime" BO_ 1914 0; -BA_ "GenMsgSendType" BO_ 2015 8; +BA_ "GenMsgSendType" BO_ 1914 1; +BA_ "GenMsgILSupport" BO_ 1914 1; BA_ "GenMsgCycleTime" BO_ 2015 0; +BA_ "GenMsgSendType" BO_ 2015 8; BA_ "GenSigStartValue" SG_ 530 brake_pedal_status 3; -BA_ "GenSigStartValue" SG_ 1056 SA1_Status_GearShftPosReq 15; BA_ "GenSigSendType" SG_ 1056 SA1_Status_GearShftPosReq 4; +BA_ "GenSigStartValue" SG_ 1056 SA1_Status_GearShftPosReq 15; BA_ "GenSigStartValue" SG_ 1056 SA1_Status_PRNDL 7; BA_ "GenSigStartValue" SG_ 16 ShiftLeverPos 7; BA_ "GenSigStartValue" SG_ 16 ActualGear 15; diff --git a/DBC/SX7H.dbc b/DBC/SX7H.dbc index b2931bd..fcf5d31 100644 --- a/DBC/SX7H.dbc +++ b/DBC/SX7H.dbc @@ -52,28 +52,30 @@ VAL_TABLE_ Shifter_Lever_Signals_VT 15 "Invalid" 11 "Z4(Between D and L)" 10 "Z3(Between N and D)" 9 "Z2(Between R and N)" 8 "Z1(Between P and R)" 7 "P" 6 "R" 5 "N" 4 "D" 3 "Sport mode,display PWR on IC" 0 "Unkown" ; -BO_ 534 CVT1: 1 Vector__XXX +BO_ 3221225472 VECTOR__INDEPENDENT_SIG_MSG: 0 Vector__XXX + SG_ Angle2 : 0|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ Angle1 : 0|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ Calibartion : 0|8@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 534 CVT1: 8 Vector__XXX SG_ Shifter_Lever_Signals : 63|8@0+ (1,0) [0|0] "" Vector__XXX -BO_ 329 IC1: 3 Vector__XXX +BO_ 329 IC1: 8 Vector__XXX SG_ odometer_value : 47|24@0+ (1,0) [0|0] "" Vector__XXX -BO_ 530 Engine2: 1 Vector__XXX +BO_ 530 Engine2: 8 Vector__XXX SG_ brake_pedal_status : 57|2@0+ (1,0) [0|0] "" Vector__XXX BO_ 512 ABS1: 3 Vector__XXX SG_ vehicle_speed : 15|13@0+ (0.05625,0) [0|0] "" Vector__XXX -BO_ 16 TCU2: 3 Vector__XXX - SG_ Calibartion : 23|8@0+ (1,0) [0|0] "" Vector__XXX +BO_ 16 TCU2: 2 Vector__XXX SG_ ActualGear : 11|4@1+ (1,0) [0|0] "" Vector__XXX SG_ TCUDrivingMode : 10|3@0+ (1,0) [0|0] "" Vector__XXX SG_ ShiftLeverPos : 2|3@0+ (1,0) [0|0] "" Vector__XXX BO_ 1056 SA1: 8 Vector__XXX - SG_ Angle2 : 55|16@0+ (1,0) [0|0] "" Vector__XXX - SG_ Angle1 : 39|16@0+ (1,0) [0|0] "" Vector__XXX - SG_ SA1_Status_ShiftPosValidFlag : 27|1@0+ (1,0) [0|0] "" Vector__XXX + SG_ SA1_Status_ShiftPosValidFlag : 32|1@0+ (1,0) [0|0] "" Vector__XXX SG_ SA1_Status_RqGearPosInV : 31|4@0+ (1,0) [0|0] "" Vector__XXX SG_ SA1_Status_GearShftPosReq : 23|4@0+ (1,0) [0|0] "" Vector__XXX SG_ SA1_Status_ParkButtonReq : 19|2@0+ (1,0) [0|0] "" Vector__XXX @@ -88,11 +90,12 @@ +CM_ BO_ 3221225472 "This is a message for not used signals, created by Vector CANdb++ DBC OLE DB Provider."; BA_DEF_ "BusType" STRING ; BA_DEF_DEF_ "BusType" "CAN"; +VAL_ 3221225472 Calibartion 10 "Finish" 9 "CAL_GAP" 8 "CAL_Y2" 7 "CAL_Y1" 6 "CAL_X1" 5 "CAL_X2" 4 "CAL_MN" 3 "CAL_MP" 2 "CAL_M" 1 "CAL_Z" 0 "start" ; VAL_ 534 Shifter_Lever_Signals 15 "Invalid" 11 "Z4(Between D and L)" 10 "Z3(Between N and D)" 9 "Z2(Between R and N)" 8 "Z1(Between P and R)" 7 "P" 6 "R" 5 "N" 4 "D" 3 "Sport mode,display PWR on IC" 0 "Unkown" ; VAL_ 530 brake_pedal_status 3 "Invalid" 2 "Not specified" 1 "Brake actuated" 0 "Brake not actuated" ; -VAL_ 16 Calibartion 10 "Finish" 9 "CAL_GAP" 8 "CAL_Y2" 7 "CAL_Y1" 6 "CAL_X1" 5 "CAL_X2" 4 "CAL_MN" 3 "CAL_MP" 2 "CAL_M" 1 "CAL_Z" 0 "start" ; VAL_ 16 ActualGear 15 "Invalid" 14 "Reserved" 13 "Current_gear_P" 12 "Reserved" 11 "Current_gear_R" 10 "Reserved" 9 "Reserved" 8 "Reserved" 7 "Current_gear_7" 6 "Current_gear_6" 5 "Current_gear_5" 4 "Current_gear_4" 3 "Current_gear_3" 2 "Current_gear_2" 1 "Current_gear_1" 0 "Current_gear_N" ; VAL_ 16 TCUDrivingMode 7 "Invalid" 6 "Reserved" 5 "Reserved" 4 "Sport" 3 "Reserved" 2 "Manual" 1 "Snow Mode" 0 "Standard" ; VAL_ 16 ShiftLeverPos 7 "Invalid" 6 "M-" 5 "M+" 4 "M" 3 "R" 2 "N" 1 "D" 0 "P" ; diff --git a/Shifter.py b/Shifter.py index 56dbb40..d637499 100644 --- a/Shifter.py +++ b/Shifter.py @@ -1,9 +1,12 @@ +from email.message import Message from ShifterDefine import * import struct from udsoncan import DidCodec import configparser -from dbc import * +import cantools + +ProjectDBC = cantools.database.load_file("DBC/SX7H.dbc") class AsciiCodec(DidCodec): @@ -138,9 +141,9 @@ class ShifterClass(): def __init__(self): - self.position = ShifterPosition(0) - self.Pbutton = 0 - self.UnlockButton = 0 + self.position = None + self.Pbutton = None + self.UnlockButton = None self.Voltage = 0 self.canid = ShifterCANID() @@ -191,20 +194,115 @@ self.canid.phy_rxId = 0x742 self.canid.fun_rxId = 0x7df self.canid.normalid = 0x420 - self.dbc = DBC("DBC/DFLZM.dbc") + self.SA1_message = ProjectDBC.get_message_by_name('SA1') def FramUnpack(self, id=0x420, frame=[]): - data = [] - data.append(' '.join( - ['{:0>2x}'.format(a).upper() for a in list(frame)])) - # print(data) - unpackframe = self.dbc.analyzer(msgid=0x420, data=str(data[0])) - # print(unpackframe[5]['value']['raw']) - self.Pbutton = unpackframe[5]['value']['raw'] - print(unpackframe[5]["name"], unpackframe[5]['value']['raw']) - # print(unpackframe[6]['value']['raw']) - self.UnlockButton = unpackframe[4]['value']['raw'] - print(unpackframe[4]["name"], unpackframe[4]['value']['raw']) - # print(unpackframe[4]['value']['raw']) - self.position = unpackframe[7]['value']['raw'] - print(unpackframe[7]["name"], unpackframe[7]['value']['raw']) + input_signal = ProjectDBC.decode_message(id, frame) + # part_str = str(input_signal['SA1_Status_ParkButtonReq']) + # print(type(part_str)) + # if input_signal['SA1_Status_ParkButtonReq'] == 'No request': + # print('yes') + # print(SA1_Status_ParkButtonReq_dic[part_str]) + self.Pbutton = SA1_Status_ParkButtonReq_dic[str( + input_signal['SA1_Status_ParkButtonReq'])] + self.UnlockButton = SA1_Status_UnlockButtonReq_dic[str( + input_signal['SA1_Status_UnlockButtonReq'])] + self.position = SA1_Status_GearShftPosReq_dic[str( + input_signal['SA1_Status_GearShftPosReq'])] + + def PackFrame(self, dic): + data = self.SA1_message.encode({ + 'SA1_Status_PRNDL': + 0, + 'SA1_Status_GearShftPosReq': + SA1_Status_GearShftPosReq_dic[self.position], + 'SA1_Status_ParkButtonReq': + SA1_Status_ParkButtonReq_dic[self.Pbutton], + "SA1_ShifterManualSignal": + 0, + "SA1_ShifterModeSignal": + 0, + "SA1_Status_ShftSensSng_Fault": + 0, + "SA1_IND_ShifterMisUsd": + 0, + "SA1_Live_counter": + 1, + "SA1_Status_UnlockButtonReq": + SA1_Status_UnlockButtonReq_dic[self.UnlockButton], + "SA1_Status_EcoShifterModeReq": + 0, + "SA1_Status_RqGearPosInV": + 0xf, + "SA1_Status_ShiftPosValidFlag": + 0, + }) + return data + + +class VehicleClass(): + + def __init__(self): + self.Odm = 0 + self.speed = 0 + self.brake = 0 + self.ShiftLeverPos = 'P' + self.pre_ShiftLeverPos = 'P' + self.max_pos = 'Shifter position Zero' + self.IC1_message = ProjectDBC.get_message_by_name('IC1') + self.TCU2_message = ProjectDBC.get_message_by_name('TCU2') + self.ABS1_message = ProjectDBC.get_message_by_name('ABS1') + self.Engine2_message = ProjectDBC.get_message_by_name('Engine2') + + def pack_IC1(self, odm): + self.Odm = odm + data = self.IC1_message.encode({"odometer_value": odm}) + return data + + def pack_TCU2(self, shiftpos): + #from value get key + self.ShiftLeverPos = [ + k for k, v in TCU2_ShiterLevel_dic.items() if v == shiftpos + ][0] + data = self.TCU2_message.encode({ + "ShiftLeverPos": shiftpos, + "TCUDrivingMode": 0, + "ActualGear": 0 + }) + return data + + def pack_ABS1(self, speed): + self.speed = speed + data = self.ABS1_message.encode({"vehicle_speed": speed}) + return data + + def pack_Engine2(self, brake): + self.brake = brake + data = self.Engine2_message.encode({"brake_pedal_status ": brake}) + return data + + def ShiftLogic(self, shift: ShifterClass): + reqpos = 0 + if shift.Pbutton == SA1_Status_ParkButtonReq_dic[ + 'Driver request park button']: + reqpos = TCU2_ShiterLevel_dic['P'] + self.pre_ShiftLeverPos = "P" + self.max_pos = 'Shifter position Zero' + elif (shift.position >= SA1_Status_GearShftPosReq_dic['M-']) and ( + shift.position <= SA1_Status_GearShftPosReq_dic['M']): + reqpos = TCU2_ShiterLevel_dic['M'] + self.pre_ShiftLeverPos = "P" + self.max_pos = 'Shifter position Zero' + else: + if shift.position is not SA1_Status_GearShftPosReq_dic[ + 'Shifter position Zero']: + self.max_pos = ShiftMaxPosMap_dic[self.max_pos][shift.position] + reqpos = GearShiftMap_dic[self.pre_ShiftLeverPos][self.max_pos] + else: + reqpos = GearShiftMap_dic[self.pre_ShiftLeverPos][self.max_pos] + self.max_pos = 'Shifter position Zero' + self.pre_ShiftLeverPos = [ + k for k, v in TCU2_ShiterLevel_dic.items() if v == reqpos + ][0] + data = self.pack_TCU2(reqpos) + return data diff --git a/ShifterDefine.py b/ShifterDefine.py index b89e25e..b279f6d 100644 --- a/ShifterDefine.py +++ b/ShifterDefine.py @@ -80,18 +80,43 @@ self.fun_rxId = 0 -class ShifterPosition(IntEnum): - ShiftPosZero = 0 - ShiftPosX2 = 2 - ShiftPosX1 = 3 - ShiftPosY1 = 4 - ShiftPosY2 = 5 - ShiftPosNotInit = 8 - ShiftPosM_Minus = 0xc - ShiftPosM_Plus = 0xd - ShiftPosM = 0xe - ShiftNotAvailable = 0xF +# class ShifterPosition(IntEnum): +# ShiftPosZero = 0 +# ShiftPosX2 = 2 +# ShiftPosX1 = 3 +# ShiftPosY1 = 4 +# ShiftPosY2 = 5 +# ShiftPosNotInit = 8 +# ShiftPosM_Minus = 0xc +# ShiftPosM_Plus = 0xd +# ShiftPosM = 0xe +# ShiftNotAvailable = 0xF +SA1_Status_ParkButtonReq_dic = { + 'No request': 0x0, + 'Driver request park button': 1, + 'Park Button fault': 2, + 'Reserved': 3 +} +SA1_Status_UnlockButtonReq_dic = { + 'No request': 0, + 'Driver request unlock button': 1 +} +SA1_Status_GearShftPosReq_dic = { + 'Shifter position Zero': 0x0, + 'Reserved1': 0x1, + 'X2 forward twice': 0x2, + 'X1 forward once': 0x3, + 'Y1 backward once': 0x4, + 'Y2 backward twice': 0x5, + 'Reserved6': 0x6, + 'Reserved7': 0x7, + 'Shifter not initialized': 0x8, + 'M-': 0xC, + 'M+': 0xD, + 'M': 0xE, + 'Signal not available': 0xF +} DID_dic = { "ProgrammingCounter": 0x2100, @@ -126,3 +151,92 @@ "ReadFingerPrint": 0xf15b, "IndicationLEDControl": 0x8101 } + +TCU2_ShiterLevel_dic = { + 'P': 0x0, + 'D': 0x1, + 'N': 0x2, + 'R': 0x3, + 'M': 0x4, + 'M+': 0x5, + 'M-': 0x6, + "Invalid": 7 +} + +GearShiftMap_dic = { + "P": { + 'X2 forward twice': 0x3, + 'X1 forward once': 2, + 'Shifter position Zero': 0x0, + 'Y1 backward once': 0x2, + 'Y2 backward twice': 1 + }, + "R": { + 'X2 forward twice': 0x3, + 'X1 forward once': 3, + 'Shifter position Zero': 0x3, + 'Y1 backward once': 0x2, + 'Y2 backward twice': 1 + }, + "N": { + 'X2 forward twice': 0x3, + 'X1 forward once': 3, + 'Shifter position Zero': 2, + 'Y1 backward once': 1, + 'Y2 backward twice': 1 + }, + "D": { + 'X2 forward twice': 0x3, + 'X1 forward once': 2, + 'Shifter position Zero': 1, + 'Y1 backward once': 1, + 'Y2 backward twice': 1 + } +} +# 'X2 forward twice': 0x2, +# 'X1 forward once': 0x3, +# 'Y1 backward once': 0x4, +# 'Y2 backward twice': 0x5, +ShiftMaxPosMap_dic = { + 'Shifter position Zero': { + 0: 'Shifter position Zero', + 2: 'X2 forward twice', + 3: 'X1 forward once', + 4: 'Y1 backward once', + 5: 'Y2 backward twice' + }, + 'X1 forward once': { + 0: 'X1 forward once', + 2: 'X2 forward twice', + 3: 'X1 forward once', + 4: 'Y1 backward once', + 5: 'Y2 backward twice' + }, + 'X2 forward twice': { + 0: 'X2 forward twice', + 2: 'X2 forward twice', + 3: 'X2 forward twice', + 4: 'Y1 backward once', + 5: 'Y2 backward twice' + }, + 'Y1 backward once': { + 0: 'Y1 backward once', + 2: 'X2 forward twice', + 3: 'X1 forward once', + 4: 'Y1 backward once', + 5: 'Y2 backward twice' + }, + 'Y2 backward twice': { + 0: 'Y2 backward twice', + 2: 'X2 forward twice', + 3: 'X1 forward once', + 4: 'Y2 backward twice', + 5: 'Y2 backward twice' + } +} + +# {GearDisplay_R, GearDisplay_R, GearDisplay_R, GearDisplay_R}, +# {GearDisplay_N, GearDisplay_R, GearDisplay_R, GearDisplay_N}, +# {GearDisplay_P, GearDisplay_R, GearDisplay_N, GearDisplay_D}, +# {GearDisplay_N, GearDisplay_N, GearDisplay_D, GearDisplay_D}, +# {GearDisplay_D, GearDisplay_D, GearDisplay_D, GearDisplay_D} diff --git a/USBCAN.py b/USBCAN.py index 751c3e0..59fd8c6 100644 --- a/USBCAN.py +++ b/USBCAN.py @@ -407,7 +407,7 @@ raw_message.TimeStamp = (c_uint)(0) raw_message.TimeFlag = (c_ubyte)(0) raw_message.SendType = (c_ubyte)(1) - raw_message.RemoteFlag = (c_ubyte)(msg.is_remote_frame) + raw_message.RemoteFlag = False raw_message.ExternFlag = (c_ubyte)(msg.is_extended_id) raw_message.DataLen = (c_ubyte)(msg.dlc) raw_message.Data = (c_ubyte * 8)(*[c_ubyte(c) for c in msg.data]) diff --git a/dbc.py b/dbc.py deleted file mode 100644 index d6e0f02..0000000 --- a/dbc.py +++ /dev/null @@ -1,641 +0,0 @@ -# reference: https://github.com/ebroecker/canmatrix - -# this script translates dbc-files to list data -from pickle import FALSE -import sys -import os -import logging -import re -import attr -import math -import decimal - -defaultFloatFactory = decimal.Decimal -dbcImportEncoding = 'iso-8859-1' - -logging.basicConfig( - level=logging.DEBUG, - format= - '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') - -MOTOROLA = 0 -INTERL = 1 -UNSIGNED = 0 -SIGNED = 1 - - -def normalizeValueTable(table): - return {int(k): v for k, v in table.items()} - - -@attr.s(cmp=False) -class Frame: - """ - Contains one CAN Frame. - The Frame has following mandatory attributes - * id, - * name, - * transmitters (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 - and any *custom* attributes in `attributes` dict. - Frame signals can be accessed using the iterator. - """ - - name = attr.ib(default="") - id = attr.ib(type=int, default=0) - size = attr.ib(default=0) - transmitters = attr.ib(default=attr.Factory(list)) - extended = attr.ib(type=bool, default=False) - is_complex_multiplexed = attr.ib(type=bool, default=False) - is_fd = attr.ib(type=bool, default=False) - comment = attr.ib(default="") - signals = attr.ib(default=attr.Factory(list)) - mux_names = attr.ib(type=dict, default=attr.Factory(dict)) - attributes = attr.ib(type=dict, default=attr.Factory(dict)) - receiver = attr.ib(default=attr.Factory(list)) - signalGroups = attr.ib(default=attr.Factory(list)) - cycle = attr.ib(type=int, default=0) - - j1939_pgn = attr.ib(default=None) - j1939_source = attr.ib(default=0) - j1939_prio = attr.ib(default=0) - is_j1939 = attr.ib(type=bool, default=False) - - def calcDLC(self): - """ - Compute minimal Frame DLC (length) based on its Signals - :return: Message DLC - """ - maxBit = 0 - for sig in self.signals: - 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). - If not, the Frame type stays unchanged. - """ - for frame in self.frames: - if frame.size > 8: - frame.is_fd = True - - 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.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): - if bitfield[i * 8 + j] == 0: - bitfield[i * 8 + j] = bitfieldBe[i * 8 + j] - - return bitfield - - def addSignal(self, signal): - """ - Add Signal to Frame. - :param Signal signal: Signal to be added. - :return: the signal added. - """ - self.signals.append(signal) - return self.signals[len(self.signals) - 1] - - -@attr.s(cmp=False) -class Signal(object): - """ - Represents a Signal in CAN Matrix. - Signal has following attributes: - * name - * startBit, size (in Bits) - * is_little_endian (1: Intel, 0: Motorola) - * is_signed (bool) - * factor, offset, min, max - * receiver (Boarunit/ECU-Name) - * attributes, _values, unit, comment - * _multiplex ('Multiplexor' or Number of Multiplex) - """ - - 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=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.default - def setDefaultMin(self): - return self.calcMin() - - max = attr.ib(converter=float_factory) - - @max.default - def setDefaultMax(self): - 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) - - 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) - - def __attrs_post_init__(self): - self.multiplex = self.multiplexSetter(self.multiplex) - - @property - def spn(self): - """Get signal J1939 SPN or None if not defined.""" - return self.attributes.get("SPN", None) - - def multiplexSetter(self, value): - self.mux_val = None - self.is_multiplexer = False - if value is not None and value != 'Multiplexor': - ret_multiplex = int(value) - self.mux_val = int(value) - else: # is it valid for None too? - self.is_multiplexer = True - ret_multiplex = value - return ret_multiplex - - def attribute(self, attributeName, db=None, default=None): - """Get any Signal attribute by its name. - :param str attributeName: attribute name, can be mandatory (ex: startBit, size) or optional (customer) attribute. - :param CanMatrix db: Optional database parameter to get global default attribute value. - :param default: Default value if attribute doesn't exist. - :return: Return the attribute value if found, else `default` or None - """ - if attributeName in attr.fields_dict(type(self)): - return getattr(self, attributeName) - if attributeName in self.attributes: - return self.attributes[attributeName] - if db is not None: - if attributeName in db.signalDefines: - define = db.signalDefines[attributeName] - return define.defaultValue - return default - - 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.size - 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): - """Get signal start bit. Handle byte and bit order.""" - startBitInternal = 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: - 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) - return int(startBitInternal) - - def calculateRawRange(self): - """Compute raw signal range based on Signal bit width and whether the Signal is signed or not. - :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)) - return (self.float_factory(-rawRange if self.is_signed else 0), - self.float_factory(rawRange - 1)) - - def calcMin(self): - """Compute minimal physical Signal value based on offset and factor and `calculateRawRange`.""" - rawMin = self.calculateRawRange()[0] - - return self.offset + (rawMin * self.factor) - - def calcMax(self): - """Compute maximal physical Signal value based on offset, factor and `calculateRawRange`.""" - rawMax = self.calculateRawRange()[1] - - return self.offset + (rawMax * self.factor) - - def bitstruct_format(self): - """Get the bit struct format for this signal. - :return: bitstruct representation of the Signal - :rtype: str - """ - endian = '<' if self.is_little_endian else '>' - if self.is_float: - bit_type = 'f' - else: - bit_type = 's' if self.is_signed else 'u' - - return endian + bit_type + str(self.size) - - def phys2raw(self, value=None): - """Return the raw value (= as is on CAN). - :param value: (scaled) value or value choice to encode - :return: raw unscaled value as it appears on the bus - """ - if value is None: - return int(self.attributes.get('GenSigStartValue', 0)) - - if isinstance(value, str): - for value_key, value_string in self.values.items(): - if value_string == value: - value = value_key - break - else: - 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)) - raw_value = (value - self.offset) / self.factor - - if not self.is_float: - raw_value = int(raw_value) - return raw_value - - def raw2phys(self, value, decodeToStr=False): - """Decode the given raw value (= as is on CAN) - :param value: raw value - :param bool decodeToStr: If True, try to get value representation as *string* ('Init' etc.) - :return: physical value (scaled) - """ - - value = value * self.factor + self.offset - if decodeToStr: - for value_key, value_string in self.values.items(): - if value_key == value: - value = value_string - break - - return value - - def __str__(self): - return self.name - - -class DBC: - - def __init__(self, dbcfile=None): - self.filePath = dbcfile - self.frames = self.__load() - self.__setFdType() - self.__setExtended() - - def __load(self): - frameList = [] - i = 0 - frame = None - with open(self.filePath, mode='r', encoding=dbcImportEncoding) as f: - for line in f.readlines(): - i = i + 1 - l = line.strip() - if len(l) == 0: - continue - # logging.info(l) - if l.startswith('BO_ '): - # frames - 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()) - frameList.append(frame) - pass - elif l.startswith('SG_ '): - # signals - 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(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) - 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) - 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(','))) - multiplex = temp.group(2) - - is_complex_multiplexed = False - - if multiplex == 'M': - multiplex = 'Multiplexor' - elif multiplex.endswith('M'): - is_complex_multiplexed = True - multiplex = multiplex[:-1] - - if multiplex != 'Multiplexor': - try: - multiplex = int(multiplex[1:]) - except: - 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) - - if is_complex_multiplexed: - tempSig.is_multiplexer = True - tempSig.multiplex = 'Multiplexor' - - if not tempSig.is_little_endian: - # startbit of motorola coded signals are MSB in dbc - tempSig.setStartbit(int(temp.group(3)), - bitNumbering=1) - frame.addSignal(tempSig) - - if is_complex_multiplexed: - frame.is_complex_multiplexed = True - elif l.startswith("BO_TX_BU_ "): - regexp = re.compile("^BO_TX_BU_ ([0-9]+) *: *(.+);") - temp = regexp.match(l) - elif l.startswith("CM_ SG_ "): - pass - elif l.startswith("CM_ BO_ "): - pattern = "^CM\_ +BO\_ +(\w+) +\"(.*)\";" - regexp = re.compile(pattern) - elif l.startswith("CM_ BU_ "): - pattern = "^CM\_ +BU\_ +(\w+) +\"(.*)\";" - regexp = re.compile(pattern) - elif l.startswith("BU_:"): - pattern = "^BU\_\:(.*)" - regexp = re.compile(pattern) - elif l.startswith("VAL_ "): - regexp = re.compile("^VAL\_ +(\w+) +(\w+) +(.*);") - temp = regexp.match(l) - tmpId = temp.group(1) - signalName = temp.group(2) - tempList = temp.group(3).split('"') - for testF in frameList: - 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() - break - break - elif l.startswith("VAL_TABLE_ "): - regexp = re.compile("^VAL\_TABLE\_ +(\w+) +(.*);") - temp = regexp.match(l) - elif l.startswith("BA_DEF_ SG_ "): - pattern = "^BA\_DEF\_ +SG\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" - regexp = re.compile(pattern) - elif l.startswith("BA_DEF_ BO_ "): - pattern = "^BA\_DEF\_ +BO\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" - regexp = re.compile(pattern) - elif l.startswith("BA_DEF_ BU_ "): - pattern = "^BA\_DEF\_ +BU\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" - regexp = re.compile(pattern) - elif l.startswith("BA_DEF_ "): - pattern = "^BA\_DEF\_ +\"([A-Za-z0-9\-_]+)\" +(.+);" - regexp = re.compile(pattern) - elif l.startswith("BA_ "): - 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+) +(.+);") - temp = regexp.match(l) - tempId = temp.group(2) - for testF in frameList: - if testF.id == int(tempId): - frame = testF - if temp.group(0).find('GenMsgCycleTime') > -1: - tempCys = temp.group(3) - frame.cycle = int(tempCys) - elif l.startswith("SIG_GROUP_ "): - 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*\:(.*);") - temp = regexp.match(l) - elif l.startswith("BA_DEF_DEF_ "): - pattern = "^BA\_DEF\_DEF\_ +\"([A-Za-z0-9\-_\.]+)\" +(.+)\;" - regexp = re.compile(pattern) - elif l.startswith("SG_MUL_VAL_ "): - pattern = "^SG\_MUL\_VAL\_ +([0-9]+) +([A-Za-z0-9\-_]+) +([A-Za-z0-9\-_]+) +([0-9]+)\-([0-9]+) *;" - regexp = re.compile(pattern) - elif l.startswith("EV_ "): - 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): - """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). - If not, the Frame type stays unchanged. - """ - for frame in self.frames: - # if frame.size == 0: - frame.calcDLC() - # 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: - if frame.id > 0x80000000: - frame.id -= 0x80000000 - frame.extended = 1 - - def frameById(self, Id, extended=None): - """Get Frame by its arbitration id. - :param Id: Frame id as str or int - :param extended: is it an extended id? None means "doesn't matter" - :rtype: Frame or None - """ - Id = int(Id) - extendedMarker = 0x80000000 - for test in self.frames: - if test.id == Id: - if extended is None: - # found ID while ignoring extended or standard - return test - elif test.extended == extended: - # found ID while checking extended or standard - return test - else: - if extended is not None: - # what to do if Id is not equal and extended is also provided ??? - pass - else: - if test.extended and Id & extendedMarker: - # check regarding common used extended Bit 31 - if test.id == Id - extendedMarker: - return test - return None - - 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 = 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) - _byteNum = 0 - _byteList = [] - while _byteNum < _byteSize: - # tmpbase = (base >> (8*_byteNum)) & 0xff - _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)) - 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 - - 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 - ''' - - ret = {} - if len(data.strip().split(' ')) != 8 or msgid is None: - logging.error('wrong data len') - return ret - for frame in self.frames: - if frame.id == int(msgid): - for i in range(len(frame.signals)): - signal = frame.signals[i] - ret[i] = {} - ret[i]['name'] = signal.name - ret[i]['unit'] = signal.unit - ret[i]['value'] = self.__getSignalVal(signal, data) - break - return ret - - -if __name__ == '__main__': - 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']) diff --git a/main.ui b/main.ui index 72cee84..de8e34a 100644 --- a/main.ui +++ b/main.ui @@ -194,7 +194,7 @@ <string notr="true"/> </property> <property name="currentIndex"> - <number>1</number> + <number>2</number> </property> <widget class="QWidget" name="tab"> <attribute name="title"> diff --git a/styleSheet.py b/styleSheet.py index 541cb16..71fdf60 100644 --- a/styleSheet.py +++ b/styleSheet.py @@ -2,8 +2,12 @@ FunctionButton_activeStyle = "background-color: rgb(0, 255, 0);\n" + "color: rgb(255,255,255); \n" + "border-radius: 30px; \n" + "font: 9pt \"AcadEref\";\n" + "border-style: outset;" FunctionButton_faultStyle = "background-color: rgb(255,0, 0);\n" + "color: rgb(255,255,255); \n" + "border-radius: 30px; \n" + "font: 9pt \"AcadEref\";\n" + "border-style: outset;" +Color_activeStyle = "background-color: rgb(0, 255, 0);\n" +Color_defaultStyle = "background-color: rgb(123, 123, 123);\n" Style_dic = { 0: FunctionButton_defaultStyle, 1: FunctionButton_activeStyle, 2: FunctionButton_faultStyle } + +ColorStyle_dic = {0: Color_defaultStyle, 1: Color_activeStyle} diff --git a/test.py b/test.py index 43ca161..584fe6b 100644 --- a/test.py +++ b/test.py @@ -2,6 +2,7 @@ # # meg = Message() # # msg = VCI_CAN_OBJ() from ast import arg +import encodings import threading from tkinter.tix import Tree from USBCAN import * @@ -11,6 +12,8 @@ from multiprocessing import Process, Queue, Value, Pipe import datetime from ShifterDefine import * +import cantools +from pprint import pprint # def rece_msg(bus): # msg = bus.Receive(0.1) # if msg[0] is not None: @@ -213,3 +216,32 @@ # # w.show() # sys.exit(app.exec_()) + +dbc = cantools.database.load_file("DBC/SX7H.dbc") +# print(dbc.messages) +sa_message = dbc.get_message_by_name('SA1') +# print(sa_message) +# pprint(sa_message.signals) +frame = [0x00, 0x0A, 0x00, 0xF0, 0, 0, 0, 0] +input_signal = dbc.decode_message(0x420, frame) +part_str = str(input_signal['SA1_Status_ParkButtonReq']) +pprint(part_str) +if input_signal['SA1_Status_ParkButtonReq'] == 'No request': + print('yes') + +data = sa_message.encode({ + 'SA1_Status_PRNDL': 0, + 'SA1_Status_GearShftPosReq': 0, #'Shifter position Zero', + 'SA1_Status_ParkButtonReq': 2, + "SA1_ShifterManualSignal": 0, + "SA1_ShifterModeSignal": 1, + "SA1_Status_ShftSensSng_Fault": 0, + "SA1_IND_ShifterMisUsd": 0, + "SA1_Live_counter": 1, + "SA1_Status_UnlockButtonReq": 1, + "SA1_Status_EcoShifterModeReq": 0, + "SA1_Status_RqGearPosInV": 0xf, + "SA1_Status_ShiftPosValidFlag": 0, +}) +# print(data) +# print(SA1_Status_ParkButtonReq_dic['No request']) diff --git a/widgets/ShifterTool.py b/widgets/ShifterTool.py index 361fa4e..e9aa7f1 100644 --- a/widgets/ShifterTool.py +++ b/widgets/ShifterTool.py @@ -236,11 +236,13 @@ self.sendQueue = Queue() # can layer send queue self.CANtoIsoTPQueue = Queue() # CAN --> isotp self.shifter = ShifterClass() + self.Vehicle = VehicleClass() self.devicedescription = HardwreDevice() self.windows = QtWidgets.QMainWindow() self.UI = Ui_MainWindow() self.UI.setupUi(window) self._dev_info = None + self.dbc = cantools.database.load_file("DBC/SX7H.dbc") self.can_thread = threading.Thread(target=self.can_thread) self.TestPresentTimer = QtCore.QTimer() self.TestPresentTimer.timeout.connect(self.creat_testpresentReq) @@ -566,6 +568,17 @@ msg.channel = 0 msg.data = [0x02, 0x3e, 0x80, 0, 0, 0, 0, 0] msg.is_extended_id = False + msg.is_remote_frame = False + self._usbcan.send(msg) + + def send_VehiclePosition(self, data=[]): + msg = Message() + msg.arbitration_id = 0x10 + msg.dlc = 8 + msg.channel = 0 + msg.data = data + msg.is_extended_id = False + msg.is_remote_frame = False self._usbcan.send(msg) def open_close(self): @@ -642,6 +655,38 @@ self.UI.pushButton_41.setStyleSheet( Style_dic[self.shifter.UnlockButton]) self.UI.pushButton_40.setStyleSheet(Style_dic[self.shifter.Pbutton]) + #X2 + self.UI.pushButton_37.setStyleSheet( + Style_dic[self.shifter.position == 2]) + #X1 + self.UI.pushButton_38.setStyleSheet( + Style_dic[self.shifter.position == 3]) + #Z + self.UI.pushButton_30.setStyleSheet( + Style_dic[self.shifter.position == 0]) + #Y1 + self.UI.pushButton_33.setStyleSheet( + Style_dic[self.shifter.position == 4]) + #Y2 + self.UI.pushButton_34.setStyleSheet( + Style_dic[self.shifter.position == 5]) + #M + self.UI.pushButton_39.setStyleSheet( + Style_dic[self.shifter.position == 0xe]) + #M+ + self.UI.pushButton_35.setStyleSheet( + Style_dic[self.shifter.position == 0xd]) + #M- + self.UI.pushButton_36.setStyleSheet( + Style_dic[self.shifter.position == 0xc]) + self.UI.pushButton_42.setStyleSheet( + ColorStyle_dic[self.Vehicle.ShiftLeverPos == "P"]) + self.UI.pushButton_43.setStyleSheet( + ColorStyle_dic[self.Vehicle.ShiftLeverPos == "D"]) + self.UI.pushButton_44.setStyleSheet( + ColorStyle_dic[self.Vehicle.ShiftLeverPos == "N"]) + self.UI.pushButton_45.setStyleSheet( + ColorStyle_dic[self.Vehicle.ShiftLeverPos == "R"]) def _updateRootList(self): _dataSize = self.msgQueue.qsize() @@ -652,11 +697,14 @@ for i in range(_dataSize): receiveNum += 1 msg = self.msgQueue.get() - # self.shifter.FramUnpack(msg.arbitration_id, msg.data) + if msg.arbitration_id == 0x420: + self.shifter.FramUnpack(msg.arbitration_id, msg.data) + resp_data = self.Vehicle.ShiftLogic(self.shifter) + self.send_VehiclePosition(resp_data) formateddata.append(self._formatMsgData( receiveNum, msg, True)) # return a data list self._insertDataSmooth(data=formateddata, datasize=_dataSize) - # self.dispShiftstatus() + self.dispShiftstatus() def _insertDataSmooth(self, data, datasize): # row = 6-datasize -- Gitblit v1.8.0