diff --git a/docs/en/port_initialization.rst b/docs/en/port_initialization.rst index bf4b6428..4411fbe2 100644 --- a/docs/en/port_initialization.rst +++ b/docs/en/port_initialization.rst @@ -7,6 +7,8 @@ The ESP_Modbus supports Modbus SERIAL and TCP communication objects and an objec - :cpp:func:`mbc_slave_create_serial` - :cpp:func:`mbc_master_create_serial` +- :cpp:func:`mbc_slave_create_serial_with_transport` +- :cpp:func:`mbc_master_create_serial_with_transport` - :cpp:func:`mbc_master_create_tcp` - :cpp:func:`mbc_slave_create_tcp` @@ -40,6 +42,49 @@ Calling the constructor function allows to create communication object with the Refer to :ref:`modbus_api_master_setup_communication_options` and :ref:`modbus_api_slave_setup_communication_options` for more information on how to configure communication options for the master and slave object accordingly. +Custom RTU Transport +^^^^^^^^^^^^^^^^^^^^ + +The serial master and slave constructors normally create the standard RTU +transport and serial port. Applications that need to provide their own RTU +framing, serial I/O, or routing can instead use +:cpp:func:`mbc_master_create_serial_with_transport` or +:cpp:func:`mbc_slave_create_serial_with_transport`. These constructors accept +a factory which creates an initialized ``mb_trans_base_t`` transport. + +The custom factory path applies only when ``config.ser_opts.mode`` is +``MB_RTU``. ASCII mode continues to use the standard transport. A factory +returns the initialized transport through its output argument and must set the +transport's ``port_obj``. It must also implement the transport callbacks used +by the controller. The controller takes ownership of a successfully returned +transport and calls its ``frm_delete`` callback during cleanup. + +The following slave example shows the factory call. The master equivalent uses +``mbc_master_create_serial_with_transport()`` and +``mbc_master_transport_factory_t``. + +.. code:: c + + static mb_err_enum_t custom_slave_transport_factory( + const mbc_slave_transport_factory_args_t *args, + mb_trans_base_t **transport) + { + // Create an initialized custom RTU transport using args->comm_info + // and, when needed, args->user_ctx. + return my_rtu_transport_create(args, transport); + } + + static void *slave_handle = NULL; + ESP_ERROR_CHECK(mbc_slave_create_serial_with_transport( + &config, custom_slave_transport_factory, my_transport_context, + &slave_handle)); + +The factory receives the requested communication configuration, the owning +controller object, and the caller-defined context. The caller retains ownership +of the context itself unless the custom transport documents otherwise. Pass +``NULL`` as the factory to use the standard RTU transport; the ordinary +``mbc_*_create_serial()`` constructors already do this. + .. _modbus_api_master_setup_communication_options: Master Communication Options diff --git a/examples/serial/mb_serial_slave/README.md b/examples/serial/mb_serial_slave/README.md index ae04a42c..6c56d212 100644 --- a/examples/serial/mb_serial_slave/README.md +++ b/examples/serial/mb_serial_slave/README.md @@ -62,6 +62,16 @@ Set ```Modbus slave address``` for the example application (by default for examp The communication parameters of esp-modbus stack (Component config->Modbus configuration) allow to configure it appropriately but usually it is enough to use default settings. See the help strings of parameters for more information. +### Custom RTU transport factory + +Enable `Create the RTU slave with a transport factory` in the `Modbus Example +Configuration` menu to exercise `mbc_slave_create_serial_with_transport()`. +The example factory delegates to the stock RTU transport, so its on-wire behavior +is unchanged. It shows the construction boundary where an application can supply +its own initialized `mb_trans_base_t` implementation instead, for example to own +serial I/O or route complete RTU frames. A custom transport must set its +`port_obj` and implement the transport callbacks required by the controller. + ### Setup external Modbus master software Option 1: Configure the external Modbus master software according to port configuration parameters used in application. diff --git a/examples/serial/mb_serial_slave/main/CMakeLists.txt b/examples/serial/mb_serial_slave/main/CMakeLists.txt index a6f301e0..1a2d576b 100644 --- a/examples/serial/mb_serial_slave/main/CMakeLists.txt +++ b/examples/serial/mb_serial_slave/main/CMakeLists.txt @@ -1,5 +1,19 @@ +set(priv_include_dirs) + +if(CONFIG_MB_USE_TRANSPORT_FACTORY) + # The factory example delegates to the stock RTU transport, whose constructor + # and transitive headers are intentionally internal to the esp-modbus component. + list(APPEND priv_include_dirs + "../../../../modbus/mb_transports/rtu" + "../../../../modbus/mb_transports" + "../../../../modbus/mb_objects/include" + "../../../../modbus/mb_objects/common" + "../../../../modbus/mb_ports/common") +endif() + idf_component_register(SRCS "serial_slave.c" - INCLUDE_DIRS ".") + INCLUDE_DIRS "." + PRIV_INCLUDE_DIRS "${priv_include_dirs}") set(PROJECT_NAME "modbus_serial_slave") diff --git a/examples/serial/mb_serial_slave/main/Kconfig.projbuild b/examples/serial/mb_serial_slave/main/Kconfig.projbuild index bf122acd..41bdbcad 100644 --- a/examples/serial/mb_serial_slave/main/Kconfig.projbuild +++ b/examples/serial/mb_serial_slave/main/Kconfig.projbuild @@ -105,6 +105,16 @@ menu "Modbus Example Configuration" endchoice + config MB_USE_TRANSPORT_FACTORY + bool "Create the RTU slave with a transport factory" + default n + depends on MB_COMM_MODE_RTU + help + Demonstrate mbc_slave_create_serial_with_transport(). The example + factory delegates to the stock RTU transport. Replace that factory + with an application transport implementation to customize framing, + serial I/O, or routing. + config MB_SLAVE_ADDR int "Modbus slave address" range 1 247 diff --git a/examples/serial/mb_serial_slave/main/serial_slave.c b/examples/serial/mb_serial_slave/main/serial_slave.c index 965e0fc1..9973d4cb 100644 --- a/examples/serial/mb_serial_slave/main/serial_slave.c +++ b/examples/serial/mb_serial_slave/main/serial_slave.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,37 @@ #define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR) // The address of device in Modbus network #define MB_DEV_SPEED (CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART +#if CONFIG_MB_USE_TRANSPORT_FACTORY +#include "rtu_transport.h" // for stock RTU transport factory delegate +/** + * @brief Create the standard RTU transport through the custom factory interface. + * + * @param[in] args Controller-provided communication settings. + * @param[out] transport Initialized RTU transport. + * + * @return `MB_ENOERR` on success; another `mb_err_enum_t` value on failure. + */ +static mb_err_enum_t serial_slave_transport_factory(const mbc_slave_transport_factory_args_t *args, + mb_trans_base_t **transport) +{ + mb_serial_opts_t serial_opts = args->comm_info->ser_opts; + mb_port_base_t port_parent = { + .descr = { + .parent_name = "factory_example", + .obj_name = "factory_example", + .parent = args->parent, + .is_master = false, + }, + }; + void *transport_instance = &port_parent; + mb_err_enum_t err = mbs_rtu_transp_create(&serial_opts, &transport_instance); + if (err == MB_ENOERR) { + *transport = transport_instance; + } + return err; +} +#endif + // Note: Some pins on target chip cannot be assigned for UART communication. // Please refer to documentation for selected board and target to configure pins using Kconfig. @@ -198,7 +229,14 @@ void app_main(void) .ser_opts.stop_bits = UART_STOP_BITS_1 }; - ESP_ERROR_CHECK(mbc_slave_create_serial(&comm_config, &mbc_slave_handle)); // Initialization of Modbus controller +#if CONFIG_MB_USE_TRANSPORT_FACTORY + ESP_ERROR_CHECK(mbc_slave_create_serial_with_transport(&comm_config, + serial_slave_transport_factory, + NULL, + &mbc_slave_handle)); +#else + ESP_ERROR_CHECK(mbc_slave_create_serial(&comm_config, &mbc_slave_handle)); +#endif const uint8_t custom_command = 0x41; // The custom command to be sent to slave // Try to delete the handler for specified command. diff --git a/modbus/mb_controller/common/esp_modbus_master_serial.c b/modbus/mb_controller/common/esp_modbus_master_serial.c index d5fe78de..c98a3c9e 100644 --- a/modbus/mb_controller/common/esp_modbus_master_serial.c +++ b/modbus/mb_controller/common/esp_modbus_master_serial.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,14 +16,17 @@ /** * Initialization of Modbus master serial */ -esp_err_t mbc_master_create_serial(mb_communication_info_t *config, void **ctx) +esp_err_t mbc_master_create_serial_with_transport(mb_communication_info_t *config, + mbc_master_transport_factory_t factory, + void *user_ctx, + void **ctx) { void *obj = NULL; esp_err_t error = ESP_ERR_NOT_SUPPORTED; switch (config->mode) { case MB_RTU: case MB_ASCII: - error = mbc_serial_master_create(config, &obj); + error = mbc_serial_master_create_with_transport(config, factory, user_ctx, &obj); break; default: return ESP_ERR_NOT_SUPPORTED; @@ -34,4 +37,9 @@ esp_err_t mbc_master_create_serial(mb_communication_info_t *config, void **ctx) return error; } +esp_err_t mbc_master_create_serial(mb_communication_info_t *config, void **ctx) +{ + return mbc_master_create_serial_with_transport(config, NULL, NULL, ctx); +} + #endif diff --git a/modbus/mb_controller/common/esp_modbus_slave_serial.c b/modbus/mb_controller/common/esp_modbus_slave_serial.c index 72af1d51..444f4a2a 100644 --- a/modbus/mb_controller/common/esp_modbus_slave_serial.c +++ b/modbus/mb_controller/common/esp_modbus_slave_serial.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,7 +17,10 @@ /** * Initialization of Modbus Serial slave controller */ -esp_err_t mbc_slave_create_serial(mb_communication_info_t *config, void **ctx) +esp_err_t mbc_slave_create_serial_with_transport(mb_communication_info_t *config, + mbc_slave_transport_factory_t factory, + void *user_ctx, + void **ctx) { void *obj = NULL; esp_err_t error = ESP_ERR_NOT_SUPPORTED; @@ -25,7 +28,7 @@ esp_err_t mbc_slave_create_serial(mb_communication_info_t *config, void **ctx) case MB_RTU: case MB_ASCII: // Call constructor function of actual port implementation - error = mbc_serial_slave_create(config, &obj); + error = mbc_serial_slave_create_with_transport(config, factory, user_ctx, &obj); break; default: return ESP_ERR_NOT_SUPPORTED; @@ -37,4 +40,9 @@ esp_err_t mbc_slave_create_serial(mb_communication_info_t *config, void **ctx) return error; } +esp_err_t mbc_slave_create_serial(mb_communication_info_t *config, void **ctx) +{ + return mbc_slave_create_serial_with_transport(config, NULL, NULL, ctx); +} + #endif diff --git a/modbus/mb_controller/common/include/esp_modbus_master.h b/modbus/mb_controller/common/include/esp_modbus_master.h index 690c298e..689a30c6 100644 --- a/modbus/mb_controller/common/include/esp_modbus_master.h +++ b/modbus/mb_controller/common/include/esp_modbus_master.h @@ -11,6 +11,8 @@ #include "soc/soc.h" // for BITN definitions #include "esp_modbus_common.h" // for common types +typedef struct mb_trans_base_t mb_trans_base_t; + #ifdef __cplusplus extern "C" { #endif @@ -223,6 +225,49 @@ esp_err_t mbc_master_create_tcp(mb_communication_info_t *config, void **ctx); */ esp_err_t mbc_master_create_serial(mb_communication_info_t *config, void **ctx); +/** + * @brief Arguments supplied when constructing a custom serial master transport. + * + * The factory must return an initialized RTU transport whose `port_obj` is set. + * The transport implementation owns `user_ctx`; the controller does not retain + * or delete it directly. + */ +typedef struct { + const mb_communication_info_t *comm_info; /*!< Requested serial configuration. */ + void *parent; /*!< Owning controller object. */ + void *user_ctx; /*!< Caller-defined factory context. */ +} mbc_master_transport_factory_args_t; + +/** + * @brief Factory used to construct a custom RTU master transport. + * + * @param[in] args Factory arguments supplied by the controller. + * @param[out] transport Initialized transport instance on success. + * + * @return `MB_ENOERR` on success; another `mb_err_enum_t` value on failure. + */ +typedef mb_err_enum_t (*mbc_master_transport_factory_t)( + const mbc_master_transport_factory_args_t *args, mb_trans_base_t **transport); + +/** + * @brief Initialize a serial Modbus master controller with a caller-provided RTU transport. + * + * Passing a factory bypasses the stock serial port and RTU transport creation. + * The supplied factory is used only for `MB_RTU`; ASCII uses the stock transport. + * + * @param[in] config Pointer to the master communication configuration. + * @param[in] factory Custom RTU transport factory, or `NULL` for the stock transport. + * @param[in] user_ctx Caller-defined context passed to `factory`. + * @param[out] ctx Initialized controller context. + * + * @return ESP_OK on success; an ESP-IDF error code otherwise. + */ +esp_err_t mbc_master_create_serial_with_transport( + mb_communication_info_t *config, + mbc_master_transport_factory_t factory, + void *user_ctx, + void **ctx); + /** * @brief Deletes Modbus controller and stack engine * diff --git a/modbus/mb_controller/common/include/esp_modbus_slave.h b/modbus/mb_controller/common/include/esp_modbus_slave.h index abea3b5f..6c3d00ed 100644 --- a/modbus/mb_controller/common/include/esp_modbus_slave.h +++ b/modbus/mb_controller/common/include/esp_modbus_slave.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 */ @@ -14,6 +14,8 @@ #include "freertos/event_groups.h" // for event groups #include "esp_modbus_common.h" // for common types +typedef struct mb_trans_base_t mb_trans_base_t; + #ifdef __cplusplus extern "C" { #endif @@ -103,6 +105,49 @@ esp_err_t mbc_slave_create_tcp(mb_communication_info_t *config, void **ctx); */ esp_err_t mbc_slave_create_serial(mb_communication_info_t *config, void **ctx); +/** + * @brief Arguments supplied when constructing a custom serial slave transport. + * + * The factory must return an initialized RTU transport whose `port_obj` is set. + * The transport implementation owns `user_ctx`; the controller does not retain + * or delete it directly. + */ +typedef struct { + const mb_communication_info_t *comm_info; /*!< Requested serial configuration. */ + void *parent; /*!< Owning controller object. */ + void *user_ctx; /*!< Caller-defined factory context. */ +} mbc_slave_transport_factory_args_t; + +/** + * @brief Factory used to construct a custom RTU slave transport. + * + * @param[in] args Factory arguments supplied by the controller. + * @param[out] transport Initialized transport instance on success. + * + * @return `MB_ENOERR` on success; another `mb_err_enum_t` value on failure. + */ +typedef mb_err_enum_t (*mbc_slave_transport_factory_t)( + const mbc_slave_transport_factory_args_t *args, mb_trans_base_t **transport); + +/** + * @brief Initialize a serial Modbus slave controller with a caller-provided RTU transport. + * + * Passing a factory bypasses the stock serial port and RTU transport creation. + * The supplied factory is used only for `MB_RTU`; ASCII uses the stock transport. + * + * @param[in] config Pointer to the slave communication configuration. + * @param[in] factory Custom RTU transport factory, or `NULL` for the stock transport. + * @param[in] user_ctx Caller-defined context passed to `factory`. + * @param[out] ctx Initialized controller context. + * + * @return ESP_OK on success; an ESP-IDF error code otherwise. + */ +esp_err_t mbc_slave_create_serial_with_transport( + mb_communication_info_t *config, + mbc_slave_transport_factory_t factory, + void *user_ctx, + void **ctx); + /** * @brief Initialize Modbus Slave controller interface handle * diff --git a/modbus/mb_controller/serial/mbc_serial_master.c b/modbus/mb_controller/serial/mbc_serial_master.c index 2f45afba..d9d98e73 100644 --- a/modbus/mb_controller/serial/mbc_serial_master.c +++ b/modbus/mb_controller/serial/mbc_serial_master.c @@ -597,7 +597,10 @@ static esp_err_t mbc_serial_master_controller_create(void **ctx) } // Initialization of resources for Modbus serial master controller -esp_err_t mbc_serial_master_create(mb_communication_info_t *config, void **ctx) +esp_err_t mbc_serial_master_create_with_transport(mb_communication_info_t *config, + mbc_master_transport_factory_t factory, + void *user_ctx, + void **ctx) { mbm_controller_iface_t *mbm_controller_iface = NULL; MB_RETURN_ON_FALSE((ctx && config), ESP_ERR_INVALID_STATE, TAG, @@ -632,7 +635,7 @@ esp_err_t mbc_serial_master_create(mb_communication_info_t *config, void **ctx) if (pcomm_info->mode == MB_RTU) { #if ( CONFIG_FMB_COMM_MODE_RTU_EN ) - err = mbm_rtu_create(pcomm_info, &inst); + err = mbm_rtu_create_with_transport(config, &inst, factory, user_ctx); #else ESP_LOGE(TAG, "RTU mode is not enabled in the configuration."); ret = ESP_ERR_NOT_SUPPORTED; @@ -675,4 +678,9 @@ esp_err_t mbc_serial_master_create(mb_communication_info_t *config, void **ctx) return ret; } +esp_err_t mbc_serial_master_create(mb_communication_info_t *config, void **ctx) +{ + return mbc_serial_master_create_with_transport(config, NULL, NULL, ctx); +} + #endif diff --git a/modbus/mb_controller/serial/mbc_serial_master.h b/modbus/mb_controller/serial/mbc_serial_master.h index c51ddad9..54fae893 100644 --- a/modbus/mb_controller/serial/mbc_serial_master.h +++ b/modbus/mb_controller/serial/mbc_serial_master.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include "soc/soc.h" // for BITN definitions #include "esp_err.h" // for esp_err_t #include "esp_modbus_common.h" // for common defines +#include "esp_modbus_master.h" // for custom transport factory #include "sdkconfig.h" #ifdef __cplusplus @@ -32,6 +33,11 @@ extern "C" { */ esp_err_t mbc_serial_master_create(mb_communication_info_t *config, void **ctx); +esp_err_t mbc_serial_master_create_with_transport(mb_communication_info_t *config, + mbc_master_transport_factory_t factory, + void *user_ctx, + void **ctx); + #endif #ifdef __cplusplus diff --git a/modbus/mb_controller/serial/mbc_serial_slave.c b/modbus/mb_controller/serial/mbc_serial_slave.c index 5e45cd83..dde65422 100644 --- a/modbus/mb_controller/serial/mbc_serial_slave.c +++ b/modbus/mb_controller/serial/mbc_serial_slave.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 */ @@ -215,7 +215,10 @@ static esp_err_t mbc_serial_slave_controller_create(void **ctx) } // Initialization of Modbus controller -esp_err_t mbc_serial_slave_create(mb_communication_info_t *config, void **ctx) +esp_err_t mbc_serial_slave_create_with_transport(mb_communication_info_t *config, + mbc_slave_transport_factory_t factory, + void *user_ctx, + void **ctx) { mbs_controller_iface_t *mbs_controller_iface = NULL; MB_RETURN_ON_FALSE((ctx && config), ESP_ERR_INVALID_STATE, TAG, @@ -248,7 +251,7 @@ esp_err_t mbc_serial_slave_create(mb_communication_info_t *config, void **ctx) // Initialize Modbus stack using mbcontroller parameters if (pcomm_info->mode == MB_RTU) { #if (CONFIG_FMB_COMM_MODE_RTU_EN) - err = mbs_rtu_create(pcomm_info, &inst); + err = mbs_rtu_create_with_transport(config, &inst, factory, user_ctx); #else ESP_LOGE(TAG, "RTU mode is not enabled in the configuration."); ret = ESP_ERR_NOT_SUPPORTED; @@ -292,4 +295,9 @@ esp_err_t mbc_serial_slave_create(mb_communication_info_t *config, void **ctx) return ret; } +esp_err_t mbc_serial_slave_create(mb_communication_info_t *config, void **ctx) +{ + return mbc_serial_slave_create_with_transport(config, NULL, NULL, ctx); +} + #endif // #if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN) diff --git a/modbus/mb_controller/serial/mbc_serial_slave.h b/modbus/mb_controller/serial/mbc_serial_slave.h index 4a7da709..15c40fa1 100644 --- a/modbus/mb_controller/serial/mbc_serial_slave.h +++ b/modbus/mb_controller/serial/mbc_serial_slave.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ extern "C" { #include // for standard int types definition #include // for NULL and std defines #include "esp_modbus_common.h" // for common defines +#include "esp_modbus_slave.h" // for custom transport factory #include "sdkconfig.h" /* ----------------------- Defines ------------------------------------------*/ @@ -34,6 +35,11 @@ extern "C" { */ esp_err_t mbc_serial_slave_create(mb_communication_info_t *config, void **ctx); +esp_err_t mbc_serial_slave_create_with_transport(mb_communication_info_t *config, + mbc_slave_transport_factory_t factory, + void *user_ctx, + void **ctx); + #endif #ifdef __cplusplus diff --git a/modbus/mb_objects/include/mb_master.h b/modbus/mb_objects/include/mb_master.h index efc01151..2f685084 100644 --- a/modbus/mb_objects/include/mb_master.h +++ b/modbus/mb_objects/include/mb_master.h @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "mb_types.h" +#include "esp_modbus_master.h" #ifdef __cplusplus extern "C" { @@ -57,6 +58,11 @@ mb_err_enum_t mbm_delete_handler(mb_base_t *inst, uint8_t func_code); // The helper function to get count of handlers for master mb_err_enum_t mbm_get_handler_count(mb_base_t *inst, uint16_t *count); +mb_err_enum_t mbm_rtu_create_with_transport(mb_communication_info_t *comm_info, + void **in_out_obj, + mbc_master_transport_factory_t factory, + void *user_ctx); + #ifdef __cplusplus } #endif diff --git a/modbus/mb_objects/include/mb_slave.h b/modbus/mb_objects/include/mb_slave.h index 780f3bad..229d0ab4 100644 --- a/modbus/mb_objects/include/mb_slave.h +++ b/modbus/mb_objects/include/mb_slave.h @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "mb_types.h" +#include "esp_modbus_slave.h" #ifdef __cplusplus extern "C" { @@ -27,6 +28,11 @@ mb_err_enum_t mbs_delete_handler(mb_base_t *inst, uint8_t func_code); // The helper function to get count of handlers for slave mb_err_enum_t mbs_get_handler_count(mb_base_t *inst, uint16_t *count); +mb_err_enum_t mbs_rtu_create_with_transport(mb_communication_info_t *comm_info, + void **in_out_obj, + mbc_slave_transport_factory_t factory, + void *user_ctx); + #ifdef __cplusplus } #endif diff --git a/modbus/mb_objects/mb_master.c b/modbus/mb_objects/mb_master.c index 208bfaac..ee323969 100644 --- a/modbus/mb_objects/mb_master.c +++ b/modbus/mb_objects/mb_master.c @@ -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 */ @@ -183,9 +183,13 @@ static mb_err_enum_t mbm_unregister_handlers(mb_base_t *inst) #if (MB_MASTER_RTU_ENABLED) -mb_err_enum_t mbm_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) +mb_err_enum_t mbm_rtu_create_with_transport(mb_communication_info_t *comm_info, + void **in_out_obj, + mbc_master_transport_factory_t factory, + void *user_ctx) { - MB_RETURN_ON_FALSE((ser_opts && in_out_obj), MB_EINVAL, TAG, "invalid options for the instance."); + MB_RETURN_ON_FALSE((comm_info && in_out_obj), MB_EINVAL, TAG, "invalid options for the instance."); + mb_serial_opts_t *ser_opts = &comm_info->ser_opts; MB_RETURN_ON_FALSE((ser_opts->mode == MB_RTU), MB_EILLSTATE, TAG, "incorrect mode != RTU."); mb_err_enum_t ret = MB_ENOERR; mbm_object_t *mbm_obj = NULL; @@ -215,8 +219,17 @@ mb_err_enum_t mbm_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) int res = asprintf(&mbm_obj->base.descr.parent_name, "mbm_rtu@%p", mbm_obj->base.descr.parent); MB_GOTO_ON_FALSE((res), MB_EILLSTATE, error, TAG, "name alloc fail, err: %d", (int)res); - transp_obj = (mb_trans_base_t *)mbm_obj; - ret = mbm_rtu_transp_create(ser_opts, (void **)&transp_obj); + if (factory) { + const mbc_master_transport_factory_args_t args = { + .comm_info = comm_info, + .parent = *in_out_obj, + .user_ctx = user_ctx, + }; + ret = factory(&args, &transp_obj); + } else { + transp_obj = (mb_trans_base_t *)mbm_obj; + ret = mbm_rtu_transp_create(ser_opts, (void **)&transp_obj); + } MB_GOTO_ON_FALSE((transp_obj && (ret == MB_ENOERR)), MB_EILLSTATE, error, TAG, "transport creation, err: %d", (int)ret); mbm_obj->cur_mode = ser_opts->mode; @@ -235,16 +248,28 @@ mb_err_enum_t mbm_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) error: if (transp_obj) { - mbm_rtu_transp_delete(transp_obj); + (void)transp_obj->frm_delete(transp_obj); + } + if (mbm_obj) { + if (mbm_obj->handler_descriptor.sema) { + (void)mbm_unregister_handlers(&mbm_obj->base); + } + free(mbm_obj->base.descr.parent_name); + CRITICAL_SECTION_CLOSE(mbm_obj->base.lock); + free(mbm_obj); } - (void)mbm_unregister_handlers(&mbm_obj->base); - free(mbm_obj->base.descr.parent_name); - CRITICAL_SECTION_CLOSE(mbm_obj->base.lock); - free(mbm_obj); mb_port_get_inst_counter_dec(); return ret; } +mb_err_enum_t mbm_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) +{ + mb_communication_info_t comm_info = { + .ser_opts = *ser_opts, + }; + return mbm_rtu_create_with_transport(&comm_info, in_out_obj, NULL, NULL); +} + #endif /* MB_MASTER_RTU_ENABLED */ #if (MB_MASTER_ASCII_ENABLED) diff --git a/modbus/mb_objects/mb_slave.c b/modbus/mb_objects/mb_slave.c index dc4f74e2..4d6220b4 100644 --- a/modbus/mb_objects/mb_slave.c +++ b/modbus/mb_objects/mb_slave.c @@ -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 */ @@ -171,9 +171,14 @@ static mb_err_enum_t mbs_unregister_handlers(mb_base_t *inst) #if (MB_SLAVE_RTU_ENABLED) -mb_err_enum_t mbs_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) +mb_err_enum_t mbs_rtu_create_with_transport(mb_communication_info_t *comm_info, + void **in_out_obj, + mbc_slave_transport_factory_t factory, + void *user_ctx) { mb_err_enum_t ret = MB_ENOERR; + MB_RETURN_ON_FALSE(comm_info, MB_EINVAL, TAG, "invalid communication options for the instance."); + mb_serial_opts_t *ser_opts = &comm_info->ser_opts; MB_RETURN_ON_FALSE(ser_opts, MB_EINVAL, TAG, "invalid options for the instance."); MB_RETURN_ON_FALSE((ser_opts->mode == MB_RTU), MB_EILLSTATE, TAG, "incorrect mode != RTU."); mbs_object_t *mbs_obj = NULL; @@ -198,8 +203,17 @@ mb_err_enum_t mbs_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) int res = asprintf(&mbs_obj->base.descr.parent_name, "mbs_rtu@%p", *in_out_obj); MB_GOTO_ON_FALSE((res), MB_EILLSTATE, error, TAG, "name alloc fail, err: %d", (int)res); - transp_obj = (mb_trans_base_t *)mbs_obj; - ret = mbs_rtu_transp_create(ser_opts, (void **)&transp_obj); + if (factory) { + const mbc_slave_transport_factory_args_t args = { + .comm_info = comm_info, + .parent = *in_out_obj, + .user_ctx = user_ctx, + }; + ret = factory(&args, &transp_obj); + } else { + transp_obj = (mb_trans_base_t *)mbs_obj; + ret = mbs_rtu_transp_create(ser_opts, (void **)&transp_obj); + } MB_GOTO_ON_FALSE((transp_obj && (ret == MB_ENOERR)), MB_EILLSTATE, error, TAG, "transport creation, err: %d", (int)ret); ret = mbs_register_default_handlers(&mbs_obj->base); @@ -217,16 +231,28 @@ mb_err_enum_t mbs_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) error: if (transp_obj) { - mbs_rtu_transp_delete(transp_obj); + (void)transp_obj->frm_delete(transp_obj); + } + if (mbs_obj) { + if (mbs_obj->handler_descriptor.sema) { + (void)mbs_unregister_handlers(&mbs_obj->base); + } + free(mbs_obj->base.descr.parent_name); + CRITICAL_SECTION_CLOSE(mbs_obj->base.lock); + free(mbs_obj); } - (void)mbs_unregister_handlers(&mbs_obj->base); - free(mbs_obj->base.descr.parent_name); - CRITICAL_SECTION_CLOSE(mbs_obj->base.lock); - free(mbs_obj); mb_port_get_inst_counter_dec(); return ret; } +mb_err_enum_t mbs_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj) +{ + mb_communication_info_t comm_info = { + .ser_opts = *ser_opts, + }; + return mbs_rtu_create_with_transport(&comm_info, in_out_obj, NULL, NULL); +} + #endif /* MB_SLAVE_RTU_ENABLED */ #if (MB_SLAVE_ASCII_ENABLED)