OpenLcbCLib 1.0 Alpha
OpenSource C Library to create OpenLcb/Lcc Nodes
Loading...
Searching...
No Matches
openlcb_application_train.h File Reference

Application-level Train Control Protocol module. More...

Go to the source code of this file.

Data Structures

struct  interface_openlcb_application_train_t
 Application-provided callbacks for the train module. More...
 

Functions

void OpenLcbApplicationTrain_initialize (const interface_openlcb_application_train_t *interface)
 Initialises the train module and stores the callback interface.
 
train_state_tOpenLcbApplicationTrain_setup (openlcb_node_t *openlcb_node)
 Allocates a train state slot and assigns it to the node.
 
train_state_tOpenLcbApplicationTrain_get_state (openlcb_node_t *openlcb_node)
 Returns the train state for a node.
 
void OpenLcbApplicationTrain_100ms_timer_tick (uint8_t current_tick)
 Decrements the heartbeat countdown for all active train nodes.
 
void OpenLcbApplicationTrain_send_set_speed (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id, uint16_t speed)
 Sends a Set Speed/Direction command to a train node.
 
void OpenLcbApplicationTrain_send_set_function (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id, uint32_t fn_address, uint16_t fn_value)
 Sends a Set Function command to a train node.
 
void OpenLcbApplicationTrain_send_emergency_stop (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id)
 Sends an Emergency Stop command to a train node.
 
void OpenLcbApplicationTrain_send_query_speeds (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id)
 Sends a Query Speeds command to a train node.
 
void OpenLcbApplicationTrain_send_query_function (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id, uint32_t fn_address)
 Sends a Query Function command to a train node.
 
void OpenLcbApplicationTrain_send_assign_controller (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id)
 Sends an Assign Controller command to a train node.
 
void OpenLcbApplicationTrain_send_release_controller (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id)
 Sends a Release Controller command to a train node.
 
void OpenLcbApplicationTrain_send_noop (openlcb_node_t *openlcb_node, uint16_t train_alias, node_id_t train_node_id)
 Sends a NOOP (no-operation) management command to a train node.
 
void OpenLcbApplicationTrain_set_dcc_address (openlcb_node_t *openlcb_node, uint16_t dcc_address, bool is_long_address)
 Sets the DCC address and address type for a train node.
 
uint16_t OpenLcbApplicationTrain_get_dcc_address (openlcb_node_t *openlcb_node)
 Returns the DCC address for a train node.
 
bool OpenLcbApplicationTrain_is_long_address (openlcb_node_t *openlcb_node)
 Returns true if the train node uses long DCC addressing.
 
void OpenLcbApplicationTrain_set_speed_steps (openlcb_node_t *openlcb_node, uint8_t speed_steps)
 Sets the speed-step mode for a train node.
 
uint8_t OpenLcbApplicationTrain_get_speed_steps (openlcb_node_t *openlcb_node)
 Returns the speed-step mode for a train node.
 

Detailed Description

Application-level Train Control Protocol module.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Provides per-node train state, a fixed-size allocation pool, throttle-side send helpers, and a heartbeat countdown timer for the OpenLCB Train Control Protocol.

The protocol handler (protocol_train_handler.c) handles incoming commands automatically. This module provides the application developer API: state allocation, state access, throttle send functions, and the heartbeat tick. State is drawn from a pool sized by USER_DEFINED_TRAIN_NODE_COUNT. Each train node gets a slot via OpenLcbApplicationTrain_setup(), which stores a pointer in node->train_state. Non-train nodes have train_state == NULL.

Author
Jim Kueneman
Date
28 Feb 2026
See also
protocol_train_handler.h

Function Documentation

◆ OpenLcbApplicationTrain_initialize()

void OpenLcbApplicationTrain_initialize ( const interface_openlcb_application_train_t * interface)
extern

Initialises the train module and stores the callback interface.

Clears the train state pool and stores the interface pointer. Must be called once before any other function in this module.

Parameters
interfacePointer to a interface_openlcb_application_train_t.
Warning
Must be called before OpenLcbApplicationTrain_setup().

