Compare commits
10
Commits
a74e2d1206
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcd5d5c3f8 | ||
|
|
51fdf710b8 | ||
|
|
95ac96f61c | ||
|
|
40f2d290ae | ||
|
|
e3c55dd432 | ||
|
|
ae2828c6bd | ||
|
|
03b5d12f1b | ||
|
|
b5b27a1937 | ||
|
|
9521a78d13 | ||
|
|
7a6c15193a |
No files matched your search
@@ -1,31 +1,41 @@
|
||||
# ESP32 ESP-IDF component for simple OTA server
|
||||
|
||||
## Tested on
|
||||
## Features
|
||||
|
||||
1. [ESP32 ESP-IDF v6.0.0](https://docs.espressif.com/projects/esp-idf/en/v6.0/esp32/index.html)
|
||||
|
||||
## SAST Tools
|
||||
|
||||
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
|
||||
1. HTTP-based OTA firmware updates via standard HTTP POST requests.
|
||||
2. Automatic partition management with next available OTA partition detection.
|
||||
3. Embedded web interface for browser-based firmware uploads.
|
||||
4. Automatic boot activation and device reboot after successful update.
|
||||
5. Chunked data reception with 1000-byte blocks for efficient memory usage.
|
||||
6. Seamless integration with ESP-IDF HTTP server and OTA APIs.
|
||||
7. Comprehensive error handling with detailed error reporting.
|
||||
8. Low memory footprint with minimal RAM consumption.
|
||||
|
||||
## Using
|
||||
|
||||
In an existing project, run the following command to install the component:
|
||||
|
||||
```text
|
||||
```bash
|
||||
cd ../your_project/components
|
||||
git clone https://github.com/aZholtikov/zh_ota_server
|
||||
```
|
||||
|
||||
In the application, add the component:
|
||||
In the application, include the header:
|
||||
|
||||
```c
|
||||
#include "zh_ota_server.h"
|
||||
```
|
||||
|
||||
## Example
|
||||
## Attention
|
||||
|
||||
OTA server by address <http://192.168.4.1/ota>
|
||||
1. The firmware upload path is fixed to /zh_ota_server and cannot be changed.
|
||||
2. The zh_ota_server_init function must be called only once during application lifetime.
|
||||
3. Memory allocated for the URI path is never freed.
|
||||
4. Flashing an invalid firmware image may render the device unbootable.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Example
|
||||
|
||||
```c
|
||||
#include "nvs_flash.h"
|
||||
@@ -58,7 +68,17 @@ void app_main(void)
|
||||
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
|
||||
esp_wifi_start();
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
httpd_start(&http_server_handle, &config);
|
||||
zh_ota_server_init(http_server_handle, "/ota");
|
||||
esp_err_t ret = httpd_start(&http_server_handle, &config);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
printf("HTTP server start error: %s\n", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
ret = zh_ota_server_init(http_server_handle, "/ota");
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
printf("OTA server init error: %s\n", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
description: ESP32 ESP-IDF component for simple OTA server
|
||||
url: https://github.com/aZholtikov/zh_ota_server
|
||||
version: "1.0.0"
|
||||
license: "Apache-2.0"
|
||||
maintainers:
|
||||
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
||||
dependencies:
|
||||
idf: ">=5.0"
|
||||
@@ -22,9 +22,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "string.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
@@ -38,8 +43,8 @@ extern "C"
|
||||
* the URI path, and registers the HTTP GET (web interface) and HTTP POST
|
||||
* (firmware upload) handlers with the provided HTTP server instance.
|
||||
*
|
||||
* @param[in] server HTTP server handle obtained from httpd_start().
|
||||
* @param[in] path URI path for the OTA server (e.g., "/ota").
|
||||
* @param[in] server HTTP server handle obtained from httpd_start() (must not be NULL)
|
||||
* @param[in] path URI path for the OTA server (e.g., "/ota")
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return ESP_ERR_INVALID_ARG if invalid server handle or path
|
||||
@@ -48,6 +53,7 @@ extern "C"
|
||||
*
|
||||
* @note The path string is copied internally and must not be freed
|
||||
* by the caller.
|
||||
*
|
||||
* @warning The memory allocated for the path is never freed.
|
||||
* Call this function only once during application lifetime.
|
||||
*/
|
||||
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
# Описание компонента zh_ota_server
|
||||
|
||||
## Общие сведения
|
||||
|
||||
**zh_ota_server** — это компонент для ESP-IDF, реализующий сервер обновлений прошивки по воздуху (Over-The-Air, OTA) для микроконтроллеров ESP32.
|
||||
|
||||
Компонент предоставляет веб-интерфейс для загрузки бинарных файлов прошивки через браузер и автоматически записывает их в свободный OTA-раздел ESP32 с последующей активацией и перезагрузкой устройства.
|
||||
|
||||
## Основные возможности
|
||||
|
||||
1. **Веб-интерфейс для загрузки** — встроенная HTML-страница для выбора и отправки файла прошивки через браузер.
|
||||
2. **Автоматическое определение раздела** — компонент сам находит следующий доступный OTA-раздел через API ESP-IDF.
|
||||
3. **Построчная запись прошивки** — данные принимаются блоками по 1000 байт для экономии оперативной памяти.
|
||||
4. **Автоматическая активация и перезагрузка** — после успешной записи прошивки раздел становится главным, и устройство перезагружается.
|
||||
5. **Интеграция с ESP-IDF HTTP server** — компонент использует встроенный HTTP-сервер ESP-IDF и регистрирует свои обработчики как стандартные URI-хендлеры.
|
||||
6. **Встроенная HTML-страница** — веб-интерфейс хранится как встроенный массив байт (EMBED_FILES), не требуя внешней файловой системы.
|
||||
7. **Детальное логирование ошибок** — при ошибках логируются файл, строка и код возврата ESP-IDF.
|
||||
|
||||
## Внутреннее устройство
|
||||
|
||||
### Глобальные переменные
|
||||
|
||||
| Переменная | Тип | Описание |
|
||||
|------------|-----|----------|
|
||||
| `_ota_path` | `char *` | Выделенная динамически память для URI-пути OTA-сервера (не освобождается) |
|
||||
| `_ota_ws_path` | `const char *` | URI-путь для POST-обработчика (`"/zh_ota_server"`) |
|
||||
| `_is_initialized` | `volatile bool` | Флаг инициализации компонента, предотвращающий повторный вызов `zh_ota_server_init()` |
|
||||
|
||||
### Структуры обработчиков
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| `_ota_page.uri` | `char *` | URI-путь для GET-запроса (устанавливается при инициализации) |
|
||||
| `_ota_page.method` | `httpd_method_t` | HTTP-метод: `HTTP_GET` |
|
||||
| `_ota_page.handler` | `httpd_req_handler_t` | Указатель на `_ota_page_handler()` |
|
||||
| `_ota_page_ws.uri` | `char *` | URI-путь для POST-запроса: `"/zh_ota_server"` |
|
||||
| `_ota_page_ws.method` | `httpd_method_t` | HTTP-метод: `HTTP_POST` |
|
||||
| `_ota_page_ws.handler` | `httpd_req_handler_t` | Указатель на `_ota_ws_page_handler()` |
|
||||
|
||||
### Встроенные ресурсы
|
||||
|
||||
HTML-страница `zh_ota_server.html` встраивается в прошивку через механизм `EMBED_FILES` CMake. Доступна через внешние символы:
|
||||
|
||||
| Символ | Описание |
|
||||
|--------|----------|
|
||||
| `zh_ota_server_html_start[]` | Начало встроенного HTML-массива |
|
||||
| `zh_ota_server_html_end[]` | Конец встроенного HTML-массива |
|
||||
|
||||
Размер страницы вычисляется как `zh_ota_server_html_end - zh_ota_server_html_start`.
|
||||
|
||||
### Управление памятью
|
||||
|
||||
При инициализации `zh_ota_path` выделяется через `heap_caps_calloc()` с флагом `MALLOC_CAP_8BIT`. Память **не освобождается** никогда — это осознанный выбор, так как функция инициализации может быть вызвана только один раз за время работы приложения.
|
||||
|
||||
## API (интерфейс)
|
||||
|
||||
### Инициализация
|
||||
|
||||
| Функция | Описание |
|
||||
|---------|----------|
|
||||
| `zh_ota_server_init()` | Инициализирует и регистрирует обработчики OTA-сервера в предоставленном экземпляре HTTP-сервера. Принимает handle сервера (`httpd_handle_t`) и URI-путь (например, `"/ota"`). Возвращает `ESP_OK` при успехе, `ESP_ERR_INVALID_ARG` при некорректных аргументах, `ESP_ERR_NO_MEM` при нехватке памяти, `ESP_FAIL` при ошибке регистрации обработчика. |
|
||||
|
||||
## Потокобезопасность
|
||||
|
||||
Компонент **не является потокобезопасным**. Глобальные переменные `_ota_path` и `_is_initialized` защищены только проверкой на повторную инициализацию (`_is_initialized == false`), но не мьютексами. Обработчики HTTP-запросов вызываются в контексте потока HTTP-сервера и не используют механизмы синхронизации.
|
||||
|
||||
## Алгоритмы
|
||||
|
||||
### Обработка OTA-обновления (`_ota_ws_page_handler`)
|
||||
|
||||
1. Выделение буфера размером **1000 байт** для приёма данных.
|
||||
2. Определение следующего доступного OTA-раздела через `esp_ota_get_next_update_partition(NULL)`.
|
||||
3. Начало записи в раздел через `esp_ota_begin()` с размером `OTA_SIZE_UNKNOWN`.
|
||||
4. **Цикл приёма данных:**
|
||||
- Приём данных из HTTP-запроса через `httpd_req_recv()` блоками до `sizeof(buf)` (1000 байт).
|
||||
- При таймауте сокета (`HTTPD_SOCK_ERR_TIMEOUT`) цикл продолжается без действия.
|
||||
- При ошибке приёма отправляется HTTP 500 и вызывается `esp_ota_abort()`.
|
||||
- Запись данных в flash через `esp_ota_write()`; при ошибке отправляется HTTP 500 и вызывается `esp_ota_abort()`.
|
||||
- Уменьшение счётчика оставшихся байт (`remaining -= recv_len`).
|
||||
5. Завершение записи через `esp_ota_end()` (валидация образа).
|
||||
6. Установка раздела как загрузочного через `esp_ota_set_boot_partition()`.
|
||||
7. Отправка HTTP-ответа `"Firmware update complete, rebooting now!\n"`.
|
||||
8. Задержка **500 мс** через `vTaskDelay()` и вызов `esp_restart()` для перезагрузки.
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Базовый пример
|
||||
|
||||
```c
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "zh_ota_server.h"
|
||||
|
||||
static httpd_handle_t http_server_handle = NULL;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_log_level_set("zh_ota_server", ESP_LOG_ERROR);
|
||||
nvs_flash_init();
|
||||
esp_netif_init();
|
||||
esp_event_loop_run(NULL, NULL);
|
||||
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
httpd_start(&http_server_handle, &config);
|
||||
|
||||
zh_ota_server_init(http_server_handle, "/ota");
|
||||
}
|
||||
```
|
||||
|
||||
### Пример с Wi-Fi в режиме точки доступа
|
||||
|
||||
```c
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "zh_ota_server.h"
|
||||
|
||||
#define WIFI_SSID "ESP32-OTA"
|
||||
#define WIFI_PASS "password123"
|
||||
|
||||
static httpd_handle_t http_server_handle = NULL;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_log_level_set("zh_ota_server", ESP_LOG_DEBUG);
|
||||
nvs_flash_init();
|
||||
esp_netif_init();
|
||||
esp_event_loop_create_default();
|
||||
|
||||
wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT();
|
||||
esp_wifi_init(&wifi_config);
|
||||
|
||||
wifi_config_t ap_config = {
|
||||
.ap = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
.max_connection = 4,
|
||||
.authmode = WIFI_AUTH_WPA2_PSK,
|
||||
},
|
||||
};
|
||||
esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
|
||||
esp_wifi_start();
|
||||
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
httpd_start(&http_server_handle, &config);
|
||||
|
||||
zh_ota_server_init(http_server_handle, "/ota");
|
||||
}
|
||||
```
|
||||
|
||||
## Логирование
|
||||
|
||||
Компонент использует ESP-IDF логирование с тегом `"zh_ota_server"`.
|
||||
|
||||
Макрос `ZH_LOGI` — для информационных сообщений. Макрос `ZH_LOGE` — для ошибок, автоматически добавляет имя файла, номер строки и строковое представление кода ошибки ESP-IDF.
|
||||
|
||||
```c
|
||||
esp_log_level_set("zh_ota_server", ESP_LOG_DEBUG);
|
||||
```
|
||||
|
||||
## Ошибки
|
||||
|
||||
| Код | Описание |
|
||||
|-----|----------|
|
||||
| `ESP_OK` | Успешное выполнение |
|
||||
| `ESP_ERR_INVALID_ARG` | Неверный аргумент: NULL-указатель на сервер или путь |
|
||||
| `ESP_ERR_INVALID_STATE` | Повторная инициализация: компонент уже был инициализирован |
|
||||
| `ESP_ERR_NO_MEM` | Нехватка памяти при выделении для URI-пути |
|
||||
| `ESP_FAIL` | Ошибка регистрации URI-обработчика, записи в flash, завершения OTA или установки загрузочного раздела |
|
||||
|
||||
## Ограничения
|
||||
|
||||
1. **Однократная инициализация** — `zh_ota_server_init()` можно вызвать только один раз за время работы приложения. Повторный вызов вернёт `ESP_ERR_INVALID_STATE`.
|
||||
2. **Утечка памяти URI-пути** — память, выделенная для `_ota_path`, никогда не освобождается.
|
||||
3. **Риск «окирпичивания» устройства** — запись невалидного образа прошивки сделает устройство не загружаемым. Необходимо иметь механизм восстановления (например, USB-прошивку).
|
||||
4. **Отсутствие потокобезопасности** — компонент не защищён мьютексами; одновременный доступ из нескольких потоков может привести к неопределённому поведению.
|
||||
5. **Размер буфера 1000 байт** — фиксированный размер буфера приёма может быть недостаточен для оптимальной производительности при больших объёмах данных.
|
||||
6. **Отсутствие контрольной суммы** — валидация образа выполняется только через `esp_ota_end()`, что не гарантирует корректность прошивки на уровне содержимого.
|
||||
|
||||
## Требования для сборки
|
||||
|
||||
- ESP-IDF (фреймворк для ESP32)
|
||||
- `esp_http_server` — встроенный HTTP-сервер ESP-IDF
|
||||
- `app_update` — модуль ESP-IDF для управления OTA-разделами и загрузкой
|
||||
- FreeRTOS (входит в состав ESP-IDF)
|
||||
|
||||
## Установка
|
||||
|
||||
```bash
|
||||
cd ваш_проект/components
|
||||
git clone https://github.com/aZholtikov/zh_ota_server
|
||||
```
|
||||
|
||||
```c
|
||||
#include "zh_ota_server.h"
|
||||
```
|
||||
+28
-13
@@ -13,17 +13,26 @@ static const char *TAG = "zh_ota_server";
|
||||
return err; \
|
||||
}
|
||||
|
||||
#define ZH_ERROR_CHECK_CONT(cond, cleanup, msg, ...) \
|
||||
if (!(cond)) \
|
||||
{ \
|
||||
ZH_LOGE(msg, ESP_FAIL, ##__VA_ARGS__); \
|
||||
cleanup; \
|
||||
}
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static char *_ota_path = NULL; /*!< Internal storage for the OTA server URI path */
|
||||
static char *_ota_ws_path = "/zh_ota_server"; /*!< Fixed URI path for WebSocket-style firmware upload */
|
||||
static char *_ota_path = NULL;
|
||||
static const char *_ota_ws_path = "/zh_ota_server";
|
||||
|
||||
volatile static bool _is_initialized = false;
|
||||
|
||||
/**
|
||||
* @brief HTTP GET handler for the OTA web interface.
|
||||
*
|
||||
* Serves the embedded HTML page for firmware upload via HTTP response.
|
||||
*
|
||||
* @param req HTTP request structure.
|
||||
* @param req HTTP request structure
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return ESP_FAIL if failed to send the response
|
||||
@@ -37,7 +46,7 @@ static esp_err_t _ota_page_handler(httpd_req_t *req);
|
||||
* available OTA partition, and activates it as the new boot partition.
|
||||
* The device reboots automatically after a successful update.
|
||||
*
|
||||
* @param req HTTP request containing the firmware binary payload.
|
||||
* @param req HTTP request containing the firmware binary payload
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return ESP_FAIL if OTA operations or HTTP response failed
|
||||
@@ -51,13 +60,13 @@ static esp_err_t _ota_ws_page_handler(httpd_req_t *req);
|
||||
extern const uint8_t zh_ota_server_html_start[] asm("_binary_zh_ota_server_html_start");
|
||||
extern const uint8_t zh_ota_server_html_end[] asm("_binary_zh_ota_server_html_end");
|
||||
|
||||
httpd_uri_t _ota_page = {
|
||||
static httpd_uri_t _ota_page = {
|
||||
.uri = NULL,
|
||||
.method = HTTP_GET,
|
||||
.handler = _ota_page_handler,
|
||||
.user_ctx = NULL};
|
||||
|
||||
httpd_uri_t _ota_page_ws = {
|
||||
static httpd_uri_t _ota_page_ws = {
|
||||
.uri = NULL,
|
||||
.method = HTTP_POST,
|
||||
.handler = _ota_ws_page_handler,
|
||||
@@ -67,13 +76,17 @@ esp_err_t zh_ota_server_init(httpd_handle_t server, const char *path)
|
||||
{
|
||||
ZH_LOGI("OTA server initialization started.");
|
||||
ZH_ERROR_CHECK(server != NULL && path != NULL, ESP_ERR_INVALID_ARG, NULL, "OTA server initialization failed. Invalid argument.");
|
||||
ZH_ERROR_CHECK(_is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "OTA server initialization failed. OTA server already initialized.");
|
||||
_ota_path = (char *)heap_caps_calloc(1, strlen(path) + 1, MALLOC_CAP_8BIT);
|
||||
ZH_ERROR_CHECK(_ota_path != NULL, ESP_ERR_NO_MEM, NULL, "OTA server initialization failed. Memory allocation fail or no free memory in the heap.");
|
||||
strcpy(_ota_path, path);
|
||||
_ota_page.uri = _ota_path;
|
||||
_ota_page_ws.uri = _ota_ws_path;
|
||||
ZH_ERROR_CHECK(httpd_register_uri_handler(server, &_ota_page) == ESP_OK, ESP_FAIL, heap_caps_free(_ota_path), "OTA server initialization failed. Register uri handler failed.");
|
||||
ZH_ERROR_CHECK(httpd_register_uri_handler(server, &_ota_page_ws) == ESP_OK, ESP_FAIL, heap_caps_free(_ota_path), "OTA server initialization failed. Register uri handler failed.");
|
||||
ZH_ERROR_CHECK(httpd_register_uri_handler(server, &_ota_page) == ESP_OK, ESP_FAIL, heap_caps_free(_ota_path); _ota_path = NULL; _ota_page.uri = NULL, "OTA server initialization failed. Register uri handler failed.");
|
||||
ZH_ERROR_CHECK(httpd_register_uri_handler(server, &_ota_page_ws) == ESP_OK, ESP_FAIL,
|
||||
{ZH_ERROR_CHECK_CONT(httpd_unregister_uri_handler(server, _ota_page.uri, HTTP_GET) == ESP_OK, NULL, "Unregister uri handler failed.")};
|
||||
heap_caps_free(_ota_path); _ota_path = NULL; _ota_page.uri = NULL, "OTA server initialization failed. Register uri handler failed.");
|
||||
_is_initialized = true;
|
||||
ZH_LOGI("OTA server initialization completed successfully.");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -84,7 +97,7 @@ esp_err_t _ota_page_handler(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t _ota_ws_page_handler(httpd_req_t *req) // -V2008
|
||||
esp_err_t _ota_ws_page_handler(httpd_req_t *req)
|
||||
{
|
||||
char buf[1000] = {0};
|
||||
esp_ota_handle_t ota_handle = {0};
|
||||
@@ -101,17 +114,19 @@ esp_err_t _ota_ws_page_handler(httpd_req_t *req) // -V2008
|
||||
}
|
||||
else if (recv_len <= 0)
|
||||
{
|
||||
ZH_ERROR_CHECK(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error") == ESP_OK, ESP_FAIL, NULL, "HTTP server internal error.");
|
||||
ZH_ERROR_CHECK_CONT(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error") == ESP_OK, NULL, "HTTP server internal error.");
|
||||
ZH_ERROR_CHECK_CONT(esp_ota_abort(ota_handle) == ESP_OK, NULL, "OTA abort failed.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ZH_ERROR_CHECK(esp_ota_write(ota_handle, (const void *)buf, recv_len) == ESP_OK, ESP_FAIL,
|
||||
{ZH_ERROR_CHECK(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Flash error.") == ESP_OK, ESP_FAIL, NULL, "HTTP server internal error.")}, "OTA write failed.");
|
||||
{ZH_ERROR_CHECK_CONT(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Flash error.") == ESP_OK, NULL, "HTTP server internal error.")};
|
||||
{ZH_ERROR_CHECK_CONT(esp_ota_abort(ota_handle) == ESP_OK, NULL, "OTA abort failed.")}, "OTA write failed.");
|
||||
remaining -= recv_len;
|
||||
}
|
||||
ZH_ERROR_CHECK(esp_ota_end(ota_handle) == ESP_OK, ESP_FAIL,
|
||||
{ZH_ERROR_CHECK(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error.") == ESP_OK, ESP_FAIL, NULL, "HTTP server internal error.")}, "OTA end failed.");
|
||||
{ZH_ERROR_CHECK_CONT(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error.") == ESP_OK, NULL, "HTTP server internal error.")}, "OTA end failed.");
|
||||
ZH_ERROR_CHECK(esp_ota_set_boot_partition(ota_partition) == ESP_OK, ESP_FAIL,
|
||||
{ZH_ERROR_CHECK(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error.") == ESP_OK, ESP_FAIL, NULL, "HTTP server internal error.")}, "OTA set boot partition failed.");
|
||||
{ZH_ERROR_CHECK_CONT(httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error.") == ESP_OK, NULL, "HTTP server internal error.")}, "OTA set boot partition failed.");
|
||||
ZH_ERROR_CHECK(httpd_resp_sendstr(req, "Firmware update complete, rebooting now!\n") == ESP_OK, ESP_FAIL, NULL, "HTTP server internal error.");
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
esp_restart();
|
||||
|
||||
Reference in new issue
Block a user