【ESP32 乐鑫 离线环境搭建】
【ESP32-S2】乐鑫离线环境 与IDF4.3构建自己的项目以及自定义目录
【ESP32-S2】OTA升级代码移植以及APP之间的切换
【ESP32-S2】使用http_cliten 相关API 主动循环下载bin文件
【ESP32-S2】ESP32-S2从服务器下载STM32F103ZET6的bin固件再使用Ymodem通讯实现bootloader
本项目基于2个官方例程1个服务器jar包 idf4.3
1、advanced_https_ota
2、hello_world
3、file-demo-0.0.1-SNAPSHOT.jar
链接:https://pan.baidu.com/s/1hhCDLQSoWAvyNpdD_OcpNA
提取码:n9kz
流程概述:
0x110000的APP1代码远程连接服务器下载其配置的APP2的bin到0x210000地址作为APP2。
然后重启自动运行APP2。
APP2中移植了APP1的OTA部分代码实现远程下载APPx到0x110000,手动重启自动运行APPx。
APPx正常运行一段时间后使用esp_ota_mark_app_invalid_rollback_and_reboot();函数
直接重启回滚 到APP2,之后重启都是运行APP2
注意回滚的意思是当前APP不用了,用上一个好的APP。如果不存在上一个好的则函数无效。
也就是说每一个代码都应该包含该函数保证能回滚到之前正常的app版本
1、首先修改 advanced_https_ota 工程的相关配置
设置WiFi账号密码
服务器链接
跳过证书
跳过版本检测
使能OTA的http访问下载
将最后的代码下载到0x110000地址
无需修改代码,其中URL的下载文件为后面工程编译的而不是自带的hellowold
2、修改hello_world配置
代码中修改服务器链接
代码中修改WiFi账号密码
代码中注释掉证书相关的部分
使能OTA的http访问下载
1、【advanced_https_ota】工程操作如下
设置当前工程为ESP32S2项目
注意:远程更新后若要重新下载,需要先擦除。
2、【hello_world】工程操作如下
注释掉证书相关的代码,WiFi的连接使用sta的代码连接路由器
注意:#define HELLOWOLD 1
使用该宏定义则编译后的bin为hellowold.bin(APP2)
不使用该宏定义则编译后的bin为hellowold1.bin(APPx)此版本不带下载功能,只做APP回退测试用
原始的APP1为advanced_https_ota.bin,运行APP2之后下载的APPx覆盖了APP1
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_ota_ops.h"
#include "esp_wifi.h"
static const char *TAG = "advanced_https_ota_example";
//extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start");
//extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end");
#define CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK 1
#define CONFIG_EXAMPLE_SKIP_VERSION_CHECK 1
#define OTA_URL_SIZE 256
static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
{
if (new_app_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t *running = esp_ota_get_running_partition();
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
}
#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK
if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) {
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
return ESP_FAIL;
}
#endif
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
/**
* Secure version check from firmware image header prevents subsequent download and flash write of
* entire firmware image. However this is optional because it is also taken care in API
* esp_https_ota_finish at the end of OTA update procedure.
*/
const uint32_t hw_sec_version = esp_efuse_read_secure_version();
if (new_app_info->secure_version < hw_sec_version) {
ESP_LOGW(TAG, "New firmware security version is less than eFuse programmed, %d < %d", new_app_info->secure_version, hw_sec_version);
return ESP_FAIL;
}
#endif
return ESP_OK;
}
static esp_err_t _http_client_init_cb(esp_http_client_handle_t http_client)
{
esp_err_t err = ESP_OK;
/* Uncomment to add custom headers to HTTP request */
// err = esp_http_client_set_header(http_client, "Custom-Header", "Value");
return err;
}
void advanced_ota_example_task(void *pvParameter)
{
ESP_LOGI(TAG, "Starting Advanced OTA example");
esp_err_t ota_finish_err = ESP_OK;
esp_http_client_config_t config = {
.url = "http://192.168.216.98:8080/downloadFile/hello-world1.bin",
//.cert_pem = (char *)server_cert_pem_start,
.timeout_ms = 5000,
.keep_alive_enable = true,
};
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
char url_buf[OTA_URL_SIZE];
if (strcmp(config.url, "FROM_STDIN") == 0) {
example_configure_stdin_stdout();
fgets(url_buf, OTA_URL_SIZE, stdin);
int len = strlen(url_buf);
url_buf[len - 1] = '\0';
config.url = url_buf;
} else {
ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
abort();
}
#endif
#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
config.skip_cert_common_name_check = true;
#endif
esp_https_ota_config_t ota_config = {
.http_config = &config,
.http_client_init_cb = _http_client_init_cb, // Register a callback to be invoked after esp_http_client is initialized
};
esp_https_ota_handle_t https_ota_handle = NULL;
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed");
vTaskDelete(NULL);
}
esp_app_desc_t app_desc;
err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed");
goto ota_end;
}
err = validate_image_header(&app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "image header verification failed");
goto ota_end;
}
while (1) {
err = esp_https_ota_perform(https_ota_handle);
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
break;
}
// esp_https_ota_perform returns after every read operation which gives user the ability to
// monitor the status of OTA upgrade by calling esp_https_ota_get_image_len_read, which gives length of image
// data read so far.
ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle));
}
if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) {
// the OTA image was not completely received and user can customise the response to this situation.
ESP_LOGE(TAG, "Complete data was not received.");
} else {
ota_finish_err = esp_https_ota_finish(https_ota_handle);
if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {
ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
for (int i = 32000; i >= 0; i--)
{
printf("OTA0 Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
//vTaskDelay(1000 / portTICK_PERIOD_MS);
//esp_restart();
} else {
if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
}
ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
vTaskDelete(NULL);
}
}
ota_end:
esp_https_ota_abort(https_ota_handle);
ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed");
vTaskDelete(NULL);
}
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG1 = "wifi station";
static int s_retry_num = 0;
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) {
if (s_retry_num < 5) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG1, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG1,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG1, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
cfg.nvs_enable=0;
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = "SGDTEST_1",
.password = "12345678",
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG1, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG1, "connected to ap SSID:%s password:%s",
"SGDTEST_1", "12345678");
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG1, "Failed to connect to SSID:%s, password:%s",
"SGDTEST_1", "12345678");
} else {
ESP_LOGE(TAG1, "UNEXPECTED EVENT");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
}
//#define HELLOWOLD 1
void app_main(void)
{
#ifdef HELLOWOLD
printf("Hello world!\n");
#else
printf("Hello world1!\n");
#endif
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
for (int i = 32767; i >= 0; i--) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
#ifdef HELLOWOLD
printf("Restarting in %d seconds...\n", i);
if(i==32767-20)
{
wifi_init_sta();
xTaskCreate(&advanced_ota_example_task, "advanced_ota_example_task", 1024 * 8, NULL, 5, NULL);
}
#else
printf("OTA1 Restarting in %d seconds...\n", i);
if(i==32767-60)
{
ESP_LOGE(TAG, "回退到之前的app版本");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
#endif
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}
3、服务器jar包的运行方法,安装java 配置环境变量 在命令模式下
浏览器访问
上传的文件保存路径