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
+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