Fixed multiple devices causing overflow in compile. Fixed PICS Float data type not being decoded correctly (bit order reversed).

This commit is contained in:
2026-05-21 14:06:43 -05:00
parent 7ab3723533
commit 70cd36c934
1394 changed files with 35353 additions and 35295 deletions

View File

@@ -15,6 +15,8 @@
#include "esp_err.h"
#include "nvs_flash.h"
#include "esp_spiffs.h"
#include "esp_heap_caps.h"
#include "esp_timer.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
@@ -31,6 +33,7 @@
#define TAG "MODBUS_MAIN"
#define MODBUS_RX_BUF_SIZE MODBUS_TCP_MAX_ADU_LEN
#define MODBUS_TX_BUF_SIZE MODBUS_TCP_MAX_ADU_LEN
#define MODBUS_CLIENT_IDLE_TIMEOUT_US (120000000LL) /* 120 seconds */
static device_config_t g_device_cfg;
@@ -52,8 +55,9 @@ typedef struct
modbus_memory_t mem;
} modbus_device_t;
static modbus_device_t g_devices[MAX_VIRTUAL_DEVICES];
static modbus_device_t **g_devices = NULL;
static size_t g_device_count = 0;
static size_t g_device_capacity = 0;
/* ------------------------------------------------------------ */
/* Helpers */
@@ -65,8 +69,8 @@ static modbus_device_t *find_device_by_unit_id(uint8_t unit_id)
for (i = 0; i < g_device_count; i++)
{
if (g_devices[i].unit_id == unit_id)
return &g_devices[i];
if (g_devices[i] != NULL && g_devices[i]->unit_id == unit_id)
return g_devices[i];
}
return NULL;
@@ -246,14 +250,53 @@ static void modbus_client_task(void *arg)
vTaskDelete(NULL);
}
static void close_client_slot(int client_socks[], struct sockaddr_in client_addrs[], int index)
{
if (client_socks[index] >= 0)
{
ESP_LOGI(TAG, "Client disconnected: %s:%d",
inet_ntoa(client_addrs[index].sin_addr),
ntohs(client_addrs[index].sin_port));
shutdown(client_socks[index], 0);
close(client_socks[index]);
client_socks[index] = -1;
if (g_active_modbus_clients > 0)
g_active_modbus_clients--;
}
}
static void modbus_server_task(void *arg)
{
int listen_sock = -1;
struct sockaddr_in server_addr;
int opt = 1;
int client_socks[16];
struct sockaddr_in client_addrs[16];
int64_t client_last_seen[16];
uint8_t rx_buf[MODBUS_RX_BUF_SIZE];
uint8_t tx_buf[MODBUS_TX_BUF_SIZE];
uint8_t max_clients = g_device_cfg.modbus.max_clients;
(void)arg;
if (max_clients == 0U)
max_clients = 1U;
if (max_clients > 16U)
max_clients = 16U;
for (int i = 0; i < 16; i++)
{
client_socks[i] = -1;
client_last_seen[i] = 0;
memset(&client_addrs[i], 0, sizeof(client_addrs[i]));
}
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (listen_sock < 0)
{
@@ -277,7 +320,7 @@ static void modbus_server_task(void *arg)
return;
}
if (listen(listen_sock, g_device_cfg.modbus.max_clients) < 0)
if (listen(listen_sock, max_clients) < 0)
{
ESP_LOGE(TAG, "Socket listen failed: errno=%d", errno);
close(listen_sock);
@@ -287,59 +330,198 @@ static void modbus_server_task(void *arg)
ESP_LOGI(TAG, "Modbus TCP server listening on port %u (max_clients=%u)",
(unsigned)g_device_cfg.modbus.port,
(unsigned)g_device_cfg.modbus.max_clients);
(unsigned)max_clients);
while (1)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);
fd_set read_fds;
int max_fd = listen_sock;
int ready;
if (client_sock < 0)
{
ESP_LOGW(TAG, "accept failed: errno=%d", errno);
continue;
}
FD_ZERO(&read_fds);
FD_SET(listen_sock, &read_fds);
if (g_active_modbus_clients >= (int)g_device_cfg.modbus.max_clients)
for (int i = 0; i < max_clients; i++)
{
ESP_LOGW(TAG, "Rejecting client %s:%d (active=%d max=%u)",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
g_active_modbus_clients,
(unsigned)g_device_cfg.modbus.max_clients);
shutdown(client_sock, 0);
close(client_sock);
continue;
}
{
modbus_client_ctx_t *ctx = malloc(sizeof(modbus_client_ctx_t));
if (ctx == NULL)
if (client_socks[i] >= 0)
{
ESP_LOGE(TAG, "Out of memory allocating client context");
shutdown(client_sock, 0);
close(client_sock);
FD_SET(client_socks[i], &read_fds);
if (client_socks[i] > max_fd)
max_fd = client_socks[i];
}
}
int64_t now = esp_timer_get_time();
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ready = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);
if (ready < 0)
{
ESP_LOGW(TAG, "select failed: errno=%d", errno);
vTaskDelay(pdMS_TO_TICKS(10));
continue;
}
if (FD_ISSET(listen_sock, &read_fds))
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len);
int slot = -1;
if (client_sock < 0)
{
if (errno == 23 || errno == EMFILE || errno == ENFILE || errno == ENOMEM)
{
ESP_LOGW(TAG,
"accept failed: socket resources exhausted errno=%d active=%d max=%u; backing off",
errno,
g_active_modbus_clients,
(unsigned)max_clients);
vTaskDelay(pdMS_TO_TICKS(500));
}
else
{
ESP_LOGW(TAG, "accept failed: errno=%d", errno);
vTaskDelay(pdMS_TO_TICKS(50));
}
}
else
{
for (int i = 0; i < max_clients; i++)
{
if (client_socks[i] < 0)
{
slot = i;
break;
}
}
if (slot < 0)
{
ESP_LOGW(TAG, "Rejecting client %s:%d (active=%d max=%u)",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
g_active_modbus_clients,
(unsigned)max_clients);
shutdown(client_sock, 0);
close(client_sock);
}
else
{
client_socks[slot] = client_sock;
client_addrs[slot] = client_addr;
client_last_seen[slot] = esp_timer_get_time();
g_active_modbus_clients++;
ESP_LOGI(TAG, "Client connected: %s:%d (active=%d)",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
g_active_modbus_clients);
}
}
}
for (int i = 0; i < max_clients; i++)
{
if (client_socks[i] < 0)
continue;
if (!FD_ISSET(client_socks[i], &read_fds))
continue;
int len = recv(client_socks[i], rx_buf, sizeof(rx_buf), 0);
if (len < 0)
{
ESP_LOGW(TAG, "recv failed from %s:%d errno=%d",
inet_ntoa(client_addrs[i].sin_addr),
ntohs(client_addrs[i].sin_port),
errno);
close_client_slot(client_socks, client_addrs, i);
client_last_seen[i] = 0;
continue;
}
ctx->sock = client_sock;
ctx->addr = client_addr;
g_active_modbus_clients++;
if (xTaskCreate(modbus_client_task,
"modbus_client_task",
6144,
ctx,
5,
NULL) != pdPASS)
if (len == 0)
{
ESP_LOGE(TAG, "Failed to create client task");
g_active_modbus_clients--;
shutdown(client_sock, 0);
close(client_sock);
free(ctx);
close_client_slot(client_socks, client_addrs, i);
client_last_seen[i] = 0;
continue;
}
if (len < 7)
continue;
client_last_seen[i] = esp_timer_get_time();
uint8_t unit_id = rx_buf[6];
modbus_device_t *dev = find_device_by_unit_id(unit_id);
if (dev == NULL)
{
ESP_LOGW(TAG, "Unknown Unit ID %u from %s:%d",
(unsigned)unit_id,
inet_ntoa(client_addrs[i].sin_addr),
ntohs(client_addrs[i].sin_port));
continue;
}
size_t resp_len = 0;
bool ok = modbus_tcp_process_request(&dev->mem,
rx_buf,
(size_t)len,
tx_buf,
sizeof(tx_buf),
&resp_len);
if (!ok)
{
if (len >= 8)
{
ESP_LOGW(TAG, "Unsupported Modbus request from %s:%d (unit_id=%u fc=0x%02X)",
inet_ntoa(client_addrs[i].sin_addr),
ntohs(client_addrs[i].sin_port),
(unsigned)unit_id,
(unsigned)rx_buf[7]);
}
continue;
}
if (resp_len > 0U)
{
int sent = send(client_socks[i], tx_buf, (int)resp_len, 0);
if (sent < 0)
{
ESP_LOGW(TAG, "send failed to %s:%d errno=%d",
inet_ntoa(client_addrs[i].sin_addr),
ntohs(client_addrs[i].sin_port),
errno);
close_client_slot(client_socks, client_addrs, i);
continue;
}
}
}
for (int i = 0; i < max_clients; i++)
{
if (client_socks[i] >= 0 && client_last_seen[i] > 0 && (now - client_last_seen[i]) > MODBUS_CLIENT_IDLE_TIMEOUT_US)
{
ESP_LOGW(TAG, "Closing idle Modbus client %s:%d",
inet_ntoa(client_addrs[i].sin_addr),
ntohs(client_addrs[i].sin_port));
close_client_slot(client_socks, client_addrs, i);
client_last_seen[i] = 0;
}
}
}
@@ -359,7 +541,11 @@ static void modbus_override_task(void *arg)
for (d = 0; d < g_device_count; d++)
{
modbus_device_t *dev = &g_devices[d];
modbus_device_t *dev = g_devices[d];
if (dev == NULL)
continue;
size_t i;
for (i = 0; i < dev->db.count; i++)
@@ -685,8 +871,27 @@ void app_main(void)
return;
}
memset(g_devices, 0, sizeof(g_devices));
g_device_count = 0U;
g_device_capacity = g_device_cfg.modbus.device_count;
g_devices = heap_caps_calloc(g_device_capacity,
sizeof(modbus_device_t *),
MALLOC_CAP_8BIT);
if (g_devices == NULL)
{
ESP_LOGE(TAG,
"Failed to allocate Modbus device table: devices=%u total=%u",
(unsigned)g_device_capacity,
(unsigned)(g_device_capacity * sizeof(modbus_device_t *)));
return;
}
ESP_LOGI(TAG,
"Allocated Modbus device table: devices=%u pointer_table_size=%u device_struct_size=%u",
(unsigned)g_device_capacity,
(unsigned)(g_device_capacity * sizeof(modbus_device_t *)),
(unsigned)sizeof(modbus_device_t));
for (i = 0; i < g_device_cfg.modbus.device_count; i++)
{
@@ -699,7 +904,28 @@ void app_main(void)
continue;
}
dev = &g_devices[g_device_count];
if (g_device_count >= g_device_capacity)
{
ESP_LOGE(TAG, "Device table full: count=%u capacity=%u",
(unsigned)g_device_count,
(unsigned)g_device_capacity);
break;
}
dev = heap_caps_calloc(1,
sizeof(modbus_device_t),
MALLOC_CAP_8BIT);
if (dev == NULL)
{
ESP_LOGE(TAG,
"Failed to allocate Modbus device %u: size=%u free_heap=%u largest_block=%u",
(unsigned)(i + 1U),
(unsigned)sizeof(modbus_device_t),
(unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
continue;
}
dev->unit_id = cfg_dev->unit_id;
@@ -723,6 +949,7 @@ void app_main(void)
ESP_LOGE(TAG, "CSV file not found for device %u: %s",
(unsigned)dev->unit_id,
dev->csv_path);
heap_caps_free(dev);
continue;
}
@@ -737,6 +964,7 @@ void app_main(void)
ESP_LOGE(TAG, "Failed to load CSV for device %u: %s",
(unsigned)dev->unit_id,
dev->csv_path);
heap_caps_free(dev);
continue;
}
@@ -750,7 +978,8 @@ void app_main(void)
(unsigned)MODBUS_MAX_POINTS);
ESP_LOGE(TAG, "Startup aborted to prevent memory corruption.");
heap_caps_free(dev);
abort();
}
@@ -758,6 +987,7 @@ void app_main(void)
{
ESP_LOGE(TAG, "Memory init failed for device %u",
(unsigned)dev->unit_id);
heap_caps_free(dev);
continue;
}
@@ -767,6 +997,7 @@ void app_main(void)
(unsigned)dev->db.count,
dev->csv_path);
g_devices[g_device_count] = dev;
g_device_count++;
}
@@ -777,10 +1008,10 @@ void app_main(void)
ESP_LOGI(TAG,
"RUNTIME device[%u]: unit_id=%u name=%s csv=%s points=%u",
(unsigned)i,
(unsigned)g_devices[i].unit_id,
g_devices[i].name,
g_devices[i].csv_path,
(unsigned)g_devices[i].db.count);
(unsigned)g_devices[i]->unit_id,
g_devices[i]->name,
g_devices[i]->csv_path,
(unsigned)g_devices[i]->db.count);
}
ESP_LOGI(TAG, "---------------------------------------");
@@ -803,7 +1034,7 @@ void app_main(void)
for (i = 0; i < g_device_count; i++)
{
const modbus_device_t *dev = &g_devices[i];
const modbus_device_t *dev = g_devices[i];
size_t remaining = 0;
float pct = 0.0f;
@@ -869,7 +1100,7 @@ void app_main(void)
for (i = 0; i < g_device_count; i++)
{
print_device_type_mix(&g_devices[i]);
print_device_type_mix(g_devices[i]);
}
ESP_LOGI(TAG, "---------------------------");
@@ -880,7 +1111,10 @@ void app_main(void)
for (size_t d = 0; d < g_device_count; d++)
{
const modbus_device_t *dev = &g_devices[d];
const modbus_device_t *dev = g_devices[d];
if (dev == NULL)
continue;
ESP_LOGI(TAG,
"Device %u (%s): %u / %u points used (%.1f%%)",
@@ -913,6 +1147,46 @@ void app_main(void)
ESP_LOGW(TAG, "Wi-Fi not connected within timeout, server will still start");
}
xTaskCreate(modbus_server_task, "modbus_server_task", 8192, NULL, 5, NULL);
xTaskCreate(modbus_override_task, "modbus_override_task", 4096, NULL, 5, NULL);
ESP_LOGI(TAG,
"Heap before starting Modbus tasks: free=%u largest=%u",
(unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
BaseType_t server_ok = xTaskCreate(modbus_server_task,
"modbus_server_task",
6144,
NULL,
5,
NULL);
if (server_ok != pdPASS)
{
ESP_LOGE(TAG,
"Failed to create modbus_server_task: free_heap=%u largest_block=%u",
(unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
return;
}
BaseType_t override_ok = xTaskCreate(modbus_override_task,
"modbus_override_task",
3072,
NULL,
5,
NULL);
if (override_ok != pdPASS)
{
ESP_LOGE(TAG,
"Failed to create modbus_override_task: free_heap=%u largest_block=%u",
(unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
return;
}
ESP_LOGI(TAG,
"Modbus tasks started: free_heap=%u largest_block=%u",
(unsigned)heap_caps_get_free_size(MALLOC_CAP_8BIT),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
}