diff --git a/CMakeLists.txt b/CMakeLists.txt index c29550c..2933ed8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ idf_component_register( "src/decode.cpp" "src/device.cpp" "src/dt1.cpp" + "src/dt4.cpp" + "src/dt5.cpp" + "src/dt6.cpp" "src/dt8.cpp" "src/sequence.cpp" "src/sequence_store.cpp" diff --git a/include/dali.hpp b/include/dali.hpp index 58964b9..f7e5117 100644 --- a/include/dali.hpp +++ b/include/dali.hpp @@ -11,6 +11,9 @@ #include "decode.hpp" #include "device.hpp" #include "dt1.hpp" +#include "dt4.hpp" +#include "dt5.hpp" +#include "dt6.hpp" #include "dt8.hpp" #include "addr.hpp" #include "gateway_cloud.hpp" @@ -46,11 +49,15 @@ class Dali { DaliBase base; DaliDecode decode; DaliDT1 dt1; + DaliDT4 dt4; + DaliDT5 dt5; + DaliDT6 dt6; DaliDT8 dt8; DaliAddr addr; explicit Dali(DaliComm& comm, int g = 0, const std::string& n = "dali1") - : name(n), gw(g), base(comm), decode(), dt1(base), dt8(base), addr(base) {} + : name(n), gw(g), base(comm), decode(), dt1(base), dt4(base), dt5(base), dt6(base), + dt8(base), addr(base) {} void open() {} void close() {} diff --git a/include/dali_define.hpp b/include/dali_define.hpp index 0c4d2f3..8dd86a2 100644 --- a/include/dali_define.hpp +++ b/include/dali_define.hpp @@ -92,6 +92,65 @@ #define DALI_CMD_SPECIAL_SET_DTR_1 0xC3 #define DALI_CMD_SPECIAL_SET_DTR_2 0xC5 +// DT4 commands and queries +#define DALI_CMD_DT4_REFERENCE_SYSTEM_POWER 0xE0 +#define DALI_CMD_DT4_SELECT_DIMMING_CURVE 0xE1 +#define DALI_CMD_DT4_QUERY_DIMMING_CURVE 0xEE +#define DALI_CMD_DT4_QUERY_DIMMER_STATUS 0xEF +#define DALI_CMD_DT4_QUERY_FEATURES 0xF0 +#define DALI_CMD_DT4_QUERY_FAILURE_STATUS 0xF1 +#define DALI_CMD_DT4_QUERY_DIMMER_TEMPERATURE 0xF2 +#define DALI_CMD_DT4_QUERY_RMS_SUPPLY_VOLTAGE 0xF3 +#define DALI_CMD_DT4_QUERY_SUPPLY_FREQUENCY 0xF4 +#define DALI_CMD_DT4_QUERY_RMS_LOAD_VOLTAGE 0xF5 +#define DALI_CMD_DT4_QUERY_RMS_LOAD_CURRENT 0xF6 +#define DALI_CMD_DT4_QUERY_REAL_LOAD_POWER 0xF7 +#define DALI_CMD_DT4_QUERY_LOAD_RATING 0xF8 +#define DALI_CMD_DT4_QUERY_REFERENCE_RUNNING 0xF9 +#define DALI_CMD_DT4_QUERY_REFERENCE_MEASUREMENT_FAILED 0xFA +#define DALI_CMD_DT4_QUERY_EXTENDED_VERSION 0xFF + +// DT5 commands and queries +#define DALI_CMD_DT5_SET_OUTPUT_RANGE_1_TO_10V 0xE0 +#define DALI_CMD_DT5_SET_OUTPUT_RANGE_0_TO_10V 0xE1 +#define DALI_CMD_DT5_SWITCH_ON_INTERNAL_PULL_UP 0xE2 +#define DALI_CMD_DT5_SWITCH_OFF_INTERNAL_PULL_UP 0xE3 +#define DALI_CMD_DT5_STORE_DTR_AS_PHYSICAL_MINIMUM 0xE4 +#define DALI_CMD_DT5_SELECT_DIMMING_CURVE 0xE5 +#define DALI_CMD_DT5_RESET_CONVERTER_SETTINGS 0xE6 +#define DALI_CMD_DT5_QUERY_DIMMING_CURVE 0xEE +#define DALI_CMD_DT5_QUERY_OUTPUT_LEVEL 0xEF +#define DALI_CMD_DT5_QUERY_CONVERTER_FEATURES 0xF0 +#define DALI_CMD_DT5_QUERY_FAILURE_STATUS 0xF1 +#define DALI_CMD_DT5_QUERY_CONVERTER_STATUS 0xF2 +#define DALI_CMD_DT5_QUERY_EXTENDED_VERSION 0xFF + +// DT6 commands and queries +#define DALI_CMD_DT6_REFERENCE_SYSTEM_POWER 0xE0 +#define DALI_CMD_DT6_ENABLE_CURRENT_PROTECTOR 0xE1 +#define DALI_CMD_DT6_DISABLE_CURRENT_PROTECTOR 0xE2 +#define DALI_CMD_DT6_SELECT_DIMMING_CURVE 0xE3 +#define DALI_CMD_DT6_STORE_DTR_AS_FAST_FADE_TIME 0xE4 +#define DALI_CMD_DT6_QUERY_GEAR_TYPE 0xED +#define DALI_CMD_DT6_QUERY_DIMMING_CURVE 0xEE +#define DALI_CMD_DT6_QUERY_POSSIBLE_OPERATING_MODES 0xEF +#define DALI_CMD_DT6_QUERY_FEATURES 0xF0 +#define DALI_CMD_DT6_QUERY_FAILURE_STATUS 0xF1 +#define DALI_CMD_DT6_QUERY_SHORT_CIRCUIT 0xF2 +#define DALI_CMD_DT6_QUERY_OPEN_CIRCUIT 0xF3 +#define DALI_CMD_DT6_QUERY_LOAD_DECREASE 0xF4 +#define DALI_CMD_DT6_QUERY_LOAD_INCREASE 0xF5 +#define DALI_CMD_DT6_QUERY_CURRENT_PROTECTOR_ACTIVE 0xF6 +#define DALI_CMD_DT6_QUERY_THERMAL_SHUTDOWN 0xF7 +#define DALI_CMD_DT6_QUERY_THERMAL_OVERLOAD 0xF8 +#define DALI_CMD_DT6_QUERY_REFERENCE_RUNNING 0xF9 +#define DALI_CMD_DT6_QUERY_REFERENCE_MEASUREMENT_FAILED 0xFA +#define DALI_CMD_DT6_QUERY_CURRENT_PROTECTOR_ENABLED 0xFB +#define DALI_CMD_DT6_QUERY_OPERATING_MODE 0xFC +#define DALI_CMD_DT6_QUERY_FAST_FADE_TIME 0xFD +#define DALI_CMD_DT6_QUERY_MIN_FAST_FADE_TIME 0xFE +#define DALI_CMD_DT6_QUERY_EXTENDED_VERSION 0xFF + // DT8 commands and queries #define DALI_CMD_DT8_STORE_DTR_AS_COLORX 0xE0 #define DALI_CMD_DT8_STORE_DTR_AS_COLORY 0xE1 diff --git a/include/device.hpp b/include/device.hpp index 58a2fc0..449d19f 100644 --- a/include/device.hpp +++ b/include/device.hpp @@ -17,6 +17,9 @@ struct DaliLongAddress { struct DaliDeviceCapabilities { std::optional supportsDt1; + std::optional supportsDt4; + std::optional supportsDt5; + std::optional supportsDt6; std::optional supportsDt8; static DaliDeviceCapabilities fromJson(const DaliValue::Object* json); diff --git a/include/dt4.hpp b/include/dt4.hpp new file mode 100644 index 0000000..96d0763 --- /dev/null +++ b/include/dt4.hpp @@ -0,0 +1,126 @@ +#pragma once + +#include "base.hpp" + +#include + +class DaliDT4DimmerStatus { + public: + explicit DaliDT4DimmerStatus(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool leadingEdgeModeRunning() const { return bit(0x01); } + bool trailingEdgeModeRunning() const { return bit(0x02); } + bool referenceMeasurementRunning() const { return bit(0x04); } + bool nonLogarithmicDimmingCurveActive() const { return bit(0x10); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT4Features { + public: + DaliDT4Features(int raw1, int raw2, int raw3) + : raw1_(raw1 & 0xFF), raw2_(raw2 & 0xFF), raw3_(raw3 & 0xFF) {} + + int raw1() const { return raw1_; } + int raw2() const { return raw2_; } + int raw3() const { return raw3_; } + + bool canQueryLoadOverCurrentShutdown() const { return bit(raw1_, 0x01); } + bool canQueryOpenCircuitDetection() const { return bit(raw1_, 0x02); } + bool canQueryLoadDecrease() const { return bit(raw1_, 0x04); } + bool canQueryLoadIncrease() const { return bit(raw1_, 0x08); } + bool canQueryThermalShutdown() const { return bit(raw1_, 0x20); } + bool canQueryThermalOverloadReduction() const { return bit(raw1_, 0x40); } + bool physicalSelectionSupported() const { return bit(raw1_, 0x80); } + + bool canQueryTemperature() const { return bit(raw2_, 0x01); } + bool canQuerySupplyVoltage() const { return bit(raw2_, 0x02); } + bool canQuerySupplyFrequency() const { return bit(raw2_, 0x04); } + bool canQueryLoadVoltage() const { return bit(raw2_, 0x08); } + bool canQueryLoadCurrent() const { return bit(raw2_, 0x10); } + bool canQueryRealLoadPower() const { return bit(raw2_, 0x20); } + bool canQueryLoadRating() const { return bit(raw2_, 0x40); } + bool canQueryCurrentOverloadReduction() const { return bit(raw2_, 0x80); } + + bool canSelectNonLogarithmicDimmingCurve() const { return bit(raw3_, 0x08); } + bool canQueryUnsuitableLoad() const { return bit(raw3_, 0x80); } + int dimmingMethodCode() const { return raw3_ & 0x03; } + + private: + int raw1_ = 0; + int raw2_ = 0; + int raw3_ = 0; + + static bool bit(int value, int mask) { return (value & mask) != 0; } +}; + +class DaliDT4FailureStatus { + public: + DaliDT4FailureStatus(int raw1, int raw2) + : raw1_(raw1 & 0xFF), raw2_(raw2 & 0xFF) {} + + int raw1() const { return raw1_; } + int raw2() const { return raw2_; } + + bool loadOverCurrentShutdown() const { return bit(raw1_, 0x01); } + bool openCircuitDetected() const { return bit(raw1_, 0x02); } + bool loadDecreaseDetected() const { return bit(raw1_, 0x04); } + bool loadIncreaseDetected() const { return bit(raw1_, 0x08); } + bool thermalShutdown() const { return bit(raw1_, 0x20); } + bool thermalOverloadReduction() const { return bit(raw1_, 0x40); } + bool referenceMeasurementFailed() const { return bit(raw1_, 0x80); } + + bool loadUnsuitableForSelectedMethod() const { return bit(raw2_, 0x01); } + bool supplyVoltageOutOfLimits() const { return bit(raw2_, 0x02); } + bool supplyFrequencyOutOfLimits() const { return bit(raw2_, 0x04); } + bool loadVoltageOutOfLimits() const { return bit(raw2_, 0x08); } + bool loadCurrentOverloadReduction() const { return bit(raw2_, 0x10); } + + private: + int raw1_ = 0; + int raw2_ = 0; + + static bool bit(int value, int mask) { return (value & mask) != 0; } +}; + +class DaliDT4 { + public: + explicit DaliDT4(DaliBase& base); + + bool enableDT4(); + bool referenceSystemPower(int a); + bool selectDimmingCurve(int a, int curve); + + std::optional getDimmingCurve(int a); + std::optional getDimmerStatus(int a); + std::optional getFeatures(int a); + std::optional getFailureStatus(int a); + std::optional getDimmerTemperatureRaw(int a); + std::optional getDimmerTemperatureCelsius(int a); + std::optional getRmsSupplyVoltageRaw(int a); + std::optional getRmsSupplyVoltageVolts(int a); + std::optional getSupplyFrequencyRaw(int a); + std::optional getSupplyFrequencyHertz(int a); + std::optional getRmsLoadVoltageRaw(int a); + std::optional getRmsLoadVoltageVolts(int a); + std::optional getRmsLoadCurrentRaw(int a); + std::optional getRmsLoadCurrentPercent(int a); + std::optional getRealLoadPowerRaw(int a); + std::optional getRealLoadPowerWatts(int a); + std::optional getLoadRatingRaw(int a); + std::optional getLoadRatingAmps(int a); + std::optional isReferenceRunning(int a); + std::optional isReferenceMeasurementFailed(int a); + std::optional getExtendedVersion(int a); + + private: + DaliBase& base_; + + bool enable(); + static int addrOf(int a); + std::optional query(int a, int code); + std::optional queryYesNo(int a, int code); +}; \ No newline at end of file diff --git a/include/dt5.hpp b/include/dt5.hpp new file mode 100644 index 0000000..74445b9 --- /dev/null +++ b/include/dt5.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "base.hpp" + +#include + +class DaliDT5ConverterFeatures { + public: + explicit DaliDT5ConverterFeatures(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool outputRange0To10VSelectable() const { return bit(0x01); } + bool internalPullUpSelectable() const { return bit(0x02); } + bool outputFaultDetectionSelectable() const { return bit(0x04); } + bool mainsRelay() const { return bit(0x08); } + bool outputLevelQueryable() const { return bit(0x10); } + bool nonLogarithmicDimmingCurveSupported() const { return bit(0x20); } + bool physicalSelectionByOutputLossSupported() const { return bit(0x40); } + bool physicalSelectionSwitchSupported() const { return bit(0x80); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT5FailureStatus { + public: + explicit DaliDT5FailureStatus(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool outputFaultDetected() const { return (raw_ & 0x01) != 0; } + + private: + int raw_ = 0; +}; + +class DaliDT5ConverterStatus { + public: + explicit DaliDT5ConverterStatus(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool zeroToTenVoltOperation() const { return (raw_ & 0x01) != 0; } + bool internalPullUpOn() const { return (raw_ & 0x02) != 0; } + bool nonLogarithmicDimmingCurveActive() const { return (raw_ & 0x04) != 0; } + + private: + int raw_ = 0; +}; + +class DaliDT5 { + public: + explicit DaliDT5(DaliBase& base); + + bool enableDT5(); + bool setOutputRange1To10V(int a); + bool setOutputRange0To10V(int a); + bool switchOnInternalPullUp(int a); + bool switchOffInternalPullUp(int a); + bool storePhysicalMinimum(int a, int level); + bool selectDimmingCurve(int a, int curve); + bool resetConverterSettings(int a); + + std::optional getDimmingCurve(int a); + std::optional getOutputLevelRaw(int a); + std::optional getOutputLevelVolts(int a); + std::optional getConverterFeatures(int a); + std::optional getFailureStatus(int a); + std::optional getConverterStatus(int a); + std::optional getExtendedVersion(int a); + + private: + DaliBase& base_; + + bool enable(); + static int addrOf(int a); + bool send(int a, int code, bool twice = false); + std::optional query(int a, int code); +}; \ No newline at end of file diff --git a/include/dt6.hpp b/include/dt6.hpp new file mode 100644 index 0000000..adf1d49 --- /dev/null +++ b/include/dt6.hpp @@ -0,0 +1,130 @@ +#pragma once + +#include "base.hpp" + +#include + +class DaliDT6GearType { + public: + explicit DaliDT6GearType(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool ledPowerSupplyIntegrated() const { return bit(0x01); } + bool ledModuleIntegrated() const { return bit(0x02); } + bool acSupplyPossible() const { return bit(0x04); } + bool dcSupplyPossible() const { return bit(0x08); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT6OperatingModes { + public: + explicit DaliDT6OperatingModes(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool pwmModePossible() const { return bit(0x01); } + bool amModePossible() const { return bit(0x02); } + bool currentControlledOutput() const { return bit(0x04); } + bool highCurrentPulseMode() const { return bit(0x08); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT6Features { + public: + explicit DaliDT6Features(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool canQueryShortCircuit() const { return bit(0x01); } + bool canQueryOpenCircuit() const { return bit(0x02); } + bool canQueryLoadDecrease() const { return bit(0x04); } + bool canQueryLoadIncrease() const { return bit(0x08); } + bool canQueryCurrentProtector() const { return bit(0x10); } + bool canQueryThermalShutdown() const { return bit(0x20); } + bool canQueryThermalOverloadReduction() const { return bit(0x40); } + bool physicalSelectionSupported() const { return bit(0x80); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT6FailureStatus { + public: + explicit DaliDT6FailureStatus(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool shortCircuit() const { return bit(0x01); } + bool openCircuit() const { return bit(0x02); } + bool loadDecrease() const { return bit(0x04); } + bool loadIncrease() const { return bit(0x08); } + bool currentProtectorActive() const { return bit(0x10); } + bool thermalShutdown() const { return bit(0x20); } + bool thermalOverloadReduction() const { return bit(0x40); } + bool referenceMeasurementFailed() const { return bit(0x80); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT6OperatingMode { + public: + explicit DaliDT6OperatingMode(int raw) : raw_(raw & 0xFF) {} + + int raw() const { return raw_; } + bool pwmModeActive() const { return bit(0x01); } + bool amModeActive() const { return bit(0x02); } + bool currentControlledOutput() const { return bit(0x04); } + bool highCurrentPulseModeActive() const { return bit(0x08); } + bool nonLogarithmicDimmingCurveActive() const { return bit(0x10); } + + private: + int raw_ = 0; + bool bit(int mask) const { return (raw_ & mask) != 0; } +}; + +class DaliDT6 { + public: + explicit DaliDT6(DaliBase& base); + + bool enableDT6(); + bool referenceSystemPower(int a); + bool enableCurrentProtector(int a); + bool disableCurrentProtector(int a); + bool selectDimmingCurve(int a, int curve); + bool storeFastFadeTime(int a, int value); + + std::optional getGearType(int a); + std::optional getDimmingCurve(int a); + std::optional getPossibleOperatingModes(int a); + std::optional getFeatures(int a); + std::optional getFailureStatus(int a); + std::optional hasShortCircuit(int a); + std::optional hasOpenCircuit(int a); + std::optional hasLoadDecrease(int a); + std::optional hasLoadIncrease(int a); + std::optional isCurrentProtectorActive(int a); + std::optional hasThermalShutDown(int a); + std::optional hasThermalOverload(int a); + std::optional isReferenceRunning(int a); + std::optional isReferenceMeasurementFailed(int a); + std::optional isCurrentProtectorEnabled(int a); + std::optional getOperatingMode(int a); + std::optional getFastFadeTime(int a); + std::optional getMinFastFadeTime(int a); + std::optional getExtendedVersion(int a); + + private: + DaliBase& base_; + + bool enable(); + static int addrOf(int a); + bool send(int a, int code, bool twice = false); + std::optional query(int a, int code); + std::optional queryYesNo(int a, int code); +}; \ No newline at end of file diff --git a/src/decode.cpp b/src/decode.cpp index bf08dd0..2b47831 100644 --- a/src/decode.cpp +++ b/src/decode.cpp @@ -383,7 +383,10 @@ std::string DaliDecode::whoLabel(int addr, bool even) { std::string DaliDecode::deviceTypeName(int v) { static const std::map map = {{0x00, "general control gear"}, {0x01, "self-contained emergency"}, + {0x04, "incandescent/halogen"}, + {0x05, "converter (0/1-10 V)"}, {0x06, "LED control gear"}, + {0x07, "switching / OLED control gear"}, {0x08, "colour control (DT8)"}}; const auto it = map.find(v); return it == map.end() ? "" : it->second; diff --git a/src/device.cpp b/src/device.cpp index d424e03..40e7338 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -49,6 +49,9 @@ DaliDeviceCapabilities DaliDeviceCapabilities::fromJson(const DaliValue::Object* DaliDeviceCapabilities c; if (!json) return c; c.supportsDt1 = getObjectBool(*json, "dt1"); + c.supportsDt4 = getObjectBool(*json, "dt4"); + c.supportsDt5 = getObjectBool(*json, "dt5"); + c.supportsDt6 = getObjectBool(*json, "dt6"); c.supportsDt8 = getObjectBool(*json, "dt8"); return c; } @@ -56,12 +59,18 @@ DaliDeviceCapabilities DaliDeviceCapabilities::fromJson(const DaliValue::Object* DaliValue::Object DaliDeviceCapabilities::toJson() const { DaliValue::Object out; if (supportsDt1.has_value()) out["dt1"] = supportsDt1.value(); + if (supportsDt4.has_value()) out["dt4"] = supportsDt4.value(); + if (supportsDt5.has_value()) out["dt5"] = supportsDt5.value(); + if (supportsDt6.has_value()) out["dt6"] = supportsDt6.value(); if (supportsDt8.has_value()) out["dt8"] = supportsDt8.value(); return out; } void DaliDeviceCapabilities::merge(const DaliDeviceCapabilities& other) { if (!supportsDt1.has_value()) supportsDt1 = other.supportsDt1; + if (!supportsDt4.has_value()) supportsDt4 = other.supportsDt4; + if (!supportsDt5.has_value()) supportsDt5 = other.supportsDt5; + if (!supportsDt6.has_value()) supportsDt6 = other.supportsDt6; if (!supportsDt8.has_value()) supportsDt8 = other.supportsDt8; } diff --git a/src/dt4.cpp b/src/dt4.cpp new file mode 100644 index 0000000..ad6745a --- /dev/null +++ b/src/dt4.cpp @@ -0,0 +1,147 @@ +#include "dt4.hpp" + +#include "dali_define.hpp" + +#include + +DaliDT4::DaliDT4(DaliBase& base) : base_(base) {} + +bool DaliDT4::enable() { return base_.dtSelect(4); } + +int DaliDT4::addrOf(int a) { return a * 2 + 1; } + +std::optional DaliDT4::query(int a, int code) { + if (!enable()) return std::nullopt; + return base_.queryCmd(static_cast(addrOf(a)), static_cast(code)); +} + +std::optional DaliDT4::queryYesNo(int a, int code) { + const auto value = query(a, code); + if (!value.has_value()) return std::nullopt; + return value.value() != 0; +} + +bool DaliDT4::enableDT4() { return enable(); } + +bool DaliDT4::referenceSystemPower(int a) { + return enable() && base_.sendExtCmd(addrOf(a), DALI_CMD_DT4_REFERENCE_SYSTEM_POWER) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT4_REFERENCE_SYSTEM_POWER); +} + +bool DaliDT4::selectDimmingCurve(int a, int curve) { + const int value = std::clamp(curve, 0, 255); + return enable() && base_.setDTR(value) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT4_SELECT_DIMMING_CURVE) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT4_SELECT_DIMMING_CURVE); +} + +std::optional DaliDT4::getDimmingCurve(int a) { return query(a, DALI_CMD_DT4_QUERY_DIMMING_CURVE); } + +std::optional DaliDT4::getDimmerStatus(int a) { + const auto raw = query(a, DALI_CMD_DT4_QUERY_DIMMER_STATUS); + if (!raw.has_value()) return std::nullopt; + return DaliDT4DimmerStatus(raw.value()); +} + +std::optional DaliDT4::getFeatures(int a) { + const auto raw1 = query(a, DALI_CMD_DT4_QUERY_FEATURES); + if (!raw1.has_value()) return std::nullopt; + const auto raw2 = base_.getDTR(a); + const auto raw3 = base_.getDTR1(a); + if (!raw2.has_value() || !raw3.has_value()) return std::nullopt; + return DaliDT4Features(raw1.value(), raw2.value(), raw3.value()); +} + +std::optional DaliDT4::getFailureStatus(int a) { + const auto raw1 = query(a, DALI_CMD_DT4_QUERY_FAILURE_STATUS); + if (!raw1.has_value()) return std::nullopt; + const auto raw2 = base_.getDTR1(a); + if (!raw2.has_value()) return std::nullopt; + return DaliDT4FailureStatus(raw1.value(), raw2.value()); +} + +std::optional DaliDT4::getDimmerTemperatureRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_DIMMER_TEMPERATURE); +} + +std::optional DaliDT4::getDimmerTemperatureCelsius(int a) { + const auto raw = getDimmerTemperatureRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() - 40; +} + +std::optional DaliDT4::getRmsSupplyVoltageRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_RMS_SUPPLY_VOLTAGE); +} + +std::optional DaliDT4::getRmsSupplyVoltageVolts(int a) { + const auto raw = getRmsSupplyVoltageRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 2.0; +} + +std::optional DaliDT4::getSupplyFrequencyRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_SUPPLY_FREQUENCY); +} + +std::optional DaliDT4::getSupplyFrequencyHertz(int a) { + const auto raw = getSupplyFrequencyRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 0.5; +} + +std::optional DaliDT4::getRmsLoadVoltageRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_RMS_LOAD_VOLTAGE); +} + +std::optional DaliDT4::getRmsLoadVoltageVolts(int a) { + const auto raw = getRmsLoadVoltageRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 2.0; +} + +std::optional DaliDT4::getRmsLoadCurrentRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_RMS_LOAD_CURRENT); +} + +std::optional DaliDT4::getRmsLoadCurrentPercent(int a) { + const auto raw = getRmsLoadCurrentRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 0.5; +} + +std::optional DaliDT4::getRealLoadPowerRaw(int a) { + const auto high = query(a, DALI_CMD_DT4_QUERY_REAL_LOAD_POWER); + if (!high.has_value()) return std::nullopt; + const auto low = base_.getDTR(a); + if (!low.has_value()) return std::nullopt; + return ((high.value() & 0xFF) << 8) | (low.value() & 0xFF); +} + +std::optional DaliDT4::getRealLoadPowerWatts(int a) { + const auto raw = getRealLoadPowerRaw(a); + if (!raw.has_value() || raw.value() == 0xFFFF) return std::nullopt; + return raw.value() * 0.25; +} + +std::optional DaliDT4::getLoadRatingRaw(int a) { + return query(a, DALI_CMD_DT4_QUERY_LOAD_RATING); +} + +std::optional DaliDT4::getLoadRatingAmps(int a) { + const auto raw = getLoadRatingRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 0.15; +} + +std::optional DaliDT4::isReferenceRunning(int a) { + return queryYesNo(a, DALI_CMD_DT4_QUERY_REFERENCE_RUNNING); +} + +std::optional DaliDT4::isReferenceMeasurementFailed(int a) { + return queryYesNo(a, DALI_CMD_DT4_QUERY_REFERENCE_MEASUREMENT_FAILED); +} + +std::optional DaliDT4::getExtendedVersion(int a) { + return query(a, DALI_CMD_DT4_QUERY_EXTENDED_VERSION); +} \ No newline at end of file diff --git a/src/dt5.cpp b/src/dt5.cpp new file mode 100644 index 0000000..74b689e --- /dev/null +++ b/src/dt5.cpp @@ -0,0 +1,93 @@ +#include "dt5.hpp" + +#include "dali_define.hpp" + +#include + +DaliDT5::DaliDT5(DaliBase& base) : base_(base) {} + +bool DaliDT5::enable() { return base_.dtSelect(5); } + +int DaliDT5::addrOf(int a) { return a * 2 + 1; } + +bool DaliDT5::send(int a, int code, bool twice) { + if (!enable()) return false; + if (!base_.sendExtCmd(addrOf(a), code)) return false; + if (twice && !base_.sendExtCmd(addrOf(a), code)) return false; + return true; +} + +std::optional DaliDT5::query(int a, int code) { + if (!enable()) return std::nullopt; + return base_.queryCmd(static_cast(addrOf(a)), static_cast(code)); +} + +bool DaliDT5::enableDT5() { return enable(); } + +bool DaliDT5::setOutputRange1To10V(int a) { + return send(a, DALI_CMD_DT5_SET_OUTPUT_RANGE_1_TO_10V, true); +} + +bool DaliDT5::setOutputRange0To10V(int a) { + return send(a, DALI_CMD_DT5_SET_OUTPUT_RANGE_0_TO_10V, true); +} + +bool DaliDT5::switchOnInternalPullUp(int a) { + return send(a, DALI_CMD_DT5_SWITCH_ON_INTERNAL_PULL_UP, true); +} + +bool DaliDT5::switchOffInternalPullUp(int a) { + return send(a, DALI_CMD_DT5_SWITCH_OFF_INTERNAL_PULL_UP, true); +} + +bool DaliDT5::storePhysicalMinimum(int a, int level) { + const int value = std::clamp(level, 0, 254); + return enable() && base_.setDTR(value) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT5_STORE_DTR_AS_PHYSICAL_MINIMUM) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT5_STORE_DTR_AS_PHYSICAL_MINIMUM); +} + +bool DaliDT5::selectDimmingCurve(int a, int curve) { + const int value = std::clamp(curve, 0, 255); + return enable() && base_.setDTR(value) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT5_SELECT_DIMMING_CURVE) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT5_SELECT_DIMMING_CURVE); +} + +bool DaliDT5::resetConverterSettings(int a) { + return send(a, DALI_CMD_DT5_RESET_CONVERTER_SETTINGS, true); +} + +std::optional DaliDT5::getDimmingCurve(int a) { return query(a, DALI_CMD_DT5_QUERY_DIMMING_CURVE); } + +std::optional DaliDT5::getOutputLevelRaw(int a) { + return query(a, DALI_CMD_DT5_QUERY_OUTPUT_LEVEL); +} + +std::optional DaliDT5::getOutputLevelVolts(int a) { + const auto raw = getOutputLevelRaw(a); + if (!raw.has_value() || raw.value() == 0xFF) return std::nullopt; + return raw.value() * 0.04; +} + +std::optional DaliDT5::getConverterFeatures(int a) { + const auto raw = query(a, DALI_CMD_DT5_QUERY_CONVERTER_FEATURES); + if (!raw.has_value()) return std::nullopt; + return DaliDT5ConverterFeatures(raw.value()); +} + +std::optional DaliDT5::getFailureStatus(int a) { + const auto raw = query(a, DALI_CMD_DT5_QUERY_FAILURE_STATUS); + if (!raw.has_value()) return std::nullopt; + return DaliDT5FailureStatus(raw.value()); +} + +std::optional DaliDT5::getConverterStatus(int a) { + const auto raw = query(a, DALI_CMD_DT5_QUERY_CONVERTER_STATUS); + if (!raw.has_value()) return std::nullopt; + return DaliDT5ConverterStatus(raw.value()); +} + +std::optional DaliDT5::getExtendedVersion(int a) { + return query(a, DALI_CMD_DT5_QUERY_EXTENDED_VERSION); +} \ No newline at end of file diff --git a/src/dt6.cpp b/src/dt6.cpp new file mode 100644 index 0000000..df1f527 --- /dev/null +++ b/src/dt6.cpp @@ -0,0 +1,139 @@ +#include "dt6.hpp" + +#include "dali_define.hpp" + +#include + +DaliDT6::DaliDT6(DaliBase& base) : base_(base) {} + +bool DaliDT6::enable() { return base_.dtSelect(6); } + +int DaliDT6::addrOf(int a) { return a * 2 + 1; } + +bool DaliDT6::send(int a, int code, bool twice) { + if (!enable()) return false; + if (!base_.sendExtCmd(addrOf(a), code)) return false; + if (twice && !base_.sendExtCmd(addrOf(a), code)) return false; + return true; +} + +std::optional DaliDT6::query(int a, int code) { + if (!enable()) return std::nullopt; + return base_.queryCmd(static_cast(addrOf(a)), static_cast(code)); +} + +std::optional DaliDT6::queryYesNo(int a, int code) { + const auto value = query(a, code); + if (!value.has_value()) return std::nullopt; + return value.value() != 0; +} + +bool DaliDT6::enableDT6() { return enable(); } + +bool DaliDT6::referenceSystemPower(int a) { + return send(a, DALI_CMD_DT6_REFERENCE_SYSTEM_POWER, true); +} + +bool DaliDT6::enableCurrentProtector(int a) { + return send(a, DALI_CMD_DT6_ENABLE_CURRENT_PROTECTOR, true); +} + +bool DaliDT6::disableCurrentProtector(int a) { + return send(a, DALI_CMD_DT6_DISABLE_CURRENT_PROTECTOR, true); +} + +bool DaliDT6::selectDimmingCurve(int a, int curve) { + const int value = std::clamp(curve, 0, 255); + return enable() && base_.setDTR(value) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT6_SELECT_DIMMING_CURVE) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT6_SELECT_DIMMING_CURVE); +} + +bool DaliDT6::storeFastFadeTime(int a, int value) { + const int clamped = std::clamp(value, 0, 27); + return enable() && base_.setDTR(clamped) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT6_STORE_DTR_AS_FAST_FADE_TIME) && + base_.sendExtCmd(addrOf(a), DALI_CMD_DT6_STORE_DTR_AS_FAST_FADE_TIME); +} + +std::optional DaliDT6::getGearType(int a) { + const auto raw = query(a, DALI_CMD_DT6_QUERY_GEAR_TYPE); + if (!raw.has_value()) return std::nullopt; + return DaliDT6GearType(raw.value()); +} + +std::optional DaliDT6::getDimmingCurve(int a) { return query(a, DALI_CMD_DT6_QUERY_DIMMING_CURVE); } + +std::optional DaliDT6::getPossibleOperatingModes(int a) { + const auto raw = query(a, DALI_CMD_DT6_QUERY_POSSIBLE_OPERATING_MODES); + if (!raw.has_value()) return std::nullopt; + return DaliDT6OperatingModes(raw.value()); +} + +std::optional DaliDT6::getFeatures(int a) { + const auto raw = query(a, DALI_CMD_DT6_QUERY_FEATURES); + if (!raw.has_value()) return std::nullopt; + return DaliDT6Features(raw.value()); +} + +std::optional DaliDT6::getFailureStatus(int a) { + const auto raw = query(a, DALI_CMD_DT6_QUERY_FAILURE_STATUS); + if (!raw.has_value()) return std::nullopt; + return DaliDT6FailureStatus(raw.value()); +} + +std::optional DaliDT6::hasShortCircuit(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_SHORT_CIRCUIT); +} + +std::optional DaliDT6::hasOpenCircuit(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_OPEN_CIRCUIT); +} + +std::optional DaliDT6::hasLoadDecrease(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_LOAD_DECREASE); +} + +std::optional DaliDT6::hasLoadIncrease(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_LOAD_INCREASE); +} + +std::optional DaliDT6::isCurrentProtectorActive(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_CURRENT_PROTECTOR_ACTIVE); +} + +std::optional DaliDT6::hasThermalShutDown(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_THERMAL_SHUTDOWN); +} + +std::optional DaliDT6::hasThermalOverload(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_THERMAL_OVERLOAD); +} + +std::optional DaliDT6::isReferenceRunning(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_REFERENCE_RUNNING); +} + +std::optional DaliDT6::isReferenceMeasurementFailed(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_REFERENCE_MEASUREMENT_FAILED); +} + +std::optional DaliDT6::isCurrentProtectorEnabled(int a) { + return queryYesNo(a, DALI_CMD_DT6_QUERY_CURRENT_PROTECTOR_ENABLED); +} + +std::optional DaliDT6::getOperatingMode(int a) { + const auto raw = query(a, DALI_CMD_DT6_QUERY_OPERATING_MODE); + if (!raw.has_value()) return std::nullopt; + return DaliDT6OperatingMode(raw.value()); +} + +std::optional DaliDT6::getFastFadeTime(int a) { return query(a, DALI_CMD_DT6_QUERY_FAST_FADE_TIME); } + +std::optional DaliDT6::getMinFastFadeTime(int a) { + return query(a, DALI_CMD_DT6_QUERY_MIN_FAST_FADE_TIME); +} + +std::optional DaliDT6::getExtendedVersion(int a) { + return query(a, DALI_CMD_DT6_QUERY_EXTENDED_VERSION); +} \ No newline at end of file