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: monitorMini:
idf.py monitor -p /dev/ttyACM0 idf.py monitor -p /dev/ttyACM0
monitorMini1:
idf.py monitor -p /dev/ttyACM1
monitorMini2:
idf.py monitor -p /dev/ttyACM2
flash0: flash0:
idf.py flash -p /dev/ttyUSB0 idf.py flash -p /dev/ttyUSB0

View File

@ -1,13 +1,14 @@
#include "communication_handler.h" #include "communication_handler.h"
#include "ota_update.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_now.h" #include "esp_now.h"
#include "esp_ota_ops.h" #include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_partition.h" #include "message_structs.h"
#include "ota_update.h"
#include "client_handler.h" #include "client_handler.h"
#include <stdbool.h> #include <stdbool.h>
@ -16,7 +17,8 @@
#include <string.h> #include <string.h>
#include <sys/types.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"; static const char *TAG = "ALOX - COM";
@ -125,7 +127,8 @@ int add_peer(uint8_t *macAddr) {
if (!IS_BROADCAST_ADDR(macAddr)) { if (!IS_BROADCAST_ADDR(macAddr)) {
int ret = add_client(esp_client_list, peerInfo.peer_addr); int ret = add_client(esp_client_list, peerInfo.peer_addr);
if (ret < 0) { 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); esp_now_del_peer(peerInfo.peer_addr);
return -1; return -1;
} }
@ -160,7 +163,6 @@ BaseMessage MessageBuilder(CommandPages commandPage, PayloadUnion payload,
void master_broadcast_task(void *param) { void master_broadcast_task(void *param) {
while (1) { while (1) {
if (!g_ota_in_progress) {
BroadCastPayload payload = {}; BroadCastPayload payload = {};
BaseMessage message = MessageBuilder( BaseMessage message = MessageBuilder(
@ -168,21 +170,18 @@ void master_broadcast_task(void *param) {
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message, ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage))); sizeof(BaseMessage)));
}
vTaskDelay(pdMS_TO_TICKS(5000)); vTaskDelay(pdMS_TO_TICKS(5000));
} }
} }
void master_broadcast_ping(void *param) { void master_broadcast_ping(void *param) {
while (1) { while (1) {
if (!g_ota_in_progress) {
PingPayload payload = {}; PingPayload payload = {};
payload.timestamp = esp_timer_get_time(); payload.timestamp = esp_timer_get_time();
BaseMessage message = BaseMessage message =
MessageBuilder(PingPage, *(PayloadUnion *)&payload, sizeof(payload)); MessageBuilder(PingPage, *(PayloadUnion *)&payload, sizeof(payload));
ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message, ESP_ERROR_CHECK(esp_now_send(broadcast_address, (uint8_t *)&message,
sizeof(BaseMessage))); sizeof(BaseMessage)));
}
vTaskDelay(pdMS_TO_TICKS(2500)); vTaskDelay(pdMS_TO_TICKS(2500));
} }
} }
@ -234,8 +233,8 @@ void master_RegisterCallback(const esp_now_recv_info_t *esp_now_info,
GetStatusPayload payload = {}; GetStatusPayload payload = {};
replyMessage = MessageBuilder(GetStatusPage, *(PayloadUnion *)&payload, replyMessage = MessageBuilder(GetStatusPage, *(PayloadUnion *)&payload,
sizeof(payload)); sizeof(payload));
esp_now_send(esp_now_info->src_addr, esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
(uint8_t *)&replyMessage, sizeof(BaseMessage)); sizeof(BaseMessage));
break; break;
default: default:
break; break;
@ -275,8 +274,7 @@ void slave_broadcastCallback(const esp_now_recv_info_t *esp_now_info,
replyMessage = replyMessage =
MessageBuilder(RegisterPage, *(PayloadUnion *)&replyMessage.payload, MessageBuilder(RegisterPage, *(PayloadUnion *)&replyMessage.payload,
sizeof(replyMessage.payload)); sizeof(replyMessage.payload));
esp_now_send(esp_now_info->src_addr, esp_now_send(esp_now_info->src_addr, (uint8_t *)&replyMessage,
(uint8_t *)&replyMessage,
sizeof(BaseMessage)); sizeof(BaseMessage));
hasMaster = true; hasMaster = true;
} }
@ -304,8 +302,8 @@ void slave_pingCallback(const esp_now_recv_info_t *esp_now_info,
return; return;
const BaseMessage *message = (const BaseMessage *)data; const BaseMessage *message = (const BaseMessage *)data;
BaseMessage replyMessage = MessageBuilder(PingPage, *(PayloadUnion *)&message->payload, BaseMessage replyMessage = MessageBuilder(
sizeof(message->payload)); PingPage, *(PayloadUnion *)&message->payload, sizeof(message->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)); 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 // Initialize the esp_now_info struct to zeros
memset(&msg_info.esp_now_info, 0, sizeof(esp_now_recv_info_t)); 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 // Now, allocate and copy the data pointed to by the pointers within
// src_addr // esp_now_info src_addr
msg_info.esp_now_info.src_addr = malloc(6); msg_info.esp_now_info.src_addr = malloc(6);
if (msg_info.esp_now_info.src_addr) { if (msg_info.esp_now_info.src_addr) {
memcpy(msg_info.esp_now_info.src_addr, esp_now_info->src_addr, 6); 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; 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() { 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, ESP_RegisterFunction(OTA_PREPARE_ACKNOWLEDGED,
master_ota_prepare_acknowledged_callback); master_ota_prepare_acknowledge_callback);
ESP_RegisterFunction(OTA_READY_TO_RECEIVE, ESP_RegisterFunction(OTA_READY_TO_RECEIVE,
master_client_ready_to_receive_chunks_callback); master_ota_ready_to_recieve_callback);
ESP_RegisterFunction(OTA_BLOCK_STATUS_REPORT, ESP_RegisterFunction(OTA_UPDATE_SLAVE_ACKED,
master_ota_block_status_report_callback); master_ota_update_slave_acknowledge_callback);
ESP_RegisterFunction(OTA_BLOCK_COMMITTED,
master_ota_block_committed_callback);
ESP_RegisterFunction(OTA_UPDATE_STATUS, master_ota_update_status_callback);
} }
void ESPNOW_RegisterOTASlave() { void ESPNOW_RegisterOTASlave() {
ESP_RegisterFunction(OTA_PREPARE_FOR_UPDATE, slave_Prep_Upgrade_Callback); ESP_RegisterFunction(OTA_PREPARE_FOR_UPDATE, slave_Prep_Upgrade_Callback);
ESP_RegisterFunction(OTA_CHUNK, slave_ota_chunk_callback); ESP_RegisterFunction(OTA_CHUNK, slave_Update_Chunk_Callback);
ESP_RegisterFunction(OTA_REQUEST_BLOCK_STATUS,
slave_request_block_status_callback); ESP_RegisterFunction(OTA_FINISH_UPDATE, slave_Update_Finished_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);
} }

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); const uint8_t *data, int data_len);
void client_data_sending_task(void *param); void client_data_sending_task(void *param);
void client_send_random_data_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 client_monitor_task(void *pvParameters);
void send_ota_block_chunks(uint8_t client_id, uint16_t block_id); void send_ota_block_chunks(uint8_t client_id, uint16_t block_id);
extern const esp_partition_t *ota_update_partition;
#endif #endif

