From a2d48215f1bbff4c9f126a5602a4e74326c698e6 Mon Sep 17 00:00:00 2001 From: shrlnm Date: Thu, 2 May 2019 18:26:44 +0300 Subject: [PATCH] 9p add terminal commands --- pyren/macro/rlink2/rlink2-HIGH1-screen.cmd | 7 +- pyren/macro/rlink2/rlink2-HIGH2-screen.cmd | 7 +- pyren/macro/rlink2/rlink2-MID1-screen.cmd | 7 +- pyren/macro/rlink2/rlink2-MID2-screen.cmd | 5 + pyren/mod_ddt_ecu.py | 190 +++++++++++-- pyren/mod_ddt_screen.py | 5 +- pyren/mod_elm.py | 28 +- pyren/mod_term.py | 311 +++++++++++++++------ 8 files changed, 432 insertions(+), 128 deletions(-) diff --git a/pyren/macro/rlink2/rlink2-HIGH1-screen.cmd b/pyren/macro/rlink2/rlink2-HIGH1-screen.cmd index 1cc062c..e3cf2a4 100644 --- a/pyren/macro/rlink2/rlink2-HIGH1-screen.cmd +++ b/pyren/macro/rlink2/rlink2-HIGH1-screen.cmd @@ -5,9 +5,14 @@ can500 # init can macro 1003 +# check if it is rlink2 +exit_if_not F18A 6 4 FFFFFF 434150 + # HIGH 1 768x1024 2E2303032802131303003C000004500014001E001E040011C5002C006967 wait 2 # reload rlink2 -1101 \ No newline at end of file +1101 + +exit diff --git a/pyren/macro/rlink2/rlink2-HIGH2-screen.cmd b/pyren/macro/rlink2/rlink2-HIGH2-screen.cmd index 5df0049..238b59f 100644 --- a/pyren/macro/rlink2/rlink2-HIGH2-screen.cmd +++ b/pyren/macro/rlink2/rlink2-HIGH2-screen.cmd @@ -5,9 +5,14 @@ can500 # init can macro 1003 +# check if it is rlink2 +exit_if_not F18A 6 4 FFFFFF 434150 + # HIGH 2 768x1024 2E2303032802131303003C000004500014001E001E040014E8002C006967 wait 2 # reload rlink2 -1101 \ No newline at end of file +1101 + +exit diff --git a/pyren/macro/rlink2/rlink2-MID1-screen.cmd b/pyren/macro/rlink2/rlink2-MID1-screen.cmd index 98ed1a7..228ed39 100644 --- a/pyren/macro/rlink2/rlink2-MID1-screen.cmd +++ b/pyren/macro/rlink2/rlink2-MID1-screen.cmd @@ -5,9 +5,14 @@ can500 # init can macro 1003 +# check if it is rlink2 +exit_if_not F18A 6 4 FFFFFF 434150 + # MID 1 480x800 2E230301F404080801E03C0000039D000A0005006E03200AD7022C006967 wait 2 # reload rlink2 -1101 \ No newline at end of file +1101 + +exit diff --git a/pyren/macro/rlink2/rlink2-MID2-screen.cmd b/pyren/macro/rlink2/rlink2-MID2-screen.cmd index b3db6f2..690e531 100644 --- a/pyren/macro/rlink2/rlink2-MID2-screen.cmd +++ b/pyren/macro/rlink2/rlink2-MID2-screen.cmd @@ -5,9 +5,14 @@ can500 # init can macro 1003 +# check if it is rlink2 +exit_if_not F18A 6 4 FFFFFF 434150 + # MID 2 480x800 2E2303020D02082301E03C000004200080000A007603200D05062C006967 wait 2 # reload rlink2 1101 + +exit diff --git a/pyren/mod_ddt_ecu.py b/pyren/mod_ddt_ecu.py index 2bfe4c0..7d35f47 100755 --- a/pyren/mod_ddt_ecu.py +++ b/pyren/mod_ddt_ecu.py @@ -685,7 +685,146 @@ class DDTECU(): return hexval - def packValues( self, requestName, iValues ): + def getParamExtr(self, parName, iValues, dValues ): + + result = '\nTerminal command hint\n\n' + + # get DataItem instance + if parName not in self.datas.keys(): + return 'Error finding datas' + + # get data + d = self.datas[parName] + + # finding read request + rr = None + for r in self.requests.values(): + if parName in r.ReceivedDI.keys() and r.SentBytes[:2] in ['21','22']: + rr = r + break + + rcm = rr.SentBytes[:2] + lid = r.SentBytes[2:].upper() + + if rcm == '21': + wcm = '3B' + lid + else: + wcm = '2E' + lid + + # finding write request + wr = None + for r in self.requests.values(): + if parName in r.SentDI.keys() and r.SentBytes.upper().startswith(wcm): + wr = r + break + + if rr==None: + return "Didn't find command for DataRead" + + if wr==None: + result += "Didn't find command for DataWrite\n\n" + + rdi = rr.ReceivedDI[parName] + if wr!=None: + sdi = wr.SentDI[parName] + + if rr.MinBytes != len(wr.SentBytes) / 2: + result += "Commands for DataRead and DataWrite have different length" + + if rdi.FirstByte!=sdi.FirstByte or rdi.BitOffset!=sdi.BitOffset or rdi.Endian!=sdi.Endian: + result += "Data not in the same place in DataRead and DataWrite" + + # get value + if d.Name in iValues.keys(): + value = iValues[d.Name].get().strip() + elif d.Name in dValues.keys(): + value = dValues[d.Name].get().strip() + else: + value = 0 + value = self.getValueFromInput(d, value) + + # prepare parameters for extraction + littleEndian = True if rdi.Endian == "Little" else False + sb = rdi.FirstByte - 1 + bits = d.BitsCount + sbit = rdi.BitOffset + bytes = (bits + sbit - 1) / 8 + 1 + if littleEndian: + lshift = sbit + else: + lshift = ((bytes + 1) * 8 - (bits + sbit)) % 8 + + # shift value on bit offset + try: + val = int(value, 16) + except: + return 'ERROR: Wrong HEX value in parametr (%s) : "%s"' % (d.Name, value) + val = (val & (2 ** bits - 1)) << lshift + value = hex(val)[2:] + # remove 'L' + if value[-1:].upper() == 'L': + value = value[:-1] + # add left zero if need + if len(value) % 2: + value = '0' + value + + # check hex + if value.upper().startswith('0X'): value = value[2:] + value = value.zfill(bytes * 2).upper() + if not all(c in string.hexdigits for c in value) and len(value) == bytes * 2: + return 'ERROR: Wrong value in parametr:%s (it should have %d bytes)' % (d.Name, d.BytesCount) + + mask = (2 ** bits - 1) << lshift + # remove '0x' + hmask = hex(mask)[2:].upper() + # remove 'L' + if hmask[-1:].upper() == 'L': + hmask = hmask[:-1] + hmask = hmask[-bytes * 2:].zfill(bytes * 2) + + func_params = ' ' + lid + ' ' + str(rr.MinBytes) + ' ' + str(rdi.FirstByte) + ' ' + hmask + ' ' + value + '\n' + + for f in ['exit_if','exit_if_not']: + result += (f + func_params) + if wr!=None: + for f in ['set_bits', 'xor_bits']: + result += (f + func_params) + + return result + + def getValueFromInput(self, d, value ): + + # list + if len(d.List.keys()) and ':' in value: + value = value.split(':')[0] + + # scaled + if d.Scaled: + # if there is units then remove them + if ' ' in value: + value = value.split(' ')[0] + # check 0x + if value.upper().startswith('0X'): + value = value[2:] + else: # calculate reverse formula + if not all((c in string.digits or c == '.' or c == ',' or c == '-' or c == 'e' or c == 'E') for c in value): + return 'ERROR: Wrong value in parametr:%s (it should have %d bytes), be decimal or starts with 0x for hex' % ( + d.Name, d.BytesCount) + flv = (float(value) * float(d.DivideBy) - float(d.Offset)) / float(d.Step) + value = hex(int(flv)) + + # ascii + if d.BytesASCII: + hst = '' + if len(value)<(d.BitsCount/8): + value += ' '*(d.BitsCount/8 - len(value)) + for c in value: + hst = hst + hex(ord(c))[2:].zfill(2) + value = hst + + return value + + def packValues( self, requestName, iValues ): ''' pack values from iValues to command ''' ''' return string ''' ''' if cathe the error then return string begining with ERROR: word''' @@ -709,31 +848,32 @@ class DDTECU(): #get value value = iValues[d.Name].get().strip() + value = self.getValueFromInput( d, value ) - # list - if len(d.List.keys()) and ':' in value: - value = value.split(':')[0] - - # scaled - if d.Scaled: - #if there is units then remove them - if ' ' in value: - value = value.split(' ')[0] - #check 0x - if value.upper().startswith('0X'): - value = value[2:] - else: #calculate reverse formula - if not all((c in string.digits or c=='.' or c==',' or c=='-' or c=='e' or c=='E') for c in value): - return 'ERROR: Wrong value in parametr:%s (it should have %d bytes), be decimal or starts with 0x for hex' % (d.Name, d.BytesCount) - flv = (float( value )*float(d.DivideBy) - float(d.Offset))/float(d.Step) - value = hex(int(flv)) - - # ascii - if d.BytesASCII: - hst = '' - for c in value: - hst = hst + hex(ord(c))[2:].zfill(2) - value = hst + ## list + #if len(d.List.keys()) and ':' in value: + # value = value.split(':')[0] + # + ## scaled + #if d.Scaled: + # #if there is units then remove them + # if ' ' in value: + # value = value.split(' ')[0] + # #check 0x + # if value.upper().startswith('0X'): + # value = value[2:] + # else: #calculate reverse formula + # if not all((c in string.digits or c=='.' or c==',' or c=='-' or c=='e' or c=='E') for c in value): + # return 'ERROR: Wrong value in parametr:%s (it should have %d bytes), be decimal or starts with 0x for hex' % (d.Name, d.BytesCount) + # flv = (float( value )*float(d.DivideBy) - float(d.Offset))/float(d.Step) + # value = hex(int(flv)) + # + ## ascii + #if d.BytesASCII: + # hst = '' + # for c in value: + # hst = hst + hex(ord(c))[2:].zfill(2) + # value = hst #prepare parameters for extraction littleEndian = True if sdi.Endian=="Little" else False diff --git a/pyren/mod_ddt_screen.py b/pyren/mod_ddt_screen.py index e684008..a6d4d9f 100755 --- a/pyren/mod_ddt_screen.py +++ b/pyren/mod_ddt_screen.py @@ -854,14 +854,17 @@ class DDTScreen (tk.Frame): closest = tag else: closest = self.tObj[self.ddt.find_closest (event.x, event.y)[0]] + + p = self.decu.getParamExtr(closest, self.iValue, self.dValue ) d = str (self.decu.datas[closest]) r = '' if closest in self.decu.req4data.keys () and \ self.decu.req4data[closest] in self.decu.requests.keys (): r = str (self.decu.requests[self.decu.req4data[closest]]) + - xText = d + '\n' + '*' * 50 + '\n' + r + xText = d + '\n' + '*' * 50 + '\n' + r + '\n' + '*' * 50 + '\n' + p dialog = InfoDialog (self.root, xText) self.root.wait_window (dialog.top) diff --git a/pyren/mod_elm.py b/pyren/mod_elm.py index fd65358..f4a4d73 100755 --- a/pyren/mod_elm.py +++ b/pyren/mod_elm.py @@ -1142,9 +1142,13 @@ class ELM: def send_can(self, command): command = command.strip ().replace (' ', '').upper () - - if len (command) % 2 != 0 or len (command) == 0: return "ODD ERROR" - if not all (c in string.hexdigits for c in command): return "HEX ERROR" + + 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" # do framing raw_command = [] @@ -1260,8 +1264,12 @@ class ELM: command = command.strip().replace(' ', '').upper() - if len(command) % 2 != 0 or len(command) == 0: return "ODD ERROR" - if not all(c in string.hexdigits for c in command): return "HEX ERROR" + 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" # do framing raw_command = [] @@ -1453,9 +1461,13 @@ class ELM: def send_can_cfc0(self, command): command = command.strip ().replace (' ', '').upper () - - if len (command) % 2 != 0 or len (command) == 0: return "ODD ERROR" - if not all (c in string.hexdigits for c in command): return "HEX ERROR" + + 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" # do framing raw_command = [] diff --git a/pyren/mod_term.py b/pyren/mod_term.py index f13c9fd..71258f7 100755 --- a/pyren/mod_term.py +++ b/pyren/mod_term.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import sys, os, re +import string import time import mod_globals import mod_elm @@ -15,6 +16,7 @@ os.chdir (os.path.dirname (os.path.realpath (sys.argv[0]))) macro = {} var = {} +cmd_delay = 0 stack = [] auto_macro = "" @@ -63,7 +65,6 @@ if mod_globals.os != 'android': print "\t\t>sudo easy_install pyserial" sys.exit() - def init_macro(): global macro macro = {} @@ -147,50 +148,6 @@ def load_macro( mf='' ): else: pars_macro(mf) -def play_macro( mname, elm ): - global macro - global var - global stack - - if mname in stack: - print 'Error: recursion prohibited:', mname - return - else: - stack.append(mname) - - for l in macro[mname]: - #find veriable definition - m = re.search('\$\S+\s*=\s*\S+', l) - if m: - r = m.group(0).replace(' ', '').replace('\t', '') - rl = r.split('=') - var[rl[0]]=rl[1] - if rl[0]=='$addr': - if var['$addr'].upper() in mod_elm.dnat.keys(): - var['$txa'] = mod_elm.dnat[var['$addr'].upper()] - var['$rxa'] = mod_elm.snat[var['$addr'].upper()] - elm.currentaddress = var['$addr'].upper() - continue - - #find veriable usage - m = re.search('\$\S+', l) - while m: - vu = m.group(0) - if vu in var.keys(): - l = re.sub("\\"+vu,var[vu], l) - else: - print 'Error: unknown variable',vu,'in',mname - return - m = re.search('\$\S+', l) - - if l in macro.keys(): - play_macro( l, elm ) - continue - - print elm.cmd(l) - - stack.remove(mname) - def print_help(): """ [h]elp - this help @@ -210,7 +167,6 @@ def print_help(): for m in macro.keys(): print ' '+m print - def optParser(): '''Parsing of command line parameters. User should define at least com port name''' @@ -299,7 +255,6 @@ def optParser(): mod_globals.opt_n1c = options.n1c auto_dia = options.dia - class FileChooser(): lay = ''' " + - ECUs local identifier. Length should be 2 simbols for KWP or 4 for CAN + - lengt of command response including positive response bytes, equals MinBytes from ddt db + - offeset in bytes to first changed byte (starts from 1 not 0) + - bit mask for changed bits, 1 - changable, 0 - untachable + - bit value + and should have equal length + + ''' + + if fnc not in ['set_bits','xor_bits','exit_if','exit_if_not']: + print "\nERROR: Unknown function\n" + return + + par = l.strip().split(' ') + if len(par)!=5: + print error_msg + return + + + try: + lid = par[0].strip() + lng = int(par[1].strip()) + off = int(par[2].strip())-1 + mask = par[3].strip() + val = par[4].strip() + except: + print error_msg + return + + if len(lid) not in [2,4] or (len(mask)!=len(val)) or off<0 or off>lng: + print error_msg + return + + if len(lid)==2: #KWP + rcmd = '21'+lid + else: #CAN + rcmd = '22' + lid + + rsp = elm.cmd(rcmd) + rsp = rsp.replace(' ','')[:lng*2].upper() + + print "read value:",rsp + + if len(rsp) != lng * 2: + print '\nERROR: Length is unexpected\n' + return + + if not all(c in string.hexdigits for c in rsp): + print '\nERROR: Wrong simbol in response\n' + return + + pos_rsp = ('6'+rcmd[1:]).upper() + if not rsp.startswith(pos_rsp): + print '\nERROR: Not positive response\n' + return + + diff = 0 + i = 0 + while i 0 and l_parts[0] in ['wait', 'sleep']: + try: + time.sleep(int(l_parts[1])) + return + except: + pass + + if len(l_parts) > 0 and l_parts[0] in ['delay']: + cmd_delay = int(l_parts[1]) + return + + if l.lower().startswith('set_bits'): + bit_cmd( l.lower()[8:], elm, fnc='set_bits' ) + return + + if l.lower().startswith('xor_bits'): + bit_cmd( l.lower()[8:], elm, fnc='xor_bits' ) + return + + if l.lower().startswith('exit_if_not'): + bit_cmd( l.lower()[11:], elm, fnc='exit_if_not' ) + return + + if l.lower().startswith('exit_if'): + bit_cmd( l.lower()[7:], elm, fnc='exit_if' ) + return + + print elm.cmd(l) + + if cmd_delay>0: + print '# delay:', cmd_delay + time.sleep(cmd_delay) + def main(): @@ -463,7 +629,7 @@ def main(): #debug #mod_globals.opt_demo = True - # disable CAN auto-formatting + # disable auto flow control mod_globals.opt_cfc0 = True print 'Opening ELM' @@ -476,6 +642,8 @@ def main(): if auto_dia: fname = FileChooser().choose() + #debug + #fname = './macro/test/test.cmd' if len(fname)>0: f = open(fname, 'rt') cmd_lines = f.readlines() @@ -497,53 +665,14 @@ def main(): l = cmd_lines[cmd_ref].strip() cmd_ref += 1 else: - l = "exit" + cmd_lines = [] + l = "# end of command file" print l - if '#' in l: - l = l.split('#')[0] - - l = l.strip() - - if len(l)==0: - continue - - if l in ['q', 'quit', 'e', 'exit', 'end']: - break - - if l in ['h', 'help', '?']: - print_help () - continue - - l_parts = l.split() - if len(l_parts)>0 and l_parts[0] in ['wait','sleep']: - try: - time.sleep(int(l_parts[1])) - continue - except: - pass - - if l in macro.keys(): - play_macro( l, elm ) - continue - - m = re.search('\$\S+\s*=\s*\S+', l) - if m: - # variable definition - r = m.group(0).replace(' ', '').replace('\t', '') - rl = r.split('=') - var[rl[0]]=rl[1] - if rl[0]=='$addr': - if var['$addr'].upper() in mod_elm.dnat.keys(): - var['$txa'] = mod_elm.dnat[var['$addr'].upper()] - var['$rxa'] = mod_elm.snat[var['$addr'].upper()] - elm.currentaddress = var['$addr'].upper() - continue - - print elm.cmd(l) + proc_line( l, elm ) if __name__ == '__main__': - main() + main()