1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono/system_timer.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <kernel.h>
18*61c4878aSAndroid Build Coastguard Worker #include <sys/mutex.h>
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono_zephyr/system_clock_constants.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_chrono_zephyr/system_timer_native.h"
24*61c4878aSAndroid Build Coastguard Worker
25*61c4878aSAndroid Build Coastguard Worker namespace pw::chrono {
26*61c4878aSAndroid Build Coastguard Worker namespace {
27*61c4878aSAndroid Build Coastguard Worker
28*61c4878aSAndroid Build Coastguard Worker constexpr SystemClock::duration kMinTimerPeriod = SystemClock::duration(1);
29*61c4878aSAndroid Build Coastguard Worker // Work synchronization objects must be in cache-coherent memory, which excludes
30*61c4878aSAndroid Build Coastguard Worker // stacks on some architectures.
31*61c4878aSAndroid Build Coastguard Worker static k_work_sync work_sync;
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker } // namespace
34*61c4878aSAndroid Build Coastguard Worker
HandleTimerWork(k_work * item)35*61c4878aSAndroid Build Coastguard Worker void HandleTimerWork(k_work* item) {
36*61c4878aSAndroid Build Coastguard Worker k_work_delayable* delayable_item = k_work_delayable_from_work(item);
37*61c4878aSAndroid Build Coastguard Worker backend::NativeSystemTimer* native_type =
38*61c4878aSAndroid Build Coastguard Worker CONTAINER_OF(delayable_item, backend::ZephyrWorkWrapper, work)->owner;
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard Worker sys_mutex_lock(&native_type->mutex, K_FOREVER);
41*61c4878aSAndroid Build Coastguard Worker #ifdef CONFIG_TIMEOUT_64BIT
42*61c4878aSAndroid Build Coastguard Worker native_type->user_callback(native_type->expiry_deadline);
43*61c4878aSAndroid Build Coastguard Worker #else
44*61c4878aSAndroid Build Coastguard Worker const SystemClock::duration time_until_deadline =
45*61c4878aSAndroid Build Coastguard Worker native_type->expiry_deadline - SystemClock::now();
46*61c4878aSAndroid Build Coastguard Worker if (time_until_deadline <= SystemClock::duration::zero()) {
47*61c4878aSAndroid Build Coastguard Worker native_type->user_callback(native_type->expiry_deadline);
48*61c4878aSAndroid Build Coastguard Worker } else {
49*61c4878aSAndroid Build Coastguard Worker // We haven't met the deadline yet, reschedule as far out as possible.
50*61c4878aSAndroid Build Coastguard Worker const SystemClock::duration period =
51*61c4878aSAndroid Build Coastguard Worker std::min(pw::chrono::zephyr::kMaxTimeout, time_until_deadline);
52*61c4878aSAndroid Build Coastguard Worker k_work_schedule(&native_type->work_wrapper.work, K_TICKS(period.count()));
53*61c4878aSAndroid Build Coastguard Worker }
54*61c4878aSAndroid Build Coastguard Worker #endif // CONFIG_TIMEOUT_64BIT
55*61c4878aSAndroid Build Coastguard Worker sys_mutex_unlock(&native_type->mutex);
56*61c4878aSAndroid Build Coastguard Worker }
57*61c4878aSAndroid Build Coastguard Worker
SystemTimer(ExpiryCallback callback)58*61c4878aSAndroid Build Coastguard Worker SystemTimer::SystemTimer(ExpiryCallback callback)
59*61c4878aSAndroid Build Coastguard Worker : native_type_{.work_wrapper =
60*61c4878aSAndroid Build Coastguard Worker {
61*61c4878aSAndroid Build Coastguard Worker .work = {},
62*61c4878aSAndroid Build Coastguard Worker .owner = nullptr,
63*61c4878aSAndroid Build Coastguard Worker },
64*61c4878aSAndroid Build Coastguard Worker .mutex = {},
65*61c4878aSAndroid Build Coastguard Worker .expiry_deadline = SystemClock::time_point(),
66*61c4878aSAndroid Build Coastguard Worker .user_callback = std::move(callback)} {
67*61c4878aSAndroid Build Coastguard Worker k_work_init_delayable(&native_type_.work_wrapper.work, HandleTimerWork);
68*61c4878aSAndroid Build Coastguard Worker sys_mutex_init(&native_type_.mutex);
69*61c4878aSAndroid Build Coastguard Worker native_type_.work_wrapper.owner = &native_type_;
70*61c4878aSAndroid Build Coastguard Worker }
71*61c4878aSAndroid Build Coastguard Worker
~SystemTimer()72*61c4878aSAndroid Build Coastguard Worker SystemTimer::~SystemTimer() {
73*61c4878aSAndroid Build Coastguard Worker k_work_cancel_sync(&native_type_.work_wrapper.work, &work_sync);
74*61c4878aSAndroid Build Coastguard Worker }
75*61c4878aSAndroid Build Coastguard Worker
InvokeAt(SystemClock::time_point timestamp)76*61c4878aSAndroid Build Coastguard Worker void SystemTimer::InvokeAt(SystemClock::time_point timestamp) {
77*61c4878aSAndroid Build Coastguard Worker sys_mutex_lock(&native_type_.mutex, K_FOREVER);
78*61c4878aSAndroid Build Coastguard Worker native_type_.expiry_deadline = timestamp;
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard Worker const SystemClock::duration time_until_deadline =
81*61c4878aSAndroid Build Coastguard Worker timestamp - SystemClock::now();
82*61c4878aSAndroid Build Coastguard Worker const SystemClock::duration period =
83*61c4878aSAndroid Build Coastguard Worker IS_ENABLED(CONFIG_TIMEOUT_64BIT)
84*61c4878aSAndroid Build Coastguard Worker ? time_until_deadline
85*61c4878aSAndroid Build Coastguard Worker : std::clamp(kMinTimerPeriod,
86*61c4878aSAndroid Build Coastguard Worker time_until_deadline,
87*61c4878aSAndroid Build Coastguard Worker pw::chrono::zephyr::kMaxTimeout);
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker k_work_schedule(&native_type_.work_wrapper.work, K_TICKS(period.count()));
90*61c4878aSAndroid Build Coastguard Worker sys_mutex_unlock(&native_type_.mutex);
91*61c4878aSAndroid Build Coastguard Worker }
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker } // namespace pw::chrono
94