Enhance DALI device type discovery and query handling

- Introduce DaliDeviceTypeDiscovery struct for managing device type queries.
- Implement discoverDeviceTypes method in DaliBase for improved device type detection.
- Update DaliComm to handle query responses more robustly, including handling multiple device replies.
- Add setDetectedDeviceTypes method in DaliDevice to manage detected device types and capabilities.
This commit is contained in:
Tony
2026-04-25 12:59:16 +08:00
parent bbcfcd11f6
commit 32e7329b3e
7 changed files with 225 additions and 14 deletions
+96
View File
@@ -4,6 +4,19 @@
#include <algorithm>
namespace {
constexpr int kDeviceTypeNone = 0xFE;
constexpr int kDeviceTypeMultiple = 0xFF;
constexpr uint8_t kQueryExtendedVersion = 0xFF;
const std::vector<int>& defaultDeviceTypeFallbackProbeOrder() {
static const std::vector<int> types = {1, 4, 5, 6, 8};
return types;
}
} // namespace
DaliStatus DaliStatus::fromByte(uint8_t status) {
DaliStatus s;
s.controlGearPresent = (status & 0x01) != 0;
@@ -17,6 +30,16 @@ DaliStatus DaliStatus::fromByte(uint8_t status) {
return s;
}
std::optional<int> DaliDeviceTypeDiscovery::primaryType() const {
if (types.empty()) return std::nullopt;
return types.front();
}
std::vector<int> DaliDeviceTypeDiscovery::extraTypes() const {
if (types.size() <= 1) return {};
return std::vector<int>(types.begin() + 1, types.end());
}
DaliBase::DaliBase(DaliComm& comm) : comm_(comm) {}
int64_t DaliBase::mcuTicks() const {
@@ -154,6 +177,40 @@ std::optional<int> DaliBase::getBright(int a) {
std::optional<int> DaliBase::getDeviceType(int a) { return queryCmd(encodeCmdAddr(a), DALI_CMD_QUERY_DEVICE_TYPE); }
std::optional<DaliDeviceTypeDiscovery> DaliBase::discoverDeviceTypes(
int a, const std::vector<int>& fallbackTypes, int maxNextTypes) {
const auto rawQueryType = getDeviceType(a);
if (!rawQueryType.has_value()) return std::nullopt;
DaliDeviceTypeDiscovery discovery;
discovery.rawQueryType = rawQueryType;
const auto addType = [&discovery](int value) {
if (!isRealDeviceTypeValue(value)) return;
if (std::find(discovery.types.begin(), discovery.types.end(), value) == discovery.types.end()) {
discovery.types.push_back(value);
}
};
addType(rawQueryType.value());
if (rawQueryType.value() == kDeviceTypeMultiple) {
const auto enumerated = discoverNextDeviceTypes(a, maxNextTypes);
for (const int type : enumerated) {
addType(type);
}
if (discovery.types.empty()) {
const auto& probeTypes = fallbackTypes.empty() ? defaultDeviceTypeFallbackProbeOrder() : fallbackTypes;
const auto probed = probeSupportedDeviceTypes(a, probeTypes);
for (const int type : probed) {
addType(type);
}
}
}
return discovery;
}
std::optional<int> DaliBase::getPhysicalMinLevel(int a) {
return queryCmd(encodeCmdAddr(a), DALI_CMD_QUERY_PHYSICAL_MINIMUM_LEVEL);
}
@@ -245,6 +302,45 @@ std::optional<int> DaliBase::getFadeRate(int a) {
std::optional<int> DaliBase::getNextDeviceType(int a) { return query(a, DALI_CMD_QUERY_NEXT_DEVICE_TYPE); }
std::vector<int> DaliBase::discoverNextDeviceTypes(int a, int maxNextTypes) {
std::vector<int> types;
types.reserve(std::max(maxNextTypes, 0));
for (int i = 0; i < maxNextTypes; i++) {
const auto next = getNextDeviceType(a);
if (!next.has_value() || !isRealDeviceTypeValue(next.value())) {
break;
}
if (std::find(types.begin(), types.end(), next.value()) != types.end()) {
break;
}
types.push_back(next.value());
}
return types;
}
std::vector<int> DaliBase::probeSupportedDeviceTypes(int a, const std::vector<int>& fallbackTypes) {
std::vector<int> types;
for (const int type : fallbackTypes) {
if (!isRealDeviceTypeValue(type)) continue;
if (std::find(types.begin(), types.end(), type) != types.end()) continue;
if (queryExtendedVersionForDeviceType(a, type).has_value()) {
types.push_back(type);
}
}
return types;
}
std::optional<int> DaliBase::queryExtendedVersionForDeviceType(int a, int deviceType) {
if (!dtSelect(deviceType)) return std::nullopt;
return queryCmd(encodeCmdAddr(a), kQueryExtendedVersion);
}
bool DaliBase::isRealDeviceTypeValue(int value) { return value >= 0 && value < kDeviceTypeNone; }
std::optional<int> DaliBase::getGroupH(int a) { return query(a, DALI_CMD_QUERY_GROUP_8_15); }
std::optional<int> DaliBase::getGroupL(int a) { return query(a, DALI_CMD_QUERY_GROUPS_0_7); }