feat(gateway): Update SDK configuration and add 485 control bridge

- Changed flash size configuration from 16MB to 4MB and updated partition table filename.
- Introduced two gateway channels with UART configurations for communication.
- Added support for gateway cache and startup services including BLE and Wi-Fi.
- Enabled SPI RAM and configured its parameters for better memory management.
- Enhanced the gateway bridge service to handle generated Modbus points more efficiently.
- Refactored the gateway Modbus component to improve point management and added new methods for point description and generation.
- Implemented a new Gateway485ControlBridge for handling 485 control communication with UART.
- Added necessary files for the 485 control bridge including configuration and implementation.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-06 00:39:58 +08:00
parent 34d2d9caa0
commit 029785ff1d
13 changed files with 925 additions and 181 deletions
+2 -1
View File
@@ -18,11 +18,12 @@ This folder hosts the native ESP-IDF C++ rewrite of the Lua DALI gateway.
- `gateway_controller/`: Lua-compatible gateway command dispatcher, internal scene/group state, and notification fan-out.
- `gateway_network/`: HTTP `/info`, `/dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP port `2020` command/notify routing, Wi-Fi STA lifecycle, ESP-Touch smartconfig, setup AP mode, ESP-NOW setup ingress, and BOOT-button Wi-Fi reset for the native gateway.
- `gateway_runtime/`: persistent runtime state, command queueing, and device info services.
- `gateway_485_control/`: optional 485 Lua control bridge for framed `0x28 0x01` commands and `0x22 ... checksum` notifications at `9600 8N1`; disabled by default because UART0 must be moved off the ESP-IDF console first.
- `gateway_usb_setup/`: optional USB Serial/JTAG setup bridge; disabled by default so USB remains available for debug at boot.
## Current status
The native rewrite now wires a shared `gateway_core` bootstrap component, a multi-channel `dali_domain` wrapper over `dali_cpp`, a local vendored `dali` hardware backend from the LuatOS ESP-IDF port with raw receive fan-out, an initial `gateway_runtime` service that provides persistent settings, device info, Lua-compatible command framing helpers, and Lua-style query command deduplication, plus a `gateway_controller` service that starts the gateway command task, dispatches core Lua gateway opcodes, and owns internal scene/group state. The gateway app also includes a `gateway_ble` NimBLE bridge that advertises a Lua-compatible GATT service and forwards `FFF3` framed notifications, incoming `FFF1`/`FFF2`/`FFF3` writes, and native raw DALI frame notifications into the matching raw channel, and a `gateway_network` service that provides the native HTTP `/info`, `GET`/`POST /dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP control-plane router on port `2020`, Wi-Fi STA lifecycle, ESP-Touch smartconfig credential provisioning, the Lua-style `LAMMIN_Gateway` setup AP on `192.168.3.1`, ESP-NOW setup ingress for Lua-compatible `connReq`/`connAck`/`echo`/`cmd`/`data`/`uart` packets, native raw DALI frame forwarding back to connected setup peers, and BOOT-button Wi-Fi credential clearing. Startup behavior is configured in `main/Kconfig.projbuild`: BLE is enabled by default, Wi-Fi STA, smartconfig, and ESP-NOW setup mode are disabled by default, and the built-in USB Serial/JTAG interface stays in debug mode unless the optional USB setup bridge mode is selected. Runtime settings and internal scene/group data are cached in RAM after load, skip unchanged flash writes, and batch Wi-Fi credential commits to reduce flash stalls on ESP32-S3 boards where flash and PSRAM share the SPI bus. The gateway app exposes per-channel PHY selection through `main/Kconfig.projbuild`; each channel can be disabled, bound to the native DALI GPIO HAL, or bound to a UART1/UART2 serial PHY. The checked-in `sdkconfig` is aligned with the app's custom 16 MB partition table so the Wi-Fi/BLE/network-enabled image fits the OTA app slots.
The native rewrite now wires a shared `gateway_core` bootstrap component, a multi-channel `dali_domain` wrapper over `dali_cpp`, a local vendored `dali` hardware backend from the LuatOS ESP-IDF port with raw receive fan-out, an initial `gateway_runtime` service that provides persistent settings, device info, Lua-compatible command framing helpers, and Lua-style query command deduplication, plus a `gateway_controller` service that starts the gateway command task, dispatches core Lua gateway opcodes, and owns internal scene/group state. The gateway app also includes a `gateway_ble` NimBLE bridge that advertises a Lua-compatible GATT service and forwards `FFF3` framed notifications, incoming `FFF1`/`FFF2`/`FFF3` writes, and native raw DALI frame notifications into the matching raw channel, a `gateway_network` service that provides the native HTTP `/info`, `GET`/`POST /dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP control-plane router on port `2020`, Wi-Fi STA lifecycle, ESP-Touch smartconfig credential provisioning, the Lua-style `LAMMIN_Gateway` setup AP on `192.168.3.1`, ESP-NOW setup ingress for Lua-compatible `connReq`/`connAck`/`echo`/`cmd`/`data`/`uart` packets, native raw DALI frame forwarding back to connected setup peers, and BOOT-button Wi-Fi credential clearing, and an optional `gateway_485_control` bridge that claims UART0 for Lua-compatible framed command ingress plus `0x22` notification egress when the console is moved off UART0. Startup behavior is configured in `main/Kconfig.projbuild`: BLE is enabled by default, Wi-Fi STA, smartconfig, and ESP-NOW setup mode are disabled by default, the built-in USB Serial/JTAG interface stays in debug mode unless the optional USB setup bridge mode is selected, and the UART0 control bridge stays disabled unless the deployment explicitly repurposes UART0 away from the ESP-IDF console. Runtime settings and internal scene/group data are cached in RAM after load, skip unchanged flash writes, and batch Wi-Fi credential commits to reduce flash stalls on ESP32-S3 boards where flash and PSRAM share the SPI bus. The gateway app exposes per-channel PHY selection through `main/Kconfig.projbuild`; each channel can be disabled, bound to the native DALI GPIO HAL, or bound to a UART1/UART2 serial PHY. The checked-in `sdkconfig` is aligned with the app's custom 16 MB partition table so the Wi-Fi/BLE/network-enabled image fits the OTA app slots.
## Modbus
+1 -1
View File
@@ -1,6 +1,6 @@
idf_component_register(
SRCS "app_main.cpp"
REQUIRES gateway_core gateway_controller gateway_network gateway_bridge gateway_cache dali_domain gateway_runtime gateway_ble gateway_usb_setup log
REQUIRES gateway_core gateway_controller gateway_network gateway_bridge gateway_cache dali_domain gateway_runtime gateway_ble gateway_usb_setup gateway_485_control log
)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
+66
View File
@@ -579,6 +579,72 @@ config GATEWAY_USB_SETUP_READ_TIMEOUT_MS
range 1 1000
default 20
config GATEWAY_485_CONTROL_ENABLED
bool "Enable UART0 Lua control bridge"
default n
help
Claims UART0 for the Lua-compatible framed gateway control channel at boot.
This requires moving the ESP-IDF console away from UART0 and prevents Modbus
serial from using UART0 at runtime.
config GATEWAY_485_CONTROL_BAUDRATE
int "UART0 control baudrate"
depends on GATEWAY_485_CONTROL_ENABLED
range 1200 921600
default 9600
config GATEWAY_485_CONTROL_TX_PIN
int "UART0 control TX pin"
depends on GATEWAY_485_CONTROL_ENABLED
range -1 48
default -1
help
Leave at -1 to keep the current UART0 TX routing.
config GATEWAY_485_CONTROL_RX_PIN
int "UART0 control RX pin"
depends on GATEWAY_485_CONTROL_ENABLED
range -1 48
default -1
help
Leave at -1 to keep the current UART0 RX routing.
config GATEWAY_485_CONTROL_RX_BUFFER
int "UART0 control RX buffer bytes"
depends on GATEWAY_485_CONTROL_ENABLED
range 64 4096
default 256
config GATEWAY_485_CONTROL_TX_BUFFER
int "UART0 control TX buffer bytes"
depends on GATEWAY_485_CONTROL_ENABLED
range 64 4096
default 256
config GATEWAY_485_CONTROL_READ_TIMEOUT_MS
int "UART0 control read timeout ms"
depends on GATEWAY_485_CONTROL_ENABLED
range 1 1000
default 20
config GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS
int "UART0 control write timeout ms"
depends on GATEWAY_485_CONTROL_ENABLED
range 1 1000
default 20
config GATEWAY_485_CONTROL_TASK_STACK_SIZE
int "UART0 control task stack bytes"
depends on GATEWAY_485_CONTROL_ENABLED
range 2048 16384
default 4096
config GATEWAY_485_CONTROL_TASK_PRIORITY
int "UART0 control task priority"
depends on GATEWAY_485_CONTROL_ENABLED
range 1 10
default 4
endmenu
menu "Gateway Network Services"
+95 -14
View File
@@ -6,6 +6,7 @@
#include "gateway_core.hpp"
#include "gateway_network.hpp"
#include "gateway_runtime.hpp"
#include "gateway_485_control.hpp"
#include "gateway_usb_setup.hpp"
#include "esp_log.h"
@@ -55,6 +56,42 @@
#define CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS 20
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_BAUDRATE
#define CONFIG_GATEWAY_485_CONTROL_BAUDRATE 9600
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_TX_PIN
#define CONFIG_GATEWAY_485_CONTROL_TX_PIN -1
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_RX_PIN
#define CONFIG_GATEWAY_485_CONTROL_RX_PIN -1
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_RX_BUFFER
#define CONFIG_GATEWAY_485_CONTROL_RX_BUFFER 256
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_TX_BUFFER
#define CONFIG_GATEWAY_485_CONTROL_TX_BUFFER 256
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS
#define CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS 20
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS
#define CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS 20
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE
#define CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE 4096
#endif
#ifndef CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY
#define CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY 4
#endif
#ifndef CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC
#define CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC 60
#endif
@@ -257,6 +294,20 @@ constexpr bool kModbusAllowUart0 = true;
constexpr bool kModbusAllowUart0 = false;
#endif
#ifdef CONFIG_GATEWAY_485_CONTROL_ENABLED
constexpr bool k485ControlEnabled = true;
#else
constexpr bool k485ControlEnabled = false;
#endif
#if defined(CONFIG_ESP_CONSOLE_UART) && defined(CONFIG_ESP_CONSOLE_UART_NUM) && CONFIG_ESP_CONSOLE_UART_NUM == 0
constexpr bool kConsoleOnUart0 = true;
#elif defined(CONFIG_CONSOLE_UART) && defined(CONFIG_CONSOLE_UART_NUM) && CONFIG_CONSOLE_UART_NUM == 0
constexpr bool kConsoleOnUart0 = true;
#else
constexpr bool kConsoleOnUart0 = false;
#endif
#ifdef CONFIG_GATEWAY_MODBUS_SERIAL_RS485_ENABLED
constexpr bool kModbusSerialRs485Enabled = true;
#else
@@ -270,6 +321,7 @@ std::unique_ptr<gateway::GatewayController> s_controller;
std::unique_ptr<gateway::GatewayBridgeService> s_bridge;
std::unique_ptr<gateway::GatewayNetworkService> s_network;
std::unique_ptr<gateway::GatewayBleBridge> s_ble_bridge;
std::unique_ptr<gateway::Gateway485ControlBridge> s_uart0_control_bridge;
std::unique_ptr<gateway::GatewayUsbSetupBridge> s_usb_setup_bridge;
[[maybe_unused]] void LogBindError(const char* channel_name, esp_err_t err) {
@@ -289,6 +341,11 @@ struct ChannelBindingConfig {
};
bool ValidateChannelBindings() {
if (k485ControlEnabled && kConsoleOnUart0) {
ESP_LOGE(kTag, "485 control bridge requires moving the ESP-IDF console off UART0");
return false;
}
ChannelBindingConfig channels[CONFIG_GATEWAY_CHANNEL_COUNT] = {};
#if CONFIG_GATEWAY_CHANNEL1_PHY_NATIVE
@@ -375,6 +432,10 @@ bool ValidateChannelBindings() {
if (kModbusBridgeSupported && kModbusDefaultSerialTransport) {
const int modbus_uart = CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT;
if (k485ControlEnabled && modbus_uart == 0) {
ESP_LOGE(kTag, "Modbus serial UART0 conflicts with the UART0 control bridge");
return false;
}
if (modbus_uart == 0 && !kModbusAllowUart0) {
ESP_LOGE(kTag, "Modbus serial is configured on UART0, but UART0 is reserved for console");
return false;
@@ -429,10 +490,10 @@ esp_err_t BindConfiguredChannels(gateway::DaliDomainService& dali_domain,
channel1.query_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL1_SERIAL_QUERY_TIMEOUT_MS);
channel1.name = runtime.gatewayName(channel1.gateway_id);
esp_err_t err = dali_domain.bindSerialBus(channel1);
LogBindError("channel1 serial DALI", err);
if (err != ESP_OK) {
return err;
esp_err_t err1 = dali_domain.bindSerialBus(channel1);
LogBindError("channel1 serial DALI", err1);
if (err1 != ESP_OK) {
return err1;
}
#endif
@@ -446,10 +507,10 @@ esp_err_t BindConfiguredChannels(gateway::DaliDomainService& dali_domain,
channel2.rx_pin = static_cast<uint8_t>(CONFIG_GATEWAY_CHANNEL2_NATIVE_RX_PIN);
channel2.baudrate = static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL2_NATIVE_BAUDRATE);
channel2.name = runtime.gatewayName(channel2.gateway_id);
esp_err_t err = dali_domain.bindHardwareBus(channel2);
LogBindError("channel2 native DALI", err);
if (err != ESP_OK) {
return err;
esp_err_t err2 = dali_domain.bindHardwareBus(channel2);
LogBindError("channel2 native DALI", err2);
if (err2 != ESP_OK) {
return err2;
}
#elif CONFIG_GATEWAY_CHANNEL2_PHY_UART1 || CONFIG_GATEWAY_CHANNEL2_PHY_UART2
gateway::DaliSerialBusConfig channel2{};
@@ -468,10 +529,10 @@ esp_err_t BindConfiguredChannels(gateway::DaliDomainService& dali_domain,
channel2.query_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL2_SERIAL_QUERY_TIMEOUT_MS);
channel2.name = runtime.gatewayName(channel2.gateway_id);
esp_err_t err = dali_domain.bindSerialBus(channel2);
LogBindError("channel2 serial DALI", err);
if (err != ESP_OK) {
return err;
esp_err_t err2 = dali_domain.bindSerialBus(channel2);
LogBindError("channel2 serial DALI", err2);
if (err2 != ESP_OK) {
return err2;
}
#endif
#endif
@@ -535,6 +596,26 @@ extern "C" void app_main(void) {
s_controller = std::make_unique<gateway::GatewayController>(*s_runtime, *s_dali_domain,
*s_cache,
controller_config);
if (k485ControlEnabled) {
gateway::Gateway485ControlBridgeConfig gateway485_config;
gateway485_config.enabled = true;
gateway485_config.tx_pin = CONFIG_GATEWAY_485_CONTROL_TX_PIN;
gateway485_config.rx_pin = CONFIG_GATEWAY_485_CONTROL_RX_PIN;
gateway485_config.baudrate = static_cast<uint32_t>(CONFIG_GATEWAY_485_CONTROL_BAUDRATE);
gateway485_config.rx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_485_CONTROL_RX_BUFFER);
gateway485_config.tx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_485_CONTROL_TX_BUFFER);
gateway485_config.read_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS);
gateway485_config.write_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS);
gateway485_config.task_stack_size =
static_cast<uint32_t>(CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE);
gateway485_config.task_priority =
static_cast<UBaseType_t>(CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY);
s_uart0_control_bridge = std::make_unique<gateway::Gateway485ControlBridge>(*s_controller,
gateway485_config);
ESP_ERROR_CHECK(s_uart0_control_bridge->start());
}
ESP_ERROR_CHECK(s_controller->start());
if (kBridgeSupported) {
@@ -552,8 +633,8 @@ 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.allow_modbus_uart0 = kModbusAllowUart0 && !k485ControlEnabled;
if (!bridge_config.allow_modbus_uart0) {
bridge_config.reserved_uart_ports.push_back(0);
}
#if CONFIG_GATEWAY_CHANNEL1_PHY_UART1
+6
View File
@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
otadata, data, ota, 0xf000, 0x2000,
phy_init, data, phy, 0x11000, 0x1000,
factory, app, factory, 0x20000, 0x200000,
storage, data, spiffs, 0x220000, 0x180000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x6000
3 otadata data ota 0xf000 0x2000
4 phy_init data phy 0x11000 0x1000
5 factory app factory 0x20000 0x200000
6 storage data spiffs 0x220000 0x180000
+86 -25
View File
@@ -562,13 +562,13 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@@ -587,8 +587,8 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4M-single.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions-4M-single.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
@@ -602,20 +602,32 @@ CONFIG_GATEWAY_CHANNEL_COUNT=2
# Gateway Channel 1
#
CONFIG_GATEWAY_CHANNEL1_GW_ID=3
CONFIG_GATEWAY_CHANNEL1_PHY_DISABLED=y
# CONFIG_GATEWAY_CHANNEL1_PHY_DISABLED is not set
# CONFIG_GATEWAY_CHANNEL1_PHY_NATIVE is not set
# CONFIG_GATEWAY_CHANNEL1_PHY_UART1 is not set
CONFIG_GATEWAY_CHANNEL1_PHY_UART1=y
# CONFIG_GATEWAY_CHANNEL1_PHY_UART2 is not set
CONFIG_GATEWAY_CHANNEL1_SERIAL_TX_PIN=1
CONFIG_GATEWAY_CHANNEL1_SERIAL_RX_PIN=2
CONFIG_GATEWAY_CHANNEL1_SERIAL_BAUDRATE=9600
CONFIG_GATEWAY_CHANNEL1_SERIAL_RX_BUFFER=512
CONFIG_GATEWAY_CHANNEL1_SERIAL_TX_BUFFER=512
CONFIG_GATEWAY_CHANNEL1_SERIAL_QUERY_TIMEOUT_MS=100
# end of Gateway Channel 1
#
# Gateway Channel 2
#
CONFIG_GATEWAY_CHANNEL2_GW_ID=4
CONFIG_GATEWAY_CHANNEL2_PHY_DISABLED=y
# CONFIG_GATEWAY_CHANNEL2_PHY_DISABLED is not set
# CONFIG_GATEWAY_CHANNEL2_PHY_NATIVE is not set
# CONFIG_GATEWAY_CHANNEL2_PHY_UART1 is not set
# CONFIG_GATEWAY_CHANNEL2_PHY_UART2 is not set
CONFIG_GATEWAY_CHANNEL2_PHY_UART2=y
CONFIG_GATEWAY_CHANNEL2_SERIAL_TX_PIN=6
CONFIG_GATEWAY_CHANNEL2_SERIAL_RX_PIN=7
CONFIG_GATEWAY_CHANNEL2_SERIAL_BAUDRATE=9600
CONFIG_GATEWAY_CHANNEL2_SERIAL_RX_BUFFER=512
CONFIG_GATEWAY_CHANNEL2_SERIAL_TX_BUFFER=512
CONFIG_GATEWAY_CHANNEL2_SERIAL_QUERY_TIMEOUT_MS=100
# end of Gateway Channel 2
#
@@ -662,6 +674,16 @@ CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE=8192
CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY=5
CONFIG_GATEWAY_USB_STARTUP_DEBUG_JTAG=y
# CONFIG_GATEWAY_USB_STARTUP_SETUP_SERIAL is not set
CONFIG_GATEWAY_485_CONTROL_ENABLED=y
CONFIG_GATEWAY_485_CONTROL_BAUDRATE=9600
CONFIG_GATEWAY_485_CONTROL_TX_PIN=-1
CONFIG_GATEWAY_485_CONTROL_RX_PIN=-1
CONFIG_GATEWAY_485_CONTROL_RX_BUFFER=256
CONFIG_GATEWAY_485_CONTROL_TX_BUFFER=256
CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS=20
CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS=20
CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE=4096
CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY=4
# end of Gateway Startup Services
#
@@ -722,6 +744,7 @@ CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING=y
#
# CONFIG_APPTRACE_DEST_JTAG is not set
CONFIG_APPTRACE_DEST_NONE=y
# CONFIG_APPTRACE_DEST_UART0 is not set
# CONFIG_APPTRACE_DEST_UART1 is not set
# CONFIG_APPTRACE_DEST_UART2 is not set
# CONFIG_APPTRACE_DEST_USB_CDC is not set
@@ -748,6 +771,7 @@ CONFIG_BT_CONTROLLER_ENABLED=y
# General
#
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL is not set
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
@@ -1500,8 +1524,8 @@ CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4
#
# Sleep Config
#
# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y
CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
@@ -1640,7 +1664,40 @@ CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP=y
#
# ESP PSRAM
#
# CONFIG_SPIRAM is not set
CONFIG_SPIRAM=y
#
# SPI RAM config
#
CONFIG_SPIRAM_MODE_QUAD=y
# CONFIG_SPIRAM_MODE_OCT is not set
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_CLK_IO=30
CONFIG_SPIRAM_CS_IO=26
# CONFIG_SPIRAM_XIP_FROM_PSRAM is not set
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
# CONFIG_SPIRAM_SPEED_120M is not set
CONFIG_SPIRAM_SPEED_80M=y
# CONFIG_SPIRAM_SPEED_40M is not set
CONFIG_SPIRAM_SPEED=80
CONFIG_SPIRAM_BOOT_HW_INIT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
# CONFIG_SPIRAM_USE_MEMMAP is not set
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config
# end of ESP PSRAM
#
@@ -1731,18 +1788,15 @@ CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
CONFIG_ESP_CONSOLE_UART_DEFAULT=y
# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set
# CONFIG_ESP_CONSOLE_USB_CDC is not set
# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
# CONFIG_ESP_CONSOLE_NONE is not set
# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set
CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y
CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y
CONFIG_ESP_CONSOLE_UART=y
CONFIG_ESP_CONSOLE_UART_NUM=0
CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
CONFIG_ESP_CONSOLE_UART_NUM=-1
CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=4
CONFIG_ESP_INT_WDT=y
CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
CONFIG_ESP_INT_WDT_CHECK_CPU1=y
@@ -1895,6 +1949,7 @@ CONFIG_FATFS_CODEPAGE=437
CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
# CONFIG_FATFS_USE_FASTSEEK is not set
CONFIG_FATFS_USE_STRFUNC_NONE=y
# CONFIG_FATFS_USE_STRFUNC_WITHOUT_CRLF_CONV is not set
@@ -1972,6 +2027,7 @@ CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y
#
# Extra
#
CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=y
# end of Extra
CONFIG_FREERTOS_PORT=y
@@ -2256,6 +2312,7 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y
# mbedTLS
#
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
@@ -2412,12 +2469,15 @@ CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y
CONFIG_LIBC_ASSERT_BUFFER_SIZE=200
# end of LibC
CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND=y
#
# NVS
#
# CONFIG_NVS_ENCRYPTION is not set
# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set
# CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM is not set
# end of NVS
#
@@ -2761,6 +2821,7 @@ CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
# CONFIG_BLUEDROID_ENABLED is not set
CONFIG_NIMBLE_ENABLED=y
CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
# CONFIG_NIMBLE_MEM_ALLOC_MODE_EXTERNAL is not set
# CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
CONFIG_NIMBLE_PINNED_TO_CORE=0
CONFIG_NIMBLE_PINNED_TO_CORE_0=y
@@ -2809,7 +2870,6 @@ CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
CONFIG_GDBSTUB_SUPPORT_TASKS=y
CONFIG_GDBSTUB_MAX_TASKS=32
# CONFIG_OTA_ALLOW_HTTP is not set
# CONFIG_ESP_SYSTEM_PD_FLASH is not set
CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000
CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000
CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y
@@ -2845,7 +2905,9 @@ CONFIG_ESP32_PHY_MAX_TX_POWER=20
# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set
CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y
CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y
# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_DEFAULT_PSRAM_CLK_IO=30
CONFIG_DEFAULT_PSRAM_CS_IO=26
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set
@@ -2853,13 +2915,11 @@ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
CONFIG_MAIN_TASK_STACK_SIZE=3584
CONFIG_CONSOLE_UART_DEFAULT=y
# CONFIG_CONSOLE_UART_DEFAULT is not set
# CONFIG_CONSOLE_UART_CUSTOM is not set
# CONFIG_CONSOLE_UART_NONE is not set
# CONFIG_ESP_CONSOLE_UART_NONE is not set
CONFIG_CONSOLE_UART=y
CONFIG_CONSOLE_UART_NUM=0
CONFIG_CONSOLE_UART_BAUDRATE=115200
CONFIG_CONSOLE_UART_NUM=-1
CONFIG_INT_WDT=y
CONFIG_INT_WDT_TIMEOUT_MS=300
CONFIG_INT_WDT_CHECK_CPU1=y
@@ -2912,6 +2972,7 @@ CONFIG_TIMER_TASK_PRIORITY=1
CONFIG_TIMER_TASK_STACK_DEPTH=2048
CONFIG_TIMER_QUEUE_LENGTH=10
# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
# CONFIG_HAL_ASSERTION_SILIENT is not set
# CONFIG_L2_TO_L3_COPY is not set
CONFIG_ESP_GRATUITOUS_ARP=y
+148 -7
View File
@@ -562,13 +562,13 @@ CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@@ -587,8 +587,8 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4M-single.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions-4M-single.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
@@ -596,7 +596,108 @@ CONFIG_PARTITION_TABLE_MD5=y
#
# Gateway App
#
CONFIG_GATEWAY_CHANNEL_COUNT=2
#
# Gateway Channel 1
#
CONFIG_GATEWAY_CHANNEL1_GW_ID=3
# CONFIG_GATEWAY_CHANNEL1_PHY_DISABLED is not set
# CONFIG_GATEWAY_CHANNEL1_PHY_NATIVE is not set
CONFIG_GATEWAY_CHANNEL1_PHY_UART1=y
# CONFIG_GATEWAY_CHANNEL1_PHY_UART2 is not set
CONFIG_GATEWAY_CHANNEL1_SERIAL_TX_PIN=1
CONFIG_GATEWAY_CHANNEL1_SERIAL_RX_PIN=2
CONFIG_GATEWAY_CHANNEL1_SERIAL_BAUDRATE=9600
CONFIG_GATEWAY_CHANNEL1_SERIAL_RX_BUFFER=512
CONFIG_GATEWAY_CHANNEL1_SERIAL_TX_BUFFER=512
CONFIG_GATEWAY_CHANNEL1_SERIAL_QUERY_TIMEOUT_MS=100
# end of Gateway Channel 1
#
# Gateway Channel 2
#
CONFIG_GATEWAY_CHANNEL2_GW_ID=4
# CONFIG_GATEWAY_CHANNEL2_PHY_DISABLED is not set
# CONFIG_GATEWAY_CHANNEL2_PHY_NATIVE is not set
# CONFIG_GATEWAY_CHANNEL2_PHY_UART1 is not set
CONFIG_GATEWAY_CHANNEL2_PHY_UART2=y
CONFIG_GATEWAY_CHANNEL2_SERIAL_TX_PIN=6
CONFIG_GATEWAY_CHANNEL2_SERIAL_RX_PIN=7
CONFIG_GATEWAY_CHANNEL2_SERIAL_BAUDRATE=9600
CONFIG_GATEWAY_CHANNEL2_SERIAL_RX_BUFFER=512
CONFIG_GATEWAY_CHANNEL2_SERIAL_TX_BUFFER=512
CONFIG_GATEWAY_CHANNEL2_SERIAL_QUERY_TIMEOUT_MS=100
# end of Gateway Channel 2
#
# Gateway Cache
#
CONFIG_GATEWAY_CACHE_SUPPORTED=y
CONFIG_GATEWAY_CACHE_START_ENABLED=y
CONFIG_GATEWAY_CACHE_RECONCILIATION_ENABLED=y
# CONFIG_GATEWAY_CACHE_FULL_STATE_MIRROR is not set
CONFIG_GATEWAY_CACHE_FLUSH_INTERVAL_MS=5000
CONFIG_GATEWAY_CACHE_OUTSIDE_BUS_FIRST=y
# CONFIG_GATEWAY_CACHE_LOCAL_GATEWAY_FIRST is not set
# end of Gateway Cache
# CONFIG_GATEWAY_ENABLE_DALI_BUS is not set
#
# Gateway Startup Services
#
CONFIG_GATEWAY_BLE_SUPPORTED=y
CONFIG_GATEWAY_START_BLE_ENABLED=y
CONFIG_GATEWAY_WIFI_SUPPORTED=y
# CONFIG_GATEWAY_START_WIFI_STA_ENABLED is not set
CONFIG_GATEWAY_ESPNOW_SETUP_SUPPORTED=y
CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED=y
# CONFIG_GATEWAY_START_ESPNOW_SETUP_ENABLED is not set
# CONFIG_GATEWAY_START_SMARTCONFIG_ENABLED is not set
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
# CONFIG_GATEWAY_START_CLOUD_BRIDGE_ENABLED is not set
CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE=6144
CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_PRIORITY=4
CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE=8192
CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY=5
CONFIG_GATEWAY_USB_STARTUP_DEBUG_JTAG=y
# CONFIG_GATEWAY_USB_STARTUP_SETUP_SERIAL is not set
CONFIG_GATEWAY_485_CONTROL_ENABLED=y
CONFIG_GATEWAY_485_CONTROL_BAUDRATE=9600
CONFIG_GATEWAY_485_CONTROL_TX_PIN=-1
CONFIG_GATEWAY_485_CONTROL_RX_PIN=-1
CONFIG_GATEWAY_485_CONTROL_RX_BUFFER=256
CONFIG_GATEWAY_485_CONTROL_TX_BUFFER=256
CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS=20
CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS=20
CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE=4096
CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY=4
# end of Gateway Startup Services
#
# Gateway Network Services
#
CONFIG_GATEWAY_NETWORK_HTTP_ENABLED=y
CONFIG_GATEWAY_NETWORK_HTTP_PORT=80
CONFIG_GATEWAY_NETWORK_UDP_ROUTER_ENABLED=y
CONFIG_GATEWAY_NETWORK_UDP_PORT=2020
CONFIG_GATEWAY_STATUS_LED_GPIO=-1
CONFIG_GATEWAY_BOOT_BUTTON_GPIO=0
CONFIG_GATEWAY_BOOT_BUTTON_ACTIVE_LOW=y
CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS=3000
# end of Gateway Network Services
# end of Gateway App
#
@@ -669,6 +770,7 @@ CONFIG_BT_CONTROLLER_ENABLED=y
# General
#
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL is not set
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
@@ -1421,8 +1523,8 @@ CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4
#
# Sleep Config
#
# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y
CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
@@ -1561,7 +1663,40 @@ CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP=y
#
# ESP PSRAM
#
# CONFIG_SPIRAM is not set
CONFIG_SPIRAM=y
#
# SPI RAM config
#
CONFIG_SPIRAM_MODE_QUAD=y
# CONFIG_SPIRAM_MODE_OCT is not set
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_CLK_IO=30
CONFIG_SPIRAM_CS_IO=26
# CONFIG_SPIRAM_XIP_FROM_PSRAM is not set
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
# CONFIG_SPIRAM_SPEED_120M is not set
CONFIG_SPIRAM_SPEED_80M=y
# CONFIG_SPIRAM_SPEED_40M is not set
CONFIG_SPIRAM_SPEED=80
CONFIG_SPIRAM_BOOT_HW_INIT=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
# CONFIG_SPIRAM_USE_MEMMAP is not set
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config
# end of ESP PSRAM
#
@@ -1816,6 +1951,7 @@ CONFIG_FATFS_CODEPAGE=437
CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
# CONFIG_FATFS_USE_FASTSEEK is not set
CONFIG_FATFS_USE_STRFUNC_NONE=y
# CONFIG_FATFS_USE_STRFUNC_WITHOUT_CRLF_CONV is not set
@@ -1893,6 +2029,7 @@ CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y
#
# Extra
#
CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=y
# end of Extra
CONFIG_FREERTOS_PORT=y
@@ -2177,6 +2314,7 @@ CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT=y
# mbedTLS
#
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
@@ -2333,12 +2471,15 @@ CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y
CONFIG_LIBC_ASSERT_BUFFER_SIZE=200
# end of LibC
CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND=y
#
# NVS
#
# CONFIG_NVS_ENCRYPTION is not set
# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set
# CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM is not set
# end of NVS
#
@@ -0,0 +1,7 @@
idf_component_register(
SRCS "src/gateway_485_control.cpp"
INCLUDE_DIRS "include"
REQUIRES esp_driver_uart freertos gateway_controller log
)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
@@ -0,0 +1,47 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
namespace gateway {
class GatewayController;
struct Gateway485ControlBridgeConfig {
bool enabled{false};
int tx_pin{-1};
int rx_pin{-1};
uint32_t baudrate{9600};
size_t rx_buffer_size{256};
size_t tx_buffer_size{256};
uint32_t read_timeout_ms{20};
uint32_t write_timeout_ms{20};
uint32_t task_stack_size{4096};
UBaseType_t task_priority{4};
};
class Gateway485ControlBridge {
public:
Gateway485ControlBridge(GatewayController& controller,
Gateway485ControlBridgeConfig config = {});
esp_err_t start();
private:
static void TaskEntry(void* arg);
void taskLoop();
void handleBytes(const uint8_t* data, size_t len);
void handleGatewayNotification(const std::vector<uint8_t>& frame);
GatewayController& controller_;
Gateway485ControlBridgeConfig config_;
TaskHandle_t task_handle_{nullptr};
bool started_{false};
};
} // namespace gateway
@@ -0,0 +1,134 @@
#include "gateway_485_control.hpp"
#include "gateway_controller.hpp"
#include "driver/uart.h"
#include "esp_log.h"
#include <algorithm>
namespace gateway {
namespace {
constexpr const char* kTag = "gateway_485";
constexpr uart_port_t kControlUart = UART_NUM_0;
constexpr size_t kCommandFrameMinLen = 7;
int EffectivePin(int pin) {
return pin >= 0 ? pin : UART_PIN_NO_CHANGE;
}
} // namespace
Gateway485ControlBridge::Gateway485ControlBridge(GatewayController& controller,
Gateway485ControlBridgeConfig config)
: controller_(controller), config_(config) {}
esp_err_t Gateway485ControlBridge::start() {
if (started_) {
return ESP_OK;
}
if (!config_.enabled) {
ESP_LOGI(kTag, "UART0 control bridge disabled");
return ESP_OK;
}
if (uart_is_driver_installed(kControlUart)) {
ESP_LOGE(kTag, "UART0 driver already installed; move console or other users off UART0");
return ESP_ERR_INVALID_STATE;
}
uart_config_t uart_config{};
uart_config.baud_rate = static_cast<int>(config_.baudrate);
uart_config.data_bits = UART_DATA_8_BITS;
uart_config.parity = UART_PARITY_DISABLE;
uart_config.stop_bits = UART_STOP_BITS_1;
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_DEFAULT;
esp_err_t err = uart_param_config(kControlUart, &uart_config);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to configure UART0: %s", esp_err_to_name(err));
return err;
}
err = uart_set_pin(kControlUart, EffectivePin(config_.tx_pin), EffectivePin(config_.rx_pin),
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to set UART0 pins: %s", esp_err_to_name(err));
return err;
}
err = uart_driver_install(kControlUart, static_cast<int>(config_.rx_buffer_size),
static_cast<int>(config_.tx_buffer_size), 0, nullptr, 0);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to install UART0 driver: %s", esp_err_to_name(err));
return err;
}
controller_.addNotificationSink(
[this](const std::vector<uint8_t>& frame) { handleGatewayNotification(frame); });
const BaseType_t created = xTaskCreate(&Gateway485ControlBridge::TaskEntry,
"gateway_485_ctrl",
static_cast<uint32_t>(config_.task_stack_size), this,
config_.task_priority, &task_handle_);
if (created != pdPASS) {
uart_driver_delete(kControlUart);
task_handle_ = nullptr;
ESP_LOGE(kTag, "failed to create 485 control task");
return ESP_ERR_NO_MEM;
}
started_ = true;
ESP_LOGI(kTag, "485 control bridge started baud=%lu", static_cast<unsigned long>(config_.baudrate));
return ESP_OK;
}
void Gateway485ControlBridge::TaskEntry(void* arg) {
static_cast<Gateway485ControlBridge*>(arg)->taskLoop();
}
void Gateway485ControlBridge::taskLoop() {
std::vector<uint8_t> read_buffer(std::max<size_t>(config_.rx_buffer_size, 64));
std::vector<uint8_t> pending;
pending.reserve(std::max<size_t>(config_.rx_buffer_size, 64));
const TickType_t timeout = pdMS_TO_TICKS(config_.read_timeout_ms);
while (true) {
const int read_len = uart_read_bytes(kControlUart, read_buffer.data(), read_buffer.size(), timeout);
if (read_len > 0) {
pending.insert(pending.end(), read_buffer.begin(), read_buffer.begin() + read_len);
continue;
}
if (!pending.empty()) {
handleBytes(pending.data(), pending.size());
pending.clear();
}
}
}
void Gateway485ControlBridge::handleBytes(const uint8_t* data, size_t len) {
if (data == nullptr || len < kCommandFrameMinLen) {
return;
}
if (data[0] != 0x28 || data[1] != 0x01) {
ESP_LOGD(kTag, "ignored non-gateway UART0 burst len=%u", static_cast<unsigned>(len));
return;
}
controller_.enqueueCommandFrame(std::vector<uint8_t>(data, data + len));
}
void Gateway485ControlBridge::handleGatewayNotification(const std::vector<uint8_t>& frame) {
if (!started_ || frame.empty()) {
return;
}
const int written = uart_write_bytes(kControlUart, frame.data(), frame.size());
if (written < 0 || static_cast<size_t>(written) != frame.size()) {
ESP_LOGW(kTag, "failed to write UART0 notification len=%u", static_cast<unsigned>(frame.size()));
return;
}
if (uart_wait_tx_done(kControlUart, pdMS_TO_TICKS(config_.write_timeout_ms)) != ESP_OK) {
ESP_LOGW(kTag, "timed out flushing UART0 notification len=%u", static_cast<unsigned>(frame.size()));
}
}
} // namespace gateway
@@ -257,9 +257,13 @@ bool SnapshotHasDeviceType(const DaliDomainSnapshot& snapshot, int device_type)
}
std::optional<bool> SnapshotBoolValue(const DaliDomainSnapshot& snapshot,
const std::string& key) {
const auto found = snapshot.bools.find(key);
return found == snapshot.bools.end() ? std::nullopt : std::optional<bool>(found->second);
std::string_view key) {
for (const auto& entry : snapshot.bools) {
if (std::string_view(entry.first) == key) {
return entry.second;
}
}
return std::nullopt;
}
std::optional<int> SnapshotIntValue(const DaliDomainSnapshot& snapshot,
@@ -1258,11 +1262,13 @@ struct GatewayBridgeService::ChannelRuntime {
}
std::optional<DaliDomainSnapshot> diagnosticSnapshotLocked(int short_address,
const std::string& kind) {
std::string_view kind) {
if (!ValidShortAddress(short_address) || kind.empty()) {
return std::nullopt;
}
const std::string key = kind + ":" + std::to_string(short_address);
std::string key(kind.data(), kind.size());
key += ":";
key += std::to_string(short_address);
const TickType_t now = xTaskGetTickCount();
const auto cached = diagnostic_snapshot_cache.find(key);
if (cached != diagnostic_snapshot_cache.end() &&
@@ -1291,8 +1297,8 @@ struct GatewayBridgeService::ChannelRuntime {
return snapshot;
}
std::optional<bool> readSnapshotBoolLocked(int short_address, const std::string& kind,
const std::string& bool_key) {
std::optional<bool> readSnapshotBoolLocked(int short_address, std::string_view kind,
std::string_view bool_key) {
const auto snapshot = diagnosticSnapshotLocked(short_address, kind);
if (!snapshot.has_value()) {
return std::nullopt;
@@ -1629,7 +1635,7 @@ struct GatewayBridgeService::ChannelRuntime {
return point;
}
bool shouldPublishGeneratedBacnetPointLocked(const GatewayModbusPointBinding& point) {
bool shouldPublishGeneratedBacnetPointLocked(const GatewayModbusPoint& point) {
if (!point.generated || point.space != GatewayModbusSpace::kDiscreteInput ||
point.access != GatewayModbusAccess::kReadOnly ||
!ValidShortAddress(point.short_address)) {
@@ -1651,7 +1657,16 @@ struct GatewayBridgeService::ChannelRuntime {
if (modbus == nullptr) {
return bindings;
}
for (const auto& point : modbus->describePoints()) {
std::vector<GatewayModbusPoint> generated_points;
generated_points.reserve(192);
for (const auto& inventory_entry : discovery_inventory) {
if (!ValidShortAddress(inventory_entry.first)) {
continue;
}
generated_points.clear();
modbus->appendGeneratedPointsForShortAddress(
static_cast<uint8_t>(inventory_entry.first), &generated_points);
for (const auto& point : generated_points) {
if (!shouldPublishGeneratedBacnetPointLocked(point)) {
continue;
}
@@ -1660,10 +1675,11 @@ struct GatewayBridgeService::ChannelRuntime {
if (discovery == nullptr || !object_instance.has_value()) {
continue;
}
const auto binding = modbus->describePoint(point);
const bool out_of_service = !discovery->online;
bindings.push_back(GatewayBacnetObjectBinding{channel.gateway_id,
point.id,
point.name,
binding.id,
binding.name,
BridgeObjectType::binaryInput,
object_instance.value(),
"presentValue",
@@ -1673,6 +1689,7 @@ struct GatewayBridgeService::ChannelRuntime {
: kBacnetReliabilityNoFaultDetected,
true});
}
}
return bindings;
}
@@ -2135,7 +2152,16 @@ struct GatewayBridgeService::ChannelRuntime {
cJSON_AddItemToArray(bindings, item);
}
if (modbus != nullptr) {
for (const auto& point : modbus->describePoints()) {
std::vector<GatewayModbusPoint> generated_points;
generated_points.reserve(192);
for (const auto& inventory_entry : discovery_inventory) {
if (!ValidShortAddress(inventory_entry.first)) {
continue;
}
generated_points.clear();
modbus->appendGeneratedPointsForShortAddress(
static_cast<uint8_t>(inventory_entry.first), &generated_points);
for (const auto& point : generated_points) {
if (!shouldPublishGeneratedBacnetPointLocked(point)) {
continue;
}
@@ -2148,25 +2174,26 @@ struct GatewayBridgeService::ChannelRuntime {
if (item == nullptr) {
continue;
}
cJSON_AddStringToObject(item, "model", point.id.c_str());
cJSON_AddStringToObject(item, "name", point.name.c_str());
const auto binding = modbus->describePoint(point);
cJSON_AddStringToObject(item, "model", binding.id.c_str());
cJSON_AddStringToObject(item, "name", binding.name.c_str());
cJSON_AddStringToObject(item, "objectType", "binaryInput");
cJSON_AddNumberToObject(item, "objectInstance", object_instance.value());
cJSON_AddStringToObject(item, "property", "presentValue");
cJSON_AddBoolToObject(item, "generated", true);
cJSON_AddStringToObject(item, "generatedKind",
GatewayModbusGeneratedKindToString(point.generated_kind));
cJSON_AddNumberToObject(item, "shortAddress", point.short_address);
if (!point.diagnostic_snapshot.empty()) {
GatewayModbusGeneratedKindToString(binding.generated_kind));
cJSON_AddNumberToObject(item, "shortAddress", binding.short_address);
if (!binding.diagnostic_snapshot.empty()) {
cJSON_AddStringToObject(item, "diagnosticSnapshot",
point.diagnostic_snapshot.c_str());
binding.diagnostic_snapshot.c_str());
}
if (!point.diagnostic_bool.empty()) {
cJSON_AddStringToObject(item, "diagnosticBool", point.diagnostic_bool.c_str());
if (!binding.diagnostic_bool.empty()) {
cJSON_AddStringToObject(item, "diagnosticBool", binding.diagnostic_bool.c_str());
}
if (point.diagnostic_device_type >= 0) {
if (binding.diagnostic_device_type >= 0) {
cJSON_AddNumberToObject(item, "diagnosticDeviceType",
point.diagnostic_device_type);
binding.diagnostic_device_type);
}
const bool out_of_service = !discovery->online;
cJSON_AddBoolToObject(item, "outOfService", out_of_service);
@@ -2174,11 +2201,13 @@ struct GatewayBridgeService::ChannelRuntime {
BacnetReliabilityToString(out_of_service
? kBacnetReliabilityCommunicationFailure
: kBacnetReliabilityNoFaultDetected));
cJSON_AddStringToObject(item, "inventoryState", DiscoveryStateString(discovery->online));
cJSON_AddStringToObject(item, "inventoryState",
DiscoveryStateString(discovery->online));
cJSON_AddItemToArray(bindings, item);
}
}
}
}
#endif
cJSON_AddItemToObject(root, "bindings", bindings);
cJSON* server_json = cJSON_CreateObject();
@@ -119,12 +119,14 @@ struct GatewayModbusPoint {
std::string name;
bool generated{false};
GatewayModbusGeneratedKind generated_kind{GatewayModbusGeneratedKind::kNone};
const char* generated_suffix{"point"};
const char* generated_name{"point"};
int short_address{-1};
std::string model_id;
BridgeOperation operation{BridgeOperation::unknown};
std::optional<int> bit_index;
std::string diagnostic_snapshot;
std::string diagnostic_bool;
const char* diagnostic_snapshot{""};
const char* diagnostic_bool{""};
int diagnostic_device_type{-1};
};
@@ -165,8 +167,12 @@ class GatewayModbusBridge {
void rebuildMap();
std::optional<GatewayModbusPoint> findPoint(GatewayModbusSpace space,
uint16_t address) const;
GatewayModbusPointBinding describePoint(const GatewayModbusPoint& point) const;
void appendGeneratedPointsForShortAddress(uint8_t short_address,
std::vector<GatewayModbusPoint>* points) const;
std::vector<GatewayModbusPointBinding> describePoints() const;
std::vector<GatewayModbusPointBinding> describeHoldingRegisters() const;
const std::vector<GatewayModbusPoint>& points() const;
DaliBridgeResult readModelPoint(const GatewayModbusPoint& point) const;
DaliBridgeResult writeRegisterPoint(const GatewayModbusPoint& point, uint16_t value) const;
+230 -65
View File
@@ -3,7 +3,6 @@
#include <algorithm>
#include <array>
#include <cstdio>
#include <map>
#include <utility>
namespace gateway {
@@ -283,6 +282,16 @@ constexpr GeneratedDiagnosticBitSpec kGeneratedDiagnosticBitsTail[] = {
{119, 1, "dt1", "controlGearFailure", "dt1_control_gear_failure", "DT1 control gear failure"},
};
constexpr size_t kGeneratedDiagnosticBitCount =
sizeof(kGeneratedDiagnosticBits) / sizeof(kGeneratedDiagnosticBits[0]) +
sizeof(kGeneratedDiagnosticBitsTail) / sizeof(kGeneratedDiagnosticBitsTail[0]);
constexpr size_t kGeneratedPointsPerShort = kGeneratedCoils.size() +
kGeneratedDiscreteInputs.size() +
kGeneratedHoldingRegisters.size() +
kGeneratedInputRegisters.size() +
kGeneratedDiagnosticBitCount;
constexpr size_t kGeneratedPointCount = kShortAddressCount * kGeneratedPointsPerShort;
uint16_t baseForSpace(GatewayModbusSpace space) {
switch (space) {
case GatewayModbusSpace::kCoil:
@@ -338,62 +347,165 @@ std::string generatedName(uint8_t short_address, const char* name) {
return buffer;
}
void addGeneratedPoint(std::map<PointKey, GatewayModbusPoint>* points, uint8_t short_address,
const GeneratedPointSpec& spec) {
if (points == nullptr) {
return;
const char* literalOrEmpty(const char* value) {
return value == nullptr ? "" : value;
}
PointKey keyForPoint(const GatewayModbusPoint& point) {
return PointKey{point.space, point.address};
}
bool pointLess(const GatewayModbusPoint& lhs, const GatewayModbusPoint& rhs) {
return keyForPoint(lhs) < keyForPoint(rhs);
}
bool pointKeyEqual(const GatewayModbusPoint& lhs, const GatewayModbusPoint& rhs) {
return lhs.space == rhs.space && lhs.address == rhs.address;
}
bool pointKeyEqual(const GatewayModbusPoint& point, const PointKey& key) {
return point.space == key.space && point.address == key.address;
}
std::vector<GatewayModbusPoint>::const_iterator findStoredPoint(
const std::vector<GatewayModbusPoint>& points, PointKey key) {
const auto found = std::lower_bound(
points.begin(), points.end(), key,
[](const GatewayModbusPoint& point, const PointKey& value) {
return keyForPoint(point) < value;
});
if (found == points.end() || !pointKeyEqual(*found, key)) {
return points.end();
}
return found;
}
GatewayModbusPoint makeGeneratedPoint(uint8_t short_address,
const GeneratedPointSpec& spec) {
const uint16_t address = static_cast<uint16_t>(baseForSpace(spec.space) +
short_address * kShortStride + spec.offset);
GatewayModbusPoint point;
point.space = spec.space;
point.access = spec.access;
point.address = address;
point.id = generatedId(short_address, spec.suffix);
point.name = generatedName(short_address, spec.name);
point.generated = true;
point.generated_kind = spec.kind;
point.generated_suffix = spec.suffix == nullptr ? "point" : spec.suffix;
point.generated_name = spec.name == nullptr ? "point" : spec.name;
point.short_address = short_address;
(*points)[PointKey{spec.space, address}] = std::move(point);
return point;
}
void addGeneratedDiagnosticPoint(std::map<PointKey, GatewayModbusPoint>* points,
uint8_t short_address,
GatewayModbusPoint makeGeneratedDiagnosticPoint(uint8_t short_address,
const GeneratedDiagnosticBitSpec& spec) {
if (points == nullptr) {
return;
}
const uint16_t address = static_cast<uint16_t>(kDiagnosticDiscreteInputBase +
short_address * kDiagnosticStride + spec.offset);
GatewayModbusPoint point;
point.space = GatewayModbusSpace::kDiscreteInput;
point.access = GatewayModbusAccess::kReadOnly;
point.address = address;
point.id = generatedId(short_address, spec.suffix);
point.name = generatedName(short_address, spec.name);
point.generated = true;
point.generated_kind = GatewayModbusGeneratedKind::kShortDiagnosticBit;
point.generated_suffix = spec.suffix == nullptr ? "point" : spec.suffix;
point.generated_name = spec.name == nullptr ? "point" : spec.name;
point.short_address = short_address;
point.diagnostic_snapshot = spec.snapshot == nullptr ? "" : spec.snapshot;
point.diagnostic_bool = spec.bool_key == nullptr ? "" : spec.bool_key;
point.diagnostic_snapshot = literalOrEmpty(spec.snapshot);
point.diagnostic_bool = literalOrEmpty(spec.bool_key);
point.diagnostic_device_type = spec.device_type;
(*points)[PointKey{point.space, address}] = std::move(point);
return point;
}
void appendIfNotOverridden(const std::vector<GatewayModbusPoint>& stored_points,
std::vector<GatewayModbusPoint>* points,
GatewayModbusPoint point) {
if (points == nullptr) {
return;
}
if (findStoredPoint(stored_points, keyForPoint(point)) != stored_points.end()) {
return;
}
points->push_back(std::move(point));
}
std::optional<GatewayModbusPoint> generatedPointForAddress(GatewayModbusSpace space,
uint16_t address) {
if (space == GatewayModbusSpace::kDiscreteInput &&
address >= kDiagnosticDiscreteInputBase) {
const uint16_t relative = static_cast<uint16_t>(address - kDiagnosticDiscreteInputBase);
const uint8_t short_address = static_cast<uint8_t>(relative / kDiagnosticStride);
const uint16_t offset = static_cast<uint16_t>(relative % kDiagnosticStride);
if (short_address >= kShortAddressCount) {
return std::nullopt;
}
for (const auto& spec : kGeneratedDiagnosticBits) {
if (spec.offset == offset) {
return makeGeneratedDiagnosticPoint(short_address, spec);
}
}
for (const auto& spec : kGeneratedDiagnosticBitsTail) {
if (spec.offset == offset) {
return makeGeneratedDiagnosticPoint(short_address, spec);
}
}
return std::nullopt;
}
const uint16_t base = baseForSpace(space);
if (address < base) {
return std::nullopt;
}
const uint16_t relative = static_cast<uint16_t>(address - base);
const uint8_t short_address = static_cast<uint8_t>(relative / kShortStride);
const uint16_t offset = static_cast<uint16_t>(relative % kShortStride);
if (short_address >= kShortAddressCount) {
return std::nullopt;
}
const auto find_regular_point = [short_address, offset](const auto& specs)
-> std::optional<GatewayModbusPoint> {
for (const auto& spec : specs) {
if (spec.offset == offset) {
return makeGeneratedPoint(short_address, spec);
}
}
return std::nullopt;
};
switch (space) {
case GatewayModbusSpace::kCoil:
return find_regular_point(kGeneratedCoils);
case GatewayModbusSpace::kDiscreteInput:
return find_regular_point(kGeneratedDiscreteInputs);
case GatewayModbusSpace::kHoldingRegister:
return find_regular_point(kGeneratedHoldingRegisters);
case GatewayModbusSpace::kInputRegister:
return find_regular_point(kGeneratedInputRegisters);
}
return std::nullopt;
}
GatewayModbusPointBinding toBinding(const GatewayModbusPoint& point) {
return GatewayModbusPointBinding{point.model_id,
point.space,
point.address,
point.id,
point.name,
point.generated,
point.generated_kind,
point.short_address,
point.access,
point.bit_index,
point.diagnostic_snapshot,
point.diagnostic_bool,
point.diagnostic_device_type};
GatewayModbusPointBinding binding;
binding.model_id = point.model_id;
binding.space = point.space;
binding.address = point.address;
if (point.generated) {
const auto short_address = static_cast<uint8_t>(point.short_address < 0 ? 0 : point.short_address);
binding.id = generatedId(short_address, point.generated_suffix);
binding.name = generatedName(short_address, point.generated_name);
} else {
binding.id = point.id;
binding.name = point.name;
}
binding.generated = point.generated;
binding.generated_kind = point.generated_kind;
binding.short_address = point.short_address;
binding.access = point.access;
binding.bit_index = point.bit_index;
binding.diagnostic_snapshot = literalOrEmpty(point.diagnostic_snapshot);
binding.diagnostic_bool = literalOrEmpty(point.diagnostic_bool);
binding.diagnostic_device_type = point.diagnostic_device_type;
return binding;
}
int clampedInt(const DaliValue::Object& json, const std::string& key, int fallback,
@@ -657,29 +769,11 @@ void GatewayModbusBridge::setConfig(const GatewayModbusConfig& config) { config_
const GatewayModbusConfig& GatewayModbusBridge::config() const { return config_; }
void GatewayModbusBridge::rebuildMap() {
std::map<PointKey, GatewayModbusPoint> next;
for (uint8_t short_address = 0; short_address < kShortAddressCount; ++short_address) {
for (const auto& spec : kGeneratedCoils) {
addGeneratedPoint(&next, short_address, spec);
}
for (const auto& spec : kGeneratedDiscreteInputs) {
addGeneratedPoint(&next, short_address, spec);
}
for (const auto& spec : kGeneratedHoldingRegisters) {
addGeneratedPoint(&next, short_address, spec);
}
for (const auto& spec : kGeneratedInputRegisters) {
addGeneratedPoint(&next, short_address, spec);
}
for (const auto& spec : kGeneratedDiagnosticBits) {
addGeneratedDiagnosticPoint(&next, short_address, spec);
}
for (const auto& spec : kGeneratedDiagnosticBitsTail) {
addGeneratedDiagnosticPoint(&next, short_address, spec);
}
}
auto models = engine_.listModels();
points_.clear();
points_.reserve(models.size());
for (const auto& model : engine_.listModels()) {
for (const auto& model : models) {
if (model.protocol != BridgeProtocolKind::modbus || !model.external.registerAddress.has_value()) {
continue;
}
@@ -701,46 +795,117 @@ void GatewayModbusBridge::rebuildMap() {
if (model.dali.kind == BridgeDaliTargetKind::shortAddress && model.dali.shortAddress.has_value()) {
point.short_address = model.dali.shortAddress.value();
}
next[PointKey{point.space, point.address}] = std::move(point);
points_.push_back(std::move(point));
}
points_.clear();
points_.reserve(next.size());
for (auto& entry : next) {
points_.push_back(std::move(entry.second));
std::stable_sort(points_.begin(), points_.end(), pointLess);
auto write = points_.begin();
for (auto read = points_.begin(); read != points_.end();) {
auto next = read + 1;
while (next != points_.end() && pointKeyEqual(*read, *next)) {
++next;
}
if (write != next - 1) {
*write = std::move(*(next - 1));
}
++write;
read = next;
}
points_.erase(write, points_.end());
}
std::optional<GatewayModbusPoint> GatewayModbusBridge::findPoint(GatewayModbusSpace space,
uint16_t address) const {
const auto found = std::find_if(points_.begin(), points_.end(), [space, address](const auto& point) {
return point.space == space && point.address == address;
});
if (found == points_.end()) {
return std::nullopt;
}
const PointKey key{space, address};
const auto found = findStoredPoint(points_, key);
if (found != points_.end()) {
return *found;
}
return generatedPointForAddress(space, address);
}
GatewayModbusPointBinding GatewayModbusBridge::describePoint(
const GatewayModbusPoint& point) const {
return toBinding(point);
}
void GatewayModbusBridge::appendGeneratedPointsForShortAddress(
uint8_t short_address, std::vector<GatewayModbusPoint>* points) const {
if (points == nullptr || short_address >= kShortAddressCount) {
return;
}
for (const auto& spec : kGeneratedCoils) {
appendIfNotOverridden(points_, points, makeGeneratedPoint(short_address, spec));
}
for (const auto& spec : kGeneratedDiscreteInputs) {
appendIfNotOverridden(points_, points, makeGeneratedPoint(short_address, spec));
}
for (const auto& spec : kGeneratedHoldingRegisters) {
appendIfNotOverridden(points_, points, makeGeneratedPoint(short_address, spec));
}
for (const auto& spec : kGeneratedInputRegisters) {
appendIfNotOverridden(points_, points, makeGeneratedPoint(short_address, spec));
}
for (const auto& spec : kGeneratedDiagnosticBits) {
appendIfNotOverridden(points_, points, makeGeneratedDiagnosticPoint(short_address, spec));
}
for (const auto& spec : kGeneratedDiagnosticBitsTail) {
appendIfNotOverridden(points_, points, makeGeneratedDiagnosticPoint(short_address, spec));
}
}
std::vector<GatewayModbusPointBinding> GatewayModbusBridge::describePoints() const {
std::vector<GatewayModbusPointBinding> bindings;
bindings.reserve(points_.size());
bindings.reserve(kGeneratedPointCount + points_.size());
std::vector<GatewayModbusPoint> generated_points;
generated_points.reserve(kGeneratedPointsPerShort);
for (uint8_t short_address = 0; short_address < kShortAddressCount; ++short_address) {
generated_points.clear();
appendGeneratedPointsForShortAddress(short_address, &generated_points);
for (const auto& point : generated_points) {
bindings.push_back(toBinding(point));
}
}
for (const auto& point : points_) {
bindings.push_back(toBinding(point));
}
std::sort(bindings.begin(), bindings.end(), [](const auto& lhs, const auto& rhs) {
if (lhs.space != rhs.space) {
return static_cast<uint8_t>(lhs.space) < static_cast<uint8_t>(rhs.space);
}
return lhs.address < rhs.address;
});
return bindings;
}
std::vector<GatewayModbusPointBinding> GatewayModbusBridge::describeHoldingRegisters() const {
std::vector<GatewayModbusPointBinding> bindings;
std::vector<GatewayModbusPoint> generated_points;
generated_points.reserve(kGeneratedPointsPerShort);
for (uint8_t short_address = 0; short_address < kShortAddressCount; ++short_address) {
generated_points.clear();
appendGeneratedPointsForShortAddress(short_address, &generated_points);
for (const auto& point : generated_points) {
if (point.space == GatewayModbusSpace::kHoldingRegister) {
bindings.push_back(toBinding(point));
}
}
}
for (const auto& point : points_) {
if (point.space == GatewayModbusSpace::kHoldingRegister) {
bindings.push_back(toBinding(point));
}
}
std::sort(bindings.begin(), bindings.end(), [](const auto& lhs, const auto& rhs) {
return lhs.address < rhs.address;
});
return bindings;
}
const std::vector<GatewayModbusPoint>& GatewayModbusBridge::points() const {
return points_;
}
DaliBridgeResult GatewayModbusBridge::readModelPoint(const GatewayModbusPoint& point) const {
return executeModelPoint(point, std::nullopt);
}