ESP32-OTA升级
基于ESP-IDF4.1
1 #include <string.h>
2 #include "freertos/FreeRTOS.h"
3 #include "freertos/task.h"
4 #include "esp_system.h"
5 #include "esp_event.h"
6 #include "esp_log.h"
7 #include "esp_ota_ops.h"
8 #include "esp_http_client.h"
9 #include "esp_flash_partitions.h"
10 #include "esp_partition.h"
11 #include "nvs.h"
12 #include "nvs_flash.h"
13 #include "driver/gpio.h"
14 #include "protocol_examples_common.h"
15 #include "errno.h"
16
17 #if CONFIG_EXAMPLE_CONNECT_WIFI
18 #include "esp_wifi.h"
19 #endif
20
21 #define BUFFSIZE 1024
22 #define HASH_LEN 32 //sha256摘要长度
23
24 static const char *TAG = "native_ota_example";
25 //准备写入闪存的OTA数据写入缓冲区
26 static char ota_write_data[BUFFSIZE + 1] = { 0 };
27 extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
28 extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
29
30 #define OTA_URL_SIZE 256
31
32 static void http_cleanup(esp_http_client_handle_t client)
33 {
34 esp_http_client_close(client);
35 esp_http_client_cleanup(client);
36 }
37
38 //__attribute__((noreturn)) 这个属性告诉编译器函数不会返回,这可以用来抑制关于未达到代码路径的错误。
39 static void __attribute__((noreturn)) task_fatal_error(void)
40 {
41 ESP_LOGE(TAG, "Exiting task due to fatal error...");
42 (void)vTaskDelete(NULL);
43
44 while (1) {
45 ;
46 }
47 }
48
49 static void print_sha256 (const uint8_t *image_hash, const char *label)
50 {
51 char hash_print[HASH_LEN * 2 + 1];
52 hash_print[HASH_LEN * 2] = 0;
53 for (int i = 0; i < HASH_LEN; ++i) {
54 sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
55 }
56 ESP_LOGI(TAG, "%s: %s", label, hash_print);
57 }
58
59 static void infinite_loop(void)
60 {
61 int i = 0;
62 ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it");
63 while(1) {
64 ESP_LOGI(TAG, "Waiting for a new firmware ... %d", ++i);
65 vTaskDelay(2000 / portTICK_PERIOD_MS);
66 }
67 }
68
69 //OTA升级任务
70 static void ota_example_task(void *pvParameter)
71 {
72 esp_err_t err;
73 //更新处理程序,通过esp_ota_begin()设置,必须通过esp_ota_end()释放
74 esp_ota_handle_t update_handle = 0 ;
75 const esp_partition_t *update_partition = NULL;
76
77 ESP_LOGI(TAG, "Starting OTA example");
78
79 const esp_partition_t *configured = esp_ota_get_boot_partition();
80 const esp_partition_t *running = esp_ota_get_running_partition();
81
82 if (configured != running) {
83 ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
84 configured->address, running->address);
85 ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
86 }
87 ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
88 running->type, running->subtype, running->address);
89
90 esp_http_client_config_t config = {
91 .url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,
92 .cert_pem = (char *)server_cert_pem_start,
93 .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
94 };
95
96 #ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
97 char url_buf[OTA_URL_SIZE];
98 if (strcmp(config.url, "FROM_STDIN") == 0) {
99 example_configure_stdin_stdout();
100 fgets(url_buf, OTA_URL_SIZE, stdin);
101 int len = strlen(url_buf);
102 url_buf[len - 1] = '\0';
103 config.url = url_buf;
104 } else {
105 ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
106 abort();
107 }
108 #endif
109
110 #ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
111 config.skip_cert_common_name_check = true;
112 #endif
113
114 esp_http_client_handle_t client = esp_http_client_init(&config);
115 if (client == NULL) {
116 ESP_LOGE(TAG, "Failed to initialise HTTP connection");
117 task_fatal_error();
118 }
119 err = esp_http_client_open(client, 0);
120 if (err != ESP_OK) {
121 ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
122 esp_http_client_cleanup(client);
123 task_fatal_error();
124 }
125 esp_http_client_fetch_headers(client);
126
127 update_partition = esp_ota_get_next_update_partition(NULL);
128 ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
129 update_partition->subtype, update_partition->address);
130 assert(update_partition != NULL);
131
132 int binary_file_length = 0;
133 //处理所有接收数据包
134 bool image_header_was_checked = false;
135 while (1) {
136 int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
137 if (data_read < 0) {
138 ESP_LOGE(TAG, "Error: SSL data read error");
139 http_cleanup(client);
140 task_fatal_error();
141 } else if (data_read > 0) {
142 if (image_header_was_checked == false) {
143 esp_app_desc_t new_app_info;
144 if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
145 //通过下载检查当前版本
146 memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
147 ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
148
149 esp_app_desc_t running_app_info;
150 if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
151 ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
152 }
153
154 const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
155 esp_app_desc_t invalid_app_info;
156 if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
157 ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
158 }
159
160 //通过最新无效分区检查当前版本
161 if (last_invalid_app != NULL) {
162 if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
163 ESP_LOGW(TAG, "New version is the same as invalid version.");
164 ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
165 ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
166 http_cleanup(client);
167 infinite_loop();
168 }
169 }
170 #ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK
171 if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
172 ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
173 http_cleanup(client);
174 infinite_loop();
175 }
176 #endif
177
178 image_header_was_checked = true;
179
180 err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
181 if (err != ESP_OK) {
182 ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
183 http_cleanup(client);
184 task_fatal_error();
185 }
186 ESP_LOGI(TAG, "esp_ota_begin succeeded");
187 } else {
188 ESP_LOGE(TAG, "received package is not fit len");
189 http_cleanup(client);
190 task_fatal_error();
191 }
192 }
193 err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
194 if (err != ESP_OK) {
195 http_cleanup(client);
196 task_fatal_error();
197 }
198 binary_file_length += data_read;
199 ESP_LOGD(TAG, "Written image length %d", binary_file_length);
200 } else if (data_read == 0) {
201 //由于esp_http_client_read从不返回负错误代码,因此我们依赖“errno”来检查底层传输连接关闭(如果有)
202 if (errno == ECONNRESET || errno == ENOTCONN) {
203 ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
204 break;
205 }
206 if (esp_http_client_is_complete_data_received(client) == true) {
207 ESP_LOGI(TAG, "Connection closed");
208 break;
209 }
210 }
211 }
212 ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
213 if (esp_http_client_is_complete_data_received(client) != true) {
214 ESP_LOGE(TAG, "Error in receiving complete file");
215 http_cleanup(client);
216 task_fatal_error();
217 }
218
219 err = esp_ota_end(update_handle);
220 if (err != ESP_OK) {
221 if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
222 ESP_LOGE(TAG, "Image validation failed, image is corrupted");
223 }
224 ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
225 http_cleanup(client);
226 task_fatal_error();
227 }
228
229 err = esp_ota_set_boot_partition(update_partition);
230 if (err != ESP_OK) {
231 ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
232 http_cleanup(client);
233 task_fatal_error();
234 }
235 ESP_LOGI(TAG, "Prepare to restart system!");
236 esp_restart();
237 return ;
238 }
239
240 //诊断
241 static bool diagnostic(void)
242 {
243 gpio_config_t io_conf;
244 io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
245 io_conf.mode = GPIO_MODE_INPUT;
246 io_conf.pin_bit_mask = (1ULL << CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
247 io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
248 io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
249 gpio_config(&io_conf);
250
251 ESP_LOGI(TAG, "Diagnostics (5 sec)...");
252 vTaskDelay(5000 / portTICK_PERIOD_MS);
253
254 bool diagnostic_is_ok = gpio_get_level(CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
255
256 gpio_reset_pin(CONFIG_EXAMPLE_GPIO_DIAGNOSTIC);
257 return diagnostic_is_ok;
258 }
259
260 void app_main(void)
261 {
262 uint8_t sha_256[HASH_LEN] = { 0 };
263 esp_partition_t partition;
264
265 //获取分区表的sha256摘要
266 partition.address = ESP_PARTITION_TABLE_OFFSET;
267 partition.size = ESP_PARTITION_TABLE_MAX_LEN;
268 partition.type = ESP_PARTITION_TYPE_DATA;
269 esp_partition_get_sha256(&partition, sha_256);
270 print_sha256(sha_256, "SHA-256 for the partition table: ");
271
272 //获取引导加载程序的sha256摘要
273 partition.address = ESP_BOOTLOADER_OFFSET;
274 partition.size = ESP_PARTITION_TABLE_OFFSET;
275 partition.type = ESP_PARTITION_TYPE_APP;
276 esp_partition_get_sha256(&partition, sha_256);
277 print_sha256(sha_256, "SHA-256 for bootloader: ");
278
279 //获取运行分区的sha256摘要
280 esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
281 print_sha256(sha_256, "SHA-256 for current firmware: ");
282
283 const esp_partition_t *running = esp_ota_get_running_partition();
284 esp_ota_img_states_t ota_state;
285 if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
286 if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
287 // 运行诊断功能 ...
288 bool diagnostic_is_ok = diagnostic();
289 if (diagnostic_is_ok) {
290 ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ...");
291 esp_ota_mark_app_valid_cancel_rollback();
292 } else {
293 ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ...");
294 esp_ota_mark_app_invalid_rollback_and_reboot();
295 }
296 }
297 }
298
299 // 初始化NVS
300 esp_err_t err = nvs_flash_init();
301 if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
302 //OTA应用程序分区表有一个比非OTA分区表更小的NVS分区。大小不匹配可能导致NVS初始化失败,如果发生这种情况,我们擦除NVS分区并在此初始化NVS
303 ESP_ERROR_CHECK(nvs_flash_erase());
304 err = nvs_flash_init();
305 }
306 ESP_ERROR_CHECK( err );
307
308 ESP_ERROR_CHECK(esp_netif_init());
309 ESP_ERROR_CHECK(esp_event_loop_create_default());
310
311 //连接网络
312 ESP_ERROR_CHECK(example_connect());
313
314 #if CONFIG_EXAMPLE_CONNECT_WIFI
315 //确保禁用低功耗模式,这样可以提供最佳的吞吐量从而节省OTA操作的时间
316 esp_wifi_set_ps(WIFI_PS_NONE);
317 #endif
318 xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
319 }
原文:https://gitee.com/EspressifSystems/esp-idf/tree/master/examples/system/ota
ESP32-OTA升级的更多相关文章
- Android OTA 升级之三:生成recovery.img
Android OTA 升级之三:生成recovery.img 作者: 宋立新 Email:zjujoe@yahoo.com 前言 得到了ota升级包后,我们就可以用它来升级系统了.Android 手 ...
- android 标准OTA升级流程
标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户.推送的信息常常会包含OTA更新包的下载地址和一些版本信息. 2.Update程序会将 ...
- ESP8266远程OTA升级
https://blog.csdn.net/xh870189248/article/details/80095139 https://www.wandianshenme.com/play/arduin ...
- ota升级动画修改
在网上可以搜到很多相关的文章,但是很多文章都是复制粘贴而来的,为了方便后面工作学习,本文会把其中最关键的几个步骤列出来. 首先根据ota升级界面的文字可以确认相关的图片资源的目录在哪里,可以网上搜一下 ...
- 乐鑫esp8266基于freeRtos实现私有服务器本地远程OTA升级
目录 一.前言: 二.回顾下OTA的流程: 三.lwip网络框架的知识的使用: 四.如何处理服务器返回的数据? 五.扇区的擦除和烧写? 六.如何调用? 七.好好享用吧! 八.下载: 九.工程截图: 代 ...
- 实现乐鑫esp8266的无线OTA升级,实现远程在线升级固件
代码地址如下:http://www.demodashi.com/demo/12994.html 一.前言: 写了这么多的8266博文,一直以满意100%的心态去敲写代码固件烧录,以致很少出现 bug ...
- OTA升级
除了云端平台这部分,还要有通讯协议层面.云端和汽车端之间指令的接口和协议的制定,不同车厂会有不同诉求.艾拉比既可以支持车厂私有化定制协议的要求,也可以提供基于OMA标准的协议. 第一,它既是云端的工具 ...
- OTA升级中关于update.zip包的一些总结【转】
本文转载自:http://429564140.iteye.com/blog/2337165 update.zip包整理 一. update.zip包的目录结构 |----boot. ...
- Android Recovery OTA升级(一)—— make otapackage
文件夹 文件夹 概述 make otapackage BUILT_TARGET_FILES_PACKAGE ota_from_target_files WriteFullOTAPackage Sign ...
- OTA升级详解(一)
不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可 ...
随机推荐
- Deploying Portainer CE in Docker
Portainer是一个轻量级的管理UI,它允许你轻松地管理你的Docker和Kubernetes集群 https://documentation.portainer.io/v2.0/deploy/c ...
- 血缘关系分析工具SQLFLOW--实践指南
SQLFlow 是用于追溯数据血缘关系的工具,它自诞生以来以帮助成千上万的工程师即用户解决了困扰许久的数据血缘梳理工作. 数据库中视图(View)的数据来自表(Table)或其他视图,视图中字段(Co ...
- jackjson学习2+CVE-2019-14379漏洞分析
最近想着分析jackson,jackson和fastjson有点相似,浅蓝大神的文章很好,个人受益匪浅 昨天简单说了下jackson的用法,现在继续拓扑,补充前置知识,前置知识补充的足够多,那么漏洞分 ...
- 【Dubbo】SPI
什么是SPI SPI是JDK内置的一种服务提供发现机制.目前市面上很多框架都用它来做服务的扩展发现.简单的说,它是一种动态替换发现的机制. jdk 实现方式 需要在 classpath 下创建一个目录 ...
- CUDA上的量化深度学习模型的自动化优化
CUDA上的量化深度学习模型的自动化优化 深度学习已成功应用于各种任务.在诸如自动驾驶汽车推理之类的实时场景中,模型的推理速度至关重要.网络量化是加速深度学习模型的有效方法.在量化模型中,数据和模型参 ...
- 人脸标记检测:ICCV2019论文解析
人脸标记检测:ICCV2019论文解析 Learning Robust Facial Landmark Detection via Hierarchical Structured Ensemble 论 ...
- H.264/H265码流解析
H.264/H265码流解析 一.H.264码流解析 一个原始的H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成 一个原始的 ...
- 基于ARM Cortex-M的SoC存储体系结构和实战
基于ARM Cortex-M的SoC存储体系结构和实战 System on Chip Architecture Tutorial Memory Architecture for ARM Cortex- ...
- FFmpeg集成到GPU
FFmpeg集成到GPU GPU加速视频处理集成到最流行的开源多媒体工具中. FFmpeg是最流行的开源多媒体操作工具之一,它有一个插件库,可以应用于音频和视频处理管道的各个部分,并在世界各地得到广泛 ...
- 构造无限级树的框架套路,附上python/golang/php/js实现
目录 前言 需求 数据 结果 框架 递归框架 迭代框架 递归框架实现 python golang php js 迭代框架实现 python golang php js 前言 框架思维非常重要,和语言无 ...