View File

@ -1,7 +1,10 @@
#include "client_handler.h" #include "client_handler.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_app_desc.h"
#include "esp_app_format.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_flash_partitions.h"
#include "esp_image_format.h" #include "esp_image_format.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_log_buffer.h" #include "esp_log_buffer.h"
@ -22,9 +25,11 @@
#include "main.h" #include "main.h"
#include "ota_update.h" #include "ota_update.h"
#include "uart_handler.h" #include "uart_handler.h"
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.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; uint32_t g_uart_firmware_total_size = 0;
static MessageBrokerTaskParams_t broker_task_params; static MessageBrokerTaskParams_t broker_task_params;
static MasterOTA_TaskParams_t master_ota_task_params;
static ESP_MessageBrokerTaskParams_t esp_broker_task_params; static ESP_MessageBrokerTaskParams_t esp_broker_task_params;
ClientList clientList = {.Clients = {{0}}, .ClientCount = 0}; ClientList clientList = {.Clients = {{0}}, .ClientCount = 0};
@ -207,7 +213,8 @@ void ota_monitor_task(void *param) {
clientList.Clients[i].ota_status != OTA_FAILED) { clientList.Clients[i].ota_status != OTA_FAILED) {
all_done = false; 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); ESP_LOGE(TAG, "Client %d timed out", i);
clientList.Clients[i].ota_status = OTA_FAILED; clientList.Clients[i].ota_status = OTA_FAILED;
} }
@ -227,7 +234,8 @@ void ota_monitor_task(void *param) {
if (clientList.Clients[i].slotIsUsed) { if (clientList.Clients[i].slotIsUsed) {
ESP_LOGI(TAG, "Client %d [MAC: " MACSTR "]: %s, Resent Chunks: %d", i, ESP_LOGI(TAG, "Client %d [MAC: " MACSTR "]: %s, Resent Chunks: %d", i,
MAC2STR(clientList.Clients[i].macAddr), 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); clientList.Clients[i].resent_chunks_counter);
} }
} }
@ -235,46 +243,25 @@ void ota_monitor_task(void *param) {
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void start_ota_update_espnow(uint8_t msgid, const uint8_t *payload, void send_client_ota_start_message(uint8_t clientID, uint32_t app_size) {
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();
BaseMessage message = {}; BaseMessage message = {};
OTA_PREPARE_FOR_UPDATE_Payload ota_payload = { OTA_PREPARE_FOR_UPDATE_Payload ota_payload = {
.total_size = g_uart_firmware_total_size, // Use the size from UART .total_size = app_size,
}; message = MessageBuilder(OTA_PREPARE_FOR_UPDATE, };
message = MessageBuilder(OTA_PREPARE_FOR_UPDATE,
*(PayloadUnion *)&ota_payload, sizeof(ota_payload)); *(PayloadUnion *)&ota_payload, sizeof(ota_payload));
esp_err_t err = esp_now_send(clientList.Clients[i].macAddr, (uint8_t *)&message, esp_err_t err = esp_now_send(clientList.Clients[clientID].macAddr,
sizeof(BaseMessage)); (uint8_t *)&message, sizeof(BaseMessage));
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not send OTA PREPARE FOR UPDATE to " MACSTR ", %s", 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 { } 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) { void app_main(void) {
ESP_LOGI(TAG, "Starting Alox Powerpod Version %d Build: %s", version, ESP_LOGI(TAG, "Starting Alox Powerpod Version %d Build: %s", version,
@ -297,7 +284,8 @@ void app_main(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_init(&cfg));
wifi_config_t wifi_config = { wifi_config_t wifi_config = {
.sta = { .sta =
{
.channel = 1, .channel = 1,
}, },
}; };
@ -323,15 +311,22 @@ void app_main(void) {
esp_ota_img_states_t ota_state; esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) { if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) { 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) { if (diagnostic_is_ok) {
esp_ota_mark_app_valid_cancel_rollback(); esp_ota_mark_app_valid_cancel_rollback();
} else { } 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(); 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 = QueueHandle_t espnow_message_queue =
xQueueCreate(10, sizeof(ESPNOW_MessageInfo)); xQueueCreate(10, sizeof(ESPNOW_MessageInfo));
ESP_InitMessageBroker(espnow_message_queue); ESP_InitMessageBroker(espnow_message_queue);
@ -340,6 +335,8 @@ void app_main(void) {
xTaskCreate(ESP_MessageBrokerTask, "espnow_message_broker_task", 4096, xTaskCreate(ESP_MessageBrokerTask, "espnow_message_broker_task", 4096,
(void *)&esp_broker_task_params, 4, NULL); (void *)&esp_broker_task_params, 4, NULL);
init_ota();
if (isMaster) { if (isMaster) {
ESP_LOGI(TAG, "Started in Mastermode"); ESP_LOGI(TAG, "Started in Mastermode");
ESPNOW_RegisterMasterCallbacks(); ESPNOW_RegisterMasterCallbacks();
@ -362,20 +359,23 @@ void app_main(void) {
broker_task_params.payload_buffer_size = broker_task_params.payload_buffer_size =
sizeof(send_message_payload_buffer); sizeof(send_message_payload_buffer);
xTaskCreate(MessageBrokerTask, "message_handler_task", 4096, xTaskCreate(MessageBrokerTask, "MessageHandler", 4096,
(void *)&broker_task_params, 5, NULL); (void *)&broker_task_params, 5, NULL);
RegisterCallback(0x01, echoCallback); master_ota_task_params.client_list = &clientList;
RegisterCallback(0x02, versionCallback); xTaskCreate(MasterOTATask, "MasterOTATask", 4096,
RegisterCallback(0x03, clientInfoCallback); (void *)&master_ota_task_params, 4, NULL);
RegisterCallback(0x04, fakeDataCallback);
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); RegisterCallback(UART_OTA_START_ESPNOW, start_ota_update_espnow);
init_ota();
} else { } else {
ESP_LOGI(TAG, "Started in Slavemode"); ESP_LOGI(TAG, "Started in Slavemode");
ESPNOW_RegisterSlaveCallbacks(); ESPNOW_RegisterSlaveCallbacks();
xTaskCreate(slave_ota_task, "SlaveOTATask", 4096, NULL, 4, NULL);
ESPNOW_RegisterOTASlave(); ESPNOW_RegisterOTASlave();
init_ota();
} }
} }

View File

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

View File

@ -1,8 +1,12 @@
#include "ota_update.h" #include "ota_update.h"
#include "client_handler.h"
#include "communication_handler.h" #include "communication_handler.h"
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_app_format.h" #include "esp_app_format.h"
#include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_log_buffer.h"
#include "esp_now.h"
#include "esp_ota_ops.h" #include "esp_ota_ops.h"
#include "esp_partition.h" #include "esp_partition.h"
#include "esp_system.h" #include "esp_system.h"
@ -11,24 +15,33 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "message_builder.h" #include "message_builder.h"
#include "message_handler.h" #include "message_handler.h"
#include "message_structs.h"
#include "uart_handler.h" #include "uart_handler.h"
#include "uart_msg_ids.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";
static const char *TAG = "ALOX - OTA_SLAVE";
static QueueHandle_t ota_task_queue = NULL; static QueueHandle_t ota_task_queue = NULL;
static esp_ota_handle_t update_handle = 0; static esp_ota_handle_t update_handle = 0;
static uint8_t update_buffer[UPDATE_BUFFER_SIZE]; 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 uint32_t chunk_bitmask;
static uint16_t current_block_id; static uint16_t current_block_id;
static uint16_t update_buffer_write_index; static uint16_t update_buffer_write_index;
static uint32_t update_size; static uint32_t update_size;
static uint16_t sequenz_counter; // how often the update buffer gets written 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_app_desc_t app_desc;
esp_ota_get_partition_description(app_size_partition, &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; return 0;
} }
u_int32_t data_len = sizeof(header); uint32_t data_len = sizeof(header);
for (int i = 0; i < header.segment_count; i++) { for (int i = 0; i < header.segment_count; i++) {
esp_image_segment_header_t segment_header; esp_image_segment_header_t segment_header;
@ -48,146 +61,281 @@ u_int32_t get_app_size(const esp_partition_t *app_size_partition) {
sizeof(segment_header)); sizeof(segment_header));
ESP_LOGI(TAG, "SEGMENT %d Address %d, Segment DataLen %d", i, ESP_LOGI(TAG, "SEGMENT %d Address %d, Segment DataLen %d", i,
segment_header.load_addr, segment_header.data_len); 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; return data_len;
} }
void ota_task(void *pvParameter) { int ota_send_finish(ClientList *client_list) {
ESP_LOGI(TAG, "ota_task started"); // 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; ota_task_queue_message_t msg;
MasterOTA_TaskParams_t task_params = *(MasterOTA_TaskParams_t *)pvParameter;
client_list = task_params.client_list;
while (1) { while (1) {
if (xQueueReceive(ota_task_queue, &msg, portMAX_DELAY)) { 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 = {}; BaseMessage replyMessage = {};
switch (msg.command) { switch (msg.command) {
case OTA_COMMAND_MASTER_READY: { case OTA_SEND_SLAVES_PREPARE_MESSAGE: {
int part = prepare_ota_update(); }
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 = {}; OTA_READY_TO_RECEIVE_Payload payload = {};
if (part < 0) { if (part < 0) {
payload.status = 1; // ERROR payload.status = 1; // ERROR
} else { } else {
payload.status = 0; // READY payload.status = 0; // READY
} }
ESP_LOGE(TAG, "PREPARED %d", part);
replyMessage = MessageBuilder( replyMessage = MessageBuilder(
OTA_READY_TO_RECEIVE, *(PayloadUnion *)&payload, sizeof(payload)); OTA_READY_TO_RECEIVE, *(PayloadUnion *)&payload, sizeof(payload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage, esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage)); sizeof(BaseMessage));
break; break;
} }
case OTA_COMMAND_PREPARE: { case OTA_MASTER_SEND_CHUNK: {
OTA_PREPARE_ACKNOWLEDGED_Payload payload = {}; // TODO: Move Update_buffer_chunk in normal update buffer no need for
replyMessage = // the extra step...
MessageBuilder(OTA_PREPARE_ACKNOWLEDGED, *(PayloadUnion *)&payload, // TODO: at the moment its just so i can use the write_ota_update
sizeof(payload)); // function unmodified
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage, ESP_LOGI(TAG, "Master send Chunk writing it!");
sizeof(BaseMessage));
chunk_bitmask = 0; write_ota_update(update_buffer_chunk_len, update_buffer_chunk);
current_block_id = 0;
break; ESP_LOGI(TAG, "AFTER WRITE_OTA_UPDATE!");
}
case OTA_COMMAND_CHUNK: { OTA_UPDATE_ACK_Payload payload = {
OTA_CHUNK_Payload *payload = &msg.payload.ota_chunk_payload; .update_buffer_write_index = update_buffer_write_index,
ESP_LOGI(TAG, "OTA_CHUNK: block_id=%d, chunk_id=%d", payload->block_id, .current_block_id = current_block_id,
payload->chunk_id); .sequenz_counter = sequenz_counter,
if (payload->block_id == current_block_id) { .status = 0,
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,
}; };
replyMessage = MessageBuilder(OTA_BLOCK_STATUS_REPORT, replyMessage = MessageBuilder(
*(PayloadUnion *)&replyPayload, OTA_UPDATE_SLAVE_ACKED, *(PayloadUnion *)&payload, sizeof(payload));
sizeof(replyPayload));
esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage, esp_now_send(msg.mac_addr, (uint8_t *)&replyMessage,
sizeof(BaseMessage)); sizeof(BaseMessage));
}
break; break;
} }
case OTA_COMMAND_COMMIT: { case OTA_MASTER_SEND_FINISH: {
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: {
esp_err_t err = end_ota_update(); esp_err_t err = end_ota_update();
OTA_UPDATE_STATUS_Payload ota_status_payload = {}; int status = 0;
ota_status_payload.status = (err == ESP_OK) ? 0 : 1; if (err != ESP_OK) {
replyMessage = MessageBuilder(OTA_UPDATE_STATUS, status = 1; // TODO: Set real error
*(PayloadUnion *)&ota_status_payload,
sizeof(ota_status_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;
}
}
}
}
} }
static uint32_t total_update_size = 0; 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));
break;
}
}
}
}
}
void start_uart_update(uint8_t msgid, const uint8_t *payload, void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer, size_t payload_len, uint8_t *send_payload_buffer,
@ -200,18 +348,12 @@ void start_uart_update(uint8_t msgid, const uint8_t *payload,
update_size = 0; update_size = 0;
update_buffer_write_index = 0; update_buffer_write_index = 0;
sequenz_counter = 0; sequenz_counter = 0;
all_chunks_send = false;
// Assuming payload contains total_size as uint32_2 at the beginning finished = false;
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
}
int part = prepare_ota_update(); int part = prepare_ota_update();
// TODO: what does this do? maybe comment it out for now?
if (part < 0) { if (part < 0) {
send_payload_buffer[1] = (part * -1) & 0xff; send_payload_buffer[1] = (part * -1) & 0xff;
} else { } 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_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) { 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_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index); esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
if (err != ESP_OK) { 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() { void init_ota() {
ota_task_queue = xQueueCreate(50, sizeof(ota_task_queue_message_t)); 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_START, start_uart_update);
RegisterCallback(UART_OTA_PAYLOAD, payload_uart_update); RegisterCallback(UART_OTA_PAYLOAD, payload_uart_update);
RegisterCallback(UART_OTA_END, end_uart_update); RegisterCallback(UART_OTA_END, end_uart_update);
@ -344,6 +490,7 @@ int prepare_ota_update() {
esp_err_t end_ota_update() { esp_err_t end_ota_update() {
if (update_buffer_write_index > 0) { if (update_buffer_write_index > 0) {
ESP_LOG_BUFFER_HEX(TAG, update_buffer, update_buffer_write_index);
esp_err_t err = esp_err_t err =
esp_ota_write(update_handle, update_buffer, update_buffer_write_index); esp_ota_write(update_handle, update_buffer, update_buffer_write_index);
vTaskDelay(1); 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); esp_err_t err = esp_ota_end(update_handle);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_end failed: %s", esp_err_to_name(err)); 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; return err;
} }
@ -372,74 +519,142 @@ esp_err_t end_ota_update() {
return err; 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, void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len) { 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 BaseMessage *message = (const BaseMessage *)data;
const OTA_PREPARE_FOR_UPDATE_Payload *payload = const OTA_PREPARE_FOR_UPDATE_Payload *payload =
&message->payload.ota_prepare_for_update_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); memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) { 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, "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 uint8_t *data, int data_len) {
const BaseMessage *message = (const BaseMessage *)data; 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.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) { 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, const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) { int data_len) {
const BaseMessage *message = (const BaseMessage *)data; ESP_LOGI(TAG, "entering master_ota_prepare_acknowledge_callback");
ota_task_queue_message_t msg = {.command = OTA_COMMAND_REQUEST_STATUS}; // 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.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) { 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, void master_ota_ready_to_recieve_callback(
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(
const esp_now_recv_info_t *esp_now_info, const uint8_t *data, const esp_now_recv_info_t *esp_now_info, const uint8_t *data,
int data_len) { 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); memcpy(msg.mac_addr, esp_now_info->src_addr, ESP_NOW_ETH_ALEN);
if (xQueueSend(ota_task_queue, &msg, pdMS_TO_TICKS(10)) != pdTRUE) { 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 #ifndef OTA_UPDATE_H
#define OTA_UPDATE_H #define OTA_UPDATE_H
#include "client_handler.h"
#include "esp_err.h" #include "esp_err.h"
#include <stdint.h>
#include <sys/types.h>
#include "esp_now.h" #include "esp_now.h"
#include "esp_partition.h" #include "esp_partition.h"
#include "message_structs.h" #include "message_structs.h"
#include <stdint.h>
#include <sys/types.h>
#define UPDATE_BUFFER_SIZE 4096 #define UPDATE_BUFFER_SIZE 4096
#define UPDATE_PAYLOAD_SIZE 200 #define UPDATE_PAYLOAD_SIZE 200
#define UPDATE_MAX_SEQUENZES (UPDATE_BUFFER_SIZE / UPDATE_PAYLOAD_SIZE) #define UPDATE_MAX_SEQUENZES (UPDATE_BUFFER_SIZE / UPDATE_PAYLOAD_SIZE)
typedef enum { typedef enum {
OTA_COMMAND_PREPARE, OTA_SEND_SLAVES_PREPARE_MESSAGE,
OTA_COMMAND_CHUNK, OTA_SLAVE_WILL_PREPARE,
OTA_COMMAND_REQUEST_STATUS, OTA_SLAVE_IS_PREPARED,
OTA_COMMAND_COMMIT, OTA_SLAVE_ACKED,
OTA_COMMAND_FINISH, OTA_SLAVE_ERROR,
OTA_COMMAND_MASTER_READY OTA_MASTER_SEND_PREAPRE_REQUEST,
OTA_MASTER_SEND_CHUNK,
OTA_MASTER_SEND_FINISH,
} ota_command_t; } ota_command_t;
typedef struct { typedef struct {
ota_command_t command; ota_command_t command;
uint8_t mac_addr[ESP_NOW_ETH_ALEN]; 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; } ota_task_queue_message_t;
typedef struct {
extern uint32_t g_uart_firmware_total_size; ClientList *client_list;
} MasterOTA_TaskParams_t;
void init_ota(); void init_ota();
void ota_task(void *pvParameter); void MasterOTATask(void *pvParameter);
void slave_ota_task(void *pvParameter);
enum OTA_UPDATE_STATES {
IDEL,
START_REQUESTED,
WAITING_FOR_PAYLOAD,
WRITING_OTA_TO_PARTITION,
};
u_int32_t get_app_size(const esp_partition_t *app_size_partition); 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, void slave_Prep_Upgrade_Callback(const esp_now_recv_info_t *esp_now_info,
const uint8_t *data, int data_len); 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); const uint8_t *data, int data_len);
void slave_request_block_status_callback( void slave_Update_Finished_Callback(const esp_now_recv_info_t *esp_now_info,
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,
const uint8_t *data, int data_len); 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, void start_uart_update(uint8_t msgid, const uint8_t *payload,
size_t payload_len, uint8_t *send_payload_buffer, size_t payload_len, uint8_t *send_payload_buffer,
size_t send_payload_buffer_size, uint8_t *send_buffer, size_t send_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size); size_t send_buffer_size);
void payload_uart_update(uint8_t msgid, const uint8_t *payload_data_from_uart, 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_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size); size_t send_buffer_size);
void end_uart_update(uint8_t msgid, const uint8_t *payload, size_t payload_len, 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_payload_buffer_size, uint8_t *send_buffer,
size_t send_buffer_size); 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 #endif