#include "addr.hpp" #include #include #include #include DaliAddr::DaliAddr(DaliBase& base) : base_(base) {} bool DaliAddr::isAllocAddr() const { return base_.isAllocAddr; } void DaliAddr::setIsAllocAddr(bool value) { base_.isAllocAddr = value; } int DaliAddr::lastAllocAddr() const { return base_.lastAllocAddr; } void DaliAddr::setLastAllocAddr(int value) { base_.lastAllocAddr = value; } void DaliAddr::selectDevice(int address) { base_.selectedAddress = address; } bool DaliAddr::writeAddr(int addr, int newAddr) { const int nAddr = newAddr * 2 + 1; return base_.setDTR(nAddr) && base_.storeDTRAsAddr(addr); } bool DaliAddr::removeAddr(int addr) { return base_.setDTR(0xFF) && base_.storeDTRAsAddr(addr); } bool DaliAddr::removeAllAddr() { return removeAddr(base_.broadcast); } std::vector DaliAddr::searchAddr(int addr) { isSearching = true; onlineDevices.clear(); const int maxAddr = std::clamp(addr, 0, 63); for (int i = 0; i < maxAddr; i++) { if (!isSearching) break; const auto status = base_.getOnlineStatus(i); if (status.has_value() && status.value()) { onlineDevices.push_back(i); } } isSearching = false; return onlineDevices; } std::vector DaliAddr::searchAddrRange(int start, int end) { int s = std::clamp(start, 0, 63); int e = std::clamp(end, 0, 63); if (s > e) return {}; isSearching = true; onlineDevices.clear(); for (int i = s; i <= e; i++) { if (!isSearching) break; const auto status = base_.getOnlineStatus(i); if (status.has_value() && status.value()) { onlineDevices.push_back(i); } } isSearching = false; return onlineDevices; } void DaliAddr::stopSearch() { isSearching = false; } bool DaliAddr::compareSingleAddress(int typ, int addr) { bool ok = false; if (typ == 1) { ok = base_.queryAddressH(addr); } else if (typ == 2) { ok = base_.queryAddressM(addr); } else if (typ == 3) { ok = base_.queryAddressL(addr); } if (!ok) return false; const auto matched = base_.compareAddress(); return matched.has_value() && matched.value(); } std::pair DaliAddr::precompareNew(int typ, int m) { int min = m; int max = 255; while ((max - min) > 6) { const int mid = static_cast((max - min) / 2.0 + min); const bool ok = compareSingleAddress(typ, mid); if (ok) { max = mid; } else { min = mid; } } return {min, max}; } int DaliAddr::compareAddress(int typ) { int min = 0; int max = 255; int vAct = 0; const auto mm = precompareNew(typ); min = mm.first; max = mm.second; std::mt19937 rng(528643246); for (int i = 0; i <= 100; i++) { if (!base_.isAllocAddr) break; if (min >= max) break; std::uniform_int_distribution dist(min, max); const int v = dist(rng); const bool res = compareSingleAddress(typ, v); if (res) { if (v == 0) { vAct = v; compareSingleAddress(typ, v); break; } const bool res2 = compareSingleAddress(typ, v - 1); if (res2) { max = v - 1; } else { vAct = v - 1; compareSingleAddress(typ, v - 1); break; } } else if (v <= 254) { const bool res3 = compareSingleAddress(typ, v + 1); if (res3) { vAct = v; compareSingleAddress(typ, v); break; } min = v + 1; } else { break; } } return vAct; } int DaliAddr::compareAddressNew(int typ, int m) { int minVal = m; int maxVal = 255; int vAct = 0; const auto mm = precompareNew(typ, minVal); minVal = mm.first; maxVal = mm.second; int v = maxVal; for (int i = 0; i <= 10; i++) { const bool ok = compareSingleAddress(typ, v); if (ok) { if (v == 0) { vAct = v; compareSingleAddress(typ, v); break; } const bool ok2 = compareSingleAddress(typ, v - 1); if (ok2) { maxVal = v - 1; } else { vAct = v - 1; compareSingleAddress(typ, v - 1); break; } } } return vAct; } DaliCompareAddrResult DaliAddr::compareAddr(int ad, std::optional /*minH*/, std::optional /*minM*/, std::optional /*minL*/) { DaliCompareAddrResult result; result.nextAddr = ad; if (ad > 63) { result.nextAddr = 63; return result; } base_.compare(128, 0, 0); result.retH = compareAddress(1); result.retM = compareAddress(2); result.retL = compareAddress(3); if (!base_.isAllocAddr) { result.retH = 0; result.retM = 0; result.retL = 0; return result; } if (result.retH == 0 && result.retM == 0 && result.retL == 0) { return result; } const auto res = base_.compare(result.retH, result.retM, result.retL + 1); if (!res.has_value() || !res.value()) { base_.isAllocAddr = false; result.retH = 0; result.retM = 0; result.retL = 0; return result; } while (true) { const auto status = base_.getOnlineStatus(ad); if (!status.has_value() || !status.value()) break; ad++; if (ad > 63) break; } if (!base_.programShortAddr(ad)) return result; const auto qsa = base_.queryShortAddr(); if (qsa.has_value() && qsa.value() == ad) { base_.withdraw(); base_.setBright(ad, 254); } result.nextAddr = ad; return result; } int DaliAddr::compareMulti(int h, int m, int l, int ad) { int addr = ad + 1; int retL = l; int retM = m; int retH = h; for (int i = 0; i < 64; i++) { if (!base_.isAllocAddr) return addr - 1; if (addr > 63) { return addr - 1; } retL++; if (retL > 255) { retL = 0; retM++; if (retM > 255) { retM = 0; retH++; if (retH > 255) { break; } } } const auto ok = base_.compare(retH, retM, retL); if (!ok.has_value() || !ok.value()) { addr--; break; } while (true) { const auto status = base_.getOnlineStatus(addr); if (!status.has_value() || !status.value()) break; addr++; if (addr > 63) { return addr - 1; } } if (!base_.programShortAddr(addr)) continue; const auto qsa = base_.queryShortAddr(); if (qsa.has_value() && qsa.value() == addr) { base_.withdraw(); base_.setBright(addr, 254); addr++; } } return addr; } bool DaliAddr::allocateAllAddr(int ads) { int ad = ads; base_.isAllocAddr = true; base_.lastAllocAddr = 255; for (int i = 0; i <= 80; i++) { if (!base_.isAllocAddr) break; bool anyDevice = false; const auto dev1 = base_.compare(255, 255, 255); if (dev1.has_value() && dev1.value()) { anyDevice = true; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else { const auto dev2 = base_.compare(255, 255, 255); if (dev2.has_value() && dev2.value()) { anyDevice = true; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else { const auto dev3 = base_.compare(255, 255, 255); if (dev3.has_value() && dev3.value()) { anyDevice = true; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } } if (!anyDevice) { break; } const auto retVals = compareAddr(ad, std::nullopt, std::nullopt, std::nullopt); ad = retVals.nextAddr; if (!base_.isAllocAddr) break; if (!(retVals.retH == 0 && retVals.retM == 0 && retVals.retL == 0)) { i = 0; } ad = compareMulti(retVals.retH, retVals.retM, retVals.retL + 1, ad); base_.lastAllocAddr = ad; ad++; if (ad > 63) { base_.isAllocAddr = false; break; } if (i == 80) { base_.isAllocAddr = false; break; } } base_.isAllocAddr = false; if (ad <= 0) { base_.lastAllocAddr = 255; } else { base_.lastAllocAddr = ad - 1; } return true; } void DaliAddr::stopAllocAddr() { base_.isAllocAddr = false; } bool DaliAddr::removeFromScene(int addr, int scene) { const int value = scene + 80; return base_.send(addr, static_cast(value)); } std::optional DaliAddr::getSceneBright(int addr, int scene) { const int value = scene + 176; return base_.query(addr, static_cast(value)); } bool DaliAddr::resetAndAllocAddr(int n, bool removeAddrFirst, bool closeLight) { const int startTime = static_cast(base_.mcuTicks()); base_.isAllocAddr = true; std::this_thread::sleep_for(std::chrono::milliseconds(100)); if (closeLight) { base_.off(base_.broadcast); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (!base_.terminate()) { base_.isAllocAddr = false; return false; } std::this_thread::sleep_for(std::chrono::milliseconds(200)); if (removeAddrFirst) { if (!base_.initialiseAll()) { base_.isAllocAddr = false; return false; } std::this_thread::sleep_for(std::chrono::milliseconds(200)); if (!removeAllAddr()) { base_.isAllocAddr = false; return false; } } else { if (!base_.initialise()) { base_.isAllocAddr = false; return false; } } std::this_thread::sleep_for(std::chrono::milliseconds(500)); if (!base_.randomise()) { base_.isAllocAddr = false; return false; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); if (!base_.randomise()) { base_.isAllocAddr = false; return false; } std::this_thread::sleep_for(std::chrono::milliseconds(300)); const bool ok = allocateAllAddr(n); (void)startTime; return ok; }