Use Transmit Flow Control

This commit is contained in:
Marianpol 2021-05-17 12:04:42 +02:00
parent a47030920f
commit a7a89f673c

View File

@ -1212,7 +1212,10 @@ 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:
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")
@ -1357,6 +1360,7 @@ class ELM:
def send_can_cfc(self, command): def send_can_cfc(self, command):
command = command.strip().replace(' ', '').upper() command = command.strip().replace(' ', '').upper()
uncutCommand = command
if len(command) == 0: if len(command) == 0:
return return
@ -1388,36 +1392,51 @@ 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 Fn > 1:
self.send_raw('at cfc1') # self.send_raw('at cfc1')
# print 'cfc1', raw_command # print 'cfc1', raw_command
while Fc < Fn: if raw_command[Fc].startswith('0'):
if uncutCommand in self.l1_cache.keys():
frsp = self.send_raw ('STPX D:' + raw_command[Fc] + ',R:' + self.l1_cache[uncutCommand]) # we'll get only 1 frame: fc, ff or sf
else:
frsp = self.send_raw ('STPX D:' + raw_command[Fc])
if raw_command[Fc].startswith('1'):
frsp = self.send_raw ('STPX D:' + raw_command[Fc] + ',R:' + '1')
if Fn > 1 and (Fn - Fc) == 1: while Fc < Fn:
self.send_raw('at cfc0') # if Fn > 1 and (Fn - Fc) == 1:
# print 'cfc0:', Fn, Fc # self.send_raw('at cfc0')
# # print 'cfc0:', Fn, Fc
# enable responses # enable responses
frsp = ''
if not self.ATR1: # if not self.ATR1:
frsp = self.send_raw('at r1') # frsp = self.send_raw('at r1')
self.ATR1 = True # self.ATR1 = True
tb = time.time() # time of sending (ff) tb = time.time() # time of sending (ff)
if len (raw_command[Fc]) == 16: # if len (raw_command[Fc]) == 16:
frsp = self.send_raw (raw_command[Fc]) # frsp = self.send_raw (raw_command[Fc])
else: # 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] + '1') # we'll get only 1 frame: fc, ff or sf
Fc = Fc + 1 # if raw_command[Fc].startswith('0'):
# frsp = self.send_raw ('STPX D:' + raw_command[Fc] + ', R:' + l1_cache[command]) # we'll get only 1 frame: fc, ff or sf
# if raw_command[Fc].startswith('1'):
# frsp = self.send_raw (raw_command[Fc] + '1')
if raw_command[Fc][:1] != '2':
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(' ', '')
@ -1446,34 +1465,52 @@ 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 # disable responses
if cf > 0: # if cf > 0:
if self.ATR1: # if self.ATR1:
frsp = self.send_raw('at r0') # frsp = self.send_raw('at r0')
self.ATR1 = False # self.ATR1 = False
while cf > 0: while cf > 0:
cf = cf - 1 burstSizeCommand = ''
for f in range(0, cf):
burstSizeCommand += raw_command[Fc + f]
if burstSizeCommand.endswith(raw_command[-1]):
if uncutCommand in self.l1_cache.keys():
burstSizeCommandRequest = 'STPX D:' + burstSizeCommand + ",R:" + self.l1_cache[uncutCommand]
else:
burstSizeCommandRequest = 'STPX D:' + burstSizeCommand
else:
burstSizeCommandRequest = 'STPX D:' + burstSizeCommand + ",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)) time.sleep(ST / 1000. - (tc - tb))
tb = tc tb = tc
frsp = self.send_raw(raw_command[Fc]) frsp = self.send_raw(burstSizeCommandRequest)
Fc = Fc + 1 Fc = Fc + cf
cf = 0
if burstSizeCommand.endswith(raw_command[-1]):
for s in frsp.split('\n'):
if s.strip()[:4] == "STPX": # echo cancelation
continue
else:
responses.append(s)
continue
# now we are going to receive data. st or ff should be in responses[0] # now we are going to receive data. st or ff should be in responses[0]
if len(responses) != 1: # if len(responses) != 1:
# print "Something went wrong. len responces != 1" # print "Something went wrong. len responces != 1"
return "WRONG RESPONSE" # return "WRONG RESPONSE"
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
@ -1495,15 +1532,12 @@ class ELM:
# while len (result) / 2 < nBytes: # while len (result) / 2 < nBytes:
while cFrame < nFrames: while cFrame < nFrames:
# now we should send ff # now we should send ff
sBS = hex(min({nFrames - cFrame, MaxBurst}))[2:] # sBS = hex(min({nFrames - cFrame, MaxBurst}))[2:]
frsp = self.send_raw('300' + sBS + '00' + sBS) # 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
@ -1514,12 +1548,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]
@ -1530,9 +1564,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 uncutCommand[:2] in AllowedList:
self.l1_cache[uncutCommand] = 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