1#!/usr/bin/env python 2import os, sys, re, time 3from ymodem import YModem 4 5try: 6 import serial 7 from serial.tools import miniterm 8except: 9 print("\nNot found pyserial, please install it by: \nsudo python%d -m pip install pyserial" % (sys.version_info.major)) 10 sys.exit(-1) 11 12def match_and_send(serialport, pattern, command, timeout): 13 """ receive serial data, and check it with pattern """ 14 pattern = re.compile(pattern) 15 start = time.time() 16 while (time.time() - start) < timeout: 17 #line = serialport.readline() 18 #timeout dont work for 'readline', so using 'read_until' instead 19 line = serialport.read_until(b'\n') 20 if len(line) == 0: 21 continue 22 match = pattern.search(line) 23 if match: 24 if command: 25 serialport.write(command) 26 print(line.decode('UTF-8',errors='ignore')) 27 sys.stdout.flush() 28 return match 29 print(line.decode('UTF-8',errors='ignore')) 30 sys.stdout.flush() 31 return None 32 33def send_and_match(serialport, command, pattern, timeout): 34 """ receive serial data, and check it with pattern """ 35 if command: 36 serialport.write(command) 37 if pattern == b'': 38 #only send 39 sys.stdout.flush() 40 return None 41 pattern = re.compile(pattern) 42 start = time.time() 43 while (time.time() - start) < timeout: 44 #line = serialport.readline() 45 #timeout dont work for 'readline', so using 'read_until' instead 46 line = serialport.read_until(b'\n') 47 if len(line) == 0: 48 continue 49 print(line.decode('UTF-8',errors='ignore')) 50 sys.stdout.flush() 51 match = pattern.search(line) 52 if match: 53 return match 54 return None 55 56#burn file in 2_boot 57def burn_bin_file(serialport, filename, address): 58 if not os.path.exists(filename): 59 print("[ScriptPrint] File \"%s\" is not existed." % filename) 60 return False 61 62 #get address 63 if address == "0" or address == "0x0" or address == "0x00": 64 # get flash address 65 match = send_and_match(serialport, b'1', b'Backup part addr:([0-9a-fxA-F]*)', 5) 66 if not match: 67 print("[ScriptPrint] Can not get flash address") 68 return False 69 address = match.group(1) 70 else: 71 send_and_match(serialport, b'1', b'', 0) 72 address = address.encode() 73 74 # set flash address 75 match = send_and_match(serialport, address + b'\r\n', b'CCCC', 30) 76 if not match: 77 print("[ScriptPrint] Can not enter ymodem mode") 78 return False 79 80 # send binary file 81 def sender_getc(size): 82 return serialport.read(size) or None 83 84 def sender_putc(data, timeout=15): 85 return serialport.write(data) 86 87 sender = YModem(sender_getc, sender_putc) 88 sent = sender.send_file(filename) 89 return True 90 91def burn_bin_files(portnum, baudrate, bin_files): 92 # open serial port 93 serialport = serial.Serial() 94 serialport.port = portnum 95 serialport.baudrate = baudrate 96 serialport.parity = "N" 97 serialport.bytesize = 8 98 serialport.stopbits = 1 99 serialport.timeout = 1 100 101 try: 102 serialport.open() 103 except Exception as e: 104 raise Exception("[ScriptPrint] Failed to open serial port: %s!" % portnum) 105 106 print("[ScriptPrint] Try to reboot...") 107 108 # 重启单板并确保进入2nd-boot 109 for i in range(10): 110 match = send_and_match(serialport, b'\n', b'\(ash', 2) 111 if match: 112 # 如果在cli模式,通过reboot重启系统 113 print("[ScriptPrint] Reboot from CLI") 114 send_and_match(serialport, b'reboot\n', b'', 0) 115 match = match_and_send(serialport, b'2ndboot cli menu', b'w', 5) 116 if match: 117 print("[ScriptPrint] check if in boot") 118 match = send_and_match(serialport, b'\n', b'aos boot', 2) 119 if match: 120 # 进入boot模式,退出 121 break 122 123 match = send_and_match(serialport, b'\n', b'aos boot', 2) 124 if match: 125 # 如果在boot模式,通过2重启系统 126 print("[ScriptPrint] Reboot from 2nd-boot") 127 send_and_match(serialport, b'2\n', b'', 0) 128 match = match_and_send(serialport, b'2ndboot cli menu', b'w', 5) 129 if match: 130 print("[ScriptPrint] check if in boot") 131 match = send_and_match(serialport, b'\n', b'aos boot', 2) 132 if match: 133 # 进入boot模式,退出 134 break 135 else: 136 # 一些solution需要先退出命令行模式回到CLI 137 print("[ScriptPrint] change to CLI mode") 138 send_and_match(serialport, b'\n\x03', b'', 0) #ctrl-C, ETX, 本文结束 139 send_and_match(serialport, b'\n\x04', b'', 0) #ctrl-D, EOT, 传输结束 140 time.sleep(2) 141 142 time.sleep(2) 143 144 if i >= 9 : 145 print("[ScriptPrint] reboot fail") 146 print("[ScriptPrint] Please connect the serial port of the board to the PC, then reset the board"); 147 # close serial port 148 serialport.close() 149 return False 150 151 # boot中下载文件 152 print("[ScriptPrint] Downloading files...") 153 for bin_file in bin_files: 154 if not burn_bin_file(serialport, bin_file[0], bin_file[1]): 155 print("[ScriptPrint] Download file %s failed." % bin_file[0]) 156 serialport.close() 157 return False 158 159 # switch partition 160 print("[ScriptPrint] Swap AB partition") 161 send_and_match(serialport, b'3\n', b'', 0) 162 time.sleep(0.5) 163 send_and_match(serialport, b'4\n', b'', 0) 164 time.sleep(0.5) 165 send_and_match(serialport, b'3\n', b'', 0) 166 time.sleep(0.5) 167 send_and_match(serialport, b'2\n', b'', 0) 168 time.sleep(0.1) 169 # workaround retry issue in 2nd boot 170 match = send_and_match(serialport, b'\n'*16, b'2ndboot cli menu', 5) 171 if match: 172 print("[ScriptPrint] Burn \"%s\" success." % bin_files) 173 174 # close serial port 175 serialport.close() 176 177 if match: 178 return True 179 else: 180 return False 181 182def main(): 183 length = len(sys.argv) 184 if (length < 5) or (length % 2 == 0): 185 print("Usage demo: ./flash_program_ll.py COM6 1500000 sendfile flash_addr\n") 186 return 1 187 188 serialport = sys.argv[1] 189 baudrate = sys.argv[2] 190 bin_files = [] 191 for i in range(3, length, 2): 192 filename = sys.argv[i] 193 address = sys.argv[i + 1] 194 bin_files.append((filename, address)) 195 196 ret = burn_bin_files(serialport, baudrate, bin_files) 197 sys.exit(ret) 198 199if __name__ == "__main__": 200 main() 201