1背景 & 现状: 2 3目前Hi3861使用Hiburn.exe工具对设备进行烧录,烧录完成后重启设备自动执行测试用例,xDevice测试框架将收集测试用例执行数据,将其数据处理、结果解析,生成测试报告。但由于各厂商L0板子与Hi3861烧录方式不尽相同,为了兼容不同厂商也能在xDevice测试框架上执行,测试框架提供了支持调用厂商升级脚本对设备实现烧写和用例执行。 4 5前提: 6 71. 串口可以实现AT命令(借助其它工具)重启和复位; 82. 刷机工具支持命令自动刷机; 9 10以下是Hiburn和升级脚本两种烧录方式,请自行选择合适的烧录方式: 11 12- Hiburn工具烧录(命令行烧写) 13 14命令行烧录和用例执行步骤: 15 161. 设备复位 17 18 AT+RST=20000000 -》复位设备,等待20s在复位,否则复位不成功 19 202. send file 21 22 发送bin文件到设备,在Window环境下,Hiburn.exe支持以命令行的方式调用,调用命令如下: 23 24```shell 25Hiburn.exe params 26``` 27 28 命令之间用空格隔开,如果命令带有参数,命令和参数之间作用冒号隔开,示例如下: 29 30``` 31Hiburn.exe -com:20 -bin:C:\test_bin\xxx.bin -signalbaud:115200 32``` 33 34Hiburn.exe烧写命令参数 35 36| 命令 | 参数 | 说明 | 37| ------------ |------------------|------------------------------------------------| 38| -com | x | PC端的串口号(例如1) | 39| -bin | path\upgrade.bin | 固件包upgrade.bin的绝对路径,固件包的名称和文件类型根据各产品实际情况可能有所不同 | 40| - signalbaud | 115200 | RomBoot下传输固件包时的串口波特率,默认为 115200bit/s | 41 423. 重启设备 43 44 与串口建立连接后发送[239, 190, 173, 222, 12, 0, 135, 120, 0, 0, 97, 148]重启设备,然后开始自动执行用例,将执行数据返回给测试框架。 45 46 Command – Reset对应的AT命令如下 47 48```shell 49['0xef', '0xbe', '0xad', '0xde', '0xc', '0x0', '0x87','0x78', '0x0', '0x0', '0x61', '0x94'] 50``` 51 52 备注:如果开发板支持Hiburn方式烧录,不需要提供升级脚本。 53 54- 升级脚本烧写 55 561. 初始化升级类 57 58 建议:文件名和类名以名字后缀区分不同厂商,如UpGradeDeviceHuawei 59 60 初始化升级类,如UpGradeDeviceXXX 61 62 输入:串口号、波特率、执行文件bin路径、烧录工具名称、其它参数等 63 64 如下图: 65 66 67 682. 调用方法burn实现烧写 69 70 该函数主要是对设备进行复位、擦除、烧写设备,烧写成功返回True,失败返回False 71 72 73 74 1) 函数_reset() 75 76 发送命令让设备复位 77 78  79 80 2) 函数_upgrade_device() 81 82 对设备进行烧录 83 84 85 863. 调用方法reset_device重启设备 87 88 该函数主要是重启设备,然后自动执行用例,返回用例执行数据给测试框架。 89 90 91 92 1 ) 返回重启设备的AT命令,由xDevice框架做重启设备的操作 93 94 95 96 2) 在不知道AT命令情况下,借助三方工具重启设备,将执行用例的数据返回给xDevice做处理 97 98 99 100 101 102 升级脚本Demo 103 104``` 105import time 106import serial 107import re 108import subprocess 109 110PATTERN = re.compile(r'\x1B(\[([0-9]{1,2}(;[0-9]{1,2})*)?m)*') 111# 测试套结束标签 112CTEST_END_SIGN = "All the test suites finished" 113 114 115class UpGradeDeviceXXX: 116 """ 117 升级类,类名使用大写字母开头的单词(CapWords)风格命令,其中XXX表示芯片型号或者厂商:如UpGradeDeviceHi3861 118 """ 119 120 def __init__(self, serial_port, baund_rate, patch_file, burn_tools, **kwargs): 121 self.serial_port = serial_port 122 self.baund_rate = baund_rate 123 self.patch_file = patch_file 124 self.burn_tools = burn_tools 125 self.object_com = None 126 self.is_open = None 127 self.arg = kwargs 128 129 def _connect(self): 130 ''' 131 连接串口 132 @return: 133 ''' 134 try: 135 if not self.is_open: 136 self.object_com = serial.Serial(self.serial_port, baudrate=self.baund_rate, timeout=1) 137 self.is_open = True 138 except Exception as error_msg: 139 error = "connect {} serial failed,please make sure this port is not occupied,error is {}".format( 140 self.serial_port, str(error_msg)) 141 raise (error) 142 143 def _close(self): 144 ''' 145 关闭串口 146 @return: 147 ''' 148 try: 149 if not self.object_com: 150 return 151 if self.is_open: 152 self.object_com.close() 153 self.is_open = False 154 except (ConnectionError, Exception) as _: 155 error_message = "Local device is disconnected abnormally" 156 raise (error_message) 157 158 def _execute_command_with_time(self, com, command, timeout): 159 ''' 160 执行命令行函数 161 @param com: 162 @param command: 163 @param timeout: 164 @return: 165 ''' 166 if isinstance(command, str): 167 command = command.encode("gbk") 168 if command[-2:] != b"\r\n": 169 command = command.rstrip() + b'\r\n' 170 com.write(command) 171 else: 172 com.write(command) 173 return self._read_local_output(com=com, command=command, 174 timeout=timeout) 175 176 def _read_local_output(self, com=None, command=None, timeout=None): 177 ''' 178 通过串口方式读取设备数据 179 @param com:串口 180 @param command:执行命令 181 @param timeout:函数超时时间 182 @return: 183 ''' 184 result = None 185 input_command = command 186 start = time.time() 187 while True: 188 data = com.readline().decode('gbk', errors="ignore") 189 data = PATTERN.sub("", data) 190 if isinstance(input_command, list): 191 if len(data.strip()) > 0: 192 # 测试日志添加时间戳 193 data = "{} {}".format(self._get_current_time(), data) 194 result = "{}{}".format(result, data.replace("\r", "")) 195 if re.search(r"\d+\s+Tests\s+\d+\s+Failures\s+\d+\s+Ignored", data): 196 start = time.time() 197 if CTEST_END_SIGN in data: 198 break 199 if (int(time.time() - int(start))) > timeout: 200 return result 201 else: 202 result = "{}{}".format(result, data.replace("\r", "").replace("\n", "").strip()) 203 if (int(time.time() - int(start))) > timeout: 204 return result 205 206 print("result:{}".format(result)) 207 return result 208 209 def _reset(self): 210 ''' 211 发送AT命令让设备复位 212 根据实际AT命令或者工具实现,如"AT+RST=20000000"是Hi3861芯片的复位命令,该函数开发根据自己业务修改 213 @return: 214 ''' 215 self._connect() 216 self._execute_command_with_time(com=self.object_com, command="AT+RST=20000000", timeout=2) 217 self._close() 218 219 def _upgrade_device(self): 220 ''' 221 烧录设备,根据各自实际情况调用升级工具对设备进行烧录 222 @return: 成功返回Ture,失败返回False 223 ''' 224 225 try: 226 port_number = re.findall(r'\d+$', self.serial_port) 227 upgrade_command = "{} -com:{} -bin:{} -signalbaud:{}".format(self.burn_tools, port_number[0], 228 self.patch_file, self.baund_rate) 229 return_code, upgrade_result = subprocess.getstatusoutput(upgrade_command) 230 if return_code == 0: 231 print("Upgrade device success !") 232 return False 233 else: 234 print("Upgrade device fail !") 235 return False 236 except Exception as error: 237 print("Upgrade device error:{}".format(error)) 238 return False 239 240 def restart_device(self): 241 ''' 242 重启设备,可以通过AT命令或者三方工具重启设备 243 @return: 用例执行数据 244 ''' 245 # 方法1:直接返回AT命令给测试框架,由测试框架重启设备,以下是3861的Reset AT命令 246 # RESET_CMD = "0xEF,0xBE,0xAD,0xED,0x0C,0x00,0x87,0x00,0x00,0x61,0x94" 247 # reset_cmd = [] 248 # reset_cmd = RESET_CMD.replace(" ", "").split(",") 249 # reset_cmd = [int(item, 16) for item in reset_cmd] 250 # return reset_cmd 251 252 # 方法2:在不知道AT命令情况下,可以通过三方工具重启命令,返回用例执行数据,如通过JFlash工具重启设备 253 result = None 254 restart_command = "{} -startapp -hide -exit".format(self.burn_tools) 255 print("Restart command:{}".format(restart_command)) 256 print("Reseting device,please wait....") 257 return_code, out = subprocess.getstatusoutput(restart_command) 258 if 0 == return_code: 259 print("Restart device success!!") 260 # 重启设备后,连接串口,获取用例执行数据 261 self._connect() 262 result = self._execute_command_with_time(com=self.object_com, command=[], timeout=90) 263 self._close() 264 else: 265 print("Restart device fail!!") 266 return result 267 268 def burn(self): 269 """ 270 烧录接口 271 主要实现设备烧录,有些开发板还需要执行前先执行擦除操作,根据实际业务实现 272 :return: 273 """ 274 # 1.设备复位 275 # 连接串口,发送AT命令复位,各厂商复位命令不同 276 self._reset() 277 # 2.烧写设备 278 return self._upgrade_device() 279 280 def _get_current_time(self): 281 """ 282 获取当前时间戳 283 :return: 284 """ 285 current_time = time.time() 286 local_time = time.localtime(current_time) 287 data_head = time.strftime("%Y-%m-%d %H:%M:%S", local_time) 288 millisecond = (current_time - int(current_time)) * 1000 289 return "%s.%03d" % (data_head, millisecond) 290 291 292if __name__ == '__main__': 293 # 1.初始化升级类 294 serial_port = "com8" 295 baund_rate = 115200 296 patch_file = r"C:\test_bin\xxx.bin" 297 burn_tools = r"D:\DeviceTests\Hiburn.exe" 298 upgrade = UpGradeDeviceXXX(serial_port=serial_port, 299 baund_rate=baund_rate, 300 patch_file=patch_file, 301 burn_tools=burn_tools) 302 303 # 2.烧写设备 304 result = upgrade.burn() 305 306 # 3.重启设备 307 result_data = upgrade.restart_device() 308 print("result_data:{}".format(result_data)) 309 310``` 311 312