| // Copyright 2021 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| #pragma once |
| |
| #include "pw_chrono/system_clock.h" |
| #include "pw_chrono_backend/system_timer_native.h" |
| #include "pw_function/function.h" |
| |
| namespace pw::chrono { |
| |
| /// The `SystemTimer` allows an `ExpiryCallback` be executed at a set time in |
| /// the future. |
| /// |
| /// The base `SystemTimer` only supports a one-shot style timer with a callback. |
| /// A periodic timer can be implemented by rescheduling the timer in the |
| /// callback through `InvokeAt(kDesiredPeriod + expired_deadline)`. |
| /// |
| /// When implementing a periodic layer on top, the user should be mindful of |
| /// handling missed periodic callbacks. They could opt to invoke the callback |
| /// multiple times with the expected expired_deadline values or instead saturate |
| /// and invoke the callback only once with the latest expired_deadline. |
| /// |
| /// The entire API is thread safe, however it is NOT always IRQ safe. |
| class SystemTimer { |
| public: |
| using native_handle_type = backend::NativeSystemTimerHandle; |
| |
| /// The `ExpiryCallback` is either invoked from a high priority thread or an |
| /// interrupt. |
| /// |
| /// For a given timer instance, its `ExpiryCallback` will not preempt itself. |
| /// This makes it appear like there is a single executor of a timer instance's |
| /// `ExpiryCallback`. |
| /// |
| /// Ergo ExpiryCallbacks should be treated as if they are executed by an |
| /// interrupt, meaning: |
| /// - Processing inside of the callback should be kept to a minimum. |
| /// - Callbacks should never attempt to block. |
| /// - APIs which are not interrupt safe such as pw::sync::Mutex should not be |
| /// used! |
| using ExpiryCallback = |
| Function<void(SystemClock::time_point expired_deadline)>; |
| |
| /// Constructs the SystemTimer based on the user provided |
| /// `pw::Function<void(SystemClock::time_point expired_deadline)>`. Note that |
| /// The `ExpiryCallback` is either invoked from a high priority thread or an |
| /// interrupt. |
| SystemTimer(ExpiryCallback&& callback); |
| |
| /// Cancels the timer and blocks if necssary if the callback is already being |
| /// processed. |
| /// |
| /// @b Postcondition: The expiry callback is not in progress and will not be |
| /// called in the future. |
| ~SystemTimer(); |
| |
| SystemTimer(const SystemTimer&) = delete; |
| SystemTimer(SystemTimer&&) = delete; |
| SystemTimer& operator=(const SystemTimer&) = delete; |
| SystemTimer& operator=(SystemTimer&&) = delete; |
| |
| /// Invokes the expiry callback as soon as possible after at least the |
| /// specified duration. |
| /// |
| /// Scheduling a callback cancels the existing callback (if pending). |
| /// If the callback is already being executed while you reschedule it, it will |
| /// finish callback execution to completion. You are responsible for any |
| /// critical section locks which may be needed for timer coordination. |
| /// |
| /// This is thread safe, it may not be IRQ safe. |
| void InvokeAfter(SystemClock::duration delay); |
| |
| /// Invokes the expiry callback as soon as possible starting at the specified |
| /// time_point. |
| /// |
| /// Scheduling a callback cancels the existing callback (if pending). |
| /// If the callback is already being executed while you reschedule it, it will |
| /// finish callback execution to completion. You are responsible for any |
| /// critical section locks which may be needed for timer coordination. |
| /// |
| /// This is thread safe, it may not be IRQ safe. |
| void InvokeAt(SystemClock::time_point timestamp); |
| |
| /// Cancels the software timer expiry callback if pending. |
| /// |
| /// Canceling a timer which isn't scheduled does nothing. |
| /// |
| /// If the callback is already being executed while you cancel it, it will |
| /// finish callback execution to completion. You are responsible for any |
| /// synchronization which is needed for thread safety. |
| /// |
| /// This is thread safe, it may not be IRQ safe. |
| void Cancel(); |
| |
| native_handle_type native_handle(); |
| |
| private: |
| /// This may be a wrapper around a native type with additional members. |
| backend::NativeSystemTimer native_type_; |
| }; |
| |
| } // namespace pw::chrono |
| |
| #include "pw_chrono_backend/system_timer_inline.h" |