From 7473cf935a70f5186cbd93c8b05c2ab682cf825c Mon Sep 17 00:00:00 2001 From: Alex Lisitsyn Date: Fri, 26 Jun 2026 15:26:05 +0100 Subject: [PATCH] fix: address maximum api blocking time --- Kconfig | 11 +++++++- .../mb_controller/common/esp_modbus_master.c | 18 ++++++++++++- modbus/mb_controller/common/mbc_master.h | 18 ++++++++++--- modbus/mb_objects/common/mb_port_types.h | 27 ++++++++++++++++--- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/Kconfig b/Kconfig index f799740..4d38df0 100644 --- a/Kconfig +++ b/Kconfig @@ -71,12 +71,21 @@ menu "Modbus configuration" config FMB_MASTER_TIMEOUT_MS_RESPOND int "Slave respond timeout (Milliseconds)" - default 10000 + default 5000 range 150 30000 help If master sends a frame which is not broadcast, it has to wait some time for slave response. if slave is not respond in this time, the master will process timeout error. + config FMB_MASTER_MAX_API_BLOCKING_TIME_MS + int "Modbus TCP master API blocking threshold (ms)" + range 3000 200000 + default 6000 + help + This option represents the maximum API blocking time used by controller API calls. + This API blocking time was intentionally separated from master timeout = CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + to prevent possible misconfiguration and the value must be higher than the master timeout. + config FMB_MASTER_DELAY_MS_CONVERT int "Slave conversion delay (Milliseconds)" default 200 diff --git a/modbus/mb_controller/common/esp_modbus_master.c b/modbus/mb_controller/common/esp_modbus_master.c index 1d9010b..69d4c83 100644 --- a/modbus/mb_controller/common/esp_modbus_master.c +++ b/modbus/mb_controller/common/esp_modbus_master.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,8 @@ static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER"; +#define API_BLOCKING_THRESHOLD 500 + // This file implements public API for Modbus master controller. /** @@ -203,6 +205,20 @@ esp_err_t mbc_master_start(void *ctx) MB_RETURN_ON_FALSE(ctx, ESP_ERR_INVALID_STATE, TAG, "Master interface is not correctly initialized."); mbm_controller_iface_t *mbm_controller = MB_MASTER_GET_IFACE(ctx); + + uint32_t response_tout_ms = mbm_controller->opts.comm_opts.common_opts.response_tout_ms; + // Keep stack response timeout below API blocking threshold + if (!response_tout_ms || (response_tout_ms >= CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS)) { + response_tout_ms = (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + <= (CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS - API_BLOCKING_THRESHOLD)) + ? CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + : (CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS - API_BLOCKING_THRESHOLD); + ESP_LOGW(TAG, + "Master timeout option = (%u) exceeded the maximum API threshold or is uninitialized, will be set to configured value = %u.", + (unsigned)mbm_controller->opts.comm_opts.common_opts.response_tout_ms, (unsigned)response_tout_ms); + mbm_controller->opts.comm_opts.common_opts.response_tout_ms = response_tout_ms; + } + MB_RETURN_ON_FALSE(mbm_controller->start, ESP_ERR_INVALID_STATE, TAG, "Master interface is not correctly initialized."); error = mbm_controller->start(ctx); diff --git a/modbus/mb_controller/common/mbc_master.h b/modbus/mb_controller/common/mbc_master.h index 40d8073..837d57d 100644 --- a/modbus/mb_controller/common/mbc_master.h +++ b/modbus/mb_controller/common/mbc_master.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,16 +22,26 @@ #include "mb_utils.h" #include "mb_master.h" +#include "sdkconfig.h" + #ifdef __cplusplus extern "C" { #endif /* ----------------------- Defines ------------------------------------------*/ +#define MB_MIN_RESP_DELAY_MS (300) // Set the maximum resource waiting time, the actual time of resource release -// will be dependent on response time set by timer + conversion time if the command is received -#define MB_MAX_RESP_DELAY_MS (3000) -#define MB_MIN_RESP_DELAY_MS (300) +// will be dependent on response time set by timer + conversion time if the command is received. +#if defined(CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS) +#define MB_MAX_RESP_DELAY_MS (CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS) +_Static_assert( + (CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS) >= (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND), + "CONFIG_FMB_MASTER_MAX_API_BLOCKING_TIME_MS must be >= CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND" +); +#else +#define MB_MAX_RESP_DELAY_MS (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND) +#endif /** * @brief Modbus controller handler structure diff --git a/modbus/mb_objects/common/mb_port_types.h b/modbus/mb_objects/common/mb_port_types.h index a40914c..a0406a4 100644 --- a/modbus/mb_objects/common/mb_port_types.h +++ b/modbus/mb_objects/common/mb_port_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,11 +37,15 @@ typedef enum mb_comm_mode_enum mb_mode_type_t; #if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN) +#include #include "driver/uart.h" struct port_serial_opts_s { mb_mode_type_t mode; /*!< Modbus communication mode */ - uart_port_t port; /*!< Modbus communication port (UART) number */ + union { + uart_port_t port; /*!< UART driver port index (user API) */ + uint32_t ser_port_align; /*!< Overlay for union with TCP/common \c port field */ + }; uint8_t uid; /*!< Modbus slave address field (dummy for master) */ uint32_t response_tout_ms; /*!< Modbus slave response timeout */ uint64_t test_tout_us; /*!< Modbus test timeout (reserved) */ @@ -63,7 +67,7 @@ typedef enum addr_type_enum { struct port_common_opts_s { mb_mode_type_t mode; /*!< Modbus communication mode */ - uint16_t port; /*!< Modbus communication port (UART) number */ + uint32_t port; /*!< Modbus port number (TCP) or UART index (serial) */ uint8_t uid; /*!< Modbus slave address field (dummy for master) */ uint32_t response_tout_ms; /*!< Modbus slave response timeout */ uint64_t test_tout_us; /*!< Modbus test timeout (reserved) */ @@ -71,7 +75,10 @@ struct port_common_opts_s { struct port_tcp_opts_s { mb_mode_type_t mode; /*!< Modbus communication mode */ - uint16_t port; /*!< Modbus communication port (UART) number */ + struct { + uint16_t port; /*!< Modbus port number (TCP) */ + uint16_t tcp_port_align; /*!< Overlay for union with SERIAL/common \c port field */ + }; uint8_t uid; /*!< Modbus slave address field (dummy for master) */ uint32_t response_tout_ms; /*!< Modbus slave response timeout */ uint64_t test_tout_us; /*!< Modbus test timeout (reserved) */ @@ -84,6 +91,18 @@ struct port_tcp_opts_s { typedef struct port_tcp_opts_s mb_tcp_opts_t; +#if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN) +_Static_assert(sizeof(uart_port_t) == sizeof(uint32_t), + "uart_port_t must match uint32_t width of common/tcp port for mb_communication_info_t union"); +_Static_assert(offsetof(struct port_serial_opts_s, response_tout_ms) == offsetof(struct port_common_opts_s, response_tout_ms), + "serial/common Modbus opts: response_tout_ms offset must match (mb_communication_info_t union)"); +#endif + +#if (CONFIG_FMB_COMM_MODE_TCP_EN) && (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN) +_Static_assert(offsetof(struct port_serial_opts_s, response_tout_ms) == offsetof(struct port_tcp_opts_s, response_tout_ms), + "serial/tcp Modbus opts: response_tout_ms offset must match (mb_communication_info_t union)"); +#endif + // The common object descriptor structure (common for mb, transport, port objects) struct obj_descr_s { char *parent_name; /*!< Name of the parent (base) object */