• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include "pw_chrono/system_clock.h"
17 #include "pw_chrono_backend/system_timer_native.h"
18 #include "pw_function/function.h"
19 
20 namespace pw::chrono {
21 
22 // The SystemTimer allows an ExpiryCallback be executed at a set time in the
23 // future.
24 //
25 // The base SystemTimer only supports a one-shot style timer with a callback.
26 // A periodic timer can be implemented by rescheduling the timer in the callback
27 // through InvokeAt(kDesiredPeriod + expired_deadline).
28 //
29 // When implementing a periodic layer on top, the user should be mindful of
30 // handling missed periodic callbacks. They could opt to invoke the callback
31 // multiple times with the expected expired_deadline values or instead
32 // saturate and invoke the callback only once with the latest expired_deadline.
33 //
34 // The entire API is thread safe, however it is NOT always IRQ safe.
35 class SystemTimer {
36  public:
37   using native_handle_type = backend::NativeSystemTimerHandle;
38 
39   // The ExpiryCallback is either invoked from a high priority thread or an
40   // interrupt.
41   //
42   // For a given timer instance, its ExpiryCallback will not preempt itself.
43   // This makes it appear like there is a single executor of a timer instance's
44   // ExpiryCallback.
45   //
46   // Ergo ExpiryCallbacks should be treated as if they are executed by an
47   // interrupt, meaning:
48   // - Processing inside of the callback should be kept to a minimum.
49   // - Callbacks should never attempt to block.
50   // - APIs which are not interrupt safe such as pw::sync::Mutex should not be
51   //   used!
52   using ExpiryCallback =
53       Function<void(SystemClock::time_point expired_deadline)>;
54 
55   SystemTimer(ExpiryCallback&& callback);
56 
57   // Cancels the timer and blocks if necssary if the callback is already being
58   // processed.
59   //
60   // Postcondition: The expiry callback is not in progress and will not be
61   // called in the future.
62   ~SystemTimer();
63 
64   SystemTimer(const SystemTimer&) = delete;
65   SystemTimer(SystemTimer&&) = delete;
66   SystemTimer& operator=(const SystemTimer&) = delete;
67   SystemTimer& operator=(SystemTimer&&) = delete;
68 
69   // Invokes the expiry callback as soon as possible after at least the
70   // specified duration.
71   //
72   // Scheduling a callback cancels the existing callback (if pending).
73   // If the callback is already being executed while you reschedule it, it will
74   // finish callback execution to completion. You are responsible for any
75   // critical section locks which may be needed for timer coordination.
76   //
77   // This is thread safe, it may not be IRQ safe.
78   void InvokeAfter(SystemClock::duration delay);
79 
80   // Invokes the expiry callback as soon as possible starting at the specified
81   // time_point.
82   //
83   // Scheduling a callback cancels the existing callback (if pending).
84   // If the callback is already being executed while you reschedule it, it will
85   // finish callback execution to completion. You are responsible for any
86   // critical section locks which may be needed for timer coordination.
87   //
88   // This is thread safe, it may not be IRQ safe.
89   void InvokeAt(SystemClock::time_point timestamp);
90 
91   // Cancels the software timer expiry callback if pending.
92   //
93   // Canceling a timer which isn't scheduled does nothing.
94   //
95   // If the callback is already being executed while you cancel it, it will
96   // finish callback execution to completion. You are responsible for any
97   // synchronization which is needed for thread safety.
98   //
99   // This is thread safe, it may not be IRQ safe.
100   void Cancel();
101 
102   native_handle_type native_handle();
103 
104  private:
105   // This may be a wrapper around a native type with additional members.
106   backend::NativeSystemTimer native_type_;
107 };
108 
109 }  // namespace pw::chrono
110 
111 #include "pw_chrono_backend/system_timer_inline.h"
112