Algorithm:

  1. Zero the train state pool.
  2. Reset _train_pool_count to 0.
  3. Store the interface pointer.
* @param interface  Pointer to a interface_openlcb_application_train_t.
* 
Warning
Must be called before any other function in this module.

◆ OpenLcbApplicationTrain_setup()

train_state_t * OpenLcbApplicationTrain_setup ( openlcb_node_t * openlcb_node)
extern

Allocates a train state slot and assigns it to the node.

Draws the next free slot from the pool, zeroes it, stores a pointer in openlcb_node->train_state, and registers the standard train event IDs on the node (Train, Emergency Off/Stop, Clear Emergency Off/Stop).

Returns the existing slot immediately if the node already has one.

Parameters
openlcb_nodePointer to the openlcb_node_t to configure as a train.
Returns
Pointer to the train_state_t, or NULL if the node pointer is NULL or the pool is exhausted.
Warning
Returns NULL if the pool is full (USER_DEFINED_TRAIN_NODE_COUNT slots used).

Algorithm:

  1. Return NULL if openlcb_node is NULL.
  2. If the node already has train_state set, return the existing pointer.
  3. Return NULL if the pool is exhausted.
  4. Take the next pool slot, zero it, and store a pointer in openlcb_node->train_state.
  5. Set state->owner_node back to the node.
  6. Register the standard train event IDs: Train producer, Emergency Off/Stop consumers, Clear Emergency Off/Stop consumers.
  7. Return the new state pointer.
* @param openlcb_node  Pointer to the openlcb_node_t to configure as a train.
* 
Returns
Pointer to the train_state_t, or NULL if the node is NULL or the pool is full.

◆ OpenLcbApplicationTrain_get_state()

train_state_t * OpenLcbApplicationTrain_get_state ( openlcb_node_t * openlcb_node)
extern

Returns the train state for a node.

Parameters
openlcb_nodePointer to the openlcb_node_t.
Returns
Pointer to the train_state_t, or NULL if the node pointer is NULL or the node has no train state assigned.

Algorithm:

  1. Return NULL if openlcb_node is NULL.
  2. Return openlcb_node->train_state.
* @param openlcb_node  Pointer to the openlcb_node_t.
* 
Returns
Pointer to the train_state_t, or NULL.

◆ OpenLcbApplicationTrain_100ms_timer_tick()

void OpenLcbApplicationTrain_100ms_timer_tick ( uint8_t current_tick)
extern

Decrements the heartbeat countdown for all active train nodes.

Called from the main loop with the current global tick. At the halfway point of each node's heartbeat timeout, a NOOP request is sent to the controller. When the counter reaches zero the train is emergency-stopped and the on_heartbeat_timeout callback is fired.

Parameters
current_tickCurrent value of the global 100ms tick counter.
Note
Nodes with heartbeat_timeout_s == 0 are skipped.

Algorithm:

  1. Compute ticks elapsed since last call via subtraction.
  2. Skip if no time has elapsed (deduplication).
  3. For each pool slot with heartbeat_timeout_s > 0:
    • Decrement heartbeat_counter_100ms by ticks_elapsed (saturate at 0).
    • At the halfway point, call _send_heartbeat_request() to ping the controller.
    • At zero, set estop_active = true, zero set_speed preserving direction, forward Set Speed 0 to listeners, and fire on_heartbeat_timeout.
* @param current_tick  Current value of the global 100ms tick counter.
* 

◆ OpenLcbApplicationTrain_send_set_speed()

void OpenLcbApplicationTrain_send_set_speed ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id,
uint16_t speed )
extern

Sends a Set Speed/Direction command to a train node.

Builds and sends an addressed Train Protocol message that sets the speed and direction of a target train. The speed value uses the OpenLCB float16 encoding where the sign bit encodes direction.

Parameters
openlcb_nodePointer to the sending (throttle) openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.
speed16-bit speed/direction value in OpenLCB float16 format.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_SET_SPEED_DIRECTION.
  3. Set payload bytes 1-2 to the 16-bit speed value.
  4. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* @param speed           16-bit speed/direction in OpenLCB float16 format.
