Fixed multiple devices causing overflow in compile. Fixed PICS Float data type not being decoded correctly (bit order reversed).
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
#define WIFI_SSID_MAX_LEN 32
|
||||
#define WIFI_PASSWORD_MAX_LEN 64
|
||||
#define IPV4_STR_MAX_LEN 16
|
||||
#define MAX_VIRTUAL_DEVICES 2
|
||||
#define MAX_VIRTUAL_DEVICES 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
392
main/main.c
392
main/main.c
@@ -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));
|
||||
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#define TAG_MEM "MODBUS_MEM"
|
||||
|
||||
static modbus_point_type_t mem_to_point_type(modbus_mem_type_t type)
|
||||
{
|
||||
switch (type)
|
||||
@@ -233,8 +236,8 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
{
|
||||
uint32_t v = (pics_i32 < 0) ? 0U : (uint32_t)pics_i32;
|
||||
|
||||
out_words[0] = (uint16_t)((v >> 16) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)(v & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(v & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((v >> 16) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 2U))
|
||||
return false;
|
||||
@@ -248,8 +251,8 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
|
||||
memcpy(&raw_f32, &f, sizeof(raw_f32));
|
||||
|
||||
out_words[0] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)(raw_f32 & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(raw_f32 & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 2U))
|
||||
return false;
|
||||
@@ -263,10 +266,10 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
|
||||
memcpy(&raw_f64, &d, sizeof(raw_f64));
|
||||
|
||||
out_words[0] = (uint16_t)((raw_f64 >> 48) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_f64 >> 32) & 0xFFFFU);
|
||||
out_words[2] = (uint16_t)((raw_f64 >> 16) & 0xFFFFU);
|
||||
out_words[3] = (uint16_t)(raw_f64 & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(raw_f64 & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_f64 >> 16) & 0xFFFFU);
|
||||
out_words[2] = (uint16_t)((raw_f64 >> 32) & 0xFFFFU);
|
||||
out_words[3] = (uint16_t)((raw_f64 >> 48) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 4U))
|
||||
return false;
|
||||
@@ -286,10 +289,10 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
uint64_t raw_f64;
|
||||
double pics_d;
|
||||
|
||||
raw_f64 = ((uint64_t)pt->pics_words[0] << 48) |
|
||||
((uint64_t)pt->pics_words[1] << 32) |
|
||||
((uint64_t)pt->pics_words[2] << 16) |
|
||||
(uint64_t)pt->pics_words[3];
|
||||
raw_f64 = ((uint64_t)pt->pics_words[3] << 48) |
|
||||
((uint64_t)pt->pics_words[2] << 32) |
|
||||
((uint64_t)pt->pics_words[1] << 16) |
|
||||
(uint64_t)pt->pics_words[0];
|
||||
|
||||
memcpy(&pics_d, &raw_f64, sizeof(pics_d));
|
||||
|
||||
@@ -321,8 +324,8 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
|
||||
u32 = (uint32_t)v;
|
||||
|
||||
out_words[0] = (uint16_t)((u32 >> 16) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)(u32 & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(u32 & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((u32 >> 16) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 2U))
|
||||
return false;
|
||||
@@ -336,8 +339,8 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
|
||||
memcpy(&raw_f32, &f, sizeof(raw_f32));
|
||||
|
||||
out_words[0] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)(raw_f32 & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(raw_f32 & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 2U))
|
||||
return false;
|
||||
@@ -350,10 +353,10 @@ static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *p
|
||||
|
||||
memcpy(&raw_out_f64, &pics_d, sizeof(raw_out_f64));
|
||||
|
||||
out_words[0] = (uint16_t)((raw_out_f64 >> 48) & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_out_f64 >> 32) & 0xFFFFU);
|
||||
out_words[2] = (uint16_t)((raw_out_f64 >> 16) & 0xFFFFU);
|
||||
out_words[3] = (uint16_t)(raw_out_f64 & 0xFFFFU);
|
||||
out_words[0] = (uint16_t)(raw_out_f64 & 0xFFFFU);
|
||||
out_words[1] = (uint16_t)((raw_out_f64 >> 16) & 0xFFFFU);
|
||||
out_words[2] = (uint16_t)((raw_out_f64 >> 32) & 0xFFFFU);
|
||||
out_words[3] = (uint16_t)((raw_out_f64 >> 48) & 0xFFFFU);
|
||||
|
||||
if (!write_point_words(mem, pt, out_words, 4U))
|
||||
return false;
|
||||
@@ -396,6 +399,7 @@ static bool write_pics_staging_word(modbus_memory_t *mem,
|
||||
return false;
|
||||
|
||||
pt->pics_words[word_index] = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -536,15 +540,44 @@ bool modbus_memory_read_holding_register(modbus_memory_t *mem, uint16_t offset,
|
||||
{
|
||||
const modbus_point_t *pt;
|
||||
|
||||
if (mem == NULL || value == NULL)
|
||||
if (mem == NULL || mem->db == NULL || value == NULL)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* First try normal/official holding register.
|
||||
*/
|
||||
pt = find_point_ro(mem, MB_MEM_HOLDING_REGISTER, offset);
|
||||
if (pt == NULL)
|
||||
return false;
|
||||
if (pt != NULL)
|
||||
{
|
||||
*value = pt->reg_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
*value = pt->reg_value;
|
||||
return true;
|
||||
/*
|
||||
* Then allow reading PICS staging registers directly.
|
||||
* This makes ModScan useful for verifying addresses like 410005-410008.
|
||||
*/
|
||||
pt = modbus_points_find_by_pics_range(mem->db,
|
||||
MB_POINT_HOLDING_REGISTER,
|
||||
offset);
|
||||
|
||||
if (pt != NULL && pt->has_pics_address)
|
||||
{
|
||||
uint16_t word_index;
|
||||
|
||||
if (offset < pt->pics_offset)
|
||||
return false;
|
||||
|
||||
word_index = (uint16_t)(offset - pt->pics_offset);
|
||||
|
||||
if (word_index >= pt->pics_reg_span || word_index >= 4U)
|
||||
return false;
|
||||
|
||||
*value = pt->pics_words[word_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool modbus_memory_write_holding_register(modbus_memory_t *mem, uint16_t offset, uint16_t value)
|
||||
@@ -562,8 +595,14 @@ bool modbus_memory_write_holding_register(modbus_memory_t *mem, uint16_t offset,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (write_pics_staging_word(mem, MB_MEM_HOLDING_REGISTER, offset, value))
|
||||
return true;
|
||||
pt = find_pics_point_rw(mem, MB_MEM_HOLDING_REGISTER, offset);
|
||||
if (pt != NULL)
|
||||
{
|
||||
if (!write_pics_staging_word(mem, MB_MEM_HOLDING_REGISTER, offset, value))
|
||||
return false;
|
||||
|
||||
return apply_pics_to_official_point(mem,pt);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "modbus_memory.h"
|
||||
|
||||
#define MODBUS_MAX_POINTS 384
|
||||
#define MODBUS_MAX_POINTS 130
|
||||
#define MODBUS_MAX_NAME_LEN 32
|
||||
#define MODBUS_MAX_NOTES_LEN 64
|
||||
#define MODBUS_MAX_CSV_LINE_LEN 256
|
||||
|
||||
Reference in New Issue
Block a user