]> granicus.if.org Git - esp-idf/commitdiff
examples/system/ota/advanced_https_ota: Add example for newly introduced APIs in...
authorJitin George <jitin@espressif.com>
Wed, 3 Apr 2019 14:28:26 +0000 (19:58 +0530)
committerJitin George <jitin@espressif.com>
Thu, 2 May 2019 06:59:29 +0000 (12:29 +0530)
examples/system/ota/advanced_https_ota/CMakeLists.txt [new file with mode: 0644]
examples/system/ota/advanced_https_ota/Makefile [new file with mode: 0644]
examples/system/ota/advanced_https_ota/main/CMakeLists.txt [new file with mode: 0644]
examples/system/ota/advanced_https_ota/main/Kconfig.projbuild [new file with mode: 0644]
examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c [new file with mode: 0644]
examples/system/ota/advanced_https_ota/main/component.mk [new file with mode: 0644]
examples/system/ota/advanced_https_ota/server_certs/ca_cert.pem [new file with mode: 0644]

diff --git a/examples/system/ota/advanced_https_ota/CMakeLists.txt b/examples/system/ota/advanced_https_ota/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3386014
--- /dev/null
@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(advanced_https_ota)
diff --git a/examples/system/ota/advanced_https_ota/Makefile b/examples/system/ota/advanced_https_ota/Makefile
new file mode 100644 (file)
index 0000000..301cf1e
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := advanced_https_ota
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/system/ota/advanced_https_ota/main/CMakeLists.txt b/examples/system/ota/advanced_https_ota/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2b2b107
--- /dev/null
@@ -0,0 +1,8 @@
+set(COMPONENT_SRCS "advanced_https_ota_example.c")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+
+# Embed the server root certificate into the final binary
+set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem)
+
+register_component()
diff --git a/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild b/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..f3f71e3
--- /dev/null
@@ -0,0 +1,21 @@
+menu "Example Configuration"
+
+    config WIFI_SSID
+        string "WiFi SSID"
+        default "myssid"
+        help
+            SSID (network name) for the example to connect to.
+
+    config WIFI_PASSWORD
+        string "WiFi Password"
+        default "mypassword"
+        help
+            WiFi password (WPA or WPA2) for the example to use.
+
+    config FIRMWARE_UPGRADE_URL
+        string "firmware upgrade url endpoint"
+        default "https://192.168.0.3:8070/hello-world.bin"
+        help
+            URL of server which hosts the firmware
+            image.
+endmenu
diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c
new file mode 100644 (file)
index 0000000..43fd162
--- /dev/null
@@ -0,0 +1,177 @@
+/* Advanced HTTPS OTA 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 "string.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "esp_ota_ops.h"
+#include "esp_http_client.h"
+#include "esp_https_ota.h"
+
+#include "nvs.h"
+#include "nvs_flash.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");
+
+/* FreeRTOS event group to signal when we are connected & ready to make a request */
+static EventGroupHandle_t wifi_event_group;
+
+/* The event group allows multiple bits for each event,
+   but we only care about one event - are we connected
+   to the AP with an IP? */
+const int CONNECTED_BIT = BIT0;
+
+static esp_err_t event_handler(void *ctx, system_event_t *event)
+{
+    switch (event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        esp_wifi_connect();
+        break;
+    case SYSTEM_EVENT_STA_GOT_IP:
+        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    case SYSTEM_EVENT_STA_DISCONNECTED:
+        /* This is a workaround as ESP32 WiFi libs don't currently
+           auto-reassociate. */
+        esp_wifi_connect();
+        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+static void initialise_wifi(void)
+{
+    tcpip_adapter_init();
+    wifi_event_group = xEventGroupCreate();
+    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
+    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = CONFIG_WIFI_SSID,
+            .password = CONFIG_WIFI_PASSWORD,
+        },
+    };
+    ESP_LOGI(TAG, "Setting WiFi configuration SSID %s", wifi_config.sta.ssid);
+    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
+    ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
+    ESP_ERROR_CHECK( esp_wifi_start() );
+}
+
+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);
+    }
+
+    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;
+    }
+    return ESP_OK;
+}
+
+void advanced_ota_example_task(void * pvParameter)
+{
+    ESP_LOGI(TAG, "Starting Advanced OTA example");
+
+    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
+                        false, true, portMAX_DELAY);
+    ESP_LOGI(TAG, "Connected to WiFi network! Attempting to connect to server...");
+    
+    esp_err_t ota_finish_err = ESP_OK;
+    esp_http_client_config_t config = {
+        .url = CONFIG_FIRMWARE_UPGRADE_URL,
+        .cert_pem = (char *)server_cert_pem_start,
+    };
+    
+    esp_https_ota_config_t ota_config = {
+        .http_config = &config,
+    };
+    
+    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));
+    }
+
+ota_end:
+    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 ...");
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+        esp_restart();
+    } else {
+        ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed...");
+    }
+
+    while (1) {
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+}
+
+void app_main()
+{
+    // Initialize NVS.
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        // 1.OTA app partition table has a smaller NVS partition size than the non-OTA
+        // partition table. This size mismatch may cause NVS initialization to fail.
+        // 2.NVS partition contains data in new format and cannot be recognized by this version of code.
+        // If this happens, we erase NVS partition and initialize NVS again.
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        err = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( err );
+
+    initialise_wifi();
+    xTaskCreate(&advanced_ota_example_task, "advanced_ota_example_task", 1024 * 8, NULL, 5, NULL);
+}
+
diff --git a/examples/system/ota/advanced_https_ota/main/component.mk b/examples/system/ota/advanced_https_ota/main/component.mk
new file mode 100644 (file)
index 0000000..3a13333
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+COMPONENT_EMBED_TXTFILES :=  ${PROJECT_PATH}/server_certs/ca_cert.pem
diff --git a/examples/system/ota/advanced_https_ota/server_certs/ca_cert.pem b/examples/system/ota/advanced_https_ota/server_certs/ca_cert.pem
new file mode 100644 (file)
index 0000000..e69de29