Files
gateway/apps/gateway/main/app_main.cpp
T
Tony 3fca7161fc fix: update DALI double send delay and increase SPIRAM malloc reserve size
This commit fix the crash risk when bus abnormal.

Signed-off-by: Tony <tonylu@tony-cloud.com>
2026-06-16 06:07:06 +08:00

1310 lines
47 KiB
C++

#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 <array>
#include <cstdio>
#include <cstdint>
#include <memory>
#include <string>
#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<gateway::DaliDomainService> s_dali_domain;
std::unique_ptr<gateway::GatewayRuntime> s_runtime;
std::unique_ptr<gateway::GatewayCache> s_cache;
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) {
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<uint8_t>(slot), static_cast<uint8_t>(CONFIG_GATEWAY_CHANNEL##number##_GW_ID), \
static_cast<uint8_t>(CONFIG_GATEWAY_CHANNEL##number##_NATIVE_BUS_ID), \
CONFIG_GATEWAY_CHANNEL##number##_NATIVE_TX_PIN, \
CONFIG_GATEWAY_CHANNEL##number##_NATIVE_RX_PIN, \
static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL##number##_NATIVE_BAUDRATE))
#define GATEWAY_CONFIGURE_SERIAL_CHANNEL(slot, number, uart) \
channels[slot] = SerialChannelConfig( \
static_cast<uint8_t>(slot), static_cast<uint8_t>(CONFIG_GATEWAY_CHANNEL##number##_GW_ID), \
uart, CONFIG_GATEWAY_CHANNEL##number##_SERIAL_TX_PIN, \
CONFIG_GATEWAY_CHANNEL##number##_SERIAL_RX_PIN, \
static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_BAUDRATE), \
static_cast<size_t>(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_RX_BUFFER), \
static_cast<size_t>(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_TX_BUFFER), \
static_cast<uint32_t>(CONFIG_GATEWAY_CHANNEL##number##_SERIAL_QUERY_TIMEOUT_MS))
std::array<ChannelBindingConfig, CONFIG_GATEWAY_CHANNEL_COUNT> BuildChannelBindings() {
std::array<ChannelBindingConfig, CONFIG_GATEWAY_CHANNEL_COUNT> 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<unsigned long>(native_baudrate),
static_cast<unsigned long>(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<uint8_t>(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<bool, 256> 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<uint8_t>(channel.native_tx_pin);
config.rx_pin = static_cast<uint8_t>(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<gateway::DaliDomainService>();
s_runtime = std::make_unique<gateway::GatewayRuntime>(
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<uint32_t>(CONFIG_GATEWAY_CACHE_FLUSH_INTERVAL_MS);
cache_config.refresh_interval_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS);
cache_config.default_priority_mode = kCachePriorityMode;
s_cache = std::make_unique<gateway::GatewayCache>(cache_config);
ESP_ERROR_CHECK(s_cache->start());
gateway::GatewayControllerConfig controller_config;
controller_config.task_stack_size =
static_cast<uint32_t>(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<uint32_t>(CONFIG_GATEWAY_CACHE_REFRESH_INTERVAL_MS);
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) {
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<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 && !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<uint16_t>(CONFIG_GATEWAY_MODBUS_TCP_PORT);
default_modbus.unit_id = static_cast<uint8_t>(CONFIG_GATEWAY_MODBUS_UNIT_ID);
default_modbus.serial.uart_port = CONFIG_GATEWAY_MODBUS_SERIAL_UART_PORT;
default_modbus.serial.tx_pin = CONFIG_GATEWAY_MODBUS_SERIAL_TX_PIN;
default_modbus.serial.rx_pin = CONFIG_GATEWAY_MODBUS_SERIAL_RX_PIN;
default_modbus.serial.baudrate =
static_cast<uint32_t>(CONFIG_GATEWAY_MODBUS_SERIAL_BAUDRATE);
default_modbus.serial.response_timeout_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_MODBUS_SERIAL_RESPONSE_TIMEOUT_MS);
default_modbus.serial.rs485.enabled = kModbusSerialRs485Enabled;
default_modbus.serial.rs485.de_pin = CONFIG_GATEWAY_MODBUS_SERIAL_RS485_DE_PIN;
bridge_config.default_modbus_config = default_modbus;
}
bridge_config.bacnet_task_stack_size =
static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_BACNET_TASK_STACK_SIZE);
bridge_config.bacnet_task_priority =
static_cast<UBaseType_t>(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<uint8_t>(CONFIG_GATEWAY_KNX_MAIN_GROUP);
default_knx.dali_bus_id = static_cast<uint8_t>(CONFIG_GATEWAY_KNX_DALI_BUS_ID);
default_knx.udp_port = static_cast<uint16_t>(CONFIG_GATEWAY_KNX_UDP_PORT);
default_knx.multicast_address = CONFIG_GATEWAY_KNX_MULTICAST_ADDRESS;
default_knx.ip_interface_individual_address =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_IP_INTERFACE_INDIVIDUAL_ADDRESS);
default_knx.individual_address =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_INDIVIDUAL_ADDRESS);
default_knx.oam_router.enabled = kKnxOamRouterSupported && kKnxOamRouterEnabled;
default_knx.oam_router.individual_address =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OAM_ROUTER_INDIVIDUAL_ADDRESS);
default_knx.oam_router.tunnel_address_base =
static_cast<uint16_t>(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<uint32_t>(CONFIG_GATEWAY_KNX_TP_BAUDRATE);
default_knx.tp_uart.startup_timeout_ms =
static_cast<uint32_t>(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<uint32_t>(CONFIG_GATEWAY_BRIDGE_KNX_TASK_STACK_SIZE);
bridge_config.knx_task_priority =
static_cast<UBaseType_t>(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<uint8_t>& 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<gateway::GatewayBridgeService>(*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<uint16_t>(CONFIG_GATEWAY_NETWORK_HTTP_PORT);
network_config.udp_port = static_cast<uint16_t>(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<uint32_t>(CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS);
network_config.ethernet_spi_clock_mhz =
static_cast<uint8_t>(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<uint32_t>(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<uint32_t>(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<gateway::GatewayNetworkService>(*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<gateway::GatewayBleBridge>(*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<uint8_t>(CONFIG_GATEWAY_USB_SETUP_CHANNEL_INDEX);
usb_config.rx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_RX_BUFFER);
usb_config.tx_buffer_size = static_cast<size_t>(CONFIG_GATEWAY_USB_SETUP_TX_BUFFER);
usb_config.read_timeout_ms = static_cast<uint32_t>(CONFIG_GATEWAY_USB_SETUP_READ_TIMEOUT_MS);
usb_config.reset_pulse_ms = static_cast<uint32_t>(CONFIG_DALI_BUS_RESET_PULSE_MS);
s_usb_setup_bridge = std::make_unique<gateway::GatewayUsbSetupBridge>(*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<unsigned>(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());
}