veecle_osal_freertos/
time.rs1use alloc::boxed::Box;
4use alloc::sync::Arc;
5use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
6use core::task::Poll;
7
8use futures::task::AtomicWaker;
9use veecle_freertos_integration::{
10 Duration as FreeRtosDuration, TickType_t, Timer as FreeRtosTimer,
11};
12use veecle_osal_api::Error;
13pub use veecle_osal_api::time::{
14 Duration, Exceeded, Instant, Interval, SystemTime, SystemTimeError, SystemTimeSync,
15 TimeAbstraction,
16};
17
18use crate::error::into_veecle_os_error;
19
20#[derive(Debug)]
28pub struct Time;
29
30impl TimeAbstraction for Time {
31 fn now() -> Instant {
32 Instant::MIN
33 + Duration::from_millis(
34 veecle_freertos_integration::scheduler::get_tick_count_duration().ms() as u64,
35 )
36 }
37
38 async fn sleep(duration: Duration) -> Result<(), Error> {
39 let duration = FreeRtosDuration::from_ms(duration.as_millis() as TickType_t);
40
41 if duration == FreeRtosDuration::zero() {
42 return Ok(());
43 }
44
45 #[derive(Default)]
47 struct Context {
48 waker: AtomicWaker,
50
51 done: AtomicBool,
53 }
54
55 let context = Arc::new(Context::default());
56
57 let callback = Box::new({
58 let context = context.clone();
59 move |_| {
60 context.done.store(true, Ordering::Relaxed);
61 context.waker.wake();
62 }
63 });
64
65 let timer =
66 FreeRtosTimer::periodic(None, duration, callback).map_err(into_veecle_os_error)?;
67
68 timer.handle().start().map_err(into_veecle_os_error)?;
69
70 core::future::poll_fn(move |cx| {
71 context.waker.register(cx.waker());
72 if context.done.load(Ordering::Relaxed) {
73 Poll::Ready(())
74 } else {
75 Poll::Pending
76 }
77 })
78 .await;
79
80 Ok(())
81 }
82
83 async fn sleep_until(deadline: Instant) -> Result<(), Error> {
84 Self::sleep(
85 deadline
86 .duration_since(Self::now())
87 .unwrap_or(Duration::ZERO),
88 )
89 .await
90 }
91
92 fn interval(period: Duration) -> impl Interval
93 where
94 Self: Sized,
95 {
96 struct Context {
98 waker: AtomicWaker,
100
101 count: AtomicUsize,
105 }
106
107 struct IntervalInternal<F>
108 where
109 F: Fn(veecle_freertos_integration::TimerHandle) + Send + 'static,
110 {
111 _timer: Option<FreeRtosTimer<F>>,
113 error: Option<veecle_freertos_integration::FreeRtosError>,
114 context: Arc<Context>,
115 }
116
117 impl<F> Interval for IntervalInternal<F>
118 where
119 F: Fn(veecle_freertos_integration::TimerHandle) + Send + 'static,
120 {
121 async fn tick(&mut self) -> Result<(), Error> {
122 if let Some(error) = self.error.take() {
123 return Err(into_veecle_os_error(error));
124 }
125
126 core::future::poll_fn(|cx| {
127 self.context.waker.register(cx.waker());
128
129 if self.context.count.load(Ordering::Relaxed) != 0 {
132 self.context.count.fetch_sub(1, Ordering::Relaxed);
133 Poll::Ready(Ok(()))
134 } else {
135 Poll::Pending
136 }
137 })
138 .await
139 }
140 }
141
142 let period = FreeRtosDuration::from_ms(period.as_millis() as TickType_t);
143
144 let context = Arc::new(Context {
145 waker: AtomicWaker::new(),
146 count: AtomicUsize::new(1),
147 });
148
149 let callback = Box::new({
150 let context = context.clone();
151 move |_| {
152 context.count.fetch_add(1, Ordering::Relaxed);
155 context.waker.wake();
156 }
157 });
158
159 let (mut error, timer) = match FreeRtosTimer::periodic(None, period, callback) {
160 Ok(timer) => (None, Some(timer)),
161 Err(error) => (Some(error), None),
162 };
163
164 if let Some(timer) = &timer {
165 error = timer.handle().start().err();
166 }
167
168 IntervalInternal {
169 _timer: timer,
170 error,
171 context,
172 }
173 }
174}
175
176static SYSTEM_TIME_OFFSET_SECONDS: AtomicU32 = AtomicU32::new(0);
177
178impl SystemTime for Time {
179 fn duration_since_epoch() -> Result<Duration, SystemTimeError> {
180 let offset = SYSTEM_TIME_OFFSET_SECONDS.load(Ordering::Relaxed);
181 if offset == 0 {
182 Err(SystemTimeError::Unsynchronized)
183 } else {
184 let duration_since_start = Self::now()
185 .duration_since(Instant::MIN)
186 .expect("now can't be less than min time");
187 Ok(duration_since_start + Duration::from_secs(offset as u64))
188 }
189 }
190}
191
192impl SystemTimeSync for Time {
193 fn set_system_time(duration_since_epoch: Duration) -> Result<(), SystemTimeError> {
194 let duration_since_start = Duration::from_millis(
195 veecle_freertos_integration::scheduler::get_tick_count_duration().ms() as u64,
196 );
197 if duration_since_epoch < duration_since_start {
198 Err(SystemTimeError::EpochIsLaterThanStartTime)
199 } else {
200 SYSTEM_TIME_OFFSET_SECONDS.store(
201 (duration_since_epoch - duration_since_start).as_secs() as u32,
202 Ordering::Relaxed,
203 );
204 Ok(())
205 }
206 }
207}