diff --git a/pyren/mod_ecu.py b/pyren/mod_ecu.py index 9431dc4..a8007cc 100755 --- a/pyren/mod_ecu.py +++ b/pyren/mod_ecu.py @@ -150,6 +150,9 @@ class ECU: self.elm.start_session( self.ecudata['startDiagReq'] ) + if self.ecudata['pin'].lower()=='can' and self.DataIds: + self.elm.checkPerformaceLevel(self.DataIds) + print "Done" global ecudump @@ -347,8 +350,9 @@ class ECU: else: initScreen = chr(27)+"[2J"+chr(27)+"[;H" - csvf = 0 + self.elm.currentScreenDataIds = [] + mask = False masks = [] datarefsToRemove = [] @@ -386,6 +390,7 @@ class ECU: if mod_globals.opt_csv and mod_globals.ext_cur_DTC == '000000': # prepare to csv save self.minimumrefreshrate = 0 + mod_globals.opt_perform = True csvline = "sep=\\t\n" csvline += u"Time" nparams = 0 @@ -527,6 +532,8 @@ class ECU: time.sleep(tb + self.minimumrefreshrate - tc) tb = tc + self.elm.currentScreenDataIds = self.getDataIds(self.elm.rsp_cache.keys(), self.DataIds) + if kb.kbhit(): c = kb.getch() if len(c)!=1: continue @@ -1026,6 +1033,23 @@ class ECU: map[key] = label return map + + def getDataIds(self, cache, dataids): + dataIdsList = [] + 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:]]) + + chunk_size = self.elm.performanceModeLevel + 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)] + + return dataIdsList def bukva( bt, l, sign = False ): S1 = chr((bt-l) % 26 + ord('A')) diff --git a/pyren/mod_ecu_service.py b/pyren/mod_ecu_service.py index c49d31c..90fb9a9 100755 --- a/pyren/mod_ecu_service.py +++ b/pyren/mod_ecu_service.py @@ -58,8 +58,14 @@ def executeService( service, elm, status = [], param = "", cache = False ): #tb = time.time() #start time #tc = tb + sentDataIdentifires = [] #dataids sent in one 22 request, nedded for a response parse + performanceMode = mod_globals.opt_perform and elm.performanceModeLevel > 1 + commandToSend = service.startReq - + + if performanceMode and elm.currentScreenDataIds: + commandToSend, sentDataIdentifires = prepareComplexRequest(service.startReq, elm.currentScreenDataIds) + if len(service.params)>0: # but I support only one and do not support SnapShot if service.params[0]['type']=='DTC': param = mod_globals.ext_cur_DTC @@ -78,6 +84,9 @@ def executeService( service, elm, status = [], param = "", cache = False ): rsp = rspStrip( rsp, commandToSend ) first_rsp = rsp + if performanceMode and sentDataIdentifires: + first_rsp = parseComplexResponse(elm, service.simpleRsp, rsp, sentDataIdentifires) + #print "Status:", status #print "Delay:",localDelay, #print "startReq ", service.startReq @@ -151,6 +160,43 @@ def executeService( service, elm, status = [], param = "", cache = False ): print "\nSomething went wrong. Counter reached maximum value.\n" return "" +def prepareComplexRequest(request, screenDataIds): + commandToSend = request + sentDataIdentifires = [] + screenDataIdsNumber = len(screenDataIds[0]) + + if screenDataIdsNumber > 1: + firstDataId = screenDataIds[0][0].id + if firstDataId == request[2:]: + commandToSend = request[:2] + for did in screenDataIds[0]: + commandToSend += did.id + + sentDataIdentifires = screenDataIds.pop(0) + + return commandToSend, sentDataIdentifires + +def parseComplexResponse(elm, positiveRsp, response, sentDataIds): + first_rsp = '' + posInResp = 2 + byteLength = 2 + sentDataIdsLength = len(sentDataIds) + + for i in range(sentDataIdsLength): + dataId = response[posInResp:posInResp + 2 * byteLength] + posInResp += 2 * byteLength + didDataLength = int(sentDataIds[i].dataBitLength)/8 + didData = response[posInResp: posInResp + didDataLength * byteLength] + posInResp += didDataLength * byteLength + if i == 0: + first_rsp = positiveRsp + dataId + didData + + resp = positiveRsp + dataId + didData + resp = ' '.join(a+b for a,b in zip(resp[::2], resp[1::2])) + + elm.rsp_cache['22' + dataId] = resp + + return first_rsp class ecu_service: diff --git a/pyren/mod_elm.py b/pyren/mod_elm.py index e7ef236..d6275fb 100644 --- a/pyren/mod_elm.py +++ b/pyren/mod_elm.py @@ -12,6 +12,7 @@ import string import threading import socket from datetime import datetime +from collections import OrderedDict try: import androidhelper as android @@ -517,6 +518,7 @@ class ELM: lastCMDtime = 0 # time when last command was sent to bus portTimeout = 5 # timeout of port (com or tcp) elmTimeout = 0 # timeout set by ATST + performanceModeLevel = 1 # number of dataids, that can be sent in one 22 request # error counters error_frame = 0 @@ -536,7 +538,8 @@ class ELM: startSession = "" lastinitrsp = "" - rsp_cache = {} # cashes responses for current screen + currentScreenDataIds = [] #dataids displayed on current screen + rsp_cache = OrderedDict() # cashes responses for current screen l1_cache = {} # save number of frames in responces notSupportedCommands = {} # save them to not slow down polling ecudump = {} # for demo only. contains responses for all 21xx and 22xxxx requests @@ -620,7 +623,7 @@ class ELM: """ Clear L2 cache before screen update """ #print 'Clearing L2 cache' - self.rsp_cache = {} + self.rsp_cache = OrderedDict() # if not mod_globals.opt_demo: # self.rsp_cache = {} @@ -1926,7 +1929,7 @@ 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_adapter () def init_iso(self): @@ -2006,6 +2009,24 @@ class ELM: self.check_answer(self.cmd("81")) # start session self.check_adapter () + + #check if ELM uderstand full Single Frame with desired response length + def checkPerformaceLevel(self, dataids): + performanceLevels = [3, 2] + + for level in performanceLevels: + if len(dataids) >= level: + paramToSend = '' + frameLength = '{:02X}'.format(1 + level * 2) + + for i in range(level): + paramToSend += dataids.keys()[i] + cmd = frameLength + '22' + paramToSend + '1' + + resp = self.send_raw(cmd) + if not '?' in resp and resp[2:4] != '7F': + self.performanceModeLevel = level + return def reset_elm(self): self.cmd ("at z") diff --git a/pyren/mod_globals.py b/pyren/mod_globals.py index 6b9a146..edb4b63 100755 --- a/pyren/mod_globals.py +++ b/pyren/mod_globals.py @@ -32,6 +32,7 @@ opt_can2 = False #can connected to pins 13 and 12 opt_ddtxml = "" opt_stn = False opt_sd = False #separate doc files +opt_perform = False dumpName = "" diff --git a/pyren/pyren.py b/pyren/pyren.py index 3687f62..29b3f21 100755 --- a/pyren/pyren.py +++ b/pyren/pyren.py @@ -237,7 +237,9 @@ def optParser(): else: print "Development MODE" mod_globals.opt_dev = True - mod_globals.opt_devses = options.dev + mod_globals.opt_devses = options.dev + if mod_globals.os == 'android': + mod_globals.opt_perform = True def main(): '''Main function'''