|
Motion Master 6.0.0-alpha.50
Next-generation motion control software
|
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. | |
| CyclicTimer & | operator= (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. | |
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:
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.CreateWaitableTimerEx with CREATE_WAITABLE_TIMER_HIGH_RESOLUTION (requires Windows 10 1803+).mach_wait_until() against an absolute mach_absolute_time() deadline (Darwin has no clock_nanosleep).Not copyable — each instance owns its own deadline state.
|
explicit |
Constructs the timer and records the current time as the first deadline baseline.
| period | Cycle period. Typical value: 1000 µs (1 ms). |
|
default |
Destroys the timer. On Windows, cancels and closes the OS timer handle. On Linux, no OS resource is held.
|
delete |
Copying is deleted — each instance owns its own deadline state and, on Windows, an OS timer handle that cannot be shared.
|
delete |
Copy assignment is deleted — see copy constructor.
| 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.
| period | New cycle period. Must be > 0. |
| 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.
[[nodiscard]] — callers that don't track skips may ignore it.