77 lines
5.2 KiB
Markdown
77 lines
5.2 KiB
Markdown
1. 4G OTA 下载的时候,为什么使用十六进制下载,读取 URC 事件?
|
||
因为使用二进制下载的时候,经常会出现错误,并且会失败?然后最稳定传输的办法,是每次传输的时候,是分块,而且每次分块都要“删/建”http实例。推测原因是因为我们现在是直接传输文件的源代码,代码中含有了一些字符串可能和 AT指令重复,导致了 AT 模块在解释的时候出错。而使用 16 进制的方式,可以避免这个问题。因为十六进制直接把数据先转成了字符串,然后在设备端再把字符串转成数据,这样就不可能出现 AT的指令,从而减少了麻烦。
|
||
2. 4G OTA 下载的时候,为什么不用 AT 模块里 HTTPDLFILE 的指令?
|
||
因为在测试中发现,使用 HTTPDLFILE,其实是下载到了 4G 模块内部,需要重新从模块内部转到存储卡,而且 4G 模块的存储较小,大概只有 40k,所以还需要分块来下载和转存,比较麻烦,于是最终使用了使用读取串口事件的模式。
|
||
3. 4G OTA 下载的时候,为什么不用 AT 模块里 HTTPREAD 的指令?
|
||
因为之前测试发现,READ模式其实是需要多步:
|
||
3.1. AT+MHTTPCREATE
|
||
3.2. AT+MHTTPCFG
|
||
3.3. AT+MHTTPREQUEST
|
||
3.4. AT+MHTTPREAD
|
||
它其实也是把数据下载到 4g 模块的缓存里,然后再从缓存里读取出来。所以也是比较繁琐的,还不如 HTTPDLFILE 简单。
|
||
4. WiFi OTA 流程(ota_manager.handle_wifi_and_update())
|
||
* 解析 ota_url 得到 host:port
|
||
* 调用 network_manager.connect_wifi(ssid, password, verify_host=host, verify_port=port, persist=True)
|
||
* 只有“能连上 WiFi 且能访问 OTA host:port”才会把新凭证保留在 /boot
|
||
* 连接成功后开始下载 OTA 文件(download_file())
|
||
* 下载成功则 apply_ota_and_reboot()
|
||
5. TCP 通信
|
||
1) 平时 TCP 通信主流程(network_manager.tcp_main())
|
||
外层无限循环:一直尝试保持与服务器的 TCP 会话。
|
||
每轮开始:
|
||
如果 OTA 正在进行:暂停(避免抢占资源/串口)。
|
||
connect_server():建立 TCP 连接(自动选 WiFi 或 4G)。
|
||
发送“登录包”(msg_type=1),等待服务器返回“登录成功”。
|
||
登录成功后进入内层循环:
|
||
接收数据:
|
||
WiFi:非阻塞 recv();没数据返回 b"";有数据进入缓冲区拼包解析。
|
||
4G:从 ATClient 的队列 pop_tcp_payload() 取数据。
|
||
处理命令/ACK:
|
||
登录响应、心跳 ACK、OTA 命令、关机命令、日志上传命令等。
|
||
发送业务队列:
|
||
从高优/普通队列取 1 条,发送失败会放回队首,并断线重连(不再丢消息)。
|
||
发送心跳:
|
||
按 HEARTBEAT_INTERVAL 发心跳包。
|
||
心跳失败会计数(当前为连续失败到阈值才重连)。
|
||
任何发送/接收致命失败:
|
||
关闭 socket/断开连接 → 跳出内层循环 → 外层等待一会儿后重新 connect_server() → 重新登录。
|
||
6. “WiFi 连接/验证”
|
||
TCP 连接建立与网络选择(connect_server() / select_network())
|
||
* select_network():WiFi 优先,但要求:
|
||
is_wifi_connected() 为 True(系统层面有 WiFi IP 或 Maix WLAN connected)
|
||
且能连到 TCP 服务器 SERVER_IP:SERVER_PORT
|
||
否则回退到 4G
|
||
* connect_server():
|
||
若已有连接:WiFi 会做 _check_wifi_connection() 轻量检查;4G 直接认为 OK(由 AT 层维护)。
|
||
否则按网络类型走:
|
||
WiFi:创建 socket → connect → setblocking(False)(接收用非阻塞)
|
||
4G:AT+MIPOPEN 建链
|
||
WiFi 链接(connect_wifi())
|
||
当前 connect_wifi() 的关键特点是:必须让 /etc/init.d/S30wifi restart 真正用新 SSID 去连,所以会临时写 /boot/wifi.ssid 和 /boot/wifi.pass,失败自动回滚。
|
||
流程是:
|
||
(1) 备份旧配置
|
||
* /boot/wifi.ssid、/boot/wifi.pass
|
||
* /etc/wpa_supplicant.conf(尽量备份)
|
||
(2) 写入新凭证
|
||
* 把新 ssid/pass 写到 /boot/*
|
||
-(同时尽量写 /etc/wpa_supplicant.conf,但不强依赖)
|
||
(3) 重启 WiFi 服务:/etc/init.d/S30wifi restart
|
||
(4) 等待获取 IP(默认 20 秒,可调)
|
||
(5) 验证可用性,连到 verify_host:verify_port
|
||
(6) 成功
|
||
* persist=True:保留 /boot/*(持久化)
|
||
* persist=False:回滚 /boot/* 到旧值(不重启,当前连接仍可继续)
|
||
(7) 失败
|
||
* 回滚 /boot/* + 回滚 /etc/wpa_supplicant.conf(如果有备份)
|
||
* 再 S30wifi restart 恢复旧网络
|
||
* 返回错误
|
||
|
||
7. 日志上传(inner_cmd == 43),当前只支持 wifi 上传日志
|
||
命令带 ssid/password/url 时:
|
||
* 若 WiFi 未连接:先 connect_wifi(..., verify_host=upload_host, verify_port=upload_port, persist=True)
|
||
上传内容:
|
||
* sync # 把日志从内存同步到文件
|
||
* 快照 app.log* 到 /tmp staging
|
||
* 打包成 tar.gz(默认)或 zip
|
||
* 以 multipart/form-data 的 file 字段 POST 到 url
|