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

Implementation of the main OpenLCB protocol state machine dispatcher. More...

Functions

void OpenLcbMainStatemachine_initialize (const interface_openlcb_main_statemachine_t *interface_openlcb_main_statemachine)
 Stores the callback interface and wires up the outgoing message buffer.
 
bool OpenLcbMainStatemachine_does_node_process_msg (openlcb_statemachine_info_t *statemachine_info)
 Returns true if the node should process this message.
 
void OpenLcbMainStatemachine_load_interaction_rejected (openlcb_statemachine_info_t *statemachine_info)
 Builds an Optional Interaction Rejected response for the current message.
 
void OpenLcbMainStatemachine_process_main_statemachine (openlcb_statemachine_info_t *statemachine_info)
 Routes incoming message to the correct protocol handler based on MTI.
 
bool OpenLcbMainStatemachine_handle_outgoing_openlcb_message (void)
 Sends the pending outgoing message if one is valid.
 
bool OpenLcbMainStatemachine_handle_try_reenumerate (void)
 Re-dispatches the current message when a handler requests multi-message enumeration.
 
bool OpenLcbMainStatemachine_handle_try_pop_next_incoming_openlcb_message (void)
 Pops the next incoming message from the receive FIFO when idle.
 
bool OpenLcbMainStatemachine_handle_try_enumerate_first_node (void)
 Begins node enumeration by fetching the first node and dispatching the message.
 
bool OpenLcbMainStatemachine_handle_try_enumerate_next_node (void)
 Advances to the next node and dispatches the current message.
 
void OpenLcbMainStatemachine_run (void)
 Runs one iteration of the main state machine dispatch loop.
 
openlcb_statemachine_info_tOpenLcbMainStatemachine_get_statemachine_info (void)
 Returns pointer to internal state. For unit testing only.
 

Detailed Description

Implementation of the main OpenLCB protocol state machine dispatcher.

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.

This file implements the central message routing and processing engine for OpenLCB protocol handling. The state machine provides a unified dispatch mechanism that routes incoming messages to appropriate protocol handlers based on Message Type Indicator (MTI) values.

Architecture: The implementation uses a single static state machine context that maintains:

  • Current incoming message being processed
  • Outgoing message buffer for responses
  • Current node being enumerated
  • Interface callbacks for all protocol handlers

Processing model: Messages are processed through node enumeration, where each incoming message is evaluated against every active node in the system. Nodes can filter messages based on addressing (global vs addressed) and node state.

The main processing loop (run function) operates in priority order:

  1. Transmit pending outgoing messages (highest priority)
  2. Handle multi-message responses via re-enumeration
  3. Pop new incoming message from queue
  4. Enumerate nodes and dispatch to handlers

Protocol support:

  • Required: Message Network Protocol, Protocol Support (PIP)
  • Optional: SNIP, Events, Train, Datagrams, Streams Optional protocols with NULL handlers automatically generate Interaction Rejected responses for compliance with OpenLCB specifications.

Thread safety: Resource locking callbacks protect access to shared buffer pools and FIFOs.

Author
Jim Kueneman
Date
8 Mar 2026
See also
openlcb_main_statemachine.h - Public interface
openlcb_types.h - Core data structures
OpenLCB Standard S-9.7.3 - Message Network Protocol

Function Documentation

◆ OpenLcbMainStatemachine_initialize()

void OpenLcbMainStatemachine_initialize ( const interface_openlcb_main_statemachine_t * interface_openlcb_main_statemachine)

Stores the callback interface and wires up the outgoing message buffer.

Stores the callback interface and prepares internal state.

Algorithm:

  1. Store interface pointer
  2. Link outgoing message buffer pointers, set payload type to STREAM
  3. Clear message and payload, mark buffer as allocated
  4. Set incoming message to NULL, clear enumerate flag, set node to NULL
* @param interface_openlcb_main_statemachine Pointer to populated interface structure
* 

◆ OpenLcbMainStatemachine_does_node_process_msg()

bool OpenLcbMainStatemachine_does_node_process_msg ( openlcb_statemachine_info_t * statemachine_info)

Returns true if the node should process this message.

Address filter. Returns true if the node should process this message.

Algorithm:

  1. Return false if node is NULL or not initialized
  2. Accept global (unaddressed) messages
  3. Accept addressed messages whose dest alias/ID matches this node
  4. Special case: always accept MTI_VERIFY_NODE_ID_GLOBAL
* @param statemachine_info Pointer to state machine context
* 
Returns
true if node should process message, false otherwise

◆ OpenLcbMainStatemachine_load_interaction_rejected()

