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

Implementation of the application-level Broadcast Time Protocol module. More...

Macros

#define BROADCAST_TIME_MS_PER_MINUTE_FIXED_POINT   240000
 

Functions

void OpenLcbApplicationBroadcastTime_initialize (const interface_openlcb_application_broadcast_time_t *interface)
 Initialises the broadcast time module and stores the callback interface.
 
broadcast_clock_state_tOpenLcbApplicationBroadcastTime_setup_consumer (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Allocates a clock slot as a consumer and registers event ranges on the node.
 
broadcast_clock_state_tOpenLcbApplicationBroadcastTime_setup_producer (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Allocates a clock slot as a producer and registers event ranges on the node.
 
void OpenLcbApplicationBroadcastTime_start (event_id_t clock_id)
 Marks the given clock as running.
 
void OpenLcbApplicationBroadcastTime_stop (event_id_t clock_id)
 Marks the given clock as stopped.
 
broadcast_clock_state_tOpenLcbApplicationBroadcastTime_get_clock (event_id_t clock_id)
 Returns the state for a registered clock.
 
bool OpenLcbApplicationBroadcastTime_is_consumer (event_id_t clock_id)
 Returns whether the given clock is registered as a consumer.
 
bool OpenLcbApplicationBroadcastTime_is_producer (event_id_t clock_id)
 Returns whether the given clock is registered as a producer.
 
void OpenLcbApplicationBroadcastTime_100ms_time_tick (uint8_t current_tick)
 Advances all running consumer clocks by one 100 ms step.
 
bool OpenLcbApplicationBroadcastTime_send_report_time (openlcb_node_t *openlcb_node, event_id_t clock_id, uint8_t hour, uint8_t minute)
 Sends a Report Time event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_report_date (openlcb_node_t *openlcb_node, event_id_t clock_id, uint8_t month, uint8_t day)
 Sends a Report Date event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_report_year (openlcb_node_t *openlcb_node, event_id_t clock_id, uint16_t year)
 Sends a Report Year event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_report_rate (openlcb_node_t *openlcb_node, event_id_t clock_id, int16_t rate)
 Sends a Report Rate event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_start (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Start event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_stop (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Stop event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_date_rollover (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Date Rollover event (PCER) for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_query_reply (openlcb_node_t *openlcb_node, event_id_t clock_id, uint8_t next_hour, uint8_t next_minute)
 Sends the full query reply sequence for a producer clock.
 
bool OpenLcbApplicationBroadcastTime_send_query (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Query event (PCER) for a consumer clock.
 
bool OpenLcbApplicationBroadcastTime_send_set_time (openlcb_node_t *openlcb_node, event_id_t clock_id, uint8_t hour, uint8_t minute)
 Sends a Set Time command to a clock generator.
 
bool OpenLcbApplicationBroadcastTime_send_set_date (openlcb_node_t *openlcb_node, event_id_t clock_id, uint8_t month, uint8_t day)
 Sends a Set Date command to a clock generator.
 
bool OpenLcbApplicationBroadcastTime_send_set_year (openlcb_node_t *openlcb_node, event_id_t clock_id, uint16_t year)
 Sends a Set Year command to a clock generator.
 
bool OpenLcbApplicationBroadcastTime_send_set_rate (openlcb_node_t *openlcb_node, event_id_t clock_id, int16_t rate)
 Sends a Set Rate command to a clock generator.
 
bool OpenLcbApplicationBroadcastTime_send_command_start (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Start command to a clock generator.
 
bool OpenLcbApplicationBroadcastTime_send_command_stop (openlcb_node_t *openlcb_node, event_id_t clock_id)
 Sends a Stop command to a clock generator.
 
void OpenLcbApplicationBroadcastTime_trigger_query_reply (event_id_t clock_id)
 Triggers an immediate query reply for a producer clock.
 
void OpenLcbApplicationBroadcastTime_trigger_sync_delay (event_id_t clock_id)
 Starts or resets the 3-second sync delay timer for a producer clock.
 

Detailed Description

Implementation of the application-level Broadcast Time 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.

Manages the fixed-size clock array, the fixed-point time accumulator, and all send functions for the OpenLCB Broadcast Time Protocol.

Author
Jim Kueneman
Date
4 Mar 2026

Macro Definition Documentation

◆ BROADCAST_TIME_MS_PER_MINUTE_FIXED_POINT

#define BROADCAST_TIME_MS_PER_MINUTE_FIXED_POINT   240000

Function Documentation

◆ OpenLcbApplicationBroadcastTime_initialize()

void OpenLcbApplicationBroadcastTime_initialize ( const interface_openlcb_application_broadcast_time_t * interface)

Initialises the broadcast time module and stores the callback interface.

Algorithm:

  1. Zero all clock slots with memset.
  2. Store the interface pointer in the static _interface variable.
* @param interface  Pointer to a interface_openlcb_application_broadcast_time_t
*                   with the desired callbacks (NULL callbacks are safe).
* 
Warning
Must be called before any other function in this module.

◆ OpenLcbApplicationBroadcastTime_setup_consumer()

broadcast_clock_state_t * OpenLcbApplicationBroadcastTime_setup_consumer ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Allocates a clock slot as a consumer and registers event ranges on the node.

Algorithm:

  1. Call _find_or_allocate_clock() for clock_id.
  2. If NULL, return NULL.
  3. Set clock->is_consumer = 1.
  4. If openlcb_node is non-NULL, register consumer and producer ranges for both halves of the clock's 65536-event range.
  5. Return pointer to the clock state.
* @param openlcb_node  Pointer to the openlcb_node_t; may be NULL to skip range registration.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
Pointer to the broadcast_clock_state_t, or NULL if no free slots.

◆ OpenLcbApplicationBroadcastTime_setup_producer()

broadcast_clock_state_t * OpenLcbApplicationBroadcastTime_setup_producer ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Allocates a clock slot as a producer and registers event ranges on the node.

Algorithm:

  1. Call _find_or_allocate_clock() for clock_id.
  2. If NULL, return NULL.
  3. Set clock->is_producer = 1.
  4. If openlcb_node is non-NULL, register producer and consumer ranges for both halves of the clock's 65536-event range.
  5. Return pointer to the clock state.
* @param openlcb_node  Pointer to the openlcb_node_t; may be NULL to skip range registration.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
Pointer to the broadcast_clock_state_t, or NULL if no free slots.

◆ OpenLcbApplicationBroadcastTime_start()

void OpenLcbApplicationBroadcastTime_start ( event_id_t clock_id)

Marks the given clock as running.

Marks the given clock as running so the 100 ms tick will advance it.

Algorithm:

  1. Find the clock slot for clock_id; if not found, return immediately.
  2. Set state.is_running = true.
* @param clock_id  64-bit event_id_t identifying the clock.
* 

◆ OpenLcbApplicationBroadcastTime_stop()

void OpenLcbApplicationBroadcastTime_stop ( event_id_t clock_id)

Marks the given clock as stopped.

Marks the given clock as stopped so the 100 ms tick will not advance it.

Algorithm:

  1. Find the clock slot for clock_id; if not found, return immediately.
  2. Set state.is_running = false.
* @param clock_id  64-bit event_id_t identifying the clock.
* 

◆ OpenLcbApplicationBroadcastTime_get_clock()

broadcast_clock_state_t * OpenLcbApplicationBroadcastTime_get_clock ( event_id_t clock_id)

Returns the state for a registered clock.

Algorithm:

  1. Call _find_clock_by_id(); if found, return &clock->state.
  2. Otherwise return NULL.
* @param clock_id  64-bit event_id_t identifying the clock.
* 
Returns
Pointer to the broadcast_clock_state_t, or NULL if not found.

◆ OpenLcbApplicationBroadcastTime_is_consumer()

bool OpenLcbApplicationBroadcastTime_is_consumer ( event_id_t clock_id)

Returns whether the given clock is registered as a consumer.

Algorithm:

  1. Find the clock slot; if not found, return false.
  2. Return clock->is_consumer.
* @param clock_id  64-bit event_id_t identifying the clock.
* 
Returns
true if registered as a consumer, false otherwise.

◆ OpenLcbApplicationBroadcastTime_is_producer()

bool OpenLcbApplicationBroadcastTime_is_producer ( event_id_t clock_id)

Returns whether the given clock is registered as a producer.

Algorithm:

  1. Find the clock slot; if not found, return false.
  2. Return clock->is_producer.
* @param clock_id  64-bit event_id_t identifying the clock.
* 
Returns
true if registered as a producer, false otherwise.

◆ OpenLcbApplicationBroadcastTime_100ms_time_tick()

void OpenLcbApplicationBroadcastTime_100ms_time_tick ( uint8_t current_tick)

Advances all running consumer clocks by one 100 ms step.

Advances all running consumer clocks based on elapsed ticks.

Algorithm:

  1. Compute ticks elapsed since last call via subtraction.
  2. Skip if no time has elapsed (deduplication).
  3. For each allocated, running consumer clock with a non-zero rate:
    • Compute abs_rate from the signed rate.
    • Add 100 * abs_rate * ticks_elapsed to state.ms_accumulator.
    • While accumulator >= BROADCAST_TIME_MS_PER_MINUTE_FIXED_POINT (240,000):
      • Subtract the threshold from the accumulator.
      • Call _advance_minute_forward() or _advance_minute_backward() depending on rate sign.
      • Fire the on_time_changed callback.
  4. For each allocated producer clock with a producer_node:
    • Compare previous_run_state with the node's current run_state.
    • On transition to RUNSTATE_RUN, auto-set query_reply_pending to trigger the Standard ยง6.1 startup sync sequence.
    • Update previous_run_state.

The threshold 240,000 equals 4 * 60 * 1000, which at rate=4 (1.0x) yields exactly one fast-minute per real minute. See the accumulator math comment above for details.

* @param current_tick  Current value of the global 100ms tick counter.
* 

◆ OpenLcbApplicationBroadcastTime_send_report_time()

bool OpenLcbApplicationBroadcastTime_send_report_time ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint8_t hour,
uint8_t minute )

Sends a Report Time event (PCER) for a producer clock.

Sends a Report Time event (Producer Identified Set) for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the time event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* @param hour          Hour value to report (0-23).
* @param minute        Minute value to report (0-59).
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_report_date()

bool OpenLcbApplicationBroadcastTime_send_report_date ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint8_t month,
uint8_t day )

Sends a Report Date event (PCER) for a producer clock.

Sends a Report Date event (Producer Identified Set) for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the date event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* @param month         Month value to report (1-12).
* @param day           Day value to report (1-31).
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_report_year()

bool OpenLcbApplicationBroadcastTime_send_report_year ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint16_t year )

Sends a Report Year event (PCER) for a producer clock.

Sends a Report Year event (Producer Identified Set) for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the year event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* @param year          Year value to report.
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_report_rate()

bool OpenLcbApplicationBroadcastTime_send_report_rate ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
int16_t rate )

Sends a Report Rate event (PCER) for a producer clock.

Sends a Report Rate event (Producer Identified Set) for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the rate event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* @param rate          12-bit signed fixed-point rate (4 = 1.0x real-time).
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_start()

bool OpenLcbApplicationBroadcastTime_send_start ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Start event (PCER) for a producer clock.

Sends a Start event for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the Start command event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_stop()

bool OpenLcbApplicationBroadcastTime_send_stop ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Stop event (PCER) for a producer clock.

Sends a Stop event for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the Stop command event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_date_rollover()

bool OpenLcbApplicationBroadcastTime_send_date_rollover ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Date Rollover event (PCER) for a producer clock.

Sends a Date Rollover event for a producer clock.

Algorithm:

  1. Find the clock; if not found or not a producer, return true (nothing to do).
  2. Build the Date Rollover command event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_query_reply()

bool OpenLcbApplicationBroadcastTime_send_query_reply ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint8_t next_hour,
uint8_t next_minute )

Sends the full query reply sequence for a producer clock.

Looks up the clock by clock_id and delegates to the internal state machine. See _send_query_reply_for_clock for the full sequence.

* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* @param next_hour     Hour of the next scheduled time event (0-23).
* @param next_minute   Minute of the next scheduled time event (0-59).
* 
Returns
true when all six messages have been queued, false if more calls are needed.
Note
State is stored per-clock in broadcast_clock_t.send_query_reply_state, allowing concurrent query replies for different clocks.

◆ OpenLcbApplicationBroadcastTime_send_query()

bool OpenLcbApplicationBroadcastTime_send_query ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Query event (PCER) for a consumer clock.

Sends a Query event for a consumer clock.

Algorithm:

  1. Find the clock; if not found or not a consumer, return true (nothing to do).
  2. Build the Query command event ID and send it as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the clock.
* 
Returns
true if queued or clock not applicable, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_set_time()

bool OpenLcbApplicationBroadcastTime_send_set_time ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint8_t hour,
uint8_t minute )

Sends a Set Time command to a clock generator.

Algorithm:

  1. Build the time event ID with the set flag.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* @param hour          Desired hour (0-23).
* @param minute        Desired minute (0-59).
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_set_date()

bool OpenLcbApplicationBroadcastTime_send_set_date ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint8_t month,
uint8_t day )

