Skip to content

Commit

Permalink
Add OTA updates for ESP32
Browse files Browse the repository at this point in the history
Related to DroneBridge#45

Add OTA firmware update functionality to the ESP32 telemetry solution.

* **CMakeLists.txt**: Include `ota.c` in the build and add `ota.h` to the include directories.
* **http_server.c**: Add `ota_update_post_handler` to handle OTA update requests and register it in `start_rest_server`.
* **main.c**: Include `ota.h` and initialize OTA update functionality in `app_main`.
* **ota.c**: Implement OTA update functionality using ESP-IDF OTA APIs and define `ota_update_task` to handle the OTA update process.
* **ota.h**: Declare `ota_update_task` function and include necessary headers.
* **README.md**: Add a section explaining how to perform OTA updates and provide instructions for uploading firmware via the web interface.
  • Loading branch information
vishwamartur committed Nov 3, 2024
1 parent 0e2810a commit 81f0fec
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 5 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
Expand Down Expand Up @@ -96,6 +95,20 @@ In any other case there are multiple ways how to flash the firmware.
- **In case of a UDP connection the GCS must send at least one packet (e.g. MAVLink heart beat etc.) to the UDP port of the ESP32 to register as an endpoint. Add ESP32 as an UDP target in the GCS**
- Manually add a UDP target using the web interface

## OTA Firmware Updates

DroneBridge for ESP32 now supports over-the-air (OTA) firmware updates. This allows you to update the firmware without needing to physically connect the ESP32 to your computer.

### How to Perform OTA Updates

1. Connect to the WiFi `DroneBridge ESP32` with password `dronebridge`.
2. In your browser, type: `dronebridge.local` (Chrome: `http://dronebridge.local`) or `192.168.2.1` into the address bar.
3. Navigate to the OTA update section in the web interface.
4. Upload the new firmware file via the web interface.
5. The ESP32 will automatically restart and apply the new firmware.

**[For further info please check the wiki!](https://dronebridge.gitbook.io/docs/dronebridge-for-esp32/ota-updates)**

## Further Support & Donations

**If you benefited from this project please consider a donation:**
Expand Down
6 changes: 3 additions & 3 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
idf_component_register(SRCS main.c db_esp32_control.c msp_ltm_serial.c http_server.c
db_esp32_comm.c db_comm.c db_crc.c tcp_server.c db_esp_now.c db_serial.c db_mavlink_msgs.c
INCLUDE_DIRS ".")
db_esp32_comm.c db_comm.c db_crc.c tcp_server.c db_esp_now.c db_serial.c db_mavlink_msgs.c ota.c
INCLUDE_DIRS "." "ota.h")

if(CONFIG_WEB_DEPLOY_SF)
set(WEB_SRC_DIR "${CMAKE_BINARY_DIR}/frontend")
spiffs_create_partition_image(www ${WEB_SRC_DIR} FLASH_IN_PROJECT DEPENDS frontend)
endif()
endif()
47 changes: 46 additions & 1 deletion main/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "globals.h"
#include "main.h"
#include "db_serial.h"
#include "ota.h"

static const char *REST_TAG = "DB_HTTP_REST";
#define REST_CHECK(a, str, goto_tag, ...) \
Expand Down Expand Up @@ -571,6 +572,41 @@ static esp_err_t settings_get_handler(httpd_req_t *req) {
return ESP_OK;
}

/**
* Handle OTA update requests
* @param req
* @return ESP_OK on successfully handling the request
*/
static esp_err_t ota_update_post_handler(httpd_req_t *req) {
int total_len = req->content_len;
int cur_len = 0;
char *buf = ((rest_server_context_t *) (req->user_ctx))->scratch;
int received = 0;
if (total_len >= SCRATCH_BUFSIZE) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "content too long");
return ESP_FAIL;
}
while (cur_len < total_len) {
received = httpd_req_recv(req, buf + cur_len, total_len);
if (received <= 0) {
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive OTA update");
return ESP_FAIL;
}
cur_len += received;
}
buf[total_len] = '\0';

// Start OTA update task
xTaskCreate(&ota_update_task, "ota_update_task", 8192, buf, 5, NULL);

httpd_resp_sendstr(req, "{\n"
" \"status\": \"success\",\n"
" \"msg\": \"OTA update started!\"\n"
" }");
return ESP_OK;
}

esp_err_t start_rest_server(const char *base_path) {
REST_CHECK(base_path, "wrong base path", err);
rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
Expand All @@ -580,7 +616,7 @@ esp_err_t start_rest_server(const char *base_path) {
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard;
config.max_uri_handlers = 9;
config.max_uri_handlers = 10;

ESP_LOGI(REST_TAG, "Starting HTTP Server");
REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);
Expand Down Expand Up @@ -656,6 +692,15 @@ esp_err_t start_rest_server(const char *base_path) {
};
httpd_register_uri_handler(server, &settings_static_ip_port_uri);

/* URI handler for handling OTA update requests */
httpd_uri_t ota_update_post_uri = {
.uri = "/api/ota/update",
.method = HTTP_POST,
.handler = ota_update_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &ota_update_post_uri);

/* URI handler for getting web server files */
httpd_uri_t common_get_uri = {
.uri = "/*",
Expand Down
1 change: 1 addition & 0 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "iot_button.h"
#include "db_serial.h"
#include "globals.h"
#include "ota.h"

#define NVS_NAMESPACE "settings"

Expand Down
46 changes: 46 additions & 0 deletions main/ota.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "ota.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"

static const char *TAG = "OTA";

void ota_update_task(void *pvParameter) {
char *ota_write_data = (char *)pvParameter;
esp_err_t err;
esp_ota_handle_t update_handle = 0;
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAG, "Starting OTA update");

err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
vTaskDelete(NULL);
return;
}

err = esp_ota_write(update_handle, (const void *)ota_write_data, strlen(ota_write_data));
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err));
esp_ota_end(update_handle);
vTaskDelete(NULL);
return;
}

err = esp_ota_end(update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_end failed (%s)", esp_err_to_name(err));
vTaskDelete(NULL);
return;
}

err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)", esp_err_to_name(err));
vTaskDelete(NULL);
return;
}

ESP_LOGI(TAG, "OTA update successful, restarting...");
esp_restart();
}
12 changes: 12 additions & 0 deletions main/ota.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef OTA_H
#define OTA_H

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_ota_ops.h"
#include "esp_log.h"

void ota_update_task(void *pvParameter);

#endif // OTA_H

0 comments on commit 81f0fec

Please sign in to comment.