void OpenLcbMainStatemachine_load_interaction_rejected ( openlcb_statemachine_info_t * statemachine_info)

Builds an Optional Interaction Rejected response for the current message.

Builds an Interaction Rejected response for the current incoming message. Internal use.

Algorithm:

  1. Validate all required pointers (return early if NULL)
  2. Load OIR message with error code and triggering MTI in payload
  3. Set valid flag for transmission
* @param statemachine_info Pointer to state machine context
* 

◆ OpenLcbMainStatemachine_process_main_statemachine()

void OpenLcbMainStatemachine_process_main_statemachine ( openlcb_statemachine_info_t * statemachine_info)

Routes incoming message to the correct protocol handler based on MTI.

MTI dispatcher. Routes incoming message to the correct handler.

Algorithm:

  1. Return early if NULL or does_node_process_msg() is false
  2. Switch on MTI (40 message types: SNIP, Message Network, PIP, Event Transport, Train, Datagram, Stream)
  3. For optional handlers that are NULL: send Interaction Rejected on request MTIs, silently ignore reply/indication MTIs
  4. Default: reject unknown addressed MTIs, ignore unknown global MTIs
* @param statemachine_info Pointer to state machine context with message and node information
* 

◆ OpenLcbMainStatemachine_handle_outgoing_openlcb_message()

bool OpenLcbMainStatemachine_handle_outgoing_openlcb_message ( void )

Sends the pending outgoing message if one is valid.

Tries to send the pending message. Returns true if one was pending.

Algorithm:

  1. If outgoing valid flag is set, call send_openlcb_msg callback
  2. On success clear the valid flag
  3. Return true if a message was pending, false if idle
Returns
true if message pending (caller should retry), false if nothing to send

◆ OpenLcbMainStatemachine_handle_try_reenumerate()

bool OpenLcbMainStatemachine_handle_try_reenumerate ( void )

Re-dispatches the current message when a handler requests multi-message enumeration.

Re-enters the state processor if the enumerate flag is set.

Algorithm:

  1. If enumerate flag is set, call process_main_statemachine again
  2. Return true while flag remains set, false when enumeration is complete
Returns
true if re-enumeration active, false if complete

◆ OpenLcbMainStatemachine_handle_try_pop_next_incoming_openlcb_message()

bool OpenLcbMainStatemachine_handle_try_pop_next_incoming_openlcb_message ( void )

Pops the next incoming message from the receive FIFO when idle.

Pops the next message from the FIFO (thread-safe). Returns true if popped.

Algorithm:

  1. If already holding a message, return false
  2. Lock shared resources, pop from FIFO, unlock
  3. Return true if pop attempted (even if queue was empty), false if busy
Returns
true if pop attempted, false if still processing previous message

◆ OpenLcbMainStatemachine_handle_try_enumerate_first_node()

bool OpenLcbMainStatemachine_handle_try_enumerate_first_node ( void )

Begins node enumeration by fetching the first node and dispatching the message.

Starts node enumeration from the first node. Returns true if processed.

Algorithm:

  1. If node pointer already set, return false (already enumerating)
  2. Reset train search match flag for new enumeration
  3. Get first node; if NULL free the message and return true
  4. If node is in RUNSTATE_RUN, dispatch message via process_main_statemachine
  5. Return true
Returns
true if enumeration step taken, false if no action needed

◆ OpenLcbMainStatemachine_handle_try_enumerate_next_node()

bool OpenLcbMainStatemachine_handle_try_enumerate_next_node ( void )

Advances to the next node and dispatches the current message.

Advances to the next node; frees message at end. Returns true if processed.

Algorithm:

  1. If no current node, return false
  2. Get next node; if NULL free the message and return true
  3. If node is in RUNSTATE_RUN, dispatch message via process_main_statemachine
  4. Return true
Returns
true if enumeration active, false if no current node

◆ OpenLcbMainStatemachine_run()

void OpenLcbMainStatemachine_run ( void )

Runs one iteration of the main state machine dispatch loop.

Runs one non-blocking step of protocol processing.

Algorithm:

  1. Send pending outgoing message (highest priority), return if busy
  2. Handle multi-message re-enumeration, return if active
  3. Pop next incoming message from FIFO, return if attempted
  4. Enumerate first node for the message, return if acted
  5. Enumerate next node, return if acted

◆ OpenLcbMainStatemachine_get_statemachine_info()

openlcb_statemachine_info_t * OpenLcbMainStatemachine_get_statemachine_info ( void )

Returns pointer to internal state. For unit testing only.

Returns pointer to internal static state machine info. For unit testing only — do not modify.


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