Constructing the Stack
How to build a kbox-stack instance — the MakeStack factory overloads, the caller-owned KnxStackStorage, StackParameters, and choosing between the Standard and Secure paths.
MakeStack
The stack is created by the MakeStack factory, not by a public constructor — the
concrete Stack type is hidden inside the archive. MakeStack placement-new's the stack
into your KnxStackStorage and returns an IKnxStack&. There are two overloads.
Standard (9 arguments) — plain telegrams, no KNX Data Secure:
IKnxStack& MakeStack(
KnxStackStorage& storage,
StackParameters& stackParameters,
IBusDriver& busDriver,
IWatchDog& watchDog,
ILed& knxLed,
IClock& clock,
ITransmitter& transmitter,
IButton& button,
KnxFlashLayout& layout);Secure (10 arguments) — adds an ISecurity& as the last argument:
IKnxStack& MakeStack(
KnxStackStorage& storage,
StackParameters& stackParameters,
IBusDriver& busDriver,
IWatchDog& watchDog,
ILed& knxLed,
IClock& clock,
ITransmitter& transmitter,
IButton& button,
KnxFlashLayout& layout,
ISecurity& security);Every reference you pass — stackParameters, all I<X> peripherals, the layout, and (for
secure) the security object — must outlive the returned IKnxStack&. Passing a temporary
or a stack-local produces a dangling reference. Give them static/file-scope lifetime. layout
must already be built (via MakeFlashLayout(), see below) before either overload runs.
MakeFlashLayout
Both MakeStack overloads above take a KnxFlashLayout&, not a raw IFlash&. You build
that layout first, from a single base flash region, with MakeFlashLayout():
static KnxFlashLayoutStorage layoutStorage; // static/file-scope lifetime — REQUIRED
// Classic — regions: {stack-state, user-data}.
KnxFlashLayout& layout = MakeFlashLayout(
layoutStorage, baseFlash, stackParameters, /*userDataPageCount=*/1u);The Secure overload additionally takes the SioSizing (so it can size the counter/SIO-key
regions):
// Secure — regions: {counter, sio-key, stack-state, user-data}.
KnxFlashLayout& layout = MakeFlashLayout(
layoutStorage, baseFlash, stackParameters, sioSizing, /*userDataPageCount=*/1u);layout.IsValid() is checked by Stack::Init() — an invalid layout reports
StackErrorTypeEnum_FLASH_LAYOUT_INVALID through onStackError and stops before any
flash-dependent step runs. See the
Integration Contract for the full error contract.
Builder/KnxDeviceStorage.h bundles KnxFlashLayoutStorage + KnxStackStorage (+, for
Secure, SecureStackStorage/SioStorage<S>) into one KnxDeviceStorage /
KnxSecureDeviceStorage<S> object per device, with forwarding overloads of
MakeFlashLayout/MakeStack/MakeSecure that take the bundle directly. This is the
recommended way to wire a new device — see
API Reference · Consumer storage bundles.
KnxStackStorage
MakeStack needs somewhere to place the stack object. That is KnxStackStorage — a
plain, aligned byte buffer you declare with static lifetime:
static KnxStackStorage stackStorage; // static/file-scope lifetime — REQUIREDNo heap. The buffer size is fixed at compile time and depends on KNX_APDU_MAX: the
larger APDU configuration selects a larger buffer. Because the storage is yours, its
lifetime is your responsibility — if it goes out of scope, the IKnxStack& returned by
MakeStack dangles. Declare it static (or global).
StackParameters
StackParameters bundles the six event callbacks, the four table sizes, the device
identity PID arrays, the manufacturer id, and a PropertyStore. You construct it once
and pass it (by reference) to MakeStack.
The constructor signature (order matters):
StackParameters(
onKnxTelegram, onDifference, onTelegram, onErrorKnxTelegram,
onResetCommand, onStackError,
addressTableSize, associationTableSize,
groupObjectTableSize, applicationProgramSize,
PID_PROGRAM_VERSION /* [5] */,
PID_HARDWARE_TYPE /* [6] */,
PID_SERIAL_NUMBER /* [6] */,
propertyStore,
manufacturerId = 0x023Eu,
maxApduLengthInit = 0x0037u);Standard vs Secure
Build the flash layout, then call the 9-argument MakeStack directly. No ISecurity is
involved; telegrams are plain.
static KnxFlashLayoutStorage layoutStorage;
KnxFlashLayout& layout = MakeFlashLayout(
layoutStorage, baseFlash, stackParameters, /*userDataPageCount=*/1u);
static KnxStackStorage stackStorage;
StackParameters stackParameters(/* ... */);
IKnxStack& stack = MakeStack(
stackStorage, stackParameters, busDriver, watchDog, knxLed,
clock, transmitter, button, layout);Build the flash layout, then the security object with MakeSecure (it reads the layout's
CounterView()/SioKeyView()), then pass the returned ISecurity& as the 10th argument to
MakeStack. The secure invariants (separate AES contexts, a single monotonic counter store)
are wired inside MakeSecure — you do not wire them by hand.
static KnxFlashLayoutStorage layoutStorage;
KnxFlashLayout& layout = MakeFlashLayout(
layoutStorage, baseFlash, stackParameters, sioSizing, /*userDataPageCount=*/1u);
static SecureStackStorage secureStorage; // static lifetime — REQUIRED
ISecurity& secure = MakeSecure(
secureStorage, layout, sioSizing, sioBuffers, deviceIA, clock);
static KnxStackStorage stackStorage;
IKnxStack& stack = MakeStack(
stackStorage, stackParameters, busDriver, watchDog, knxLed,
clock, transmitter, button, layout,
secure);See KNX Data Secure for the full secure setup.
Your application logic
Derive your logic from KnxLogicBase. Its constructor takes the IKnxStack& and
auto-calls SetLogic(this) — registration cannot be forgotten:
class MyLogic : public KnxLogicBase {
public:
explicit MyLogic(IKnxStack& stack) : KnxLogicBase(stack) {}
void Work() override { /* ... */ }
};
MyLogic logic(stack); // registers itself with the stack in its ctorThe concrete peripheral objects you pass to MakeStack (the bus driver, transceiver,
flash, LED, …) are platform-specific. On STM32 these are the Hal* classes wired to
HAL handles. See the platform walkthrough:
First Application.