API Reference
The portable public API of the kbox-stack KNX library — header map, the IKnxStack facade, the MakeStack / MakeSecure factories, models, helpers, serialization, and storage.
The public surface of kbox-stack is portable: every type on this page is
MCU-agnostic, and each hardware dependency is a pure I<X> interface. The
prebuilt static library ships for Cortex-M3 / STM32F103xB today, but nothing on
this page is STM32-specific.
Only the signatures are public. The library is distributed as a precompiled
static .a plus 88 public headers under Stack/…; the implementation is not
shipped. Include a type with its namespaced path, e.g. #include <Stack/Logic/IKnxStack.h>.
Header map
Every public header lives under Stack/<dir>/. This is what each directory
provides.
| Directory | Provides |
|---|---|
Builder/ | KnxTelegramBuilder — fluent construction of a raw KNX telegram / frame. StackFlashLayout.h — MakeFlashLayout() and the KnxFlashLayout type. KnxDeviceStorage.h — the KnxDeviceStorage / KnxSecureDeviceStorage<S> consumer storage bundles. |
Comparator/ | Difference — the old/new value pair delivered on a group-object change. |
Config/ | StackConfig.h — compile-time knobs (KNX_APDU_MAX, KNX_FRAME_MAX, KNX_OBJ_VALUE_MAX). |
Enums/ | All wire and stack enums. See Enums Reference. |
Helpers/ | ByteSpan, FixedString, FixedVec, FrameRing, and the Dpt:: codecs. |
Logger/ | BaseLogger — the logging base and LogLevelEnum. See Logging. |
Logic/ | IKnxStack facade, ILogic, KnxLogicBase, and the MakeStack factory. |
Models/ | DeviceObject, KnxData, KnxTelegram, KnxAddress, GroupObjectTables, StackParameters, GroupObjectFlag, interface-object / property models. |
Peripheral/ | The I<X> peripheral interfaces (IBusDriver, IClock, IFlash, ILed, IButton, IWatchDog, ITransmitter) plus Base<X> and STM32 Hal<X> implementations. |
Security/ | ISecurity, IKnxSecure.h (the MakeSecure factory), SecureConfig.h. See KNX Data Secure. |
Serialize/ | Serializable, Serialized, SerializedTypeEnum. |
Storage/ | FlashDataStore — magic + CRC framed blob persistence over an IFlash&. |
Stack facade
IKnxStack is the whole runtime surface. You obtain one from MakeStack(...)
and drive it from your main loop.
| Method | Signature | Purpose |
|---|---|---|
Init | void Init() | One-time init; loads machine state from flash. Call once after construction. |
Work | void Work() | Drives the state machine and your logic.Work(). Call every main-loop iteration. |
Process | void Process() | Bus-driver ISR hook — call from the RX/TX interrupt (wiring is platform-specific). |
OnButtonPress | void OnButtonPress() | Signals the programming-mode button event to the stack. |
SetLogic | void SetLogic(ILogic* logic) | Installs the application logic. Deriving from KnxLogicBase auto-registers, so this is usually not called directly. |
IsAllMachineStateLoaded | bool IsAllMachineStateLoaded() | true once every stored table loaded successfully. |
Tables | GroupObjectTables& Tables() | Access to the group-object database (push objects, resolve addresses). |
SendTelegramGroupValueWrite | void SendTelegramGroupValueWrite(DeviceObject& deviceParameter) | Sends a GroupValueWrite for the given object's current value. |
EnableGroupObjectCommunication | void EnableGroupObjectCommunication() | Enables group-object traffic. |
DisableGroupObjectCommunication | void DisableGroupObjectCommunication() | Disables group-object traffic. |
SaveUserData | bool SaveUserData(const uint8_t* data, uint16_t size) | Persists your own app data (e.g. an AC-state snapshot) into the layout's UserDataView() region. Returns false if size exceeds UserDataCapacity(), the flash write fails, or the flash layout is invalid. |
LoadUserData | uint16_t LoadUserData(uint8_t* out, uint16_t maxSize) | Loads previously-saved app data. Returns the valid payload length (>0), or 0 if nothing was saved, the data is corrupt (bad magic/CRC), or the flash layout is invalid — out must not be used when the return value is 0. |
UserDataCapacity | uint16_t UserDataCapacity() const | Maximum size SaveUserData accepts (header excluded). Returns 0 if the flash layout is invalid. |
MakeFlashLayout
Before either factory below runs, one base flash region (a single IFlash&
you provide) is split into the stack's own named sub-regions by
MakeFlashLayout(). It is placement-constructed the same way MakeStack/
MakeSecure are — into a caller-owned KnxFlashLayoutStorage — and returns a
KnxFlashLayout& that both other factories consume.
// KBOX_FLASH_LAYOUT_STORAGE_SIZE == 256u (host upper bound).
struct KnxFlashLayoutStorage {
alignas(alignof(std::max_align_t)) unsigned char data[KBOX_FLASH_LAYOUT_STORAGE_SIZE];
};
class KnxFlashLayout {
public:
IFlash& StackStateView(); // stack machine-state region
IFlash& UserDataView(); // your own app-data region (SaveUserData/LoadUserData)
IFlash& CounterView(); // Secure only — Classic returns a valid but fail-closed view
IFlash& SioKeyView(); // Secure only — Classic returns a valid but fail-closed view
bool IsValid() const; // checked by Stack::Init() — see Integration Contract
};
// Classic — regions: {stack-state, user-data}.
KnxFlashLayout& MakeFlashLayout(KnxFlashLayoutStorage& storage, IFlash& baseFlash,
const StackParameters& sp, uint16_t userDataPageCount);
// Secure — regions: {counter, sio-key, stack-state, user-data}.
KnxFlashLayout& MakeFlashLayout(KnxFlashLayoutStorage& storage, IFlash& baseFlash,
const StackParameters& sp, const SioSizing& sioSizing,
uint16_t userDataPageCount);layout.IsValid() == false (misaligned base tail, or a region window that
overflows the 64KB tail-address space) is not checked by this factory
itself — it is propagated into MakeStack()'s Stack::Init(), which reports
StackErrorTypeEnum_FLASH_LAYOUT_INVALID and stops before any flash-dependent
step runs. See Integration Contract.
MakeStack / MakeSecure
The stack is placement-constructed into a caller-owned, opaquely-sized storage buffer. There is no heap allocation — you provide the memory and every dependency by reference, and all of them must outlive the returned handle.
// Storage size is chosen at compile time from KNX_APDU_MAX.
// KBOX_STACK_STORAGE_SIZE == 1344u when KNX_APDU_MAX >= 254
// == 952u otherwise
struct KnxStackStorage {
alignas(alignof(std::max_align_t)) unsigned char data[KBOX_STACK_STORAGE_SIZE];
};
// Classic (non-secure) stack.
IKnxStack& MakeStack(KnxStackStorage& storage, StackParameters& stackParameters,
IBusDriver& busDriver, IWatchDog& watchDog, ILed& knxLed,
IClock& clock, ITransmitter& transmitter, IButton& button,
KnxFlashLayout& layout);
// Secure stack — same, plus an ISecurity& from MakeSecure(...).
IKnxStack& MakeStack(KnxStackStorage& storage, StackParameters& stackParameters,
IBusDriver& busDriver, IWatchDog& watchDog, ILed& knxLed,
IClock& clock, ITransmitter& transmitter, IButton& button,
KnxFlashLayout& layout, ISecurity& security);The security object is built by its own factory. It needs the same
KnxFlashLayout& (it reads its CounterView()/SioKeyView()), a
sizing/buffers pair describing the key tables, the device individual address,
and a clock.
// KBOX_SECURE_STORAGE_SIZE == 1560u when KNX_APDU_MAX >= 254, else 1304u.
struct SecureStackStorage {
alignas(alignof(std::max_align_t)) unsigned char data[KBOX_SECURE_STORAGE_SIZE];
};
ISecurity& MakeSecure(SecureStackStorage& storage, KnxFlashLayout& layout,
const SioSizing& sizing, const SioBuffers& buffers,
KnxAddress deviceIA, IClock& clock);Give KnxStackStorage, SecureStackStorage, and KnxFlashLayoutStorage
static / file-scope lifetime. The returned reference points into that
buffer; a stack-local buffer dangles the moment its function returns. layout
itself must be constructed before both MakeSecure() and MakeStack().
See the Integration Contract.
Consumer storage bundles
Builder/KnxDeviceStorage.h collects the storage variables above (Classic: 2;
Secure: 4, plus the MakeBuffers()/sioBuffers threading) into one aggregate
per device kind, and adds header-only overloads of MakeFlashLayout/
MakeStack/MakeSecure that take the bundle instead of the individual
storages. The underlying factories (shown above) are unchanged — these are
one-line forwarders. This is the recommended way to wire a new device.
// ─── Classic ────────────────────────────────────────────────────────────
struct KnxDeviceStorage {
KnxFlashLayoutStorage layout;
KnxStackStorage stack;
};
KnxFlashLayout& MakeFlashLayout(KnxDeviceStorage& device, IFlash& baseFlash,
const StackParameters& sp, uint16_t userDataPageCount);
IKnxStack& MakeStack(KnxDeviceStorage& device, StackParameters& stackParameters,
IBusDriver& busDriver, IWatchDog& watchDog, ILed& knxLed,
IClock& clock, ITransmitter& transmitter, IButton& button,
KnxFlashLayout& layout);
// Usage:
static KnxDeviceStorage device;
KnxFlashLayout& layout = MakeFlashLayout(device, baseFlash, stackParameters, /*userDataPageCount=*/1u);
IKnxStack& stack = MakeStack(device, stackParameters, busDriver, watchDog, knxLed,
clock, transmitter, button, layout);
// ─── Secure — S is a `static constexpr SioSizing` bound as a template ref ──
template <const SioSizing& S>
struct KnxSecureDeviceStorage {
KnxFlashLayoutStorage layout;
SecureStackStorage secure;
KnxStackStorage stack;
SioStorage<S> sio;
};
template <const SioSizing& S>
KnxFlashLayout& MakeFlashLayout(KnxSecureDeviceStorage<S>& device, IFlash& baseFlash,
const StackParameters& sp, uint16_t userDataPageCount);
// deviceIA defaults to KnxAddress(0xFFFFu) — the S-Mode "unprogrammed" address;
// pass your own only if the device ships pre-addressed.
template <const SioSizing& S>
ISecurity& MakeSecure(KnxSecureDeviceStorage<S>& device, KnxFlashLayout& layout,
IClock& clock, KnxAddress deviceIA = KnxAddress(0xFFFFu));
template <const SioSizing& S>
IKnxStack& MakeStack(KnxSecureDeviceStorage<S>& device, StackParameters& stackParameters,
IBusDriver& busDriver, IWatchDog& watchDog, ILed& knxLed,
IClock& clock, ITransmitter& transmitter, IButton& button,
KnxFlashLayout& layout, ISecurity& security);
// Usage:
static constexpr SioSizing kSioSizing = {5u, 0u, 16u, 8u, 0u};
static KnxSecureDeviceStorage<kSioSizing> device;
KnxFlashLayout& layout = MakeFlashLayout(device, baseFlash, stackParameters, /*userDataPageCount=*/1u);
ISecurity& secure = MakeSecure(device, layout, clock); // deviceIA default 0xFFFF
IKnxStack& stack = MakeStack(device, stackParameters, busDriver, watchDog, knxLed,
clock, transmitter, button, layout, secure);Models
Helpers
Fixed-capacity, heap-free building blocks. All sizes are compile-time.
ByteSpan— a non-owning{const uint8_t*, size_t}view. Implicitly constructs fromFixedVec<uint8_t,N>andstd::vector<uint8_t>. Read-only.FixedString<N>— a bounded string builder (append,appendDec,appendHexByte,appendHexSpaced, …) that flagsoverflowed()instead of overrunning. Aliases:LogString(192) andErrString(16).FixedVec<T, N>— a fixed-capacitystd::vector-like container. It is fail-closed: overflowingpush_back/insertdrops the element and setsoverflowed()rather than reallocating or writing out of bounds. Aliases includeFrameBytes,ApduBytes,SmallApdu(16),MedApdu(72).- DPT codecs — the
Dpt::value encoders/decoders live underHelpers/Dpt/. See Value Encoding (DPT).
Serialize / Storage
Serialize/ is a compact tag-length-value scheme for packing typed records into
a byte blob; Storage/FlashDataStore persists an arbitrary blob to an IFlash&
behind a magic + CRC header.
// Serialize — a TLV record you Push into and iterate with Next().
class Serializable {
public:
virtual Serialized Serialize() = 0;
};
class Serialized {
public:
Serialized();
Serialized(uint8_t* data, uint8_t size);
void Push(uint8_t* data, SerializedTypeEnum type, uint8_t size);
void Push(Serialized serializedData);
bool Valid();
Serialized Next();
uint8_t GetType();
uint8_t* GetData();
uint8_t* GetPayload();
uint8_t GetDataSize();
uint8_t GetPayloadSize();
};
// Storage — framed blob persistence over an injected IFlash.
class FlashDataStore {
public:
explicit FlashDataStore(IFlash& flash);
bool Save(const uint8_t* data, uint16_t size);
uint16_t Load(uint8_t* out, uint16_t maxSize);
uint16_t Capacity() const;
};