* 

◆ OpenLcbApplicationTrain_send_set_function()

void OpenLcbApplicationTrain_send_set_function ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id,
uint32_t fn_address,
uint16_t fn_value )
extern

Sends a Set Function command to a train node.

Builds and sends an addressed Train Protocol message that sets a DCC function on the target train. Function 0 is the headlight; higher numbers follow the NMRA function mapping.

Parameters
openlcb_nodePointer to the sending openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.
fn_address24-bit function address.
fn_value16-bit function value (0 = off, non-zero = on or analog value).

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_SET_FUNCTION.
  3. Set payload bytes 1-3 to the 24-bit function address.
  4. Set payload bytes 4-5 to the 16-bit function value.
  5. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* @param fn_address      24-bit function address.
* @param fn_value        16-bit function value.
* 

◆ OpenLcbApplicationTrain_send_emergency_stop()

void OpenLcbApplicationTrain_send_emergency_stop ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id )
extern

Sends an Emergency Stop command to a train node.

Commands the target train to stop immediately. The train node sets its speed to zero and activates its emergency-stop flag.

Parameters
openlcb_nodePointer to the sending openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_EMERGENCY_STOP.
  3. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* 

◆ OpenLcbApplicationTrain_send_query_speeds()

void OpenLcbApplicationTrain_send_query_speeds ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id )
extern

Sends a Query Speeds command to a train node.

Asks the train node to reply with its current set speed, actual speed (if available), and emergency-stop status.

Parameters
openlcb_nodePointer to the sending openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_QUERY_SPEEDS.
  3. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* 

◆ OpenLcbApplicationTrain_send_query_function()

void OpenLcbApplicationTrain_send_query_function ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id,
uint32_t fn_address )
extern

Sends a Query Function command to a train node.

Asks the train node to reply with the current value of the specified function address.

Parameters
openlcb_nodePointer to the sending openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.
fn_address24-bit function address to query.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_QUERY_FUNCTION.
  3. Set payload bytes 1-3 to the 24-bit function address.
  4. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* @param fn_address      24-bit function address to query.
* 

◆ OpenLcbApplicationTrain_send_assign_controller()

void OpenLcbApplicationTrain_send_assign_controller ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id )
extern

Sends an Assign Controller command to a train node.

Sends the throttle node's own Node ID as the controller to assign. Once assigned, the train node accepts speed/function commands only from the assigned controller and begins heartbeat monitoring.

Parameters
openlcb_nodePointer to the sending (throttle) openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_CONTROLLER_CONFIG, byte 1 to TRAIN_CONTROLLER_ASSIGN.
  3. Set payload bytes 2-7 to openlcb_node->id (the throttle's Node ID).
  4. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending (throttle) openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* 

◆ OpenLcbApplicationTrain_send_release_controller()

void OpenLcbApplicationTrain_send_release_controller ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id )
extern

Sends a Release Controller command to a train node.

Sends the throttle node's own Node ID as the controller to release. The train node clears its controller assignment and stops heartbeat monitoring.

