Files
gateway/components/knx_dali_gw/src/dali_gateway_bridge.cpp
T
Tony 449a3a801a Add KNX DALI Gateway Module and Message Queue Implementation
- Introduced KnxDaliModule class for handling DALI message queuing, commissioning, and KNX group-object dispatch.
- Implemented Message and MessageQueue classes for managing message operations.
- Removed obsolete OpenKNX IDF component files and CMake configurations.
- Updated submodule reference for KNX.

Signed-off-by: Tony <tonylu@tony-cloud.com>
2026-05-15 12:34:13 +08:00

324 lines
11 KiB
C++

#include "dali_gateway_bridge.h"
#include "dali_define.hpp"
#include "dali_comm.hpp"
#include <algorithm>
#include <cmath>
namespace gateway {
namespace knx_dali_gw {
namespace {
constexpr double kArcMax = 254.0;
constexpr double kLogFactor = 3.0;
// DALI address encoding helpers (mirroring lib/dali/comm.dart).
// Short address 0-63 → (addr << 1) | 0x01 for commands.
constexpr uint8_t kShortAddrCmdBase = 0x01;
constexpr uint8_t kShortAddrArcBase = 0x00;
constexpr uint8_t kGroupAddrBase = 0x80;
constexpr uint8_t kBroadcastCmd = 0xFE;
constexpr uint8_t kBroadcastArc = 0xFF;
uint8_t makeShortCmdAddr(int addr) {
return static_cast<uint8_t>((addr << 1) | kShortAddrCmdBase);
}
uint8_t makeShortArcAddr(int addr) {
return static_cast<uint8_t>((addr << 1) | kShortAddrArcBase);
}
uint8_t makeGroupCmdAddr(int group) {
return static_cast<uint8_t>(kGroupAddrBase | (group << 1) | 0x01);
}
uint8_t makeBroadcastCmdAddr() { return kBroadcastCmd; }
uint8_t makeBroadcastArcAddr() { return kBroadcastArc; }
bool isBroadcastAddr(uint8_t raw) { return raw == kBroadcastCmd || raw == kBroadcastArc; }
bool isGroupAddr(uint8_t raw) { return (raw & 0x80) != 0 && !isBroadcastAddr(raw); }
int extractGroupAddr(uint8_t raw) { return (raw >> 1) & 0x0F; }
int extractShortAddr(uint8_t raw) { return (raw >> 1) & 0x3F; }
uint8_t encodeDaliRawAddr(DaliTarget target) {
switch (target.kind) {
case DaliTargetKind::kShortAddress:
return makeShortCmdAddr(target.address);
case DaliTargetKind::kGroup:
return makeGroupCmdAddr(target.address);
case DaliTargetKind::kBroadcast:
default:
return makeBroadcastCmdAddr();
}
}
} // namespace
// =============================================================================
// DaliTarget ↔ raw address encoding (public API)
// =============================================================================
uint8_t EncodeDaliRawAddr(DaliTarget target) {
return encodeDaliRawAddr(target);
}
DaliTarget DecodeDaliRawAddr(uint8_t raw_addr, int default_short_address) {
if (isBroadcastAddr(raw_addr)) {
return {DaliTargetKind::kBroadcast, 0};
}
if (isGroupAddr(raw_addr)) {
return {DaliTargetKind::kGroup, extractGroupAddr(raw_addr)};
}
int sa = extractShortAddr(raw_addr);
if (sa < 0 && default_short_address >= 0) {
sa = default_short_address;
}
return {DaliTargetKind::kShortAddress, sa};
}
// =============================================================================
// Arc power ↔ percentage conversion
// =============================================================================
double ArcToPercent(uint8_t arc) {
if (arc == 0) return 0.0;
return 100.0 * std::pow(static_cast<double>(arc) / kArcMax, kLogFactor);
}
uint8_t PercentToArc(double percent) {
if (percent <= 0.0) return 0;
if (percent >= 100.0) return 254;
return static_cast<uint8_t>(
std::round(kArcMax * std::pow(percent / 100.0, 1.0 / kLogFactor)));
}
// =============================================================================
// DaliGatewayBridge
// =============================================================================
DaliGatewayBridge::DaliGatewayBridge(DaliDomainService& dali, uint8_t gateway_id)
: dali_(dali), gateway_id_(gateway_id) {}
bool DaliGatewayBridge::sendRaw(DaliTarget target, uint8_t command) const {
return dali_.sendRaw(gateway_id_, encodeDaliRawAddr(target), command);
}
bool DaliGatewayBridge::sendExtRaw(DaliTarget target, uint8_t command) const {
return dali_.sendExtRaw(gateway_id_, encodeDaliRawAddr(target), command);
}
std::optional<uint8_t> DaliGatewayBridge::queryRaw(DaliTarget target, uint8_t command) const {
return dali_.queryRaw(gateway_id_, encodeDaliRawAddr(target), command);
}
bool DaliGatewayBridge::setArc(DaliTarget target, uint8_t arc) const {
return sendRaw(target, arc);
}
std::optional<uint8_t> DaliGatewayBridge::queryActualLevel(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_ACTUAL_LEVEL);
}
bool DaliGatewayBridge::on(DaliTarget target) const {
return sendRaw(target, DALI_CMD_RECALL_MAX);
}
bool DaliGatewayBridge::off(DaliTarget target) const {
return sendRaw(target, DALI_CMD_OFF);
}
bool DaliGatewayBridge::stepUp(DaliTarget target) const {
return sendRaw(target, DALI_CMD_RECALL_MAX);
}
bool DaliGatewayBridge::stepDown(DaliTarget target) const {
return sendRaw(target, DALI_CMD_OFF);
}
bool DaliGatewayBridge::recallMax(DaliTarget target) const {
return sendRaw(target, DALI_CMD_RECALL_MAX);
}
bool DaliGatewayBridge::recallMin(DaliTarget target) const {
return sendRaw(target, DALI_CMD_RECALL_MIN);
}
bool DaliGatewayBridge::goToScene(DaliTarget target, uint8_t scene) const {
return sendRaw(target, DALI_CMD_GO_TO_SCENE(scene & 0x0F));
}
std::optional<uint8_t> DaliGatewayBridge::queryStatus(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_STATUS);
}
std::optional<uint8_t> DaliGatewayBridge::queryDeviceType(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_DEVICE_TYPE);
}
std::optional<uint8_t> DaliGatewayBridge::queryMinLevel(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_MIN_LEVEL);
}
std::optional<uint8_t> DaliGatewayBridge::queryMaxLevel(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_MAX_LEVEL);
}
std::optional<uint8_t> DaliGatewayBridge::queryPowerOnLevel(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_POWER_ON_LEVEL);
}
std::optional<uint8_t> DaliGatewayBridge::querySystemFailureLevel(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_SYSTEM_FAILURE_LEVEL);
}
std::optional<uint8_t> DaliGatewayBridge::queryFadeTimeRate(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_FADE_TIME_FADE_RATE);
}
std::optional<uint8_t> DaliGatewayBridge::queryFadeTime(int short_address) const {
return dali_.queryRaw(gateway_id_, makeShortCmdAddr(short_address),
DALI_CMD_QUERY_EXTENDED_FADE_TIME);
}
std::optional<uint16_t> DaliGatewayBridge::queryGroups(int short_address) const {
return dali_.queryGroupMask(gateway_id_, short_address);
}
std::optional<uint8_t> DaliGatewayBridge::querySceneLevel(int short_address,
uint8_t scene) const {
return dali_.querySceneLevel(gateway_id_, short_address, scene & 0x0F);
}
// ---- DT8 ----
bool DaliGatewayBridge::setColourTemperature(int short_address, int kelvin) const {
return dali_.setColTemp(gateway_id_, short_address, kelvin);
}
bool DaliGatewayBridge::setColourRGB(int short_address, uint8_t r, uint8_t g,
uint8_t b) const {
return dali_.setColourRGB(gateway_id_, short_address, r, g, b);
}
std::optional<DaliDomainSnapshot> DaliGatewayBridge::dt8StatusSnapshot(
int short_address) const {
return dali_.dt8StatusSnapshot(gateway_id_, short_address);
}
std::optional<DaliDomainSnapshot> DaliGatewayBridge::dt8SceneColorReport(
int short_address, int scene) const {
return dali_.dt8SceneColorReport(gateway_id_, short_address, scene);
}
// ---- Scenes & groups ----
bool DaliGatewayBridge::setDtr(uint8_t value) const {
return dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(),
DALI_CMD_SPECIAL_SET_DTR0) &&
dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(), value);
}
bool DaliGatewayBridge::setDtrAsScene(DaliTarget target, uint8_t scene) const {
return sendRaw(target, DALI_CMD_SET_SCENE(scene & 0x0F));
}
bool DaliGatewayBridge::addToGroup(DaliTarget target, uint8_t group) const {
return sendRaw(target, DALI_CMD_ADD_TO_GROUP(group & 0x0F));
}
bool DaliGatewayBridge::removeFromGroup(DaliTarget target, uint8_t group) const {
return sendRaw(target, DALI_CMD_REMOVE_FROM_GROUP(group & 0x0F));
}
bool DaliGatewayBridge::removeFromScene(DaliTarget target, uint8_t scene) const {
return sendRaw(target, DALI_CMD_REMOVE_SCENE(scene & 0x0F));
}
bool DaliGatewayBridge::setSceneLevel(DaliTarget target, uint8_t scene,
uint8_t level) const {
return setDtr(level) && setDtrAsScene(target, scene);
}
// ---- Commissioning ----
bool DaliGatewayBridge::initialise(DaliTarget target) const {
return sendRaw(target, DALI_CMD_SPECIAL_INITIALIZE);
}
bool DaliGatewayBridge::randomise() const {
return sendRaw({DaliTargetKind::kBroadcast, 0}, DALI_CMD_SPECIAL_RANDOMIZE);
}
bool DaliGatewayBridge::searchAddrH(uint8_t high) const {
return dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(),
DALI_CMD_SPECIAL_SEARCHADDRH) &&
dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(), high);
}
bool DaliGatewayBridge::searchAddrM(uint8_t middle) const {
return dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(),
DALI_CMD_SPECIAL_SEARCHADDRM) &&
dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(), middle);
}
bool DaliGatewayBridge::searchAddrL(uint8_t low) const {
return dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(),
DALI_CMD_SPECIAL_SEARCHADDRL) &&
dali_.sendRaw(gateway_id_, makeBroadcastCmdAddr(), low);
}
bool DaliGatewayBridge::compare() const {
return sendRaw({DaliTargetKind::kBroadcast, 0}, DALI_CMD_SPECIAL_COMPARE);
}
bool DaliGatewayBridge::withdraw() const {
return sendRaw({DaliTargetKind::kBroadcast, 0}, DALI_CMD_SPECIAL_WITHDRAW);
}
bool DaliGatewayBridge::terminate() const {
return sendRaw({DaliTargetKind::kBroadcast, 0}, DALI_CMD_SPECIAL_TERMINATE);
}
bool DaliGatewayBridge::programShort(DaliTarget target, uint8_t short_address) const {
const uint8_t raw = (short_address << 1) | 0x01;
return dali_.sendRaw(gateway_id_, encodeDaliRawAddr(target),
DALI_CMD_SPECIAL_PROGRAM_SHORT_ADDRESS) &&
dali_.sendRaw(gateway_id_, encodeDaliRawAddr(target), raw);
}
bool DaliGatewayBridge::verifyShort(DaliTarget target) const {
return sendRaw(target, DALI_CMD_SPECIAL_VERIFY_SHORT_ADDRESS);
}
std::optional<uint8_t> DaliGatewayBridge::queryShort(DaliTarget target) const {
return dali_.queryRaw(gateway_id_, encodeDaliRawAddr(target),
DALI_CMD_SPECIAL_QUERY_SHORT_ADDRESS);
}
bool DaliGatewayBridge::allocateAllAddr(int start_address) const {
return dali_.allocateAllAddr(gateway_id_, start_address);
}
void DaliGatewayBridge::stopAllocAddr() const {
dali_.stopAllocAddr(gateway_id_);
}
bool DaliGatewayBridge::resetAndAllocAddr(int start_address, bool remove_addr_first,
bool close_light) const {
return dali_.resetAndAllocAddr(gateway_id_, start_address, remove_addr_first, close_light);
}
bool DaliGatewayBridge::resetBus() const {
return dali_.resetBus(gateway_id_);
}
} // namespace knx_dali_gw
} // namespace gateway