419 lines
16 KiB
C++
419 lines
16 KiB
C++
#include "decode.hpp"
|
|
|
|
#include "base.hpp"
|
|
#include "dali_define.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
DaliDecode::DaliDecode() {
|
|
cmd_ = {
|
|
{DALI_CMD_OFF, "OFF"},
|
|
{DALI_CMD_RECALL_MAX_LEVEL, "RECALL_MAX_LEVEL"},
|
|
{DALI_CMD_RECALL_MIN_LEVEL, "RECALL_MIN_LEVEL"},
|
|
{DALI_CMD_RESET, "RESET"},
|
|
{DALI_CMD_STORE_ACTUAL_LEVEL_IN_THE_DTR, "STORE_ACTUAL_LEVEL_IN_THE_DTR"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_MAX_LEVEL, "STORE_THE_DTR_AS_MAX_LEVEL"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_MIN_LEVEL, "STORE_THE_DTR_AS_MIN_LEVEL"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_SYS_FAIL_LEVEL, "STORE_THE_DTR_AS_SYS_FAIL_LEVEL"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_PWR_ON_LEVEL, "STORE_THE_DTR_AS_PWR_ON_LEVEL"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_FADE_TIME, "STORE_THE_DTR_AS_FADE_TIME"},
|
|
{DALI_CMD_STORE_THE_DTR_AS_FADE_RATE, "STORE_THE_DTR_AS_FADE_RATE"},
|
|
{DALI_CMD_STORE_DTR_AS_SHORT_ADDRESS, "STORE_DTR_AS_SHORT_ADDRESS"},
|
|
{DALI_CMD_QUERY_STATUS, "QUERY_STATUS"},
|
|
{DALI_CMD_QUERY_BALLAST, "QUERY_BALLAST"},
|
|
{DALI_CMD_QUERY_LAMP_FAILURE, "QUERY_LAMP_FAILURE"},
|
|
{DALI_CMD_QUERY_LAMP_POWER_ON, "QUERY_LAMP_POWER_ON"},
|
|
{DALI_CMD_QUERY_LIMIT_ERROR, "QUERY_LIMIT_ERROR"},
|
|
{DALI_CMD_QUERY_RESET_STATE, "QUERY_RESET_STATE"},
|
|
{DALI_CMD_QUERY_MISSING_SHORT_ADDRESS, "QUERY_MISSING_SHORT_ADDRESS"},
|
|
{DALI_CMD_QUERY_VERSION_NUMBER, "QUERY_VERSION_NUMBER"},
|
|
{DALI_CMD_QUERY_CONTENT_DTR, "QUERY_CONTENT_DTR"},
|
|
{DALI_CMD_QUERY_DEVICE_TYPE, "QUERY_DEVICE_TYPE"},
|
|
{DALI_CMD_QUERY_PHYSICAL_MINIMUM_LEVEL, "QUERY_PHYSICAL_MINIMUM_LEVEL"},
|
|
{DALI_CMD_QUERY_CONTENT_DTR1, "QUERY_CONTENT_DTR1"},
|
|
{DALI_CMD_QUERY_CONTENT_DTR2, "QUERY_CONTENT_DTR2"},
|
|
{DALI_CMD_QUERY_OPERATING_MODE, "QUERY_OPERATING_MODE"},
|
|
{DALI_CMD_QUERY_LIGHT_SOURCE_TYPE, "QUERY_LIGHT_SOURCE_TYPE"},
|
|
{DALI_CMD_QUERY_ACTUAL_LEVEL, "QUERY_ACTUAL_LEVEL"},
|
|
{DALI_CMD_QUERY_MAX_LEVEL, "QUERY_MAX_LEVEL"},
|
|
{DALI_CMD_QUERY_MIN_LEVEL, "QUERY_MIN_LEVEL"},
|
|
{DALI_CMD_QUERY_POWER_ON_LEVEL, "QUERY_POWER_ON_LEVEL"},
|
|
{DALI_CMD_QUERY_SYSTEM_FAILURE_LEVEL, "QUERY_SYSTEM_FAILURE_LEVEL"},
|
|
{DALI_CMD_QUERY_FADE_TIME_FADE_RATE, "QUERY_FADE_TIME/FADE_RATE"},
|
|
{DALI_CMD_QUERY_NEXT_DEVICE_TYPE, "QUERY_NEXT_DEVICE_TYPE"},
|
|
{DALI_CMD_QUERY_GROUPS_0_7, "QUERY_GROUPS_0-7"},
|
|
{DALI_CMD_QUERY_GROUP_8_15, "QUERY_GROUP_8-15"},
|
|
{DALI_CMD_QUERY_RANDOM_ADDRESS_H, "QUERY_RANDOM_ADDRESS_(H)"},
|
|
{DALI_CMD_QUERY_RANDOM_ADDRESS_M, "QUERY_RANDOM_ADDRESS_(M)"},
|
|
{DALI_CMD_QUERY_RANDOM_ADDRESS_L, "QUERY_RANDOM_ADDRESS_(L)"},
|
|
{DALI_CMD_READ_MEMORY_LOCATION, "READ_MEMORY_LOCATION"},
|
|
{DALI_CMD_DT8_STORE_DTR_AS_COLORX, "STORE_DTR_AS_COLORX"},
|
|
{DALI_CMD_DT8_STORE_DTR_AS_COLORY, "STORE_DTR_AS_COLORY"},
|
|
{DALI_CMD_DT8_ACTIVATE, "ACTIVATE"},
|
|
{DALI_CMD_DT8_SET_COLOR_TEMPERATURE, "SET_COLOR_TEMPERATURE"},
|
|
{DALI_CMD_DT8_STEP_UP_COLOR_TEMPERATURE, "STEP_UP_COLOR_TEMPERATURE"},
|
|
{DALI_CMD_DT8_STEP_DOWN_COLOR_TEMPERATURE, "STEP_DOWN_COLOR_TEMPERATURE"},
|
|
{DALI_CMD_QUERY_COLOR_STATUS, "QUERY_COLOR_STATUS"},
|
|
{DALI_CMD_QUERY_COLOR_TYPE, "QUERY_COLOR_TYPE"},
|
|
{DALI_CMD_QUERY_COLOR_VALUE, "QUERY_COLOR_VALUE"},
|
|
};
|
|
|
|
sCMD_ = {
|
|
{DALI_CMD_SPECIAL_TERMINATE, "TERMINATE"},
|
|
{DALI_CMD_SPECIAL_SET_DTR0, "SET_DTR0"},
|
|
{DALI_CMD_SPECIAL_INITIALIZE, "INITIALIZE"},
|
|
{DALI_CMD_SPECIAL_RANDOMIZE, "RANDOMIZE"},
|
|
{DALI_CMD_SPECIAL_COMPARE, "COMPARE"},
|
|
{DALI_CMD_SPECIAL_WITHDRAW, "WITHDRAW"},
|
|
{DALI_CMD_SPECIAL_SEARCHADDRH, "SEARCHADDRH"},
|
|
{DALI_CMD_SPECIAL_SEARCHADDRM, "SEARCHADDRM"},
|
|
{DALI_CMD_SPECIAL_SEARCHADDRL, "SEARCHADDRL"},
|
|
{DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS, "PROGRAM_SHORT_ADDRESS"},
|
|
{DALI_CMD_SPECIAL_VERIFY_SHORT_ADDRESS, "VERIFY_SHORT_ADDRESS"},
|
|
{DALI_CMD_SPECIAL_QUERY_SHORT_ADDRESS, "QUERY_SHORT_ADDRESS"},
|
|
{DALI_CMD_SPECIAL_PHYSICAL_SELECTION, "PHYSICAL_SELECTION"},
|
|
{DALI_CMD_SPECIAL_DT_SELECT, "DT_SELECT"},
|
|
{DALI_CMD_SPECIAL_SET_DTR_1, "SET_DTR_1"},
|
|
{DALI_CMD_SPECIAL_SET_DTR_2, "SET_DTR_2"},
|
|
};
|
|
|
|
queryCmd_ = {DALI_CMD_QUERY_STATUS,
|
|
DALI_CMD_QUERY_BALLAST,
|
|
DALI_CMD_QUERY_LAMP_FAILURE,
|
|
DALI_CMD_QUERY_LAMP_POWER_ON,
|
|
DALI_CMD_QUERY_LIMIT_ERROR,
|
|
DALI_CMD_QUERY_RESET_STATE,
|
|
DALI_CMD_QUERY_MISSING_SHORT_ADDRESS,
|
|
DALI_CMD_QUERY_VERSION_NUMBER,
|
|
DALI_CMD_QUERY_CONTENT_DTR,
|
|
DALI_CMD_QUERY_DEVICE_TYPE,
|
|
DALI_CMD_QUERY_PHYSICAL_MINIMUM_LEVEL,
|
|
DALI_CMD_QUERY_POWER_FAILURE,
|
|
DALI_CMD_QUERY_CONTENT_DTR1,
|
|
DALI_CMD_QUERY_CONTENT_DTR2,
|
|
DALI_CMD_QUERY_OPERATING_MODE,
|
|
DALI_CMD_QUERY_LIGHT_SOURCE_TYPE,
|
|
DALI_CMD_QUERY_ACTUAL_LEVEL,
|
|
DALI_CMD_QUERY_MAX_LEVEL,
|
|
DALI_CMD_QUERY_MIN_LEVEL,
|
|
DALI_CMD_QUERY_POWER_ON_LEVEL,
|
|
DALI_CMD_QUERY_SYSTEM_FAILURE_LEVEL,
|
|
DALI_CMD_QUERY_FADE_TIME_FADE_RATE,
|
|
DALI_CMD_QUERY_MANUFACTURER_SPECIFIC_MODE,
|
|
DALI_CMD_QUERY_NEXT_DEVICE_TYPE,
|
|
DALI_CMD_QUERY_EXTENDED_FADE_TIME,
|
|
DALI_CMD_QUERY_CONTROL_GEAR_FAILURE,
|
|
DALI_CMD_QUERY_GROUPS_0_7,
|
|
DALI_CMD_QUERY_GROUP_8_15,
|
|
DALI_CMD_QUERY_RANDOM_ADDRESS_H,
|
|
DALI_CMD_QUERY_RANDOM_ADDRESS_M,
|
|
DALI_CMD_QUERY_RANDOM_ADDRESS_L,
|
|
DALI_CMD_READ_MEMORY_LOCATION,
|
|
DALI_CMD_DT8_ACTIVATE,
|
|
DALI_CMD_DT8_SET_COLOR_TEMPERATURE,
|
|
DALI_CMD_DT8_STEP_UP_COLOR_TEMPERATURE,
|
|
DALI_CMD_DT8_STEP_DOWN_COLOR_TEMPERATURE,
|
|
DALI_CMD_QUERY_COLOR_VALUE};
|
|
for (int c = DALI_CMD_QUERY_SCENE_LEVEL_MIN; c <= DALI_CMD_QUERY_SCENE_LEVEL_MAX; c++) {
|
|
queryCmd_.push_back(c);
|
|
}
|
|
}
|
|
|
|
int DaliDecode::isQueryCmd(int cmd) const {
|
|
return std::find(queryCmd_.begin(), queryCmd_.end(), cmd) != queryCmd_.end() ? 1 : 0;
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeBright(int addr, int level) {
|
|
DecodedRecord r;
|
|
r.text = whoLabel(addr, true) + " DAPC level=" + std::to_string(level);
|
|
r.type = "brightness";
|
|
r.addr = addr;
|
|
r.cmd = level;
|
|
r.proto = 0x10;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeScene(int addr, int sceneCmd) {
|
|
const int sc = sceneCmd - DALI_CMD_GO_TO_SCENE_MIN;
|
|
DecodedRecord r;
|
|
r.text = whoLabel(addr, false) + " GO_TO_SCENE " + std::to_string(sc);
|
|
r.type = "cmd";
|
|
r.addr = addr;
|
|
r.cmd = sceneCmd;
|
|
r.proto = 0x10;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeCmd(int addr, int c) {
|
|
std::string name = "CMD 0x" + hex(c);
|
|
const auto it = cmd_.find(c);
|
|
if (it != cmd_.end()) name = it->second;
|
|
|
|
if (c >= DALI_CMD_SET_SCENE_MIN && c <= DALI_CMD_SET_SCENE_MAX) {
|
|
name = "SET_SCENE " + std::to_string(c - DALI_CMD_SET_SCENE_MIN);
|
|
} else if (c >= DALI_CMD_ADD_TO_GROUP_MIN && c <= DALI_CMD_ADD_TO_GROUP_MAX) {
|
|
name = "ADD_TO_GROUP " + std::to_string(c - DALI_CMD_ADD_TO_GROUP_MIN);
|
|
} else if (c >= DALI_CMD_REMOVE_FROM_GROUP_MIN && c <= DALI_CMD_REMOVE_FROM_GROUP_MAX) {
|
|
name = "REMOVE_FROM_GROUP " + std::to_string(c - DALI_CMD_REMOVE_FROM_GROUP_MIN);
|
|
}
|
|
|
|
DecodedRecord r;
|
|
r.text = whoLabel(addr, false) + " " + name;
|
|
r.type = "cmd";
|
|
r.addr = addr;
|
|
r.cmd = c;
|
|
r.proto = 0x10;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeSpCmd(int addr, int c) {
|
|
const int cmdByte = addr & 0xFF;
|
|
const int dataByte = c & 0xFF;
|
|
|
|
if (cmdByte == DALI_CMD_SPECIAL_COMPARE || cmdByte == DALI_CMD_SPECIAL_VERIFY_SHORT_ADDRESS ||
|
|
cmdByte == DALI_CMD_SPECIAL_QUERY_SHORT_ADDRESS) {
|
|
return querySpCMD(cmdByte, dataByte);
|
|
}
|
|
|
|
std::string name = "SPECIAL_CMD 0x" + hex(cmdByte);
|
|
const auto it = sCMD_.find(cmdByte);
|
|
if (it != sCMD_.end()) name = it->second;
|
|
|
|
if (cmdByte == DALI_CMD_SPECIAL_SET_DTR0) {
|
|
dtr0 = dataByte;
|
|
} else if (cmdByte == DALI_CMD_SPECIAL_SET_DTR_1) {
|
|
dtr1 = dataByte;
|
|
} else if (cmdByte == DALI_CMD_SPECIAL_SET_DTR_2) {
|
|
dtr2 = dataByte;
|
|
}
|
|
|
|
DecodedRecord r;
|
|
r.text = name + " data=0x" + hex(dataByte) + " (" + std::to_string(dataByte) + ")";
|
|
r.type = "special";
|
|
r.addr = addr;
|
|
r.cmd = c;
|
|
r.proto = 0x10;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::querySpCMD(int cmdByte, int dataByte) {
|
|
lastQueryCmd_ = cmdByte;
|
|
lastQueryAtMs_ = nowMs();
|
|
|
|
std::string name = "SPECIAL_CMD 0x" + hex(cmdByte);
|
|
const auto it = sCMD_.find(cmdByte);
|
|
if (it != sCMD_.end()) name = it->second;
|
|
|
|
DecodedRecord r;
|
|
r.text = name + " query data=0x" + hex(dataByte) + " (" + std::to_string(dataByte) + ")";
|
|
r.type = "query";
|
|
r.addr = cmdByte;
|
|
r.cmd = dataByte;
|
|
r.proto = 0x10;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeQuery(int addr, int c) {
|
|
lastQueryCmd_ = c;
|
|
lastQueryAtMs_ = nowMs();
|
|
|
|
std::string name = "QUERY 0x" + hex(c);
|
|
const auto it = cmd_.find(c);
|
|
if (it != cmd_.end()) name = it->second;
|
|
|
|
if (c >= DALI_CMD_QUERY_SCENE_LEVEL_MIN && c <= DALI_CMD_QUERY_SCENE_LEVEL_MAX) {
|
|
name = "QUERY_SCENE_LEVEL " + std::to_string(c - DALI_CMD_QUERY_SCENE_LEVEL_MIN);
|
|
}
|
|
|
|
if (c == DALI_CMD_QUERY_COLOR_VALUE) {
|
|
lastColourQueryAtMs_ = nowMs();
|
|
int t = dtr0;
|
|
if (t == 128) t = 0;
|
|
if (t == 130) t = 1;
|
|
pendingColourType_ = (t == 0 || t == 1 || t == 2) ? t : -1;
|
|
if (pendingColourType_ == 0) name = "QUERY_COLOUR_VALUE(x)";
|
|
if (pendingColourType_ == 1) name = "QUERY_COLOUR_VALUE(y)";
|
|
if (pendingColourType_ == 2) name = "QUERY_COLOUR_VALUE(ct)";
|
|
}
|
|
|
|
DecodedRecord r;
|
|
r.text = whoLabel(addr, false) + " " + name;
|
|
r.type = "query";
|
|
r.addr = addr;
|
|
r.cmd = c;
|
|
r.proto = 0x12;
|
|
return withRaw(r);
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decodeCmdResponse(int value, int /*gwPrefix*/) {
|
|
const int64_t now = nowMs();
|
|
if ((now - lastQueryAtMs_) > responseWindowMs || lastQueryCmd_ == 0) {
|
|
DecodedRecord r{"unknown back 0x" + hex(value) + " / " + std::to_string(value), "unknown", -1,
|
|
-1, 0xFF};
|
|
return withRaw(r);
|
|
}
|
|
|
|
const int c = lastQueryCmd_;
|
|
|
|
if (c == DALI_CMD_QUERY_CONTENT_DTR) dtr0 = value & 0xFF;
|
|
if (c == DALI_CMD_QUERY_CONTENT_DTR1) dtr1 = value & 0xFF;
|
|
if (c == DALI_CMD_QUERY_CONTENT_DTR2) dtr2 = value & 0xFF;
|
|
|
|
if (c == DALI_CMD_QUERY_STATUS) {
|
|
const auto ds = DaliStatus::fromByte(static_cast<uint8_t>(value));
|
|
std::ostringstream oss;
|
|
oss << "status gearPresent=" << yn(ds.controlGearPresent) << " lampFailure=" << yn(ds.lampFailure)
|
|
<< " lampOn=" << yn(ds.lampPowerOn) << " limitError=" << yn(ds.limitError)
|
|
<< " fadingDone=" << yn(ds.fadingCompleted) << " reset=" << yn(ds.resetState)
|
|
<< " missingAddr=" << yn(ds.missingShortAddress) << " psFault=" << yn(ds.psFault);
|
|
return withRaw({oss.str(), "response", -1, c, 0xFF});
|
|
}
|
|
|
|
if (c == DALI_CMD_QUERY_DEVICE_TYPE) {
|
|
const auto name = deviceTypeName(value);
|
|
std::string text = "QUERY_DEVICE_TYPE => ";
|
|
text += name.empty() ? ("0x" + hex(value) + " / " + std::to_string(value))
|
|
: (name + " (0x" + hex(value) + " / " + std::to_string(value) + ")");
|
|
return withRaw({text, "response", -1, c, 0xFF});
|
|
}
|
|
|
|
if (c == DALI_CMD_QUERY_LIGHT_SOURCE_TYPE) {
|
|
const auto name = lightSourceName(value);
|
|
std::string text = "QUERY_LIGHT_SOURCE_TYPE => ";
|
|
text += name.empty() ? ("0x" + hex(value) + " / " + std::to_string(value))
|
|
: (name + " (0x" + hex(value) + " / " + std::to_string(value) + ")");
|
|
return withRaw({text, "response", -1, c, 0xFF});
|
|
}
|
|
|
|
if (c == DALI_CMD_QUERY_FADE_TIME_FADE_RATE) {
|
|
const int ft = (value >> 4) & 0xF;
|
|
const int fr = value & 0xF;
|
|
return withRaw({"fade time index=" + std::to_string(ft) + ", fade rate code=" + std::to_string(fr),
|
|
"response", -1, c, 0xFF});
|
|
}
|
|
|
|
if (c >= DALI_CMD_QUERY_SCENE_LEVEL_MIN && c <= DALI_CMD_QUERY_SCENE_LEVEL_MAX) {
|
|
const int idx = c - DALI_CMD_QUERY_SCENE_LEVEL_MIN;
|
|
const std::string text = (value == 0xFF)
|
|
? ("scene level " + std::to_string(idx) + " = MASK")
|
|
: ("scene level " + std::to_string(idx) + " = " + std::to_string(value));
|
|
return withRaw({text, "response", -1, c, 0xFF});
|
|
}
|
|
|
|
if (pendingColourType_ >= 0 && (now - lastColourQueryAtMs_) <= 1000) {
|
|
const int combined = dtr1 * 256 + dtr0;
|
|
std::string pretty;
|
|
if (pendingColourType_ == 2) {
|
|
const int kelvin = combined == 0 ? 0 : (1000000 / combined);
|
|
pretty = "ct mirek=" + std::to_string(combined) + " kelvin=" + std::to_string(kelvin);
|
|
} else {
|
|
const char key = pendingColourType_ == 0 ? 'x' : 'y';
|
|
std::ostringstream oss;
|
|
oss << key << "=" << std::fixed << std::setprecision(4)
|
|
<< (static_cast<double>(combined) / 65535.0) << " (" << combined << ")";
|
|
pretty = oss.str();
|
|
}
|
|
return withRaw({"colour value " + pretty, "response", -1, c, 0xFF});
|
|
}
|
|
|
|
return withRaw({"0x" + hex(value) + " / " + std::to_string(value) + " / " + bin(value), "response",
|
|
-1, c, 0xFF});
|
|
}
|
|
|
|
DecodedRecord DaliDecode::decode(int addr, int c, int proto) {
|
|
if (addr >= DALI_CMD_SPECIAL_RANGE_MIN && addr <= DALI_CMD_SPECIAL_RANGE_MAX) {
|
|
return decodeSpCmd(addr, c);
|
|
}
|
|
if (proto == 0x12 || isQueryCmd(c) == 1) {
|
|
return decodeQuery(addr, c);
|
|
}
|
|
if ((addr & 1) == 0) {
|
|
return decodeBright(addr, c);
|
|
}
|
|
if (c >= DALI_CMD_GO_TO_SCENE_MIN && c <= DALI_CMD_GO_TO_SCENE_MAX) {
|
|
return decodeScene(addr, c);
|
|
}
|
|
if (proto == 0x11) {
|
|
if (c == DALI_CMD_QUERY_COLOR_VALUE) return decodeQuery(addr, c);
|
|
std::string name = "EXT 0x" + hex(c);
|
|
const auto it = cmd_.find(c);
|
|
if (it != cmd_.end()) name = it->second;
|
|
return withRaw({whoLabel(addr, false) + " " + name, "ext", addr, c, proto});
|
|
}
|
|
return decodeCmd(addr, c);
|
|
}
|
|
|
|
int64_t DaliDecode::nowMs() {
|
|
const auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now());
|
|
return now.time_since_epoch().count();
|
|
}
|
|
|
|
std::string DaliDecode::hex(int v) {
|
|
std::ostringstream oss;
|
|
oss << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << (v & 0xFF);
|
|
return oss.str();
|
|
}
|
|
|
|
std::string DaliDecode::bin(int v) {
|
|
std::string out;
|
|
out.reserve(8);
|
|
for (int i = 7; i >= 0; i--) {
|
|
out.push_back(((v >> i) & 0x1) ? '1' : '0');
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::string DaliDecode::yn(bool b) { return b ? "yes" : "no"; }
|
|
|
|
std::string DaliDecode::whoLabel(int addr, bool even) {
|
|
if (even) {
|
|
if (addr == 0xFE) return "broadcast";
|
|
if (addr >= 0x80 && addr <= 0x8F) return "group " + std::to_string(addr - 0x80);
|
|
return "short " + std::to_string(addr / 2);
|
|
}
|
|
if (addr == 0xFF) return "broadcast";
|
|
if (addr >= 0x80 && addr <= 0x8F) return "group " + std::to_string(addr - 0x80);
|
|
return "short " + std::to_string((addr - 1) / 2);
|
|
}
|
|
|
|
std::string DaliDecode::deviceTypeName(int v) {
|
|
static const std::map<int, std::string> map = {{0x00, "general control gear"},
|
|
{0x01, "self-contained emergency"},
|
|
{0x06, "LED control gear"},
|
|
{0x08, "colour control (DT8)"}};
|
|
const auto it = map.find(v);
|
|
return it == map.end() ? "" : it->second;
|
|
}
|
|
|
|
std::string DaliDecode::lightSourceName(int v) {
|
|
static const std::map<int, std::string> map = {
|
|
{0x00, "fluorescent"}, {0x01, "compact fluorescent"}, {0x02, "high intensity discharge"},
|
|
{0x04, "incandescent/halogen"}, {0x06, "LED"}, {0x07, "other"}};
|
|
const auto it = map.find(v);
|
|
return it == map.end() ? "" : it->second;
|
|
}
|
|
|
|
DecodedRecord DaliDecode::withRaw(const DecodedRecord& r) const {
|
|
if (!displayRaw) return r;
|
|
std::vector<std::string> parts;
|
|
if (r.addr >= 0) parts.push_back("0x" + hex(r.addr));
|
|
if (r.cmd >= 0) parts.push_back("0x" + hex(r.cmd));
|
|
|
|
if (parts.empty()) return r;
|
|
|
|
DecodedRecord out = r;
|
|
std::ostringstream oss;
|
|
oss << r.text << " [";
|
|
for (size_t i = 0; i < parts.size(); i++) {
|
|
if (i > 0) oss << ", ";
|
|
oss << parts[i];
|
|
}
|
|
oss << "]";
|
|
out.text = oss.str();
|
|
return out;
|
|
}
|