Parameters
openlcb_nodePointer to the sending (throttle) openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_CONTROLLER_CONFIG, byte 1 to TRAIN_CONTROLLER_RELEASE.
  3. Set payload bytes 2-7 to openlcb_node->id (the throttle's Node ID).
  4. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending (throttle) openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* 

◆ OpenLcbApplicationTrain_send_noop()

void OpenLcbApplicationTrain_send_noop ( openlcb_node_t * openlcb_node,
uint16_t train_alias,
node_id_t train_node_id )
extern

Sends a NOOP (no-operation) management command to a train node.

Resets the train's heartbeat countdown timer without changing speed, functions, or any other state. Throttle applications should send this periodically to prevent heartbeat timeout and emergency stop.

Parameters
openlcb_nodePointer to the sending openlcb_node_t.
train_alias12-bit CAN alias of the target train node.
train_node_id48-bit node_id_t of the target train node.

Sends a NOOP (no-operation) management command to a train node.

Algorithm:

  1. Call _prepare_train_command(); return if it fails.
  2. Set payload byte 0 to TRAIN_MANAGEMENT, byte 1 to TRAIN_MGMT_NOOP.
  3. Call send_openlcb_msg().
* @param openlcb_node    Pointer to the sending openlcb_node_t.
* @param train_alias     12-bit CAN alias of the target train node.
* @param train_node_id   48-bit node_id_t of the target train node.
* 

◆ OpenLcbApplicationTrain_set_dcc_address()

void OpenLcbApplicationTrain_set_dcc_address ( openlcb_node_t * openlcb_node,
uint16_t dcc_address,
bool is_long_address )
extern

Sets the DCC address and address type for a train node.

Parameters
openlcb_nodePointer to the openlcb_node_t with an assigned train state.
dcc_addressDCC address (1–9999 for long, 1–127 for short).
is_long_addresstrue for long (four-digit) addressing, false for short.
Note
Silently ignored if the node pointer or train_state pointer is NULL.

Algorithm:

  1. Return if openlcb_node or train_state is NULL.
  2. Store dcc_address and is_long_address in the train state.
* @param openlcb_node    Pointer to the openlcb_node_t.
* @param dcc_address     DCC address value.
* @param is_long_address true for long addressing, false for short.
* 

◆ OpenLcbApplicationTrain_get_dcc_address()

uint16_t OpenLcbApplicationTrain_get_dcc_address ( openlcb_node_t * openlcb_node)
extern

Returns the DCC address for a train node.

Parameters
openlcb_nodePointer to the openlcb_node_t.
Returns
DCC address, or 0 if the node has no train state.

Algorithm:

  1. Return 0 if openlcb_node or train_state is NULL.
  2. Return train_state->dcc_address.
* @param openlcb_node  Pointer to the openlcb_node_t.
* 
Returns
DCC address, or 0 if the node has no train state.

◆ OpenLcbApplicationTrain_is_long_address()

bool OpenLcbApplicationTrain_is_long_address ( openlcb_node_t * openlcb_node)
extern

Returns true if the train node uses long DCC addressing.

Parameters
openlcb_nodePointer to the openlcb_node_t.
Returns
true for long addressing, false if short or node has no train state.

Algorithm:

  1. Return false if openlcb_node or train_state is NULL.
  2. Return train_state->is_long_address.
* @param openlcb_node  Pointer to the openlcb_node_t.
* 
Returns
true for long addressing, false otherwise.

◆ OpenLcbApplicationTrain_set_speed_steps()

void OpenLcbApplicationTrain_set_speed_steps ( openlcb_node_t * openlcb_node,
uint8_t speed_steps )
extern

Sets the speed-step mode for a train node.

Parameters
openlcb_nodePointer to the openlcb_node_t with an assigned train state.
speed_stepsSpeed-step count (14, 28, or 128).
Note
Silently ignored if the node pointer or train_state pointer is NULL.

Algorithm:

  1. Return if openlcb_node or train_state is NULL.
  2. Store speed_steps in train_state->speed_steps.
* @param openlcb_node  Pointer to the openlcb_node_t.
* @param speed_steps   Speed-step count (14, 28, or 128).
* 

◆ OpenLcbApplicationTrain_get_speed_steps()

uint8_t OpenLcbApplicationTrain_get_speed_steps ( openlcb_node_t * openlcb_node)
extern

Returns the speed-step mode for a train node.

Parameters
openlcb_nodePointer to the openlcb_node_t.
Returns
Speed-step count (14, 28, or 128), or 0 if the node has no train state.

Algorithm:

  1. Return 0 if openlcb_node or train_state is NULL.
  2. Return train_state->speed_steps.
* @param openlcb_node  Pointer to the openlcb_node_t.
* 
Returns
Speed-step count, or 0 if the node has no train state.

Copyright (c) 2026 Jim Kueneman all rights reserved. See the License