57 lines
3.4 KiB
C
57 lines
3.4 KiB
C
#include "web_server_pages.h"
|
|
#include "esp_log.h"
|
|
#include "esp_ota_ops.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include <stdlib.h>
|
|
|
|
static const char *TAG = "SYS_WEB_OTA";
|
|
|
|
static void reboot_task(void *arg)
|
|
{
|
|
(void)arg;
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
esp_restart();
|
|
}
|
|
|
|
static esp_err_t ota_get(httpd_req_t *request)
|
|
{
|
|
const char *page = "<!doctype html><html><head><meta name=viewport content=\"width=device-width\"><title>ABrobot OTA</title><style>body{font:16px sans-serif;max-width:480px;margin:2em auto;padding:0 1em}input,button{font:inherit;padding:.6em;width:100%;box-sizing:border-box}button{margin-top:1em}progress{width:100%;margin-top:1em}</style></head><body><h1>Firmware update</h1><form id=form><input id=file type=file accept=\".bin,application/octet-stream\" required><button type=submit>Upload firmware</button></form><progress id=progress value=0 max=100 hidden></progress><p id=message></p><script>form.onsubmit=async e=>{e.preventDefault();if(!file.files.length)return;progress.hidden=false;message.textContent='Uploading...';try{let r=await fetch('/ota',{method:'POST',headers:{'Content-Type':'application/octet-stream'},body:file.files[0]});if(!r.ok)throw Error(await r.text());progress.value=100;message.textContent='Update installed. Rebooting...'}catch(e){message.textContent='Update failed: '+e.message;progress.hidden=true}}</script></body></html>";
|
|
httpd_resp_set_type(request, "text/html");
|
|
return httpd_resp_send(request, page, HTTPD_RESP_USE_STRLEN);
|
|
}
|
|
|
|
static esp_err_t ota_post(httpd_req_t *request)
|
|
{
|
|
const esp_partition_t *partition = esp_ota_get_next_update_partition(NULL);
|
|
if (!partition || request->content_len == 0 || request->content_len > partition->size) return httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Firmware image is too large or unavailable");
|
|
esp_ota_handle_t handle;
|
|
esp_err_t err = esp_ota_begin(partition, request->content_len, &handle);
|
|
if (err != ESP_OK) return httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Could not begin firmware update");
|
|
uint8_t *buffer = malloc(4096);
|
|
if (!buffer) { esp_ota_abort(handle); return httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Not enough memory"); }
|
|
size_t remaining = request->content_len;
|
|
while (remaining) {
|
|
size_t requested = remaining < 4096 ? remaining : 4096;
|
|
int received = httpd_req_recv(request, (char *)buffer, requested);
|
|
if (received <= 0 || esp_ota_write(handle, buffer, received) != ESP_OK) { free(buffer); esp_ota_abort(handle); return httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Firmware upload failed"); }
|
|
remaining -= (size_t)received;
|
|
}
|
|
free(buffer);
|
|
err = esp_ota_end(handle);
|
|
if (err == ESP_OK) err = esp_ota_set_boot_partition(partition);
|
|
if (err != ESP_OK) return httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "Invalid firmware image");
|
|
httpd_resp_sendstr(request, "Firmware update installed. Rebooting.");
|
|
ESP_LOGI(TAG, "OTA image installed to %s; rebooting", partition->label);
|
|
xTaskCreate(reboot_task, "ota_reboot", 2048, NULL, 5, NULL);
|
|
return ESP_OK;
|
|
}
|
|
|
|
void web_server_register_ota_page(httpd_handle_t server)
|
|
{
|
|
const httpd_uri_t page = {.uri = "/ota", .method = HTTP_GET, .handler = ota_get};
|
|
const httpd_uri_t upload = {.uri = "/ota", .method = HTTP_POST, .handler = ota_post};
|
|
httpd_register_uri_handler(server, &page);
|
|
httpd_register_uri_handler(server, &upload);
|
|
}
|