ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
clock.h File Reference

Pluggable monotonic clock for all library timing. More...

#include "protocore_config.h"

Go to the source code of this file.

Classes

struct  ClockSrcArgs
 Install a custom clock running at ticks_per_second; the library divides it down to its internal 1000 Hz. Pass (NULL, 0) to revert to the platform default. More...
 
struct  ClockNs
 
struct  protocore_latency_stat
 Rolling latency statistics in microseconds: sample count, min / max / mean, and how many samples blew a budget. Fixed size, no heap; a subsystem (the preempting queue, a DMA path, a forwarding rule) keeps one and reports it for real-time visibility. More...
 

Functions

PROTOCORE_INLINE void pcdelay (uint32_t ms)
 The library's monotonic time at 1000 Hz (milliseconds).
 
PROTOCORE_INLINE void protocore_delay_us (uint32_t us)
 Install a custom microsecond clock running at ticks_per_second; the library divides it down to 1 MHz. Pass (NULL, 0) for the platform default.
 
PROTOCORE_INLINE void protocore_lat_reset (protocore_latency_stat *s)
 Zero a stat (min seeded high so the first sample sets it).
 
PROTOCORE_INLINE uint32_t protocore_lat_begin (void)
 Start of a measured span: capture the current microsecond time.
 
PROTOCORE_INLINE void protocore_lat_end (protocore_latency_stat *s, uint32_t start_us, uint32_t budget_us)
 End of a span started at start_us: record its latency, counting it as over-budget when budget_us is non-zero and exceeded. Wrap-safe.
 
PROTOCORE_INLINE uint32_t protocore_lat_avg_us (const protocore_latency_stat *s)
 Mean latency (us) over the recorded samples, 0 if none.
 
PROTOCORE_INLINE uint32_t protocore_cycles_to_ns (uint32_t delta_cycles, uint32_t cpu_mhz)
 Free-running CPU cycle count. ISR-safe. On a part that has one this is the hardware cycle counter; on host it falls back to protocore_micros() scaled by host_fallback_mhz (a coarse stand-in - override with a real cycle source in a host test that needs nanosecond precision).
 

Variables

PROTOCORE_BEGIN_DECLS typedef uint32_t(* protocore_clock_fn )(void)
 User clock: returns a free-running monotonic tick count.
 
ClockNs Clock
 The one symbol this module exports.
 

Detailed Description

Pluggable monotonic clock for all library timing.

The library's internal timing runs at 1000 Hz - one tick is one millisecond, the cadence the test suite asserts and every timeout / poll is expressed in. Clock.millis() is that single time source, leaving the reading in Clock.ms; by default it is the platform millis().

To drive the library from your own clock (a hardware timer, an external RTC, a simulation clock), call:

Clock.src.fn = my_clock_fn;
Clock.src.ticks_per_second = my_ticks_per_second;
Clock.set_ms(Clock.internal);

Your clock reports a free-running tick count at ticks_per_second. The library divides it down to its internal 1000 Hz, so timeouts and polling keep the exact 1 ms granularity the tests verify regardless of how fast your clock runs. Pass a rate >= 1000, ideally a multiple of 1000 for exact division (e.g. a 1 MHz timer -> ticks_per_second = 1000000, divided by 1000). Pass NULL to revert to the platform default. One source covers everything - swap it once and every subsystem follows.

The worker poll cadence is fixed at 1000 Hz (the tested default); a build can trade latency for idle power with PROTOCORE_WORKER_POLL_TICKS - see protocore_config.h.

The installed clocks live in clock.c, one instance for the whole program, so a build that reads the clock links that translation unit.

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file clock.h.

Function Documentation

◆ pcdelay()

PROTOCORE_INLINE void pcdelay ( uint32_t  ms)

The library's monotonic time at 1000 Hz (milliseconds).

Block for ms milliseconds - the library's single delay primitive.

Hands the core back for ms ticks. A tick is a millisecond, and zero is a bare yield.

Definition at line 110 of file clock.h.

◆ protocore_delay_us()

