Chapter 2 — Building and Running
A comprehensive platform-specific build guide is planned as a separate document. This chapter provides a brief overview of the compile-time configuration system that every build must satisfy.
2.1 The Configuration Header
Every project that uses the library must provide an openlcb_user_config.h file on the compiler include path. The library core locates it automatically:
#if __has_include("openlcb_user_config.h")
#include "openlcb_user_config.h"
#elif __has_include("../../openlcb_user_config.h")
#include "../../openlcb_user_config.h"
#else
#error "openlcb_user_config.h not found. Copy templates/openlcb_user_config.h to your project include path."
#endif
If the header cannot be found, the build fails with a helpful error message directing you to copy the template file from the templates/ directory.
2.2 USER_DEFINED_* Macros
The configuration header defines all compile-time constants that control memory allocation and feature enablement. These are the required macros:
| Macro | Purpose | Typical Value |
|---|---|---|
USER_DEFINED_BASIC_BUFFER_DEPTH |
Number of 16-byte message buffers | 32 |
USER_DEFINED_DATAGRAM_BUFFER_DEPTH |
Number of 72-byte message buffers | 4 |
USER_DEFINED_SNIP_BUFFER_DEPTH |
Number of 256-byte message buffers | 4 |
USER_DEFINED_STREAM_BUFFER_DEPTH |
Number of 512-byte message buffers | 1 |
USER_DEFINED_NODE_BUFFER_DEPTH |
Maximum virtual nodes | 1-4 |
USER_DEFINED_CDI_LENGTH |
CDI XML buffer size (bytes) | 2000-20000 |
USER_DEFINED_FDI_LENGTH |
FDI buffer size (bytes) | 100-1000 |
USER_DEFINED_PRODUCER_COUNT |
Max produced events per node | 8-64 |
USER_DEFINED_PRODUCER_RANGE_COUNT |
Max producer event ranges (must be >= 1) | 1-5 |
USER_DEFINED_CONSUMER_COUNT |
Max consumed events per node | 8-32 |
USER_DEFINED_CONSUMER_RANGE_COUNT |
Max consumer event ranges (must be >= 1) | 1-5 |
USER_DEFINED_CONFIG_MEM_USER_NAME_ADDRESS |
Config memory address for user name | 0x00000000 |
USER_DEFINED_CONFIG_MEM_USER_DESCRIPTION_ADDRESS |
Config memory address for user description | 62 |
USER_DEFINED_TRAIN_NODE_COUNT |
Max simultaneous train nodes | 0-4 |
USER_DEFINED_MAX_LISTENERS_PER_TRAIN |
Max consist members per train | 4-6 |
USER_DEFINED_MAX_TRAIN_FUNCTIONS |
DCC function count (F0-F28 = 29) | 29 |
On 8-bit processors, the total number of message buffers (BASIC + DATAGRAM + SNIP + STREAM) must not exceed 126. This is because buffer indices are stored in uint8_t fields with sentinel values reserved.
2.3 Feature Flags
Feature flags are #define symbols (no value needed) that enable or disable entire protocol modules at compile time. Unneeded code is completely excluded, saving flash and RAM on constrained targets.
| Flag | Enables |
|---|---|
OPENLCB_COMPILE_EVENTS |
Event Transport Protocol (producer/consumer identification, PCER) |
OPENLCB_COMPILE_DATAGRAMS |
Datagram Protocol (reliable point-to-point transfer) |
OPENLCB_COMPILE_MEMORY_CONFIGURATION |
Memory Configuration Protocol (read/write address spaces) |
OPENLCB_COMPILE_FIRMWARE |
Firmware Upgrade Protocol |
OPENLCB_COMPILE_BROADCAST_TIME |
Broadcast Time Protocol (layout fast clock) |
OPENLCB_COMPILE_TRAIN |
Train Control Protocol (speed, functions, consist) |
2.4 Feature Flag Dependencies
Some protocols depend on others. The dependency chain is:
For example, OPENLCB_COMPILE_MEMORY_CONFIGURATION requires OPENLCB_COMPILE_DATAGRAMS because configuration memory commands are carried inside datagrams. Similarly, OPENLCB_COMPILE_BROADCAST_TIME requires OPENLCB_COMPILE_EVENTS because broadcast time uses event IDs to encode time, date, and rate information.
2.5 Example Configuration
A typical configuration for a standard node with broadcast time support:
// Feature Flags
#define OPENLCB_COMPILE_EVENTS
#define OPENLCB_COMPILE_DATAGRAMS
#define OPENLCB_COMPILE_MEMORY_CONFIGURATION
#define OPENLCB_COMPILE_FIRMWARE
#define OPENLCB_COMPILE_BROADCAST_TIME
// Buffer Pool Sizes
#define USER_DEFINED_BASIC_BUFFER_DEPTH 32
#define USER_DEFINED_DATAGRAM_BUFFER_DEPTH 4
#define USER_DEFINED_SNIP_BUFFER_DEPTH 4
#define USER_DEFINED_STREAM_BUFFER_DEPTH 1
// Node Configuration
#define USER_DEFINED_NODE_BUFFER_DEPTH 4
#define USER_DEFINED_PRODUCER_COUNT 64
#define USER_DEFINED_PRODUCER_RANGE_COUNT 5
#define USER_DEFINED_CONSUMER_COUNT 32
#define USER_DEFINED_CONSUMER_RANGE_COUNT 5
// Memory Configuration
#define USER_DEFINED_CDI_LENGTH 20000
#define USER_DEFINED_FDI_LENGTH 1000
#define USER_DEFINED_CONFIG_MEM_USER_NAME_ADDRESS 0x00000000
#define USER_DEFINED_CONFIG_MEM_USER_DESCRIPTION_ADDRESS 63
// Train Configuration
#define USER_DEFINED_TRAIN_NODE_COUNT 4
#define USER_DEFINED_MAX_LISTENERS_PER_TRAIN 6
#define USER_DEFINED_MAX_TRAIN_FUNCTIONS 29
2.6 CAN Transport Configuration
The CAN transport layer has its own compile-time constant defined in can_types.h:
| Macro | Default | Purpose |
|---|---|---|
USER_DEFINED_CAN_MSG_BUFFER_DEPTH |
10 | Number of CAN frame buffers in the pool (max 254) |
ALIAS_MAPPING_BUFFER_DEPTH |
USER_DEFINED_NODE_BUFFER_DEPTH |
Number of alias mapping table slots |
These can be overridden via compiler command-line defines (e.g., -D USER_DEFINED_CAN_MSG_BUFFER_DEPTH=20) or by defining them in openlcb_user_config.h before the CAN headers are included.