elemes/velxio-deployer-firmware/main/binary_parser.c

145 lines
4.3 KiB
C

#include <string.h>
#include <inttypes.h>
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "binary_parser.h"
#include "checksum.h"
#include "ble_service.h"
static const char *TAG = "BIN_PARSER";
static parser_state_t state = PARSER_IDLE;
static uint8_t *hex_buffer = NULL;
static size_t buffer_offset = 0;
static size_t buffer_size = 0;
static uint32_t expected_total_crc = 0;
static int total_chunks = 0;
static int received_chunks = 0;
void binary_parser_init(void)
{
hex_buffer = (uint8_t *)heap_caps_malloc(MAX_HEX_SIZE, MALLOC_CAP_SPIRAM);
if (hex_buffer) {
ESP_LOGI(TAG, "PSRAM buffer allocated: %d bytes at %p", MAX_HEX_SIZE, hex_buffer);
} else {
ESP_LOGE(TAG, "Failed to allocate PSRAM buffer!");
hex_buffer = malloc(MAX_HEX_SIZE);
if (hex_buffer) {
ESP_LOGW(TAG, "Fallback to SRAM buffer: %d bytes", MAX_HEX_SIZE);
}
}
}
parser_state_t binary_parser_process_packet(uint8_t *payload, size_t len)
{
if (len < 8) return PARSER_ERROR;
if (!hex_buffer) return PARSER_ERROR;
uint8_t cmd = payload[0];
uint16_t index = payload[1] | (payload[2] << 8);
uint8_t data_len = payload[3];
if (4 + data_len + 4 > len) return PARSER_ERROR;
uint8_t *data = payload + 4;
uint32_t received_crc = (uint32_t)payload[4 + data_len] |
((uint32_t)payload[4 + data_len + 1] << 8) |
((uint32_t)payload[4 + data_len + 2] << 16) |
((uint32_t)payload[4 + data_len + 3] << 24);
switch (cmd) {
case CMD_INIT: {
if (data_len >= 4) {
expected_total_crc = (uint32_t)data[0] |
((uint32_t)data[1] << 8) |
((uint32_t)data[2] << 16) |
((uint32_t)data[3] << 24);
}
buffer_offset = 0;
buffer_size = 0;
received_chunks = 0;
total_chunks = 0;
memset(hex_buffer, 0, MAX_HEX_SIZE);
state = PARSER_RECEIVING;
ESP_LOGI(TAG, "INIT: expected total CRC = 0x%08lX", (unsigned long)expected_total_crc);
/* Echo the received index so the webapp can distinguish INIT ACK
* from DATA chunk-0 ACK (both would be index 0 if hardcoded).
* Webapp sends INIT with INIT_ACK_INDEX (0xFFFE) for uniqueness. */
uint8_t ack[] = {CMD_ACK, index & 0xFF, (index >> 8) & 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00};
ble_service_send_notify_flashing(ack, sizeof(ack));
break;
}
case CMD_DATA: {
if (state != PARSER_RECEIVING) return PARSER_ERROR;
uint32_t chunk_crc = checksum_crc32(data, data_len);
if (chunk_crc != received_crc) {
ESP_LOGE(TAG, "CRC mismatch chunk %d: expected 0x%08lX, got 0x%08lX",
index, (unsigned long)received_crc, (unsigned long)chunk_crc);
uint8_t err[] = {CMD_ERR, index & 0xFF, (index >> 8) & 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00};
ble_service_send_notify_flashing(err, sizeof(err));
return PARSER_ERROR;
}
if (buffer_offset + data_len <= MAX_HEX_SIZE) {
memcpy(hex_buffer + buffer_offset, data, data_len);
buffer_offset += data_len;
received_chunks++;
} else {
ESP_LOGE(TAG, "Buffer overflow!");
state = PARSER_ERROR;
return PARSER_ERROR;
}
uint8_t ack[] = {CMD_ACK, index & 0xFF, (index >> 8) & 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00};
ble_service_send_notify_flashing(ack, sizeof(ack));
break;
}
case CMD_END: {
buffer_size = buffer_offset;
state = PARSER_COMPLETE;
ESP_LOGI(TAG, "END: %d bytes in %d chunks, buffer_size=%d",
buffer_size, received_chunks, (int)buffer_size);
break;
}
default:
return PARSER_ERROR;
}
return state;
}
uint32_t binary_parser_get_total_crc(void)
{
return expected_total_crc;
}
uint8_t *binary_parser_get_buffer(void)
{
return hex_buffer;
}
size_t binary_parser_get_buffer_size(void)
{
return buffer_size;
}
void binary_parser_reset(void)
{
state = PARSER_IDLE;
buffer_offset = 0;
buffer_size = 0;
received_chunks = 0;
total_chunks = 0;
expected_total_crc = 0;
}
parser_state_t binary_parser_get_state(void)
{
return state;
}