PROTOCORE_INLINE void protocore_delay_us ( uint32_t  us)

Install a custom microsecond clock running at ticks_per_second; the library divides it down to 1 MHz. Pass (NULL, 0) for the platform default.

Monotonic microseconds - the high-resolution time base for ISR timestamps and sub-millisecond latency. Safe to call from an ISR. Wraps roughly every 71 minutes, so use it only for short deltas (unsigned subtraction is wrap-safe).

Block for at least us microseconds of REAL time - a hardware settle.

pcdelay sleeps the task one RTOS tick at a time and a tick is a millisecond, so it cannot express a shorter wait: asking it for 500 us waits 1 ms.

This reads ::protocore_platform_micros, the raw counter, and NOT ::protocore_micros. The library clock is pluggable: an application can install one that runs at its own rate, and a test can install one it steps by hand. A part that needs 500 us to settle needs 500 us of real time, so a clock the application controls cannot be what decides when the wait ends - against a stepped clock this returns at once or never returns. The subtraction is unsigned, so the counter's wrap is safe.

This SPINS: it does not yield, and nothing else on the core runs while it does. That holds only where the wait is part of bringing a device up. On the request path it stalls handle() for its whole duration, which the pump's latency budget then records.

Definition at line 153 of file clock.h.

◆ protocore_lat_reset()

PROTOCORE_INLINE void protocore_lat_reset ( protocore_latency_stat *  s)

Zero a stat (min seeded high so the first sample sets it).

Definition at line 181 of file clock.h.

References protocore_latency_stat::count, protocore_latency_stat::max_us, protocore_latency_stat::min_us, protocore_latency_stat::over_budget, and protocore_latency_stat::sum_us.

◆ protocore_lat_begin()

PROTOCORE_INLINE uint32_t protocore_lat_begin ( void  )

Start of a measured span: capture the current microsecond time.

Definition at line 191 of file clock.h.

References Clock, ClockNs::internal, ClockNs::micros, and ClockNs::us.

◆ protocore_lat_end()

PROTOCORE_INLINE void protocore_lat_end ( protocore_latency_stat *  s,
uint32_t  start_us,
uint32_t  budget_us 
)

End of a span started at start_us: record its latency, counting it as over-budget when budget_us is non-zero and exceeded. Wrap-safe.

Definition at line 201 of file clock.h.

References Clock, protocore_latency_stat::count, ClockNs::internal, protocore_latency_stat::max_us, ClockNs::micros, protocore_latency_stat::min_us, protocore_latency_stat::over_budget, protocore_latency_stat::sum_us, and ClockNs::us.

◆ protocore_lat_avg_us()

PROTOCORE_INLINE uint32_t protocore_lat_avg_us ( const protocore_latency_stat *  s)

Mean latency (us) over the recorded samples, 0 if none.

Definition at line 222 of file clock.h.

References protocore_latency_stat::count, and protocore_latency_stat::sum_us.

◆ protocore_cycles_to_ns()

PROTOCORE_INLINE uint32_t protocore_cycles_to_ns ( uint32_t  delta_cycles,
uint32_t  cpu_mhz 
)

Free-running CPU cycle count. ISR-safe. On a part that has one this is the hardware cycle counter; on host it falls back to protocore_micros() scaled by host_fallback_mhz (a coarse stand-in - override with a real cycle source in a host test that needs nanosecond precision).

Convert a cycle-count delta to nanoseconds at cpu_mhz (the running CPU frequency, as the platform reports it). delta_cycles must come from a wrap-safe unsigned subtraction of two protocore_cycles() reads.

Definition at line 254 of file clock.h.

Variable Documentation

◆ protocore_clock_fn

PROTOCORE_BEGIN_DECLS typedef uint32_t(* protocore_clock_fn) (void) ( void  )

User clock: returns a free-running monotonic tick count.

Definition at line 46 of file clock.h.

◆ Clock

ClockNs Clock
extern

The one symbol this module exports.

Referenced by protocore_lat_begin(), and protocore_lat_end().