Add serial configuration support to Gateway Modbus

- Introduced GatewayModbusSerialConfig structure to encapsulate serial communication settings.
- Added clamping functions for integer and size values to ensure valid configuration ranges.
- Updated GatewayModbusConfigFromValue to parse serial configuration from JSON input.
- Implemented transport type checking functions for TCP, RTU, ASCII, and Serial.
- Enhanced GatewayModbusConfigToValue to include serial configuration in output.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-04 14:34:05 +08:00
parent 640e78f688
commit 34d2d9caa0
10 changed files with 1364 additions and 204 deletions
+91 -7
View File
@@ -387,20 +387,104 @@ config GATEWAY_BRIDGE_SUPPORTED
Enables per-channel dali_cpp bridge model provisioning, execution, and protocol adapter state.
config GATEWAY_MODBUS_BRIDGE_SUPPORTED
bool "Modbus TCP bridge is supported"
depends on GATEWAY_BRIDGE_SUPPORTED && GATEWAY_WIFI_SUPPORTED
bool "Modbus bridge is supported"
depends on GATEWAY_BRIDGE_SUPPORTED
default y
help
Enables the gateway-owned per-channel Modbus TCP server, generated DALI point map,
and provisioned model overrides. Runtime startup still requires persisted bridge
config with Modbus settings.
Enables the gateway-owned per-channel Modbus TCP, RTU, or ASCII server,
generated DALI point map, and provisioned model overrides.
config GATEWAY_START_MODBUS_BRIDGE_ENABLED
bool "Start Modbus TCP bridge at startup"
bool "Start Modbus bridge at startup"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED
default n
help
Starts configured Modbus TCP listeners at boot. Disabled by default so ports are opened only after provisioning or explicit runtime start.
Starts the configured or Kconfig-default Modbus listener at boot. Disabled
by default so ports are opened only after provisioning or explicit runtime start.
choice GATEWAY_MODBUS_DEFAULT_TRANSPORT
prompt "Default Modbus transport"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED
default GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP
help
Selects the default Modbus transport used before runtime bridge config is saved.
config GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP
bool "TCP server"
depends on GATEWAY_WIFI_SUPPORTED
config GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU
bool "RTU server on UART"
config GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII
bool "ASCII server on UART"
endchoice
config GATEWAY_MODBUS_TCP_PORT
int "Default Modbus TCP port"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP
range 1 65535
default 1502
config GATEWAY_MODBUS_UNIT_ID
int "Default Modbus unit id"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED
range 0 247
default 1
help
Unit id used by the default Modbus server. A value of 0 keeps the existing
gateway wildcard behavior for incoming requests.
config GATEWAY_MODBUS_SERIAL_UART_PORT
int "Default Modbus serial UART port"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
range 0 2
default 1
config GATEWAY_MODBUS_ALLOW_UART0
bool "Allow Modbus/setup to claim UART0"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
default n
help
UART0 is normally reserved for the ESP-IDF console. Enable only when the
console has been moved away from UART0 or the deployment intentionally
repurposes it.
config GATEWAY_MODBUS_SERIAL_TX_PIN
int "Default Modbus serial TX pin"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
range -1 48
default -1
config GATEWAY_MODBUS_SERIAL_RX_PIN
int "Default Modbus serial RX pin"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
range -1 48
default -1
config GATEWAY_MODBUS_SERIAL_BAUDRATE
int "Default Modbus serial baudrate"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
range 1200 921600
default 9600
config GATEWAY_MODBUS_SERIAL_RESPONSE_TIMEOUT_MS
int "Default Modbus serial response timeout ms"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
range 1 1000
default 20
config GATEWAY_MODBUS_SERIAL_RS485_ENABLED
bool "Enable Modbus RS485 half-duplex mode"
depends on GATEWAY_MODBUS_BRIDGE_SUPPORTED && (GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU || GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
default n
config GATEWAY_MODBUS_SERIAL_RS485_DE_PIN
int "Default Modbus RS485 DE/RTS pin"
depends on GATEWAY_MODBUS_SERIAL_RS485_ENABLED
range -1 48
default -1
config GATEWAY_BACNET_BRIDGE_SUPPORTED
bool "BACnet/IP bridge is supported"
+106 -3
View File
@@ -67,6 +67,38 @@
#define CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_PRIORITY 4
#endif
#ifndef CONFIG_GATEWAY_MODBUS_TCP_PORT
#define CONFIG_GATEWAY_MODBUS_TCP_PORT 1502
#endif
#ifndef CONFIG_GATEWAY_MODBUS_UNIT_ID
#define CONFIG_GATEWAY_MODBUS_UNIT_ID 1
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT
#define CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT 1
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_TX_PIN
#define CONFIG_GATEWAY_MODBUS_SERIAL_TX_PIN -1
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_RX_PIN
#define CONFIG_GATEWAY_MODBUS_SERIAL_RX_PIN -1
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_BAUDRATE
#define CONFIG_GATEWAY_MODBUS_SERIAL_BAUDRATE 9600
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_RESPONSE_TIMEOUT_MS
#define CONFIG_GATEWAY_MODBUS_SERIAL_RESPONSE_TIMEOUT_MS 20
#endif
#ifndef CONFIG_GATEWAY_MODBUS_SERIAL_RS485_DE_PIN
#define CONFIG_GATEWAY_MODBUS_SERIAL_RS485_DE_PIN -1
#endif
#ifndef CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE
#define CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE 8192
#endif
@@ -212,6 +244,25 @@ constexpr gateway::GatewayCachePriorityMode kCachePriorityMode =
gateway::GatewayCachePriorityMode::kOutsideBusFirst;
#endif
#if defined(CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU) || \
defined(CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
constexpr bool kModbusDefaultSerialTransport = true;
#else
constexpr bool kModbusDefaultSerialTransport = false;
#endif
#ifdef CONFIG_GATEWAY_MODBUS_ALLOW_UART0
constexpr bool kModbusAllowUart0 = true;
#else
constexpr bool kModbusAllowUart0 = false;
#endif
#ifdef CONFIG_GATEWAY_MODBUS_SERIAL_RS485_ENABLED
constexpr bool kModbusSerialRs485Enabled = true;
#else
constexpr bool kModbusSerialRs485Enabled = false;
#endif
std::unique_ptr<gateway::DaliDomainService> s_dali_domain;
std::unique_ptr<gateway::GatewayRuntime> s_runtime;
std::unique_ptr<gateway::GatewayCache> s_cache;
@@ -322,6 +373,21 @@ bool ValidateChannelBindings() {
}
}
if (kModbusBridgeSupported && kModbusDefaultSerialTransport) {
const int modbus_uart = CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT;
if (modbus_uart == 0 && !kModbusAllowUart0) {
ESP_LOGE(kTag, "Modbus serial is configured on UART0, but UART0 is reserved for console");
return false;
}
for (int i = 0; i < CONFIG_GATEWAY_CHANNEL_COUNT; ++i) {
if (channels[i].enabled && channels[i].serial_phy && channels[i].uart_port == modbus_uart) {
ESP_LOGE(kTag, "Modbus serial UART%d conflicts with DALI channel %d serial PHY",
modbus_uart, i + 1);
return false;
}
}
}
if (!any_enabled) {
ESP_LOGE(kTag, "no DALI PHY is configured; enable at least one native or serial channel");
return false;
@@ -474,9 +540,8 @@ extern "C" void app_main(void) {
if (kBridgeSupported) {
gateway::GatewayBridgeServiceConfig bridge_config;
bridge_config.bridge_enabled = true;
bridge_config.modbus_enabled = profile.enable_wifi && kModbusBridgeSupported;
bridge_config.modbus_startup_enabled = profile.enable_wifi && kModbusBridgeSupported &&
kModbusBridgeStartupEnabled;
bridge_config.modbus_enabled = kModbusBridgeSupported;
bridge_config.modbus_startup_enabled = kModbusBridgeSupported && kModbusBridgeStartupEnabled;
bridge_config.bacnet_enabled = profile.enable_wifi && kBacnetBridgeSupported;
bridge_config.bacnet_startup_enabled = profile.enable_wifi && kBacnetBridgeSupported &&
kBacnetBridgeStartupEnabled;
@@ -487,6 +552,44 @@ extern "C" void app_main(void) {
static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE);
bridge_config.modbus_task_priority =
static_cast<UBaseType_t>(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_PRIORITY);
bridge_config.allow_modbus_uart0 = kModbusAllowUart0;
if (!kModbusAllowUart0) {
bridge_config.reserved_uart_ports.push_back(0);
}
#if CONFIG_GATEWAY_CHANNEL1_PHY_UART1
bridge_config.reserved_uart_ports.push_back(1);
#elif CONFIG_GATEWAY_CHANNEL1_PHY_UART2
bridge_config.reserved_uart_ports.push_back(2);
#endif
#if CONFIG_GATEWAY_CHANNEL_COUNT >= 2
#if CONFIG_GATEWAY_CHANNEL2_PHY_UART1
bridge_config.reserved_uart_ports.push_back(1);
#elif CONFIG_GATEWAY_CHANNEL2_PHY_UART2
bridge_config.reserved_uart_ports.push_back(2);
#endif
#endif
if (kModbusBridgeSupported) {
gateway::GatewayModbusConfig default_modbus;
#if defined(CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU)
default_modbus.transport = "rtu-server";
#elif defined(CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII)
default_modbus.transport = "ascii-server";
#else
default_modbus.transport = "tcp-server";
#endif
default_modbus.port = static_cast<uint16_t>(CONFIG_GATEWAY_MODBUS_TCP_PORT);
default_modbus.unit_id = static_cast<uint8_t>(CONFIG_GATEWAY_MODBUS_UNIT_ID);
default_modbus.serial.uart_port = CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT;
default_modbus.serial.tx_pin = CONFIG_GATEWAY_MODBUS_SERIAL_TX_PIN;
default_modbus.serial.rx_pin = CONFIG_GATEWAY_MODBUS_SERIAL_RX_PIN;
default_modbus.serial.baudrate =
static_cast<uint32_t>(CONFIG_GATEWAY_MODBUS_SERIAL_BAUDRATE);
default_modbus.serial.response_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_MODBUS_SERIAL_RESPONSE_TIMEOUT_MS);
default_modbus.serial.rs485.enabled = kModbusSerialRs485Enabled;
default_modbus.serial.rs485.de_pin = CONFIG_GATEWAY_MODBUS_SERIAL_RS485_DE_PIN;
bridge_config.default_modbus_config = default_modbus;
}
bridge_config.bacnet_task_stack_size =
static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE);
bridge_config.bacnet_task_priority =
+5
View File
@@ -647,6 +647,11 @@ CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC=60
CONFIG_GATEWAY_BRIDGE_SUPPORTED=y
CONFIG_GATEWAY_MODBUS_BRIDGE_SUPPORTED=y
# CONFIG_GATEWAY_START_MODBUS_BRIDGE_ENABLED is not set
CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP=y
# CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU is not set
# CONFIG_GATEWAY_MODBUS_DEFAULT_TRANSPORT_ASCII is not set
CONFIG_GATEWAY_MODBUS_TCP_PORT=1502
CONFIG_GATEWAY_MODBUS_UNIT_ID=1
CONFIG_GATEWAY_BACNET_BRIDGE_SUPPORTED=y
# CONFIG_GATEWAY_START_BACNET_BRIDGE_ENABLED is not set
CONFIG_GATEWAY_CLOUD_BRIDGE_SUPPORTED=y