Sends a Set Date command to a clock generator.

Algorithm:

  1. Build the date event ID with the set flag.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* @param month         Desired month (1-12).
* @param day           Desired day (1-31).
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_set_year()

bool OpenLcbApplicationBroadcastTime_send_set_year ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
uint16_t year )

Sends a Set Year command to a clock generator.

Algorithm:

  1. Build the year event ID with the set flag.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* @param year          Desired year.
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_set_rate()

bool OpenLcbApplicationBroadcastTime_send_set_rate ( openlcb_node_t * openlcb_node,
event_id_t clock_id,
int16_t rate )

Sends a Set Rate command to a clock generator.

Algorithm:

  1. Build the rate event ID with the set flag.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* @param rate          12-bit signed fixed-point rate (4 = 1.0x real-time).
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_command_start()

bool OpenLcbApplicationBroadcastTime_send_command_start ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Start command to a clock generator.

Algorithm:

  1. Build the Start command event ID.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_send_command_stop()

bool OpenLcbApplicationBroadcastTime_send_command_stop ( openlcb_node_t * openlcb_node,
event_id_t clock_id )

Sends a Stop command to a clock generator.

Algorithm:

  1. Build the Stop command event ID.
  2. Send as a PC Event Report.
* @param openlcb_node  Pointer to the sending openlcb_node_t.
* @param clock_id      64-bit event_id_t identifying the target clock.
* 
Returns
true if queued, false if the transmit buffer is full.

◆ OpenLcbApplicationBroadcastTime_trigger_query_reply()

void OpenLcbApplicationBroadcastTime_trigger_query_reply ( event_id_t clock_id)

Triggers an immediate query reply for a producer clock.

Triggers an immediate query reply (6-message sync sequence) for a producer clock.

Sets the query_reply_pending flag and resets the state machine so the 100ms tick will drive the 6-message sync sequence.

* @param clock_id  64-bit event_id_t identifying the clock.
* 

◆ OpenLcbApplicationBroadcastTime_trigger_sync_delay()

void OpenLcbApplicationBroadcastTime_trigger_sync_delay ( event_id_t clock_id)

Starts or resets the 3-second sync delay timer for a producer clock.

Each call resets the timer to 30 ticks (3 seconds at 100ms). When the timer expires, the query reply state machine is triggered automatically, sending the 6-message sync sequence.

* @param clock_id  64-bit event_id_t identifying the clock.
* 

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