This commit is contained in:
shrlnm 2019-03-09 21:49:14 +03:00
parent bad4ee4654
commit 4dd363777b
13 changed files with 1685 additions and 448 deletions

View File

@ -6,7 +6,7 @@
################################## ##################################
# # # #
# # # #
# Version: 2.0 (02-Feb-2019) # # Version: 2.1 (09-Mar-2019) #
# Author: Shr-Lnm # # Author: Shr-Lnm #
# # # #
# # # #
@ -26,6 +26,14 @@ except:
osname = os.name osname = os.name
currenPath = os.path.dirname(os.path.abspath(__file__))
for f in listdir('.'):
if isdir('./' + f) and f.lower().startswith('pyren') and isdir('./' + f + '/serial'):
sys.path.append(os.path.join(currenPath,f))
sys.path.append(os.path.join(currenPath,f,"serial"))
if osname == 'nt': if osname == 'nt':
import pip import pip

7
pyren/CHANGE_LOG.txt Executable file → Normal file
View File

@ -297,3 +297,10 @@ v 0.9.n (beta)
- подсчет изменений во фреймах в bus_monitor - подсчет изменений во фреймах в bus_monitor
- библиотека pyserial включена в дистрибутив - библиотека pyserial включена в дистрибутив
v 0.9.p (beta)
Исправлено:
- ошибки логирования в mod_elm
- расчет CRC для VIN
Добавлено:
- новый лаунчер mod_ddt.py

0
pyren/README.md Executable file → Normal file
View File

