From d36c6558bd26dd7b262b198c6355079c8ff38cc2 Mon Sep 17 00:00:00 2001 From: Marianpol Date: Mon, 15 Feb 2021 12:16:36 +0100 Subject: [PATCH 1/2] Fix --- pyren/mod_ecu.py | 104 ++++++++++++++++++++++++++++------------------- pyren/mod_elm.py | 49 +++++++++++++--------- 2 files changed, 93 insertions(+), 60 deletions(-) diff --git a/pyren/mod_ecu.py b/pyren/mod_ecu.py index eca93ac..f3b0208 100755 --- a/pyren/mod_ecu.py +++ b/pyren/mod_ecu.py @@ -24,6 +24,7 @@ import mod_db_manager from xml.dom.minidom import parse from datetime import datetime +from collections import OrderedDict from mod_utils import show_doc import xml.dom.minidom #import xml.etree.ElementTree as et @@ -432,7 +433,8 @@ class ECU: tb = time.time() #time of begining if len(datarefs)==0 and 'DE' not in path: return - + self.elm.clear_cache() + tmpArray = OrderedDict() if mod_globals.opt_csv and mod_globals.opt_csv_only: print "Data is sending directly to csv-file" @@ -457,49 +459,60 @@ class ECU: # csvf.write(pyren_decode(csvline).encode('utf8') if mod_globals.opt_csv_human else csvline) csvf.flush() csvline = datetime.now().strftime("%H:%M:%S.%f") - + + if mod_globals.opt_perform: + if not tmpArray or tmpArray.keys()[-1].startswith('21') : + for x in self.elm.rsp_cache.keys(): + if (x.startswith('22') and len(x) > 6) or x.startswith('21') or len(self.elm.rsp_cache) == 1: + tmpArray[x] = x + if len(self.elm.currentScreenDataIds) > 1: + tmpArray["22" + self.elm.currentScreenDataIds[-1][0].id] = "22" + self.elm.currentScreenDataIds[-1][0].id + self.elm.clear_cache() - - for dr in datarefs: - datastr = dr.name - help = dr.type - if dr.type=='State': - if self.DataIds and "DTC" in path and dr in self.Defaults[mod_globals.ext_cur_DTC[:4]].memDatarefs: - datastr, help, csvd = get_state( self.States[dr.name], self.Mnemonics, self.Services, self.elm, self.calc, self.DataIds ) - else: - datastr, help, csvd = get_state( self.States[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) - if dr.type=='Parameter': - if self.DataIds and "DTC" in path and dr in self.Defaults[mod_globals.ext_cur_DTC[:4]].memDatarefs: - datastr, help, csvd = get_parameter( self.Parameters[dr.name], self.Mnemonics, self.Services, self.elm, self.calc, self.DataIds ) - else: - datastr, help, csvd = get_parameter( self.Parameters[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) - if dr.type=='Identification': - datastr, help, csvd = get_identification( self.Identifications[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) - if dr.type=='Command': - datastr = dr.name + " [Command] " + self.Commands[dr.name].label - if dr.type=="Text": + if not (tmpArray and mod_globals.opt_csv_only): + for dr in datarefs: datastr = dr.name - help = "" - if mod_globals.opt_csv and csvf!=0 and (dr.type=='State' or dr.type=='Parameter'): - csvline += ";" + (pyren_encode(csvd) if mod_globals.opt_csv_human else str(csvd)) + help = dr.type + if dr.type=='State': + if self.DataIds and "DTC" in path and dr in self.Defaults[mod_globals.ext_cur_DTC[:4]].memDatarefs: + datastr, help, csvd = get_state( self.States[dr.name], self.Mnemonics, self.Services, self.elm, self.calc, self.DataIds ) + else: + datastr, help, csvd = get_state( self.States[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) + if dr.type=='Parameter': + if self.DataIds and "DTC" in path and dr in self.Defaults[mod_globals.ext_cur_DTC[:4]].memDatarefs: + datastr, help, csvd = get_parameter( self.Parameters[dr.name], self.Mnemonics, self.Services, self.elm, self.calc, self.DataIds ) + else: + datastr, help, csvd = get_parameter( self.Parameters[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) + if dr.type=='Identification': + datastr, help, csvd = get_identification( self.Identifications[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) + if dr.type=='Command': + datastr = dr.name + " [Command] " + self.Commands[dr.name].label + if dr.type=="Text": + datastr = dr.name + help = "" + if mod_globals.opt_csv and csvf!=0 and (dr.type=='State' or dr.type=='Parameter'): + csvline += ";" + (pyren_encode(csvd) if mod_globals.opt_csv_human else str(csvd)) - if not (mod_globals.opt_csv and mod_globals.opt_csv_only): - strlst.append(datastr) - if mod_globals.opt_verbose and len(help)>0: - tmp_str = '' - for s in help: - #s = s.replace('\n','\n\t') - s = s.replace('\r','\n') - s = s.replace('>','>') - s = s.replace('≤','<') - tmp_str = tmp_str + s + '\n\n' - W = 50 - for line in tmp_str.split('\n'): - i = 0 - while i*W0: + tmp_str = '' + for s in help: + #s = s.replace('\n','\n\t') + s = s.replace('\r','\n') + s = s.replace('>','>') + s = s.replace('≤','<') + tmp_str = tmp_str + s + '\n\n' + W = 50 + for line in tmp_str.split('\n'): + i = 0 + while i*W0: # and mod_globals.opt_demo==False: 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+") if mod_globals.opt_debug and mod_globals.debug_file==None: mod_globals.debug_file = open ("./logs/debug.txt", "at") @@ -590,7 +590,7 @@ class ELM: # check OBDLink elm_rsp = self.cmd("STPR") - if '?' not in elm_rsp: + if elm_rsp and '?' not in elm_rsp: mod_globals.opt_obdlink = True # check STN @@ -599,10 +599,10 @@ class ELM: mod_globals.opt_stn = True # Max out the UART speed for the fastest polling rate - if mod_globals.opt_csv: + if mod_globals.opt_csv and not mod_globals.opt_demo: if mod_globals.opt_obdlink: self.port.soft_boudrate(2000000) - elif self.port.portType == 0: + else: self.port.soft_boudrate(230400) def __del__(self): @@ -1205,8 +1205,9 @@ class ELM: cmd_len = len (command) / 2 if cmd_len < 8: # single frame # check L1 cache here - if isCommandInCache and int('0x' + self.l1_cache[commandString], 16) < 16: - raw_command.append (("%0.2X" % cmd_len) + command + self.l1_cache[command]) + # if isCommandInCache and int('0x' + self.l1_cache[commandString], 16) < 16: + if isCommandInCache: + raw_command.append ("STPX D:" + ("%0.2X" % cmd_len) + command + ",R:" +self.l1_cache[command]) else: raw_command.append (("%0.2X" % cmd_len) + command) else: @@ -1223,15 +1224,20 @@ class ELM: # add response frames number to each frame to increase polling if mod_globals.opt_obdlink and mod_globals.opt_perform: if commandString[:2] in AllowedList and isCommandInCache: - if int('0x' + self.l1_cache[commandString], 16) < 16: - for index in range(len(raw_command) - 1): - raw_command[index] = raw_command[index] + '1' - raw_command[-1] = raw_command[-1] + self.l1_cache[commandString] - else: - readyFrame = '' - for f in raw_command: - readyFrame += f - raw_command = ["STPX D:" + readyFrame + ",R:" + self.l1_cache[commandString]] + readyFrame = '' + for f in raw_command: + readyFrame += f + raw_command = ["STPX D:" + readyFrame + ",R:" + self.l1_cache[commandString]] + + # if int('0x' + self.l1_cache[commandString], 16) < 16: + # for index in range(len(raw_command) - 1): + # raw_command[index] = raw_command[index] + '1' + # raw_command[-1] = raw_command[-1] + self.l1_cache[commandString] + # else: + # readyFrame = '' + # for f in raw_command: + # readyFrame += f + # raw_command = ["STPX D:" + readyFrame + ",R:" + self.l1_cache[commandString]] responses = [] @@ -1301,10 +1307,10 @@ class ELM: # populate L1 cache if noerrors and commandString[:2] in AllowedList and not mod_globals.opt_n1c: - if nframes < 16: - self.l1_cache[commandString] = str(hex(nframes))[2:].upper() - else: #for OBDLink STPX command - self.l1_cache[commandString] = str(nframes) + # if nframes < 16: + # self.l1_cache[commandString] = str(hex(nframes))[2:].upper() + # else: #for OBDLink STPX command + self.l1_cache[commandString] = str(nframes) if len (result) / 2 >= nbytes and noerrors: # split by bytes and return @@ -1962,6 +1968,11 @@ class ELM: self.check_answer (self.cmd ("at at 1")) # reset adaptive timing step 3 self.check_answer (self.cmd ("at cra " + RXa)) + + self.check_answer (self.cmd ("at sh 35C")) + self.send_raw ("FA 40 00 00 00 20 60 04") + self.check_answer (self.cmd ("at sh " + TXa)) + self.check_adapter () def init_iso(self): From 04e089591c247506e777ba730e92d26b1a1aec38 Mon Sep 17 00:00:00 2001 From: Marianpol Date: Wed, 17 Feb 2021 22:14:38 +0100 Subject: [PATCH 2/2] csv_only mode upgrade --- pyren/mod_ecu.py | 133 ++++++++++++++++++++++++++----------- pyren/mod_ecu_parameter.py | 3 +- pyren/mod_ecu_state.py | 2 +- pyren/mod_elm.py | 42 ++++-------- pyren/pyren.py | 1 + 5 files changed, 113 insertions(+), 68 deletions(-) diff --git a/pyren/mod_ecu.py b/pyren/mod_ecu.py index f3b0208..133625a 100755 --- a/pyren/mod_ecu.py +++ b/pyren/mod_ecu.py @@ -398,11 +398,10 @@ class ECU: nparams = 0 for dr in datarefs: if dr.type=='State': - csvline += ";" + self.States[dr.name].codeMR + (":" + self.States[dr.name].label if mod_globals.opt_csv_human else "") + csvline += ";" + self.States[dr.name].codeMR + ":" + self.States[dr.name].label nparams += 1 if dr.type=='Parameter': - csvline += (";" + self.Parameters[dr.name].codeMR + (":" +self.Parameters[dr.name].label if mod_globals.opt_csv_human else "") + - " [" + self.Parameters[dr.name].unit + "]") + csvline += (";" + self.Parameters[dr.name].codeMR + ":" +self.Parameters[dr.name].label + " [" + self.Parameters[dr.name].unit + "]") nparams += 1 if mod_globals.opt_usrkey: csvline += ";User events" csvline = pyren_encode(csvline) @@ -434,25 +433,37 @@ class ECU: if len(datarefs)==0 and 'DE' not in path: return self.elm.clear_cache() - tmpArray = OrderedDict() + + #csv_only mode workflow in performance mode + #1. Read all parameters from the current screen using defalut mode + #2. Get all dataIds from the 22 service requests and create a list from them according to a module performance level + #3. Collect all 21 service requests and push them into requests list + #4. Create a complex requests from the all dataIds list and push them into requests list + #5. Send reqests from the requests list and save the responses in a responseHistory list + #6. On exit generate csv log file from the responseHistory - if mod_globals.opt_csv and mod_globals.opt_csv_only: + if mod_globals.opt_csv_only: print "Data is sending directly to csv-file" print "" print "Press any key to exit" page = 0 + + displayedDataIds = [] #Current screen dataIds list for csv_only mode + responseHistory = OrderedDict() + requests = OrderedDict() #list of requests to send in csv_only mode while(True): strlst = [] + datarefsRequestTime = int(round(time.time() * 1000)) - if mod_globals.opt_csv and csvf!=0: + if mod_globals.opt_csv_human and csvf!=0: csvline = csvline + "\n" #csvline = csvline.replace('.',',') #csvline = csvline.replace(',','.') csvline = csvline.replace(';','\t') - csvf.write(pyren_decode(csvline).encode('utf8') if mod_globals.opt_csv_human else csvline) + csvf.write(pyren_decode(csvline).encode('utf8')) #if mod_globals.os == 'nt' or mod_globals.os == 'android': # csvf.write(pyren_decode(csvline).encode('cp1251') if mod_globals.opt_csv_human else csvline) #else: @@ -460,16 +471,14 @@ class ECU: csvf.flush() csvline = datetime.now().strftime("%H:%M:%S.%f") - if mod_globals.opt_perform: - if not tmpArray or tmpArray.keys()[-1].startswith('21') : - for x in self.elm.rsp_cache.keys(): - if (x.startswith('22') and len(x) > 6) or x.startswith('21') or len(self.elm.rsp_cache) == 1: - tmpArray[x] = x - if len(self.elm.currentScreenDataIds) > 1: - tmpArray["22" + self.elm.currentScreenDataIds[-1][0].id] = "22" + self.elm.currentScreenDataIds[-1][0].id + #Collect all the requests from the current screen + if mod_globals.opt_perform and self.elm.performanceModeLevel > 1 and mod_globals.opt_csv_only: + if self.elm.rsp_cache: + if not requests: + requests = self.generateRequestsList() self.elm.clear_cache() - if not (tmpArray and mod_globals.opt_csv_only): + if not (mod_globals.opt_csv_only and requests): for dr in datarefs: datastr = dr.name help = dr.type @@ -490,8 +499,8 @@ class ECU: if dr.type=="Text": datastr = dr.name help = "" - if mod_globals.opt_csv and csvf!=0 and (dr.type=='State' or dr.type=='Parameter'): - csvline += ";" + (pyren_encode(csvd) if mod_globals.opt_csv_human else str(csvd)) + if mod_globals.opt_csv_human and csvf!=0 and (dr.type=='State' or dr.type=='Parameter'): + csvline += ";" + pyren_encode(csvd) if not (mod_globals.opt_csv and mod_globals.opt_csv_only): strlst.append(datastr) @@ -510,8 +519,8 @@ class ECU: strlst.append('\t'+line[i*W:(i+1)*W]) i=i+1 strlst.append('') - else: - for req in tmpArray: + else: #Send requests, do not calculate data + for req in requests: self.elm.request(req) if not (mod_globals.opt_csv and mod_globals.opt_csv_only): @@ -548,8 +557,13 @@ class ECU: time.sleep(tb + self.minimumrefreshrate - tc) tb = tc - if mod_globals.opt_perform: - self.elm.currentScreenDataIds = self.getDataIds(self.elm.rsp_cache.keys(), self.DataIds) + if mod_globals.opt_csv_only: + responseHistory[datarefsRequestTime] = self.elm.rsp_cache #Collect data to generate a file + + if mod_globals.opt_perform and self.elm.performanceModeLevel > 1: + self.elm.currentScreenDataIds = self.getDataIds(self.elm.rsp_cache, self.DataIds) + if self.elm.currentScreenDataIds: #DataIds list is generated only at first data read pass in csv_only mode + displayedDataIds = self.elm.currentScreenDataIds #We save it for file generating function if kb.kbhit(): c = kb.getch() @@ -565,8 +579,11 @@ class ECU: continue kb.set_normal_term() if mod_globals.opt_csv and csvf!=0: - csvf.close() - self.saveFavList() + self.saveFavList() + if mod_globals.opt_csv_human: + csvf.close() + return + self.createFile(responseHistory, displayedDataIds, csvline, csvf, datarefs) return else: n = ord(c)-ord('0') @@ -592,19 +609,58 @@ class ECU: continue kb.set_normal_term() if mod_globals.opt_csv and csvf!=0: - csvf.close() - # self.elm.vf.read() - # with open ("./logs/ecu_" + mod_globals.opt_log, "r") as f: - # for line in f: - # print line - for line in self.elm.vf: - print line - raw_input() - # raw_input('2322232') - # self.elm.vf.read() + if mod_globals.opt_csv_human: + csvf.close() + return + self.createFile(responseHistory, displayedDataIds, csvline, csvf, datarefs) if "DTC" in path: mod_globals.ext_cur_DTC = "000000" return + + def generateRequestsList(self): + requests = OrderedDict() + + currentScreenDataIdsLength = len(self.elm.currentScreenDataIds) + for reqDidsIndex in range(currentScreenDataIdsLength): #Create complex requests from all 22 requests + firstRequest = '22' + self.elm.currentScreenDataIds[0][0].id + complexRequest, sentDataIdentifires = prepareComplexRequest(firstRequest, self.elm.currentScreenDataIds) + requests[complexRequest] = complexRequest + for req in self.elm.rsp_cache.keys(): #Get all the 21 requests + if req.startswith('21'): + requests[req] = req + + return requests + + def createFile(self, responseHistory, displayedDataIds, csvline, csvf, datarefs): + clearScreen() + print 'Generating a file. Please wait...' + + for reqTime, reqCache in responseHistory.iteritems(): + for req, rsp in reqCache.iteritems(): + if req.startswith('22') and len(req) > 6: + for reqDids in displayedDataIds: + if reqDids[0].id == req[2:6]: + parseComplexResponse(self.elm, '62', rsp.replace(' ', ''), reqDids) + else: + self.elm.rsp_cache[req] = rsp + + csvline = csvline + "\n" + csvline = csvline.replace(';','\t') + csvf.write(pyren_decode(csvline).encode('utf8')) + csvf.flush() + csvline = datetime.fromtimestamp(reqTime/1000.0).strftime("%H:%M:%S.%f")[:-3] + + for dr in datarefs: + datastr = dr.name + help = dr.type + if dr.type=='State': + datastr, help, csvd = get_state( self.States[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) + if dr.type=='Parameter': + datastr, help, csvd = get_parameter( self.Parameters[dr.name], self.Mnemonics, self.Services, self.elm, self.calc ) + if csvf!=0 and (dr.type=='State' or dr.type=='Parameter'): + csvline += ";" + pyren_encode(csvd) + + csvf.close() def add_favourite(self): H = 25 @@ -1066,13 +1122,14 @@ class ECU: if self.elm.performanceModeLevel == 1: return dataIdsList - for key in cache: - if key.startswith('22'): - if key[2:] in dataids.keys(): - dataIdsList.append(dataids[key[2:]]) + for req in cache: + if req.startswith('22'): + if req[2:] in dataids.keys(): + if req not in self.elm.notSupportedCommands: + dataIdsList.append(dataids[req[2:]]) chunk_size = self.elm.performanceModeLevel - if dataIdsList: + if dataIdsList: # split dataIdsList into chunks based on the performace level return [dataIdsList[offset:offset+chunk_size] for offset in range(0, len(dataIdsList), chunk_size)] diff --git a/pyren/mod_ecu_parameter.py b/pyren/mod_ecu_parameter.py index b518082..1aadba8 100755 --- a/pyren/mod_ecu_parameter.py +++ b/pyren/mod_ecu_parameter.py @@ -31,9 +31,10 @@ def get_parameter( pr, mn, se, elm, calc, dataids = {} ): comp = comp.replace(m, val) pr.value = calc.calculate(comp) - csv_data = unicode(pr.value) if mod_globals.opt_csv_human else pr.value + if '.' in str(pr.value): pr.value = "%10.2f"%float(pr.value) + csv_data = unicode(pr.value) tmpmin = str(pr.min) tmpmax = str(pr.max) diff --git a/pyren/mod_ecu_state.py b/pyren/mod_ecu_state.py index 3688328..53e1e0d 100755 --- a/pyren/mod_ecu_state.py +++ b/pyren/mod_ecu_state.py @@ -23,7 +23,7 @@ def get_state( st, mn, se, elm, calc, dataids = {} ): else: st.value = str(tmp_val).encode("utf-8") - csv_val = unicode(st.value) if mod_globals.opt_csv_human else tmp_val + csv_val = unicode(st.value) if mod_globals.os=='android': st.value = " "*(8-len(st.value)/2) + st.value return "%-6s %-41s %-16s"%(st.codeMR,st.label,st.value), st.helps, csv_val diff --git a/pyren/mod_elm.py b/pyren/mod_elm.py index 6a3f62e..57497db 100644 --- a/pyren/mod_elm.py +++ b/pyren/mod_elm.py @@ -575,7 +575,7 @@ class ELM: if len(mod_globals.opt_log)>0: # and mod_globals.opt_demo==False: 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") if mod_globals.opt_debug and mod_globals.debug_file==None: mod_globals.debug_file = open ("./logs/debug.txt", "at") @@ -602,7 +602,7 @@ class ELM: if mod_globals.opt_csv and not mod_globals.opt_demo: if mod_globals.opt_obdlink: self.port.soft_boudrate(2000000) - else: + elif self.port.portType == 0: self.port.soft_boudrate(230400) def __del__(self): @@ -1205,9 +1205,8 @@ class ELM: cmd_len = len (command) / 2 if cmd_len < 8: # single frame # check L1 cache here - # if isCommandInCache and int('0x' + self.l1_cache[commandString], 16) < 16: - if isCommandInCache: - raw_command.append ("STPX D:" + ("%0.2X" % cmd_len) + command + ",R:" +self.l1_cache[command]) + if isCommandInCache and int('0x' + self.l1_cache[commandString], 16) < 16: + raw_command.append (("%0.2X" % cmd_len) + command + self.l1_cache[command]) else: raw_command.append (("%0.2X" % cmd_len) + command) else: @@ -1224,20 +1223,12 @@ class ELM: # add response frames number to each frame to increase polling if mod_globals.opt_obdlink and mod_globals.opt_perform: if commandString[:2] in AllowedList and isCommandInCache: - readyFrame = '' - for f in raw_command: - readyFrame += f - raw_command = ["STPX D:" + readyFrame + ",R:" + self.l1_cache[commandString]] - - # if int('0x' + self.l1_cache[commandString], 16) < 16: - # for index in range(len(raw_command) - 1): - # raw_command[index] = raw_command[index] + '1' - # raw_command[-1] = raw_command[-1] + self.l1_cache[commandString] - # else: - # readyFrame = '' - # for f in raw_command: - # readyFrame += f - # raw_command = ["STPX D:" + readyFrame + ",R:" + self.l1_cache[commandString]] + for index in range(len(raw_command) - 1): + raw_command[index] = raw_command[index] + '1' + if int('0x' + self.l1_cache[commandString], 16) < 16: + raw_command[-1] = raw_command[-1] + self.l1_cache[commandString] + else: + raw_command[-1] = "STPX D:" + raw_command[-1] + ",R:" + self.l1_cache[commandString] responses = [] @@ -1307,10 +1298,10 @@ class ELM: # populate L1 cache if noerrors and commandString[:2] in AllowedList and not mod_globals.opt_n1c: - # if nframes < 16: - # self.l1_cache[commandString] = str(hex(nframes))[2:].upper() - # else: #for OBDLink STPX command - self.l1_cache[commandString] = str(nframes) + if nframes < 16: + self.l1_cache[commandString] = str(hex(nframes))[2:].upper() + else: #for OBDLink STPX command + self.l1_cache[commandString] = str(nframes) if len (result) / 2 >= nbytes and noerrors: # split by bytes and return @@ -1968,11 +1959,6 @@ class ELM: self.check_answer (self.cmd ("at at 1")) # reset adaptive timing step 3 self.check_answer (self.cmd ("at cra " + RXa)) - - self.check_answer (self.cmd ("at sh 35C")) - self.send_raw ("FA 40 00 00 00 20 60 04") - self.check_answer (self.cmd ("at sh " + TXa)) - self.check_adapter () def init_iso(self): diff --git a/pyren/pyren.py b/pyren/pyren.py index 56a25d2..6bb7b5c 100755 --- a/pyren/pyren.py +++ b/pyren/pyren.py @@ -219,6 +219,7 @@ def optParser(): mod_globals.opt_scan = options.scan mod_globals.opt_csv = options.csv mod_globals.opt_csv_only = options.csv_only + if mod_globals.opt_csv : mod_globals.opt_csv_human = True if mod_globals.opt_csv_only : mod_globals.opt_csv = True mod_globals.opt_csv_human = options.csv_human if mod_globals.opt_csv_human : mod_globals.opt_csv = True