605 lines
22 KiB
C++
605 lines
22 KiB
C++
#include "dt8.hpp"
|
|
|
|
#include "dali_define.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace {
|
|
int colourTempLimitQuerySelector(int limitType) {
|
|
switch (limitType & 0xFF) {
|
|
case 0:
|
|
return 128;
|
|
case 1:
|
|
return 130;
|
|
case 2:
|
|
return 129;
|
|
case 3:
|
|
return 131;
|
|
default:
|
|
return (limitType & 0x01) == 0 ? 128 : 130;
|
|
}
|
|
}
|
|
|
|
std::optional<int> kelvinFromMirek(std::optional<int> mirek) {
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
} // namespace
|
|
|
|
DaliDT8::DaliDT8(DaliBase& base) : base_(base) {}
|
|
|
|
bool DaliDT8::enableDT8() { return base_.dtSelect(8); }
|
|
|
|
std::optional<ColorTypeFeature> DaliDT8::getColorTypeFeature(int a) {
|
|
const auto addr = DaliComm::toCmdAddr(a);
|
|
base_.dtSelect(8);
|
|
const auto result = base_.queryCmd(addr, DALI_CMD_QUERY_COLOR_TYPE);
|
|
if (!result.has_value()) return std::nullopt;
|
|
return ColorTypeFeature(result.value());
|
|
}
|
|
|
|
std::optional<ColorStatus> DaliDT8::getColorStatus(int a) {
|
|
const auto addr = DaliComm::toCmdAddr(a);
|
|
base_.dtSelect(8);
|
|
const auto result = base_.queryCmd(addr, DALI_CMD_QUERY_COLOR_STATUS);
|
|
if (!result.has_value()) return std::nullopt;
|
|
return ColorStatus(result.value());
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getColTempRaw(int a, int type) {
|
|
int selector;
|
|
switch (type) {
|
|
case 0:
|
|
selector = 128;
|
|
break;
|
|
case 1:
|
|
selector = 130;
|
|
break;
|
|
case 3:
|
|
selector = 129;
|
|
break;
|
|
case 4:
|
|
selector = 131;
|
|
break;
|
|
case 2:
|
|
default:
|
|
selector = 2;
|
|
break;
|
|
}
|
|
const auto features = getColorTypeFeature(a);
|
|
if (!features.has_value() || !features->ctCapable()) return 0;
|
|
const auto v = getColourRaw(a, selector);
|
|
if (!v.has_value()) return 0;
|
|
return v.value();
|
|
}
|
|
|
|
bool DaliDT8::setColTempRaw(int a, int value) {
|
|
int v = value;
|
|
if (v < 0) v = 0;
|
|
if (v > 65535) v = 65535;
|
|
const int dtr = v & 0xFF;
|
|
const int dtr1 = (v >> 8) & 0xFF;
|
|
|
|
if (!base_.setDTR(dtr)) return false;
|
|
if (!base_.setDTR1(dtr1)) return false;
|
|
if (!base_.dtSelect(8)) return false;
|
|
if (!base_.setDTRAsColourTemp(a)) return false;
|
|
if (!base_.dtSelect(8)) return false;
|
|
return base_.activate(a);
|
|
}
|
|
|
|
bool DaliDT8::setColorTemperature(int addr, int kelvin) {
|
|
int v = kelvin == 0 ? 1 : kelvin;
|
|
const int mirek = static_cast<int>(std::floor(1000000.0 / static_cast<double>(v)));
|
|
return setColTempRaw(addr, mirek);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getColorTemperature(int a) {
|
|
const auto mirek = getColourRaw(a, 2);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
const int kelvin = static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
return kelvin;
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getMinColorTemperature(int a) {
|
|
const auto mirek = getColTempRaw(a, 0);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getMaxColorTemperature(int a) {
|
|
const auto mirek = getColTempRaw(a, 1);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getPhysicalMinColorTemperature(int a) {
|
|
const auto mirek = getColTempRaw(a, 3);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getPhysicalMaxColorTemperature(int a) {
|
|
const auto mirek = getColTempRaw(a, 4);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getColourTempLimitRaw(int address, int limitType) {
|
|
return getColourRaw(address, colourTempLimitQuerySelector(limitType));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getColourTempLimit(int address, int limitType) {
|
|
return kelvinFromMirek(getColourTempLimitRaw(address, limitType));
|
|
}
|
|
|
|
bool DaliDT8::setColourRaw(int addr, int x1, int y1) {
|
|
const int x1L = x1 & 0xFF;
|
|
const int y1L = y1 & 0xFF;
|
|
const int x1H = (x1 >> 8) & 0xFF;
|
|
const int y1H = (y1 >> 8) & 0xFF;
|
|
|
|
const int a = addr / 2;
|
|
if (!base_.setDTR(x1L)) return false;
|
|
if (!base_.setDTR1(x1H)) return false;
|
|
if (!base_.dtSelect(8)) return false;
|
|
if (!base_.setDTRAsColourX(a)) return false;
|
|
if (!base_.setDTR(y1L)) return false;
|
|
if (!base_.setDTR1(y1H)) return false;
|
|
if (!base_.dtSelect(8)) return false;
|
|
if (!base_.setDTRAsColourY(a)) return false;
|
|
if (!base_.dtSelect(8)) return false;
|
|
return base_.activate(a);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryColourXRaw(int addr, int x1) {
|
|
const int x1L = x1 & 0xFF;
|
|
const int x1H = (x1 >> 8) & 0xFF;
|
|
const int a = addr / 2;
|
|
return base_.setDTR(x1L) && base_.setDTR1(x1H) && base_.dtSelect(8) && base_.setDTRAsColourX(a);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryColourYRaw(int addr, int y1) {
|
|
const int y1L = y1 & 0xFF;
|
|
const int y1H = (y1 >> 8) & 0xFF;
|
|
const int a = addr / 2;
|
|
return base_.setDTR(y1L) && base_.setDTR1(y1H) && base_.dtSelect(8) && base_.setDTRAsColourY(a);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryColourXY(int a, double x, double y) {
|
|
double xClamped = std::clamp(x, 0.0, 1.0);
|
|
double yClamped = std::clamp(y, 0.0, 1.0);
|
|
const int x1 = static_cast<int>(std::round(xClamped * 65535.0));
|
|
const int y1 = static_cast<int>(std::round(yClamped * 65535.0));
|
|
const int addr = a * 2 + 1;
|
|
return setTemporaryColourXRaw(addr, x1) && setTemporaryColourYRaw(addr, y1);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryColourTemperature(int a, int kelvin) {
|
|
int k = kelvin <= 0 ? 1 : kelvin;
|
|
const int mirek = static_cast<int>(std::floor(1000000.0 / static_cast<double>(k)));
|
|
const int addr = a * 2 + 1;
|
|
const int dtr = mirek & 0xFF;
|
|
const int dtr1 = (mirek >> 8) & 0xFF;
|
|
const int dec = addr / 2;
|
|
return base_.setDTR(dtr) && base_.setDTR1(dtr1) && base_.dtSelect(8) && base_.setDTRAsColourTemp(dec);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryPrimaryDimLevel(int a, int n, double level) {
|
|
int idx = std::clamp(n, 0, 5);
|
|
double v = std::clamp(level, 0.0, 1.0);
|
|
int raw = static_cast<int>(std::round(v * 65535.0));
|
|
if (raw > 65534) raw = 65534;
|
|
const int lsb = raw & 0xFF;
|
|
const int msb = (raw >> 8) & 0xFF;
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(lsb) && base_.setDTR1(msb) && base_.setDTR2(idx) &&
|
|
base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_PRIMARY_DIM_LEVEL);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryRGBDimLevels(int a, int r, int g, int b) {
|
|
const int R = std::clamp(r, 0, 255);
|
|
const int G = std::clamp(g, 0, 255);
|
|
const int B = std::clamp(b, 0, 255);
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(R) && base_.setDTR1(G) && base_.setDTR2(B) &&
|
|
base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_RGB_DIM_LEVELS);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryWAFDimLevels(int a, int w, int amber, int freecolour) {
|
|
const int W = std::clamp(w, 0, 255);
|
|
const int A = std::clamp(amber, 0, 255);
|
|
const int F = std::clamp(freecolour, 0, 255);
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(W) && base_.setDTR1(A) && base_.setDTR2(F) &&
|
|
base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_WAF_DIM_LEVELS);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryRGBWAFControl(int a, int control) {
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(control & 0xFF) && base_.dtSelect(8) &&
|
|
base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_RGBWAF_CONTROL);
|
|
}
|
|
|
|
bool DaliDT8::setTemporaryColourMask(int a) {
|
|
if (setTemporaryRGBDimLevels(a, 255, 255, 255)) return true;
|
|
if (base_.setDTR(0xFF) && base_.setDTR1(0xFF) && base_.dtSelect(8) && base_.setDTRAsColourTemp(a)) {
|
|
return true;
|
|
}
|
|
const int addr = DaliComm::toCmdAddr(a);
|
|
return setTemporaryColourXRaw(addr, 0xFFFF) && setTemporaryColourYRaw(addr, 0xFFFF);
|
|
}
|
|
|
|
bool DaliDT8::copyReportToTemporary(int a) { return base_.dtSelect(8) && base_.copyReportColourToTemp(a); }
|
|
|
|
bool DaliDT8::stepXUp(int a) {
|
|
return base_.dtSelect(8) && base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_UP_X_COORDINATE);
|
|
}
|
|
|
|
bool DaliDT8::stepXDown(int a) {
|
|
return base_.dtSelect(8) && base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_DOWN_X_COORDINATE);
|
|
}
|
|
|
|
bool DaliDT8::stepYUp(int a) {
|
|
return base_.dtSelect(8) && base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_UP_Y_COORDINATE);
|
|
}
|
|
|
|
bool DaliDT8::stepYDown(int a) {
|
|
return base_.dtSelect(8) && base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_DOWN_Y_COORDINATE);
|
|
}
|
|
|
|
bool DaliDT8::stepTcCooler(int a) {
|
|
return base_.dtSelect(8) &&
|
|
base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_UP_COLOR_TEMPERATURE);
|
|
}
|
|
|
|
bool DaliDT8::stepTcWarmer(int a) {
|
|
return base_.dtSelect(8) &&
|
|
base_.sendExtCmd(a * 2 + 1, DALI_CMD_DT8_STEP_DOWN_COLOR_TEMPERATURE);
|
|
}
|
|
|
|
bool DaliDT8::setColourRGBRaw(int addr, int r, int g, int b) {
|
|
const int a = addr / 2;
|
|
return base_.setDTR(r) && base_.setDTR1(g) && base_.setDTR2(b) && base_.dtSelect(8) && base_.setDTRAsColourRGB(a) && base_.dtSelect(8) && base_.activate(a);
|
|
}
|
|
|
|
bool DaliDT8::setColour(int a, double x, double y) {
|
|
double xClamped = std::clamp(x, 0.0, 1.0);
|
|
double yClamped = std::clamp(y, 0.0, 1.0);
|
|
const int x1 = static_cast<int>(std::round(xClamped * 65535.0));
|
|
const int y1 = static_cast<int>(std::round(yClamped * 65535.0));
|
|
const int addr = a * 2 + 1;
|
|
return setColourRaw(addr, x1, y1);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getColourRaw(int a, int type) {
|
|
const uint8_t code = static_cast<uint8_t>(type & 0xFF);
|
|
const auto features = getColorTypeFeature(a);
|
|
if (!features.has_value()) return std::nullopt;
|
|
if ((code == 2 || code == 128 || code == 129 || code == 130 || code == 131) && !features->ctCapable()) {
|
|
return std::nullopt;
|
|
}
|
|
|
|
bool is8bit = false;
|
|
if (code == 82 || (code >= 9 && code <= 15) || (code >= 201 && code <= 207) || code == 208 ||
|
|
(code >= 233 && code <= 239) || code == 240) {
|
|
is8bit = true;
|
|
}
|
|
|
|
if (!base_.setDTR(code)) return std::nullopt;
|
|
if (!base_.dtSelect(8)) return std::nullopt;
|
|
if (!base_.queryColourValue(a)) return std::nullopt;
|
|
const auto dtr = base_.getDTR(a);
|
|
const auto dtr1 = base_.getDTR1(a);
|
|
if (!dtr.has_value() || !dtr1.has_value()) return std::nullopt;
|
|
|
|
if (is8bit) {
|
|
if (dtr.value() == 0xFF) return std::nullopt;
|
|
return dtr.value() & 0xFF;
|
|
}
|
|
|
|
if (dtr.value() == 0xFF && dtr1.value() == 0xFF) return std::nullopt;
|
|
return ((dtr1.value() & 0xFF) << 8) | (dtr.value() & 0xFF);
|
|
}
|
|
|
|
std::vector<double> DaliDT8::getColour(int a) {
|
|
const auto x = getColourRaw(a, 0);
|
|
const auto y = getColourRaw(a, 1);
|
|
if (!x.has_value() || !y.has_value()) return {};
|
|
return {x.value() / 65535.0, y.value() / 65535.0};
|
|
}
|
|
|
|
bool DaliDT8::setColourRGB(int addr, int r, int g, int b) {
|
|
int R = std::clamp(r, 0, 255);
|
|
int G = std::clamp(g, 0, 255);
|
|
int B = std::clamp(b, 0, 255);
|
|
const auto xy = DaliColor::rgb2xy(static_cast<double>(R) / 255.0, static_cast<double>(G) / 255.0,
|
|
static_cast<double>(B) / 255.0);
|
|
return setColour(addr, xy[0], xy[1]);
|
|
}
|
|
|
|
std::vector<int> DaliDT8::getColourRGB(int a) {
|
|
const auto xy = getColour(a);
|
|
if (xy.empty()) return {};
|
|
const auto rgb = DaliColor::xy2rgb(xy[0], xy[1]);
|
|
return {rgb[0], rgb[1], rgb[2]};
|
|
}
|
|
|
|
bool DaliDT8::storeSceneSnapshot(int address, int scene, int brightness,
|
|
Dt8SceneStoreColorMode colorMode, int colorTemperature, int red,
|
|
int green, int blue, int /*gateway*/) {
|
|
const int sceneBrightness = std::clamp(brightness, 0, 255);
|
|
const int sceneIndex = std::clamp(scene, 0, 15);
|
|
|
|
if (sceneBrightness != 255) {
|
|
switch (colorMode) {
|
|
case Dt8SceneStoreColorMode::colorTemperature:
|
|
if (!setTemporaryColourTemperature(address, colorTemperature)) return false;
|
|
break;
|
|
case Dt8SceneStoreColorMode::rgb: {
|
|
const int r = std::clamp(red, 0, 255);
|
|
const int g = std::clamp(green, 0, 255);
|
|
const int b = std::clamp(blue, 0, 255);
|
|
const auto xy = DaliColor::rgb2xy(static_cast<double>(r) / 255.0,
|
|
static_cast<double>(g) / 255.0,
|
|
static_cast<double>(b) / 255.0);
|
|
if (!setTemporaryColourXY(address, xy[0], xy[1])) return false;
|
|
break;
|
|
}
|
|
case Dt8SceneStoreColorMode::disabled:
|
|
if (!setTemporaryColourMask(address)) return false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!base_.setDTR(sceneBrightness)) return false;
|
|
// DT SELECT is one-shot and SET DTR consumes any earlier selection.
|
|
return base_.dtSelect(8) && base_.storeDTRAsSceneBright(address, sceneIndex);
|
|
}
|
|
|
|
bool DaliDT8::storePowerOnLevelSnapshot(int address, int level) {
|
|
const int storedLevel = std::clamp(level, 0, 254);
|
|
// DT SELECT is one-shot and SET DTR consumes any earlier selection.
|
|
return base_.setDTR(storedLevel) && base_.dtSelect(8) && base_.storeDTRAsPoweredBright(address);
|
|
}
|
|
|
|
bool DaliDT8::storeSystemFailureLevelSnapshot(int address, int level) {
|
|
const int storedLevel = std::clamp(level, 0, 254);
|
|
// DT SELECT is one-shot and SET DTR consumes any earlier selection.
|
|
return base_.setDTR(storedLevel) && base_.dtSelect(8) &&
|
|
base_.storeDTRAsSystemFailureLevel(address);
|
|
}
|
|
|
|
bool DaliDT8::activateTemporaryColour(int a) { return base_.dtSelect(8) && base_.activate(a); }
|
|
|
|
std::optional<int> DaliDT8::getPrimaryDimLevel(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 3 + n);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getRedDimLevel(int a) { return getColourRaw(a, 9); }
|
|
std::optional<int> DaliDT8::getGreenDimLevel(int a) { return getColourRaw(a, 10); }
|
|
std::optional<int> DaliDT8::getBlueDimLevel(int a) { return getColourRaw(a, 11); }
|
|
std::optional<int> DaliDT8::getWhiteDimLevel(int a) { return getColourRaw(a, 12); }
|
|
std::optional<int> DaliDT8::getAmberDimLevel(int a) { return getColourRaw(a, 13); }
|
|
std::optional<int> DaliDT8::getFreecolourDimLevel(int a) { return getColourRaw(a, 14); }
|
|
std::optional<int> DaliDT8::getRGBWAFControl(int a) { return getColourRaw(a, 15); }
|
|
|
|
std::optional<int> DaliDT8::getTemporaryXRaw(int a) { return getColourRaw(a, 192); }
|
|
std::optional<int> DaliDT8::getTemporaryYRaw(int a) { return getColourRaw(a, 193); }
|
|
std::optional<int> DaliDT8::getTemporaryColourTemperatureRaw(int a) { return getColourRaw(a, 194); }
|
|
|
|
std::optional<int> DaliDT8::getTemporaryPrimaryDimLevel(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 195 + n);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getTemporaryRedDimLevel(int a) { return getColourRaw(a, 201); }
|
|
std::optional<int> DaliDT8::getTemporaryGreenDimLevel(int a) { return getColourRaw(a, 202); }
|
|
std::optional<int> DaliDT8::getTemporaryBlueDimLevel(int a) { return getColourRaw(a, 203); }
|
|
std::optional<int> DaliDT8::getTemporaryWhiteDimLevel(int a) { return getColourRaw(a, 204); }
|
|
std::optional<int> DaliDT8::getTemporaryAmberDimLevel(int a) { return getColourRaw(a, 205); }
|
|
std::optional<int> DaliDT8::getTemporaryFreecolourDimLevel(int a) { return getColourRaw(a, 206); }
|
|
std::optional<int> DaliDT8::getTemporaryRGBWAFControl(int a) { return getColourRaw(a, 207); }
|
|
std::optional<int> DaliDT8::getTemporaryColourType(int a) { return getColourRaw(a, 208); }
|
|
|
|
std::vector<double> DaliDT8::getTemporaryColour(int a) {
|
|
const auto x = getTemporaryXRaw(a);
|
|
const auto y = getTemporaryYRaw(a);
|
|
if (!x.has_value() || !y.has_value()) return {};
|
|
return {x.value() / 65535.0, y.value() / 65535.0};
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getTemporaryColorTemperature(int a) {
|
|
const auto mirek = getTemporaryColourTemperatureRaw(a);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getReportXRaw(int a) { return getColourRaw(a, 224); }
|
|
std::optional<int> DaliDT8::getReportYRaw(int a) { return getColourRaw(a, 225); }
|
|
std::optional<int> DaliDT8::getReportColourTemperatureRaw(int a) { return getColourRaw(a, 226); }
|
|
|
|
std::optional<int> DaliDT8::getReportPrimaryDimLevel(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 227 + n);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getReportRedDimLevel(int a) { return getColourRaw(a, 233); }
|
|
std::optional<int> DaliDT8::getReportGreenDimLevel(int a) { return getColourRaw(a, 234); }
|
|
std::optional<int> DaliDT8::getReportBlueDimLevel(int a) { return getColourRaw(a, 235); }
|
|
std::optional<int> DaliDT8::getReportWhiteDimLevel(int a) { return getColourRaw(a, 236); }
|
|
std::optional<int> DaliDT8::getReportAmberDimLevel(int a) { return getColourRaw(a, 237); }
|
|
std::optional<int> DaliDT8::getReportFreecolourDimLevel(int a) { return getColourRaw(a, 238); }
|
|
std::optional<int> DaliDT8::getReportRGBWAFControl(int a) { return getColourRaw(a, 239); }
|
|
std::optional<int> DaliDT8::getReportColourType(int a) { return getColourRaw(a, 240); }
|
|
|
|
std::vector<double> DaliDT8::getReportColour(int a) {
|
|
const auto x = getReportXRaw(a);
|
|
const auto y = getReportYRaw(a);
|
|
if (!x.has_value() || !y.has_value()) return {};
|
|
return {x.value() / 65535.0, y.value() / 65535.0};
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getReportColorTemperature(int a) {
|
|
const auto mirek = getReportColourTemperatureRaw(a);
|
|
if (!mirek.has_value() || mirek.value() == 0) return std::nullopt;
|
|
return static_cast<int>(std::floor(1000000.0 / static_cast<double>(mirek.value())));
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getNumberOfPrimaries(int a) { return getColourRaw(a, 82); }
|
|
|
|
std::optional<int> DaliDT8::getPrimaryXRaw(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 64 + 3 * n);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getPrimaryYRaw(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 65 + 3 * n);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getPrimaryTy(int a, int n) {
|
|
if (n < 0 || n > 5) return std::nullopt;
|
|
return getColourRaw(a, 66 + 3 * n);
|
|
}
|
|
|
|
std::optional<SceneColorReport> DaliDT8::getSceneColorReport(int a, int sense, int gateway) {
|
|
const auto brightness = base_.getScene(a, sense, gateway);
|
|
if (!brightness.has_value() || brightness.value() == 255) return std::nullopt;
|
|
|
|
const int colorTypeValue = getReportColourType(a).value_or(0);
|
|
const ColorType colorType(colorTypeValue);
|
|
|
|
SceneColorReport report;
|
|
report.brightness = brightness.value();
|
|
report.colorTypeValue = colorTypeValue;
|
|
|
|
if (colorType.xy()) {
|
|
report.xy = getReportColour(a);
|
|
return report;
|
|
}
|
|
|
|
if (colorType.ct()) {
|
|
report.colorTemperature = getReportColorTemperature(a);
|
|
return report;
|
|
}
|
|
|
|
return report;
|
|
}
|
|
|
|
std::vector<double> DaliDT8::getSceneColor(int a, int sense, int gateway) {
|
|
const auto report = getSceneColorReport(a, sense, gateway);
|
|
if (!report.has_value() || !report->colorType().xy() || !report->hasXy()) return {};
|
|
return report->xy;
|
|
}
|
|
|
|
std::optional<Dt8LevelColorReport> DaliDT8::buildLevelColorReport(int a, std::optional<int> level) {
|
|
if (!level.has_value() || level.value() == 255) return std::nullopt;
|
|
|
|
Dt8LevelColorReport report;
|
|
report.level = level.value();
|
|
report.colorTypeValue = getReportColourType(a).value_or(0);
|
|
|
|
const ColorType colorType(report.colorTypeValue);
|
|
if (colorType.xy()) {
|
|
report.xy = getReportColour(a);
|
|
return report;
|
|
}
|
|
|
|
if (colorType.ct()) {
|
|
report.colorTemperature = getReportColorTemperature(a);
|
|
return report;
|
|
}
|
|
|
|
return report;
|
|
}
|
|
|
|
std::optional<Dt8LevelColorReport> DaliDT8::getPowerOnLevelColorReport(int a) {
|
|
return buildLevelColorReport(a, base_.getPowerOnLevel(a));
|
|
}
|
|
|
|
std::optional<Dt8LevelColorReport> DaliDT8::getSystemFailureLevelColorReport(int a) {
|
|
return buildLevelColorReport(a, base_.getSystemFailureLevel(a));
|
|
}
|
|
|
|
bool DaliDT8::storePrimaryTy(int a, int n, int ty) {
|
|
int idx = std::clamp(n, 0, 5);
|
|
int t = std::clamp(ty, 0, 65535);
|
|
const int lsb = t & 0xFF;
|
|
const int msb = (t >> 8) & 0xFF;
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(lsb) && base_.setDTR1(msb) && base_.setDTR2(idx) &&
|
|
base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_STORE_PRIMARY_N_TY);
|
|
}
|
|
|
|
bool DaliDT8::storePrimaryXY(int a, int n, double x, double y) {
|
|
int idx = std::clamp(n, 0, 5);
|
|
if (!setTemporaryColourXY(a, x, y)) return false;
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR2(idx) && base_.dtSelect(8) &&
|
|
base_.sendExtCmd(addr, DALI_CMD_DT8_STORE_PRIMARY_N_XY);
|
|
}
|
|
|
|
bool DaliDT8::storeColourTempLimitRaw(int a, int limitType, int mirek) {
|
|
int m = mirek;
|
|
if (m < 1) m = 1;
|
|
if (m > 65534) m = 65534;
|
|
const int lsb = m & 0xFF;
|
|
const int msb = (m >> 8) & 0xFF;
|
|
const int addr = a * 2 + 1;
|
|
return base_.setDTR(lsb) && base_.setDTR1(msb) && base_.setDTR2(limitType & 0xFF) &&
|
|
base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_STORE_COLOR_TEMPERATURE_LIMIT);
|
|
}
|
|
|
|
bool DaliDT8::storeColourTempLimit(int a, int limitType, int kelvin) {
|
|
const int mirek = static_cast<int>(std::floor(1000000.0 / static_cast<double>(kelvin <= 0 ? 1 : kelvin)));
|
|
return storeColourTempLimitRaw(a, limitType, mirek);
|
|
}
|
|
|
|
bool DaliDT8::setGearAutoActivate(int a, bool enable) {
|
|
const int addr = a * 2 + 1;
|
|
const int opts = enable ? 0x01 : 0x00;
|
|
return base_.setDTR(opts) && base_.dtSelect(8) &&
|
|
base_.sendExtCmd(addr, DALI_CMD_DT8_SET_GEAR_FEATURES);
|
|
}
|
|
|
|
bool DaliDT8::assignColourToLinkedChannels(int a, int colourId) {
|
|
const int addr = a * 2 + 1;
|
|
const int id = std::clamp(colourId, 0, 6);
|
|
return base_.setDTR(id) && base_.dtSelect(8) &&
|
|
base_.sendExtCmd(addr, DALI_CMD_DT8_ASSIGN_COLOR_TO_LINKED_CHANNEL);
|
|
}
|
|
|
|
bool DaliDT8::startAutoCalibration(int a) {
|
|
const int addr = a * 2 + 1;
|
|
return base_.dtSelect(8) && base_.sendExtCmd(addr, DALI_CMD_DT8_START_AUTO_CALIBRATION);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getGearFeaturesStatus(int a) {
|
|
const int addr = a * 2 + 1;
|
|
base_.dtSelect(8);
|
|
return base_.queryCmd(addr, DALI_CMD_DT8_QUERY_GEAR_FEATURES_STATUS);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getRGBWAFControlDirect(int a) {
|
|
const int addr = a * 2 + 1;
|
|
base_.dtSelect(8);
|
|
return base_.queryCmd(addr, DALI_CMD_DT8_QUERY_RGBWAF_CONTROL);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getAssignedColourForChannel(int a, int channelId) {
|
|
const int addr = a * 2 + 1;
|
|
const int ch = channelId & 0xFF;
|
|
if (!base_.setDTR(ch)) return std::nullopt;
|
|
if (!base_.dtSelect(8)) return std::nullopt;
|
|
return base_.queryCmd(addr, DALI_CMD_DT8_QUERY_ASSIGNED_COLOR);
|
|
}
|
|
|
|
std::optional<int> DaliDT8::getExtendedVersion(int a) {
|
|
const int addr = a * 2 + 1;
|
|
base_.dtSelect(8);
|
|
return base_.queryCmd(addr, DALI_CMD_DT8_QUERY_EXTENDED_VERSION);
|
|
}
|