feat: Enhance OAM router functionality and improve KNX device handling

- Added support for OAM router configuration in app_main, allowing the IP interface individual address to be set based on the OAM router's individual address.
- Updated GatewayBridgeService to validate IP interface addresses only when OAM router is disabled, ensuring proper address management.
- Introduced KnxResponseDeduplicator to prevent duplicate responses in KNX communication.
- Enhanced ETS device runtime to handle bus frames and set up frame receivers for OAM router.
- Improved GatewayKnxTpIpRouter to manage OAM router interactions, including handling tunnel frames and bus frames.
- Updated CMakeLists to include new knx_device_broker source file.
- Refined logging messages to provide clearer context regarding the IP interface being used.
- Added methods to retrieve IP interface names and friendly names based on the OAM router configuration.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-28 15:44:17 +08:00
parent 078c37a20f
commit 8211514fe3
17 changed files with 432 additions and 75 deletions
@@ -208,6 +208,10 @@ void OamRouterRuntime::setNetworkInterface(esp_netif_t* netif) {
#endif
}
void OamRouterRuntime::setBusFrameSender(CemiFrameSender sender) {
bus_frame_sender_ = std::move(sender);
}
bool OamRouterRuntime::handleTunnelFrame(const uint8_t* data, size_t len,
CemiFrameSender sender) {
#if defined(ENABLE_BAU091A_PERSONA) && defined(USE_CEMI_SERVER)
@@ -260,6 +264,34 @@ bool OamRouterRuntime::handleLocalBroadcastManagementFrame(const uint8_t* data,
#endif
}
bool OamRouterRuntime::handleBusFrame(const uint8_t* data, size_t len,
CemiFrameSender sender) {
#if defined(ENABLE_BAU091A_PERSONA)
auto* data_link_layer = device_.getSecondaryDataLinkLayer();
if (data_link_layer == nullptr || data == nullptr || len < 2) {
return false;
}
std::vector<uint8_t> frame_data(data, data + len);
CemiFrame frame(frame_data.data(), static_cast<uint16_t>(frame_data.size()));
if (!shouldConsumeBusFrame(frame)) {
return false;
}
if (frame.messageCode() == L_data_req) {
frame.messageCode(L_data_ind);
}
sender_ = std::move(sender);
data_link_layer->externalFrameReceived(frame);
loop();
sender_ = nullptr;
return true;
#else
(void)data;
(void)len;
(void)sender;
return false;
#endif
}
void OamRouterRuntime::loop() {
#if defined(ENABLE_BAU091A_PERSONA)
device_.loop();
@@ -277,10 +309,16 @@ bool OamRouterRuntime::HandleOutboundCemiFrame(CemiFrame& frame, void* context)
void OamRouterRuntime::EmitTunnelFrame(CemiFrame& frame, void* context) {
auto* self = static_cast<OamRouterRuntime*>(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());
}
}
uint16_t OamRouterRuntime::DefaultTunnelClientAddress(uint16_t individual_address) {
@@ -320,4 +358,20 @@ bool OamRouterRuntime::shouldConsumeTunnelFrame(CemiFrame& frame) const {
}
}
bool OamRouterRuntime::shouldConsumeBusFrame(CemiFrame& frame) const {
if (frame.messageCode() != L_data_ind && frame.messageCode() != L_data_req) {
return false;
}
if (IsBroadcastManagementRequest(frame)) {
return true;
}
if (frame.addressType() != IndividualAddress) {
return false;
}
const uint16_t dest = frame.destinationAddress();
const bool commissioning = !configured() || programmingMode();
return dest == individualAddress() || dest == tunnelClientAddress() ||
(commissioning && dest == kKnxUnconfiguredBroadcastAddress);
}
} // namespace gateway::openknx