当前位置: 首页 > news >正文

ESP8285 RTOS SDK OTA

一、官方资源说明

官方指南:空中升级 (OTA) - ESP32 - — ESP-IDF 编程指南 v4.3.6 文档,虽然是正对ESP32的,但是原理是一样的。

官方参考例程:esp-idf\ESP8266_RTOS_SDK\examples\system\ota\,其中包含两个例程,一个是simple_ota_example,另一个是native_ota。simple_ota_example例程调用的是封装之后函数,只需要将固件的下载地址传入函数即可自动完成升级,而native_ota调用的是原生的函数,有更多的过程,详细展示了OTA的下载、存储过程以及校验。这里以simple_ota_example为例进行讲解。

二、修改配置文件

1、修改Partition Table

使用带ota分区的Partition Table,在flash区域中划出两块app存储空间,一块区域是当前运行的app区,另一块区域是新下载的app存放的区域。进入到工程目录中,执行make menuconfig,然后选择

Partition Table  --->

        Partition Table (Single factory app, no OTA)  --->  

                        (X) Factory app, two OTA definitions

2、允许http方式进行ota

此方式不需要证书,更简单。

 Component config  ---> 

        ESP HTTPS OTA  --->

                 [*] Allow HTTP for OTA (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)  

三、编写代码

1、升级流程

上电->进入app_main()->创建升级任务(simple_ota_example_task)->执行任务->等待wifi连接并获取IP地址->http请求服务器上的固件版本号->与当前运行版本号进行比较->如果服务器上的固件版本号更高->下载新的固件->下载完成之后重启设备。

2、代码

版本比较函数

/*** @brief  None.* @param  None.* @retval None.*/
int edition_compare(const char* pszStr1, const char* pszStr2)
{if (pszStr1 == NULL || pszStr2 == NULL) {return 0;}int nCurPos = 0, nCapPos=-1;const char* pszTmp1 = pszStr1;const char* pszTmp2 = pszStr2;while ((*pszTmp1 != '\0') && (*pszTmp2 != '\0') && (*pszTmp1 == *pszTmp2)) {	nCurPos++;									//找到第一个处不相同出现的位置pszTmp1++;pszTmp2++;if (*pszTmp1 == '.') {nCapPos = nCurPos;						//记录最近的‘.’的位置}}if (*pszTmp1 == '\0' && *pszTmp2 == '\0') { // 两个字符串相等return 0;} else if(*pszTmp1 == '\0'){return -1;} else if(*pszTmp2 == '\0'){return 1;}else{ // 两个字符串不相等,比较大小pszTmp1 = pszStr1 + nCapPos + 1;pszTmp2 = pszStr2 + nCapPos + 1;int pszNub1=strtol(pszTmp1,NULL,10);int pszNub2=strtol(pszTmp2,NULL,10);return (pszNub1 - pszNub2);}
}

创建设备事件,用于等待网络连接

const int CONNECTED_BIT = BIT0;s_device_event_group = xEventGroupCreate();

 event_handler()函数中加入s_device_event_group的设置

/*** @brief  event_handler.* @param  None.* @retval None.*/
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();}else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {	xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);xEventGroupClearBits(s_device_event_group, WIFI_CONNECTED_BIT);esp_wifi_connect();}else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);xEventGroupSetBits(s_device_event_group, WIFI_CONNECTED_BIT);}else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {ESP_LOGI(TAG, "Scan done");}else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {ESP_LOGI(TAG, "Found channel");} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {ESP_LOGI(TAG, "Got SSID and password");smartconfig_event_got_ssid_pswd_t* evt = (smartconfig_event_got_ssid_pswd_t*)event_data;wifi_config_t wifi_config;uint8_t ssid[33] = { 0 };uint8_t password[65] = { 0 };uint8_t rvd_data[33] = { 0 };bzero(&wifi_config, sizeof(wifi_config_t));memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));wifi_config.sta.bssid_set = evt->bssid_set;if (wifi_config.sta.bssid_set == true) {memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));}memcpy(ssid, evt->ssid, sizeof(evt->ssid));memcpy(password, evt->password, sizeof(evt->password));ESP_LOGI(TAG, "SSID:%s", ssid);ESP_LOGI(TAG, "PASSWORD:%s", password);if (evt->type == SC_TYPE_ESPTOUCH_V2) {ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );ESP_LOGI(TAG, "RVD_DATA:%s", rvd_data);}ESP_ERROR_CHECK(esp_wifi_disconnect());ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));ESP_ERROR_CHECK(esp_wifi_connect());} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);}
}

