Merge branch 'cfc1' into 'master'
Add CFC1 and CAF1 modes for STN based ELMs See merge request py_ren/pyren!18
This commit is contained in:
commit
c0502b4c9a
238
pyren/mod_elm.py
238
pyren/mod_elm.py
@ -604,9 +604,19 @@ class ELM:
|
|||||||
self.lf.flush()
|
self.lf.flush()
|
||||||
|
|
||||||
# check OBDLink
|
# check OBDLink
|
||||||
elm_rsp = self.cmd("STPR")
|
elm_rsp = self.cmd("STI")
|
||||||
if elm_rsp and '?' not in elm_rsp:
|
if elm_rsp and '?' not in elm_rsp:
|
||||||
mod_globals.opt_obdlink = True
|
firmware_version = elm_rsp.split(" ")[-1]
|
||||||
|
try:
|
||||||
|
firmware_version = firmware_version.split(".")
|
||||||
|
version_number = int(''.join([re.sub('\D', '', version) for version in firmware_version]))
|
||||||
|
stpx_introduced_in_version_number = 420 #STN1110 got STPX last in version v4.2.0
|
||||||
|
if version_number >= stpx_introduced_in_version_number:
|
||||||
|
mod_globals.opt_obdlink = True
|
||||||
|
except:
|
||||||
|
raw_input("\nCannot determine OBDLink version.\n" +
|
||||||
|
"OBDLink performance may be decreased.\n" +
|
||||||
|
"Press any key to continue...\n")
|
||||||
|
|
||||||
# check STN
|
# check STN
|
||||||
elm_rsp = self.cmd("STP 53")
|
elm_rsp = self.cmd("STP 53")
|
||||||
@ -1212,7 +1222,13 @@ class ELM:
|
|||||||
if self.ATCFC0:
|
if self.ATCFC0:
|
||||||
return self.send_can_cfc0 (command)
|
return self.send_can_cfc0 (command)
|
||||||
else:
|
else:
|
||||||
rsp = self.send_can (command)
|
if mod_globals.opt_obdlink:
|
||||||
|
if mod_globals.opt_caf:
|
||||||
|
rsp = self.send_can_cfc_caf(command)
|
||||||
|
else:
|
||||||
|
rsp = self.send_can_cfc(command)
|
||||||
|
else:
|
||||||
|
rsp = self.send_can (command)
|
||||||
if self.error_frame > 0 or self.error_bufferfull > 0: # then fallback to cfc0
|
if self.error_frame > 0 or self.error_bufferfull > 0: # then fallback to cfc0
|
||||||
self.ATCFC0 = True
|
self.ATCFC0 = True
|
||||||
self.cmd ("at cfc0")
|
self.cmd ("at cfc0")
|
||||||
@ -1222,7 +1238,6 @@ class ELM:
|
|||||||
def send_can(self, command):
|
def send_can(self, command):
|
||||||
command = command.strip ().replace (' ', '').upper ()
|
command = command.strip ().replace (' ', '').upper ()
|
||||||
isCommandInCache = command in self.l1_cache.keys()
|
isCommandInCache = command in self.l1_cache.keys()
|
||||||
commandString = command
|
|
||||||
|
|
||||||
if len(command) == 0:
|
if len(command) == 0:
|
||||||
return
|
return
|
||||||
@ -1236,7 +1251,7 @@ class ELM:
|
|||||||
cmd_len = len (command) / 2
|
cmd_len = len (command) / 2
|
||||||
if cmd_len < 8: # single frame
|
if cmd_len < 8: # single frame
|
||||||
# check L1 cache here
|
# check L1 cache here
|
||||||
if isCommandInCache and int('0x' + self.l1_cache[commandString], 16) < 16:
|
if isCommandInCache and int('0x' + self.l1_cache[command], 16) < 16:
|
||||||
raw_command.append (("%0.2X" % cmd_len) + command + self.l1_cache[command])
|
raw_command.append (("%0.2X" % cmd_len) + command + self.l1_cache[command])
|
||||||
else:
|
else:
|
||||||
raw_command.append (("%0.2X" % cmd_len) + command)
|
raw_command.append (("%0.2X" % cmd_len) + command)
|
||||||
@ -1250,17 +1265,7 @@ class ELM:
|
|||||||
raw_command.append ("2" + ("%X" % frame_number)[-1:] + command[:14])
|
raw_command.append ("2" + ("%X" % frame_number)[-1:] + command[:14])
|
||||||
frame_number = frame_number + 1
|
frame_number = frame_number + 1
|
||||||
command = command[14:]
|
command = command[14:]
|
||||||
|
|
||||||
# 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:
|
|
||||||
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 = []
|
responses = []
|
||||||
|
|
||||||
# send farmes
|
# send farmes
|
||||||
@ -1328,11 +1333,8 @@ class ELM:
|
|||||||
if result[:2] == '7F': noerrors = False
|
if result[:2] == '7F': noerrors = False
|
||||||
|
|
||||||
# populate L1 cache
|
# populate L1 cache
|
||||||
if noerrors and commandString[:2] in AllowedList and not mod_globals.opt_n1c:
|
if noerrors and command[:2] in AllowedList and not mod_globals.opt_n1c:
|
||||||
if nframes < 16:
|
self.l1_cache[command] = str(hex(nframes))[2:].upper()
|
||||||
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:
|
if len (result) / 2 >= nbytes and noerrors:
|
||||||
# split by bytes and return
|
# split by bytes and return
|
||||||
@ -1354,9 +1356,72 @@ class ELM:
|
|||||||
else:
|
else:
|
||||||
return "WRONG RESPONSE"
|
return "WRONG RESPONSE"
|
||||||
|
|
||||||
|
# Can be used only with OBDLink based ELM, wireless especially.
|
||||||
|
def send_can_cfc_caf(self, command):
|
||||||
|
if len(command) == 0:
|
||||||
|
return
|
||||||
|
if len(command) % 2 != 0:
|
||||||
|
return "ODD ERROR"
|
||||||
|
if not all(c in string.hexdigits for c in command):
|
||||||
|
return "HEX ERROR"
|
||||||
|
|
||||||
|
frsp = self.send_raw('STPX D:' + command + ',R:' + '1')
|
||||||
|
|
||||||
|
responses = []
|
||||||
|
|
||||||
|
for s in frsp.split('\n'):
|
||||||
|
if s.strip()[:4] == "STPX": # echo cancelation
|
||||||
|
continue
|
||||||
|
|
||||||
|
s = s.strip().replace(' ', '')
|
||||||
|
if len(s) == 0: # empty string
|
||||||
|
continue
|
||||||
|
|
||||||
|
responses.append(s)
|
||||||
|
|
||||||
|
result = ""
|
||||||
|
noerrors = True
|
||||||
|
|
||||||
|
if len (responses) == 0: # no data in response
|
||||||
|
return ""
|
||||||
|
|
||||||
|
nodataflag = False
|
||||||
|
for s in responses:
|
||||||
|
|
||||||
|
if 'NO DATA' in s:
|
||||||
|
nodataflag = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if all(c in string.hexdigits for c in s): # some data
|
||||||
|
result = s
|
||||||
|
|
||||||
|
# Check for negative
|
||||||
|
if result[:2] == '7F': noerrors = False
|
||||||
|
|
||||||
|
if noerrors:
|
||||||
|
# split by bytes and return
|
||||||
|
result = ' '.join(a + b for a, b in zip(result[::2], result[1::2]))
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
# check for negative response (repeat the same as in cmd())
|
||||||
|
# debug
|
||||||
|
# print "Size error: ", result
|
||||||
|
if result[:2] == '7F' and result[4:6] in negrsp.keys():
|
||||||
|
if self.vf != 0:
|
||||||
|
tmstr = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
||||||
|
self.vf.write(
|
||||||
|
tmstr + ";" + dnat[self.currentaddress] + ";" + command + ";" + result + ";" + negrsp[
|
||||||
|
result[4:6]] + "\n")
|
||||||
|
self.vf.flush()
|
||||||
|
return "NR:" + result[4:6] + ':' + negrsp[result[4:6]]
|
||||||
|
else:
|
||||||
|
return "WRONG RESPONSE"
|
||||||
|
|
||||||
|
# Can be used only with OBDLink based ELM
|
||||||
def send_can_cfc(self, command):
|
def send_can_cfc(self, command):
|
||||||
|
|
||||||
command = command.strip().replace(' ', '').upper()
|
command = command.strip().replace(' ', '').upper()
|
||||||
|
init_command = command
|
||||||
|
|
||||||
if len(command) == 0:
|
if len(command) == 0:
|
||||||
return
|
return
|
||||||
@ -1388,37 +1453,26 @@ class ELM:
|
|||||||
ST = 0 # Frame Interval
|
ST = 0 # Frame Interval
|
||||||
Fc = 0 # Current frame
|
Fc = 0 # Current frame
|
||||||
Fn = len(raw_command) # Number of frames
|
Fn = len(raw_command) # Number of frames
|
||||||
|
frsp = ''
|
||||||
|
|
||||||
if Fn > 1:
|
if raw_command[Fc].startswith('0') and init_command in self.l1_cache.keys():
|
||||||
self.send_raw('at cfc1')
|
frsp = self.send_raw ('STPX D:' + raw_command[Fc] + ',R:' + self.l1_cache[init_command])
|
||||||
# print 'cfc1', raw_command
|
elif raw_command[Fc].startswith('1'):
|
||||||
|
frsp = self.send_raw ('STPX D:' + raw_command[Fc] + ',R:' + '1')
|
||||||
|
else:
|
||||||
|
frsp = self.send_raw ('STPX D:' + raw_command[Fc])
|
||||||
|
|
||||||
|
|
||||||
while Fc < Fn:
|
while Fc < Fn:
|
||||||
|
|
||||||
if Fn > 1 and (Fn - Fc) == 1:
|
|
||||||
self.send_raw('at cfc0')
|
|
||||||
# print 'cfc0:', Fn, Fc
|
|
||||||
|
|
||||||
# enable responses
|
|
||||||
frsp = ''
|
|
||||||
if not self.ATR1:
|
|
||||||
frsp = self.send_raw('at r1')
|
|
||||||
self.ATR1 = True
|
|
||||||
|
|
||||||
tb = time.time() # time of sending (ff)
|
tb = time.time() # time of sending (ff)
|
||||||
|
|
||||||
if len (raw_command[Fc]) == 16:
|
if raw_command[Fc][:1] != '2':
|
||||||
frsp = self.send_raw (raw_command[Fc])
|
Fc = Fc + 1
|
||||||
else:
|
|
||||||
frsp = self.send_raw (raw_command[Fc] + '1') # we'll get only 1 frame: fc, ff or sf
|
|
||||||
|
|
||||||
frsp = self.send_raw(raw_command[Fc])
|
|
||||||
Fc = Fc + 1
|
|
||||||
|
|
||||||
# analyse response
|
# analyse response
|
||||||
for s in frsp.split('\n'):
|
for s in frsp.split('\n'):
|
||||||
|
|
||||||
if s.strip()[:len(raw_command[Fc - 1])] == raw_command[Fc - 1]: # echo cancelation
|
if s.strip()[:4] == "STPX": # echo cancelation
|
||||||
continue
|
continue
|
||||||
|
|
||||||
s = s.strip().replace(' ', '')
|
s = s.strip().replace(' ', '')
|
||||||
@ -1447,38 +1501,50 @@ class ELM:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# sending consequent frames according to FlowControl
|
# sending consequent frames according to FlowControl
|
||||||
|
frames_left = (Fn - Fc)
|
||||||
cf = min({BS - 1, (Fn - Fc) - 1}) # number of frames to send without response
|
cf = min({BS, frames_left}) # number of frames to send without response
|
||||||
|
|
||||||
# disable responses
|
|
||||||
if cf > 0:
|
|
||||||
if self.ATR1:
|
|
||||||
frsp = self.send_raw('at r0')
|
|
||||||
self.ATR1 = False
|
|
||||||
|
|
||||||
while cf > 0:
|
while cf > 0:
|
||||||
cf = cf - 1
|
burst_size_command = ''
|
||||||
|
for f in range(0, cf):
|
||||||
|
burst_size_command += raw_command[Fc + f]
|
||||||
|
|
||||||
|
if burst_size_command.endswith(raw_command[-1]):
|
||||||
|
if init_command in self.l1_cache.keys():
|
||||||
|
burst_size_request = 'STPX D:' + burst_size_command + ",R:" + self.l1_cache[init_command]
|
||||||
|
else:
|
||||||
|
burst_size_request = 'STPX D:' + burst_size_command
|
||||||
|
else:
|
||||||
|
burst_size_request = 'STPX D:' + burst_size_command + ",R:1"
|
||||||
|
|
||||||
# Ensure time gap between frames according to FlowControl
|
# Ensure time gap between frames according to FlowControl
|
||||||
tc = time.time() # current time
|
tc = time.time() # current time
|
||||||
if (tc - tb) * 1000. < ST:
|
if (tc - tb) * 1000. < ST:
|
||||||
time.sleep(ST / 1000. - (tc - tb))
|
target_time = time.clock() + (ST / 1000. - (tc - tb))
|
||||||
|
while time.clock() < target_time:
|
||||||
|
pass
|
||||||
tb = tc
|
tb = tc
|
||||||
|
|
||||||
frsp = self.send_raw(raw_command[Fc])
|
frsp = self.send_raw(burst_size_request)
|
||||||
Fc = Fc + 1
|
Fc = Fc + cf
|
||||||
|
cf = 0
|
||||||
# now we are going to receive data. st or ff should be in responses[0]
|
if burst_size_command.endswith(raw_command[-1]):
|
||||||
if len(responses) != 1:
|
for s in frsp.split('\n'):
|
||||||
# print "Something went wrong. len responces != 1"
|
if s.strip()[:4] == "STPX": # echo cancelation
|
||||||
return "WRONG RESPONSE"
|
continue
|
||||||
|
else:
|
||||||
|
responses.append(s)
|
||||||
|
continue
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
noErrors = True
|
noerrors = True
|
||||||
cFrame = 0 # frame counter
|
cFrame = 0 # frame counter
|
||||||
nBytes = 0 # number bytes in response
|
nBytes = 0 # number bytes in response
|
||||||
nFrames = 0 # numer frames in response
|
nFrames = 0 # numer frames in response
|
||||||
|
|
||||||
|
if len (responses) == 0: # no data in response
|
||||||
|
return ""
|
||||||
|
|
||||||
if responses[0][:1] == '0': # single frame (sf)
|
if responses[0][:1] == '0': # single frame (sf)
|
||||||
nBytes = int(responses[0][1:2], 16)
|
nBytes = int(responses[0][1:2], 16)
|
||||||
nFrames = 1
|
nFrames = 1
|
||||||
@ -1492,19 +1558,11 @@ class ELM:
|
|||||||
|
|
||||||
result = responses[0][4:16]
|
result = responses[0][4:16]
|
||||||
|
|
||||||
# receiving consecutive frames
|
|
||||||
# while len (result) / 2 < nBytes:
|
|
||||||
while cFrame < nFrames:
|
while cFrame < nFrames:
|
||||||
# now we should send ff
|
|
||||||
sBS = hex(min({nFrames - cFrame, MaxBurst}))[2:]
|
|
||||||
frsp = self.send_raw('300' + sBS + '00' + sBS)
|
|
||||||
|
|
||||||
# analyse response
|
# analyse response
|
||||||
nodataflag = False
|
nodataflag = False
|
||||||
for s in frsp.split('\n'):
|
for s in responses:
|
||||||
|
|
||||||
if s.strip()[:len(raw_command[Fc - 1])] == raw_command[Fc - 1]: # echo cancelation
|
|
||||||
continue
|
|
||||||
|
|
||||||
if 'NO DATA' in s:
|
if 'NO DATA' in s:
|
||||||
nodataflag = True
|
nodataflag = True
|
||||||
@ -1515,12 +1573,12 @@ class ELM:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if all(c in string.hexdigits for c in s): # some data
|
if all(c in string.hexdigits for c in s): # some data
|
||||||
responses.append(s)
|
# responses.append(s)
|
||||||
if s[:1] == '2': # consecutive frames (cf)
|
if s[:1] == '2': # consecutive frames (cf)
|
||||||
tmp_fn = int(s[1:2], 16)
|
tmp_fn = int(s[1:2], 16)
|
||||||
if tmp_fn != (cFrame % 16): # wrong response (frame lost)
|
if tmp_fn != (cFrame % 16): # wrong response (frame lost)
|
||||||
self.error_frame += 1
|
self.error_frame += 1
|
||||||
noErrors = False
|
noerrors = False
|
||||||
continue
|
continue
|
||||||
cFrame += 1
|
cFrame += 1
|
||||||
result += s[2:16]
|
result += s[2:16]
|
||||||
@ -1531,9 +1589,16 @@ class ELM:
|
|||||||
|
|
||||||
else: # wrong response (first frame omitted)
|
else: # wrong response (first frame omitted)
|
||||||
self.error_frame += 1
|
self.error_frame += 1
|
||||||
noErrors = False
|
noerrors = False
|
||||||
|
|
||||||
|
# Check for negative
|
||||||
|
if result[:2] == '7F': noerrors = False
|
||||||
|
|
||||||
if len(result) / 2 >= nBytes and noErrors and result[:2] != '7F':
|
# populate L1 cache
|
||||||
|
if noerrors and init_command[:2] in AllowedList:
|
||||||
|
self.l1_cache[init_command] = str(nFrames)
|
||||||
|
|
||||||
|
if noerrors and len(result) / 2 >= nBytes:
|
||||||
# split by bytes and return
|
# split by bytes and return
|
||||||
result = ' '.join(a + b for a, b in zip(result[::2], result[1::2]))
|
result = ' '.join(a + b for a, b in zip(result[::2], result[1::2]))
|
||||||
return result
|
return result
|
||||||
@ -1886,7 +1951,14 @@ class ELM:
|
|||||||
self.check_answer(self.cmd("at h0"))
|
self.check_answer(self.cmd("at h0"))
|
||||||
self.check_answer(self.cmd("at l0"))
|
self.check_answer(self.cmd("at l0"))
|
||||||
self.check_answer(self.cmd("at al"))
|
self.check_answer(self.cmd("at al"))
|
||||||
self.check_answer(self.cmd("at caf0"))
|
|
||||||
|
if mod_globals.opt_obdlink and mod_globals.opt_caf:
|
||||||
|
self.check_answer(self.cmd("AT CAF1"))
|
||||||
|
self.check_answer(self.cmd("STCSEGR 1"))
|
||||||
|
self.check_answer(self.cmd("STCSEGT 1"))
|
||||||
|
else:
|
||||||
|
self.check_answer(self.cmd("at caf0"))
|
||||||
|
|
||||||
if self.ATCFC0:
|
if self.ATCFC0:
|
||||||
self.check_answer(self.cmd("at cfc0"))
|
self.check_answer(self.cmd("at cfc0"))
|
||||||
else:
|
else:
|
||||||
@ -1969,6 +2041,9 @@ class ELM:
|
|||||||
self.check_answer (self.cmd ("at fc sm 1"))
|
self.check_answer (self.cmd ("at fc sm 1"))
|
||||||
self.check_answer (self.cmd ("at st ff")) # reset adaptive timing step 1
|
self.check_answer (self.cmd ("at st ff")) # reset adaptive timing step 1
|
||||||
self.check_answer (self.cmd ("at at 0")) # reset adaptive timing step 2
|
self.check_answer (self.cmd ("at at 0")) # reset adaptive timing step 2
|
||||||
|
|
||||||
|
if mod_globals.opt_obdlink and mod_globals.opt_caf:
|
||||||
|
self.check_answer (self.cmd ("STCFCPA " + TXa + ", " + RXa))
|
||||||
|
|
||||||
# some models of cars may have different CAN buses
|
# some models of cars may have different CAN buses
|
||||||
if 'brp' in ecu.keys () and '1' in ecu['brp'] and '0' in ecu['brp']: # double brp
|
if 'brp' in ecu.keys () and '1' in ecu['brp'] and '0' in ecu['brp']: # double brp
|
||||||
@ -2082,7 +2157,7 @@ class ELM:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if self.performanceModeLevel == 3 and mod_globals.opt_obdlink:
|
if self.performanceModeLevel == 3 and mod_globals.opt_obdlink:
|
||||||
for level in reversed(range(4,26)): #26 - 1 = 25 parameters per page
|
for level in reversed(range(4,100)): #26 - 1 = 25 parameters per page
|
||||||
isLevelAccepted = self.checkPerformaceLevel(level, dataids)
|
isLevelAccepted = self.checkPerformaceLevel(level, dataids)
|
||||||
if isLevelAccepted:
|
if isLevelAccepted:
|
||||||
return
|
return
|
||||||
@ -2095,7 +2170,12 @@ class ELM:
|
|||||||
frameLength = '{:02X}'.format(1 + level * 2)
|
frameLength = '{:02X}'.format(1 + level * 2)
|
||||||
for lvl in range(level):
|
for lvl in range(level):
|
||||||
paramToSend += dataids.keys()[lvl]
|
paramToSend += dataids.keys()[lvl]
|
||||||
cmd = frameLength + '22' + paramToSend + '1'
|
|
||||||
|
if mod_globals.opt_caf:
|
||||||
|
cmd = '22' + paramToSend + '1'
|
||||||
|
else:
|
||||||
|
cmd = frameLength + '22' + paramToSend + '1'
|
||||||
|
|
||||||
resp = self.send_raw(cmd)
|
resp = self.send_raw(cmd)
|
||||||
for s in resp.split('\n'):
|
for s in resp.split('\n'):
|
||||||
if s.strip().startswith('037F'):
|
if s.strip().startswith('037F'):
|
||||||
@ -2103,7 +2183,7 @@ class ELM:
|
|||||||
else: # send multiframe command for more than 3 dataids
|
else: # send multiframe command for more than 3 dataids
|
||||||
# Some modules can return NO DATA if multi frame command is sent after some no activity time
|
# Some modules can return NO DATA if multi frame command is sent after some no activity time
|
||||||
# Sending anything before main command usually helps that command to be accepted
|
# Sending anything before main command usually helps that command to be accepted
|
||||||
self.send_raw ("0322" + dataids.keys()[0] + "1")
|
self.send_cmd ("22" + dataids.keys()[0] + "1")
|
||||||
|
|
||||||
for lvl in range(level):
|
for lvl in range(level):
|
||||||
resp = self.request("22" + dataids.keys()[lvl])
|
resp = self.request("22" + dataids.keys()[lvl])
|
||||||
|
@ -23,6 +23,7 @@ opt_cmd = False
|
|||||||
opt_ddt = False
|
opt_ddt = False
|
||||||
opt_si = False #try slow init every time
|
opt_si = False #try slow init every time
|
||||||
opt_cfc0 = False #turn off automatic FC and do it by script
|
opt_cfc0 = False #turn off automatic FC and do it by script
|
||||||
|
opt_caf = False #turn on CAN Automatic Formatting
|
||||||
opt_n1c = False #turn off L1 cache
|
opt_n1c = False #turn off L1 cache
|
||||||
opt_dev = False #switch to development session for commands from DevList
|
opt_dev = False #switch to development session for commands from DevList
|
||||||
opt_devses = '1086' #development session for commands from DevList
|
opt_devses = '1086' #development session for commands from DevList
|
||||||
|
Loading…
x
Reference in New Issue
Block a user