Add diagnostic bit support to Gateway Modbus

- Introduced new enum value `kShortDiagnosticBit` to `GatewayModbusGeneratedKind`.
- Enhanced `GatewayModbusPoint` and `GatewayModbusPointBinding` structures to include diagnostic snapshot, boolean key, and device type.
- Added new diagnostic bit specifications and updated the corresponding arrays for generated discrete inputs and holding registers.
- Implemented `addGeneratedDiagnosticPoint` function to handle the creation of diagnostic points.
- Updated `rebuildMap` method to include generated diagnostic points during the map rebuilding process.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Tony
2026-05-04 02:26:09 +08:00
parent 694217eb2c
commit 7424b43bdd
13 changed files with 1133 additions and 40 deletions
+156
View File
@@ -466,6 +466,113 @@ std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::baseStatusSnapshot(
uint8_t gateway_id, int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const auto raw_status = channel->dali->base.getStatus(short_address);
if (!raw_status.has_value()) {
return std::nullopt;
}
const DaliStatus status = DaliStatus::fromByte(static_cast<uint8_t>(raw_status.value()));
auto snapshot = MakeSnapshot(gateway_id, short_address, "base_status");
snapshot.ints["rawStatus"] = raw_status.value() & 0xFF;
snapshot.bools["controlGearPresent"] = status.controlGearPresent;
snapshot.bools["lampFailure"] = status.lampFailure;
snapshot.bools["lampPowerOn"] = status.lampPowerOn;
snapshot.bools["limitError"] = status.limitError;
snapshot.bools["fadingCompleted"] = status.fadingCompleted;
snapshot.bools["resetState"] = status.resetState;
snapshot.bools["missingShortAddress"] = status.missingShortAddress;
snapshot.bools["powerSupplyFault"] = status.psFault;
snapshot.bools["psFault"] = status.psFault;
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt1Snapshot(uint8_t gateway_id,
int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const auto detailed = channel->dali->dt1.getDT1TestStatusDetailed(short_address);
if (!detailed.has_value()) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt1");
PutOptionalInt(snapshot, "failureStatusRaw", detailed->failureStatus);
PutOptionalInt(snapshot, "emergencyStatusRaw", detailed->emergencyStatus);
PutOptionalInt(snapshot, "emergencyModeRaw", detailed->emergencyMode);
PutOptionalInt(snapshot, "featuresRaw", detailed->feature);
PutOptionalInt(snapshot, "deviceStatusRaw", detailed->deviceStatus);
snapshot.bools["testInProgress"] = detailed->testInProgress;
snapshot.bools["lampFailure"] = detailed->lampFailure;
snapshot.bools["batteryFailure"] = detailed->batteryFailure;
snapshot.bools["functionTestActive"] = detailed->functionTestActive;
snapshot.bools["durationTestActive"] = detailed->durationTestActive;
snapshot.bools["testDone"] = detailed->testDone;
snapshot.bools["identifyActive"] = detailed->identifyActive;
snapshot.bools["physicalSelectionActive"] = detailed->physicalSelectionActive;
snapshot.bools["circuitFailure"] = detailed->circuitFailure;
snapshot.bools["batteryDurationFailure"] = detailed->batteryDurationFailure;
snapshot.bools["emergencyLampFailure"] = detailed->emergencyLampFailure;
snapshot.bools["functionTestMaxDelayExceeded"] = detailed->functionTestMaxDelayExceeded;
snapshot.bools["durationTestMaxDelayExceeded"] = detailed->durationTestMaxDelayExceeded;
snapshot.bools["functionTestFailed"] = detailed->functionTestFailed;
snapshot.bools["durationTestFailed"] = detailed->durationTestFailed;
snapshot.bools["functionTestResultValid"] = detailed->functionTestResultValid;
snapshot.bools["durationTestResultValid"] = detailed->durationTestResultValid;
snapshot.bools["batteryFullyCharged"] = detailed->batteryFullyCharged;
snapshot.bools["functionTestPending"] = detailed->functionTestPending;
snapshot.bools["durationTestPending"] = detailed->durationTestPending;
snapshot.bools["restModeActive"] = detailed->restModeActive;
snapshot.bools["normalModeActive"] = detailed->normalModeActive;
snapshot.bools["emergencyModeActive"] = detailed->emergencyModeActive;
snapshot.bools["extendedEmergencyModeActive"] = detailed->extendedEmergencyModeActive;
snapshot.bools["hardwiredInhibitActive"] = detailed->hardwiredInhibitActive;
snapshot.bools["hardwiredSwitchOn"] = detailed->hardwiredSwitchOn;
snapshot.bools["supportsAutoTest"] = detailed->supportsAutoTest;
snapshot.bools["supportsAdjustableEmergencyLevel"] = detailed->supportsAdjustableEmergencyLevel;
if (detailed->emergencyStatus.has_value()) {
const DaliDT1EmergencyStatus status(detailed->emergencyStatus.value());
snapshot.bools["inhibitMode"] = status.inhibitMode();
snapshot.bools["functionTestRequestPending"] = status.functionTestRequestPending();
snapshot.bools["durationTestRequestPending"] = status.durationTestRequestPending();
snapshot.bools["identificationActive"] = status.identificationActive();
snapshot.bools["physicallySelected"] = status.physicallySelected();
}
if (detailed->emergencyMode.has_value()) {
const DaliDT1EmergencyMode mode(detailed->emergencyMode.value());
snapshot.bools["functionTestInProgress"] = mode.functionTestInProgress();
snapshot.bools["durationTestInProgress"] = mode.durationTestInProgress();
}
if (detailed->feature.has_value()) {
const DaliDT1Features features(detailed->feature.value());
snapshot.bools["integralEmergencyControlGear"] = features.integralEmergencyControlGear();
snapshot.bools["maintainedControlGear"] = features.maintainedControlGear();
snapshot.bools["switchedMaintainedControlGear"] = features.switchedMaintainedControlGear();
snapshot.bools["autoTestCapability"] = features.autoTestCapability();
snapshot.bools["adjustableEmergencyLevel"] = features.adjustableEmergencyLevel();
snapshot.bools["hardwiredInhibitSupported"] = features.hardwiredInhibitSupported();
snapshot.bools["physicalSelectionSupported"] = features.physicalSelectionSupported();
snapshot.bools["relightInRestModeSupported"] = features.relightInRestModeSupported();
}
if (detailed->deviceStatus.has_value()) {
const DaliDT1DeviceStatus status(detailed->deviceStatus.value());
snapshot.bools["controlGearFailure"] = status.controlGearFailure();
snapshot.bools["controlGearOk"] = status.controlGearOk();
snapshot.bools["lampPoweredByEmergencyGear"] = status.lampPoweredByEmergencyGear();
snapshot.bools["deviceResetState"] = status.resetState();
snapshot.bools["deviceMissingShortAddress"] = status.missingShortAddress();
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt4Snapshot(uint8_t gateway_id,
int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
@@ -506,15 +613,27 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt4Snapshot(uint8_t gateway
snapshot.ints["featuresRaw2"] = features->raw2();
snapshot.ints["featuresRaw3"] = features->raw3();
snapshot.ints["dimmingMethodCode"] = features->dimmingMethodCode();
snapshot.bools["canQueryLoadOverCurrentShutdown"] =
features->canQueryLoadOverCurrentShutdown();
snapshot.bools["canQueryOpenCircuitDetection"] = features->canQueryOpenCircuitDetection();
snapshot.bools["canQueryLoadDecrease"] = features->canQueryLoadDecrease();
snapshot.bools["canQueryLoadIncrease"] = features->canQueryLoadIncrease();
snapshot.bools["canQueryThermalShutdown"] = features->canQueryThermalShutdown();
snapshot.bools["canQueryThermalOverloadReduction"] =
features->canQueryThermalOverloadReduction();
snapshot.bools["canQueryTemperature"] = features->canQueryTemperature();
snapshot.bools["canQuerySupplyVoltage"] = features->canQuerySupplyVoltage();
snapshot.bools["canQuerySupplyFrequency"] = features->canQuerySupplyFrequency();
snapshot.bools["canQueryLoadVoltage"] = features->canQueryLoadVoltage();
snapshot.bools["canQueryLoadCurrent"] = features->canQueryLoadCurrent();
snapshot.bools["canQueryRealLoadPower"] = features->canQueryRealLoadPower();
snapshot.bools["canQueryLoadRating"] = features->canQueryLoadRating();
snapshot.bools["canQueryCurrentOverloadReduction"] =
features->canQueryCurrentOverloadReduction();
snapshot.bools["physicalSelectionSupported"] = features->physicalSelectionSupported();
snapshot.bools["canSelectNonLogarithmicDimmingCurve"] =
features->canSelectNonLogarithmicDimmingCurve();
snapshot.bools["canQueryUnsuitableLoad"] = features->canQueryUnsuitableLoad();
}
if (const auto failure = dt4.getFailureStatus(short_address)) {
snapshot.ints["failureRaw1"] = failure->raw1();
@@ -526,7 +645,10 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt4Snapshot(uint8_t gateway
snapshot.bools["thermalShutdown"] = failure->thermalShutdown();
snapshot.bools["thermalOverloadReduction"] = failure->thermalOverloadReduction();
snapshot.bools["referenceMeasurementFailedStatus"] = failure->referenceMeasurementFailed();
snapshot.bools["loadUnsuitableForSelectedMethod"] =
failure->loadUnsuitableForSelectedMethod();
snapshot.bools["supplyVoltageOutOfLimits"] = failure->supplyVoltageOutOfLimits();
snapshot.bools["supplyFrequencyOutOfLimits"] = failure->supplyFrequencyOutOfLimits();
snapshot.bools["loadVoltageOutOfLimits"] = failure->loadVoltageOutOfLimits();
snapshot.bools["loadCurrentOverloadReduction"] = failure->loadCurrentOverloadReduction();
}
@@ -637,6 +759,40 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt6Snapshot(uint8_t gateway
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt8StatusSnapshot(
uint8_t gateway_id, int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt8_status");
bool has_data = false;
if (const auto status = channel->dali->dt8.getColorStatus(short_address)) {
has_data = true;
snapshot.ints["colorStatusRaw"] = status->raw();
snapshot.bools["xyOutOfRange"] = status->xyOutOfRange();
snapshot.bools["ctOutOfRange"] = status->ctOutOfRange();
snapshot.bools["autoCalibrationActive"] = status->autoCalibrationActive();
snapshot.bools["autoCalibrationSuccess"] = status->autoCalibrationSuccess();
snapshot.bools["xyActive"] = status->xyActive();
snapshot.bools["ctActive"] = status->ctActive();
snapshot.bools["primaryNActive"] = status->primaryNActive();
snapshot.bools["rgbwafActive"] = status->rgbwafActive();
}
if (const auto features = channel->dali->dt8.getColorTypeFeature(short_address)) {
has_data = true;
snapshot.ints["colorTypeFeaturesRaw"] = features->features();
snapshot.ints["primaryCount"] = features->primaryCount();
snapshot.ints["rgbwafChannels"] = features->rgbwafChannels();
snapshot.bools["xyCapable"] = features->xyCapable();
snapshot.bools["ctCapable"] = features->ctCapable();
snapshot.bools["primaryNCapable"] = features->primaryNCapable();
snapshot.bools["rgbwafCapable"] = features->rgbwafCapable();
}
return has_data ? std::optional<DaliDomainSnapshot>(std::move(snapshot)) : std::nullopt;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt8SceneColorReport(
uint8_t gateway_id, int short_address, int scene) const {
const auto* channel = findChannelByGateway(gateway_id);