Motion Master 6.0.0-alpha.50
Next-generation motion control software
Loading...
Searching...
No Matches
mm::core::CyclicTimer Class Reference

Precision cyclic timer for fixed-period loops. More...

#include <cyclic_timer.h>

Public Member Functions

 CyclicTimer (std::chrono::microseconds period)
 Constructs the timer and records the current time as the first deadline baseline.
 
 ~CyclicTimer ()
 Destroys the timer. On Windows, cancels and closes the OS timer handle. On Linux, no OS resource is held.
 
 CyclicTimer (const CyclicTimer &)=delete
 Copying is deleted — each instance owns its own deadline state and, on Windows, an OS timer handle that cannot be shared.
 
CyclicTimeroperator= (const CyclicTimer &)=delete
 Copy assignment is deleted — see copy constructor.
 
uint64_t waitForNextCycle ()
 Blocks until the next cycle deadline, then returns.
 
void setPeriod (std::chrono::microseconds period)
 Changes the cycle period and re-anchors the deadline grid to now.
 

Detailed Description

Precision cyclic timer for fixed-period loops.

Sleeps to an absolute deadline each cycle so that scheduling jitter from one cycle does not accumulate into drift over time. The sequence of deadlines is a fixed grid anchored at construction — each call to waitForNextCycle() advances the target by one period regardless of actual wake-up time.

Ordinary jitter (a late wake-up whose cycle work still fits the budget) leaves the next deadline in the future and is absorbed drift-free in that cycle's remaining slack. A genuine overrun or multi-cycle stall leaves the next deadline already in the past; rather than fire the missed cycles back-to-back (a burst that, on an EtherCAT bus, would spam stale process data), the timer skips the backlog and re-syncs to the next FUTURE grid point, preserving the original phase. waitForNextCycle() returns how many cycles it skipped so the caller can track them.

Platform implementations:

  • Linux: clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ...). Works on standard kernels; becomes hard real-time when the calling thread runs at SCHED_FIFO priority on a CONFIG_PREEMPT_RT kernel.
  • Windows: CreateWaitableTimerEx with CREATE_WAITABLE_TIMER_HIGH_RESOLUTION (requires Windows 10 1803+).
  • macOS: mach_wait_until() against an absolute mach_absolute_time() deadline (Darwin has no clock_nanosleep).

Not copyable — each instance owns its own deadline state.

Constructor & Destructor Documentation

◆ CyclicTimer() [1/2]

mm::core::CyclicTimer::CyclicTimer ( std::chrono::microseconds  period)
explicit

Constructs the timer and records the current time as the first deadline baseline.

Parameters
periodCycle period. Typical value: 1000 µs (1 ms).

◆ ~CyclicTimer()

mm::core::CyclicTimer::~CyclicTimer ( )
default

Destroys the timer. On Windows, cancels and closes the OS timer handle. On Linux, no OS resource is held.

◆ CyclicTimer() [2/2]

mm::core::CyclicTimer::CyclicTimer ( const CyclicTimer )
delete

Copying is deleted — each instance owns its own deadline state and, on Windows, an OS timer handle that cannot be shared.

Member Function Documentation

◆ operator=()

CyclicTimer & mm::core::CyclicTimer::operator= ( const CyclicTimer )
delete

Copy assignment is deleted — see copy constructor.

◆ setPeriod()

void mm::core::CyclicTimer::setPeriod ( std::chrono::microseconds  period)

Changes the cycle period and re-anchors the deadline grid to now.

Recomputes the internal period and resets the deadline baseline to the current time, so the next waitForNextCycle() targets now + period on a fresh grid — exactly as construction does. Re-anchoring (rather than keeping the old baseline) means a period change does not manifest as a spurious skip burst: without it, a longer period against a baseline in the past would report a pile of skipped cycles, and a shorter one would leave the deadline stranded far in the future.

Intended to be called only by the thread that drives waitForNextCycle() (the RT loop), between cycles — it mutates the same deadline state and holds no lock.

Parameters
periodNew cycle period. Must be > 0.

◆ waitForNextCycle()

uint64_t mm::core::CyclicTimer::waitForNextCycle ( )

Blocks until the next cycle deadline, then returns.

Advances the internal deadline by one period and sleeps until that absolute point in time. Because the target is absolute rather than relative, late wake-ups in one cycle do not shift the deadline of the next.

If the newly-advanced deadline is already in the past — an overrun or a multi-cycle scheduling stall — the timer does not run the missed cycles back-to-back. It fast-forwards over the backlog to the next grid point still in the future and sleeps to that, so at most one cycle runs per period and the deadline phase is preserved.

Signals that interrupt the sleep (EINTR) are retried transparently: the sleep resumes toward the same absolute deadline, so signal delivery neither shortens a cycle nor causes drift. Callers should check their own stop condition after this function returns.

Returns
Number of cycles skipped to catch up to the grid. 0 on the normal path (deadline was met or the wake was merely late); positive only after an overrun/stall. Not [[nodiscard]] — callers that don't track skips may ignore it.

The documentation for this class was generated from the following files: