feat(gateway): add extended function property handlers and diagnostics support for OpenKNX
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -29,6 +29,11 @@ class EtsDeviceRuntime {
|
|||||||
using FunctionPropertyHandler = std::function<bool(uint8_t object_index, uint8_t property_id,
|
using FunctionPropertyHandler = std::function<bool(uint8_t object_index, uint8_t property_id,
|
||||||
const uint8_t* data, size_t len,
|
const uint8_t* data, size_t len,
|
||||||
std::vector<uint8_t>* response)>;
|
std::vector<uint8_t>* response)>;
|
||||||
|
using FunctionPropertyExtHandler = std::function<bool(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len,
|
||||||
|
std::vector<uint8_t>* response)>;
|
||||||
|
|
||||||
EtsDeviceRuntime(std::string nvs_namespace,
|
EtsDeviceRuntime(std::string nvs_namespace,
|
||||||
uint16_t fallback_individual_address,
|
uint16_t fallback_individual_address,
|
||||||
@@ -52,6 +57,8 @@ class EtsDeviceRuntime {
|
|||||||
|
|
||||||
void setFunctionPropertyHandlers(FunctionPropertyHandler command_handler,
|
void setFunctionPropertyHandlers(FunctionPropertyHandler command_handler,
|
||||||
FunctionPropertyHandler state_handler);
|
FunctionPropertyHandler state_handler);
|
||||||
|
void setFunctionPropertyExtHandlers(FunctionPropertyExtHandler command_handler,
|
||||||
|
FunctionPropertyExtHandler state_handler);
|
||||||
void setGroupWriteHandler(GroupWriteHandler handler);
|
void setGroupWriteHandler(GroupWriteHandler handler);
|
||||||
void setGroupObjectWriteHandler(GroupObjectWriteHandler handler);
|
void setGroupObjectWriteHandler(GroupObjectWriteHandler handler);
|
||||||
void setBusFrameSender(CemiFrameSender sender);
|
void setBusFrameSender(CemiFrameSender sender);
|
||||||
@@ -79,10 +86,29 @@ class EtsDeviceRuntime {
|
|||||||
static bool HandleFunctionPropertyState(uint8_t object_index, uint8_t property_id,
|
static bool HandleFunctionPropertyState(uint8_t object_index, uint8_t property_id,
|
||||||
uint8_t length, uint8_t* data,
|
uint8_t length, uint8_t* data,
|
||||||
uint8_t* result_data, uint8_t& result_length);
|
uint8_t* result_data, uint8_t& result_length);
|
||||||
|
static bool HandleFunctionPropertyExtCommand(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length);
|
||||||
|
static bool HandleFunctionPropertyExtState(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length);
|
||||||
static uint16_t DefaultTunnelClientAddress(uint16_t individual_address);
|
static uint16_t DefaultTunnelClientAddress(uint16_t individual_address);
|
||||||
static bool DispatchFunctionProperty(FunctionPropertyHandler* handler, uint8_t object_index,
|
static bool DispatchFunctionProperty(FunctionPropertyHandler* handler, uint8_t object_index,
|
||||||
uint8_t property_id, uint8_t length, uint8_t* data,
|
uint8_t property_id, uint8_t length, uint8_t* data,
|
||||||
uint8_t* result_data, uint8_t& result_length);
|
uint8_t* result_data, uint8_t& result_length);
|
||||||
|
static bool DispatchFunctionPropertyExt(FunctionPropertyExtHandler* handler,
|
||||||
|
uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length);
|
||||||
void installGroupObjectCallbacks();
|
void installGroupObjectCallbacks();
|
||||||
bool shouldConsumeTunnelFrame(CemiFrame& frame) const;
|
bool shouldConsumeTunnelFrame(CemiFrame& frame) const;
|
||||||
bool shouldConsumeBusFrame(CemiFrame& frame) const;
|
bool shouldConsumeBusFrame(CemiFrame& frame) const;
|
||||||
@@ -97,6 +123,8 @@ class EtsDeviceRuntime {
|
|||||||
GroupObjectWriteHandler group_object_write_handler_;
|
GroupObjectWriteHandler group_object_write_handler_;
|
||||||
FunctionPropertyHandler command_handler_;
|
FunctionPropertyHandler command_handler_;
|
||||||
FunctionPropertyHandler state_handler_;
|
FunctionPropertyHandler state_handler_;
|
||||||
|
FunctionPropertyExtHandler command_ext_handler_;
|
||||||
|
FunctionPropertyExtHandler state_ext_handler_;
|
||||||
bool suppress_group_object_write_callback_{false};
|
bool suppress_group_object_write_callback_{false};
|
||||||
uint16_t group_object_callback_count_{0};
|
uint16_t group_object_callback_count_{0};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -236,6 +236,17 @@ class GatewayKnxTpIpRouter {
|
|||||||
bool publishDaliStatus(const GatewayKnxDaliTarget& target, uint8_t actual_level);
|
bool publishDaliStatus(const GatewayKnxDaliTarget& target, uint8_t actual_level);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool handleFunctionPropertyExtCommand(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len,
|
||||||
|
std::vector<uint8_t>* response);
|
||||||
|
bool handleFunctionPropertyExtState(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len,
|
||||||
|
std::vector<uint8_t>* response);
|
||||||
|
|
||||||
static constexpr size_t kMaxTunnelClients = 16;
|
static constexpr size_t kMaxTunnelClients = 16;
|
||||||
static constexpr size_t kMaxTcpClients = 4;
|
static constexpr size_t kMaxTcpClients = 4;
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,8 @@ EtsDeviceRuntime::EtsDeviceRuntime(std::string nvs_namespace,
|
|||||||
}
|
}
|
||||||
device_.functionPropertyCallback(&EtsDeviceRuntime::HandleFunctionPropertyCommand);
|
device_.functionPropertyCallback(&EtsDeviceRuntime::HandleFunctionPropertyCommand);
|
||||||
device_.functionPropertyStateCallback(&EtsDeviceRuntime::HandleFunctionPropertyState);
|
device_.functionPropertyStateCallback(&EtsDeviceRuntime::HandleFunctionPropertyState);
|
||||||
|
device_.functionPropertyExtCallback(&EtsDeviceRuntime::HandleFunctionPropertyExtCommand);
|
||||||
|
device_.functionPropertyExtStateCallback(&EtsDeviceRuntime::HandleFunctionPropertyExtState);
|
||||||
#ifdef USE_DATASECURE
|
#ifdef USE_DATASECURE
|
||||||
device_.secureGroupWriteCallback(&EtsDeviceRuntime::HandleSecureGroupWrite, this);
|
device_.secureGroupWriteCallback(&EtsDeviceRuntime::HandleSecureGroupWrite, this);
|
||||||
#endif
|
#endif
|
||||||
@@ -168,6 +170,8 @@ EtsDeviceRuntime::~EtsDeviceRuntime() {
|
|||||||
}
|
}
|
||||||
device_.functionPropertyCallback(nullptr);
|
device_.functionPropertyCallback(nullptr);
|
||||||
device_.functionPropertyStateCallback(nullptr);
|
device_.functionPropertyStateCallback(nullptr);
|
||||||
|
device_.functionPropertyExtCallback(nullptr);
|
||||||
|
device_.functionPropertyExtStateCallback(nullptr);
|
||||||
if (auto* server = device_.getCemiServer()) {
|
if (auto* server = device_.getCemiServer()) {
|
||||||
server->tunnelFrameCallback(nullptr, nullptr);
|
server->tunnelFrameCallback(nullptr, nullptr);
|
||||||
}
|
}
|
||||||
@@ -251,6 +255,12 @@ void EtsDeviceRuntime::setFunctionPropertyHandlers(FunctionPropertyHandler comma
|
|||||||
state_handler_ = std::move(state_handler);
|
state_handler_ = std::move(state_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EtsDeviceRuntime::setFunctionPropertyExtHandlers(FunctionPropertyExtHandler command_handler,
|
||||||
|
FunctionPropertyExtHandler state_handler) {
|
||||||
|
command_ext_handler_ = std::move(command_handler);
|
||||||
|
state_ext_handler_ = std::move(state_handler);
|
||||||
|
}
|
||||||
|
|
||||||
void EtsDeviceRuntime::setGroupWriteHandler(GroupWriteHandler handler) {
|
void EtsDeviceRuntime::setGroupWriteHandler(GroupWriteHandler handler) {
|
||||||
group_write_handler_ = std::move(handler);
|
group_write_handler_ = std::move(handler);
|
||||||
}
|
}
|
||||||
@@ -337,6 +347,7 @@ bool EtsDeviceRuntime::handleBusFrame(const uint8_t* data, size_t len) {
|
|||||||
if (!consumed) {
|
if (!consumed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ActiveFunctionPropertyRuntimeScope callback_scope(this);
|
||||||
data_link_layer->externalFrameReceived(frame);
|
data_link_layer->externalFrameReceived(frame);
|
||||||
loop();
|
loop();
|
||||||
installGroupObjectCallbacks();
|
installGroupObjectCallbacks();
|
||||||
@@ -371,7 +382,10 @@ bool EtsDeviceRuntime::emitGroupValue(uint16_t group_object_number, const uint8_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EtsDeviceRuntime::loop() { device_.loop(); }
|
void EtsDeviceRuntime::loop() {
|
||||||
|
ActiveFunctionPropertyRuntimeScope callback_scope(this);
|
||||||
|
device_.loop();
|
||||||
|
}
|
||||||
|
|
||||||
bool EtsDeviceRuntime::HandleOutboundCemiFrame(CemiFrame& frame, void* context) {
|
bool EtsDeviceRuntime::HandleOutboundCemiFrame(CemiFrame& frame, void* context) {
|
||||||
auto* self = static_cast<EtsDeviceRuntime*>(context);
|
auto* self = static_cast<EtsDeviceRuntime*>(context);
|
||||||
@@ -453,6 +467,34 @@ bool EtsDeviceRuntime::HandleFunctionPropertyState(uint8_t object_index, uint8_t
|
|||||||
property_id, length, data, result_data, result_length);
|
property_id, length, data, result_data, result_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EtsDeviceRuntime::HandleFunctionPropertyExtCommand(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length) {
|
||||||
|
if (active_function_property_runtime == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DispatchFunctionPropertyExt(&active_function_property_runtime->command_ext_handler_,
|
||||||
|
object_type, object_instance, property_id, length, data,
|
||||||
|
result_data, result_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EtsDeviceRuntime::HandleFunctionPropertyExtState(uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length) {
|
||||||
|
if (active_function_property_runtime == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DispatchFunctionPropertyExt(&active_function_property_runtime->state_ext_handler_,
|
||||||
|
object_type, object_instance, property_id, length, data,
|
||||||
|
result_data, result_length);
|
||||||
|
}
|
||||||
|
|
||||||
bool EtsDeviceRuntime::DispatchFunctionProperty(FunctionPropertyHandler* handler,
|
bool EtsDeviceRuntime::DispatchFunctionProperty(FunctionPropertyHandler* handler,
|
||||||
uint8_t object_index, uint8_t property_id,
|
uint8_t object_index, uint8_t property_id,
|
||||||
uint8_t length, uint8_t* data,
|
uint8_t length, uint8_t* data,
|
||||||
@@ -471,6 +513,27 @@ bool EtsDeviceRuntime::DispatchFunctionProperty(FunctionPropertyHandler* handler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EtsDeviceRuntime::DispatchFunctionPropertyExt(FunctionPropertyExtHandler* handler,
|
||||||
|
uint16_t object_type,
|
||||||
|
uint8_t object_instance,
|
||||||
|
uint8_t property_id,
|
||||||
|
uint8_t length, uint8_t* data,
|
||||||
|
uint8_t* result_data,
|
||||||
|
uint8_t& result_length) {
|
||||||
|
if (handler == nullptr || !*handler || result_data == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> response;
|
||||||
|
if (!(*handler)(object_type, object_instance, property_id, data, length, &response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result_length = static_cast<uint8_t>(std::min<size_t>(response.size(), result_length));
|
||||||
|
if (result_length > 0) {
|
||||||
|
std::copy_n(response.begin(), result_length, result_data);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void EtsDeviceRuntime::installGroupObjectCallbacks() {
|
void EtsDeviceRuntime::installGroupObjectCallbacks() {
|
||||||
active_group_object_runtime = this;
|
active_group_object_runtime = this;
|
||||||
auto& table = device_.groupObjectTable();
|
auto& table = device_.groupObjectTable();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "tpuart_uart_interface.h"
|
#include "tpuart_uart_interface.h"
|
||||||
|
|
||||||
#include "knx/cemi_frame.h"
|
#include "knx/cemi_frame.h"
|
||||||
|
#include "knx/interface_object.h"
|
||||||
#include "knx/knx_ip_connect_request.h"
|
#include "knx/knx_ip_connect_request.h"
|
||||||
#include "knx/knx_ip_connect_response.h"
|
#include "knx/knx_ip_connect_response.h"
|
||||||
#include "knx/knx_ip_config_request.h"
|
#include "knx/knx_ip_config_request.h"
|
||||||
@@ -140,12 +141,22 @@ constexpr uint8_t kReg1DeviceTypeDt8 = 8;
|
|||||||
constexpr uint8_t kReg1ColorTypeTw = 1;
|
constexpr uint8_t kReg1ColorTypeTw = 1;
|
||||||
constexpr uint8_t kDaliDeviceTypeNone = 0xfe;
|
constexpr uint8_t kDaliDeviceTypeNone = 0xfe;
|
||||||
constexpr uint8_t kDaliDeviceTypeMultiple = 0xff;
|
constexpr uint8_t kDaliDeviceTypeMultiple = 0xff;
|
||||||
|
constexpr uint16_t kGroupObjectTableObjectType = OT_GRP_OBJ_TABLE;
|
||||||
|
constexpr uint8_t kPidGoDiagnostics = 0x42;
|
||||||
|
constexpr uint8_t kGoDiagnosticsReservedByte = 0x00;
|
||||||
|
constexpr uint8_t kGoDiagnosticsGroupWriteService = 0x01;
|
||||||
|
|
||||||
struct DecodedGroupWrite {
|
struct DecodedGroupWrite {
|
||||||
uint16_t group_address{0};
|
uint16_t group_address{0};
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DecodedGoDiagnosticsGroupWrite {
|
||||||
|
uint16_t group_address{0};
|
||||||
|
const uint8_t* payload{nullptr};
|
||||||
|
size_t payload_len{0};
|
||||||
|
};
|
||||||
|
|
||||||
struct KnxNetifInfo {
|
struct KnxNetifInfo {
|
||||||
const char* key{nullptr};
|
const char* key{nullptr};
|
||||||
esp_netif_t* netif{nullptr};
|
esp_netif_t* netif{nullptr};
|
||||||
@@ -550,6 +561,26 @@ std::optional<DecodedGroupWrite> DecodeOpenKnxGroupWrite(const uint8_t* data, si
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<DecodedGoDiagnosticsGroupWrite> DecodeGoDiagnosticsGroupWrite(
|
||||||
|
const uint8_t* data, size_t len) {
|
||||||
|
if (data == nullptr || len < 5) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
if (data[0] != kGoDiagnosticsReservedByte || data[1] != kGoDiagnosticsGroupWriteService) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const size_t encoded_length = data[2];
|
||||||
|
if (encoded_length < 2 || len != encoded_length + 3) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodedGoDiagnosticsGroupWrite out;
|
||||||
|
out.group_address = ReadBe16(data + 3);
|
||||||
|
out.payload = data + 5;
|
||||||
|
out.payload_len = encoded_length - 2;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsOpenKnxGroupValueWrite(const uint8_t* data, size_t len) {
|
bool IsOpenKnxGroupValueWrite(const uint8_t* data, size_t len) {
|
||||||
return DecodeOpenKnxGroupWrite(data, len).has_value();
|
return DecodeOpenKnxGroupWrite(data, len).has_value();
|
||||||
}
|
}
|
||||||
@@ -705,6 +736,27 @@ std::optional<int> MetadataInt(const DaliBridgeResult& result, const std::string
|
|||||||
return getObjectInt(result.metadata, key);
|
return getObjectInt(result.metadata, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t GoDiagnosticsReturnCode(const DaliBridgeResult& result) {
|
||||||
|
if (result.ok) {
|
||||||
|
return ReturnCodes::Success;
|
||||||
|
}
|
||||||
|
if (getObjectBool(result.metadata, "ignored").value_or(false)) {
|
||||||
|
return ReturnCodes::TemporarilyNotAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& error = result.error;
|
||||||
|
if (error.find("unmapped") != std::string::npos ||
|
||||||
|
error.find("does not match gateway config") != std::string::npos) {
|
||||||
|
return ReturnCodes::AddressVoid;
|
||||||
|
}
|
||||||
|
if (error.find("disabled") != std::string::npos ||
|
||||||
|
error.find("commissioning-only") != std::string::npos ||
|
||||||
|
error.find("not configured") != std::string::npos) {
|
||||||
|
return ReturnCodes::TemporarilyNotAvailable;
|
||||||
|
}
|
||||||
|
return ReturnCodes::GenericError;
|
||||||
|
}
|
||||||
|
|
||||||
std::string HexBytes(const uint8_t* data, size_t len) {
|
std::string HexBytes(const uint8_t* data, size_t len) {
|
||||||
if (data == nullptr || len == 0) {
|
if (data == nullptr || len == 0) {
|
||||||
return {};
|
return {};
|
||||||
@@ -2498,6 +2550,17 @@ esp_err_t GatewayKnxTpIpRouter::initializeRuntime() {
|
|||||||
return bridge_.handleFunctionPropertyState(object_index, property_id, data, len,
|
return bridge_.handleFunctionPropertyState(object_index, property_id, data, len,
|
||||||
response);
|
response);
|
||||||
});
|
});
|
||||||
|
ets_device_->setFunctionPropertyExtHandlers(
|
||||||
|
[this](uint16_t object_type, uint8_t object_instance, uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len, std::vector<uint8_t>* response) {
|
||||||
|
return handleFunctionPropertyExtCommand(object_type, object_instance, property_id,
|
||||||
|
data, len, response);
|
||||||
|
},
|
||||||
|
[this](uint16_t object_type, uint8_t object_instance, uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len, std::vector<uint8_t>* response) {
|
||||||
|
return handleFunctionPropertyExtState(object_type, object_instance, property_id,
|
||||||
|
data, len, response);
|
||||||
|
});
|
||||||
ets_device_->setGroupWriteHandler(
|
ets_device_->setGroupWriteHandler(
|
||||||
[this](uint16_t group_address, const uint8_t* data, size_t len) {
|
[this](uint16_t group_address, const uint8_t* data, size_t len) {
|
||||||
if (!shouldRouteDaliApplicationFrames()) {
|
if (!shouldRouteDaliApplicationFrames()) {
|
||||||
@@ -4266,6 +4329,93 @@ bool GatewayKnxTpIpRouter::routeOpenKnxGroupWrite(const uint8_t* data, size_t le
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GatewayKnxTpIpRouter::handleFunctionPropertyExtCommand(
|
||||||
|
uint16_t object_type, uint8_t object_instance, uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len, std::vector<uint8_t>* response) {
|
||||||
|
if (response == nullptr || object_type != kGroupObjectTableObjectType ||
|
||||||
|
property_id != kPidGoDiagnostics) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto decoded = DecodeGoDiagnosticsGroupWrite(data, len);
|
||||||
|
if (!decoded.has_value()) {
|
||||||
|
const std::string payload = HexBytes(data, len);
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics write malformed objType=0x%04X objInst=%u property=0x%02X len=%u payload=%s",
|
||||||
|
static_cast<unsigned>(object_type), static_cast<unsigned>(object_instance),
|
||||||
|
static_cast<unsigned>(property_id), static_cast<unsigned>(len), payload.c_str());
|
||||||
|
*response = {ReturnCodes::DataVoid};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string group_address_text =
|
||||||
|
GatewayKnxGroupAddressString(decoded->group_address);
|
||||||
|
const std::string payload = HexBytes(decoded->payload, decoded->payload_len);
|
||||||
|
ESP_LOGI(kTag,
|
||||||
|
"OpenKNX GO diagnostics group write ga=0x%04X (%s) len=%u payload=%s",
|
||||||
|
static_cast<unsigned>(decoded->group_address), group_address_text.c_str(),
|
||||||
|
static_cast<unsigned>(decoded->payload_len), payload.c_str());
|
||||||
|
|
||||||
|
if (!shouldRouteDaliApplicationFrames()) {
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics group write ga=0x%04X (%s) blocked by commissioning-only routing state",
|
||||||
|
static_cast<unsigned>(decoded->group_address), group_address_text.c_str());
|
||||||
|
*response = {ReturnCodes::TemporarilyNotAvailable};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DaliBridgeResult result =
|
||||||
|
group_write_handler_ ? group_write_handler_(decoded->group_address, decoded->payload,
|
||||||
|
decoded->payload_len)
|
||||||
|
: bridge_.handleGroupWrite(decoded->group_address,
|
||||||
|
decoded->payload,
|
||||||
|
decoded->payload_len);
|
||||||
|
const uint8_t return_code = GoDiagnosticsReturnCode(result);
|
||||||
|
if (return_code == ReturnCodes::AddressVoid) {
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics group write ga=0x%04X (%s) returning AddressVoid: %s",
|
||||||
|
static_cast<unsigned>(decoded->group_address), group_address_text.c_str(),
|
||||||
|
result.error.empty() ? "unmapped KNX group address"
|
||||||
|
: result.error.c_str());
|
||||||
|
} else if (!result.ok) {
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics group write ga=0x%04X (%s) failed rc=0x%02X: %s",
|
||||||
|
static_cast<unsigned>(decoded->group_address), group_address_text.c_str(),
|
||||||
|
static_cast<unsigned>(return_code),
|
||||||
|
result.error.empty() ? "command routing failed" : result.error.c_str());
|
||||||
|
}
|
||||||
|
response->assign(1, return_code);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GatewayKnxTpIpRouter::handleFunctionPropertyExtState(
|
||||||
|
uint16_t object_type, uint8_t object_instance, uint8_t property_id,
|
||||||
|
const uint8_t* data, size_t len, std::vector<uint8_t>* response) {
|
||||||
|
if (response == nullptr || object_type != kGroupObjectTableObjectType ||
|
||||||
|
property_id != kPidGoDiagnostics) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto decoded = DecodeGoDiagnosticsGroupWrite(data, len);
|
||||||
|
if (!decoded.has_value()) {
|
||||||
|
const std::string payload = HexBytes(data, len);
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics state request malformed objType=0x%04X objInst=%u property=0x%02X len=%u payload=%s",
|
||||||
|
static_cast<unsigned>(object_type), static_cast<unsigned>(object_instance),
|
||||||
|
static_cast<unsigned>(property_id), static_cast<unsigned>(len), payload.c_str());
|
||||||
|
*response = {ReturnCodes::DataVoid};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string group_address_text =
|
||||||
|
GatewayKnxGroupAddressString(decoded->group_address);
|
||||||
|
ESP_LOGW(kTag,
|
||||||
|
"OpenKNX GO diagnostics state request unsupported ga=0x%04X (%s)",
|
||||||
|
static_cast<unsigned>(decoded->group_address), group_address_text.c_str());
|
||||||
|
*response = {ReturnCodes::InvalidCommand};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GatewayKnxTpIpRouter::emitOpenKnxGroupValue(uint16_t group_object_number,
|
bool GatewayKnxTpIpRouter::emitOpenKnxGroupValue(uint16_t group_object_number,
|
||||||
const uint8_t* data, size_t len) {
|
const uint8_t* data, size_t len) {
|
||||||
SemaphoreGuard guard(openknx_lock_);
|
SemaphoreGuard guard(openknx_lock_);
|
||||||
|
|||||||
+1
-1
Submodule knx updated: dac61e2707...af9be62529
Reference in New Issue
Block a user