基于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升级的更多相关文章

  1. Android OTA 升级之三:生成recovery.img

    Android OTA 升级之三:生成recovery.img 作者: 宋立新 Email:zjujoe@yahoo.com 前言 得到了ota升级包后,我们就可以用它来升级系统了.Android 手 ...

  2. android 标准OTA升级流程

    标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户.推送的信息常常会包含OTA更新包的下载地址和一些版本信息. 2.Update程序会将 ...

  3. ESP8266远程OTA升级

    https://blog.csdn.net/xh870189248/article/details/80095139 https://www.wandianshenme.com/play/arduin ...

  4. ota升级动画修改

    在网上可以搜到很多相关的文章,但是很多文章都是复制粘贴而来的,为了方便后面工作学习,本文会把其中最关键的几个步骤列出来. 首先根据ota升级界面的文字可以确认相关的图片资源的目录在哪里,可以网上搜一下 ...

  5. 乐鑫esp8266基于freeRtos实现私有服务器本地远程OTA升级

    目录 一.前言: 二.回顾下OTA的流程: 三.lwip网络框架的知识的使用: 四.如何处理服务器返回的数据? 五.扇区的擦除和烧写? 六.如何调用? 七.好好享用吧! 八.下载: 九.工程截图: 代 ...

  6. 实现乐鑫esp8266的无线OTA升级,实现远程在线升级固件

    代码地址如下:http://www.demodashi.com/demo/12994.html 一.前言: 写了这么多的8266博文,一直以满意100%的心态去敲写代码固件烧录,以致很少出现 bug ...

  7. OTA升级

    除了云端平台这部分,还要有通讯协议层面.云端和汽车端之间指令的接口和协议的制定,不同车厂会有不同诉求.艾拉比既可以支持车厂私有化定制协议的要求,也可以提供基于OMA标准的协议. 第一,它既是云端的工具 ...

  8. OTA升级中关于update.zip包的一些总结【转】

    本文转载自:http://429564140.iteye.com/blog/2337165 update.zip包整理 一. update.zip包的目录结构           |----boot. ...

  9. Android Recovery OTA升级(一)—— make otapackage

    文件夹 文件夹 概述 make otapackage BUILT_TARGET_FILES_PACKAGE ota_from_target_files WriteFullOTAPackage Sign ...

  10. OTA升级详解(一)

    不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可 ...

随机推荐

  1. 《Matlab实用案例》系列Matlab从入门到精通实用100例案例教程目录(持续更新)

    目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 2. 专栏地址 「 刘一哥与GIS的故事 」之<Matlab使用案例> 3. 专栏目录 [MATLAB统计分析与应用1 ...

  2. docker部署安装流程第一版

    docker部署安装流程第一版 1.以Dockerfile的方式进行构建docker 以cloud 新联盟为例 dockerfile from hub.c.163.com/library/maven  ...

  3. 浅谈:Redis持久化机制(二)AOF篇

    浅谈:Redis持久化机制(二)AOF篇 ​ 上一篇我们提及到了redis的默认持久化方式RDB,是一种通过存储快照数据方式持久化的机制,它在宕机后会丢失掉最后一次更新RDB文件后的数据,这也是由于它 ...

  4. 干货:ANR日志分析全面解析

    一.概述 解决ANR一直是Android 开发者需要掌握的重要技巧,一般从三个方面着手. 开发阶段:通过工具检查各个方法的耗时,卡顿情况,发现一处修改一处. 线上阶段:这个阶段主要依靠监控工具发现AN ...

  5. 结构感知图像修复:ICCV2019论文解析

    结构感知图像修复:ICCV2019论文解析 StructureFlow: Image Inpainting via Structure-aware Appearance Flow 论文链接: http ...

  6. deeplearning算法优化原理

    deeplearning算法优化原理目录· 量化原理介绍 · 剪裁原理介绍 · 蒸馏原理介绍 · 轻量级模型结构搜索原理介绍 1. Quantization Aware Training量化介绍1.1 ...

  7. python+selenium_鼠标事件

    引言--在实际的web产品测试中,对于鼠标的操作,不单单只有click(),有时候还要用到右击.双击.拖动等操作,这些操作包含在ActionChains类中. 一.ActionChains类中鼠标操作 ...

  8. IDEA骚技巧

    1. var 声明 2. null 判空 3. notnull 判非空 4. nn 判非空 5. for 遍历 6. fori 带索引的遍历 7. not 取反 8. if 条件判断 9. cast ...

  9. Centos7 安装 Keepalived

    目标: Keeplaived 简单模拟测试一下Nginx 故障切换前言:C7 默认的 1.3.5 似乎有点问题,改装 keepalived-2.0.7 1:安装 Nginx 和确认 (略)2:安装配置 ...

  10. 【NX二次开发】NX内部函数,查找内部函数的方法

    [NX二次开发]NX内部函数,libufunx.dll文件中的内部函数 [NX二次开发]NX内部函数,libugui.dll文件中的内部函数 [NX二次开发]NX内部函数,libuifw.dll文件中 ...