Files
dali_cpp/tests/dali_gateway_test.cpp
T
Tony c5a079e779 Implement DALI Gateway Cache with State Management and Reconciliation
- Added DaliGatewayCache class for managing DALI device states, including address states, presence, and group statuses.
- Implemented methods for configuring cache, enabling/disabling features, and setting status update callbacks.
- Introduced state encoding/decoding for persistence and added support for CSV parsing.
- Created mutation handling for runtime status updates, group masks, scene levels, and settings.
- Developed reconciliation logic to handle incoming frames and classify mutations.
- Added tests to validate cache functionality, persistence, and DALI protocol handling.

Signed-off-by: Tony <tonylu@tony-cloud.com>
2026-08-01 01:52:12 +08:00

120 lines
4.7 KiB
C++

#include "dali_gateway.hpp"
#include <array>
#include <cassert>
#include <map>
#include <utility>
int main() {
DaliGatewayCache cache;
std::map<std::pair<uint8_t, uint8_t>, std::string> persisted;
int commits = 0;
cache.setPersistenceCallbacks({
[&](uint8_t channel, uint8_t address) -> std::optional<std::string> {
const auto it = persisted.find({channel, address});
return it == persisted.end() ? std::nullopt
: std::optional<std::string>(it->second);
},
[&](uint8_t channel, uint8_t address, const std::optional<std::string>& payload) {
if (payload.has_value()) {
persisted[{channel, address}] = *payload;
} else {
persisted.erase({channel, address});
}
return true;
},
[&]() {
++commits;
return true;
},
});
int status_updates = 0;
DaliGatewayStatusUpdate last_update;
cache.setStatusUpdateCallback([&](const DaliGatewayStatusUpdate& update) {
++status_updates;
last_update = update;
});
assert(cache.setGroupMask(7, 4, 0x0001));
assert(cache.mirrorForwardFrame(7, 0x80, 42));
assert(status_updates == 1);
assert(last_update.channel == 7);
assert(last_update.target.kind == DaliGatewayTargetKind::group);
assert(last_update.target.value == 0);
assert(last_update.status.actualLevel == 42);
assert(last_update.affectedShortAddresses == std::vector<uint8_t>{4});
assert(cache.groupStatus(7, 0).actualLevel == 42);
assert(cache.addressState(7, 4).status.actualLevel == 42);
// The command-state cache tracks DTR-dependent settings and applies a
// broadcast command to every state known by the adapter.
cache.mirrorForwardFrame(7, 0xA3, 12);
assert(cache.mirrorForwardFrame(7, 0x09, 0x2B));
assert(cache.addressState(7, 4).settings.minLevel == 12);
assert(cache.mirrorForwardFrame(7, 0xFF, 0x06));
assert(cache.addressState(7, 4).status.actualLevel == 12);
assert(cache.observeForwardFrame(7, 0x09, 0x60, DaliGatewayFrameOrigin::outsideBus));
assert(cache.pendingChannelFlags(7).needUpdateGroup);
assert(cache.flush());
assert(commits == 1);
assert(!persisted.empty());
DaliGatewayCache restored;
restored.setPersistenceCallbacks({
[&](uint8_t channel, uint8_t address) -> std::optional<std::string> {
const auto it = persisted.find({channel, address});
return it == persisted.end() ? std::nullopt
: std::optional<std::string>(it->second);
},
{},
{},
});
assert(restored.preloadChannel(7));
const auto restored_state = restored.addressState(7, 4);
assert(restored_state.groupMaskKnown);
assert(restored_state.groupMask == 0x0001);
assert(restored_state.settings.minLevel == 12);
assert(restored_state.status.stale);
DaliApplicationControllerConfig config;
config.shortAddress = 3;
config.randomAddress = 0x123456;
DaliApplicationController controller(config);
const auto capabilities = controller.handleForwardFrame({0x07, 0xFE, 0x46});
assert(capabilities.backwardFrame == 0x01);
const auto status = controller.handleForwardFrame({0x07, 0xFE, 0x30});
assert(status.backwardFrame == 0x28);
// Commission short address 5 by selecting the controller's random address.
controller.handleForwardFrame({0xC1, 0x01, 0xFF}, true);
controller.handleForwardFrame({0xC1, 0x05, 0x12});
controller.handleForwardFrame({0xC1, 0x06, 0x34});
controller.handleForwardFrame({0xC1, 0x07, 0x56});
const auto compared = controller.handleForwardFrame({0xC1, 0x03, 0x00});
assert(compared.backwardFrame == 0xFF);
const auto programmed = controller.handleForwardFrame({0xC1, 0x08, 0x0B});
assert(programmed.shortAddressChanged);
assert(programmed.shortAddress == 5);
const auto verified = controller.handleForwardFrame({0xC1, 0x09, 0x0B});
assert(verified.backwardFrame == 0xFF);
controller.handleForwardFrame({0xC1, 0x30, 0x5A});
const auto dtr0 = controller.handleForwardFrame({0x0B, 0xFE, 0x36});
assert(dtr0.backwardFrame == 0x5A);
const auto before_repeat = controller.handleForwardFrame({0x0B, 0xFE, 0x00});
assert(!before_repeat.identifyRequested);
const auto identity = controller.handleForwardFrame({0x0B, 0xFE, 0x00}, true);
assert(identity.identifyRequested);
DaliApplicationControllerConfig unaddressed_config;
unaddressed_config.shortAddress.reset();
DaliApplicationController unaddressed(unaddressed_config);
const auto missing_short_address = unaddressed.handleForwardFrame({0xFF, 0xFE, 0x33});
assert(missing_short_address.backwardFrame == 0xFF);
const auto unaddressed_status = unaddressed.handleForwardFrame({0xFF, 0xFE, 0x30});
assert(unaddressed_status.backwardFrame == 0x2C);
}