2026-04-05 21:23:14 +09:00
|
|
|
#pragma once
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include "pico/time.h"
|
2026-04-11 14:26:53 +09:00
|
|
|
#include "callback_list.h"
|
2026-04-05 21:23:14 +09:00
|
|
|
|
|
|
|
|
struct timer_entry {
|
|
|
|
|
absolute_time_t when;
|
|
|
|
|
std::function<void()> fn;
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-11 14:26:53 +09:00
|
|
|
using timer_handle = callback_list<timer_entry, 16>::node*;
|
2026-04-11 08:28:32 +09:00
|
|
|
|
2026-04-05 21:23:14 +09:00
|
|
|
struct timer_queue {
|
2026-04-11 14:26:53 +09:00
|
|
|
callback_list<timer_entry, 16> list;
|
2026-04-05 21:23:14 +09:00
|
|
|
alarm_id_t alarm = -1;
|
2026-04-10 22:00:34 +09:00
|
|
|
volatile bool irq_pending = false;
|
2026-04-05 21:23:14 +09:00
|
|
|
|
2026-04-11 08:28:32 +09:00
|
|
|
timer_handle schedule(absolute_time_t when, std::function<void()> fn) {
|
2026-04-11 14:26:53 +09:00
|
|
|
auto* n = list.insert_sorted({when, std::move(fn)},
|
|
|
|
|
[](const timer_entry& a, const timer_entry& b) {
|
|
|
|
|
return absolute_time_diff_us(b.when, a.when) < 0;
|
|
|
|
|
});
|
2026-04-05 21:23:14 +09:00
|
|
|
arm();
|
2026-04-11 08:28:32 +09:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timer_handle schedule_ms(uint32_t ms, std::function<void()> fn) {
|
|
|
|
|
return schedule(make_timeout_time_ms(ms), std::move(fn));
|
2026-04-05 21:23:14 +09:00
|
|
|
}
|
|
|
|
|
|
2026-04-11 08:28:32 +09:00
|
|
|
bool cancel(timer_handle h) {
|
2026-04-11 15:01:37 +09:00
|
|
|
if (!h) return false;
|
2026-04-11 14:26:53 +09:00
|
|
|
list.remove(h);
|
|
|
|
|
arm();
|
|
|
|
|
return true;
|
2026-04-05 21:23:14 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void run() {
|
2026-04-10 22:00:34 +09:00
|
|
|
if (!irq_pending) return;
|
|
|
|
|
irq_pending = false;
|
2026-04-11 14:26:53 +09:00
|
|
|
while (auto* n = list.front()) {
|
2026-04-11 15:01:37 +09:00
|
|
|
if (absolute_time_diff_us(get_absolute_time(), n->value.when) > 0) break;
|
|
|
|
|
auto fn = std::move(n->value.fn);
|
2026-04-11 14:26:53 +09:00
|
|
|
list.remove(n);
|
2026-04-05 21:23:14 +09:00
|
|
|
fn();
|
|
|
|
|
}
|
|
|
|
|
arm();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 14:26:53 +09:00
|
|
|
bool empty() const { return list.empty(); }
|
2026-04-05 21:23:14 +09:00
|
|
|
|
|
|
|
|
private:
|
2026-04-10 22:00:34 +09:00
|
|
|
static int64_t alarm_cb(alarm_id_t, void* user_data) {
|
|
|
|
|
static_cast<timer_queue*>(user_data)->irq_pending = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2026-04-05 21:23:14 +09:00
|
|
|
|
|
|
|
|
void arm() {
|
|
|
|
|
if (alarm >= 0) cancel_alarm(alarm);
|
|
|
|
|
alarm = -1;
|
2026-04-11 14:26:53 +09:00
|
|
|
if (auto* n = list.front())
|
2026-04-11 15:01:37 +09:00
|
|
|
alarm = add_alarm_at(n->value.when, alarm_cb, this, false);
|
2026-04-05 21:23:14 +09:00
|
|
|
}
|
|
|
|
|
};
|