#include "base.hpp" #include "dali_define.hpp" #include DaliStatus DaliStatus::fromByte(uint8_t status) { DaliStatus s; s.controlGearPresent = (status & 0x01) != 0; s.lampFailure = (status & 0x02) != 0; s.lampPowerOn = (status & 0x04) != 0; s.limitError = (status & 0x08) != 0; s.fadingCompleted = (status & 0x10) != 0; s.resetState = (status & 0x20) != 0; s.missingShortAddress = (status & 0x40) != 0; s.psFault = (status & 0x80) != 0; return s; } DaliBase::DaliBase(DaliComm& comm) : comm_(comm) {} int64_t DaliBase::mcuTicks() const { const auto now = std::chrono::time_point_cast( std::chrono::system_clock::now()); return now.time_since_epoch().count(); } uint8_t DaliBase::encodeCmdAddr(int dec_addr) { return DaliComm::toCmdAddr(dec_addr); } uint8_t DaliBase::encodeArcAddr(int dec_addr) { return DaliComm::toArcAddr(dec_addr); } bool DaliBase::toScene(int a, int s) { const int scene = DALI_CMD_GO_TO_SCENE(s); return send(a, static_cast(scene)); } bool DaliBase::reset(int a, int /*t*/) { return send(a, DALI_CMD_RESET); } int DaliBase::brightnessToLog(int brightness) const { const double val = std::log(static_cast(brightness) + 1.0) / std::log(256.0) * 255.0; return static_cast(val); } int DaliBase::logToBrightness(int logValue) const { const double val = std::pow(10.0, logValue * std::log(256.0) / std::log(10.0)) - 1.0; return static_cast(val); } bool DaliBase::setBright(int a, int b) { int bright = std::clamp(b, 0, 254); const auto addr = encodeArcAddr(a); return comm_.sendCmd(addr, static_cast(bright)); } bool DaliBase::setBrightPercentage(int a, double b) { int bright = static_cast(b * 254.0 / 100.0); bright = std::clamp(bright, 0, 254); return setBright(a, bright); } bool DaliBase::stopFade(int a) { return sendCmd(encodeCmdAddr(a), DALI_CMD_STOP_FADE); } bool DaliBase::off(int a) { return sendCmd(encodeCmdAddr(a), DALI_CMD_OFF); } bool DaliBase::on(int a) { return sendCmd(encodeCmdAddr(a), DALI_CMD_RECALL_MAX); } bool DaliBase::recallMaxLevel(int a) { return sendCmd(encodeCmdAddr(a), DALI_CMD_RECALL_MAX); } bool DaliBase::recallMinLevel(int a) { return sendCmd(encodeCmdAddr(a), DALI_CMD_RECALL_MIN); } int DaliBase::groupToAddr(int gp) const { return 64 + gp; } bool DaliBase::send(int a, uint8_t cmd) { return sendCmd(encodeCmdAddr(a), cmd); } bool DaliBase::sendCmd(uint8_t addr, uint8_t cmd) { return comm_.sendCmd(addr, cmd); } bool DaliBase::sendExtCmd(int cmd, int value) { return comm_.sendExtCmd(static_cast(cmd), static_cast(value)); } bool DaliBase::setDTR(int value) { return comm_.sendCmd(DALI_CMD_SPECIAL_SET_DTR0, static_cast(value)); } bool DaliBase::setDTR1(int value) { return comm_.sendCmd(DALI_CMD_SPECIAL_SET_DTR_1, static_cast(value)); } bool DaliBase::setDTR2(int value) { return comm_.sendCmd(DALI_CMD_SPECIAL_SET_DTR_2, static_cast(value)); } std::optional DaliBase::getDTR(int a) { return query(a, DALI_CMD_QUERY_CONTENT_DTR); } std::optional DaliBase::getDTR1(int a) { return query(a, DALI_CMD_QUERY_CONTENT_DTR1); } std::optional DaliBase::getDTR2(int a) { return query(a, DALI_CMD_QUERY_CONTENT_DTR2); } bool DaliBase::copyCurrentBrightToDTR(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_ACTUAL_LEVEL_IN_THE_DTR); } bool DaliBase::queryColourValue(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_QUERY_COLOR_VALUE); } bool DaliBase::storeDTRAsAddr(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_DTR_AS_SHORT_ADDRESS); } bool DaliBase::storeDTRAsSceneBright(int a, int s) { const int value = DALI_CMD_SET_SCENE(s); return sendExtCmd(encodeCmdAddr(a), value); } bool DaliBase::storeScene(int a, int s) { return copyCurrentBrightToDTR(a) && storeDTRAsSceneBright(a, s); } bool DaliBase::removeScene(int a, int s) { const int value = DALI_CMD_REMOVE_SCENE(s); return sendExtCmd(encodeCmdAddr(a), value); } bool DaliBase::addToGroup(int a, int g) { const int value = DALI_CMD_ADD_TO_GROUP(g); return sendExtCmd(encodeCmdAddr(a), value); } bool DaliBase::removeFromGroup(int a, int g) { const int value = DALI_CMD_REMOVE_FROM_GROUP(g); return sendExtCmd(encodeCmdAddr(a), value); } bool DaliBase::storeDTRAsFadeTime(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_FADE_TIME); } bool DaliBase::storeDTRAsFadeRate(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_FADE_RATE); } bool DaliBase::storeDTRAsPoweredBright(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_PWR_ON_LEVEL); } bool DaliBase::storeDTRAsSystemFailureLevel(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_SYS_FAIL_LEVEL); } bool DaliBase::storeDTRAsMinLevel(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_MIN_LEVEL); } bool DaliBase::storeDTRAsMaxLevel(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_STORE_THE_DTR_AS_MAX_LEVEL); } bool DaliBase::storeColourTempLimits(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_STORE_COLOR_TEMPERATURE_LIMIT); } std::optional DaliBase::getOnlineStatus(int a) { const auto status = query(a, DALI_CMD_QUERY_BALLAST); if (!status.has_value()) return std::nullopt; return status.value() == 255; } std::optional DaliBase::getBright(int a) { const auto res = query(a, DALI_CMD_QUERY_ACTUAL_LEVEL); if (!res.has_value()) return std::nullopt; if (res.value() == 255) return 254; return res; } std::optional DaliBase::getDeviceType(int a) { return queryCmd(encodeCmdAddr(a), DALI_CMD_QUERY_DEVICE_TYPE); } std::optional DaliBase::getPhysicalMinLevel(int a) { return queryCmd(encodeCmdAddr(a), DALI_CMD_QUERY_PHYSICAL_MINIMUM_LEVEL); } std::optional DaliBase::getDeviceVersion(int a) { return queryCmd(encodeCmdAddr(a), DALI_CMD_QUERY_VERSION_NUMBER); } bool DaliBase::dtSelect(int value) { return comm_.sendCmd(DALI_CMD_SPECIAL_DT_SELECT, static_cast(value)); } bool DaliBase::activate(int a) { return comm_.sendCmd(encodeCmdAddr(a), DALI_CMD_DT8_ACTIVATE); } bool DaliBase::setDTRAsColourX(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_STORE_DTR_AS_COLORX); } bool DaliBase::setDTRAsColourY(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_STORE_DTR_AS_COLORY); } bool DaliBase::setDTRAsColourRGB(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_ACTIVATE); } bool DaliBase::setDTRAsColourTemp(int a) { return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_SET_COLOR_TEMPERATURE); } bool DaliBase::copyReportColourToTemp(int a) { if (!dtSelect(8)) return false; return sendExtCmd(encodeCmdAddr(a), DALI_CMD_DT8_COPY_REPORT_TO_TEMPORARY); } bool DaliBase::setGradualChangeSpeed(int a, int value) { return setDTR(value) && storeDTRAsFadeTime(a); } bool DaliBase::setGradualChangeRate(int a, int value) { return setDTR(value) && storeDTRAsFadeRate(a); } std::optional> DaliBase::getGradualChange(int a) { const auto ret = query(a, DALI_CMD_QUERY_FADE_TIME_FADE_RATE); if (!ret.has_value()) return std::nullopt; int speed = ret.value(); int rate = 0; while (speed > 15) { speed -= 16; rate++; } return std::make_pair(rate, speed); } std::optional DaliBase::getGradualChangeRate(int a) { const auto rs = getGradualChange(a); if (!rs.has_value()) return std::nullopt; return rs->second; } std::optional DaliBase::getGradualChangeSpeed(int a) { const auto rs = getGradualChange(a); if (!rs.has_value()) return std::nullopt; return rs->first; } bool DaliBase::setPowerOnLevel(int a, int value) { return setDTR(value) && storeDTRAsPoweredBright(a); } std::optional DaliBase::getPowerOnLevel(int a) { return query(a, DALI_CMD_QUERY_MAX_LEVEL); } bool DaliBase::setSystemFailureLevel(int a, int value) { return setDTR(value) && storeDTRAsSystemFailureLevel(a); } std::optional DaliBase::getSystemFailureLevel(int a) { return query(a, DALI_CMD_QUERY_MIN_LEVEL); } bool DaliBase::setMinLevel(int a, int value) { return setDTR(value) && storeDTRAsMinLevel(a); } std::optional DaliBase::getMinLevel(int a) { return query(a, DALI_CMD_QUERY_POWER_ON_LEVEL); } bool DaliBase::setMaxLevel(int a, int value) { return setDTR(value) && storeDTRAsMaxLevel(a); } std::optional DaliBase::getMaxLevel(int a) { return query(a, DALI_CMD_QUERY_SYSTEM_FAILURE_LEVEL); } bool DaliBase::setFadeTime(int a, int value) { int v = value; if (v > 15) v = 15; return setDTR(v) && storeDTRAsFadeTime(a); } std::optional DaliBase::getFadeTime(int a) { const auto rs = getGradualChange(a); if (!rs.has_value()) return std::nullopt; return rs->first; } bool DaliBase::setFadeRate(int a, int value) { return setDTR(value) && storeDTRAsFadeRate(a); } std::optional DaliBase::getFadeRate(int a) { const auto rs = getGradualChange(a); if (!rs.has_value()) return std::nullopt; return rs->second; } std::optional DaliBase::getNextDeviceType(int a) { return query(a, DALI_CMD_QUERY_NEXT_DEVICE_TYPE); } std::optional DaliBase::getGroupH(int a) { return query(a, DALI_CMD_QUERY_GROUP_8_15); } std::optional DaliBase::getGroupL(int a) { return query(a, DALI_CMD_QUERY_GROUPS_0_7); } std::optional DaliBase::getGroup(int a) { const auto h = getGroupH(a); const auto l = getGroupL(a); if (!h.has_value() || !l.has_value()) return std::nullopt; return h.value() * 256 + l.value(); } bool DaliBase::setGroup(int a, int value) { auto currentGroupOpt = getGroup(a); int currentGroup = currentGroupOpt.value_or(-1); for (int i = 0; i < 16; i++) { if (currentGroup != -1 && (currentGroup & (1 << i)) == (value & (1 << i))) { continue; } if ((value & (1 << i)) != 0) { if (!addToGroup(a, i)) return false; } else { if (!removeFromGroup(a, i)) return false; } } return true; } std::optional DaliBase::getScene(int a, int b) { return query(a, static_cast(DALI_CMD_QUERY_SCENE_LEVEL(b))); } bool DaliBase::setScene(int a, int b) { return setDTR(b) && storeDTRAsSceneBright(a, b); } std::map DaliBase::getScenes(int a) { std::map ret; for (int i = 0; i < 16; i++) { const auto r = getScene(a, i); if (r.has_value()) ret[i] = r.value(); } return ret; } std::optional DaliBase::getStatus(int a) { return query(a, DALI_CMD_QUERY_STATUS); } std::optional DaliBase::getControlGearPresent(int a) { const auto ret = query(a, DALI_CMD_QUERY_BALLAST); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } std::optional DaliBase::getLampFailureStatus(int a) { const auto ret = query(a, DALI_CMD_QUERY_LAMP_FAILURE); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } std::optional DaliBase::getLampPowerOnStatus(int a) { const auto ret = query(a, DALI_CMD_QUERY_LAMP_POWER_ON); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } std::optional DaliBase::getLimitError(int a) { const auto ret = query(a, DALI_CMD_QUERY_LIMIT_ERROR); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } std::optional DaliBase::getResetStatus(int a) { const auto ret = query(a, DALI_CMD_QUERY_RESET_STATE); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } std::optional DaliBase::getMissingShortAddress(int a) { const auto ret = query(a, DALI_CMD_QUERY_MISSING_SHORT_ADDRESS); if (!ret.has_value()) return std::nullopt; return ret.value() == 255; } bool DaliBase::terminate() { return comm_.sendCmd(DALI_CMD_SPECIAL_TERMINATE, DALI_CMD_OFF); } bool DaliBase::randomise() { return comm_.sendExtCmd(DALI_CMD_SPECIAL_RANDOMIZE, DALI_CMD_OFF); } bool DaliBase::initialiseAll() { return comm_.sendExtCmd(DALI_CMD_SPECIAL_INITIALIZE, DALI_CMD_OFF); } bool DaliBase::initialise() { return comm_.sendExtCmd(DALI_CMD_SPECIAL_INITIALIZE, DALI_CMD_STOP_FADE); } bool DaliBase::withdraw() { return comm_.sendCmd(DALI_CMD_SPECIAL_WITHDRAW, DALI_CMD_OFF); } bool DaliBase::cancel() { return comm_.sendCmd(DALI_CMD_SPECIAL_CANCEL, DALI_CMD_OFF); } bool DaliBase::physicalSelection() { return comm_.sendCmd(DALI_CMD_SPECIAL_PHYSICAL_SELECTION, DALI_CMD_OFF); } bool DaliBase::queryAddressH(int addr) { return comm_.sendCmd(DALI_CMD_SPECIAL_SEARCHADDRH, static_cast(addr)); } bool DaliBase::queryAddressM(int addr) { return comm_.sendCmd(DALI_CMD_SPECIAL_SEARCHADDRM, static_cast(addr)); } bool DaliBase::queryAddressL(int addr) { return comm_.sendCmd(DALI_CMD_SPECIAL_SEARCHADDRL, static_cast(addr)); } bool DaliBase::programShortAddr(int a) { return comm_.sendCmd(DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS, encodeCmdAddr(a)); } std::optional DaliBase::queryShortAddr() { const auto ret1 = queryCmd(DALI_CMD_SPECIAL_QUERY_SHORT_ADDRESS, DALI_CMD_OFF); if (!ret1.has_value()) return std::nullopt; int ret = ret1.value() - 1; return ret / 2; } std::optional DaliBase::verifyShortAddr(int a) { const auto res = queryCmd(DALI_CMD_SPECIAL_VERIFY_SHORT_ADDRESS, encodeCmdAddr(a)); if (!res.has_value()) return std::nullopt; return true; } std::optional DaliBase::compareAddress() { const auto ret = queryCmd(DALI_CMD_SPECIAL_COMPARE, DALI_CMD_OFF); if (!ret.has_value()) return std::nullopt; return ret.value() >= 0; } std::optional DaliBase::compare(int h, int m, int l) { if (!queryAddressL(l)) return std::nullopt; if (!queryAddressM(m)) return std::nullopt; if (!queryAddressH(h)) return std::nullopt; const auto matched = compareAddress(); if (!matched.has_value()) return std::nullopt; return matched.value(); } std::optional DaliBase::getRandomAddrH(int addr) { return query(addr, DALI_CMD_QUERY_RANDOM_ADDRESS_H); } std::optional DaliBase::getRandomAddrM(int addr) { return query(addr, DALI_CMD_QUERY_RANDOM_ADDRESS_M); } std::optional DaliBase::getRandomAddrL(int addr) { return query(addr, DALI_CMD_QUERY_RANDOM_ADDRESS_L); } std::optional DaliBase::query(int a, uint8_t cmd) { return comm_.queryCmd(encodeCmdAddr(a), cmd); } std::optional DaliBase::queryCmd(uint8_t addr, uint8_t cmd) { return comm_.queryCmd(addr, cmd); }