µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
os-clocks.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2016-2025 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software
6 * for any purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can
9 * be obtained from https://opensource.org/licenses/mit.
10 */
11
12#if defined(OS_USE_OS_APP_CONFIG_H)
13#include <cmsis-plus/os-app-config.h>
14#endif
15
16#include <cmsis-plus/rtos/os.h>
17
18// ----------------------------------------------------------------------------
19
20#if defined(__clang__)
21#pragma clang diagnostic ignored "-Wc++98-compat"
22#endif
23
24// ----------------------------------------------------------------------------
25
26using namespace os;
27using namespace os::rtos;
28
29// ----------------------------------------------------------------------------
30
35void
37{
38 using namespace os::rtos;
39
40#if defined(OS_USE_RTOS_PORT_SCHEDULER)
41 // Prevent scheduler actions before starting it.
42 if (scheduler::started ())
43 {
45 }
46#endif
47
48#if defined(OS_TRACE_RTOS_SYSCLOCK_TICK)
49 trace::putchar ('.');
50#elif defined(OS_TRACE_RTOS_SYSCLOCK_TICK_BRACES)
51 trace::printf ("{t ");
52#endif
53
54 {
55 // ----- Enter critical section -------------------------------------------
57
58 sysclock.internal_increment_count ();
60 // ----- Exit critical section --------------------------------------------
61 }
62 sysclock.internal_check_timestamps ();
63 hrclock.internal_check_timestamps ();
64
65#if !defined(OS_INCLUDE_RTOS_REALTIME_CLOCK_DRIVER)
66
67 // Simulate an RTC driver.
68 static uint32_t ticks = clock_systick::frequency_hz;
69
70 if (--ticks == 0)
71 {
73
75 }
76
77#endif /* !defined(OS_INCLUDE_RTOS_REALTIME_CLOCK_DRIVER) */
78
79#if !defined(OS_USE_RTOS_PORT_SCHEDULER)
80
82
83#endif /* !defined(OS_USE_RTOS_PORT_SCHEDULER) */
84
85#if defined(OS_TRACE_RTOS_SYSCLOCK_TICK_BRACES)
86 trace::printf (" t}");
87#endif
88}
89
94void
96{
97
98#if defined(OS_USE_RTOS_PORT_SCHEDULER)
99 // Prevent scheduler actions before starting it.
100 if (scheduler::started ())
101 {
103 }
104#endif
105
106#if defined(OS_TRACE_RTOS_RTC_TICK)
107 trace_putchar ('!');
108#endif
109
110 {
111 // ----- Enter critical section -------------------------------------------
113
114 rtclock.internal_increment_count ();
115 // ----- Exit critical section --------------------------------------------
116 }
117
119}
120
121// ----------------------------------------------------------------------------
122
123namespace os
124{
125 namespace rtos
126 {
127
128 // ========================================================================
129
131 {
132 }
133
138 void
140 {
141 }
142
148 {
149 // ----- Enter critical section -----------------------------------------
151
152 // Prevent inconsistent values using the critical section.
153 return steady_count_;
154 // ----- Exit critical section ------------------------------------------
155 }
156
162 {
163 // ----- Enter critical section -----------------------------------------
165
166 // Prevent inconsistent values using the critical section.
167 return steady_count_;
168 // ----- Exit critical section ------------------------------------------
169 }
170
176 {
177#if defined(OS_TRACE_RTOS_CLOCKS)
178
179#pragma GCC diagnostic push
180#if defined(__clang__)
181#elif defined(__GNUC__)
182#pragma GCC diagnostic ignored "-Wuseless-cast"
183#endif
184 trace::printf ("%s(%u) %p %s\n", __func__,
185 static_cast<unsigned int> (duration),
187#pragma GCC diagnostic pop
188
189#endif // defined(OS_TRACE_RTOS_CLOCKS)
190
191 // Don't call this from interrupt handlers.
193 // Don't call this from critical regions.
194 os_assert_err (!scheduler::locked (), EPERM);
195
196 clock::timestamp_t timestamp = steady_now () + duration;
197 for (;;)
198 {
199 result_t res;
200 res = internal_wait_until_ (timestamp, steady_list_);
201
202 timestamp_t n = steady_now ();
203 if (n >= timestamp)
204 {
205 return ETIMEDOUT;
206 }
207
208 if (this_thread::thread ().interrupted ())
209 {
210 return EINTR;
211 }
212
213 if (res != result::ok)
214 {
215 return res;
216 }
217 }
218 return ENOTRECOVERABLE;
219 }
220
226 {
227#if defined(OS_TRACE_RTOS_CLOCKS)
228 trace::printf ("%s()\n", __func__);
229#endif
230
231 // Don't call this from interrupt handlers.
233 // Don't call this from critical regions.
234 os_assert_err (!scheduler::locked (), EPERM);
235
236 for (;;)
237 {
238 result_t res;
239 res = internal_wait_until_ (timestamp, steady_list_);
240
241 timestamp_t nw = now ();
242 if (nw >= timestamp)
243 {
244 return ETIMEDOUT;
245 }
246
247 if (this_thread::thread ().interrupted ())
248 {
249 return EINTR;
250 }
251
252 if (res != result::ok)
253 {
254 return res;
255 }
256 }
257 return ENOTRECOVERABLE;
258 }
259
265 {
266#if defined(OS_TRACE_RTOS_CLOCKS)
267
268#pragma GCC diagnostic push
269#if defined(__clang__)
270#elif defined(__GNUC__)
271#pragma GCC diagnostic ignored "-Wuseless-cast"
272#endif
273 trace::printf ("%s(%u)\n", __func__,
274 static_cast<unsigned int> (timeout));
275#pragma GCC diagnostic pop
276
277#endif // defined(OS_TRACE_RTOS_CLOCKS)
278
279 // Don't call this from interrupt handlers.
281 // Don't call this from critical regions.
282 os_assert_err (!scheduler::locked (), EPERM);
283
284 clock::timestamp_t timestamp = steady_now () + timeout;
285
286 result_t res;
287 res = internal_wait_until_ (timestamp, steady_list_);
288
289 timestamp_t nw = steady_now ();
290 if (nw >= timestamp)
291 {
292 return ETIMEDOUT;
293 }
294
295 if (this_thread::thread ().interrupted ())
296 {
297 return EINTR;
298 }
299
300 return res;
301 }
302
316 {
317 // ----- Enter critical section -----------------------------------------
319
320#pragma GCC diagnostic push
321#if defined(__clang__)
322#pragma clang diagnostic ignored "-Wdeprecated-volatile"
323#elif defined(__GNUC__)
324#pragma GCC diagnostic ignored "-Wvolatile"
325#endif
326 steady_count_ += duration;
327#pragma GCC diagnostic pop
328
329 internal_check_timestamps ();
330 return steady_count_;
331 // ----- Exit critical section ------------------------------------------
332 }
333
336 {
337 return 0;
338 }
339
341 clock::offset (offset_t offset __attribute__ ((unused)))
342 {
343 return 0;
344 }
345
350#pragma GCC diagnostic push
351#if defined(__clang__)
352#elif defined(__GNUC__)
353#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
354#pragma GCC diagnostic ignored "-Wsuggest-final-types"
355#endif
357 clock::internal_wait_until_ (timestamp_t timestamp,
359 {
360 thread& crt_thread = this_thread::thread ();
361
362 // Prepare a list node pointing to the current thread.
363 // Do not worry for being on stack, it is temporarily linked to the
364 // list and guaranteed to be removed before this function returns.
365 internal::timeout_thread_node node{ timestamp, crt_thread };
366
367 {
368 // ----- Enter critical section ---------------------------------------
370
371 // Remove this thread from the ready list, if there.
373
374 // Add this thread to the clock waiting list.
375 list.link (node);
376 crt_thread.clock_node_ = &node;
377 crt_thread.state_ = thread::state::suspended;
378 // ----- Exit critical section ----------------------------------------
379 }
380
382
383 {
384 // ----- Enter critical section ---------------------------------------
386
387 // Remove the thread from the clock timeout list,
388 // if not already removed by the timer.
389 crt_thread.clock_node_ = nullptr;
390 node.unlink ();
391 // ----- Exit critical section ----------------------------------------
392 }
393
394 return result::ok;
395 }
396#pragma GCC diagnostic pop
397
402 // ========================================================================
407 {
408 }
409
413#pragma GCC diagnostic push
414#if defined(__clang__)
415#elif defined(__GNUC__)
416#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
417#endif
420 {
421 // Prevent inconsistent values.
422 // ----- Enter critical section -----------------------------------------
424
425#pragma GCC diagnostic push
426#if defined(__clang__)
427#pragma clang diagnostic ignored "-Wsign-conversion"
428#elif defined(__GNUC__)
429#pragma GCC diagnostic ignored "-Wsign-conversion"
430#endif
431 return steady_count_ + offset_;
432#pragma GCC diagnostic pop
433 // ----- Exit critical section ------------------------------------------
434 }
435#pragma GCC diagnostic pop
436
441 adjustable_clock::sleep_until (timestamp_t timestamp)
442 {
443#if defined(OS_TRACE_RTOS_CLOCKS)
444 trace::printf ("%s()\n", __func__);
445#endif
446
447 // Don't call this from interrupt handlers.
449 // Don't call this from critical regions.
450 os_assert_err (!scheduler::locked (), EPERM);
451
452 for (;;)
453 {
454 result_t res;
455 res = internal_wait_until_ (timestamp, adjusted_list_);
456
457 timestamp_t nw = now ();
458 if (nw >= timestamp)
459 {
460 return ETIMEDOUT;
461 }
462
463 if (this_thread::thread ().interrupted ())
464 {
465 return EINTR;
466 }
467
468 if (res != result::ok)
469 {
470 return res;
471 }
472 }
473 return ENOTRECOVERABLE;
474 }
475
481 {
482 return offset_;
483 }
484
489 adjustable_clock::offset (offset_t value)
490 {
491 // ----- Enter critical section -----------------------------------------
493
494 offset_t tmp;
495 tmp = offset_;
496 offset_ = value;
497
498 return tmp;
499 // ----- Exit critical section ------------------------------------------
500 }
501
502 // ========================================================================
503
543 // ------------------------------------------------------------------------
544#pragma GCC diagnostic push
545#if defined(__clang__)
546#pragma clang diagnostic ignored "-Wglobal-constructors"
547#pragma clang diagnostic ignored "-Wexit-time-destructors"
548#endif
554#pragma GCC diagnostic pop
555
556 // ------------------------------------------------------------------------
557
561 clock_systick::clock_systick () : clock{ "sysclock" }
562 {
563 }
564
569 {
570 }
571
575 void
577 {
578#if defined(OS_TRACE_RTOS_CLOCKS)
579 trace::printf ("clock_systick::%s()\n", __func__);
580#endif
582 }
583
584 // ------------------------------------------------------------------------
585
586#if defined(OS_USE_RTOS_PORT_CLOCK_SYSTICK_WAIT_FOR)
587
589 clock_systick::internal_wait_until_ (timestamp_t timestamp,
591 __attribute__ ((unused)))
592 {
593 result_t res;
594
595 timestamp_t nw = now ();
596 if (nw >= timestamp)
597 {
598 return result::ok;
599 }
600 duration_t ticks = ((duration_t)(timestamp - nw));
601 res = port::clock_systick::wait_for (ticks);
602 return res;
603 }
604
605#endif /* defined(OS_USE_RTOS_PORT_CLOCK_SYSTICK_WAIT_FOR) */
606
607 // ========================================================================
608
645 // ------------------------------------------------------------------------
646#pragma GCC diagnostic push
647#if defined(__clang__)
648#pragma clang diagnostic ignored "-Wglobal-constructors"
649#pragma clang diagnostic ignored "-Wexit-time-destructors"
650#endif
651 // error: Ignoring @brief command inside argument documentation
652 /*
653 * @brief Kind of singleton instance of the clock_rtc class.
654 */
656#pragma GCC diagnostic pop
657
658 // ------------------------------------------------------------------------
659
663 clock_rtc::clock_rtc () : adjustable_clock{ "rtclock" }
664 {
665 }
666
671 {
672 }
673
674 // ------------------------------------------------------------------------
675
682 void
683 clock_rtc::start (void)
684 {
685#if defined(OS_TRACE_RTOS_CLOCKS)
686 trace::printf ("clock_rtc::%s()\n", __func__);
687#endif
688 // Don't call this from interrupt handlers.
689 assert (!interrupts::in_handler_mode ());
690
691 // TODO: Use the RTC driver to initialise the seconds to epoch.
692 }
693
694 // ========================================================================
695
696#pragma GCC diagnostic push
697#if defined(__clang__)
698#pragma clang diagnostic ignored "-Wglobal-constructors"
699#pragma clang diagnostic ignored "-Wexit-time-destructors"
700#endif
701 // error: Ignoring @brief command inside argument documentation
702 /*
703 * @brief Kind of singleton instance of the clock_highres class.
704 */
706#pragma GCC diagnostic pop
707
708 // ------------------------------------------------------------------------
709
713 clock_highres::clock_highres () : clock{ "hrclock" }
714 {
715 }
716
721 {
722 }
723
727 void
729 {
730#if defined(OS_TRACE_RTOS_CLOCKS)
731 trace::printf ("clock_highres::%s()\n", __func__);
732#endif
733
735 }
736
738 clock_highres::now (void)
739 {
740 // ----- Enter critical section -----------------------------------------
742
743 return steady_count_ + port::clock_highres::cycles_since_tick ();
744 // ----- Exit critical section ------------------------------------------
745 }
746
747 // ------------------------------------------------------------------------
748
749 } /* namespace rtos */
750} /* namespace os */
751
752// ----------------------------------------------------------------------------
Adjustable (non-steady) clock.
Definition os-clocks.h:326
virtual timestamp_t now(void) override
Tell the current time adjusted for epoch.
virtual offset_t offset(void) override
Get adjustment offset.
virtual result_t sleep_until(timestamp_t timestamp) override
Sleep until an absolute timestamp.
virtual ~adjustable_clock() override
Destruct the clock object instance.
void internal_check_timestamps(void)
High Resolution derived clock.
Definition os-clocks.h:706
void internal_increment_count(void)
Definition os-clocks.h:905
virtual ~clock_highres() override
Destruct the SysTick clock object instance.
virtual void start(void) override
Start the clock.
clock_highres()
Construct a SysTick clock object instance.
virtual timestamp_t now(void) override
Tell the current time.
Real time clock.
Definition os-clocks.h:591
virtual void start(void) override
Initialise and make the RTC tick.
virtual ~clock_rtc() override
Destruct the real time clock object instance.
clock_rtc()
Construct a real time clock object instance.
SysTick derived clock.
Definition os-clocks.h:461
static constexpr uint32_t frequency_hz
SysTick frequency in Hz.
Definition os-clocks.h:471
virtual void start(void) override
Start the clock.
clock_systick()
Construct a SysTick clock object instance.
virtual ~clock_systick() override
Destruct the SysTick clock object instance.
Generic clock.
Definition os-clocks.h:61
virtual offset_t offset(void)
Get adjustment offset (placeholder).
result_t wait_for(duration_t timeout)
Timed wait for an event.
virtual result_t sleep_until(timestamp_t timestamp)
Sleep until an absolute timestamp.
timestamp_t update_for_slept_time(duration_t duration)
Increase the internal count after a deep sleep.
timestamp_t steady_now(void)
Tell the current time since startup.
virtual timestamp_t now(void)
Tell the current time, possibly adjusted for epoch.
virtual void start(void)=0
Start the clock.
virtual ~clock()
Destruct the clock object instance.
result_t sleep_for(duration_t duration)
Sleep for a relative duration.
Ordered list of time stamp nodes.
Definition os-lists.h:666
void link(timestamp_node &node)
Add a new thread node to the list.
Definition os-lists.cpp:413
const char * name(void) const
Get object name.
Definition os-decls.h:753
Double linked list node, with time stamp and thread.
Definition os-lists.h:220
Interrupts critical section RAII helper.
Definition os-sched.h:502
static uint32_t cycles_since_tick(void)
static void internal_interrupt_service_routine(void)
RTC implementation hook.
static result_t wait_for(clock::duration_t ticks)
static void internal_interrupt_service_routine(void)
SysTick implementation hook.
POSIX compliant thread, using the default RTOS allocator.
Definition os-thread.h:251
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:59
int putchar(int c)
Write the single character to the trace device.
Definition trace.cpp:120
void os_systick_handler(void)
SysTick interrupt handler.
Definition os-clocks.cpp:36
void os_rtc_handler(void)
RTC interrupt handler.
Definition os-clocks.cpp:95
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition os-clocks.h:78
clock_highres hrclock
The high resolution clock object instance.
clock_rtc rtclock
The real time clock object instance.
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition os-clocks.h:88
clock_systick sysclock
The system clock object instance.
port::clock::offset_t offset_t
Type of variables holding clock offsets.
Definition os-clocks.h:99
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition os-sched.h:1101
uint64_t timestamp_t
Type of variables holding time stamps.
Definition os-decls.h:821
@ ok
Function completed; no errors or events occurred.
Definition os-decls.h:179
bool started(void)
Check if the scheduler was started.
Definition os-sched.h:829
bool locked(void)
Check if the scheduler is locked.
Definition os-sched.h:858
uint64_t duration_t
Type of variables holding durations in CPU cycles.
Definition os-decls.h:220
thread & thread(void)
Get the current running thread.
RTOS namespace.
Definition os-flags.h:37
uint32_t result_t
Type of values returned by RTOS functions.
Definition os-decls.h:95
System namespace.
#define os_assert_err(__e, __er)
Assert or return an error.
Definition os-decls.h:1101
Single file µOS++ RTOS definitions.
@ suspended
Not present in the READY list, waiting for an event.
Definition os-thread.h:390
int trace_putchar(int c)