我前面介紹過RT-thread的一種OTA方案,可以通過串口或者網絡進行遠程升級,那今天在原來的這套方案的基礎上做一些修改,實現U盤升級。
相比于串口和網絡,U盤升級在某些方面有很大的優(yōu)勢,首先它不需要網絡,對于那些不具備上網功能的設備來說很方便,其次它不需要連接數據線,在距離上有優(yōu)勢,說到這,可能有人會說,u盤要插到設備上才能用,距離怎么就有優(yōu)勢了呢?
是的,U盤升級確實需要有人到設備這邊手動操作,但是因為U盤是很通用的設備,即使是非研發(fā)人員也可以操作,不需要燒錄器,也不需要安裝一些驅動和軟件,只需要找一個U盤把升級固件放進去,然后插到設備上升級即可。
比如有個客戶安裝了我們的設備,但是后來軟件要進行升級優(yōu)化,如果這個設備是支持U盤升級的那么我就可以把升級的固件發(fā)給客戶,讓他自己用一個U盤來升級設備,這樣一來,我們就不需要跑到現場去燒錄固件了。
好了,廢話不多說,馬上開整。
一、掛載U盤
使用U盤升級,第一步要先把U盤的讀寫調試好,關于U盤的使用,可以看下我之前的博客,有很詳細的介紹,這里就不多說了。
RT-thread應用講解——U盤(usb host)
二、使能OTA
要想遠程升級,那肯定先得有OTA的功能,關于OTA的使用我在前面的博客里面也詳細介紹過了,不知道的同學可以先去看下。
RT-thread應用講解——OTA
OTA部分只要要完成bootloader的制作和app的制作即可。這兩部分都調試好了之后就可以加入U盤升級的代碼。
三、U盤升級代碼
前面把U盤的掛載和OTA都調試好了之后就可以使用U盤來進行OTA了。
示例代碼如下:
#include <rtthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <finsh.h>
#include <fal.h>
#include <dfs_posix.h>
#define DBG_SECTION_NAME "ota_usb"
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>
/* 固件版本號 */
#define APP_VERSION "1.0.0"
/* 固件名稱 */
#define USBH_UPDATE_FN "/rtthread.rbl"
/* 固件下載分區(qū)名稱 */
#define DEFAULT_DOWNLOAD_PART "download"
static char* recv_partition = DEFAULT_DOWNLOAD_PART;
rt_sem_t ota_sem = RT_NULL;
static void print_progress(size_t cur_size, size_t total_size)
{
static unsigned char progress_sign[100 + 1];
uint8_t i, per = cur_size * 100 / total_size;
if (per > 100)
{
per = 100;
}
for (i = 0; i < 100; i++)
{
if (i < per)
{
progress_sign[i] = '=';
}
else if (per == i)
{
progress_sign[i] = '>';
}
else
{
progress_sign[i] = ' ';
}
}
progress_sign[sizeof(progress_sign) - 1] = '?';
LOG_I("?33[2A");
LOG_I("Download: [%s] %d%%", progress_sign, per);
}
static int ota_usb_download_entry(void* parameter)
{
DIR *dirp;
static size_t update_file_total_size, update_file_cur_size;
static const struct fal_partition * dl_part = RT_NULL;
static int fd;
static rt_uint8_t buf[1024];
static rt_err_t result;
struct stat file;
rt_kprintf("The current version of APP firmware is %sn", APP_VERSION);
while(1)
{
result = rt_sem_take(ota_sem, RT_WAITING_FOREVER);
if(result == RT_EOK)
{
rt_kprintf("Default save firmware on download partition.n");
rt_kprintf("Warning: usb has started! This operator will not recovery.n");
/* 查詢固件大小 */
result = stat(USBH_UPDATE_FN, &file);
if(result == RT_EOK)
{
LOG_D(""USBH_UPDATE_FN" file size is : %dn", file.st_size);
}
else
{
LOG_E(""USBH_UPDATE_FN" file not fonud.");
goto __exit;
}
if(file.st_size <= 0)
{
LOG_E(""USBH_UPDATE_FN" file is empty.");
goto __exit;
}
/* 獲取"download"分區(qū)信息并清除分區(qū)數據 */
if ((dl_part = fal_partition_find(recv_partition)) == RT_NULL)
{
LOG_E("Firmware download failed! Partition (%s) find error!", recv_partition);
goto __exit;
}
if (file.st_size > dl_part->len)
{
LOG_E("Firmware is too large! File size (%d), '%s' partition size (%d)", file.st_size, recv_partition, dl_part->len);
}
if (fal_partition_erase(dl_part, 0, file.st_size) < 0)
{
LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
}
/* 以只讀模式打開固件 */
fd = open(USBH_UPDATE_FN, O_RDONLY);
if (fd >= 0)
{
do
{
/* 讀取u盤的固件,一次讀1024字節(jié) */
update_file_cur_size = read(fd, buf, sizeof(buf));
/* 把固件寫入片外flash的download分區(qū) */
if (fal_partition_write(dl_part, update_file_total_size, buf, update_file_cur_size) < 0)
{
LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name);
close(fd);
goto __exit;
}
update_file_total_size += update_file_cur_size;
print_progress(update_file_total_size, file.st_size);
}
while (update_file_total_size != file.st_size);
close(fd);
}
else
{
LOG_E("check: open file for read failedn");
goto __exit;
}
rt_kprintf("Download firmware to flash success.n");
rt_kprintf("System now will restart...rn");
/* wait some time for terminal response finish */
rt_thread_delay(rt_tick_from_millisecond(200));
/* Reset the device, Start new firmware */
extern void rt_hw_cpu_reset(void);
rt_hw_cpu_reset();
/* wait some time for terminal response finish */
rt_thread_delay(rt_tick_from_millisecond(200));
__exit:
LOG_E("download rtthread.rbl file failed");
}
}
}
void ota_usb_init(void)
{
fal_init();
ota_sem = rt_sem_create("otasem", 0, RT_IPC_FLAG_FIFO);
rt_thread_t thread1 = rt_thread_create("ota_usb", ota_usb_download_entry, RT_NULL, 4096, 26, 10);
if (thread1 != RT_NULL)
{
rt_thread_startup(thread1);
}
}
INIT_APP_EXPORT(ota_usb_init);
static rt_uint8_t ota_usb_start(void)
{
rt_sem_release(ota_sem);
return RT_EOK;
}
MSH_CMD_EXPORT(ota_usb_start, OTA start);
四、運行測試
先做好一個要升級的固件(rtthread.rbl)放到U盤里,插入U盤之后,查看U盤是否有該文件。
通過調用命令開始升級。
提示:用命令只是為了方便調試,實際使用可以通過實體按鍵或屏幕按鍵來觸發(fā)升級。
至此,整個升級的流程就走完了。
五、結束語
好了,關于U盤升級的介紹就到這里,整個流程看著挺復雜,但是知道原理之后回頭再看,其實結構還是很清晰的,如果還有什么問題,歡迎在評論區(qū)留言。如果這篇文章能夠幫到你,就給我點個贊吧,如果想了解更多RT-thread和單片機的內容,可以關注一下博主,后續(xù)我還會繼續(xù)分享更多的經驗給大家。
教程相關源碼:https://download.csdn.net/download/ShenZhen_zixian/12880749
RT-thread相關教程匯總:https://blog.csdn.net/ShenZhen_zixian/article/details/120563891