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:
@@ -3427,8 +3427,9 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config.ip_interface_individual_address == 0 ||
|
||||
config.ip_interface_individual_address == 0xffff) {
|
||||
if (!config.oam_router.enabled &&
|
||||
(config.ip_interface_individual_address == 0 ||
|
||||
config.ip_interface_individual_address == 0xffff)) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "KNX IP interface individual address must be a configured address";
|
||||
}
|
||||
@@ -3440,7 +3441,8 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config.ip_interface_individual_address == config.individual_address) {
|
||||
if (!config.oam_router.enabled &&
|
||||
config.ip_interface_individual_address == config.individual_address) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "KNX IP interface and KNX-DALI gateway addresses must differ";
|
||||
}
|
||||
@@ -3463,11 +3465,10 @@ struct GatewayBridgeService::ChannelRuntime {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config.oam_router.individual_address == config.individual_address ||
|
||||
config.oam_router.individual_address == config.ip_interface_individual_address ||
|
||||
config.oam_router.tunnel_address_base == config.individual_address ||
|
||||
config.oam_router.tunnel_address_base == config.ip_interface_individual_address) {
|
||||
config.oam_router.tunnel_address_base == config.oam_router.individual_address) {
|
||||
if (error_message != nullptr) {
|
||||
*error_message = "OAM KNX/IP router addresses must differ from the shared IP interface and KNX-DALI gateway addresses";
|
||||
*error_message = "OAM KNX/IP router addresses must differ from KNX-DALI gateway and OAM tunnel addresses";
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -4364,6 +4365,19 @@ esp_err_t GatewayBridgeService::startKnxEndpoint(ChannelRuntime* requested_runti
|
||||
requested_runtime->channel.gateway_id, owner->channel.gateway_id);
|
||||
}
|
||||
|
||||
for (const auto& runtime : runtimes_) {
|
||||
if (runtime.get() == owner) {
|
||||
continue;
|
||||
}
|
||||
if (runtime->knx_started ||
|
||||
(runtime->knx_router != nullptr && runtime->knx_router->started())) {
|
||||
ESP_LOGI(kTag,
|
||||
"gateway=%u stopping non-owner KNXnet/IP router; shared endpoint owner is gateway=%u",
|
||||
runtime->channel.gateway_id, owner->channel.gateway_id);
|
||||
runtime->stopKnx();
|
||||
}
|
||||
}
|
||||
|
||||
if (used_uarts != nullptr) {
|
||||
LockGuard guard(owner->lock);
|
||||
const auto owner_config = owner->activeKnxConfigLocked();
|
||||
@@ -4404,23 +4418,33 @@ esp_err_t GatewayBridgeService::stopKnxEndpoint(ChannelRuntime* requested_runtim
|
||||
|
||||
DaliBridgeResult GatewayBridgeService::routeKnxGroupWrite(uint16_t group_address,
|
||||
const uint8_t* data, size_t len) {
|
||||
ChannelRuntime* runtime = knx_endpoint_runtime_ != nullptr ? knx_endpoint_runtime_
|
||||
: selectKnxEndpointRuntime();
|
||||
if (runtime == nullptr) {
|
||||
DaliBridgeResult result;
|
||||
result.error = "No DALI channel is selected for KNX group " +
|
||||
GatewayKnxGroupAddressString(group_address);
|
||||
return result;
|
||||
DaliBridgeResult aggregate;
|
||||
aggregate.error = "No DALI channel maps KNX group " +
|
||||
GatewayKnxGroupAddressString(group_address);
|
||||
size_t matched_count = 0;
|
||||
for (const auto& candidate : runtimes_) {
|
||||
LockGuard guard(candidate->lock);
|
||||
const auto config = candidate->activeKnxConfigLocked();
|
||||
if (candidate->knx == nullptr || !config.has_value() || !config->dali_router_enabled ||
|
||||
!candidate->channel.native_bus_id.has_value() ||
|
||||
candidate->channel.native_bus_id.value() != config->dali_bus_id ||
|
||||
!candidate->knx->matchesGroupAddress(group_address)) {
|
||||
continue;
|
||||
}
|
||||
++matched_count;
|
||||
DaliBridgeResult child = candidate->knx->handleGroupWrite(group_address, data, len);
|
||||
child.metadata["gatewayId"] = static_cast<int>(candidate->channel.gateway_id);
|
||||
child.metadata["channelIndex"] = static_cast<int>(candidate->channel.channel_index);
|
||||
aggregate.results.emplace_back(child.toJson());
|
||||
if (child.ok) {
|
||||
aggregate.ok = true;
|
||||
aggregate.error.clear();
|
||||
} else if (!child.error.empty() && aggregate.error.empty()) {
|
||||
aggregate.error = child.error;
|
||||
}
|
||||
}
|
||||
|
||||
LockGuard guard(runtime->lock);
|
||||
if (runtime->knx == nullptr || !runtime->knx->matchesGroupAddress(group_address)) {
|
||||
DaliBridgeResult result;
|
||||
result.error = "Selected DALI bus does not map KNX group " +
|
||||
GatewayKnxGroupAddressString(group_address);
|
||||
return result;
|
||||
}
|
||||
return runtime->knx->handleGroupWrite(group_address, data, len);
|
||||
aggregate.metadata["matchedChannels"] = static_cast<int>(matched_count);
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
DaliBridgeResult GatewayBridgeService::routeKnxGroupObjectWrite(uint16_t group_object_number,
|
||||
|
||||
Reference in New Issue
Block a user