blob: f356edecc664523dc221b9cda8c3da259857ca21 [file] [log] [blame]
// 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)>;
SystemTimer(ExpiryCallback&& callback);
// Cancels the timer and blocks if necssary if the callback is already being
// processed.
//
// 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"