基于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. 基于Jira的运维发布平台的设计与实现

    作者:乔克 公众号:运维开发故事 上线发布是运维的日常工作,常见的发布方式有: 手动发布 Jenkins发布平台 Gitlab CI ...... 除此之外还有需要开源软件,他们都有非常不错的发布管理 ...

  2. Linxu 修改主机名

    方法一: # hostname NEW_NAME <这种方法只对当前系统有效,重启后无效> 方法二: # hostnamectl set-hostname NEW_NAME:设定主机名,永 ...

  3. zookeeper之二:zookeeper3.7.0安装过程实操

    前面分享了zookeeper的基本知识,下面分享有关zookeeper安装的知识. 1.下载 zookeeper的官网是:https://zookeeper.apache.org/ 在官网上找到下载链 ...

  4. Python+Selenium自动化-清空输入框、输入内容、点击按钮

    Python+Selenium自动化-清空输入框.输入内容.点击按钮   1.输入内容 send_keys('valve'):输入内容valve #定位输入框 input_box = browser. ...

  5. Angel图算法

    Angel图算法 [2.0]CommonFriends 计算两个好友的共同好友数,某种程度上可以刻画两个节点之间的紧密程度. 输入 输入数据路径:输入文件所在路径,无权网络数据, 数据格式为两列 sr ...

  6. 编写CUDA内核

    编写CUDA内核 介绍 与用于CPU编程的传统顺序模型不同,CUDA具有执行模型.在CUDA中,编写的代码将同时由多个线程(通常成百上千个)执行.解决方案将通过定义网格,块和线程层次结构进行建模. N ...

  7. httprunner的简介、httprunner做接口测试入门知识,使用httprunner模拟get请求及post请求

    一.httprunner的简介 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种 ...

  8. linux文件内容列传行_行转列

    ================ 文件内容列传行_行转列  ================ 一.列转行 1.编辑测试文件 vi log.txt 16:23:00 8.2% 1773620k 16:2 ...

  9. vulhub-struts2-s2-007

    0x00 漏洞原理   当配置了验证规则 <ActionName>-validation.xml 时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL ...

  10. P4779 【模板】单源最短路径(标准版)单源最短路Dijkstra

    题目描述 给定一个$n$个点,$m$条有向边的带非负权图,请你计算从$s$出发,到每个点的距离. 数据保证你能从$s$出发到任意点. 输入格式 第一行为三个正整数$n,m,s$. 第二行起$m$行,每 ...