Refactor KNX DALI Gateway Configuration and Update Device Parameters

- Introduced configuration macros for OEM manufacturer ID, application number, and application version in knxprod.h.
- Updated product identity definitions to use the new configuration macros.
- Modified device type enumeration to include additional device types.
- Adjusted color space enumeration values for consistency.
- Defined generated group object layout constants for memory offsets and block sizes.
- Enhanced knx_dali_gw.cpp to utilize the new configuration macros for manufacturer ID and program version.
- Updated the device initialization logic to reflect the new hardware and program version structures.
- Removed obsolete knx_dali_gw subproject and updated related submodules.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-16 01:51:01 +08:00
parent 2a3808c1e4
commit e79223c87e
18 changed files with 699 additions and 780 deletions
@@ -72,7 +72,6 @@ class GatewayBridgeService {
esp_err_t startKnxEndpoint(ChannelRuntime* requested_runtime,
std::set<int>* used_uarts = nullptr);
esp_err_t stopKnxEndpoint(ChannelRuntime* requested_runtime);
DaliBridgeResult routeKnxCemiFrame(const uint8_t* data, size_t len);
DaliBridgeResult routeKnxGroupWrite(uint16_t group_address, const uint8_t* data,
size_t len);
void handleDaliRawFrame(const DaliRawFrame& frame);
@@ -1433,11 +1433,7 @@ struct GatewayBridgeService::ChannelRuntime {
}
knx = std::make_unique<GatewayKnxBridge>(*engine);
knx_router = std::make_unique<GatewayKnxTpIpRouter>(
*knx, [this](const uint8_t* data, size_t len) {
return service.routeKnxCemiFrame(data, len);
},
openKnxNamespace());
knx_router = std::make_unique<GatewayKnxTpIpRouter>(*knx, openKnxNamespace());
knx_router->setGroupWriteHandler(
[this](uint16_t group_address, const uint8_t* data, size_t len) {
return service.routeKnxGroupWrite(group_address, data, len);
@@ -4028,36 +4024,6 @@ esp_err_t GatewayBridgeService::stopKnxEndpoint(ChannelRuntime* requested_runtim
return owner->stopKnx();
}
DaliBridgeResult GatewayBridgeService::routeKnxCemiFrame(const uint8_t* data, size_t len) {
std::vector<ChannelRuntime*> matches;
for (const auto& runtime : runtimes_) {
LockGuard guard(runtime->lock);
if (runtime->knx != nullptr && runtime->knx->matchesCemiFrame(data, len)) {
matches.push_back(runtime.get());
}
}
if (matches.empty()) {
DaliBridgeResult result;
result.error = "No DALI bridge mapping matched KNX cEMI group write";
return result;
}
if (matches.size() > 1) {
DaliBridgeResult result;
result.error = "KNX cEMI group write matched multiple DALI bridge channels";
ESP_LOGW(kTag, "%s", result.error.c_str());
return result;
}
ChannelRuntime* runtime = matches.front();
LockGuard guard(runtime->lock);
if (runtime->knx == nullptr || !runtime->knx->matchesCemiFrame(data, len)) {
DaliBridgeResult result;
result.error = "DALI bridge mapping changed before KNX cEMI dispatch";
return result;
}
return runtime->knx->handleCemiFrame(data, len);
}
DaliBridgeResult GatewayBridgeService::routeKnxGroupWrite(uint16_t group_address,
const uint8_t* data, size_t len) {
std::vector<ChannelRuntime*> matches;
@@ -1,5 +1,7 @@
#include "security_storage.h"
#include "gateway_knx_internal.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_timer.h"
@@ -9,7 +11,9 @@
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <string>
@@ -22,11 +26,7 @@ constexpr const char* kFactoryFdskKey = "factory_fdsk";
constexpr size_t kFdskSize = 16;
constexpr size_t kSerialSize = 6;
constexpr size_t kFdskQrSize = 36;
constexpr uint16_t kKnxManufacturerId = 0x00A4;
constexpr const char* kProductIdentity = "REG1-Dali";
constexpr const char* kManufacturerId = "00A4";
constexpr const char* kApplicationNumber = "01";
constexpr const char* kApplicationVersion = "05";
constexpr const char* kDevelopmentStorage = "base_mac_derived_plain_nvs_development";
constexpr char kFdskDerivationLabel[] = "DaliMaster REG1-Dali deterministic FDSK v1";
constexpr uint8_t kCrc4Tab[16] = {
@@ -38,6 +38,12 @@ constexpr char kHexAlphabet[] = "0123456789ABCDEF";
extern "C" void knx_platform_clear_cached_fdsk() __attribute__((weak));
std::string hexValue(uint32_t value, int width) {
std::array<char, 9> buffer{};
std::snprintf(buffer.data(), buffer.size(), "%0*" PRIX32, width, value);
return buffer.data();
}
bool ensureNvsReady() {
const esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
@@ -123,8 +129,10 @@ bool loadKnxSerialNumber(uint8_t* serial) {
return false;
}
serial[0] = static_cast<uint8_t>((kKnxManufacturerId >> 8) & 0xff);
serial[1] = static_cast<uint8_t>(kKnxManufacturerId & 0xff);
serial[0] = static_cast<uint8_t>(
(gateway::knx_internal::kReg1DaliManufacturerId >> 8) & 0xff);
serial[1] = static_cast<uint8_t>(
gateway::knx_internal::kReg1DaliManufacturerId & 0xff);
std::copy(mac.begin() + 2, mac.end(), serial + 2);
return true;
}
@@ -352,9 +360,11 @@ FactoryCertificatePayload BuildFactoryCertificatePayload() {
}
payload.available = true;
payload.productIdentity = kProductIdentity;
payload.manufacturerId = kManufacturerId;
payload.applicationNumber = kApplicationNumber;
payload.applicationVersion = kApplicationVersion;
payload.manufacturerId = hexValue(gateway::knx_internal::kReg1DaliManufacturerId, 4);
payload.applicationNumber = hexValue(
gateway::knx_internal::kReg1DaliApplicationNumber, 2);
payload.applicationVersion = hexValue(
gateway::knx_internal::kReg1DaliApplicationVersion, 2);
payload.serialNumber = info.serialNumber;
payload.fdskLabel = info.label;
payload.fdskQrCode = info.qrCode;
@@ -9,11 +9,14 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace gateway::openknx {
class TpuartUartInterface;
class EtsDeviceRuntime {
public:
using CemiFrameSender = std::function<void(const uint8_t* data, size_t len)>;
@@ -25,7 +28,8 @@ class EtsDeviceRuntime {
EtsDeviceRuntime(std::string nvs_namespace,
uint16_t fallback_individual_address,
uint16_t tunnel_client_address = 0);
uint16_t tunnel_client_address = 0,
std::unique_ptr<TpuartUartInterface> tp_uart_interface = nullptr);
~EtsDeviceRuntime();
uint16_t individualAddress() const;
@@ -43,7 +47,12 @@ class EtsDeviceRuntime {
void setFunctionPropertyHandlers(FunctionPropertyHandler command_handler,
FunctionPropertyHandler state_handler);
void setGroupWriteHandler(GroupWriteHandler handler);
void setBusFrameSender(CemiFrameSender sender);
void setNetworkInterface(esp_netif_t* netif);
bool hasTpUart() const;
bool enableTpUart(bool enabled = true);
bool tpUartOnline() const;
bool transmitTpFrame(const uint8_t* data, size_t len);
bool handleTunnelFrame(const uint8_t* data, size_t len, CemiFrameSender sender);
bool handleBusFrame(const uint8_t* data, size_t len);
@@ -70,9 +79,11 @@ class EtsDeviceRuntime {
bool shouldConsumeBusFrame(CemiFrame& frame) const;
std::string nvs_namespace_;
std::unique_ptr<TpuartUartInterface> tp_uart_interface_;
EspIdfPlatform platform_;
Bau07B0 device_;
CemiFrameSender sender_;
CemiFrameSender bus_frame_sender_;
GroupWriteHandler group_write_handler_;
FunctionPropertyHandler command_handler_;
FunctionPropertyHandler state_handler_;
+17 -23
View File
@@ -27,6 +27,7 @@ namespace gateway {
namespace openknx {
class EtsDeviceRuntime;
class TpuartUartInterface;
}
constexpr uint16_t kGatewayKnxDefaultUdpPort = 3671;
@@ -143,9 +144,7 @@ class GatewayKnxBridge {
size_t etsBindingCount() const;
std::vector<GatewayKnxDaliBinding> describeDaliBindings() const;
bool matchesCemiFrame(const uint8_t* data, size_t len) const;
bool matchesGroupAddress(uint16_t group_address) const;
DaliBridgeResult handleCemiFrame(const uint8_t* data, size_t len);
DaliBridgeResult handleGroupWrite(uint16_t group_address, const uint8_t* data,
size_t len);
bool handleFunctionPropertyCommand(uint8_t object_index, uint8_t property_id,
@@ -198,12 +197,11 @@ class GatewayKnxBridge {
class GatewayKnxTpIpRouter {
public:
using CemiFrameHandler = std::function<DaliBridgeResult(const uint8_t* data, size_t len)>;
using GroupWriteHandler = std::function<DaliBridgeResult(uint16_t group_address,
const uint8_t* data,
size_t len)>;
GatewayKnxTpIpRouter(GatewayKnxBridge& bridge, CemiFrameHandler handler,
GatewayKnxTpIpRouter(GatewayKnxBridge& bridge,
std::string openknx_namespace = "openknx");
~GatewayKnxTpIpRouter();
@@ -256,22 +254,23 @@ class GatewayKnxTpIpRouter {
void handleTcpAccept();
void handleTcpClient(TcpClient& client);
void closeTcpClient(TcpClient& client);
std::unique_ptr<openknx::TpuartUartInterface> createOpenKnxTpUartInterface();
bool configureTpUart();
bool initializeTpUart();
bool configureProgrammingGpio();
void refreshNetworkInterfaces(bool force_log = false);
void handleUdpDatagram(const uint8_t* data, size_t len, const ::sockaddr_in& remote);
void handleSearchRequest(const uint8_t* data, size_t len, const ::sockaddr_in& remote);
void handleDescriptionRequest(const uint8_t* data, size_t len,
void handleSearchRequest(uint16_t service, const uint8_t* packet_data, size_t len,
const ::sockaddr_in& remote);
void handleDescriptionRequest(const uint8_t* packet_data, size_t len,
const ::sockaddr_in& remote);
void handleRoutingIndication(const uint8_t* body, size_t len);
void handleTunnellingRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
void handleDeviceConfigurationRequest(const uint8_t* body, size_t len,
void handleRoutingIndication(const uint8_t* packet_data, size_t len);
void handleTunnellingRequest(const uint8_t* packet_data, size_t len, const ::sockaddr_in& remote);
void handleDeviceConfigurationRequest(const uint8_t* packet_data, size_t len,
const ::sockaddr_in& remote);
void handleConnectRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
void handleConnectionStateRequest(const uint8_t* body, size_t len,
void handleConnectRequest(const uint8_t* packet_data, size_t len, const ::sockaddr_in& remote);
void handleConnectionStateRequest(const uint8_t* packet_data, size_t len,
const ::sockaddr_in& remote);
void handleDisconnectRequest(const uint8_t* body, size_t len, const ::sockaddr_in& remote);
void handleDisconnectRequest(const uint8_t* packet_data, size_t len, const ::sockaddr_in& remote);
void handleSecureService(uint16_t service, const uint8_t* body, size_t len,
const ::sockaddr_in& remote);
void sendTunnellingAck(uint8_t channel_id, uint8_t sequence, uint8_t status,
@@ -283,6 +282,8 @@ class GatewayKnxTpIpRouter {
void sendSecureSessionStatus(uint8_t status, const ::sockaddr_in& remote);
void sendTunnelIndication(const uint8_t* data, size_t len);
void sendTunnelIndicationToClient(TunnelClient& client, const uint8_t* data, size_t len);
void sendCemiFrameToClient(TunnelClient& client, uint16_t service,
const uint8_t* data, size_t len);
void sendConnectionStateResponse(uint8_t channel_id, uint8_t status,
const ::sockaddr_in& remote);
void sendDisconnectResponse(uint8_t channel_id, uint8_t status,
@@ -319,9 +320,11 @@ class GatewayKnxTpIpRouter {
uint16_t effectiveTunnelAddressForSlot(size_t slot) const;
void pruneStaleTunnelClients();
bool handleOpenKnxTunnelFrame(const uint8_t* data, size_t len,
TunnelClient* response_client);
TunnelClient* response_client, uint16_t response_service);
bool handleOpenKnxBusFrame(const uint8_t* data, size_t len);
bool transmitOpenKnxTpFrame(const uint8_t* data, size_t len);
void selectOpenKnxNetworkInterface(const ::sockaddr_in& remote);
bool routeOpenKnxGroupWrite(const uint8_t* data, size_t len, const char* context);
bool emitOpenKnxGroupValue(uint16_t group_object_number, const uint8_t* data, size_t len);
bool shouldRouteDaliApplicationFrames() const;
uint8_t advertisedMedium() const;
@@ -329,16 +332,11 @@ class GatewayKnxTpIpRouter {
uint16_t effectiveIpInterfaceIndividualAddress() const;
uint16_t effectiveKnxDeviceIndividualAddress() const;
uint16_t effectiveTunnelAddress() const;
void pollTpUart();
void pollProgrammingButton();
void updateProgrammingLed();
void setProgrammingLed(bool on);
void handleTpUartControlByte(uint8_t byte);
void handleTpTelegram(const uint8_t* data, size_t len);
void forwardCemiToTp(const uint8_t* data, size_t len);
GatewayKnxBridge& bridge_;
CemiFrameHandler handler_;
GroupWriteHandler group_write_handler_;
std::string openknx_namespace_;
GatewayKnxConfig config_;
@@ -361,10 +359,6 @@ class GatewayKnxTpIpRouter {
std::array<TunnelClient, kMaxTunnelClients> tunnel_clients_{};
std::unique_ptr<IpParameterObject> knx_ip_parameters_;
uint8_t last_tunnel_channel_id_{0};
std::vector<uint8_t> tp_rx_frame_;
std::vector<uint8_t> tp_last_sent_telegram_;
TickType_t tp_uart_last_byte_tick_{0};
bool tp_uart_extended_frame_{false};
bool tp_uart_online_{false};
bool commissioning_only_{false};
std::atomic_bool openknx_configured_{false};
@@ -1,10 +1,11 @@
#pragma once
// Internal header shared between gateway_knx.cpp and gateway_knx_router.cpp.
// Internal helpers and product identity shared by gateway_knx component sources.
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "sdkconfig.h"
#include "soc/uart_periph.h"
#include <cstdint>
@@ -15,6 +16,46 @@ namespace knx_internal {
constexpr const char* kTag = "gateway_knx";
#ifndef CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID
#define CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID 0x00A4
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER 0x0001
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION 0x08
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_HARDWARE_ID
#define CONFIG_GATEWAY_KNX_OEM_HARDWARE_ID 0xA401
#endif
inline constexpr uint16_t kReg1DaliManufacturerId =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID);
inline constexpr uint16_t kReg1DaliHardwareId =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OEM_HARDWARE_ID);
inline constexpr uint16_t kReg1DaliApplicationNumber =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER);
inline constexpr uint8_t kReg1DaliApplicationVersion =
static_cast<uint8_t>(CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION);
inline constexpr uint8_t kReg1DaliHardwareType[6] = {
0x00,
0x00,
static_cast<uint8_t>((kReg1DaliHardwareId >> 8) & 0xff),
static_cast<uint8_t>(kReg1DaliHardwareId & 0xff),
kReg1DaliApplicationVersion,
0x00};
inline constexpr uint8_t kReg1DaliOrderNumber[10] = {
'R', 'E', 'G', '1', '-', 'D', 'a', 'l', 'i', 0};
inline constexpr uint8_t kReg1DaliProgramVersion[5] = {
static_cast<uint8_t>((kReg1DaliManufacturerId >> 8) & 0xff),
static_cast<uint8_t>(kReg1DaliManufacturerId & 0xff),
static_cast<uint8_t>((kReg1DaliApplicationNumber >> 8) & 0xff),
static_cast<uint8_t>(kReg1DaliApplicationNumber & 0xff),
kReg1DaliApplicationVersion};
// RAII semaphore guard.
class SemaphoreGuard {
public:
+117 -22
View File
@@ -1,11 +1,17 @@
#include "ets_device_runtime.h"
#include "gateway_knx_internal.h"
#include "esp_log.h"
#include "knx/cemi_server.h"
#include "knx/secure_application_layer.h"
#include "knx/property.h"
#include "tpuart_uart_interface.h"
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <string>
#include <utility>
#include <vector>
@@ -29,53 +35,97 @@ class ActiveFunctionPropertyRuntimeScope {
constexpr uint16_t kInvalidIndividualAddress = 0xffff;
constexpr uint16_t kKnxUnconfiguredBroadcastAddress = 0xffff; // KNX broadcast IA for unconfigured devices
constexpr uint16_t kReg1DaliManufacturerId = 0x00a4;
constexpr uint8_t kReg1DaliApplicationNumber = 0x01;
constexpr uint8_t kReg1DaliApplicationVersion = 0x05;
constexpr uint8_t kReg1DaliOrderNumber[10] = {'R', 'E', 'G', '1', '-', 'D', 'a', 'l', 'i', 0};
bool IsUsableIndividualAddress(uint16_t address) {
return address != 0 && address != kInvalidIndividualAddress;
}
bool IsErasedMemory(const uint8_t* data, size_t size) {
if (data == nullptr || size == 0) {
return true;
std::string HexBytesString(const uint8_t* data, size_t length) {
if (data == nullptr || length == 0) {
return {};
}
return std::all_of(data, data + size, [](uint8_t value) { return value == 0xff; });
std::string out;
out.reserve(length * 3);
char buffer[4] = {0};
for (size_t index = 0; index < length; ++index) {
std::snprintf(buffer, sizeof(buffer), "%02X", data[index]);
out += buffer;
if (index + 1 < length) {
out.push_back(' ');
}
}
return out;
}
std::string PrintableOrderNumber(const uint8_t* data, size_t length) {
if (data == nullptr || length == 0) {
return {};
}
std::string out;
out.reserve(length);
for (size_t index = 0; index < length; ++index) {
if (data[index] == 0) {
break;
}
out.push_back(static_cast<char>(data[index]));
}
return out;
}
void LogReg1DaliIdentity(const std::string& nvs_namespace, Bau07B0& device) {
uint8_t program_version[5] = {0};
if (auto* property = device.parameters().property(PID_PROG_VERSION); property != nullptr) {
property->read(program_version);
}
const std::string hardware_type =
HexBytesString(device.deviceObject().hardwareType(), LEN_HARDWARE_TYPE);
const std::string program_version_hex =
HexBytesString(program_version, sizeof(program_version));
const std::string order_number =
PrintableOrderNumber(device.deviceObject().orderNumber(),
sizeof(knx_internal::kReg1DaliOrderNumber));
ESP_LOGI("gateway_knx",
"OpenKNX identity namespace=%s manufacturer=0x%04x mask=0x%04x deviceVersion=0x%04x hardwareType=%s progVersion=%s order=%s",
nvs_namespace.c_str(), device.deviceObject().manufacturerId(),
device.deviceObject().maskVersion(), device.deviceObject().version(),
hardware_type.c_str(), program_version_hex.c_str(), order_number.c_str());
}
void ApplyReg1DaliIdentity(Bau07B0& device, EspIdfPlatform& platform) {
device.deviceObject().manufacturerId(kReg1DaliManufacturerId);
device.deviceObject().manufacturerId(knx_internal::kReg1DaliManufacturerId);
device.deviceObject().bauNumber(platform.uniqueSerialNumber());
device.deviceObject().orderNumber(kReg1DaliOrderNumber);
const uint8_t program_version[5] = {0x00, 0xa4, 0x00, kReg1DaliApplicationNumber,
kReg1DaliApplicationVersion};
device.parameters().property(PID_PROG_VERSION)->write(program_version);
device.deviceObject().hardwareType(knx_internal::kReg1DaliHardwareType);
device.deviceObject().orderNumber(knx_internal::kReg1DaliOrderNumber);
device.parameters().property(PID_PROG_VERSION)->write(
knx_internal::kReg1DaliProgramVersion);
}
} // namespace
EtsDeviceRuntime::EtsDeviceRuntime(std::string nvs_namespace,
uint16_t fallback_individual_address,
uint16_t tunnel_client_address)
uint16_t tunnel_client_address,
std::unique_ptr<TpuartUartInterface> tp_uart_interface)
: nvs_namespace_(std::move(nvs_namespace)),
platform_(nullptr, nvs_namespace_.c_str()),
tp_uart_interface_(std::move(tp_uart_interface)),
platform_(tp_uart_interface_.get(), nvs_namespace_.c_str()),
device_(platform_) {
platform_.outboundCemiFrameCallback(&EtsDeviceRuntime::HandleOutboundCemiFrame, this);
ApplyReg1DaliIdentity(device_, platform_);
if (IsUsableIndividualAddress(fallback_individual_address)) {
device_.deviceObject().individualAddress(fallback_individual_address);
}
const uint8_t* memory = platform_.getNonVolatileMemoryStart();
const size_t memory_size = platform_.getNonVolatileMemorySize();
if (!IsErasedMemory(memory, memory_size)) {
device_.readMemory();
}
ESP_LOGI("gateway_knx", "OpenKNX loading memory namespace=%s", nvs_namespace_.c_str());
device_.readMemory();
if (!IsUsableIndividualAddress(device_.deviceObject().individualAddress()) &&
IsUsableIndividualAddress(fallback_individual_address)) {
device_.deviceObject().individualAddress(fallback_individual_address);
}
LogReg1DaliIdentity(nvs_namespace_, device_);
if (auto* server = device_.getCemiServer()) {
server->clientAddress(IsUsableIndividualAddress(tunnel_client_address)
? tunnel_client_address
@@ -92,6 +142,9 @@ EtsDeviceRuntime::EtsDeviceRuntime(std::string nvs_namespace,
}
EtsDeviceRuntime::~EtsDeviceRuntime() {
if (tp_uart_interface_ != nullptr) {
device_.enabled(false);
}
platform_.outboundCemiFrameCallback(nullptr, nullptr);
#ifdef USE_DATASECURE
device_.secureGroupWriteCallback(nullptr, nullptr);
@@ -170,10 +223,43 @@ void EtsDeviceRuntime::setGroupWriteHandler(GroupWriteHandler handler) {
group_write_handler_ = std::move(handler);
}
void EtsDeviceRuntime::setBusFrameSender(CemiFrameSender sender) {
bus_frame_sender_ = std::move(sender);
}
void EtsDeviceRuntime::setNetworkInterface(esp_netif_t* netif) {
platform_.networkInterface(netif);
}
bool EtsDeviceRuntime::hasTpUart() const { return tp_uart_interface_ != nullptr; }
bool EtsDeviceRuntime::enableTpUart(bool enabled) {
if (tp_uart_interface_ == nullptr) {
return false;
}
device_.enabled(enabled);
loop();
return !enabled || device_.enabled();
}
bool EtsDeviceRuntime::tpUartOnline() const {
return tp_uart_interface_ != nullptr && const_cast<Bau07B0&>(device_).enabled();
}
bool EtsDeviceRuntime::transmitTpFrame(const uint8_t* data, size_t len) {
auto* data_link_layer = device_.getDataLinkLayer();
if (tp_uart_interface_ == nullptr || data_link_layer == nullptr || data == nullptr || len < 2 ||
!data_link_layer->enabled()) {
return false;
}
std::vector<uint8_t> frame_data(data, data + len);
CemiFrame frame(frame_data.data(), static_cast<uint16_t>(frame_data.size()));
if (!frame.valid()) {
return false;
}
return data_link_layer->transmitFrame(frame);
}
bool EtsDeviceRuntime::handleTunnelFrame(const uint8_t* data, size_t len,
CemiFrameSender sender) {
auto* server = device_.getCemiServer();
@@ -248,10 +334,16 @@ bool EtsDeviceRuntime::HandleOutboundCemiFrame(CemiFrame& frame, void* context)
void EtsDeviceRuntime::EmitTunnelFrame(CemiFrame& frame, void* context) {
auto* self = static_cast<EtsDeviceRuntime*>(context);
if (self == nullptr || !self->sender_) {
if (self == nullptr) {
return;
}
self->sender_(frame.data(), frame.dataLength());
if (self->sender_) {
self->sender_(frame.data(), frame.dataLength());
return;
}
if (self->bus_frame_sender_) {
self->bus_frame_sender_(frame.data(), frame.dataLength());
}
}
void EtsDeviceRuntime::HandleSecureGroupWrite(uint16_t group_address, const uint8_t* data,
@@ -324,6 +416,9 @@ bool EtsDeviceRuntime::shouldConsumeTunnelFrame(CemiFrame& frame) const {
case M_FuncPropStateRead_req:
return true;
case L_data_req: {
if (tpUartOnline()) {
return true;
}
// In commissioning / programming mode ETS may address the device via its
// individual address, the cEMI-client tunnel address (device+1), or the
// unconfigured broadcast address 0xFFFF. Consume only those; let all
@@ -1,6 +1,7 @@
#include "ets_memory_loader.h"
#include "esp_idf_platform.h"
#include "gateway_knx_internal.h"
#include "knx/bau07B0.h"
#include "knx/property.h"
@@ -28,18 +29,13 @@ bool IsErasedMemory(const uint8_t* data, size_t size) {
return std::all_of(data, data + size, [](uint8_t value) { return value == 0xff; });
}
constexpr uint16_t kReg1DaliManufacturerId = 0x00a4;
constexpr uint8_t kReg1DaliApplicationNumber = 0x01;
constexpr uint8_t kReg1DaliApplicationVersion = 0x05;
constexpr uint8_t kReg1DaliOrderNumber[10] = {'R', 'E', 'G', '1', '-', 'D', 'a', 'l', 'i', 0};
void ApplyReg1DaliIdentity(Bau07B0& device, EspIdfPlatform& platform) {
device.deviceObject().manufacturerId(kReg1DaliManufacturerId);
device.deviceObject().manufacturerId(knx_internal::kReg1DaliManufacturerId);
device.deviceObject().bauNumber(platform.uniqueSerialNumber());
device.deviceObject().orderNumber(kReg1DaliOrderNumber);
const uint8_t program_version[5] = {0x00, 0xa4, 0x00, kReg1DaliApplicationNumber,
kReg1DaliApplicationVersion};
device.parameters().property(PID_PROG_VERSION)->write(program_version);
device.deviceObject().hardwareType(knx_internal::kReg1DaliHardwareType);
device.deviceObject().orderNumber(knx_internal::kReg1DaliOrderNumber);
device.parameters().property(PID_PROG_VERSION)->write(
knx_internal::kReg1DaliProgramVersion);
}
} // namespace
File diff suppressed because it is too large Load Diff
+33 -14
View File
@@ -1,13 +1,27 @@
#pragma once
#include "sdkconfig.h"
#ifndef CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID
#define CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID 0x00A4
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER 0x0001
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION 0x08
#endif
// Minimal stub for knxprod.h — generated KNX product definitions.
// The full file (1796 bytes of parameters, 1439 group objects) will be
// adapted in Phase 3 to use the gateway/knx API directly.
// Product identity
#define MAIN_OpenKnxId 0xA4
#define MAIN_ApplicationNumber 1
#define MAIN_ApplicationVersion 5
#define MAIN_OpenKnxId (CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID & 0xff)
#define MAIN_ApplicationNumber CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER
#define MAIN_ApplicationVersion CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION
#define MAIN_OrderNumber "REG1-Dali"
#define MAIN_ParameterSize 1796
#define MAIN_MaxKoNumber 1439
@@ -17,8 +31,13 @@ enum PT_DeviceType : uint8_t {
PT_deviceType_Deaktiviert = 0,
PT_deviceType_DT0 = 1,
PT_deviceType_DT1 = 2,
PT_deviceType_DT6 = 3,
PT_deviceType_DT8 = 4,
PT_deviceType_DT2 = 3,
PT_deviceType_DT3 = 4,
PT_deviceType_DT4 = 5,
PT_deviceType_DT5 = 6,
PT_deviceType_DT6 = 7,
PT_deviceType_DT7 = 8,
PT_deviceType_DT8 = 9,
};
enum PT_ColorType : uint8_t {
@@ -29,8 +48,8 @@ enum PT_ColorType : uint8_t {
};
enum PT_ColorSpace : uint8_t {
PT_colorSpace_rgb = 0,
PT_colorSpace_xy = 1,
PT_colorSpace_rgb = 1,
PT_colorSpace_xy = 0,
};
// Placeholder macros — will be replaced with direct Bau07B0 access in Phase 3.
@@ -57,10 +76,10 @@ enum PT_ColorSpace : uint8_t {
#define ParamHCL_type(channelIndex) (0)
// Group object offset placeholders
#define ADR_KoOffset 0
#define GRP_KoOffset 0
#define HCL_KoOffset 0
#define ADR_KoBlockSize 0
#define GRP_KoBlockSize 0
#define HCL_KoBlockSize 0
// Generated group object layout constants
#define ADR_KoOffset 12
#define GRP_KoOffset 1164
#define HCL_KoOffset 1436
#define ADR_KoBlockSize 18
#define GRP_KoBlockSize 17
#define HCL_KoBlockSize 1
+39 -4
View File
@@ -2,6 +2,8 @@
#include "knx/bau07B0.h"
#include "sdkconfig.h"
#include "esp_log.h"
namespace gateway {
@@ -11,6 +13,38 @@ namespace {
constexpr const char* kTag = "knx_dali_gw";
#ifndef CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID
#define CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID 0x00A4
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER 0x0001
#endif
#ifndef CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION
#define CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION 0x08
#endif
constexpr uint16_t kKnxOemManufacturerId =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OEM_MANUFACTURER_ID);
constexpr uint16_t kKnxOemApplicationNumber =
static_cast<uint16_t>(CONFIG_GATEWAY_KNX_OEM_APPLICATION_NUMBER);
constexpr uint8_t kKnxOemApplicationVersion =
static_cast<uint8_t>(CONFIG_GATEWAY_KNX_OEM_APPLICATION_VERSION);
constexpr uint8_t kKnxOemHardwareType[6] = {
0x00,
0x00,
static_cast<uint8_t>(kKnxOemManufacturerId & 0xff),
static_cast<uint8_t>(kKnxOemApplicationNumber & 0xff),
kKnxOemApplicationVersion,
0x00};
constexpr uint8_t kKnxOemProgramVersion[5] = {
static_cast<uint8_t>((kKnxOemManufacturerId >> 8) & 0xff),
static_cast<uint8_t>(kKnxOemManufacturerId & 0xff),
static_cast<uint8_t>((kKnxOemApplicationNumber >> 8) & 0xff),
static_cast<uint8_t>(kKnxOemApplicationNumber & 0xff),
kKnxOemApplicationVersion};
} // namespace
// =============================================================================
@@ -31,12 +65,13 @@ struct KnxDaliGateway::Impl {
bool init() {
if (initialized) return true;
device.deviceObject().manufacturerId(0x00a4);
device.deviceObject().manufacturerId(kKnxOemManufacturerId);
device.deviceObject().bauNumber(platform.uniqueSerialNumber());
const uint8_t order_number[10] = {'R', 'E', 'G', '1', '-', 'D', 'a', 'l', 'i', 0};
device.deviceObject().hardwareType(kKnxOemHardwareType);
const uint8_t order_number[10] = {
'R', 'E', 'G', '1', '-', 'D', 'a', 'l', 'i', 0};
device.deviceObject().orderNumber(order_number);
const uint8_t program_version[5] = {0x00, 0xa4, 0x00, 0x01, 0x05};
device.parameters().property(PID_PROG_VERSION)->write(program_version);
device.parameters().property(PID_PROG_VERSION)->write(kKnxOemProgramVersion);
device.readMemory();