任务函数

/*** @brief  None.* @param  None.* @retval None.*/
static void simple_ota_example_task(void * pvParameter)
{EventBits_t uxBits = xEventGroupWaitBits(s_device_event_group, WIFI_CONNECTED_BIT, pdFALSE, false, portMAX_DELAY ); if( (uxBits & WIFI_CONNECTED_BIT) == WIFI_CONNECTED_BIT ){ESP_LOGI(TAG, "Starting OTA example...");char local_response_buffer[101] = {0};esp_http_client_config_t config0 = {.url = "http://www.huochaigun.top/hello-world/version.html",.event_handler = _http_event_handler,
//	        .user_data = local_response_buffer,        // Pass address of local buffer to get response.buffer_size = 100};esp_http_client_handle_t client = esp_http_client_init(&config0);		// GETesp_err_t err = esp_http_client_perform(client);if (err == ESP_OK) {ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",esp_http_client_get_status_code(client),esp_http_client_get_content_length(client));} else {ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));}esp_http_client_read_response( client, local_response_buffer, 100 );local_response_buffer[ esp_http_client_get_content_length(client) ] = '\0';ESP_LOGI(TAG,"http response:%s\n", local_response_buffer );esp_http_client_cleanup(client);if( edition_compare(local_response_buffer, AppVer) > 0 ){esp_http_client_config_t config = {.url = "http://www.huochaigun.top/hello-world/hello-world.bin",.event_handler = _http_event_handler,};esp_err_t ret = esp_https_ota(&config);if (ret == ESP_OK) {esp_restart();} else {ESP_LOGE(TAG, "Firmware Upgrades Failed");}}else{ESP_LOGI(TAG, "The current software is the latest version");}}vTaskDelete( NULL );
}

app_main()中加入以下代码创建任务 

xTaskCreate(simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);

 四、编译固件

执行make之后,会新生成4个bin文件,将4个bin文件下载到设备即可。

0xd000 ota_data_initial.bin
0x0 bootloader.bin
0x10000 hello-world.bin
0x8000 partitions_two_ota.bin

可提供有偿技术支持。

http://www.lryc.cn/news/194053.html

相关文章:

  • Hadoop3教程(四):HDFS的读写流程及节点距离计算
  • [0xGameCTF 2023] web题解
  • Qt之submodule编译
  • Python实现带图形界面的计算器
  • $ vue -Vbash: vue: command not found
  • 专业音视频领域中,Pro AV的崛起之路
  • vscode 右侧滚动条标记不提示,问题解决纪录
  • 【Java 进阶篇】JavaScript特殊语法详解
  • PCL点云处理之配准中的匹配对连线可视化显示 Correspondences(二百一十九)
  • Vue el-table全表搜索,模糊匹配-前端静态查询
  • 基于html5开发的Win12网页版,抢先体验
  • Studio One6.5中文版本下载安装步骤
  • Java架构师缓存架构设计解决方案
  • 【玩转Redhat Linux 8.0系列 | 实验—使用Bash shell执行命令】
  • Linux系统编程详解
  • ios设备管理软件iMazing 2.17.11官方中文版新增功能介绍
  • 算法通关村第18关【青铜】| 回溯
  • 【环境搭建】linux docker-compose安装seata1.6.1,使用nacos注册、db模式
  • 20231008-20231013 读书笔记
  • YOLOv8 windows下的离线安装 offline install 指南 -- 以 带有CUDA版本的pytorch 为例
  • 百度车牌识别AI Linux使用方法-armV7交叉编译
  • 数学建模——确定性时间序列分析方法
  • Opencv——颜色模型+通道分离与合并
  • 解码自然语言处理之 Transformers
  • 【前端设计模式】之迭代器模式
  • 【Android知识笔记】图片专题(BitmapDrawable)
  • 前端工程化知识系列(10)
  • 大数据flink篇之三-flink运行环境安装(一)单机Standalone安装
  • Redisson使用延时队列
  • 基于php 进行每半小时钉钉预警