OTA pipeline working
This commit is contained in:
@@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
file(READ "${CMAKE_SOURCE_DIR}/version.txt" PROJECT_VER)
|
||||
string(STRIP "${PROJECT_VER}" PROJECT_VER)
|
||||
add_compile_definitions(FW_VERSION=${PROJECT_VER})
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32)
|
||||
|
||||
@@ -29,6 +29,7 @@ idf_component_register(
|
||||
esp_driver_gpio
|
||||
esp_http_client
|
||||
app_update
|
||||
mbedtls
|
||||
)
|
||||
# добавляем кастомный Kconfig
|
||||
set(COMPONENT_KCONFIG "Kconfig")
|
||||
@@ -22,9 +22,11 @@ static void heartbeat_task(void* arg)
|
||||
time(&now);
|
||||
|
||||
protocol_send_event_hb((uint32_t)now);
|
||||
vTaskDelay(pdMS_TO_TICKS(30000)); // 30 сек
|
||||
} else
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10000)); // 10 сек
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,57 +8,102 @@
|
||||
#include "ws.h"
|
||||
#include "heartbeat_task.h"
|
||||
#include "fw_command.h"
|
||||
#include "psa/crypto.h"
|
||||
|
||||
static TaskHandle_t ota_task_handle = nullptr;
|
||||
static char url_copy[256];
|
||||
static char sha256[65];
|
||||
|
||||
#define TAG "OTA"
|
||||
|
||||
void perform_ota(void* par)
|
||||
{
|
||||
sampler_task_stop();
|
||||
sender_task_stop();
|
||||
heartbeat_task_stop();
|
||||
ws_disconnect();
|
||||
|
||||
ESP_LOGI(TAG, "OTA task started");
|
||||
esp_ota_handle_t ota_handle;
|
||||
uint8_t buf[1024];
|
||||
int read_bytes;
|
||||
const esp_partition_t* partition = nullptr;
|
||||
int content_length = 0;
|
||||
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
|
||||
|
||||
const char* url = static_cast<const char*>(par);
|
||||
|
||||
ESP_LOGI(TAG, "URL: %s", url);
|
||||
|
||||
esp_http_client_config_t config = {};
|
||||
config.url = url;
|
||||
config.timeout_ms = 5000;
|
||||
config.buffer_size = 1024;
|
||||
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
ESP_LOGI(TAG, "HTTP init complete");
|
||||
|
||||
|
||||
if (esp_http_client_open(client, 0) != ESP_OK)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "HTTP connection established");
|
||||
|
||||
content_length = esp_http_client_fetch_headers(client);
|
||||
ESP_LOGI(TAG, "content_length=%d", content_length);
|
||||
|
||||
partition = esp_ota_get_next_update_partition(nullptr);
|
||||
|
||||
ESP_LOGI(TAG, "OTA update partition selected %s (offset 0x%08x)", partition->label, partition->address);
|
||||
|
||||
if (esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &ota_handle) != ESP_OK)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while ((read_bytes = esp_http_client_read(client, (char*)buf, sizeof(buf))) > 0)
|
||||
psa_crypto_init();
|
||||
psa_hash_setup(&op, PSA_ALG_SHA_256);
|
||||
|
||||
ESP_LOGI(TAG, "OTA update started");
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (esp_ota_write(ota_handle, buf, read_bytes) != ESP_OK)
|
||||
int data_read = esp_http_client_read(client, (char*)buf, sizeof(buf));
|
||||
|
||||
if (data_read < 0)
|
||||
{
|
||||
esp_ota_end(ota_handle);
|
||||
ESP_LOGE(TAG, "read error");
|
||||
break;
|
||||
}
|
||||
else if (data_read == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "download finished");
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "write chunk: %d bytes", data_read);
|
||||
|
||||
if (esp_ota_write(ota_handle, buf, data_read) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "flash write failed");
|
||||
goto cleanup;
|
||||
}
|
||||
if (psa_hash_update(&op, buf, data_read) != PSA_SUCCESS) {
|
||||
ESP_LOGE(TAG, "hash update failed");
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "finalizing...");
|
||||
|
||||
if (esp_ota_end(ota_handle) == ESP_OK)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
size_t hash_len;
|
||||
|
||||
if (esp_partition_get_sha256(partition, hash) != ESP_OK)
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
psa_hash_finish(&op, hash, sizeof(hash), &hash_len);
|
||||
|
||||
// переводим в hex
|
||||
char hash_str[65];
|
||||
@@ -68,16 +113,24 @@ void perform_ota(void* par)
|
||||
}
|
||||
hash_str[64] = '\0';
|
||||
|
||||
ESP_LOGI(TAG, "sha256 = %s. Comparing...", hash_str);
|
||||
|
||||
// сравнение
|
||||
if (strncmp(hash_str, sha256, 64) != 0)
|
||||
{
|
||||
printf("SHA256 mismatch!\n");
|
||||
ESP_LOGE(TAG, "SHA256 mismatch!");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "set boot partition");
|
||||
esp_ota_set_boot_partition(partition);
|
||||
ESP_LOGI(TAG, "restart pending");
|
||||
esp_restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "ota_end failed");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
esp_http_client_cleanup(client);
|
||||
@@ -89,10 +142,6 @@ void ota_task_start(const fw_cmd_t* cmd)
|
||||
{
|
||||
strncpy(url_copy, cmd->url, sizeof(url_copy));
|
||||
strncpy(sha256, cmd->sha256, sizeof(sha256));
|
||||
sampler_task_stop();
|
||||
sender_task_stop();
|
||||
heartbeat_task_stop();
|
||||
ws_disconnect();
|
||||
if (ota_task_handle == nullptr)
|
||||
{
|
||||
xTaskCreate(
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#define PROTOCOL_VERSION 1
|
||||
|
||||
@@ -195,16 +197,45 @@ uint32_t protocol_next_id()
|
||||
|
||||
void protocol_send_event_hb(int64_t ts)
|
||||
{
|
||||
// формируешь JSON строго по контракту
|
||||
char buf[256];
|
||||
|
||||
// пример:
|
||||
char buf[128];
|
||||
wifi_ap_record_t ap;
|
||||
esp_wifi_sta_get_ap_info(&ap);
|
||||
|
||||
int rssi = ap.rssi;
|
||||
const char *ssid = (const char *)ap.ssid;
|
||||
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
|
||||
esp_netif_get_ip_info(netif, &ip_info);
|
||||
|
||||
uint32_t ip = ip_info.ip.addr;
|
||||
|
||||
size_t heap_free = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
|
||||
size_t heap_largest = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT);
|
||||
|
||||
uint32_t id = protocol_next_id();
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"{\"v\":1,\"id\":%" PRIu32 ",\"t\":\"e\",\"ts\":%" PRIu64 ",\"d\":%u,\"p\":{\"type\":\"hb\"}}",
|
||||
id, ts, CONFIG_DEVICE_ID);
|
||||
"{\"v\":1,\"id\":%" PRIu32 ",\"t\":\"e\",\"ts\":%" PRIu64 ",\"d\":%u,"
|
||||
"\"p\":{"
|
||||
"\"t\":\"hb\","
|
||||
"\"v\":%u,"
|
||||
"\"hp\":%u,"
|
||||
"\"hl\":%u,"
|
||||
"\"rs\":%d,"
|
||||
"\"ip\":%" PRIu32 ","
|
||||
"\"si\":\"%s\""
|
||||
"}}",
|
||||
id, ts, CONFIG_DEVICE_ID,
|
||||
FW_VERSION,
|
||||
heap_free,
|
||||
heap_largest,
|
||||
rssi,
|
||||
ip,
|
||||
ssid
|
||||
);
|
||||
|
||||
ws_send(buf);
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
1
|
||||
8
|
||||
Reference in New Issue
Block a user