Chapter 2 — Building and Running

Dedicated Build Guide

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
8-Bit Processor Constraint

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:

flowchart TD EVENTS["OPENLCB_COMPILE_EVENTS"] DATAGRAMS["OPENLCB_COMPILE_DATAGRAMS"] MEMCONFIG["OPENLCB_COMPILE_MEMORY_CONFIGURATION"] FIRMWARE["OPENLCB_COMPILE_FIRMWARE"] BTIME["OPENLCB_COMPILE_BROADCAST_TIME"] TRAIN["OPENLCB_COMPILE_TRAIN"] MEMCONFIG -->|"requires"| DATAGRAMS FIRMWARE -->|"requires"| MEMCONFIG FIRMWARE -->|"requires"| DATAGRAMS BTIME -->|"requires"| EVENTS TRAIN -->|"requires"| EVENTS TRAIN -->|"requires"| DATAGRAMS style EVENTS fill:#c8e6c9,stroke:#2e7d32 style DATAGRAMS fill:#c8e6c9,stroke:#2e7d32 style MEMCONFIG fill:#bbdefb,stroke:#1565c0 style FIRMWARE fill:#ffe0b2,stroke:#e65100 style BTIME fill:#e1bee7,stroke:#7b1fa2 style TRAIN fill:#ffccbc,stroke:#bf360c

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.

← Previous: Ch 1 — Project Overview Next: Ch 3 — Types and Constants →