Kbox-UniStack Docs

Lifecycle & Main Loop

Driving a kbox-stack instance — the IKnxStack facade methods, Init vs Work vs Process, readiness checks, enabling group-object communication, and the programming button.

The facade

IKnxStack is the entire public surface you drive at runtime. Every method:

MethodSignaturePurpose
Initvoid Init()One-time boot: read persistent state from flash, load the individual address, init the driver/transceiver.
Workvoid Work()Call every main-loop iteration: process RX, drive TX, run your logic.
Processvoid Process()Step the stack's processing without the full Work cycle.
OnButtonPressvoid OnButtonPress()Notify the stack the programming button was pressed (toggle programming mode).
SetLogicvoid SetLogic(ILogic* logic)Register the application logic. KnxLogicBase calls this for you.
IsAllMachineStateLoadedbool IsAllMachineStateLoaded()True when every loadable object is in the LOADED state (device is configured).
TablesGroupObjectTables& Tables()Access the group-address ↔ object database.
SendTelegramGroupValueWritevoid SendTelegramGroupValueWrite(DeviceObject& deviceParameter)Publish an object's value to its group address(es).
EnableGroupObjectCommunicationvoid EnableGroupObjectCommunication()Allow group objects to send/receive on the bus.
DisableGroupObjectCommunicationvoid DisableGroupObjectCommunication()Suspend group-object communication.
SaveUserDatabool SaveUserData(const uint8_t* data, uint16_t size)Persist the application's own arbitrary-size data into the flash layout's user-data region. Returns false if size exceeds UserDataCapacity() or the underlying flash write fails.
LoadUserDatauint16_t LoadUserData(uint8_t* out, uint16_t maxSize)Load previously saved application data. Returns the valid payload length (0 = no valid data — never saved, or corrupt/torn write); out must not be used when the return value is 0.
UserDataCapacityuint16_t UserDataCapacity() constThe maximum size accepted by SaveUserData. Calls above this limit are rejected (not clamped).

Init vs Work vs Process

  • Init() runs once, before the main loop. It loads the persisted machine state from flash (individual address, per-object load states), falls back to defaults on first boot, and initializes the bus driver and transceiver.
  • Work() runs every main-loop iteration. It drains and decodes the RX queue, pushes any pending TX to the wire, calls your logic's Work(), and handles connection time-outs and the start-up run-state transition.
  • Process() advances the stack's processing step. Work() is the normal driver for a bare-metal super-loop; Process() exists for integrations that want finer control over the processing phase.
int main(void) {
  // ... platform + peripheral init ...
  logic.Init();          // your application's own init
  stack.Init();          // one-time stack boot: REQUIRED before the loop

  while (1) {
    stack.Work();        // every iteration
  }
}

Which method runs where:

  • Init() — once, in main() before the loop.
  • Work() / Process() — repeatedly, in the main loop.
  • OnButtonPress() — from an interrupt/ISR context (a GPIO EXTI handler), not the main loop.

Readiness: IsAllMachineStateLoaded

A freshly manufactured device is unconfigured until ETS downloads its tables. IsAllMachineStateLoaded() returns true only when all loadable objects (device object, address table, association table, group object table, application program) are in the LOADED state.

Use it as a gate: run application behaviour that depends on group communication only once the device reports loaded.

if (stack.IsAllMachineStateLoaded()) {
  // device is configured — safe to publish values, run scheduled logic, etc.
}

Enabling and disabling group object communication

EnableGroupObjectCommunication() / DisableGroupObjectCommunication() gate whether group objects participate on the bus. Disable to quiesce the device (for example during a maintenance or safe-stop condition) without tearing down the stack, and re-enable to resume.

Button and programming mode

KNX devices assign their individual (physical) address via programming mode, entered by a physical button. Wire your button interrupt to OnButtonPress():

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if (GPIO_Pin == KNX_BUTTON_Pin) {
    stack.OnButtonPress();   // enter/leave programming mode
  }
}

While programming mode is active the stack responds to ETS individual-address assignment. See the platform peripherals page for the button and LED wiring: STM32 Peripherals.

Next steps