Create a simpler version of the OTA Update

Using no Broadcast logic for speed but its working now.
There is to much Acks going on but for the prototyp that is okay
This commit is contained in:
simon 2025-09-28 20:52:36 +02:00
parent 7097e9e7ab
commit f2296a33e6
7 changed files with 529 additions and 507 deletions

View File

@ -49,6 +49,12 @@ flashCluster:
monitorMini:
idf.py monitor -p /dev/ttyACM0
monitorMini1:
idf.py monitor -p /dev/ttyACM1
monitorMini2:
idf.py monitor -p /dev/ttyACM2
flash0:
idf.py flash -p /dev/ttyUSB0

View File

@ -1,13 +1,14 @@
#include "communication_handler.h"
#include "ota_update.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_now.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_timer.h"
#include "freertos/idf_additions.h"
#include "freertos/task.h"
#include "esp_partition.h"
#include "message_structs.h"
#include "ota_update.h"
#include "client_handler.h"
#include <stdbool.h>
@ -16,7 +17,8 @@
#include <string.h>
#include <sys/types.h>
uint8_t broadcast_address[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t broadcast_address[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
static const char *TAG = "ALOX - COM";
@ -125,7 +127,8 @@ int add_peer(uint8_t *macAddr) {
if (!IS_BROADCAST_ADDR(macAddr)) {
int ret = add_client(esp_client_list, peerInfo.peer_addr);
if (ret < 0) {
ESP_LOGE(TAG, "Client could not be added to client handler, removing it from esp now client list!");
ESP_LOGE(TAG, "Client could not be added to client handler, removing "
"it from esp now client list!");
esp_now_del_peer(peerInfo.peer_addr);
return -1;
}
@ -160,7 +163,6 @@ BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
void master_broadcast_task(void *param) {
while (1) {
if (!g_ota_in_progress) {
BroadCastPayload payload = {};
BaseMessage message = MessageBuilder(
@ -168,21 +170,18 @@ void master_broadcast_task(void *param) {
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage)));
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
void master_broadcast_ping(void *param) {
while (1) {
if (!g_ota_in_progress) {
PingPayload payload = {};
payload.timestamp = esp_timer_get_time();
BaseMessage message =
MessageBuilder(PingPage, *(PayloadUnion *)&payload, sizeof(payload));
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage)));
}
vTaskDelay(pdMS_TO_TICKS(2500));
}
}
@ -234,8 +233,8 @@ void master_RegisterCallback(const esp_now_recv_info_t *esp_now_info,
GetStatusPayload payload = {};
replyMessage = MessageBuilder(GetStatusPage, *(PayloadUnion *)&payload,
sizeof(payload));
esp_now_send(esp_now_info->src_addr,
(uint8_t *)&replyMessage, sizeof(BaseMessage));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
break;
default:
break;
@ -275,8 +274,7 @@ void slave_broadcastCallback(const esp_now_recv_info_t *esp_now_info,
replyMessage =
MessageBuilder(RegisterPage, *(PayloadUnion *)&replyMessage.payload,
sizeof(replyMessage.payload));
esp_now_send(esp_now_info->src_addr,
(uint8_t *)&replyMessage,
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
hasMaster = true;
}
@ -304,8 +302,8 @@ void slave_pingCallback(const esp_now_recv_info_t *esp_now_info,
return;
const BaseMessage *message = (const BaseMessage *)data;
BaseMessage replyMessage = MessageBuilder(PingPage, *(PayloadUnion *)&message->payload,
sizeof(message->payload));
BaseMessage replyMessage = MessageBuilder(
PingPage, *(PayloadUnion *)&message->payload, sizeof(message->payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
}
@ -359,8 +357,8 @@ void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
// Initialize the esp_now_info struct to zeros
memset(&msg_info.esp_now_info, 0, sizeof(esp_now_recv_info_t));
// Now, allocate and copy the data pointed to by the pointers within esp_now_info
// src_addr
// Now, allocate and copy the data pointed to by the pointers within
// esp_now_info src_addr
msg_info.esp_now_info.src_addr = malloc(6);
if (msg_info.esp_now_info.src_addr) {
memcpy(msg_info.esp_now_info.src_addr, esp_now_info->src_addr, 6);
@ -410,222 +408,25 @@ void client_monitor_task(void *pvParameters) {
const esp_partition_t *ota_update_partition = NULL;
void master_ota_prepare_acknowledged_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "Master received OTA_PREPARE_ACKNOWLEDGED");
int client_id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (client_id >= 0) {
esp_client_list->Clients[client_id].ota_status = OTA_PREPARING;
esp_client_list->Clients[client_id].last_seen = xTaskGetTickCount();
BaseMessage master_ready_msg = {};
master_ready_msg = MessageBuilder(MASTER_READY_TO_SEND_CHUNKS, *(PayloadUnion *)&master_ready_msg.payload, 0); // Empty payload
esp_err_t err = esp_now_send(esp_now_info->src_addr, (uint8_t *)&master_ready_msg, sizeof(BaseMessage));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not send MASTER_READY_TO_SEND_CHUNKS, %s",
esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Sent MASTER_READY_TO_SEND_CHUNKS");
}
}
}
void master_client_ready_to_receive_chunks_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "Master received OTA_READY_TO_RECEIVE");
int client_id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (client_id >= 0) {
esp_client_list->Clients[client_id].ota_status = OTA_UPDATING;
esp_client_list->Clients[client_id].last_seen = xTaskGetTickCount();
// Start sending chunks for block 0 to this specific client
esp_client_list->Clients[client_id].current_block_id = 0;
send_ota_block_chunks(client_id, 0);
BaseMessage status_request_message = {};
OTA_REQUEST_BLOCK_STATUS_Payload status_payload = {};
status_payload.block_id = 0;
status_request_message = MessageBuilder(
OTA_REQUEST_BLOCK_STATUS, *(PayloadUnion *)&status_payload,
sizeof(status_payload));
esp_now_send(esp_client_list->Clients[client_id].macAddr,
(uint8_t *)&status_request_message, sizeof(BaseMessage));
}
}
void master_ota_block_status_report_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_BLOCK_STATUS_REPORT_Payload *payload =
&message->payload.ota_block_status_report_payload;
int client_id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (client_id < 0) {
return;
}
esp_client_list->Clients[client_id].last_seen = xTaskGetTickCount();
if (payload->block_id == esp_client_list->Clients[client_id].current_block_id) {
uint32_t complete_bitmask = (1 << UPDATE_MAX_SEQUENZES) - 1; // Use UPDATE_MAX_SEQUENZES (20) for the bitmask
if (payload->chunk_bitmask == complete_bitmask) {
esp_client_list->Clients[client_id].retry_counter = 0;
BaseMessage commit_message = {};
OTA_COMMIT_BLOCK_Payload commit_payload = {
.block_id = esp_client_list->Clients[client_id].current_block_id,
};
commit_message = MessageBuilder(OTA_COMMIT_BLOCK,
*(PayloadUnion *)&commit_payload,
sizeof(commit_payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&commit_message,
sizeof(BaseMessage));
} else {
if (esp_client_list->Clients[client_id].retry_counter > 3) {
esp_client_list->Clients[client_id].ota_status = OTA_FAILED;
return;
}
uint8_t chunk_buffer[UPDATE_PAYLOAD_SIZE]; // Use constant
for (int i = 0; i < UPDATE_MAX_SEQUENZES; i++) { // Use UPDATE_MAX_SEQUENZES (20) for the loop limit
if (!((payload->chunk_bitmask >> i) & 1)) {
esp_partition_read(ota_update_partition,
(esp_client_list->Clients[client_id].current_block_id *
4096) +
(i * UPDATE_PAYLOAD_SIZE), // Use constant
chunk_buffer, UPDATE_PAYLOAD_SIZE); // Use constant
BaseMessage message = {};
OTA_CHUNK_Payload chunk_payload = {};
chunk_payload.block_id =
esp_client_list->Clients[client_id].current_block_id;
chunk_payload.chunk_id = i;
memcpy(chunk_payload.data, chunk_buffer, UPDATE_PAYLOAD_SIZE); // Use constant
message = MessageBuilder(OTA_CHUNK, *(PayloadUnion *)&chunk_payload,
sizeof(chunk_payload));
esp_now_send(esp_now_info->src_addr, (uint8_t *)&message,
sizeof(BaseMessage));
esp_client_list->Clients[client_id].resent_chunks_counter++;
}
}
esp_client_list->Clients[client_id].retry_counter++;
}
}
}
void master_ota_block_committed_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_BLOCK_COMMITTED_Payload *payload =
&message->payload.ota_block_committed_payload;
int client_id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (client_id < 0) {
return;
}
esp_client_list->Clients[client_id].last_seen = xTaskGetTickCount();
if (payload->block_id == esp_client_list->Clients[client_id].current_block_id) {
esp_client_list->Clients[client_id].current_block_id++;
const int total_size = ota_update_partition->size;
const int block_size = 4096;
const int num_blocks = (total_size + block_size - 1) / block_size;
if (esp_client_list->Clients[client_id].current_block_id < num_blocks) {
send_ota_block_chunks(client_id, esp_client_list->Clients[client_id].current_block_id);
BaseMessage status_request_message = {};
OTA_REQUEST_BLOCK_STATUS_Payload status_payload = {};
status_payload.block_id = esp_client_list->Clients[client_id].current_block_id;
status_request_message = MessageBuilder(
OTA_REQUEST_BLOCK_STATUS, *(PayloadUnion *)&status_payload,
sizeof(status_payload));
esp_now_send(esp_client_list->Clients[client_id].macAddr,
(uint8_t *)&status_request_message, sizeof(BaseMessage));
} else {
BaseMessage finish_message = {};
OTA_FINISH_UPDATE_Payload finish_payload = {};
finish_message = MessageBuilder(OTA_FINISH_UPDATE,
*(PayloadUnion *)&finish_payload,
sizeof(finish_payload));
esp_now_send(esp_client_list->Clients[client_id].macAddr,
(uint8_t *)&finish_message, sizeof(BaseMessage));
}
}
}
void master_ota_update_status_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_UPDATE_STATUS_Payload *payload =
&message->payload.ota_update_status_payload;
int client_id = get_client_id(esp_client_list, esp_now_info->src_addr);
if (client_id < 0) {
return;
}
esp_client_list->Clients[client_id].last_seen = xTaskGetTickCount();
if (payload->status == 0) {
esp_client_list->Clients[client_id].ota_status = OTA_SUCCESS;
} else {
esp_client_list->Clients[client_id].ota_status = OTA_FAILED;
}
}
void send_ota_block_chunks(uint8_t client_id, uint16_t block_id) {
const int block_size = 4096;
const int chunk_size = 200;
const int num_chunks = block_size / chunk_size;
uint8_t chunk_buffer[200];
for (int j = 0; j < num_chunks; j++) {
esp_partition_read(
ota_update_partition,
(block_id * block_size) +
(j * chunk_size),
chunk_buffer, chunk_size);
BaseMessage message = {};
OTA_CHUNK_Payload payload = {};
payload.block_id = block_id;
payload.chunk_id = j;
memcpy(payload.data, chunk_buffer, chunk_size);
message = MessageBuilder(OTA_CHUNK, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(esp_client_list->Clients[client_id].macAddr, (uint8_t *)&message, sizeof(BaseMessage));
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void ESPNOW_RegisterOTAMaster() {
// Observe this States for all Slaves in ClientList
// OTA_SLAVE_PREPARING
// OTA_SLAVE_READY
// OTA_SLAVE_ERROR
// OTA_SLAVE_WRITE_FINISHED
// OTA_SLAVE_FINISHED
ESP_RegisterFunction(OTA_PREPARE_ACKNOWLEDGED,
master_ota_prepare_acknowledged_callback);
master_ota_prepare_acknowledge_callback);
ESP_RegisterFunction(OTA_READY_TO_RECEIVE,
master_client_ready_to_receive_chunks_callback);
ESP_RegisterFunction(OTA_BLOCK_STATUS_REPORT,
master_ota_block_status_report_callback);
ESP_RegisterFunction(OTA_BLOCK_COMMITTED,
master_ota_block_committed_callback);
ESP_RegisterFunction(OTA_UPDATE_STATUS, master_ota_update_status_callback);
master_ota_ready_to_recieve_callback);
ESP_RegisterFunction(OTA_UPDATE_SLAVE_ACKED,
master_ota_update_slave_acknowledge_callback);
}
void ESPNOW_RegisterOTASlave() {
ESP_RegisterFunction(OTA_PREPARE_FOR_UPDATE, slave_Prep_Upgrade_Callback);
ESP_RegisterFunction(OTA_CHUNK, slave_ota_chunk_callback);
ESP_RegisterFunction(OTA_REQUEST_BLOCK_STATUS,
slave_request_block_status_callback);
ESP_RegisterFunction(OTA_COMMIT_BLOCK, slave_commit_block_callback);
ESP_RegisterFunction(OTA_FINISH_UPDATE, slave_finish_update_callback);
ESP_RegisterFunction(MASTER_READY_TO_SEND_CHUNKS, slave_master_ready_to_send_chunks_callback);
ESP_RegisterFunction(OTA_CHUNK, slave_Update_Chunk_Callback);
ESP_RegisterFunction(OTA_FINISH_UPDATE, slave_Update_Finished_Callback);
}

View File

@ -114,20 +114,9 @@ void client_receive_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void client_data_sending_task(void *param);
void client_send_random_data_task(void *param);
#include "esp_partition.h"
typedef struct {
const esp_partition_t *update_partition;
} master_ota_task_params_t;
extern bool g_ota_in_progress;
void client_monitor_task(void *pvParameters);
void send_ota_block_chunks(uint8_t client_id, uint16_t block_id);
extern const esp_partition_t *ota_update_partition;
#endif

View File

@ -1,7 +1,10 @@
#include "client_handler.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_app_desc.h"
#include "esp_app_format.h"
#include "esp_err.h"
#include "esp_flash_partitions.h"
#include "esp_image_format.h"
#include "esp_log.h"
#include "esp_log_buffer.h"
@ -22,9 +25,11 @@
#include "main.h"
#include "ota_update.h"
#include "uart_handler.h"
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@ -38,6 +43,7 @@ static uint8_t send_message_payload_buffer[512];
uint32_t g_uart_firmware_total_size = 0;
static MessageBrokerTaskParams_t broker_task_params;
static MasterOTA_TaskParams_t master_ota_task_params;
static ESP_MessageBrokerTaskParams_t esp_broker_task_params;
ClientList clientList = {.Clients = {{0}}, .ClientCount = 0};
@ -207,7 +213,8 @@ void ota_monitor_task(void *param) {
clientList.Clients[i].ota_status != OTA_FAILED) {
all_done = false;
if ((xTaskGetTickCount() - clientList.Clients[i].last_seen) > timeout) {
if ((xTaskGetTickCount() - clientList.Clients[i].last_seen) >
timeout) {
ESP_LOGE(TAG, "Client %d timed out", i);
clientList.Clients[i].ota_status = OTA_FAILED;
}
@ -227,7 +234,8 @@ void ota_monitor_task(void *param) {
if (clientList.Clients[i].slotIsUsed) {
ESP_LOGI(TAG, "Client %d [MAC: " MACSTR "]: %s, Resent Chunks: %d", i,
MAC2STR(clientList.Clients[i].macAddr),
clientList.Clients[i].ota_status == OTA_SUCCESS ? "SUCCESS" : "FAILED",
clientList.Clients[i].ota_status == OTA_SUCCESS ? "SUCCESS"
: "FAILED",
clientList.Clients[i].resent_chunks_counter);
}
}
@ -235,45 +243,24 @@ void ota_monitor_task(void *param) {
vTaskDelete(NULL);
}
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size) {
ESP_LOGI(TAG, "Starting OTA update for all clients");
const esp_partition_t *ota_update_partition;
ota_update_partition = esp_ota_get_next_update_partition(NULL);
if (ota_update_partition == NULL) {
ESP_LOGE(TAG, "Failed to get update partition");
return;
}
g_ota_in_progress = true;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (clientList.Clients[i].slotIsUsed) {
clientList.Clients[i].ota_status = OTA_AWAITING_ACK;
clientList.Clients[i].last_seen = xTaskGetTickCount();
void send_client_ota_start_message(uint8_t clientID, uint32_t app_size) {
BaseMessage message = {};
OTA_PREPARE_FOR_UPDATE_Payload ota_payload = {
.total_size = g_uart_firmware_total_size, // Use the size from UART
}; message = MessageBuilder(OTA_PREPARE_FOR_UPDATE,
.total_size = app_size,
};
message = MessageBuilder(OTA_PREPARE_FOR_UPDATE,
*(PayloadUnion *)&ota_payload, sizeof(ota_payload));
esp_err_t err = esp_now_send(clientList.Clients[i].macAddr, (uint8_t *)&message,
sizeof(BaseMessage));
esp_err_t err = esp_now_send(clientList.Clients[clientID].macAddr,
(uint8_t *)&message, sizeof(BaseMessage));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not send OTA PREPARE FOR UPDATE to " MACSTR ", %s",
MAC2STR(clientList.Clients[i].macAddr), esp_err_to_name(err));
MAC2STR(clientList.Clients[clientID].macAddr),
esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Sent OTA PREPARE FOR UPDATE to " MACSTR, MAC2STR(clientList.Clients[i].macAddr));
ESP_LOGI(TAG, "Sent OTA PREPARE FOR UPDATE to " MACSTR,
MAC2STR(clientList.Clients[clientID].macAddr));
}
}
}
xTaskCreate(ota_monitor_task, "ota_monitor_task", 4096, NULL, 5, NULL);
}
void app_main(void) {
@ -297,7 +284,8 @@ void app_main(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
wifi_config_t wifi_config = {
.sta = {
.sta =
{
.channel = 1,
},
};
@ -323,15 +311,22 @@ void app_main(void) {
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
bool diagnostic_is_ok = true;
bool diagnostic_is_ok = true; // TODO build in valid diagnostics
if (diagnostic_is_ok) {
esp_ota_mark_app_valid_cancel_rollback();
} else {
// esp_ota_mark_app_invalid_rollback(); Put this function at the start
// so when the esp crashes it can rollback
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
const esp_partition_t *next_ota_partition =
esp_ota_get_next_update_partition(NULL);
int app_size = get_app_size(next_ota_partition);
ESP_LOGE(TAG, "App Size in Other Partition %d", app_size);
QueueHandle_t espnow_message_queue =
xQueueCreate(10, sizeof(ESPNOW_MessageInfo));
ESP_InitMessageBroker(espnow_message_queue);
@ -340,6 +335,8 @@ void app_main(void) {
xTaskCreate(ESP_MessageBrokerTask, "espnow_message_broker_task", 4096,
(void *)&esp_broker_task_params, 4, NULL);
init_ota();
if (isMaster) {
ESP_LOGI(TAG, "Started in Mastermode");
ESPNOW_RegisterMasterCallbacks();
@ -362,20 +359,23 @@ void app_main(void) {
broker_task_params.payload_buffer_size =
sizeof(send_message_payload_buffer);
xTaskCreate(MessageBrokerTask, "message_handler_task", 4096,
xTaskCreate(MessageBrokerTask, "MessageHandler", 4096,
(void *)&broker_task_params, 5, NULL);
RegisterCallback(0x01, echoCallback);
RegisterCallback(0x02, versionCallback);
RegisterCallback(0x03, clientInfoCallback);
RegisterCallback(0x04, fakeDataCallback);
master_ota_task_params.client_list = &clientList;
xTaskCreate(MasterOTATask, "MasterOTATask", 4096,
(void *)&master_ota_task_params, 4, NULL);
RegisterCallback(UART_ECHO, echoCallback);
RegisterCallback(UART_VERSION, versionCallback);
RegisterCallback(UART_CLIENT_INFO, clientInfoCallback);
RegisterCallback(UART_CLIENT_INPUT, fakeDataCallback);
RegisterCallback(UART_OTA_START_ESPNOW, start_ota_update_espnow);
init_ota();
} else {
ESP_LOGI(TAG, "Started in Slavemode");
ESPNOW_RegisterSlaveCallbacks();
xTaskCreate(slave_ota_task, "SlaveOTATask", 4096, NULL, 4, NULL);
ESPNOW_RegisterOTASlave();
init_ota();
}
}

View File

@ -1,8 +1,9 @@
#ifndef MESSAGE_STRUCTS_H
#define MESSAGE_STRUCTS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
@ -18,6 +19,7 @@ typedef enum {
OTA_BLOCK_COMMITTED,
OTA_FINISH_UPDATE,
OTA_UPDATE_STATUS,
OTA_UPDATE_SLAVE_ACKED,
MASTER_READY_TO_SEND_CHUNKS,
StatusPage,
GetStatusPage,
@ -43,6 +45,7 @@ typedef struct __attribute__((packed)) {
typedef struct __attribute__((packed)) {
uint16_t block_id;
uint8_t chunk_id;
uint8_t data_len;
uint8_t data[200];
} OTA_CHUNK_Payload;
@ -71,6 +74,14 @@ typedef struct __attribute__((packed)) {
uint8_t status; // 0 = SUCCESS, 1 = FAILED
} OTA_UPDATE_STATUS_Payload;
typedef struct __attribute__((packed)) {
uint16_t current_block_id;
uint16_t update_buffer_write_index;
uint32_t update_size;
uint16_t sequenz_counter; // how often the update buffer gets written
uint8_t status; // 0 = SUCCESS, 1 = FAILED
} OTA_UPDATE_ACK_Payload;
typedef struct __attribute__((packed)) {
uint16_t version; // software version
uint8_t runningPartition;

View File

@ -1,8 +1,12 @@
#include "ota_update.h"
#include "client_handler.h"
#include "communication_handler.h"
#include "driver/uart.h"
#include "esp_app_format.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_log_buffer.h"
#include "esp_now.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_system.h"
@ -11,24 +15,33 @@
#include "freertos/task.h"
#include "message_builder.h"
#include "message_handler.h"
#include "message_structs.h"
#include "uart_handler.h"
#include "uart_msg_ids.h"
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
extern uint32_t g_uart_firmware_total_size;
static const char *TAG = "ALOX - OTA_SLAVE";
static const char *TAG = "ALOX - OTA";
static QueueHandle_t ota_task_queue = NULL;
static esp_ota_handle_t update_handle = 0;
static uint8_t update_buffer[UPDATE_BUFFER_SIZE];
static uint8_t update_buffer_chunk[250];
static uint8_t update_buffer_chunk_len;
static uint32_t chunk_bitmask;
static uint16_t current_block_id;
static uint16_t update_buffer_write_index;
static uint32_t update_size;
static uint16_t sequenz_counter; // how often the update buffer gets written
static esp_partition_t partition_to_read_update_from;
static uint32_t partition_to_read_from_read_index;
static ClientList *client_list;
static bool all_chunks_send;
static bool finished;
u_int32_t get_app_size(const esp_partition_t *app_size_partition) {
uint32_t get_app_size(const esp_partition_t *app_size_partition) {
esp_app_desc_t app_desc;
esp_ota_get_partition_description(app_size_partition, &app_desc);
@ -40,7 +53,7 @@ u_int32_t get_app_size(const esp_partition_t *app_size_partition) {
return 0;
}
u_int32_t data_len = sizeof(header);
uint32_t data_len = sizeof(header);
for (int i = 0; i < header.segment_count; i++) {
esp_image_segment_header_t segment_header;
@ -48,138 +61,275 @@ u_int32_t get_app_size(const esp_partition_t *app_size_partition) {
sizeof(segment_header));
ESP_LOGI(TAG, "SEGMENT %d Address %d, Segment DataLen %d", i,
segment_header.load_addr, segment_header.data_len);
data_len += segment_header.data_len + sizeof(segment_header);
uint32_t padded_len = (segment_header.data_len + 3) & ~3;
data_len += padded_len + sizeof(segment_header);
}
data_len += 1;
data_len += 32;
uint32_t padding = (16 - (data_len % 16)) % 16;
data_len += padding;
return data_len;
}
void ota_task(void *pvParameter) {
ESP_LOGI(TAG, "ota_task started");
int ota_send_finish(ClientList *client_list) {
// read flash and send data
BaseMessage replyMessage = {};
OTA_FINISH_UPDATE_Payload payload = {};
ESP_LOGI(TAG, "OTA SEND FINISH");
replyMessage = MessageBuilder(OTA_FINISH_UPDATE, *(PayloadUnion *)&payload,
sizeof(payload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status == OTA_UPDATING) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_AWAITING_ACK;
}
}
}
finished = true;
return 0;
}
int ota_send_next_update_chunk(ClientList *client_list) {
// read flash and send data
BaseMessage replyMessage = {};
OTA_CHUNK_Payload payload = {};
size_t actual_read = 200;
if (partition_to_read_from_read_index + actual_read > update_size) {
actual_read = update_size - partition_to_read_from_read_index;
}
esp_err_t err = esp_partition_read(&partition_to_read_update_from,
partition_to_read_from_read_index,
payload.data, actual_read);
if (actual_read < 200) {
ESP_LOG_BUFFER_HEX(TAG, payload.data, actual_read);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not read partition");
}
partition_to_read_from_read_index += actual_read;
payload.data_len = actual_read;
ESP_LOGI(TAG, "READ %d Bytes Sendig it to all Clients waiting", actual_read);
ESP_LOGI(TAG, "READ PARTITION AT %d Bytes MAX Bytes %d",
partition_to_read_from_read_index, update_size);
replyMessage =
MessageBuilder(OTA_CHUNK, *(PayloadUnion *)&payload, sizeof(payload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status == OTA_UPDATING) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_AWAITING_ACK;
}
}
}
if (partition_to_read_from_read_index == update_size)
return 1; // last update chunk send now finish it!
return 0;
}
void MasterOTATask(void *pvParameter) {
ESP_LOGI(TAG, "master_ota_task started");
ota_task_queue_message_t msg;
MasterOTA_TaskParams_t task_params = *(MasterOTA_TaskParams_t *)pvParameter;
client_list = task_params.client_list;
while (1) {
if (xQueueReceive(ota_task_queue, &msg, portMAX_DELAY)) {
ESP_LOGI(TAG, "ota_task received command: %d", msg.command);
ESP_LOGI(TAG, "master ota_task received command: %d", msg.command);
BaseMessage replyMessage = {};
switch (msg.command) {
case OTA_COMMAND_MASTER_READY: {
int part = prepare_ota_update();
case OTA_SEND_SLAVES_PREPARE_MESSAGE: {
}
case OTA_SLAVE_WILL_PREPARE: {
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
ESP_LOGE(TAG, "Error set OTA_PREPARE could not get client id");
}
// just wait
// mark client that it will wait
ESP_LOGI(TAG, "MASTER OTA TASK: Marking Client %d as OTA_PREPARING",
id);
client_list->Clients[id].ota_status = OTA_PREPARING;
break;
}
case OTA_SLAVE_IS_PREPARED: {
// client is prepared check if all clients are preapred to send chunks
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
}
if (client_list->Clients[id].ota_status == OTA_PREPARING) {
ESP_LOGI(TAG, "MASTER OTA TASK: Marking Client %d as OTA_UPDATING",
id);
client_list->Clients[id].ota_status = OTA_UPDATING;
} else {
ESP_LOGE(TAG, "MASTER OTA TASK: Client this should not happend");
}
bool start = true;
// check if all clients are prepared
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
if (client_list->Clients[i].ota_status != OTA_UPDATING)
start = false;
}
}
if (start)
ota_send_next_update_chunk(client_list);
break;
}
case OTA_SLAVE_ACKED: {
// mark client as acked check if all clients acked to send next message
int id = get_client_id(client_list, msg.mac_addr);
if (id < 0) {
// error
}
if (client_list->Clients[id].ota_status == OTA_AWAITING_ACK) {
ESP_LOGI(TAG, "OTA_SLAVE_ACKED Client %d Status Update OTA_UPDATING",
id);
client_list->Clients[id].ota_status = OTA_UPDATING;
} else {
ESP_LOGE(TAG, "OTA_SLAVE_ACKED Client %d Status Should not HAPPEND",
id);
}
bool start = true;
// check if all clients are prepared
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
ESP_LOGI(TAG, "SLOT %d is USED", i);
if (client_list->Clients[i].ota_status != OTA_UPDATING)
start = false;
}
}
if (start) {
if (finished)
break; // dont need to send anything else
if (all_chunks_send) {
ota_send_finish(client_list);
break;
}
ESP_LOGE(TAG, "OTA_SLAVE_ACKED all clients have the status "
"OTA_UPDATING SENDING NEXT CHUNK");
int end = ota_send_next_update_chunk(client_list);
if (end) {
all_chunks_send = true;
}
}
break;
}
case OTA_SLAVE_ERROR:
break;
// mark client as error
case OTA_MASTER_SEND_PREAPRE_REQUEST:
break;
case OTA_MASTER_SEND_CHUNK:
break;
case OTA_MASTER_SEND_FINISH:
break;
}
}
}
}
void slave_ota_task(void *pvParameter) {
ESP_LOGI(TAG, "slave_ota_task started");
ota_task_queue_message_t msg;
BaseMessage replyMessage = {};
while (1) {
if (xQueueReceive(ota_task_queue, &msg, portMAX_DELAY)) {
ESP_LOGI(TAG, "slave ota_task received command: %d", msg.command);
switch (msg.command) {
case OTA_SEND_SLAVES_PREPARE_MESSAGE:
break;
case OTA_SLAVE_WILL_PREPARE:
break;
case OTA_SLAVE_IS_PREPARED:
break;
case OTA_SLAVE_ACKED:
break;
case OTA_SLAVE_ERROR:
break;
case OTA_MASTER_SEND_PREAPRE_REQUEST: {
ESP_LOGE(TAG, "START PREAPRE CALL");
int part = prepare_ota_update(); // this part function is blocking
OTA_READY_TO_RECEIVE_Payload payload = {};
if (part < 0) {
payload.status = 1; // ERROR
} else {
payload.status = 0; // READY
}
ESP_LOGE(TAG, "PREPARED %d", part);
replyMessage = MessageBuilder(
OTA_READY_TO_RECEIVE, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
break;
}
case OTA_COMMAND_PREPARE: {
OTA_PREPARE_ACKNOWLEDGED_Payload payload = {};
replyMessage =
MessageBuilder(OTA_PREPARE_ACKNOWLEDGED, *(PayloadUnion *)&payload,
sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
chunk_bitmask = 0;
current_block_id = 0;
break;
}
case OTA_COMMAND_CHUNK: {
OTA_CHUNK_Payload *payload = &msg.payload.ota_chunk_payload;
ESP_LOGI(TAG, "OTA_CHUNK: block_id=%d, chunk_id=%d", payload->block_id,
payload->chunk_id);
if (payload->block_id == current_block_id) {
if (payload->chunk_id < UPDATE_MAX_SEQUENZES) { // UPDATE_MAX_SEQUENZES is 20
memcpy(&update_buffer[payload->chunk_id * UPDATE_PAYLOAD_SIZE], payload->data, UPDATE_PAYLOAD_SIZE);
chunk_bitmask |= (1 << payload->chunk_id);
ESP_LOGD(TAG, "OTA_CHUNK: memcpy done, chunk_bitmask=0x%x",
chunk_bitmask);
} else {
ESP_LOGE(TAG, "OTA_CHUNK: Invalid chunk_id %d. Max allowed is %d", payload->chunk_id, UPDATE_MAX_SEQUENZES - 1);
// Optionally, send an error back to master or reset state
}
} else {
ESP_LOGW(TAG, "OTA_CHUNK: Mismatched block_id. Expected %d, got %d",
current_block_id, payload->block_id);
}
ESP_LOGD(TAG, "OTA_CHUNK: Calling vTaskDelay(10ms)");
//vTaskDelay(pdMS_TO_TICKS(10));
break;
}
case OTA_COMMAND_REQUEST_STATUS: {
OTA_REQUEST_BLOCK_STATUS_Payload *payload =
&msg.payload.ota_request_block_status_payload;
if (payload->block_id == current_block_id) {
OTA_BLOCK_STATUS_REPORT_Payload replyPayload = {
.block_id = current_block_id,
.chunk_bitmask = chunk_bitmask,
case OTA_MASTER_SEND_CHUNK: {
// TODO: Move Update_buffer_chunk in normal update buffer no need for
// the extra step...
// TODO: at the moment its just so i can use the write_ota_update
// function unmodified
ESP_LOGI(TAG, "Master send Chunk writing it!");
write_ota_update(update_buffer_chunk_len, update_buffer_chunk);
ESP_LOGI(TAG, "AFTER WRITE_OTA_UPDATE!");
OTA_UPDATE_ACK_Payload payload = {
.update_buffer_write_index = update_buffer_write_index,
.current_block_id = current_block_id,
.sequenz_counter = sequenz_counter,
.status = 0,
};
replyMessage = MessageBuilder(OTA_BLOCK_STATUS_REPORT,
*(PayloadUnion *)&replyPayload,
sizeof(replyPayload));
replyMessage = MessageBuilder(
OTA_UPDATE_SLAVE_ACKED, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
}
break;
}
case OTA_COMMAND_COMMIT: {
OTA_COMMIT_BLOCK_Payload *payload =
&msg.payload.ota_commit_block_payload;
ESP_LOGI(TAG, "OTA_COMMIT: block_id=%d", payload->block_id);
if (payload->block_id == current_block_id) {
uint32_t write_size = UPDATE_BUFFER_SIZE;
if ((current_block_id + 1) * UPDATE_BUFFER_SIZE > total_update_size) {
write_size = total_update_size % UPDATE_BUFFER_SIZE;
}
ESP_LOGI(TAG, "OTA_COMMIT: Writing %lu bytes to partition.",
write_size);
esp_err_t err =
esp_ota_write(update_handle, update_buffer, write_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "OTA_COMMIT: esp_ota_write failed (%s)",
esp_err_to_name(err));
}
ESP_LOGD(TAG, "OTA_COMMIT: Calling vTaskDelay(10ms)");
vTaskDelay(pdMS_TO_TICKS(10));
OTA_BLOCK_COMMITTED_Payload replyPayload = {
.block_id = current_block_id,
};
replyMessage = MessageBuilder(OTA_BLOCK_COMMITTED,
*(PayloadUnion *)&replyPayload,
sizeof(replyPayload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
current_block_id++;
chunk_bitmask = 0;
ESP_LOGI(TAG, "OTA_COMMIT: Block %d committed. Next block_id=%d",
payload->block_id, current_block_id);
} else {
ESP_LOGW(TAG, "OTA_COMMIT: Mismatched block_id. Expected %d, got %d",
current_block_id, payload->block_id);
}
break;
case OTA_COMMAND_FINISH: {
case OTA_MASTER_SEND_FINISH: {
esp_err_t err = end_ota_update();
OTA_UPDATE_STATUS_Payload ota_status_payload = {};
ota_status_payload.status = (err == ESP_OK) ? 0 : 1;
replyMessage = MessageBuilder(OTA_UPDATE_STATUS,
*(PayloadUnion *)&ota_status_payload,
sizeof(ota_status_payload));
int status = 0;
if (err != ESP_OK) {
status = 1; // TODO: Set real error
}
ESP_LOGI(TAG, "UPDATE FERTIG STATUS %d should be 0", status);
OTA_UPDATE_ACK_Payload payload = {
.update_buffer_write_index = update_buffer_write_index,
.current_block_id = current_block_id,
.sequenz_counter = sequenz_counter,
.status = status,
};
replyMessage = MessageBuilder(
OTA_UPDATE_SLAVE_ACKED, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
if (err == ESP_OK) {
esp_restart();
}
break;
}
default:
ESP_LOGW(TAG, "Unknown command received: %d", msg.command);
break;
}
}
@ -187,8 +337,6 @@ void ota_task(void *pvParameter) {
}
}
static uint32_t total_update_size = 0;
void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
@ -200,18 +348,12 @@ void start_uart_update(uint8_t msgid, const uint8_t *payload,
update_size = 0;
update_buffer_write_index = 0;
sequenz_counter = 0;
// Assuming payload contains total_size as uint32_2 at the beginning
if (payload_len >= sizeof(uint32_t)) {
g_uart_firmware_total_size = *(uint32_t *)payload;
ESP_LOGI(TAG, "UART OTA: Received total firmware size: %lu bytes", g_uart_firmware_total_size);
} else {
ESP_LOGE(TAG, "UART OTA: Payload too short for total firmware size.");
g_uart_firmware_total_size = 0; // Reset or handle error appropriately
}
all_chunks_send = false;
finished = false;
int part = prepare_ota_update();
// TODO: what does this do? maybe comment it out for now?
if (part < 0) {
send_payload_buffer[1] = (part * -1) & 0xff;
} else {
@ -233,7 +375,11 @@ void start_uart_update(uint8_t msgid, const uint8_t *payload,
}
esp_err_t write_ota_update(uint32_t write_len, const uint8_t *payload) {
ESP_LOGI(TAG, "write_ota_update: write_len: %d", write_len);
ESP_LOGI(TAG, "write_ota_update: update_buffer_write_index: %d",
update_buffer_write_index);
if (update_buffer_write_index + write_len > UPDATE_BUFFER_SIZE) {
ESP_LOGI(TAG, "write_ota_update: schreib das update weg!");
esp_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
if (err != ESP_OK) {
@ -315,7 +461,7 @@ void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
void init_ota() {
ota_task_queue = xQueueCreate(50, sizeof(ota_task_queue_message_t));
xTaskCreate(ota_task, "ota_task", 8192, NULL, 4, NULL);
RegisterCallback(UART_OTA_START, start_uart_update);
RegisterCallback(UART_OTA_PAYLOAD, payload_uart_update);
RegisterCallback(UART_OTA_END, end_uart_update);
@ -344,6 +490,7 @@ int prepare_ota_update() {
esp_err_t end_ota_update() {
if (update_buffer_write_index > 0) {
ESP_LOG_BUFFER_HEX(TAG, update_buffer, update_buffer_write_index);
esp_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
vTaskDelay(1);
@ -354,11 +501,11 @@ esp_err_t end_ota_update() {
}
}
g_uart_firmware_total_size = update_size;
esp_err_t err = esp_ota_end(update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_end failed: %s", esp_err_to_name(err));
ESP_LOGI(TAG, "Total blocks written: %u, Last partial block size: %u", sequenz_counter, update_buffer_write_index);
ESP_LOGI(TAG, "Total blocks written: %u, Last partial block size: %u",
sequenz_counter, update_buffer_write_index);
return err;
}
@ -372,74 +519,142 @@ esp_err_t end_ota_update() {
return err;
}
// Acknoledge that the slave should prepare for an update
// Queues the Prepare Task beacuse it takes like 30 seconds
void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
ESP_LOGE(TAG, "SLAVE PREPARE FOR UPDATE Callback");
update_size = 0;
update_buffer_write_index = 0;
sequenz_counter = 0;
const BaseMessage *message = (const BaseMessage *)data;
const OTA_PREPARE_FOR_UPDATE_Payload *payload =
&message->payload.ota_prepare_for_update_payload;
total_update_size = payload->total_size;
// total_update_size = payload->total_size;
ota_task_queue_message_t msg = {.command = OTA_COMMAND_PREPARE};
// Queue Command for Task to call the prepare method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_PREAPRE_REQUEST};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
ESP_LOGE(TAG, "SLAVE PREPARE CALLBACK AFTER QUEUE SEND");
// Tell the master that the slave will preapre
OTA_PREPARE_ACKNOWLEDGED_Payload *reply_payload;
BaseMessage reply_message =
MessageBuilder(OTA_PREPARE_ACKNOWLEDGED, *(PayloadUnion *)&reply_payload,
sizeof(OTA_PREPARE_ACKNOWLEDGED_Payload));
ESP_ERROR_CHECK(esp_now_send(esp_now_info->src_addr,
(uint8_t *)&reply_message, sizeof(BaseMessage)));
}
void slave_Update_Chunk_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
const OTA_CHUNK_Payload *payload = &message->payload.ota_chunk_payload;
// copy data to update_buffer_chunk so that the write method can write it
// back later
memcpy(update_buffer_chunk, payload->data, payload->data_len);
update_buffer_chunk_len = payload->data_len;
ESP_LOGI(TAG, "slave_update_Chunk_Callback got %d bytes from Master",
payload->data_len);
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_CHUNK};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void slave_ota_chunk_callback(const esp_now_recv_info_t *esp_now_info,
void slave_Update_Finished_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
ota_task_queue_message_t msg = {.command = OTA_COMMAND_CHUNK};
const OTA_FINISH_UPDATE_Payload *payload =
&message->payload.ota_finish_update_payload;
ESP_LOGI(TAG, "slave_Update_Finished_Callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_MASTER_SEND_FINISH};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
memcpy(&msg.payload.ota_chunk_payload, &message->payload.ota_chunk_payload,
sizeof(OTA_CHUNK_Payload));
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send chunk to OTA task");
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void slave_request_block_status_callback(
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size) {
ESP_LOGI(TAG, "Starting OTA update for all clients");
const esp_partition_t *ota_update_partition;
ota_update_partition = esp_ota_get_next_update_partition(NULL);
if (ota_update_partition == NULL) {
ESP_LOGE(TAG, "Failed to get update partition");
return;
}
update_size = get_app_size(ota_update_partition);
partition_to_read_update_from = *ota_update_partition;
partition_to_read_from_read_index = 0;
BaseMessage replyMessage = {};
OTA_PREPARE_FOR_UPDATE_Payload replyPayload = {};
replyMessage =
MessageBuilder(OTA_PREPARE_FOR_UPDATE, *(PayloadUnion *)&replyPayload,
sizeof(replyPayload));
for (int i = 0; i < MAX_CLIENTS; i++) {
if (client_list->Clients[i].slotIsUsed) {
esp_now_send(client_list->Clients[i].macAddr, (uint8_t *)&replyMessage,
sizeof(BaseMessage));
client_list->Clients[i].ota_status = OTA_READY;
}
}
}
void master_ota_prepare_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
ota_task_queue_message_t msg = {.command = OTA_COMMAND_REQUEST_STATUS};
ESP_LOGI(TAG, "entering master_ota_prepare_acknowledge_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_WILL_PREPARE};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
memcpy(&msg.payload.ota_request_block_status_payload,
&message->payload.ota_request_block_status_payload,
sizeof(OTA_REQUEST_BLOCK_STATUS_Payload));
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send block status request to OTA task");
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void slave_commit_block_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data;
ota_task_queue_message_t msg = {.command = OTA_COMMAND_COMMIT};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
memcpy(&msg.payload.ota_commit_block_payload,
&message->payload.ota_commit_block_payload,
sizeof(OTA_COMMIT_BLOCK_Payload));
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send commit command to OTA task");
}
}
void slave_finish_update_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) {
ota_task_queue_message_t msg = {.command = OTA_COMMAND_FINISH};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send finish command to OTA task");
}
}
void slave_master_ready_to_send_chunks_callback(
void master_ota_ready_to_recieve_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ota_task_queue_message_t msg = {.command = OTA_COMMAND_MASTER_READY};
ESP_LOGI(TAG, "entering master_ota_ready_to_recieve_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_IS_PREPARED};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send master ready command to OTA task");
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}
void master_ota_update_slave_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) {
ESP_LOGI(TAG, "entering master_ota_update_slave_acknowledge_callback");
// Queue Command for Task to call the ota_write_message method
ota_task_queue_message_t msg = {.command = OTA_SLAVE_ACKED};
memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGE(TAG, "Failed to send prepare command to OTA task");
}
}

View File

@ -1,49 +1,41 @@
#ifndef OTA_UPDATE_H
#define OTA_UPDATE_H
#include "client_handler.h"
#include "esp_err.h"
#include <stdint.h>
#include <sys/types.h>
#include "esp_now.h"
#include "esp_partition.h"
#include "message_structs.h"
#include <stdint.h>
#include <sys/types.h>
#define UPDATE_BUFFER_SIZE 4096
#define UPDATE_PAYLOAD_SIZE 200
#define UPDATE_MAX_SEQUENZES (UPDATE_BUFFER_SIZE / UPDATE_PAYLOAD_SIZE)
typedef enum {
OTA_COMMAND_PREPARE,
OTA_COMMAND_CHUNK,
OTA_COMMAND_REQUEST_STATUS,
OTA_COMMAND_COMMIT,
OTA_COMMAND_FINISH,
OTA_COMMAND_MASTER_READY
OTA_SEND_SLAVES_PREPARE_MESSAGE,
OTA_SLAVE_WILL_PREPARE,
OTA_SLAVE_IS_PREPARED,
OTA_SLAVE_ACKED,
OTA_SLAVE_ERROR,
OTA_MASTER_SEND_PREAPRE_REQUEST,
OTA_MASTER_SEND_CHUNK,
OTA_MASTER_SEND_FINISH,
} ota_command_t;
typedef struct {
ota_command_t command;
uint8_t mac_addr[ESP_NOW_ETH_ALEN];
union {
OTA_CHUNK_Payload ota_chunk_payload;
OTA_REQUEST_BLOCK_STATUS_Payload ota_request_block_status_payload;
OTA_COMMIT_BLOCK_Payload ota_commit_block_payload;
} payload;
} ota_task_queue_message_t;
extern uint32_t g_uart_firmware_total_size;
typedef struct {
ClientList *client_list;
} MasterOTA_TaskParams_t;
void init_ota();
void ota_task(void *pvParameter);
enum OTA_UPDATE_STATES {
IDEL,
START_REQUESTED,
WAITING_FOR_PAYLOAD,
WRITING_OTA_TO_PARTITION,
};
void MasterOTATask(void *pvParameter);
void slave_ota_task(void *pvParameter);
u_int32_t get_app_size(const esp_partition_t *app_size_partition);
@ -53,24 +45,27 @@ esp_err_t end_ota_update();
void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_ota_chunk_callback(const esp_now_recv_info_t *esp_now_info,
void slave_Update_Chunk_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_request_block_status_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len);
void slave_commit_block_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_finish_update_callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void slave_master_ready_to_send_chunks_callback(const esp_now_recv_info_t *esp_now_info,
void slave_Update_Finished_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len);
void master_ota_prepare_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void master_ota_ready_to_recieve_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void master_ota_update_slave_acknowledge_callback(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int data_len);
void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void payload_uart_update(uint8_t msgid, const uint8_t *payload_data_from_uart,
size_t total_payload_len_from_uart, uint8_t *send_payload_buffer,
size_t total_payload_len_from_uart,
uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
@ -78,4 +73,9 @@ void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len,
size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size);
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size,
uint8_t *send_buffer, size_t send_buffer_size);
#endif