µOS++ IIIe Reference  v6.3.15
“Perfekt ist nicht gut genug”
The third edition of µOS++, a POSIX inspired open source system, written in C++.
os-clocks.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the µOS++ distribution.
3  * (https://github.com/micro-os-plus)
4  * Copyright (c) 2016 Liviu Ionescu.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #include <cmsis-plus/rtos/os.h>
29 
30 // ----------------------------------------------------------------------------
31 
32 using namespace os;
33 using namespace os::rtos;
34 
35 // ----------------------------------------------------------------------------
36 
41 void
43 {
44  using namespace os::rtos;
45 
46 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
47  // Prevent scheduler actions before starting it.
48  if (scheduler::started ())
49  {
51  }
52 #endif
53 
54 #if defined(OS_TRACE_RTOS_SYSCLOCK_TICK)
55  trace::putchar ('.');
56 #endif
57 
58  {
59  // ----- Enter critical section -----------------------------------------
61 
62  sysclock.internal_increment_count ();
64  // ----- Exit critical section ------------------------------------------
65  }
66  sysclock.internal_check_timestamps ();
67  hrclock.internal_check_timestamps ();
68 
69 #if !defined(OS_INCLUDE_RTOS_REALTIME_CLOCK_DRIVER)
70 
71  // Simulate an RTC driver.
72  static uint32_t ticks = clock_systick::frequency_hz;
73 
74  if (--ticks == 0)
75  {
77 
78  os_rtc_handler ();
79  }
80 
81 #endif /* !defined(OS_INCLUDE_RTOS_REALTIME_CLOCK_DRIVER) */
82 
83 #if !defined(OS_USE_RTOS_PORT_SCHEDULER)
84 
86 
87 #endif /* !defined(OS_USE_RTOS_PORT_SCHEDULER) */
88 
89 #if defined(OS_TRACE_RTOS_SYSCLOCK_TICK)
90  trace::putchar (',');
91 #endif
92 }
93 
98 void
100 {
101 
102 #if defined(OS_USE_RTOS_PORT_SCHEDULER)
103  // Prevent scheduler actions before starting it.
104  if (scheduler::started ())
105  {
107  }
108 #endif
109 
110 #if defined(OS_TRACE_RTOS_RTC_TICK)
111  trace_putchar ('!');
112 #endif
113 
114  {
115  // ----- Enter critical section -----------------------------------------
117 
118  rtclock.internal_increment_count ();
119  // ----- Exit critical section ------------------------------------------
120  }
121 
123 }
124 
125 // ----------------------------------------------------------------------------
126 
127 namespace os
128 {
129  namespace rtos
130  {
131 
132  // ========================================================================
133 
149  {
150  ;
151  }
152 
157  void
159  {
160  ;
161  }
162 
169  clock::now (void)
170  {
171  // ----- Enter critical section -----------------------------------------
173 
174  // Prevent inconsistent values using the critical section.
175  return steady_count_;
176  // ----- Exit critical section ------------------------------------------
177  }
178 
186  {
187  // ----- Enter critical section -----------------------------------------
189 
190  // Prevent inconsistent values using the critical section.
191  return steady_count_;
192  // ----- Exit critical section ------------------------------------------
193  }
194 
200  result_t
202  {
203 #if defined(OS_TRACE_RTOS_CLOCKS)
204  trace::printf ("%s(%u) %p %s\n", __func__,
205  static_cast<unsigned int> (duration),
206  &this_thread::thread (), this_thread::thread ().name ());
207 #endif
208 
209  // Don't call this from interrupt handlers.
211  // Don't call this from critical regions.
212  os_assert_err(!scheduler::locked (), EPERM);
213 
214  clock::timestamp_t timestamp = steady_now () + duration;
215  for (;;)
216  {
217  result_t res;
218  res = internal_wait_until_ (timestamp, steady_list_);
219 
220  timestamp_t n = steady_now ();
221  if (n >= timestamp)
222  {
223  return ETIMEDOUT;
224  }
225 
226  if (this_thread::thread ().interrupted ())
227  {
228  return EINTR;
229  }
230 
231  if (res != result::ok)
232  {
233  return res;
234  }
235  }
236  return ENOTRECOVERABLE;
237  }
238 
244  result_t
246  {
247 #if defined(OS_TRACE_RTOS_CLOCKS)
248  trace::printf ("%s()\n", __func__);
249 #endif
250 
251  // Don't call this from interrupt handlers.
253  // Don't call this from critical regions.
254  os_assert_err(!scheduler::locked (), EPERM);
255 
256  for (;;)
257  {
258  result_t res;
259  res = internal_wait_until_ (timestamp, steady_list_);
260 
261  timestamp_t nw = now ();
262  if (nw >= timestamp)
263  {
264  return ETIMEDOUT;
265  }
266 
267  if (this_thread::thread ().interrupted ())
268  {
269  return EINTR;
270  }
271 
272  if (res != result::ok)
273  {
274  return res;
275  }
276  }
277  return ENOTRECOVERABLE;
278  }
279 
285  result_t
287  {
288 #if defined(OS_TRACE_RTOS_CLOCKS)
289  trace::printf ("%s(%u)\n", __func__, static_cast<unsigned int> (timeout));
290 #endif
291 
292  // Don't call this from interrupt handlers.
294  // Don't call this from critical regions.
295  os_assert_err(!scheduler::locked (), EPERM);
296 
297  clock::timestamp_t timestamp = steady_now () + timeout;
298 
299  result_t res;
300  res = internal_wait_until_ (timestamp, steady_list_);
301 
302  timestamp_t nw = steady_now ();
303  if (nw >= timestamp)
304  {
305  return ETIMEDOUT;
306  }
307 
308  if (this_thread::thread ().interrupted ())
309  {
310  return EINTR;
311  }
312 
313  return res;
314  }
315 
329  {
330  // ----- Enter critical section -----------------------------------------
332 
333  steady_count_ += duration;
334 
335  internal_check_timestamps ();
336  return steady_count_;
337  // ----- Exit critical section ------------------------------------------
338  }
339 
345  clock::offset (void)
346  {
347  return 0;
348  }
349 
351  clock::offset (offset_t offset __attribute__((unused)))
352  {
353  return 0;
354  }
355 
356  result_t
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.
366  { timestamp, crt_thread };
367 
368  {
369  // ----- Enter critical section -------------------------------------
371 
372  // Remove this thread from the ready list, if there.
374 
375  // Add this thread to the clock waiting list.
376  list.link (node);
377  crt_thread.clock_node_ = &node;
378  crt_thread.state_ = thread::state::suspended;
379  // ----- Exit critical section --------------------------------------
380  }
381 
383 
384  {
385  // ----- Enter critical section -------------------------------------
387 
388  // Remove the thread from the clock timeout list,
389  // if not already removed by the timer.
390  crt_thread.clock_node_ = nullptr;
391  node.unlink ();
392  // ----- Exit critical section --------------------------------------
393  }
394 
395  return result::ok;
396  }
397 
402  // ========================================================================
409  {
410  ;
411  }
412 
420  {
421  // Prevent inconsistent values.
422  // ----- Enter critical section -----------------------------------------
424 
425 #pragma GCC diagnostic push
426 #pragma GCC diagnostic ignored "-Wsign-conversion"
427  return steady_count_ + offset_;
428 #pragma GCC diagnostic pop
429  // ----- Exit critical section ------------------------------------------
430  }
431 
437  result_t
439  {
440 #if defined(OS_TRACE_RTOS_CLOCKS)
441  trace::printf ("%s()\n", __func__);
442 #endif
443 
444  // Don't call this from interrupt handlers.
446  // Don't call this from critical regions.
447  os_assert_err(!scheduler::locked (), EPERM);
448 
449  for (;;)
450  {
451  result_t res;
452  res = internal_wait_until_ (timestamp, adjusted_list_);
453 
454  timestamp_t nw = now ();
455  if (nw >= timestamp)
456  {
457  return ETIMEDOUT;
458  }
459 
460  if (this_thread::thread ().interrupted ())
461  {
462  return EINTR;
463  }
464 
465  if (res != result::ok)
466  {
467  return res;
468  }
469  }
470  return ENOTRECOVERABLE;
471  }
472 
480  {
481  return offset_;
482  }
483 
491  {
492  // ----- Enter critical section -----------------------------------------
494 
495  offset_t tmp;
496  tmp = offset_;
497  offset_ = value;
498 
499  return tmp;
500  // ----- Exit critical section ------------------------------------------
501  }
502 
503  // ========================================================================
504 
542  // ------------------------------------------------------------------------
543 #pragma GCC diagnostic push
544 #if defined(__clang__)
545 #pragma clang diagnostic ignored "-Wglobal-constructors"
546 #pragma clang diagnostic ignored "-Wexit-time-destructors"
547 #endif
548 
552 #pragma GCC diagnostic pop
553 
554  // ------------------------------------------------------------------------
555 
562  clock
563  { "sysclock" }
564  {
565  ;
566  }
567 
574  {
575  ;
576  }
577 
583  void
585  {
586 #if defined(OS_TRACE_RTOS_CLOCKS)
587  trace::printf ("clock_systick::%s()\n", __func__);
588 #endif
590  }
591 
592  // ------------------------------------------------------------------------
593 
594 #if defined(OS_USE_RTOS_PORT_CLOCK_SYSTICK_WAIT_FOR)
595 
596  result_t
597  clock_systick::internal_wait_until_ (timestamp_t timestamp,
598  internal::clock_timestamps_list& list __attribute__((unused)))
599  {
600  result_t res;
601 
602  timestamp_t nw = now ();
603  if (nw >= timestamp)
604  {
605  return result::ok;
606  }
607  duration_t ticks = ((duration_t) (timestamp - nw));
608  res = port::clock_systick::wait_for (ticks);
609  return res;
610  }
611 
612 #endif /* defined(OS_USE_RTOS_PORT_CLOCK_SYSTICK_WAIT_FOR) */
613 
614  // ========================================================================
615 
651  // ------------------------------------------------------------------------
652 #pragma GCC diagnostic push
653 #if defined(__clang__)
654 #pragma clang diagnostic ignored "-Wglobal-constructors"
655 #pragma clang diagnostic ignored "-Wexit-time-destructors"
656 #endif
657 
661 #pragma GCC diagnostic pop
662 
663  // ------------------------------------------------------------------------
664 
672  { "rtclock" }
673  {
674  ;
675  }
676 
683  {
684  ;
685  }
686 
687  // ------------------------------------------------------------------------
688 
695  void
697  {
698 #if defined(OS_TRACE_RTOS_CLOCKS)
699  trace::printf ("clock_rtc::%s()\n", __func__);
700 #endif
701  // Don't call this from interrupt handlers.
702  assert (!interrupts::in_handler_mode ());
703 
704  // TODO: Use the RTC driver to initialise the seconds to epoch.
705  }
706 
707  // ========================================================================
708 
709 #pragma GCC diagnostic push
710 #if defined(__clang__)
711 #pragma clang diagnostic ignored "-Wglobal-constructors"
712 #pragma clang diagnostic ignored "-Wexit-time-destructors"
713 #endif
714 
718 #pragma GCC diagnostic pop
719 
720  // ------------------------------------------------------------------------
721 
728  clock
729  { "hrclock" }
730  {
731  ;
732  }
733 
740  {
741  ;
742  }
743 
749  void
751  {
752 #if defined(OS_TRACE_RTOS_CLOCKS)
753  trace::printf ("clock_highres::%s()\n", __func__);
754 #endif
755 
757  }
758 
761  {
762  // ----- Enter critical section -----------------------------------------
764 
765  return steady_count_ + port::clock_highres::cycles_since_tick ();
766  // ----- Exit critical section ------------------------------------------
767  }
768 
769  // --------------------------------------------------------------------------
770 
771  } /* namespace rtos */
772 } /* namespace os */
virtual ~clock()
Destruct the clock object instance.
Definition: os-clocks.cpp:148
port::clock::timestamp_t timestamp_t
Type of variables holding clock time stamps.
Definition: os-clocks.h:81
void link(timestamp_node &node)
Add a new thread node to the list.
Definition: os-lists.cpp:384
High Resolution derived clock.
Definition: os-clocks.h:702
virtual void start(void) override
Definition: os-clocks.cpp:584
clock_systick()
Construct a SysTick clock object instance.
Definition: os-clocks.cpp:561
state_t locked(state_t state)
Lock/unlock the scheduler.
Definition: os-sched.h:899
void internal_increment_count(void)
Definition: os-clocks.h:897
clock_highres()
Construct a SysTick clock object instance.
Definition: os-clocks.cpp:727
timestamp_t steady_now(void)
Tell the current time since startup.
Definition: os-clocks.cpp:185
port::clock::offset_t offset_t
Type of variables holding clock offsets.
Definition: os-clocks.h:91
virtual ~clock_highres() override
Destruct the SysTick clock object instance.
Definition: os-clocks.cpp:739
Interrupts critical section RAII helper.
Definition: os-sched.h:498
virtual void start(void)=0
Start the clock.
Definition: os-clocks.cpp:158
void os_rtc_handler(void)
RTC interrupt handler.
Definition: os-clocks.cpp:99
System namespace.
Double linked list node, with time stamp and thread.
Definition: os-lists.h:213
int putchar(int c)
Write the single character to the trace device.
Definition: trace.cpp:126
clock_highres hrclock
The high resolution clock object instance.
Definition: os-clocks.cpp:717
virtual void start(void) override
Definition: os-clocks.cpp:750
Real time clock.
Definition: os-clocks.h:587
virtual ~adjustable_clock() override
Destruct the clock object instance.
Definition: os-clocks.cpp:408
clock_rtc rtclock
The real time clock object instance.
Definition: os-clocks.cpp:660
virtual ~clock_rtc() override
Destruct the real time clock object instance.
Definition: os-clocks.cpp:682
result_t sleep_for(duration_t duration)
Sleep for a relative duration.
Definition: os-clocks.cpp:201
POSIX compliant thread, using the default RTOS allocator.
Definition: os-thread.h:230
bool started(void)
Check if the scheduler was started.
Definition: os-sched.h:827
port::clock::duration_t duration_t
Type of variables holding clock durations.
Definition: os-clocks.h:72
SysTick derived clock.
Definition: os-clocks.h:457
result_t wait_for(duration_t timeout)
Timed wait for an event.
Definition: os-clocks.cpp:286
virtual ~clock_systick() override
Destruct the SysTick clock object instance.
Definition: os-clocks.cpp:573
static void internal_interrupt_service_routine(void)
RTC implementation hook.
virtual result_t sleep_until(timestamp_t timestamp) override
Sleep until an absolute timestamp.
Definition: os-clocks.cpp:438
Single file µOS++ RTOS definitions.
clock_systick sysclock
The system clock object instance.
Definition: os-clocks.cpp:551
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition: trace.cpp:74
Function completed; no errors or events occurred.
Definition: os-decls.h:181
static void internal_interrupt_service_routine(void)
SysTick implementation hook.
Not present in the READY list, waiting for an event.
Definition: os-thread.h:370
virtual offset_t offset(void) override
Get adjustment offset.
Definition: os-clocks.cpp:479
virtual void start(void) override
Initialise and make the RTC tick.
Definition: os-clocks.cpp:696
static constexpr uint32_t frequency_hz
SysTick frequency in Hz.
Definition: os-clocks.h:469
virtual result_t sleep_until(timestamp_t timestamp)
Sleep until an absolute timestamp.
Definition: os-clocks.cpp:245
virtual timestamp_t now(void) override
Tell the current time.
Definition: os-clocks.cpp:760
Adjustable (non-steady) clock.
Definition: os-clocks.h:319
clock_rtc()
Construct a real time clock object instance.
Definition: os-clocks.cpp:670
Ordered list of time stamp nodes.
Definition: os-lists.h:657
Generic clock.
Definition: os-clocks.h:54
RTOS namespace.
Definition: os-flags.h:41
int trace_putchar(int c)
thread & thread(void)
Get the current running thread.
Definition: os-thread.cpp:1543
virtual timestamp_t now(void) override
Tell the current time adjusted for epoch.
Definition: os-clocks.cpp:419
static result_t wait_for(clock::duration_t ticks)
uint32_t result_t
Type of values returned by RTOS functions.
Definition: os-decls.h:96
void os_systick_handler(void)
SysTick interrupt handler.
Definition: os-clocks.cpp:42
timestamp_t update_for_slept_time(duration_t duration)
Increase the internal count after a deep sleep.
Definition: os-clocks.cpp:328
static uint32_t cycles_since_tick(void)
void internal_check_timestamps(void)
virtual timestamp_t now(void)
Tell the current time, possibly adjusted for epoch.
Definition: os-clocks.cpp:169
#define os_assert_err(__e, __er)
Assert or return an error.
Definition: os-decls.h:1112
bool in_handler_mode(void)
Check if the CPU is in handler mode.
Definition: os-sched.h:1091