0
pyren/macro/init.txt Executable file → Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@ def trim( st ):
#import traceback #import traceback
import mod_globals import mod_globals
import mod_ddt_utils
from mod_ddt_request import * from mod_ddt_request import *
from mod_ddt_data import * from mod_ddt_data import *
from mod_utils import * from mod_utils import *
@ -215,72 +216,6 @@ class DDTECU():
else: else:
return data return data
def minDist(self, a, b):
""" calculate distance between strings """
""" a - readen value """
""" b - pattern from eculist """
d = 0
if a==b:
return d
try:
d = abs(int(a,16)-int(b,16))
return d
except:
d = 0
l = min(len(a),len(b))
for i in range(0,l):
if b[i]!='?':
d = d + abs(ord(a[i])-ord(b[i]))
return d
def ecuSearch( self, vehTypeCode, Address, DiagVersion, Supplier, Soft, Version, el):
if Address not in el.keys():
return []
ela = el[Address]
print Address, '#', pyren_encode( ela['FuncName'] )
t = ela['targets']
cand = {}
min = 0xFFFFFFFF
kOther = ''
minOther = 0xFFFFFFFF
for k in t.keys():
#print vehTypeCode, t[k]['Projects']
for ai in t[k]['AutoIdents']:
dist = 0
dist = dist + self.minDist(DiagVersion, ai['DiagVersion']) * 1000 # weight
dist = dist + self.minDist(Supplier, ai['Supplier']) * 1 # weight
dist = dist + self.minDist(Soft, ai['Soft']) * 1 # weight
dist = dist + self.minDist(Version, ai['Version']) * 1 # weight
if vehTypeCode in t[k]['Projects'] or dist==0:
if k not in cand.keys (): cand[k] = 0xFFFFFFFF
if dist < cand[k]: cand[k] = dist
if dist < min: min = dist
else:
if dist < minOther:
minOther = dist
kOther = k
print '#'*40
for k in cand.keys():
print "%7s - %s" % ( cand[k], k )
if cand[k]>min:
del cand[k]
print '#'*40
if len(cand)==0 and kOther!='':
cand[kOther] = minOther
return cand.keys()
def scanECU( self ): def scanECU( self ):
global eculist global eculist
@ -324,45 +259,47 @@ class DDTECU():
#DiagVersion F1A0 #DiagVersion F1A0
IdRsp_F1A0 = self.elm.request( req = '22F1A0', positive = '62', cache = False ) IdRsp_F1A0 = self.elm.request( req = '22F1A0', positive = '62', cache = False )
if len(IdRsp_F1A0)>8: if len(IdRsp_F1A0)>8 and 'NR' not in IdRsp_F1A0:
DiagVersion = str(int(IdRsp_F1A0[9:11],16)) DiagVersion = str(int(IdRsp_F1A0[9:11],16))
#if len(DiagVersion)==1 : DiagVersion = '0'+DiagVersion #if len(DiagVersion)==1 : DiagVersion = '0'+DiagVersion
#Supplier F18A #Supplier F18A
IdRsp_F18A = self.elm.request( req = '22F18A', positive = '62', cache = False ) IdRsp_F18A = self.elm.request( req = '22F18A', positive = '62', cache = False )
if len(IdRsp_F18A)>8: if len(IdRsp_F18A)>8 and 'NR' not in IdRsp_F18A:
Supplier = trim(IdRsp_F18A[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore')) Supplier = trim(IdRsp_F18A[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore'))
#Soft F194 #Soft F194
IdRsp_F194 = self.elm.request( req = '22F194', positive = '62', cache = False ) IdRsp_F194 = self.elm.request( req = '22F194', positive = '62', cache = False )
if len(IdRsp_F194)>8: if len(IdRsp_F194)>8 and 'NR' not in IdRsp_F194:
Soft = trim(IdRsp_F194[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore')) Soft = trim(IdRsp_F194[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore'))
#Version F195 #Version F195
IdRsp_F195 = self.elm.request( req = '22F195', positive = '62', cache = False ) IdRsp_F195 = self.elm.request( req = '22F195', positive = '62', cache = False )
if len(IdRsp_F195)>8: if len(IdRsp_F195)>8 and 'NR' not in IdRsp_F195:
Version = trim(IdRsp_F195[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore')) Version = trim(IdRsp_F195[9:].replace(' ','').decode('hex').decode('ASCII', errors='ignore'))
hash = Address+DiagVersion+Supplier+Soft+Version hash = Address+DiagVersion+Supplier+Soft+Version
print 'Address:"%s" DiagVersion:"%s" Supplier:"%s" Soft:"%s" Version:"%s"'%( Address, DiagVersion, Supplier, Soft, Version) print 'Address:"%s" DiagVersion:"%s" Supplier:"%s" Soft:"%s" Version:"%s"'%( Address, DiagVersion, Supplier, Soft, Version)
#make or load eculist eculist = mod_ddt_utils.loadECUlist()
print "Loading eculist"
eculistcache = "./cache/ddt_eculist.p"
if os.path.isfile(eculistcache): #if cache exists ##make or load eculist
eculist = pickle.load( open( eculistcache, "rb" ) ) #load it #print "Loading eculist"
else: #else #eculistcache = "./cache/ddt_eculist.p"
self.loadECUlist() #loading original data #
if eculist == None: return #return if no eculist file #if os.path.isfile(eculistcache): #if cache exists
pickle.dump( eculist, open( eculistcache, "wb" ) ) #and save cache # eculist = pickle.load( open( eculistcache, "rb" ) ) #load it
#else: #else
# eculist = mod_ddt_utils.loadECUlist() #loading original data
# if eculist == None: return #return if no eculist file
# pickle.dump( eculist, open( eculistcache, "wb" ) ) #and save cache
if len(mod_globals.opt_ddtxml)>0: if len(mod_globals.opt_ddtxml)>0:
fname = mod_globals.opt_ddtxml fname = mod_globals.opt_ddtxml
self.ecufname = '../ecus/'+fname self.ecufname = '../ecus/'+fname
else: else:
problist = self.ecuSearch (vehTypeCode, Address, DiagVersion, Supplier, Soft, Version, eculist) problist = ecuSearch(vehTypeCode, Address, DiagVersion, Supplier, Soft, Version, eculist)
while 1: while 1:
print "You may enter the file name by yourself or left empty to exit" print "You may enter the file name by yourself or left empty to exit"
@ -424,6 +361,7 @@ class DDTECU():
if di.Name not in self.cmd4data.keys(): if di.Name not in self.cmd4data.keys():
self.cmd4data[di.Name] = r.Name self.cmd4data[di.Name] = r.Name
'''
def loadECUlist(self): def loadECUlist(self):
global eculist global eculist
@ -477,6 +415,7 @@ class DDTECU():
#eculist[hash] = href #eculist[hash] = href
ail.append(air) ail.append(air)
eculist[Address]["targets"][href]['AutoIdents'] = ail eculist[Address]["targets"][href]['AutoIdents'] = ail
'''
def saveDump( self ): def saveDump( self ):
''' save responces from all 21xx, 22xxxx commands ''' ''' save responces from all 21xx, 22xxxx commands '''
@ -516,11 +455,9 @@ class DDTECU():
ecudump = {} ecudump = {}
xmlname = self.ecufname xmlname = self.ecufname.split('/')[-1]
if xmlname.upper().endswith('.XML'): if xmlname.upper().endswith('.XML'):
xmlname = xmlname[:-4] xmlname = xmlname[:-4]
if xmlname.upper().startswith('../ECUS/'):
xmlname = xmlname[8:]
if len(dumpname)==0: if len(dumpname)==0:
flist = [] flist = []
@ -1077,3 +1014,71 @@ class DDTECU():
return equ return equ
def minDist(a, b):
""" calculate distance between strings """
""" a - readen value """
""" b - pattern from eculist """
d = 0
if a == b:
return d
try:
d = abs(int(a, 16) - int(b, 16))
return d
except:
d = 0
l = min(len(a), len(b))
for i in range(0, l):
if b[i] != '?':
d = d + abs(ord(a[i]) - ord(b[i]))
return d
def ecuSearch(vehTypeCode, Address, DiagVersion, Supplier, Soft, Version, el, interactive = True):
if Address not in el.keys():
return []
ela = el[Address]
if interactive:
print Address, '#', pyren_encode(ela['FuncName'])
t = ela['targets']
cand = {}
min = 0xFFFFFFFF
kOther = ''
minOther = 0xFFFFFFFF
for k in t.keys():
for ai in t[k]['AutoIdents']:
dist = 0
dist = dist + minDist(DiagVersion, ai['DiagVersion']) * 1000 # weight
dist = dist + minDist(Supplier, ai['Supplier']) * 1 # weight
dist = dist + minDist(Soft, ai['Soft']) * 1 # weight
dist = dist + minDist(Version, ai['Version']) * 1 # weight
if vehTypeCode in t[k]['Projects'] or dist == 0:
if k not in cand.keys(): cand[k] = 0xFFFFFFFF
if dist < cand[k]: cand[k] = dist
if dist < min: min = dist
else:
if dist < minOther:
minOther = dist
kOther = k
if interactive:
print '#' * 40
for k in cand.keys():
print "%7s - %s" % (cand[k], k)
if cand[k] > min:
del cand[k]
print '#' * 40
if len(cand) == 0 and kOther != '':
cand[kOther] = minOther
return cand.keys()

View File

@ -139,7 +139,7 @@ class ListDialog (tkSimpleDialog.Dialog):
class DDTScreen (tk.Frame): class DDTScreen (tk.Frame):
tl = 0 tl = 0
updatePeriod = 25 updatePeriod = 50
decu = None decu = None
xmlName = '' xmlName = ''
Screens = {} Screens = {}
@ -166,7 +166,7 @@ class DDTScreen (tk.Frame):
scf = 1.0 # font scale factor scf = 1.0 # font scale factor
def __init__(self, ddtFileName, xdoc, decu): def __init__(self, ddtFileName, xdoc, decu, top = False):
self.xmlName = ddtFileName self.xmlName = ddtFileName
self.xdoc = xdoc self.xdoc = xdoc
@ -178,7 +178,11 @@ class DDTScreen (tk.Frame):
self.decu.screen = self self.decu.screen = self
# init window # init window
if top:
self.root = tk.Toplevel()
else:
self.root = tk.Tk() self.root = tk.Tk()
self.root.option_add ('*Dialog.msg.font', 'Courier New 12') self.root.option_add ('*Dialog.msg.font', 'Courier New 12')
# self.root.overrideredirect(True) # self.root.overrideredirect(True)
self.root.geometry ("1024x768") self.root.geometry ("1024x768")
@ -931,7 +935,11 @@ class DDTScreen (tk.Frame):
else: else:
self.scf = 1.25 # scale font self.scf = 1.25 # scale font
self.root.title (self.xmlName) screenTitle = self.xmlName
if mod_globals.opt_demo:
screenTitle = 'OFF-LINE: ' + screenTitle
self.root.title (screenTitle)
self.style = ttk.Style () self.style = ttk.Style ()
self.style.theme_use ('classic') self.style.theme_use ('classic')
@ -1341,7 +1349,7 @@ class DDTScreen (tk.Frame):
id = self.ddt.create_text (xrLeft, xrTop, text=xText, font=lFont, width=xrWidth, anchor=xAlignment, id = self.ddt.create_text (xrLeft, xrTop, text=xText, font=lFont, width=xrWidth, anchor=xAlignment,
fill=self.ddtColor (xfColor)) fill=self.ddtColor (xfColor))
else: else:
gifname = xText.replace ('::pic:', '../graphics/') + '.gif' gifname = xText.replace ('::pic:', mod_globals.ddtroot+'/graphics/') + '.gif'
gifname = gifname.replace ('\\', '/') gifname = gifname.replace ('\\', '/')
if os.path.isfile (gifname): if os.path.isfile (gifname):
self.images.append (tk.PhotoImage (file=gifname)) self.images.append (tk.PhotoImage (file=gifname))

View File

@ -552,7 +552,7 @@ class ELM:
# self.port = serial.Serial(portName, baudrate=speed, timeout=self.portTimeout) # self.port = serial.Serial(portName, baudrate=speed, timeout=self.portTimeout)
self.port = Port (portName, speed, self.portTimeout) self.port = Port (portName, speed, self.portTimeout)
if len (mod_globals.opt_log) > 0: if len(mod_globals.opt_log)>0: # and mod_globals.opt_demo==False:
self.lf = open ("./logs/elm_" + mod_globals.opt_log, "at") self.lf = open ("./logs/elm_" + mod_globals.opt_log, "at")
self.vf = open ("./logs/ecu_" + mod_globals.opt_log, "at") self.vf = open ("./logs/ecu_" + mod_globals.opt_log, "at")
@ -965,7 +965,11 @@ class ELM:
# save log # save log
if self.vf != 0 and 'NR' not in rsp : if self.vf != 0 and 'NR' not in rsp :
tmstr = datetime.now ().strftime ("%H:%M:%S.%f")[:-3] tmstr = datetime.now ().strftime ("%H:%M:%S.%f")[:-3]
self.vf.write (tmstr + ";" + dnat[self.currentaddress] + ";" + req + ";" + rsp + "\n")
tmp_addr = self.currentaddress
if self.currentaddress in dnat.keys():
tmp_addr = dnat[self.currentaddress]
self.vf.write (tmstr + ";" + tmp_addr + ";" + req + ";" + rsp + "\n")
self.vf.flush () self.vf.flush ()
return rsp return rsp
@ -1100,7 +1104,12 @@ class ELM:
self.lf.flush () self.lf.flush ()
if self.vf != 0: if self.vf != 0:
tmstr = datetime.now ().strftime ("%H:%M:%S.%f")[:-3] tmstr = datetime.now ().strftime ("%H:%M:%S.%f")[:-3]
self.vf.write (tmstr + ";" + dnat[self.currentaddress] + ";" + command + ";" + line + ";" + negrsp[line[6:8]] + "\n")
tmp_addr = self.currentaddress
if self.currentaddress in dnat.keys():
tmp_addr = dnat[self.currentaddress]
self.vf.write (tmstr + ";" + tmp_addr + ";" + command + ";" + line + ";" + negrsp[line[6:8]] + "\n")
self.vf.flush () self.vf.flush ()
return cmdrsp return cmdrsp
@ -1786,8 +1795,15 @@ class ELM:
self.l1_cache = {} self.l1_cache = {}
self.clear_cache() self.clear_cache()
if addr in dnat.keys():
TXa = dnat[addr] TXa = dnat[addr]
else:
TXa = 'undefined'
if addr in snat.keys():
RXa = snat[addr] RXa = snat[addr]
else:
RXa = 'undefined'
self.check_answer (self.cmd ("at sh " + TXa)) self.check_answer (self.cmd ("at sh " + TXa))
self.check_answer (self.cmd ("at cra " + RXa)) self.check_answer (self.cmd ("at cra " + RXa))

View File

@ -40,6 +40,8 @@ none_val = 'None'
mtcdir = '../MTCSAVE/VIN' mtcdir = '../MTCSAVE/VIN'
ddtroot = '..' # parent folder for backward compatibility. for 9n and up use ../DDT2000data
os = "" os = ""
language_dict = {} language_dict = {}

View File

@ -840,6 +840,103 @@ class ScanEcus:
row['rerr'] = rerr row['rerr'] = rerr
self.detectedEcus.append(row) self.detectedEcus.append(row)
def readECUIds( elm ):
# clear cache
elm.clear_cache()
StartSession = ''
DiagVersion = ''
Supplier = ''
Version = ''
Soft = ''
Std = ''
VIN = ''
rsp = ''
# check session start command
if elm.startSession == '':
# check 10C0
res = elm.request(req='10C0', positive='50', cache=False)
if res=='' or 'ERROR' in res: # no response from ecu
return StartSession, DiagVersion, Supplier, Version, Soft, Std, VIN
if res.startswith('50'):
StartSession = '10C0'
else:
res = elm.request(req='1003', positive='50', cache=False)
if res.startswith('50'):
StartSession = '1003'
else:
StartSession = elm.startSession
res = elm.request(req=elm.startSession, positive='50', cache=False)
if not res.startswith('50'):
# debug
# print 'ERROR: Could not open the session
pass
# check STD_A
IdRsp = elm.request(req='2180', positive='61', cache=False)
''' 0 1 2 3 4 5 6 7 '''
''' 01234567890123456789012345678901234567890123456789012345678901234567890123456'''
# Debug
# IdRsp = '61 80 34 36 33 32 52 45 34 42 45 30 30 33 37 52 00 83 9D 00 1A 90 01 01 00 88 AA'
''' -- -------- ----- ----- '''
''' DiagVersion--+ | | +--Version '''
''' Supplier--+ +--Soft '''
if len(IdRsp) > 59:
DiagVersion = str(int(IdRsp[21:23], 16))
Supplier = IdRsp[24:32].replace(' ', '').strip().decode('hex').decode('ASCII', errors='ignore')
Soft = IdRsp[48:53].strip().replace(' ', '')
Version = IdRsp[54:59].strip().replace(' ', '')
Std = 'STD_A'
vinRsp = elm.request(req='2181', positive='61', cache=False)
# debug
# vinRsp = '61 81 56 46 31 30 30 30 30 30 30 30 30 30 30 30 30 30 30 00 00 00 00 00 00 00 00'
if len(vinRsp)>55 and 'NR' not in vinRsp:
VIN = vinRsp[6:56].strip().replace(' ', '').decode('hex').decode('ASCII', errors='ignore')
else:
try:
# DiagVersion F1A0
IdRsp_F1A0 = elm.request(req='22F1A0', positive='62', cache=False)
if len(IdRsp_F1A0) > 8 and 'NR' not in IdRsp_F1A0 and 'BUS' not in IdRsp_F1A0:
DiagVersion = str(int(IdRsp_F1A0[9:11], 16))
# Supplier F18A
IdRsp_F18A = elm.request(req='22F18A', positive='62', cache=False)
if len(IdRsp_F18A) > 8 and 'NR' not in IdRsp_F18A and 'BUS' not in IdRsp_F18A:
Supplier = IdRsp_F18A[9:].strip().replace(' ', '').decode('hex').decode('ASCII', errors='ignore')
# Soft F194
IdRsp_F194 = elm.request(req='22F194', positive='62', cache=False)
if len(IdRsp_F194) > 8 and 'NR' not in IdRsp_F194 and 'BUS' not in IdRsp_F194:
Soft = IdRsp_F194[9:].strip().replace(' ', '').decode('hex').decode('ASCII', errors='ignore')
# Version F195
IdRsp_F195 = elm.request(req='22F195', positive='62', cache=False)
if len(IdRsp_F195) > 8 and 'NR' not in IdRsp_F195 and 'BUS' not in IdRsp_F195:
Version = IdRsp_F195[9:].strip().replace(' ', '').decode('hex').decode('ASCII', errors='ignore')
Std = 'STD_B'
# Vin F190
vinRsp = elm.request(req='22F190', positive='62', cache=False)
if len(vinRsp) > 58:
VIN = vinRsp[9:59].strip().replace(' ', '').decode('hex').decode('ASCII', errors='ignore')
except:
pass
return StartSession, DiagVersion, Supplier, Version, Soft, Std, VIN
def findTCOM( addr, cmd, rsp ): def findTCOM( addr, cmd, rsp ):
ecuvhc = {} ecuvhc = {}
vehicle = '' vehicle = ''

View File

@ -295,8 +295,11 @@ def hex_VIN_plus_CRC( VIN ):
b2 = CRC & 0xFF b2 = CRC & 0xFF
CRC = ((b2 << 8) | b1) & 0xFFFF CRC = ((b2 << 8) | b1) & 0xFFFF
sCRC = hex( CRC )[2:].upper()
sCRC = '0'*(4-len(sCRC))+sCRC
# result # result
return hexVIN+hex( CRC )[2:].upper() return hexVIN+sCRC
# Test # Test
if __name__ == "__main__": if __name__ == "__main__":
@ -364,6 +367,19 @@ def loadDumpToELM( ecuname, elm ):
elm.setDump( ecudump ) elm.setDump( ecudump )
def chkDirTree():
'''Check direcories'''
if not os.path.exists('./cache'):
os.makedirs('./cache')
if not os.path.exists('./csv'):
os.makedirs('./csv')
if not os.path.exists('./logs'):
os.makedirs('./logs')
if not os.path.exists('./dumps'):
os.makedirs('./dumps')
if not os.path.exists('./macro'):
os.makedirs('./macro')
def getVIN( de, elm ): def getVIN( de, elm ):
''' getting VINs from every ECU ''' ''' getting VINs from every ECU '''

View File

@ -2,6 +2,7 @@
import sys, os import sys, os
import mod_globals import mod_globals
import mod_utils
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
@ -12,17 +13,6 @@ mod_globals.os = os.name
if mod_globals.os == 'nt': if mod_globals.os == 'nt':
import pip import pip
#try:
# import psutil
#except ImportError:
# pip.main(['install','psutil'])
#try:
# import psutil
# p = psutil.Process(os.getpid())
# p.nice(psutil.HIGH_PRIORITY_CLASS)
#except ImportError:
# pass
try: try:
import serial import serial
except ImportError: except ImportError:
@ -75,7 +65,7 @@ def optParser():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
#usage = "%prog -p <port> [options]", #usage = "%prog -p <port> [options]",
version="pyRen Version 0.9.n", version="pyRen Version 0.9.p",
description = "pyRen - python program for diagnostic Renault cars" description = "pyRen - python program for diagnostic Renault cars"
) )
@ -244,15 +234,7 @@ def main():
optParser() optParser()
'''Check direcories''' mod_utils.chkDirTree()
if not os.path.exists('./cache'):
os.makedirs('./cache')
if not os.path.exists('./csv'):
os.makedirs('./csv')
if not os.path.exists('./logs'):
os.makedirs('./logs')
if not os.path.exists('./dumps'):
os.makedirs('./dumps')
print 'Opening ELM' print 'Opening ELM'
elm = ELM( mod_globals.opt_port, mod_globals.opt_speed, mod_globals.opt_log ) elm = ELM( mod_globals.opt_port, mod_globals.opt_speed, mod_globals.opt_log )