ac73febc9c
Signed-off-by: Tony <tonylu@tony-cloud.com>
406 lines
9.4 KiB
C++
406 lines
9.4 KiB
C++
#include "addr.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <random>
|
|
#include <thread>
|
|
|
|
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<int> 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<int> 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<int, int> DaliAddr::precompareNew(int typ, int m) {
|
|
int min = m;
|
|
int max = 255;
|
|
while ((max - min) > 6) {
|
|
const int mid = static_cast<int>((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<int> 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<int> /*minH*/,
|
|
std::optional<int> /*minM*/, std::optional<int> /*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<uint8_t>(value));
|
|
}
|
|
|
|
std::optional<int> DaliAddr::getSceneBright(int addr, int scene) {
|
|
const int value = scene + 176;
|
|
return base_.query(addr, static_cast<uint8_t>(value));
|
|
}
|
|
|
|
bool DaliAddr::resetAndAllocAddr(int n, bool removeAddrFirst, bool closeLight) {
|
|
const int startTime = static_cast<int>(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;
|
|
}
|