#include "dali_domain.hpp" #include "gateway_ble.hpp" #include "gateway_bridge.hpp" #include "gateway_cache.hpp" #include "gateway_controller.hpp" #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" #include "sdkconfig.h" #include #include #include #include #include #ifndef CONFIG_GATEWAY_CHANNEL_COUNT #define CONFIG_GATEWAY_CHANNEL_COUNT 2 #endif #ifndef CONFIG_GATEWAY_NETWORK_HTTP_PORT #define CONFIG_GATEWAY_NETWORK_HTTP_PORT 80 #endif #ifndef CONFIG_GATEWAY_NETWORK_UDP_PORT #define CONFIG_GATEWAY_NETWORK_UDP_PORT 2020 #endif #ifndef CONFIG_GATEWAY_STATUS_LED_GPIO #define CONFIG_GATEWAY_STATUS_LED_GPIO -1 #endif #ifndef CONFIG_GATEWAY_BOOT_BUTTON_GPIO #define CONFIG_GATEWAY_BOOT_BUTTON_GPIO -1 #endif #ifndef CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS #define CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS 3000 #endif #ifndef CONFIG_GATEWAY_SETUP_AP_BUTTON_GPIO #ifdef CONFIG_GATEWAY_BOOT_BUTTON_GPIO #define CONFIG_GATEWAY_SETUP_AP_BUTTON_GPIO CONFIG_GATEWAY_BOOT_BUTTON_GPIO #ifdef CONFIG_GATEWAY_BOOT_BUTTON_ACTIVE_LOW #define CONFIG_GATEWAY_SETUP_AP_BUTTON_ACTIVE_LOW 1 #endif #else #define CONFIG_GATEWAY_SETUP_AP_BUTTON_GPIO -1 #endif #endif #ifndef CONFIG_GATEWAY_BUTTON_TASK_STACK_SIZE #define CONFIG_GATEWAY_BUTTON_TASK_STACK_SIZE 8192 #endif #ifndef CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX #define CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX 0 #endif #ifndef CONFIG_GATEWAY_USB_SETUP_RX_BUFFER #define CONFIG_GATEWAY_USB_SETUP_RX_BUFFER 256 #endif #ifndef CONFIG_GATEWAY_USB_SETUP_TX_BUFFER #define CONFIG_GATEWAY_USB_SETUP_TX_BUFFER 256 #endif #ifndef CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS #define CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS 20 #endif #ifndef CONFIG_DALI_BUS_RESET_PULSE_MS #define CONFIG_DALI_BUS_RESET_PULSE_MS 10 #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_KNX_TP_STARTUP_TIMEOUT_MS #define CONFIG_GATEWAY_KNX_TP_STARTUP_TIMEOUT_MS 2000 #endif #ifndef CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC #define CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC 60 #endif #ifndef CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE #define CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE 0 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST #define CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST 1 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO #define CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO 14 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO #define CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO 13 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO #define CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO 12 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO #define CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO 15 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO #define CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO 4 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS #define CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS 0 #endif #ifndef CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ #define CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ 36 #endif #ifndef CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO #define CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO 5 #endif #ifndef CONFIG_GATEWAY_ETHERNET_PHY_ADDR #define CONFIG_GATEWAY_ETHERNET_PHY_ADDR 1 #endif #ifndef CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE #define CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE 3072 #endif #ifndef CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE #define CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE 12288 #endif #ifndef CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE #define CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE 6144 #endif #ifndef CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_PRIORITY #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 #ifndef CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY #define CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY 5 #endif #ifndef CONFIG_GATEWAY_BRIDGE_KNX_TASK_STACK_SIZE #define CONFIG_GATEWAY_BRIDGE_KNX_TASK_STACK_SIZE 12288 #endif #ifndef CONFIG_GATEWAY_BRIDGE_KNX_TASK_PRIORITY #define CONFIG_GATEWAY_BRIDGE_KNX_TASK_PRIORITY 5 #endif #ifndef CONFIG_GATEWAY_KNX_MAIN_GROUP #define CONFIG_GATEWAY_KNX_MAIN_GROUP 0 #endif #ifndef CONFIG_GATEWAY_KNX_DALI_BUS_ID #define CONFIG_GATEWAY_KNX_DALI_BUS_ID 0 #endif #ifndef CONFIG_GATEWAY_KNX_UDP_PORT #define CONFIG_GATEWAY_KNX_UDP_PORT 3671 #endif #ifndef CONFIG_GATEWAY_KNX_MULTICAST_ADDRESS #define CONFIG_GATEWAY_KNX_MULTICAST_ADDRESS "224.0.23.12" #endif #ifndef CONFIG_GATEWAY_KNX_INDIVIDUAL_ADDRESS #define CONFIG_GATEWAY_KNX_INDIVIDUAL_ADDRESS 65534 #endif #ifndef CONFIG_GATEWAY_KNX_IP_INTERFACE_INDIVIDUAL_ADDRESS #define CONFIG_GATEWAY_KNX_IP_INTERFACE_INDIVIDUAL_ADDRESS 65281 #endif #ifndef CONFIG_GATEWAY_KNX_OAM_ROUTER_INDIVIDUAL_ADDRESS #define CONFIG_GATEWAY_KNX_OAM_ROUTER_INDIVIDUAL_ADDRESS 65282 #endif #ifndef CONFIG_GATEWAY_KNX_OAM_ROUTER_TUNNEL_ADDRESS_BASE #define CONFIG_GATEWAY_KNX_OAM_ROUTER_TUNNEL_ADDRESS_BASE 65296 #endif #ifndef CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_BUTTON_GPIO #define CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_BUTTON_GPIO -1 #endif #ifndef CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_LED_GPIO #define CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_LED_GPIO -1 #endif #ifndef CONFIG_GATEWAY_KNX_PROGRAMMING_BUTTON_GPIO #define CONFIG_GATEWAY_KNX_PROGRAMMING_BUTTON_GPIO -1 #endif #ifndef CONFIG_GATEWAY_KNX_PROGRAMMING_LED_GPIO #define CONFIG_GATEWAY_KNX_PROGRAMMING_LED_GPIO -1 #endif #ifndef CONFIG_GATEWAY_KNX_TP_UART_PORT #define CONFIG_GATEWAY_KNX_TP_UART_PORT -1 #endif #ifndef CONFIG_GATEWAY_KNX_TP_TX_PIN #define CONFIG_GATEWAY_KNX_TP_TX_PIN -1 #endif #ifndef CONFIG_GATEWAY_KNX_TP_RX_PIN #define CONFIG_GATEWAY_KNX_TP_RX_PIN -1 #endif #ifndef CONFIG_GATEWAY_KNX_TP_BAUDRATE #define CONFIG_GATEWAY_KNX_TP_BAUDRATE 19200 #endif #ifndef CONFIG_GATEWAY_CACHE_FLUSH_INTERVAL_MS #define CONFIG_GATEWAY_CACHE_FLUSH_INTERVAL_MS 10000 #endif #ifndef CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS #define CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS 120000 #endif namespace { constexpr const char* kProjectName = "DALI_485_Gateway"; constexpr const char* kProjectVersion = "0.1.0"; constexpr const char* kTag = "gateway_main"; #ifdef CONFIG_GATEWAY_WIFI_SUPPORTED constexpr bool kWifiSupported = true; #else constexpr bool kWifiSupported = false; #endif #ifdef CONFIG_GATEWAY_ETHERNET_SUPPORTED constexpr bool kEthernetSupported = true; #else constexpr bool kEthernetSupported = false; #endif #ifdef CONFIG_GATEWAY_START_WIFI_STA_ENABLED constexpr bool kWifiStartupEnabled = true; #else constexpr bool kWifiStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_START_ETHERNET_ENABLED constexpr bool kEthernetStartupEnabled = true; #else constexpr bool kEthernetStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_BLE_SUPPORTED constexpr bool kBleSupported = true; #else constexpr bool kBleSupported = false; #endif #ifdef CONFIG_GATEWAY_START_BLE_ENABLED constexpr bool kBleStartupEnabled = true; #else constexpr bool kBleStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_ESPNOW_SETUP_SUPPORTED constexpr bool kEspnowSetupSupported = true; #else constexpr bool kEspnowSetupSupported = false; #endif #ifdef CONFIG_GATEWAY_START_ESPNOW_SETUP_ENABLED constexpr bool kEspnowSetupStartupEnabled = true; #else constexpr bool kEspnowSetupStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED constexpr bool kSmartconfigSupported = true; #else constexpr bool kSmartconfigSupported = false; #endif #ifdef CONFIG_GATEWAY_START_SMARTCONFIG_ENABLED constexpr bool kSmartconfigStartupEnabled = true; #else constexpr bool kSmartconfigStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_USB_STARTUP_SETUP_SERIAL constexpr bool kUsbSetupStartupEnabled = true; #else constexpr bool kUsbSetupStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_BRIDGE_SUPPORTED constexpr bool kBridgeSupported = true; #else constexpr bool kBridgeSupported = false; #endif #ifdef CONFIG_GATEWAY_MODBUS_BRIDGE_SUPPORTED constexpr bool kModbusBridgeSupported = true; #else constexpr bool kModbusBridgeSupported = false; #endif #ifdef CONFIG_GATEWAY_START_MODBUS_BRIDGE_ENABLED constexpr bool kModbusBridgeStartupEnabled = true; #else constexpr bool kModbusBridgeStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_BACNET_BRIDGE_SUPPORTED constexpr bool kBacnetBridgeSupported = true; #else constexpr bool kBacnetBridgeSupported = false; #endif #ifdef CONFIG_GATEWAY_START_BACNET_BRIDGE_ENABLED constexpr bool kBacnetBridgeStartupEnabled = true; #else constexpr bool kBacnetBridgeStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_KNX_BRIDGE_SUPPORTED constexpr bool kKnxBridgeSupported = true; #else constexpr bool kKnxBridgeSupported = false; #endif #ifdef CONFIG_GATEWAY_START_KNX_BRIDGE_ENABLED constexpr bool kKnxBridgeStartupEnabled = true; #else constexpr bool kKnxBridgeStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_KNX_TUNNEL_ENABLED constexpr bool kKnxTunnelEnabled = true; #else constexpr bool kKnxTunnelEnabled = false; #endif #ifdef CONFIG_GATEWAY_KNX_MULTICAST_ENABLED constexpr bool kKnxMulticastEnabled = true; #else constexpr bool kKnxMulticastEnabled = false; #endif #ifdef CONFIG_GATEWAY_KNX_OAM_ROUTER_SUPPORTED constexpr bool kKnxOamRouterSupported = true; #else constexpr bool kKnxOamRouterSupported = false; #endif #ifdef CONFIG_GATEWAY_KNX_OAM_ROUTER_ENABLED constexpr bool kKnxOamRouterEnabled = true; #else constexpr bool kKnxOamRouterEnabled = false; #endif #ifdef CONFIG_GATEWAY_CLOUD_BRIDGE_SUPPORTED constexpr bool kCloudBridgeSupported = true; #else constexpr bool kCloudBridgeSupported = false; #endif #ifdef CONFIG_GATEWAY_START_CLOUD_BRIDGE_ENABLED constexpr bool kCloudBridgeStartupEnabled = true; #else constexpr bool kCloudBridgeStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_CACHE_SUPPORTED constexpr bool kCacheSupported = true; #else constexpr bool kCacheSupported = false; #endif #ifdef CONFIG_GATEWAY_CACHE_START_ENABLED constexpr bool kCacheStartupEnabled = true; #else constexpr bool kCacheStartupEnabled = false; #endif #ifdef CONFIG_GATEWAY_CACHE_RECONCILIATION_ENABLED constexpr bool kCacheReconciliationEnabled = true; #else constexpr bool kCacheReconciliationEnabled = false; #endif #ifdef CONFIG_GATEWAY_CACHE_FULL_STATE_MIRROR constexpr bool kCacheFullStateMirrorEnabled = true; #else constexpr bool kCacheFullStateMirrorEnabled = false; #endif #ifdef CONFIG_GATEWAY_CACHE_LOCAL_GATEWAY_FIRST constexpr gateway::GatewayCachePriorityMode kCachePriorityMode = gateway::GatewayCachePriorityMode::kLocalGatewayFirst; #else 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_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 constexpr bool kModbusSerialRs485Enabled = false; #endif std::unique_ptr s_dali_domain; std::unique_ptr s_runtime; std::unique_ptr s_cache; std::unique_ptr s_controller; std::unique_ptr s_bridge; std::unique_ptr s_network; std::unique_ptr s_ble_bridge; std::unique_ptr s_uart0_control_bridge; std::unique_ptr s_usb_setup_bridge; [[maybe_unused]] void LogBindError(const char* channel_name, esp_err_t err) { if (err != ESP_OK) { std::printf("gateway_main: failed to bind %s err=%d\n", channel_name, err); } } struct ChannelBindingConfig { bool enabled{false}; bool native_phy{false}; bool serial_phy{false}; uint8_t channel_index{0}; uint8_t gateway_id{0}; uint8_t native_bus_id{0}; uint32_t native_baudrate{0}; int native_tx_pin{-1}; int native_rx_pin{-1}; int uart_port{-1}; int serial_tx_pin{-1}; int serial_rx_pin{-1}; uint32_t serial_baudrate{0}; size_t serial_rx_buffer_size{0}; size_t serial_tx_buffer_size{0}; uint32_t serial_query_timeout_ms{0}; }; ChannelBindingConfig NativeChannelConfig(uint8_t channel_index, uint8_t gateway_id, uint8_t bus_id, int tx_pin, int rx_pin, uint32_t baudrate) { ChannelBindingConfig channel{}; channel.enabled = true; channel.native_phy = true; channel.channel_index = channel_index; channel.gateway_id = gateway_id; channel.native_bus_id = bus_id; channel.native_tx_pin = tx_pin; channel.native_rx_pin = rx_pin; channel.native_baudrate = baudrate; return channel; } [[maybe_unused]] ChannelBindingConfig SerialChannelConfig(uint8_t channel_index, uint8_t gateway_id, int uart_port, int tx_pin, int rx_pin, uint32_t baudrate, size_t rx_buffer_size, size_t tx_buffer_size, uint32_t query_timeout_ms) { ChannelBindingConfig channel{}; channel.enabled = true; channel.serial_phy = true; channel.channel_index = channel_index; channel.gateway_id = gateway_id; channel.uart_port = uart_port; channel.serial_tx_pin = tx_pin; channel.serial_rx_pin = rx_pin; channel.serial_baudrate = baudrate; channel.serial_rx_buffer_size = rx_buffer_size; channel.serial_tx_buffer_size = tx_buffer_size; channel.serial_query_timeout_ms = query_timeout_ms; return channel; } #define GATEWAY_CONFIGURE_NATIVE_CHANNEL(slot, number) \ channels[slot] = NativeChannelConfig( \ static_cast(slot), static_cast(CONFIG_GATEWAY_CHANNEL##number##_GW_ID), \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_NATIVE_BUS_ID), \ CONFIG_GATEWAY_CHANNEL##number##_NATIVE_TX_PIN, \ CONFIG_GATEWAY_CHANNEL##number##_NATIVE_RX_PIN, \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_NATIVE_BAUDRATE)) #define GATEWAY_CONFIGURE_SERIAL_CHANNEL(slot, number, uart) \ channels[slot] = SerialChannelConfig( \ static_cast(slot), static_cast(CONFIG_GATEWAY_CHANNEL##number##_GW_ID), \ uart, CONFIG_GATEWAY_CHANNEL##number##_SERIAL_TX_PIN, \ CONFIG_GATEWAY_CHANNEL##number##_SERIAL_RX_PIN, \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_BAUDRATE), \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_RX_BUFFER), \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_TX_BUFFER), \ static_cast(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_QUERY_TIMEOUT_MS)) std::array BuildChannelBindings() { std::array channels{}; #if CONFIG_GATEWAY_CHANNEL1_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(0, 1); #elif CONFIG_GATEWAY_CHANNEL1_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(0, 1, 1); #elif CONFIG_GATEWAY_CHANNEL1_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(0, 1, 2); #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 2 #if CONFIG_GATEWAY_CHANNEL2_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(1, 2); #elif CONFIG_GATEWAY_CHANNEL2_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(1, 2, 1); #elif CONFIG_GATEWAY_CHANNEL2_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(1, 2, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 3 #if CONFIG_GATEWAY_CHANNEL3_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(2, 3); #elif CONFIG_GATEWAY_CHANNEL3_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(2, 3, 1); #elif CONFIG_GATEWAY_CHANNEL3_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(2, 3, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 4 #if CONFIG_GATEWAY_CHANNEL4_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(3, 4); #elif CONFIG_GATEWAY_CHANNEL4_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(3, 4, 1); #elif CONFIG_GATEWAY_CHANNEL4_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(3, 4, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 5 #if CONFIG_GATEWAY_CHANNEL5_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(4, 5); #elif CONFIG_GATEWAY_CHANNEL5_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(4, 5, 1); #elif CONFIG_GATEWAY_CHANNEL5_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(4, 5, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 6 #if CONFIG_GATEWAY_CHANNEL6_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(5, 6); #elif CONFIG_GATEWAY_CHANNEL6_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(5, 6, 1); #elif CONFIG_GATEWAY_CHANNEL6_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(5, 6, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 7 #if CONFIG_GATEWAY_CHANNEL7_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(6, 7); #elif CONFIG_GATEWAY_CHANNEL7_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(6, 7, 1); #elif CONFIG_GATEWAY_CHANNEL7_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(6, 7, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 8 #if CONFIG_GATEWAY_CHANNEL8_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(7, 8); #elif CONFIG_GATEWAY_CHANNEL8_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(7, 8, 1); #elif CONFIG_GATEWAY_CHANNEL8_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(7, 8, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 9 #if CONFIG_GATEWAY_CHANNEL9_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(8, 9); #elif CONFIG_GATEWAY_CHANNEL9_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(8, 9, 1); #elif CONFIG_GATEWAY_CHANNEL9_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(8, 9, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 10 #if CONFIG_GATEWAY_CHANNEL10_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(9, 10); #elif CONFIG_GATEWAY_CHANNEL10_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(9, 10, 1); #elif CONFIG_GATEWAY_CHANNEL10_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(9, 10, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 11 #if CONFIG_GATEWAY_CHANNEL11_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(10, 11); #elif CONFIG_GATEWAY_CHANNEL11_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(10, 11, 1); #elif CONFIG_GATEWAY_CHANNEL11_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(10, 11, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 12 #if CONFIG_GATEWAY_CHANNEL12_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(11, 12); #elif CONFIG_GATEWAY_CHANNEL12_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(11, 12, 1); #elif CONFIG_GATEWAY_CHANNEL12_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(11, 12, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 13 #if CONFIG_GATEWAY_CHANNEL13_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(12, 13); #elif CONFIG_GATEWAY_CHANNEL13_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(12, 13, 1); #elif CONFIG_GATEWAY_CHANNEL13_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(12, 13, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 14 #if CONFIG_GATEWAY_CHANNEL14_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(13, 14); #elif CONFIG_GATEWAY_CHANNEL14_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(13, 14, 1); #elif CONFIG_GATEWAY_CHANNEL14_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(13, 14, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 15 #if CONFIG_GATEWAY_CHANNEL15_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(14, 15); #elif CONFIG_GATEWAY_CHANNEL15_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(14, 15, 1); #elif CONFIG_GATEWAY_CHANNEL15_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(14, 15, 2); #endif #endif #if CONFIG_GATEWAY_CHANNEL_COUNT >= 16 #if CONFIG_GATEWAY_CHANNEL16_PHY_NATIVE GATEWAY_CONFIGURE_NATIVE_CHANNEL(15, 16); #elif CONFIG_GATEWAY_CHANNEL16_PHY_UART1 GATEWAY_CONFIGURE_SERIAL_CHANNEL(15, 16, 1); #elif CONFIG_GATEWAY_CHANNEL16_PHY_UART2 GATEWAY_CONFIGURE_SERIAL_CHANNEL(15, 16, 2); #endif #endif return channels; } bool ValidateChannelBindings() { if (k485ControlEnabled && kConsoleOnUart0) { ESP_LOGE(kTag, "485 control bridge requires moving the ESP-IDF console off UART0"); return false; } const auto channels = BuildChannelBindings(); bool any_enabled = false; bool saw_native = false; uint32_t native_baudrate = 0; for (int i = 0; i < CONFIG_GATEWAY_CHANNEL_COUNT; ++i) { if (!channels[i].enabled) { continue; } any_enabled = true; if (channels[i].native_phy && (channels[i].native_tx_pin < 0 || channels[i].native_rx_pin < 0)) { ESP_LOGE(kTag, "native DALI channel %d requires TX and RX GPIO pins", i + 1); return false; } for (int j = i + 1; j < CONFIG_GATEWAY_CHANNEL_COUNT; ++j) { if (!channels[j].enabled) { continue; } if (channels[i].gateway_id == channels[j].gateway_id) { ESP_LOGE(kTag, "duplicate gateway ids configured: %u", channels[i].gateway_id); return false; } if (channels[i].serial_phy && channels[j].serial_phy && channels[i].uart_port == channels[j].uart_port) { ESP_LOGE(kTag, "duplicate serial PHY UART%d configured for multiple channels", channels[i].uart_port); return false; } if (channels[i].native_phy && channels[j].native_phy && channels[i].native_bus_id == channels[j].native_bus_id) { ESP_LOGE(kTag, "duplicate native DALI bus ids configured: %u", channels[i].native_bus_id); return false; } } if (channels[i].native_phy) { if (!saw_native) { saw_native = true; native_baudrate = channels[i].native_baudrate; } else if (native_baudrate != channels[i].native_baudrate) { ESP_LOGE(kTag, "mixed native PHY baudrates are not supported by the shared DALI HAL: %lu vs %lu", static_cast(native_baudrate), static_cast(channels[i].native_baudrate)); return false; } } } 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; } if (modbus_uart == 0 && kConsoleOnUart0) { ESP_LOGE(kTag, "Modbus serial UART0 requires moving the ESP-IDF console off UART0"); 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 (kKnxBridgeSupported) { const int knx_uart = CONFIG_GATEWAY_KNX_TP_UART_PORT; if (kKnxBridgeStartupEnabled) { const uint8_t knx_dali_bus_id = static_cast(CONFIG_GATEWAY_KNX_DALI_BUS_ID); int matches = 0; for (int i = 0; i < CONFIG_GATEWAY_CHANNEL_COUNT; ++i) { if (channels[i].enabled && channels[i].native_phy && channels[i].native_bus_id == knx_dali_bus_id) { ++matches; } } if (matches != 1) { ESP_LOGE(kTag, "KNX DALI bus id %u must match exactly one enabled native DALI channel", knx_dali_bus_id); return false; } } if (knx_uart >= 0 && k485ControlEnabled && knx_uart == 0) { ESP_LOGE(kTag, "KNX TP UART0 conflicts with the UART0 control bridge"); return false; } if (knx_uart >= 0 && knx_uart == 0 && kConsoleOnUart0) { ESP_LOGE(kTag, "KNX TP-UART on UART0 requires moving the ESP-IDF console off UART0"); return false; } if (knx_uart >= 0 && kModbusBridgeSupported && kModbusDefaultSerialTransport && knx_uart == CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT) { ESP_LOGE(kTag, "KNX TP UART%d conflicts with default Modbus serial UART", knx_uart); return false; } for (int i = 0; i < CONFIG_GATEWAY_CHANNEL_COUNT; ++i) { if (knx_uart >= 0 && channels[i].enabled && channels[i].serial_phy && channels[i].uart_port == knx_uart) { ESP_LOGE(kTag, "KNX TP UART%d conflicts with DALI channel %d serial PHY", knx_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; } return true; } esp_err_t BindConfiguredChannels(gateway::DaliDomainService& dali_domain, const gateway::GatewayRuntime& runtime) { std::array used_gateway_ids{}; for (const auto& channel : BuildChannelBindings()) { if (!channel.enabled) { continue; } const uint8_t gateway_id = runtime.gatewayIdForChannel(channel.channel_index, channel.gateway_id); if (used_gateway_ids[gateway_id]) { ESP_LOGE(kTag, "duplicate runtime gateway id configured: %u", gateway_id); return ESP_ERR_INVALID_STATE; } used_gateway_ids[gateway_id] = true; if (channel.native_phy) { gateway::DaliHardwareBusConfig config{}; config.channel_index = channel.channel_index; config.gateway_id = gateway_id; config.bus_id = channel.native_bus_id; config.tx_pin = static_cast(channel.native_tx_pin); config.rx_pin = static_cast(channel.native_rx_pin); config.baudrate = channel.native_baudrate; config.name = runtime.gatewayName(config.gateway_id); const esp_err_t err = dali_domain.bindHardwareBus(config); LogBindError(config.name.c_str(), err); if (err != ESP_OK) { return err; } } else if (channel.serial_phy) { gateway::DaliSerialBusConfig config{}; config.channel_index = channel.channel_index; config.gateway_id = gateway_id; config.uart_port = channel.uart_port; config.tx_pin = channel.serial_tx_pin; config.rx_pin = channel.serial_rx_pin; config.baudrate = channel.serial_baudrate; config.rx_buffer_size = channel.serial_rx_buffer_size; config.tx_buffer_size = channel.serial_tx_buffer_size; config.query_timeout_ms = channel.serial_query_timeout_ms; config.name = runtime.gatewayName(config.gateway_id); const esp_err_t err = dali_domain.bindSerialBus(config); LogBindError(config.name.c_str(), err); if (err != ESP_OK) { return err; } } } return ESP_OK; } } // namespace extern "C" void app_main(void) { ESP_ERROR_CHECK(gateway::InitializeRuntimeNvs()); const gateway::BootProfile profile{ gateway::AppRole::kGateway, "gateway", kWifiSupported, kBleSupported, kEthernetSupported, kEspnowSetupSupported, kUsbSetupStartupEnabled, }; gateway::GatewayCore core(profile); core.start(); ESP_ERROR_CHECK(ValidateChannelBindings() ? ESP_OK : ESP_ERR_INVALID_STATE); s_dali_domain = std::make_unique(); s_runtime = std::make_unique( profile, gateway::GatewayRuntimeConfig{ kProjectName, kProjectVersion, gateway::ReadRuntimeSerialId(), kBleStartupEnabled, kCacheSupported && kCacheStartupEnabled, }, s_dali_domain.get()); ESP_ERROR_CHECK(s_runtime->start()); ESP_ERROR_CHECK(BindConfiguredChannels(*s_dali_domain, *s_runtime)); s_runtime->setGatewayCount(s_dali_domain->channelCount()); gateway::GatewayCacheConfig cache_config; cache_config.cache_enabled = kCacheSupported && kCacheStartupEnabled && s_runtime->cacheEnabled(); cache_config.reconciliation_enabled = cache_config.cache_enabled && kCacheReconciliationEnabled; cache_config.full_state_mirror_enabled = cache_config.reconciliation_enabled && kCacheFullStateMirrorEnabled; cache_config.flush_interval_ms = static_cast(CONFIG_GATEWAY_CACHE_FLUSH_INTERVAL_MS); cache_config.refresh_interval_ms = static_cast(CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS); cache_config.default_priority_mode = kCachePriorityMode; s_cache = std::make_unique(cache_config); ESP_ERROR_CHECK(s_cache->start()); gateway::GatewayControllerConfig controller_config; controller_config.task_stack_size = static_cast(CONFIG_GATEWAY_CONTROLLER_TASK_STACK_SIZE); const bool network_transport_supported = profile.enable_wifi || profile.enable_eth; controller_config.setup_supported = true; controller_config.ble_supported = profile.enable_ble; controller_config.wifi_supported = profile.enable_wifi; controller_config.ip_router_supported = network_transport_supported; controller_config.internal_scene_supported = true; controller_config.internal_group_supported = true; controller_config.cache_supported = kCacheSupported; controller_config.cache_refresh_interval_ms = static_cast(CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS); s_controller = std::make_unique(*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(CONFIG_GATEWAY_485_CONTROL_BAUDRATE); gateway485_config.rx_buffer_size = static_cast(CONFIG_GATEWAY_485_CONTROL_RX_BUFFER); gateway485_config.tx_buffer_size = static_cast(CONFIG_GATEWAY_485_CONTROL_TX_BUFFER); gateway485_config.read_timeout_ms = static_cast(CONFIG_GATEWAY_485_CONTROL_READ_TIMEOUT_MS); gateway485_config.write_timeout_ms = static_cast(CONFIG_GATEWAY_485_CONTROL_WRITE_TIMEOUT_MS); gateway485_config.task_stack_size = static_cast(CONFIG_GATEWAY_485_CONTROL_TASK_STACK_SIZE); gateway485_config.task_priority = static_cast(CONFIG_GATEWAY_485_CONTROL_TASK_PRIORITY); s_uart0_control_bridge = std::make_unique(*s_controller, gateway485_config); ESP_ERROR_CHECK(s_uart0_control_bridge->start()); } ESP_ERROR_CHECK(s_controller->start()); if (kBridgeSupported) { gateway::GatewayBridgeServiceConfig bridge_config; bridge_config.bridge_enabled = true; bridge_config.modbus_enabled = kModbusBridgeSupported; bridge_config.modbus_startup_enabled = kModbusBridgeSupported && kModbusBridgeStartupEnabled; bridge_config.bacnet_enabled = network_transport_supported && kBacnetBridgeSupported; bridge_config.bacnet_startup_enabled = network_transport_supported && kBacnetBridgeSupported && kBacnetBridgeStartupEnabled; bridge_config.knx_enabled = network_transport_supported && kKnxBridgeSupported; bridge_config.knx_startup_enabled = network_transport_supported && kKnxBridgeSupported && kKnxBridgeStartupEnabled; bridge_config.cloud_enabled = network_transport_supported && kCloudBridgeSupported; bridge_config.cloud_startup_enabled = network_transport_supported && kCloudBridgeSupported && kCloudBridgeStartupEnabled; bridge_config.modbus_task_stack_size = static_cast(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE); bridge_config.modbus_task_priority = static_cast(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_PRIORITY); bridge_config.allow_modbus_uart0 = kModbusAllowUart0 && !kConsoleOnUart0 && !k485ControlEnabled; bridge_config.allow_knx_uart0 = !kConsoleOnUart0 && !k485ControlEnabled; for (const auto& channel : BuildChannelBindings()) { if (channel.enabled && channel.serial_phy) { bridge_config.reserved_uart_ports.push_back(channel.uart_port); } } 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(CONFIG_GATEWAY_MODBUS_TCP_PORT); default_modbus.unit_id = static_cast(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(CONFIG_GATEWAY_MODBUS_SERIAL_BAUDRATE); default_modbus.serial.response_timeout_ms = static_cast(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(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE); bridge_config.bacnet_task_priority = static_cast(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_PRIORITY); if (kKnxBridgeSupported) { gateway::GatewayKnxConfig default_knx; default_knx.dali_router_enabled = true; default_knx.ip_router_enabled = true; default_knx.tunnel_enabled = kKnxTunnelEnabled; default_knx.multicast_enabled = kKnxMulticastEnabled; default_knx.main_group = static_cast(CONFIG_GATEWAY_KNX_MAIN_GROUP); default_knx.dali_bus_id = static_cast(CONFIG_GATEWAY_KNX_DALI_BUS_ID); default_knx.udp_port = static_cast(CONFIG_GATEWAY_KNX_UDP_PORT); default_knx.multicast_address = CONFIG_GATEWAY_KNX_MULTICAST_ADDRESS; default_knx.ip_interface_individual_address = static_cast(CONFIG_GATEWAY_KNX_IP_INTERFACE_INDIVIDUAL_ADDRESS); default_knx.individual_address = static_cast(CONFIG_GATEWAY_KNX_INDIVIDUAL_ADDRESS); default_knx.oam_router.enabled = kKnxOamRouterSupported && kKnxOamRouterEnabled; default_knx.oam_router.individual_address = static_cast(CONFIG_GATEWAY_KNX_OAM_ROUTER_INDIVIDUAL_ADDRESS); default_knx.oam_router.tunnel_address_base = static_cast(CONFIG_GATEWAY_KNX_OAM_ROUTER_TUNNEL_ADDRESS_BASE); if (default_knx.oam_router.enabled) { default_knx.ip_interface_individual_address = default_knx.oam_router.individual_address; } default_knx.oam_router.programming_button_gpio = CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_BUTTON_GPIO; default_knx.oam_router.programming_led_gpio = CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_LED_GPIO; #ifdef CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_BUTTON_ACTIVE_LOW default_knx.oam_router.programming_button_active_low = true; #else default_knx.oam_router.programming_button_active_low = false; #endif #ifdef CONFIG_GATEWAY_KNX_OAM_PROGRAMMING_LED_ACTIVE_HIGH default_knx.oam_router.programming_led_active_high = true; #else default_knx.oam_router.programming_led_active_high = false; #endif default_knx.programming_button_gpio = CONFIG_GATEWAY_KNX_PROGRAMMING_BUTTON_GPIO; default_knx.programming_led_gpio = CONFIG_GATEWAY_KNX_PROGRAMMING_LED_GPIO; #ifdef CONFIG_GATEWAY_KNX_PROGRAMMING_BUTTON_ACTIVE_LOW default_knx.programming_button_active_low = true; #else default_knx.programming_button_active_low = false; #endif #ifdef CONFIG_GATEWAY_KNX_PROGRAMMING_LED_ACTIVE_HIGH default_knx.programming_led_active_high = true; #else default_knx.programming_led_active_high = false; #endif default_knx.tp_uart.uart_port = CONFIG_GATEWAY_KNX_TP_UART_PORT; default_knx.tp_uart.tx_pin = CONFIG_GATEWAY_KNX_TP_TX_PIN; default_knx.tp_uart.rx_pin = CONFIG_GATEWAY_KNX_TP_RX_PIN; default_knx.tp_uart.baudrate = static_cast(CONFIG_GATEWAY_KNX_TP_BAUDRATE); default_knx.tp_uart.startup_timeout_ms = static_cast(CONFIG_GATEWAY_KNX_TP_STARTUP_TIMEOUT_MS); #ifdef CONFIG_GATEWAY_KNX_TP_UART_9BIT_MODE default_knx.tp_uart.nine_bit_mode = true; #else default_knx.tp_uart.nine_bit_mode = false; #endif bridge_config.default_knx_config = default_knx; } bridge_config.knx_task_stack_size = static_cast(CONFIG_GATEWAY_BRIDGE_KNX_TASK_STACK_SIZE); bridge_config.knx_task_priority = static_cast(CONFIG_GATEWAY_BRIDGE_KNX_TASK_PRIORITY); bridge_config.gateway_device_name_provider = []() { return s_runtime == nullptr ? std::string() : s_runtime->deviceName(); }; bridge_config.knx_gateway_snapshot_provider = []() { gateway::GatewayKnxGatewaySnapshot out; if (s_controller == nullptr) { return out; } const auto snapshot = s_controller->snapshot(); out.channels.reserve(snapshot.channels.size()); for (const auto& channel : snapshot.channels) { out.channels.push_back( gateway::GatewayKnxGatewayChannelSnapshot{channel.gateway_id}); } return out; }; bridge_config.knx_gateway_command_transactor = [](const std::vector& frame, uint32_t timeout_ms) { gateway::GatewayKnxGatewayTransactionResult out; if (s_controller == nullptr) { return out; } const auto result = s_controller->transactCommandFrame(frame, timeout_ms); switch (result.status) { case gateway::GatewayCommandTransactionStatus::kOk: out.status = gateway::GatewayKnxGatewayTransactionStatus::kOk; break; case gateway::GatewayCommandTransactionStatus::kInvalidFrame: out.status = gateway::GatewayKnxGatewayTransactionStatus::kInvalidFrame; break; case gateway::GatewayCommandTransactionStatus::kQueueRejected: out.status = gateway::GatewayKnxGatewayTransactionStatus::kQueueRejected; break; case gateway::GatewayCommandTransactionStatus::kTimeout: out.status = gateway::GatewayKnxGatewayTransactionStatus::kTimeout; break; case gateway::GatewayCommandTransactionStatus::kNoResponse: out.status = gateway::GatewayKnxGatewayTransactionStatus::kNoResponse; break; } out.frames = result.frames; return out; }; s_bridge = std::make_unique(*s_dali_domain, *s_cache, bridge_config); s_controller->setBridgeService(s_bridge.get()); s_controller->addGatewayNameSink([](uint8_t gateway_id) { if (s_bridge != nullptr) { s_bridge->handleGatewayNameChanged(gateway_id); } }); } if (profile.enable_wifi || profile.enable_eth) { gateway::GatewayNetworkServiceConfig network_config; network_config.wifi_enabled = profile.enable_wifi && kWifiStartupEnabled; network_config.ethernet_enabled = profile.enable_eth && kEthernetStartupEnabled; #if CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE network_config.ethernet_ignore_init_failure = true; #else network_config.ethernet_ignore_init_failure = false; #endif network_config.espnow_setup_enabled = profile.enable_espnow; network_config.espnow_setup_startup_enabled = profile.enable_espnow && kEspnowSetupStartupEnabled; network_config.smartconfig_enabled = profile.enable_wifi && kSmartconfigSupported; network_config.smartconfig_startup_enabled = profile.enable_wifi && kSmartconfigSupported && kSmartconfigStartupEnabled; network_config.smartconfig_timeout_sec = CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC; #ifdef CONFIG_GATEWAY_NETWORK_HTTP_ENABLED network_config.http_enabled = true; #else network_config.http_enabled = false; #endif #ifdef CONFIG_GATEWAY_NETWORK_UDP_ROUTER_ENABLED network_config.udp_enabled = true; #else network_config.udp_enabled = false; #endif network_config.http_port = static_cast(CONFIG_GATEWAY_NETWORK_HTTP_PORT); network_config.udp_port = static_cast(CONFIG_GATEWAY_NETWORK_UDP_PORT); network_config.ethernet_spi_host = CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST; network_config.ethernet_spi_sclk_gpio = CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO; network_config.ethernet_spi_mosi_gpio = CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO; network_config.ethernet_spi_miso_gpio = CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO; network_config.ethernet_spi_cs_gpio = CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO; network_config.ethernet_spi_int_gpio = CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO; network_config.ethernet_poll_period_ms = static_cast(CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS); network_config.ethernet_spi_clock_mhz = static_cast(CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ); network_config.ethernet_phy_reset_gpio = CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO; network_config.ethernet_phy_addr = CONFIG_GATEWAY_ETHERNET_PHY_ADDR; network_config.ethernet_rx_task_stack_size = static_cast(CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE); network_config.status_led_gpio = CONFIG_GATEWAY_STATUS_LED_GPIO; network_config.boot_button_gpio = CONFIG_GATEWAY_BOOT_BUTTON_GPIO; network_config.setup_ap_button_gpio = CONFIG_GATEWAY_SETUP_AP_BUTTON_GPIO; network_config.boot_button_long_press_ms = CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS; network_config.boot_button_task_stack_size = static_cast(CONFIG_GATEWAY_BUTTON_TASK_STACK_SIZE); #ifdef CONFIG_GATEWAY_STATUS_LED_ACTIVE_HIGH network_config.status_led_active_high = true; #else network_config.status_led_active_high = false; #endif #ifdef CONFIG_GATEWAY_BOOT_BUTTON_ACTIVE_LOW network_config.boot_button_active_low = true; #else network_config.boot_button_active_low = false; #endif #ifdef CONFIG_GATEWAY_SETUP_AP_BUTTON_ACTIVE_LOW network_config.setup_ap_button_active_low = true; #else network_config.setup_ap_button_active_low = false; #endif s_network = std::make_unique(*s_controller, *s_runtime, *s_dali_domain, network_config, s_bridge.get()); ESP_ERROR_CHECK(s_network->start()); } if (s_bridge != nullptr) { ESP_ERROR_CHECK(s_bridge->start()); } if (profile.enable_ble) { s_ble_bridge = std::make_unique(*s_controller, *s_runtime, *s_dali_domain); ESP_ERROR_CHECK(s_ble_bridge->start()); } if (profile.enable_usb) { gateway::GatewayUsbSetupBridgeConfig usb_config; usb_config.enabled = true; usb_config.channel_index = static_cast(CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX); usb_config.rx_buffer_size = static_cast(CONFIG_GATEWAY_USB_SETUP_RX_BUFFER); usb_config.tx_buffer_size = static_cast(CONFIG_GATEWAY_USB_SETUP_TX_BUFFER); usb_config.read_timeout_ms = static_cast(CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS); usb_config.reset_pulse_ms = static_cast(CONFIG_DALI_BUS_RESET_PULSE_MS); s_usb_setup_bridge = std::make_unique(*s_controller, *s_dali_domain, usb_config); ESP_ERROR_CHECK(s_usb_setup_bridge->start()); } const auto device_info = s_runtime->deviceInfo(); std::printf("gateway_main: dali domain implementation=%s bound=%d channels=%u\n", s_dali_domain->implementationName(), s_dali_domain->isBound(), static_cast(s_dali_domain->channelCount())); for (const auto& channel : s_dali_domain->channelInfo()) { std::printf("gateway_main: channel=%u gateway=%u name=%s\n", channel.channel_index, channel.gateway_id, channel.name.c_str()); } std::printf("gateway_main: runtime device type=%s serial=%s project=%s version=%s\n", device_info.type.c_str(), device_info.serial_id.c_str(), device_info.project.c_str(), device_info.version.c_str()); }