#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys, os import operator import ast import gc import time import mod_ddt_utils import mod_utils import mod_db_manager from shutil import copyfile os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) import mod_globals import mod_scan_ecus import mod_ddt_ecu import mod_elm try: # Python2 import tkinter as tk import tkinter.ttk import tkinter.font import tkinter.messagebox import tkinter.filedialog import tkinter.simpledialog except ImportError: # Python3 import tkinter as tk import tkinter.ttk as ttk import tkinter.font import tkinter.messagebox import tkinter.filedialog from mod_ddt_ecu import DDTECU from mod_ddt_screen import DDTScreen import xml.etree.ElementTree as et from xml.dom.minidom import parse import xml.dom.minidom mod_globals.os = os.name if mod_globals.os == 'nt': import pip try: import serial except ImportError: pip.main(['install', 'pyserial']) else: # let's try android try: import androidhelper as android mod_globals.os = 'android' except: try: import android mod_globals.os = 'android' except: pass if mod_globals.os != 'android': try: import serial from serial.tools import list_ports # import ply except ImportError: print("\n\n\n\tPleas install additional modules") print("\t\t>sudo easy_install pyserial") sys.exit() from mod_elm import ELM from mod_optfile import * from mod_utils import * class DDT(): decu = None # ddt ecu cecu = None # chosen ecu def __init__(self, elm, cecu, langmap={}): self.elm = elm self.cecu = cecu clearScreen() print("Starting DDT process") # make or load ddt ecu decucashfile = "./cache/ddt_" + cecu['ModelId'] + ".p" if os.path.isfile(decucashfile) and mod_globals.opt_ddtxml == '': # if cache exists and no xml defined self.decu = pickle.load(open(decucashfile, "rb")) # load it else: # else self.decu = DDTECU(self.cecu) # init class self.decu.setELM(self.elm) # define ELM for it self.decu.scanECU() # scan and loading original data for chosen ECU self.decu.setELM(None) # clear elm before serialization if len(self.decu.ecufname) > 0: pickle.dump(self.decu, open(decucashfile, "wb")) # and save cache self.decu.setELM(self.elm) # re-define ELM self.decu.setLangMap(langmap) if len(self.decu.ecufname) == 0: return if '/' in self.decu.ecufname: xfn = self.decu.ecufname[:-4].split('/')[-1] else: xfn = self.decu.ecufname[:-4].split('\\')[-1] dumpIs = False for root, dirs, files in os.walk("./dumps"): for f in files: if ('_' + xfn + '.') in f: dumpIs = True break if not mod_globals.opt_demo and not dumpIs and not mod_globals.opt_dump: answer = input('Save dump ? [y/n] : ') if 'N' in answer.upper(): dumpIs = True if mod_globals.opt_demo: print("Loading dump") self.decu.loadDump() elif mod_globals.opt_dump or not dumpIs: print("Saving dump") self.decu.saveDump() # Load XML if not self.decu.ecufname.startswith(mod_globals.ddtroot): tmp_f_name = self.decu.ecufname.split('/')[-1] self.decu.ecufname = 'ecus/'+tmp_f_name if not mod_db_manager.file_in_ddt(self.decu.ecufname): print("No such file: ", self.decu.ecufname) return None ns = {'ns0': 'http://www-diag.renault.com/2002/ECU', 'ns1': 'http://www-diag.renault.com/2002/screens'} tree = et.parse(mod_db_manager.get_file_from_ddt(self.decu.ecufname)) xdoc = tree.getroot() # Show screen print("Show screen") scr = DDTScreen(self.decu.ecufname, xdoc, self.decu) del scr del self.decu def __del__(self): # debug # print sys.getrefcount(self.elm) del self.elm del self.cecu def optParser(): '''Parsing of command line parameters. User should define at least com port name''' '''Not used in current version''' import argparse parser = argparse.ArgumentParser( # usage = "%prog -p [options]", version="mod_ddt Version 0.9.q", description="mod_ddt - python program for diagnostic Renault cars" ) parser.add_argument('-p', help="ELM327 com port name", dest="port", default="") parser.add_argument("-r", help="com port rate during diagnostic session {38400[default],57600,115200,230400,500000}", dest="rate", default="38400", ) parser.add_argument("-a", help="functional address of ecu", dest="ecuAddr", default="") parser.add_argument("-i", help="interface protocol [can250|250|can500|500|kwpS|S|kwpF|F]", dest="protocol", default='500') parser.add_argument("-L", help="language option {RU[default],GB,FR,IT,...}", dest="lang", default="RU") parser.add_argument("--cfc", help="turn off automatic FC and do it by script", dest="cfc", default=False, action="store_true") parser.add_argument("--n1c", help="turn off L1 cache", dest="n1c", default=False, action="store_true") parser.add_argument("--log", help="log file name", dest="logfile", default="") parser.add_argument("--xml", help="xml file name", dest="ddtxml", default="") parser.add_argument("--demo", help="for debuging purpose. Work without car and ELM", dest="demo", default=False, action="store_true") parser.add_argument("--dump", help="dump responces from all 21xx and 22xxxx requests", dest="dump", default=True, action="store_true") parser.add_argument("--exp", help="swith to Expert mode (allow to use buttons in DDT)", dest="exp", default=False, action="store_true") options = parser.parse_args() if not options.port and mod_globals.os != 'android': parser.print_help() iterator = sorted(list(list_ports.comports())) print("") print("Available COM ports:") for port, desc, hwid in iterator: print("%-30s \n\tdesc: %s \n\thwid: %s" % (port, desc.decode("windows-1251"), hwid)) print("") exit(2) else: mod_globals.opt_port = options.port mod_globals.opt_ecuAddr = options.ecuAddr.upper() mod_globals.opt_rate = int(options.rate) mod_globals.opt_lang = options.lang mod_globals.opt_log = options.logfile mod_globals.opt_demo = options.demo mod_globals.opt_dump = options.dump mod_globals.opt_exp = options.exp mod_globals.opt_cfc0 = options.cfc mod_globals.opt_n1c = options.n1c mod_globals.opt_ddtxml = options.ddtxml if 'S' in options.protocol.upper(): mod_globals.opt_protocol = 'S' elif 'F' in options.protocol.upper(): mod_globals.opt_protocol = 'F' elif '250' in options.protocol: mod_globals.opt_protocol = '250' elif '500' in options.protocol: mod_globals.opt_protocol = '500' else: mod_globals.opt_protocol = '500' class DDTLauncher(): def __init__(self): self.eculist = mod_ddt_utils.loadECUlist() self.carecus = [] self.root = tk.Tk() self.root.title("mod_ddt Launcher") self.style = tkinter.ttk.Style () self.style.theme_use ('classic') self.var_dump = tk.BooleanVar() self.var_log = tk.BooleanVar() self.var_cfc = tk.BooleanVar() self.var_can2 = tk.BooleanVar() self.var_portList = [] self.var_speedList = [] self.var_port = tk.StringVar() self.var_speed = tk.StringVar() self.var_logName = tk.StringVar() self.elm = None self.save = mod_ddt_utils.settings() self.loadSettings() self.currentEcu = None self.v_xmlList = [] self.v_dumpList = [] self.root.rowconfigure(0, weight=1) self.root.rowconfigure(1, weight=1) self.root.columnconfigure(0, weight=1, minsize=300) self.root.columnconfigure(1) # not stretchable self.root.columnconfigure(2, weight=3, minsize=300) optsGrid = {'ipadx': 0, 'ipady': 0, 'sticky': 'nswe'} optsGrid_w = {'ipadx': 0, 'ipady': 0, 'sticky': 'w'} optsGrid_e = {'ipadx': 0, 'ipady': 0, 'sticky': 'e'} btn_style = { 'activebackground':"#d9d9d9", 'activeforeground':"#000000", 'background':"#d9d9d9", 'foreground':"#000000", 'highlightbackground':"#d9d9d9"} ent_style = { 'background':"#FFFFFF", 'foreground':"#000000", 'highlightbackground':"#d9d9d9"} self.tf = tk.Frame(self.root) self.tf.grid(row=0, column=0, **optsGrid ) self.tf.rowconfigure(0) # not stretchable self.tf.rowconfigure(1, weight=1) self.tf.columnconfigure(0, weight=1) self.tf.columnconfigure(1) self.filterText = tk.StringVar() self.filtentry = tk.Entry(self.tf, textvariable=self.filterText, **ent_style) self.filtentry.bind('', self.fltBtnClick) self.filtentry.grid(row=0, column=0, **optsGrid) self.filtbutton = tk.Button(self.tf, text="Filter", command=self.fltBtnClick, **btn_style) self.filtbutton.grid(row=0, column=1, **optsGrid) self.ptree = tkinter.ttk.Treeview(self.tf, columns = ['name','segment'], height=10) self.ptree.grid(row=1, column=0, columnspan = 2, **optsGrid) self.vsb = tkinter.ttk.Scrollbar(self.root, orient="vertical", command=self.ptree.yview) self.vsb.grid(row=0, column=1, **optsGrid) self.ptree.configure(yscrollcommand=self.vsb.set) #self.ptree.bind('', self.OnDoubleClick) self.ptree.bind('', self.CarDoubleClick) self.ptree.heading('#0', text='Project') self.ptree.heading('name', text='Name', anchor='center') self.ptree.heading('segment', text='Segm', anchor='e') self.ptree.column('#0', minwidth=100, width=100, stretch=False) self.ptree.column('#1', minwidth=150, width=150, stretch=True) self.ptree.column('#2', minwidth=50, width=50, stretch=False) self.mf = tk.Frame(self.root, background="#d9d9d9") self.mf.grid(row=0, column=2, **optsGrid) self.mf.rowconfigure(0) self.mf.rowconfigure(1) self.mf.rowconfigure(2) self.mf.rowconfigure(3) self.mf.rowconfigure(4) self.mf.rowconfigure(5) self.mf.rowconfigure(6, weight = 1) self.mf.rowconfigure(7) self.mf.rowconfigure(8) self.mf.columnconfigure(0, weight = 1) self.mf.columnconfigure(1, weight = 1) self.mf.columnconfigure(2, weight = 1) self.mf.columnconfigure(3, weight = 1) self.l_db = tk.Label(self.mf, text='DB root:', background="#d9d9d9") self.l_db.grid(row=0, column=0, **optsGrid_e) self.l_db2 = tk.Label(self.mf, text=mod_globals.ddtroot, background="#d9d9d9") self.l_db2.grid(row=0, column=1, **optsGrid_w) self.l_pr = tk.Label(self.mf, text='Project:', background="#d9d9d9") self.l_pr.grid(row=1, column=0, **optsGrid_e) self.v_proj = tk.StringVar() self.v_proj.set("") self.e_proj = tk.Label(self.mf, textvariable=self.v_proj, background="#d9d9d9") #self.e_proj.config(state=tk.DISABLED) self.e_proj.grid(row=1, column=1, **optsGrid_w) self.l_af = tk.Label(self.mf, text='Addressing:', background="#d9d9d9") self.l_af.grid(row=2, column=0, **optsGrid_e) self.v_addr = tk.StringVar() self.v_addr.set("") self.e_addr = tk.Label(self.mf, textvariable=self.v_addr, background="#d9d9d9") #self.e_addr.config(state=tk.DISABLED) self.e_addr.grid(row=2, column=1, **optsGrid_w) self.l_pcan = tk.Label(self.mf, text='Primary CAN:', background="#d9d9d9") self.l_pcan.grid(row=3, column=0, **optsGrid_e) self.v_pcan = tk.StringVar() self.v_pcan.set("") self.e_pcan = tk.Label(self.mf, textvariable=self.v_pcan, background="#d9d9d9") #self.e_pcan.config(state=tk.DISABLED) self.e_pcan.grid(row=3, column=1, **optsGrid_w) self.l_mcan = tk.Label(self.mf, text='Secondary CAN:', background="#d9d9d9") self.l_mcan.grid(row=4, column=0, **optsGrid_e) self.v_mcan = tk.StringVar() self.v_mcan.set("") self.e_mcan = tk.Label(self.mf, textvariable=self.v_mcan, background="#d9d9d9") #self.e_mcan.config(state=tk.DISABLED) self.e_mcan.grid(row=4, column=1, **optsGrid_w) self.l_vi = tk.Label(self.mf, text='VIN or car name:', background="#d9d9d9") self.l_vi.grid(row=5, column=0, **optsGrid_e) self.v_vin = tk.StringVar() self.v_vin.set("") self.e_vin = tk.Entry(self.mf, textvariable=self.v_vin, **ent_style) self.e_vin.grid(row=5, column=1, columnspan=3, **optsGrid) #################################################################################### self.set_fr = tk.LabelFrame(self.mf, text="Settings", padx=5, background="#d9d9d9") self.set_fr.grid(row=0, rowspan=5, column=2, columnspan=4, **optsGrid) self.set_fr.rowconfigure(0) self.set_fr.rowconfigure(1) self.set_fr.rowconfigure(2) self.set_fr.columnconfigure(0, weight=1) self.set_fr.columnconfigure(1, weight=1) self.set_fr.columnconfigure(2, weight=1) self.port_lbl = tk.Label(self.set_fr, text='ELM:', background="#d9d9d9") self.port_lbl.grid(row=0, column=0, **optsGrid_e) self.portList = tkinter.ttk.Combobox(self.set_fr) self.portList.grid(row=0, column=1, **optsGrid) self.portList.configure(values=self.var_portList) self.portList.configure(textvariable=self.var_port) self.portList.configure(takefocus="") self.speedList = tkinter.ttk.Combobox(self.set_fr, width=6) self.speedList.grid(row=0, column=2, **optsGrid_w) self.speedList.configure(values=self.var_speedList) self.speedList.configure(textvariable=self.var_speed) self.speedList.configure(takefocus="") self.log_lbl = tk.Label(self.set_fr, text='Log:', background="#d9d9d9") self.log_lbl.grid(row=1, column=0, **optsGrid_e) self.logName = tk.Entry(self.set_fr, textvariable=self.var_logName, **ent_style) self.logName.grid(row=1, column=1, **optsGrid) self.logChk = tk.Checkbutton(self.set_fr, variable=self.var_log, background="#d9d9d9") self.logChk.grid(row=1, column=2, **optsGrid_w) self.dump_lbl = tk.Label(self.set_fr, text='Dump:', background="#d9d9d9") self.dump_lbl.grid(row=2, column=0, **optsGrid_e) self.dumpChk = tk.Checkbutton(self.set_fr, variable=self.var_dump, background="#d9d9d9") self.dumpChk.grid(row=2, column=1, **optsGrid_w) self.can2_lbl = tk.Label(self.set_fr, text='CAN2:', background="#d9d9d9") self.can2_lbl.grid(row=2, column=1, **optsGrid_e) self.can2Chk = tk.Checkbutton(self.set_fr, variable=self.var_can2, background="#d9d9d9") self.can2Chk.grid(row=2, column=2, **optsGrid_w) #################################################################################### self.btn_connect = tk.Button(self.mf, text="Connect selected ECU (ON-line)", command=self.ConnectBtnClick, **btn_style) self.btn_connect.grid(row=6, column=0, columnspan=2, **optsGrid) self.btn_connect = tk.Button(self.mf, text="Show selected ECU (OFF-line)", command=self.DemoBtnClick, **btn_style) self.btn_connect.grid(row=6, column=3, **optsGrid) self.btn_scan_all_car = tk.Button(self.mf, text="Scan all ECUs", command=self.ScanAllBtnClick, **btn_style) self.btn_scan_all_car.grid(row=7, column=0, **optsGrid) self.btn_scan_car = tk.Button(self.mf, text="Scan selected ECU", command=self.ScanSelectedBtnClick, **btn_style) self.btn_scan_car.grid(row=7, column=1, **optsGrid) self.btn_load_car = tk.Button(self.mf, text="Load car", command=self.LoadBtnClick, **btn_style) self.btn_load_car.grid(row=7, column=2, **optsGrid) self.btn_save_car = tk.Button(self.mf, text="Save car", command=self.SaveBtnClick, **btn_style) self.btn_save_car.grid(row=7, column=3, **optsGrid) self.progress = tkinter.ttk.Progressbar(self.mf, mode="determinate") self.progress.grid(row=8, column=0, columnspan=4, **optsGrid) self.df = tk.Frame(self.root, background='#d9d9d9') self.df.grid(row=1, column=0, columnspan=3, **optsGrid ) self.df.rowconfigure(0) # not stretchable self.df.columnconfigure(0, weight=1) self.df.columnconfigure(1) self.ecutree = tkinter.ttk.Treeview(self.df, columns = ['ISO8','XId','RId','Prot','Type','Name','XML','dump'], height=20) self.ecutree.grid(row=0, column=0, **optsGrid) self.vsb1 = tkinter.ttk.Scrollbar(self.df, orient="vertical", command=self.ecutree.yview) self.vsb1.grid(row=0, column=1, **optsGrid) self.ecutree.configure(yscrollcommand=self.vsb1.set) self.ecutree.bind('', self.EcuDoubleClick) self.ecutree.bind('', self.EcuDoubleClick) self.ecutree.heading('#0', text='Addr') self.ecutree.heading('#1', text='ISO8') self.ecutree.heading('#2', text='XId') self.ecutree.heading('#3', text='RId') self.ecutree.heading('#4', text='Protocol') self.ecutree.heading('#5', text='Type') self.ecutree.heading('#6', text='Name') self.ecutree.heading('#7', text='XML') self.ecutree.heading('#8', text='dump') self.ecutree.column('#0', minwidth=40, width=40, stretch=False) self.ecutree.column('#1', minwidth=40, width=40, stretch=False) self.ecutree.column('#2', minwidth=40, width=40, stretch=False) self.ecutree.column('#3', minwidth=40, width=40, stretch=False) self.ecutree.column('#4', minwidth=80, width=80, stretch=False) self.ecutree.column('#5', minwidth=100, width=100, stretch=False) self.ecutree.column('#6', minwidth=150, width=150, stretch=False) self.ecutree.column('#7', minwidth=300, width=300, stretch=True) self.ecutree.column('#8', minwidth=150, width=150, stretch=True) self.pl = mod_ddt_utils.ddtProjects() self.fltBtnClick() # show tree with apply clear filter self.LoadCarFile("./savedCAR_prev.csv") self.root.mainloop() def __del__(self): self.SaveBtnClick() self.saveSettings() def enableELM(self): # print self.elm if self.elm != None: try: self.elm.port.hdr.close() del(self.elm) self.elm = None gc.collect() except: pass self.applySettings() try: mod_globals.opt_demo = False self.elm = ELM(mod_globals.opt_port, mod_globals.opt_speed, mod_globals.opt_log) except: result = tkinter.messagebox.askquestion("Warning", "ELM is not connected. Would you like to work OFF-line?", icon='warning') if result == 'yes': mod_globals.opt_demo = True self.elm = ELM(mod_globals.opt_port, mod_globals.opt_speed, mod_globals.opt_log) if mod_globals.opt_obdlink == True: self.elm.ATCFC0 = False mod_globals.opt_cfc0 = False else: raise Exception('elm is not connected') return # change serial port baud rate if mod_globals.opt_speed < mod_globals.opt_rate and not mod_globals.opt_demo: self.elm.port.soft_boudrate(mod_globals.opt_rate) def LoadCarFile(self, filename): if not os.path.isfile(filename): return with open(filename, 'r') as fin: lines = fin.read().splitlines() fin.close() self.carecus = [] for l in lines: l = l.strip() if len(l)==0 or l.startswith('#'): continue li = l.split(';') if li[0].lower()=='car': self.v_proj.set(li[1]) self.v_addr.set(li[2]) self.v_pcan.set(li[3]) self.v_mcan.set(li[4]) self.v_vin.set(li[5]) else: ecu = {} ecu['undef'] = li[0] ecu['addr'] = li[1] ecu['iso8'] = li[2] ecu['xid'] = li[3] ecu['rid'] = li[4] ecu['prot'] = li[5] ecu['type'] = li[6] ecu['name'] = li[7] ecu['xml'] = li[8] ecu['dump'] = li[9] ecu['ses'] = li[10] self.carecus.append(ecu) self.renewEcuList() def LoadBtnClick(self): filename = tkinter.filedialog.askopenfilename(initialdir='./', title='Select file', filetypes=[('csv files', '*.csv')]) self.LoadCarFile(filename) return def SaveBtnClick(self): filename = './savedCAR_'+self.v_vin.get()+'.csv' with open( filename, 'w') as fout: car = ['car',self.v_proj.get(), self.v_addr.get(), self.v_pcan.get(), self.v_mcan.get(), self.v_vin.get()] fout.write(';'.join(car)+'\n') for ecu in self.carecus: e = [ecu['undef'], ecu['addr'], ecu['iso8'], ecu['xid'], ecu['rid'], ecu['prot'], ecu['type'], ecu['name'], ecu['xml'], ecu['dump'], ecu['ses']] fout.write(';'.join(e) + '\n') fout.close() copyfile(filename, "./savedCAR_prev.csv") return def setEcuAddress(self, ce, pro ): # define ecudata ecudata = {'idTx': ce['xid'], 'idRx': ce['rid'], 'slowInit': '', 'fastInit': '', 'ModelId': ce['addr'], 'ecuname': 'ddt_unknown', } if pro == 'CAN': if ce['prot'] == 'CAN-250': ecudata['protocol'] = 'CAN_250' ecudata['brp'] = '01' else: ecudata['protocol'] = 'CAN_500' ecudata['brp'] = '0' ecudata['pin'] = 'can' self.elm.set_can_addr(ce['addr'], ecudata) if pro == 'KWP' or pro == 'ISO': if ce['prot'] == 'KWP-FAST': ecudata['protocol'] = 'KWP_Fast' ecudata['fastInit'] = ce['addr'] ecudata['slowInit'] = '' mod_globals.opt_si = False elif ce['prot'] == 'ISO8' and ce['iso8'] != '': ecudata['protocol'] = 'KWP_Slow' ecudata['fastInit'] = '' ecudata['slowInit'] = ce['iso8'] mod_globals.opt_si = True else: ecudata['protocol'] = 'KWP_Slow' ecudata['fastInit'] = '' ecudata['slowInit'] = ce['addr'] mod_globals.opt_si = True ecudata['pin'] = 'iso' self.elm.set_iso_addr(ce['addr'], ecudata) def ScanAllBtnClick(self): # Enable ELM try: self.enableELM() except: return if self.elm==None or self.elm.port==0: tkinter.messagebox.showinfo("ERROR", "ELM is not connected. You may work only offline.") return # for all carecus find can ecus, then k-line ecus scansequence = ['CAN','KWP','ISO'] vins = {} self.progress['maximum'] = len(self.carecus)+1 progressValue = 1 self.progress['value'] = progressValue for pro in scansequence: # init protocol if pro == 'CAN': self.elm.init_can() else: self.elm.init_iso() for ce in self.carecus: if pro in ce['prot'] or ce['prot']=='': # set address self.setEcuAddress(ce, pro) progressValue = progressValue + 1 self.progress['value'] = progressValue self.progress.update() # get ID (StartSession, DiagVersion, Supplier, Version, Soft, Std, VIN) = mod_scan_ecus.readECUIds(self.elm) if DiagVersion=='' and DiagVersion=='' and Version=='' and Soft=='' and VIN=='': continue candlist = mod_ddt_ecu.ecuSearch(self.v_proj.get(), ce['addr'], DiagVersion, Supplier, Soft, Version, self.eculist, interactive = False) ce['xml'] = candlist[0] ce['ses'] = StartSession ce['undef'] = '0' tmp = self.getDumpListByXml(ce['xml']) if len(tmp)>0: ce['dump'] = tmp[-1] else: ce['dump'] = '' # count most frequent VINs if VIN!='': if VIN not in list(vins.keys()): vins[VIN] = 1 else: vins[VIN] = vins[VIN] + 1 self.renewEcuList() if self.v_vin.get()=='' and len(list(vins.keys())): self.v_vin.set(max(iter(vins.items()), key=operator.itemgetter(1))[0]) self.progress['value'] = 0 return def ScanSelectedBtnClick(self): # Enable ELM try: self.enableELM() except: return if self.elm==None or self.elm.port==0: tkinter.messagebox.showinfo("ERROR", "ELM is not connected. You may work only offline.") return try: item = self.ecutree.selection()[0] e = self.ecutree.item(item)['values'][8] except: pass ce = None for ce in self.carecus: if str(ce)==e: break self.currentEcu = self.carecus.index(ce) if ce==None: return #ce = self.getSelectedECU() # init protocol if 'CAN' in ce['prot'] and ce['xid']!='' and ce['rid']!='': pro = 'CAN' else: pro = 'KWP' if pro == 'CAN': self.elm.init_can() else: self.elm.init_iso() # set address self.setEcuAddress(ce, pro) # get ID (StartSession, DiagVersion, Supplier, Version, Soft, Std, VIN) = mod_scan_ecus.readECUIds(self.elm) if DiagVersion=='' and Supplier=='' and Version=='' and Soft=='': tkinter.messagebox.showinfo("INFO", "no response from this ECU") return candlist = mod_ddt_ecu.ecuSearch(self.v_proj.get(), ce['addr'], DiagVersion, Supplier, Soft, Version, self.eculist, interactive = False) ce['xml'] = candlist[0] ce['ses'] = StartSession ce['undef'] = '0' self.renewEcuList() return def ConnectBtnClick(self): ecu = self.getSelectedECU() if ecu==None or ecu['xml']=='': tkinter.messagebox.showinfo("INFO", "Selected ECU is undefined. Please scan it first.") return None mod_globals.opt_demo = False self.OpenECUScreens(ecu) return def getSelectedECU(self): try: item = self.ecutree.selection()[0] line = self.ecutree.item(item)['values'] except: if len(self.ecutree.get_children(""))==0: tkinter.messagebox.showinfo("INFO", "Please select the project in the left list and then ECU in the bottom") else: tkinter.messagebox.showinfo("INFO", "Please select an ECU in the bottom list") return None ecu = ast.literal_eval(line[8]) return ecu def OpenECUScreens(self, ce): decu = None # Enable ELM try: self.enableELM() except: return if not mod_globals.opt_demo and self.var_dump.get(): mod_globals.opt_dump = True ce = self.getSelectedECU() # init protocol if 'CAN' in ce['prot'] and ce['xid']!='' and ce['rid']!='': pro = 'CAN' else: pro = 'KWP' #check elm timeout ct1 = time.time() if pro == 'CAN': self.elm.init_can() else: self.elm.init_iso() ct2 = time.time() if ct2-ct1 > 5: tkinter.messagebox.showinfo("ERROR", "ELM is not responding well.") return # set address self.setEcuAddress(ce, pro) self.elm.start_session(ce['ses']) # make or load ddt ecu decucashfile = "./cache/ddt_" + ce['xml'][:-4] + ".p" if os.path.isfile(decucashfile): # if cache exists and no xml defined decu = pickle.load(open(decucashfile, "rb")) # load it else: # else decu = DDTECU(None) # init class decu.loadXml('ecus/'+ce['xml']) if len(decu.ecufname) > 0: pickle.dump(decu, open(decucashfile, "wb")) # and save cache decu.setELM(self.elm) # re-define ELM if len(decu.ecufname) == 0: return if '/' in decu.ecufname: xfn = decu.ecufname[:-4].split('/')[-1] else: xfn = decu.ecufname[:-4].split('\\')[-1] dumpIs = False for root, dirs, files in os.walk("./dumps"): for f in files: if (xfn + '.') in f: dumpIs = True break #if not mod_globals.opt_demo and not dumpIs and not mod_globals.opt_dump: # answer = raw_input('Save dump ? [y/n] : ') # if 'N' in answer.upper(): # dumpIs = True if mod_globals.opt_demo: print("Loading dump") if len(ce['dump'])==0: decu.loadDump() else: decu.loadDump("./dumps/"+ce['dump']) elif mod_globals.opt_dump: ce['dump'] = self.guiSaveDump(decu) for ec in self.carecus: if ce['xml'][:-4] in ec['xml']: ec['dump'] = ce['dump'] self.renewEcuList() self.SaveBtnClick() # Load XML if not mod_db_manager.file_in_ddt(decu.ecufname): print("No such file: ", decu.ecufname) return None ns = {'ns0': 'http://www-diag.renault.com/2002/ECU', 'ns1': 'http://www-diag.renault.com/2002/screens'} tree = et.parse(mod_db_manager.get_file_from_ddt(decu.ecufname)) xdoc = tree.getroot() # Show screen print("Show screen") scr = DDTScreen(decu.ecufname, xdoc, decu, top=True) del scr del decu def guiSaveDump(self,decu): ''' save responces from all 21xx, 22xxxx commands ''' self.pdlg = tk.Toplevel() self.pdlg.option_add ('*Dialog.msg.font', 'Courier\ New 12') self.pdlg.geometry("256x100") self.pdlg.title("Saving dump") self.pdlg.configure(background="#d9d9d9") v_cmd = tk.StringVar() v_cmd.set("") e_cmd = tk.Label(self.pdlg, textvariable=v_cmd, background="#d9d9d9") e_cmd.pack(expand=1, fill=tk.X) v_cnt = tk.StringVar() v_cnt.set("") e_cnt = tk.Label(self.pdlg, textvariable=v_cnt, background="#d9d9d9") e_cnt.pack(expand=1, fill=tk.X) progress = tkinter.ttk.Progressbar(self.pdlg, mode="determinate") progress.pack(expand=1, fill=tk.X) xmlname = decu.ecufname if xmlname.upper().endswith('.XML'): xmlname = xmlname[:-4] if '/' in xmlname: xmlname = xmlname.split('/')[-1] else: xmlname = xmlname.split('\\')[-1] dumpFileName = str(int(time.time())) + '_' + xmlname + '.txt' dumpPath = './dumps/' + dumpFileName df = open(dumpPath, 'wt') decu.elm.clear_cache() max = len(list(decu.requests.keys())) progress['maximum'] = max progressValue = 1 progress['value'] = progressValue im = ' from ' + str(max) i = 0 for request in list(decu.requests.values()): i = i + 1 progressValue = progressValue + 1 progress['value'] = progressValue progress.update() sys.stdout.flush() if request.SentBytes[:2] in mod_elm.AllowedList + ['17', '19']: if request.SentBytes[:2] == '19' and request.SentBytes[:2] != '1902': continue if request.SentBytes[:2] == '22' and len(request.SentBytes) < 6: continue v_cmd.set(request.SentBytes) e_cmd.update() v_cnt.set(str(i)+'/'+str(max)) e_cnt.update() pos = chr(ord(request.SentBytes[0]) + 4) + request.SentBytes[1] rsp = decu.elm.request(request.SentBytes, pos, False) if ':' in rsp: continue df.write('%s:%s\n' % (request.SentBytes, rsp)) df.close() self.pdlg.destroy() return dumpFileName def DemoBtnClick(self): ecu = self.getSelectedECU() if ecu==None or ecu['xml']=='': tkinter.messagebox.showinfo("INFO", "Selected ECU is undefined. Please scan it first.") return None mod_globals.opt_demo = True self.OpenECUScreens(ecu) return def fltBtnClick(self, ev=None): self.ptree.delete(*self.ptree.get_children()) ptrn = self.filterText.get().strip().lower() for m in self.pl.plist: self.ptree.insert('','end',iid=m['name'], text=m['name'], open=True) for c in m['list']: if len(ptrn)==0 or ptrn in str(c).lower(): self.ptree.insert(m['name'], 'end', iid = c['code'], text = c['code'], values=[c['name'],c['segment'],c['addr']]) def treeview_sort_column(self, tv, col, reverse): l = [(tv.set(k, col), k) for k in tv.get_children('')] l.sort(reverse=reverse) # rearrange items in sorted positions for index, (val, k) in enumerate(l): tv.move(k, '', index) # reverse sort next time tv.heading(col, command=lambda: \ self.treeview_sort_column(tv, col, not reverse)) def CarDoubleClick(self, event): try: item = self.ptree.selection()[0] line = self.ptree.item(item)['values'] self.addr = mod_ddt_utils.ddtAddressing(line[2]) self.v_proj.set(item) self.v_addr.set(line[2]) self.v_vin.set('') except: pass tmpL = [] self.carecus = [] for e in self.addr.alist: if e['Address']==0: self.v_pcan.set(e['baudRate']) continue if e['Address']==255: self.v_mcan.set(e['baudRate']) continue if 'en' in list(e['longname'].keys()): longname = e['longname']['en'] else: longname = list(e['longname'].values())[0] if e['Address']: v_addr = hex(int(e['Address']))[2:].upper() if len(v_addr)==1: v_addr = '0'+v_addr else: v_addr = '' if e['ISO8']: v_iso = hex(int(e['ISO8']))[2:].upper() if len(v_iso)==1: v_addr = '0'+v_iso else: v_iso = '' if e['XId']: if len(e['XId'])>6: v_XId = hex(0x80000000+int(e['XId']))[2:].upper() else: v_XId = hex(int(e['XId']))[2:].upper() else: v_XId = '' if e['RId']: if len(e['RId'])>6: v_RId = hex(0x80000000+int(e['RId']))[2:].upper() else: v_RId = hex(int(e['RId']))[2:].upper() else: v_RId = '' if e['protocol']=='6' and (v_XId=='' or v_RId==''): continue # key = e['protocol'] + v_addr if key in tmpL: continue tmpL.append(key) v_prot = e['protocol'] if e['protocol']=='1': v_prot = 'ISO8' elif e['protocol']=='2' or e['protocol']=='3': v_prot = 'KWP-SLOW' elif e['protocol']=='4' or e['protocol']=='5': v_prot = 'KWP-FAST' elif e['protocol']=='6' and self.v_pcan.get()=='250000': v_prot = 'CAN-250' elif e['protocol']=='6': v_prot = 'CAN-500' ecu = {} ecu['undef'] = '1' ecu['addr'] = v_addr ecu['iso8'] = v_iso ecu['xid'] = v_XId ecu['rid'] = v_RId ecu['prot'] = v_prot ecu['type'] = e['Name'] ecu['name'] = longname ecu['xml'] = '' ecu['dump'] = '' ecu['ses'] = '' self.carecus.append(ecu) self.renewEcuList() def EcuDoubleClick(self, event): self.currentEcu = None try: item = self.ecutree.selection()[0] e = self.ecutree.item(item)['values'][8] except: pass ecu = None for ecu in self.carecus: if str(ecu)==e: break self.currentEcu = self.carecus.index(ecu) if ecu==None: return self.ecudlg = tk.Toplevel() self.ecudlg.option_add ('*Dialog.msg.font', 'Courier\ New 12') #ecudlg.geometry("256x256") self.ecudlg.title("Ecu settings") self.ecudlg.configure(background="#d9d9d9") optsGrid = {'ipadx': 0, 'ipady': 0, 'sticky': 'nswe'} optsGrid_w = {'ipadx': 0, 'ipady': 0, 'sticky': 'w'} optsGrid_e = {'ipadx': 0, 'ipady': 0, 'sticky': 'e'} ent_style = { 'background':"#FFFFFF", 'foreground':"#000000", 'highlightbackground':"#d9d9d9"} btn_style = { 'activebackground':"#d9d9d9", 'activeforeground':"#000000", 'background':"#d9d9d9", 'foreground':"#000000", 'highlightbackground':"#d9d9d9"} l_type = tk.Label(self.ecudlg, text='Type:', background="#d9d9d9") l_type.grid(row=0, column=0, **optsGrid_e) self.dv_type = tk.StringVar() self.dv_type.set(ecu['type']) e_type = tk.Entry(self.ecudlg, textvariable=self.dv_type, width=10, **ent_style) e_type.grid(row=0, column=1, **optsGrid) l_name = tk.Label(self.ecudlg, text='Name:', background="#d9d9d9") l_name.grid(row=1, column=0, **optsGrid_e) self.dv_name = tk.StringVar() self.dv_name.set(ecu['name']) e_name = tk.Entry(self.ecudlg, textvariable=self.dv_name, width=10, **ent_style) e_name.grid(row=1, column=1, **optsGrid) l_xid = tk.Label(self.ecudlg, text='Xid:', background="#d9d9d9") l_xid.grid(row=2, column=0, **optsGrid_e) self.dv_xid = tk.StringVar() self.dv_xid.set(ecu['xid']) e_xid = tk.Entry(self.ecudlg, textvariable=self.dv_xid, width=10, **ent_style) e_xid.grid(row=2, column=1, **optsGrid) l_rid = tk.Label(self.ecudlg, text='Rid:', background="#d9d9d9") l_rid.grid(row=3, column=0, **optsGrid_e) self.dv_rid = tk.StringVar() self.dv_rid.set(ecu['rid']) e_rid = tk.Entry(self.ecudlg, textvariable=self.dv_rid, width=10, **ent_style) e_rid.grid(row=3, column=1, **optsGrid) l_addr = tk.Label(self.ecudlg, text='Functional address:', background="#d9d9d9") l_addr.grid(row=4, column=0, **optsGrid_e) self.dv_addr = tk.StringVar() self.dv_addr.set(ecu['addr']) e_addr = tk.Entry(self.ecudlg, textvariable=self.dv_addr, width=10, **ent_style) e_addr.grid(row=4, column=1, **optsGrid) l_iso = tk.Label(self.ecudlg, text='ISO address:', background="#d9d9d9") l_iso.grid(row=5, column=0, **optsGrid_e) self.dv_iso = tk.StringVar() self.dv_iso.set(ecu['iso8']) e_iso = tk.Entry(self.ecudlg, textvariable=self.dv_iso, width=10, **ent_style) e_iso.grid(row=5, column=1, **optsGrid) l_ses = tk.Label(self.ecudlg, text='Session open cmd:', background="#d9d9d9") l_ses.grid(row=6, column=0, **optsGrid_e) self.dv_ses = tk.StringVar() self.dv_ses.set(ecu['ses']) e_ses = tk.Entry(self.ecudlg, textvariable=self.dv_ses, width=10, **ent_style) e_ses.grid(row=6, column=1, **optsGrid) v_protList = ['ISO8', 'KWP-SLOW', 'KWP-FAST', 'CAN-250', 'CAN-500'] l_pro = tk.Label(self.ecudlg, text='BUS type:', background="#d9d9d9") l_pro.grid(row=7, column=0, **optsGrid_e) self.dv_pro = tk.StringVar() self.dv_pro.set(ecu['prot']) c_pro = tkinter.ttk.Combobox(self.ecudlg) c_pro.configure(values=v_protList) c_pro.configure(textvariable=self.dv_pro) c_pro.configure(takefocus="") c_pro.grid(row=7, column=1, **optsGrid) self.getXmlListByProj() l_xml = tk.Label(self.ecudlg, text='Recommended XML:', background="#d9d9d9") l_xml.grid(row=8, column=0, **optsGrid_e) self.dv_xml = tk.StringVar() self.dv_xml.set(ecu['xml']) c_xml = tkinter.ttk.Combobox(self.ecudlg, width=30) c_xml.configure(values=self.v_xmlList) c_xml.configure(textvariable=self.dv_xml) c_xml.configure(takefocus="") c_xml.grid(row=8, column=1, **optsGrid_w) #b_xml = tk.Button(self.ecudlg, text="XML file", command=self.xmlBtnClick, **btn_style) #b_xml.grid(row=8, column=2, **optsGrid) allxmllist = [] for l in sorted(mod_db_manager.get_file_list_from_ddt('ecus/*')): allxmllist.append( os.path.basename(l) ) l2_xml = tk.Label(self.ecudlg, text='ALL XML:', background="#d9d9d9") l2_xml.grid(row=9, column=0, **optsGrid_e) a_xml = tkinter.ttk.Combobox(self.ecudlg, width=30) a_xml.configure(values=allxmllist) a_xml.configure(textvariable=self.dv_xml) a_xml.configure(takefocus="") a_xml.grid(row=9, column=1, **optsGrid_w) self.getDumpListByXml() l_dump = tk.Label(self.ecudlg, text='Dump:', background="#d9d9d9") l_dump.grid(row=10, column=0, **optsGrid_e) self.dv_dump = tk.StringVar() self.dv_dump.set(ecu['dump']) c_dump = tkinter.ttk.Combobox(self.ecudlg, width=30) c_dump.configure(values=self.v_dumpList) c_dump.configure(textvariable=self.dv_dump) c_dump.configure(takefocus="") c_dump.grid(row=10, column=1, **optsGrid_w) b_dump = tk.Button(self.ecudlg, text="Dump file", command=self.dumpBtnClick, **btn_style) b_dump.grid(row=10, column=2, **optsGrid) b_save = tk.Button(self.ecudlg, text="Save", command=self.ecuSaveBtnClick, **btn_style) b_save.grid(row=11, column=1, **optsGrid) b_canc = tk.Button(self.ecudlg, text="Cancel", command=self.ecuCancelBtnClick, **btn_style) b_canc.grid(row=11, column=2, **optsGrid) def renewEcuList(self): self.ecutree.delete(*self.ecutree.get_children()) for ecu in mod_ddt_utils.multikeysort( self.carecus, ['undef','addr']): columns = (ecu['iso8'], ecu['xid'], ecu['rid'], ecu['prot'], ecu['type'], ecu['name'], ecu['xml'], ecu['dump'], ecu) if ecu['undef']=='0': self.ecutree.insert('', 'end', text=ecu['addr'], values=columns, tag='t1') else: self.ecutree.insert('', 'end', text=ecu['addr'], values=columns, tag='') self.ecutree.tag_configure('t1', background = "#fefcef") self.ecutree.update() def applySettings(self): mod_globals.opt_port = self.var_port.get().split(';')[0] mod_globals.opt_rate = int(self.var_speed.get()) mod_globals.opt_can2 = self.var_can2.get() if self.var_log.get(): mod_globals.opt_log = self.var_logName.get() else: mod_globals.opt_log = "" mod_globals.opt_cfc0 = True def xmlBtnClick(self): filename = tkinter.filedialog.askopenfilename(initialdir=mod_globals.ddtroot+'/ecus/', title='Select file', filetypes=[('xml files', '*.xml')]) if '/' in filename: xfn = filename.split('/')[-1] else: xfn = filename.split('\\')[-1] self.dv_xml.set(xfn) return def dumpBtnClick(self): filename = tkinter.filedialog.askopenfilename(initialdir='./dumps/', title='Select file', filetypes=[('txt files', '*.txt')]) if '/' in filename: xfn = filename.split('/')[-1] else: xfn = filename.split('\\')[-1] self.dv_dump.set(xfn) return def ecuSaveBtnClick(self): if self.currentEcu==None: return self.carecus[self.currentEcu]['type'] = self.dv_type.get() self.carecus[self.currentEcu]['name'] = self.dv_name.get() self.carecus[self.currentEcu]['xid'] = self.dv_xid.get() self.carecus[self.currentEcu]['rid'] = self.dv_rid.get() self.carecus[self.currentEcu]['addr'] = self.dv_addr.get() self.carecus[self.currentEcu]['iso8'] = self.dv_iso.get() self.carecus[self.currentEcu]['prot'] = self.dv_pro.get() self.carecus[self.currentEcu]['ses'] = self.dv_ses.get() self.carecus[self.currentEcu]['xml'] = self.dv_xml.get() self.carecus[self.currentEcu]['dump'] = self.dv_dump.get() if self.dv_xml.get()!='': self.carecus[self.currentEcu]['undef'] = '0' else: self.carecus[self.currentEcu]['undef'] = '1' self.ecudlg.destroy() self.renewEcuList() return def ecuCancelBtnClick(self): self.ecudlg.destroy() return def getXmlListByProj(self): self.v_xmlList = [] try: for t in self.eculist[self.dv_addr.get()]['targets']: if self.v_proj.get().upper() in self.eculist[self.dv_addr.get()]['targets'][t]['Projects']: self.v_xmlList.append(t) except: pass def getDumpListByXml(self, xmlname=None): if xmlname==None: self.v_dumpList = [] xml = self.dv_xml.get()[:-4] for root, dirs, files in os.walk("./dumps"): for f in files: if (xml + '.') in f: self.v_dumpList.append(f) else: xmlname = xmlname[:-4] flist = [] for root, dirs, files in os.walk("./dumps"): for f in files: if (xmlname + '.') in f: flist.append(f) if len(flist) == 0: return [] flist.sort() return flist def saveSettings(self): self.save.port = self.var_port.get().split(';')[0] self.save.speed = self.var_speed.get() self.save.log = self.var_log.get() self.save.logName = self.var_logName.get() self.save.cfc = self.var_cfc.get() self.save.dump = self.var_dump.get() self.save.save() def loadSettings(self): self.var_cfc.set(self.save.cfc) self.var_dump.set(self.save.dump) self.var_port.set(self.save.port) self.var_speed.set(self.save.speed) self.var_log.set(self.save.log) self.var_logName.set(self.save.logName) self.var_speedList = ['38400', '115200', '230400', '500000', '1000000', '2000000' ] self.var_portList = mod_ddt_utils.getPortList() if len(self.var_port.get()) == 0: for p in self.var_portList: self.var_port.set(p) if 'OBD' in p: break def main(): '''Main function''' mod_utils.chkDirTree() mod_db_manager.find_DBs() lau = DDTLauncher() print("Done") if __name__ == '__main__': main()