fix(gateway): update DALI configuration parameters for improved performance and reliability

This commit add comat parameter for some old DALI-1 control gear.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-21 17:03:35 +08:00
parent 0827befb06
commit 20642e5ec3
8 changed files with 239 additions and 73 deletions
+123 -31
View File
@@ -247,6 +247,121 @@ void GatewayKnxBridge::runCommissioningScanTask() {
}
while (!is_cancelled()) {
auto log_and_record_ballast = [&](const GatewayKnxCommissioningBallast& ballast) {
record_ballast(ballast);
ESP_LOGI(kTag, "REG1-Dali scan found random=0x%02X%02X%02X short=%u",
ballast.high, ballast.middle, ballast.low,
static_cast<unsigned>(ballast.short_address));
};
auto withdraw_selected = [&]() {
return SendRaw(engine_, DALI_CMD_SPECIAL_WITHDRAW, DALI_CMD_OFF,
"knx-function-scan-withdraw");
};
auto program_selected_ballast =
[&](uint8_t short_address,
uint32_t fallback_random_address) -> std::optional<GatewayKnxCommissioningBallast> {
if (!ProgramShortAddressAndConfirm(engine_, short_address)) {
return std::nullopt;
}
const auto random_address =
QueryRandomAddressForShortAddress(engine_, short_address).value_or(fallback_random_address);
GatewayKnxCommissioningBallast ballast;
ballast.high = static_cast<uint8_t>((random_address >> 16) & 0xff);
ballast.middle = static_cast<uint8_t>((random_address >> 8) & 0xff);
ballast.low = static_cast<uint8_t>(random_address & 0xff);
ballast.short_address = short_address;
return ballast;
};
if (options.assign) {
const auto next_address = NextFreeShortAddress(used_addresses);
if (!next_address.has_value()) {
ESP_LOGW(kTag, "REG1-Dali scan has no free short address left");
break;
}
const auto compare_base = FindSelectedCommissioningCompareBase(engine_);
if (!compare_base.has_value()) {
break;
}
const auto first_ballast =
program_selected_ballast(next_address.value(), compare_base.value());
if (!first_ballast.has_value()) {
ESP_LOGW(kTag, "REG1-Dali scan failed to program short address %u",
static_cast<unsigned>(next_address.value()));
break;
}
used_addresses[next_address.value()] = true;
log_and_record_ballast(first_ballast.value());
if (is_cancelled()) {
clear_results = true;
break;
}
if (!withdraw_selected()) {
ESP_LOGW(kTag, "REG1-Dali scan failed while withdrawing matched device");
break;
}
auto compare_cursor = IncrementRandomAddress(compare_base.value());
bool compare_multi_failed = false;
while (!is_cancelled() && compare_cursor.has_value()) {
const auto contiguous_short = NextFreeShortAddress(used_addresses);
if (!contiguous_short.has_value()) {
break;
}
const auto next_search = IncrementRandomAddress(compare_cursor.value());
if (!next_search.has_value()) {
break;
}
const auto matched = CompareSelectedSearchAddress(
engine_, next_search.value(), "knx-function-scan-compare-multi");
if (!matched.has_value()) {
compare_multi_failed = true;
break;
}
if (!matched.value()) {
break;
}
compare_cursor = next_search.value();
const auto ballast =
program_selected_ballast(contiguous_short.value(), compare_cursor.value());
if (!ballast.has_value()) {
ESP_LOGW(kTag, "REG1-Dali scan failed to program short address %u",
static_cast<unsigned>(contiguous_short.value()));
compare_multi_failed = true;
break;
}
used_addresses[contiguous_short.value()] = true;
log_and_record_ballast(ballast.value());
if (is_cancelled()) {
clear_results = true;
break;
}
if (!withdraw_selected()) {
ESP_LOGW(kTag, "REG1-Dali scan failed while withdrawing matched device");
compare_multi_failed = true;
break;
}
}
if (compare_multi_failed) {
break;
}
if (is_cancelled()) {
clear_results = true;
break;
}
continue;
}
const auto random_address = FindLowestSelectedRandomAddress(engine_);
if (!random_address.has_value()) {
break;
@@ -258,38 +373,15 @@ void GatewayKnxBridge::runCommissioningScanTask() {
ballast.low = static_cast<uint8_t>(random_address.value() & 0xff);
ballast.short_address = 0xff;
if (options.assign) {
const auto next_address = NextFreeShortAddress(used_addresses);
if (!next_address.has_value()) {
ESP_LOGW(kTag, "REG1-Dali scan has no free short address left for 0x%06x",
static_cast<unsigned>(random_address.value()));
break;
}
if (!SendRaw(engine_, DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS,
DaliComm::toCmdAddr(next_address.value()),
"knx-function-scan-program-short") ||
!VerifyShortAddress(engine_, next_address.value())) {
ESP_LOGW(kTag, "REG1-Dali scan failed to program short address %u",
static_cast<unsigned>(next_address.value()));
break;
}
used_addresses[next_address.value()] = true;
ballast.short_address = next_address.value();
} else {
ballast.short_address = QuerySelectedShortAddress(engine_).value_or(0xff);
}
ballast.short_address = QuerySelectedShortAddress(engine_).value_or(0xff);
record_ballast(ballast);
ESP_LOGI(kTag, "REG1-Dali scan found random=0x%02X%02X%02X short=%u",
ballast.high, ballast.middle, ballast.low,
static_cast<unsigned>(ballast.short_address));
log_and_record_ballast(ballast);
if (is_cancelled()) {
clear_results = true;
break;
}
if (!SendRaw(engine_, DALI_CMD_SPECIAL_WITHDRAW, DALI_CMD_OFF,
"knx-function-scan-withdraw")) {
if (!withdraw_selected()) {
ESP_LOGW(kTag, "REG1-Dali scan failed while withdrawing matched device");
break;
}
@@ -662,12 +754,12 @@ bool GatewayKnxBridge::handleReg1AssignCommand(const uint8_t* data, size_t len,
const uint8_t short_address = data[1] == 99 ? 0xff : data[1];
const bool ok = SendRawExt(engine_, DALI_CMD_SPECIAL_INITIALIZE, 0x00,
"knx-function-assign-init") &&
SendRaw(engine_, DALI_CMD_SPECIAL_SEARCHADDRH, data[2],
"knx-function-assign-search-h") &&
SendRaw(engine_, DALI_CMD_SPECIAL_SEARCHADDRM, data[3],
"knx-function-assign-search-m") &&
SendRaw(engine_, DALI_CMD_SPECIAL_SEARCHADDRL, data[4],
"knx-function-assign-search-l") &&
"knx-function-assign-search-l") &&
SendRaw(engine_, DALI_CMD_SPECIAL_SEARCHADDRM, data[3],
"knx-function-assign-search-m") &&
SendRaw(engine_, DALI_CMD_SPECIAL_SEARCHADDRH, data[2],
"knx-function-assign-search-h") &&
SendRaw(engine_, DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS,
short_address == 0xff ? 0xff : DaliComm::toCmdAddr(short_address),
"knx-function-assign-program") &&
@@ -969,19 +969,16 @@ DaliBridgeResult IgnoredResult(uint16_t group_address, uint16_t group_object_num
}
bool SetSearchAddress(DaliBridgeEngine& engine, uint32_t search_address, const char* sequence) {
return SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRH,
static_cast<uint8_t>((search_address >> 16) & 0xff), sequence) &&
return SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRL,
static_cast<uint8_t>(search_address & 0xff), sequence) &&
SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRM,
static_cast<uint8_t>((search_address >> 8) & 0xff), sequence) &&
SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRL,
static_cast<uint8_t>(search_address & 0xff), sequence);
SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRH,
static_cast<uint8_t>((search_address >> 16) & 0xff), sequence);
}
std::optional<bool> CompareSelectedSearchAddress(DaliBridgeEngine& engine, uint32_t search_address,
const char* sequence) {
if (!SetSearchAddress(engine, search_address, sequence)) {
return std::nullopt;
}
std::optional<bool> CompareCurrentSearchAddress(DaliBridgeEngine& engine,
const char* sequence) {
const auto result = ExecuteRaw(engine, BridgeOperation::query, DALI_CMD_SPECIAL_COMPARE,
DALI_CMD_OFF, sequence);
if (result.ok && result.data.has_value()) {
@@ -989,14 +986,14 @@ std::optional<bool> CompareSelectedSearchAddress(DaliBridgeEngine& engine, uint3
}
if (DaliQueryResultHasStatus(result, "noResponse") ||
DaliQueryResultHasStatus(result, "timeout")) {
ESP_LOGD(kTag, "DALI compare no match seq=%s search=0x%06x status=%s",
sequence == nullptr ? "" : sequence, static_cast<unsigned>(search_address),
ESP_LOGD(kTag, "DALI compare no match seq=%s status=%s",
sequence == nullptr ? "" : sequence,
DaliQueryResultHasStatus(result, "timeout") ? "timeout" : "noResponse");
return false;
}
if (!result.error.empty()) {
ESP_LOGW(kTag, "DALI compare failed seq=%s search=0x%06x error=%s",
sequence == nullptr ? "" : sequence, static_cast<unsigned>(search_address),
ESP_LOGW(kTag, "DALI compare failed seq=%s error=%s",
sequence == nullptr ? "" : sequence,
result.error.c_str());
}
if (!result.ok || !result.data.has_value()) {
@@ -1005,6 +1002,53 @@ std::optional<bool> CompareSelectedSearchAddress(DaliBridgeEngine& engine, uint3
return true;
}
std::optional<bool> CompareSelectedSearchAddress(DaliBridgeEngine& engine, uint32_t search_address,
const char* sequence) {
if (!SetSearchAddress(engine, search_address, sequence)) {
return std::nullopt;
}
return CompareCurrentSearchAddress(engine, sequence);
}
bool SetSearchAddressComponent(DaliBridgeEngine& engine, int typ, uint8_t value,
const char* sequence) {
switch (typ) {
case 1:
return SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRH, value, sequence);
case 2:
return SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRM, value, sequence);
case 3:
return SendRaw(engine, DALI_CMD_SPECIAL_SEARCHADDRL, value, sequence);
default:
return false;
}
}
std::optional<bool> CompareSelectedSearchComponent(DaliBridgeEngine& engine, int typ, int value,
const char* sequence) {
if (!SetSearchAddressComponent(engine, typ, static_cast<uint8_t>(value & 0xff), sequence)) {
return std::nullopt;
}
return CompareCurrentSearchAddress(engine, sequence);
}
std::optional<uint32_t> IncrementRandomAddress(uint32_t random_address) {
if (random_address >= 0x00ffffffu) {
return std::nullopt;
}
return random_address + 1u;
}
std::optional<uint32_t> FindLowestSelectedRandomAddress(DaliBridgeEngine& engine);
std::optional<uint32_t> FindSelectedCommissioningCompareBase(DaliBridgeEngine& engine) {
const auto lowest = FindLowestSelectedRandomAddress(engine);
if (!lowest.has_value()) {
return std::nullopt;
}
return lowest.value() == 0 ? 0u : lowest.value() - 1u;
}
std::optional<uint32_t> FindLowestSelectedRandomAddress(DaliBridgeEngine& engine) {
const auto any = CompareSelectedSearchAddress(engine, 0x00ffffffu,
"knx-function-scan-compare-any");
@@ -1042,13 +1086,42 @@ std::optional<uint8_t> QuerySelectedShortAddress(DaliBridgeEngine& engine) {
return static_cast<uint8_t>((raw.value() >> 1) & 0x3f);
}
bool VerifyShortAddress(DaliBridgeEngine& engine, uint8_t short_address) {
bool VerifySelectedShortAddress(DaliBridgeEngine& engine, uint8_t short_address) {
const auto raw = ExecuteRawQuery(engine, DALI_CMD_SPECIAL_VERIFY_SHORT_ADDRESS,
DaliComm::toCmdAddr(short_address),
"knx-function-scan-verify-short");
return raw.has_value() && raw.value() == 0xff;
}
bool ProgramShortAddressAndConfirm(DaliBridgeEngine& engine, uint8_t short_address) {
if (!SendRaw(engine, DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS,
DaliComm::toCmdAddr(short_address),
"knx-function-scan-program-short")) {
return false;
}
if (VerifySelectedShortAddress(engine, short_address)) {
return true;
}
const auto confirmed = QuerySelectedShortAddress(engine);
return confirmed.has_value() && confirmed.value() == short_address;
}
std::optional<uint32_t> QueryRandomAddressForShortAddress(DaliBridgeEngine& engine,
uint8_t short_address) {
const auto high = QueryShort(engine, short_address, DALI_CMD_QUERY_RANDOM_ADDRESS_H,
"knx-function-scan-query-random-h");
const auto middle = QueryShort(engine, short_address, DALI_CMD_QUERY_RANDOM_ADDRESS_M,
"knx-function-scan-query-random-m");
const auto low = QueryShort(engine, short_address, DALI_CMD_QUERY_RANDOM_ADDRESS_L,
"knx-function-scan-query-random-l");
if (!high.has_value() || !middle.has_value() || !low.has_value()) {
return std::nullopt;
}
return (static_cast<uint32_t>(high.value() & 0xff) << 16) |
(static_cast<uint32_t>(middle.value() & 0xff) << 8) |
static_cast<uint32_t>(low.value() & 0xff);
}
std::array<bool, 64> QueryUsedShortAddresses(DaliBridgeEngine& engine) {
std::array<bool, 64> used{};
for (int short_address = 0; short_address < static_cast<int>(used.size()); ++short_address) {