d8d0c39630
Signed-off-by: Tony <tonylu@tony-cloud.com>
142 lines
5.6 KiB
C++
142 lines
5.6 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;
|
|
int observer_updates = 0;
|
|
DaliGatewayStatusUpdate last_update;
|
|
cache.setStatusUpdateCallback([&](const DaliGatewayStatusUpdate& update) {
|
|
++status_updates;
|
|
last_update = update;
|
|
});
|
|
cache.addStatusUpdateCallback(
|
|
[&](const DaliGatewayStatusUpdate&) { ++observer_updates; });
|
|
|
|
assert(cache.setGroupMask(7, 4, 0x0001));
|
|
assert(cache.setCapabilities(7, 4, 0x0180, 0x07));
|
|
assert(cache.mirrorForwardFrame(7, 0x80, 42));
|
|
assert(status_updates == 1);
|
|
assert(observer_updates == status_updates);
|
|
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);
|
|
|
|
// Replacing the owning callback must not remove additive adapter observers.
|
|
cache.setStatusUpdateCallback({});
|
|
assert(cache.setActualLevel(7, 4, 43));
|
|
assert(status_updates == 1);
|
|
assert(observer_updates == 2);
|
|
|
|
// 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);
|
|
assert(restored_state.daliDeviceTypeMask == 0x0180);
|
|
assert(restored_state.dt8ColorTypeFeatures == 0x07);
|
|
|
|
// Version-one records remain readable and retain their original fields.
|
|
persisted[{8, 2}] = "1,129,9,2,111,0,0,0,4,254,0,0,0";
|
|
assert(restored.preloadChannel(8));
|
|
const auto migrated_state = restored.addressState(8, 2);
|
|
assert(migrated_state.groupMaskKnown);
|
|
assert(migrated_state.groupMask == 2);
|
|
assert(migrated_state.settings.minLevel == 4);
|
|
assert(!migrated_state.daliDeviceTypeMask.has_value());
|
|
|
|
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);
|
|
}
|