接上一篇博文,使用了在線升級的STM32程序的方法。此篇博文將利用4G模塊Air720H,使用AT指令集,通過HTTP協議從雲端服務器下載新版固件,從而實現對STM32的遠程無線程序升級。
前面關於前期準備工作,在此不再累述 具體可以參考上一篇博文https://blog.csdn.net/ylzmm/article/details/104234099,關於簡易的HTTP服務器的搭建參考這篇博文https://blog.csdn.net/ylzmm/article/details/104311190。
本文在 RT_thread給出的HTTP升級的案例(具體參考https://www.rt-thread.org/document/site/application-note/system/rtboot/an0028-rtboot/中的源碼實現部分),進行了部分修改。修改了爲AT指令的方式獲取固件。以下是整體的升級思路和在使用AT指令獲取固件時需要注意的事項。
1.AT指令獲取固件 (未提供完整AT指令步驟,重點步驟提出)
發送:AT+HTTPACTION=0
應答:
OK
+HTTPACTION: 0,200,92240 /*200爲正常的服務器返回狀態 92240爲固件大小*/
發送:AT+HTTPREAD=0,100 /*0表示獲取固件從固件頭開始,100表示獲取前100個字節*/
應答: /*100,100 表示獲取從固件的100字節開始,後面100個字節*/
+HTTPREAD: 100 /*本次獲取的固件大小100*/
RBLk??^app2.0.000010203040506070809`?荱{qa苧餲噗?%2? /*實際固件數據*/
OK
通過AT指令依次循環獲取固件數據,獲取一批固件數據,寫入FLASH,以此循環。
2.固件數據的接收與寫入處理
但是我在調試的過程中遇到了一個很奇特的問題。在升級固件時偶爾會出現升級失敗的現象,提示固件的CRC校驗錯誤,明顯是固件數據出現了遺漏。開始的時候我一直覺得是HTTP通信的問題,通信上下載固件數據偶爾出現了掉數據,後面實際中測試發現某次固件升級不成功,他會一直不成功,無論你重複下載多少次。由此排除了通信遺漏數據問題。之前我遇到的問題可以參考論壇中這一篇https://www.rt-thread.org/qa/thread-423550-1-1.html。
採用論壇中網友的答覆的方法,從而解決了這個問題。
確實。我進行AT指令的應答處理中,我遺漏了一個很嚴重的問題。固件數據是一堆16進制的數據,如果我以讀取到OK,或者\r\n
這樣的判斷方式來進行判斷本次接收固件數據完畢,很容易出現誤判,固件數據可能存在干擾。
最後採用了以下方式成功做到了100%升級:
/*僅僅發送 應答數據在URC函數中處理*/
if (at_exec_cmd(NULL,"AT+HTTPREAD=%d,4096",len_fir) != RT_EOK)
{
LOG_E("AT+HTTPACTION=%d,4096, send commands failed , response error or timeout
!",len_fir);
goto __exit;
}
/*發送郵件 下載的字節數*/
rt_mb_send(&http_mb, (rt_uint32_t)4096);
/* 等待http數據傳回 信號量 */
result = rt_sem_take(http_dysem, HTTP_OTA_OUTTIME);
AT指令只是發生下載的固件的指令,不進行返回值的判斷處理。一直等待一個信號量。
/*HTTP固件信息數據處理*/
static void urc_http_func(struct at_client *client ,const char *data, rt_size_t size)
{
char *recv_buf = RT_NULL;
int number = 0;
recv_buf = (char *)rt_calloc(1, 4096);
if (rt_mb_recv(&http_mb, (rt_ubase_t *)&number, RT_WAITING_FOREVER) == RT_EOK)
{
at_client_obj_recv(client,recv_buf,number,number);
// /*打印接收部分數據*/
// ulog_hexdump(LOG_TAG, 16, (rt_uint8_t *)recv_buf, number);
rt_memset(firmware_http,0,sizeof(firmware_http));
rt_memcpy(firmware_http,recv_buf,number);
rt_sem_release(http_dysem);
}
rt_free(recv_buf);
}
static struct at_urc urc_firmware[]= {
{"+HTTPREAD:", "\r\n", urc_http_func},
};
通過註冊URC回調函數,當接收到“+HTTPREAD:”數據時,表明了正在進入了固件下載時。於是在URC回調函數中進行接收指定的固件數的大小的數據字節即可。
更加具體的代碼實現,可以去參考RT的底層上關於TCP接收服務器下發的數據的處理方法。