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