1use crate::base::*;
2use crate::base_type::v1::*;
3use crate::isr::*;
4use crate::shim::*;
5use crate::units::*;
6use crate::utils::*;
7use core::mem::size_of;
8
9unsafe impl Send for Task {}
10
11#[derive(Debug, Clone, PartialEq)]
13pub struct Task {
14 task_handle: FreeRtosTaskHandle,
15}
16
17#[derive(Debug, Copy, Clone)]
19pub struct TaskPriority(pub u8);
20
21#[derive(Debug, Copy, Clone)]
23pub enum TaskNotification {
24 NoAction,
26 SetBits(u32),
28 Increment,
30 OverwriteValue(u32),
32 SetValue(u32),
36}
37
38impl TaskNotification {
39 fn to_freertos(&self) -> (u32, u8) {
40 match *self {
41 TaskNotification::NoAction => (0, 0),
42 TaskNotification::SetBits(v) => (v, 1),
43 TaskNotification::Increment => (0, 2),
44 TaskNotification::OverwriteValue(v) => (v, 3),
45 TaskNotification::SetValue(v) => (v, 4),
46 }
47 }
48}
49
50impl TaskPriority {
51 fn to_freertos(&self) -> FreeRtosUBaseType {
52 self.0 as FreeRtosUBaseType
53 }
54}
55
56pub struct TaskBuilder {
60 task_name: String,
61 task_stack_size: u16,
62 task_priority: TaskPriority,
63}
64
65impl TaskBuilder {
66 pub fn name(&mut self, name: &str) -> &mut Self {
68 self.task_name = name.into();
69 self
70 }
71
72 pub fn stack_size(&mut self, stack_size: u16) -> &mut Self {
74 self.task_stack_size = stack_size;
75 self
76 }
77
78 pub fn stack_size_bytes(&mut self, stack_size: usize) -> &mut Self {
80 self.task_stack_size = (stack_size / size_of::<usize>()) as u16;
81 self
82 }
83
84 pub fn priority(&mut self, priority: TaskPriority) -> &mut Self {
86 self.task_priority = priority;
87 self
88 }
89
90 pub fn start<F>(&self, func: F) -> Result<Task, FreeRtosError>
92 where
93 F: FnOnce(Task) -> (),
94 F: Send + 'static,
95 {
96 Task::spawn(
97 &self.task_name,
98 self.task_stack_size,
99 self.task_priority,
100 func,
101 )
102 }
103}
104
105impl Task {
106 pub fn new() -> TaskBuilder {
108 TaskBuilder {
109 task_name: "rust_task".into(),
110 task_stack_size: 1024,
111 task_priority: TaskPriority(1),
112 }
113 }
114
115 #[inline]
119 pub unsafe fn from_raw_handle(handle: FreeRtosTaskHandle) -> Self {
120 Self {
121 task_handle: handle,
122 }
123 }
124 #[inline]
125 pub fn raw_handle(&self) -> FreeRtosTaskHandle {
126 self.task_handle
127 }
128
129 #[inline]
130 pub fn is_null(&self) -> bool {
131 self.task_handle.is_null()
132 }
133
134 pub fn suspend_all() {
135 unsafe {
136 freertos_rs_vTaskSuspendAll();
137 }
138 }
139
140 pub unsafe fn resume_all() {
145 unsafe {
146 freertos_rs_xTaskResumeAll();
147 }
148 }
149
150 unsafe fn spawn_inner<'a>(
151 f: Box<dyn FnOnce(Task)>,
152 name: &str,
153 stack_size: u16,
154 priority: TaskPriority,
155 ) -> Result<Task, FreeRtosError> {
156 let f = Box::new(f);
157 let param_ptr = &*f as *const _ as *mut _;
158
159 let (success, task_handle) = {
160 let name = name.as_bytes();
161 let name_len = name.len();
162 let mut task_handle = core::ptr::null();
163
164 let ret = unsafe {
165 freertos_rs_spawn_task(
166 thread_start,
167 param_ptr,
168 name.as_ptr(),
169 name_len as u8,
170 stack_size,
171 priority.to_freertos(),
172 &mut task_handle,
173 )
174 };
175
176 (ret == 0, task_handle)
177 };
178
179 if success {
180 mem::forget(f);
181 } else {
182 return Err(FreeRtosError::OutOfMemory);
183 }
184
185 use core::ffi::c_void;
186 extern "C" fn thread_start(main: *mut c_void) -> *mut c_void {
187 unsafe {
188 {
189 let b = Box::from_raw(main as *mut Box<dyn FnOnce(Task)>);
190 b(Task {
191 task_handle: freertos_rs_get_current_task(),
192 });
193 }
194
195 #[cfg(feature = "delete-task")]
196 freertos_rs_delete_task(0 as *const _);
197 }
198
199 #[cfg(feature = "delete-task")]
200 return 0 as *mut _;
201 #[cfg(not(feature = "delete-task"))]
202 panic!("Not allowed to quit the task!");
203 }
204
205 Ok(Task { task_handle })
206 }
207
208 fn spawn<F>(
209 name: &str,
210 stack_size: u16,
211 priority: TaskPriority,
212 f: F,
213 ) -> Result<Task, FreeRtosError>
214 where
215 F: FnOnce(Task) -> (),
216 F: Send + 'static,
217 {
218 unsafe {
219 return Task::spawn_inner(Box::new(f), name, stack_size, priority);
220 }
221 }
222
223 pub fn get_name(&self) -> Result<String, ()> {
225 unsafe {
226 let name_ptr = freertos_rs_task_get_name(self.task_handle);
227 let name = str_from_c_string(name_ptr);
228 if let Ok(name) = name {
229 return Ok(name.to_string());
230 }
231
232 Err(())
233 }
234 }
235
236 pub fn current() -> Result<Task, FreeRtosError> {
238 unsafe {
239 let t = freertos_rs_get_current_task();
240 if t != 0 as *const _ {
241 Ok(Task { task_handle: t })
242 } else {
243 Err(FreeRtosError::TaskNotFound)
244 }
245 }
246 }
247
248 pub fn set_notification_value(&self, val: u32) {
250 self.notify(TaskNotification::OverwriteValue(val))
251 }
252
253 pub fn notify(&self, notification: TaskNotification) {
255 unsafe {
256 let n = notification.to_freertos();
257 freertos_rs_task_notify(self.task_handle, n.0, n.1);
258 }
259 }
260
261 pub fn notify_from_isr(
263 &self,
264 context: &mut InterruptContext,
265 notification: TaskNotification,
266 ) -> Result<(), FreeRtosError> {
267 unsafe {
268 let n = notification.to_freertos();
269 let t = freertos_rs_task_notify_isr(
270 self.task_handle,
271 n.0,
272 n.1,
273 context.get_task_field_mut(),
274 );
275 if t != 0 {
276 Err(FreeRtosError::QueueFull)
277 } else {
278 Ok(())
279 }
280 }
281 }
282
283 pub fn wait_for_notification<D: DurationTicks>(
285 &self,
286 clear_bits_enter: u32,
287 clear_bits_exit: u32,
288 wait_for: D,
289 ) -> Result<u32, FreeRtosError> {
290 let mut val = 0;
291 let r = unsafe {
292 freertos_rs_task_notify_wait(
293 clear_bits_enter,
294 clear_bits_exit,
295 &mut val as *mut _,
296 wait_for.to_ticks(),
297 )
298 };
299
300 if r == 0 {
301 Ok(val)
302 } else {
303 Err(FreeRtosError::Timeout)
304 }
305 }
306
307 #[cfg(feature = "stack-high-water")]
309 #[inline]
310 pub fn get_stack_high_water_mark(&self) -> usize {
311 unsafe { freertos_rs_get_stack_high_water_mark(self.task_handle) as usize }
312 }
313
314 #[cfg(feature = "stack-high-water")]
316 #[inline]
317 pub fn get_stack_high_water_mark_bytes(&self) -> usize {
318 self.get_stack_high_water_mark() * size_of::<usize>()
319 }
320
321 #[cfg(feature = "trace-facility")]
322 pub fn get_id(&self) -> Result<FreeRtosBaseType, FreeRtosError> {
323 let task_id = unsafe { freertos_rs_uxTaskGetTaskNumber(self.task_handle) };
324 if task_id == 0 {
325 Err(FreeRtosError::TaskNotFound)
326 } else {
327 Ok(task_id)
328 }
329 }
330
331 #[cfg(feature = "trace-facility")]
332 pub fn set_id(&mut self, value: FreeRtosUBaseType) {
333 unsafe { freertos_rs_vTaskSetTaskNumber(self.task_handle, value) };
334 }
335}
336
337pub struct CurrentTask;
339
340impl CurrentTask {
341 pub fn delay<D: DurationTicks>(delay: D) {
343 unsafe {
344 freertos_rs_vTaskDelay(delay.to_ticks());
345 }
346 }
347
348 #[cfg(feature = "task-suspend")]
349 pub fn suspend() {
350 unsafe { freertos_rs_suspend_task(0 as FreeRtosTaskHandle) }
351 }
352
353 pub fn yield_now() {
354 unsafe { freertos_rs_task_yield() }
355 }
356
357 pub fn take_notification<D: DurationTicks>(clear: bool, wait_for: D) -> u32 {
359 unsafe { freertos_rs_task_notify_take(if clear { 1 } else { 0 }, wait_for.to_ticks()) }
360 }
361
362 #[cfg(feature = "stack-high-water")]
364 #[inline]
365 pub fn get_stack_high_water_mark() -> usize {
366 unsafe { freertos_rs_get_stack_high_water_mark(0 as FreeRtosTaskHandle) as usize }
367 }
368
369 #[cfg(feature = "stack-high-water")]
371 #[inline]
372 pub fn get_stack_high_water_mark_bytes() -> usize {
373 Self::get_stack_high_water_mark() * size_of::<usize>()
374 }
375}
376
377#[derive(Debug)]
378pub struct FreeRtosSystemState {
379 pub tasks: Vec<FreeRtosTaskStatus>,
380 pub total_run_time: u32,
381}
382
383impl fmt::Display for FreeRtosSystemState {
384 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
385 fmt.write_str("FreeRTOS tasks\r\n")?;
386
387 write!(
388 fmt,
389 "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
390 id = "ID",
391 name = "Name",
392 state = "State",
393 priority = "Priority",
394 stack = "Stack left",
395 cpu_abs = "CPU",
396 cpu_rel = "%"
397 )?;
398
399 for task in &self.tasks {
400 write!(
401 fmt,
402 "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
403 id = task.task_number,
404 name = task.name,
405 state = format!("{:?}", task.task_state),
406 priority = task.current_priority.0,
407 stack = task.stack_high_water_mark,
408 cpu_abs = task.run_time_counter,
409 cpu_rel = if self.total_run_time > 0 && task.run_time_counter <= self.total_run_time
410 {
411 let p = (((task.run_time_counter as u64) * 100) / self.total_run_time as u64)
412 as u32;
413 let ps = if p == 0 && task.run_time_counter > 0 {
414 "<1".to_string()
415 } else {
416 p.to_string()
417 };
418 format!("{: >3}%", ps)
419 } else {
420 "-".to_string()
421 }
422 )?;
423 }
424
425 if self.total_run_time > 0 {
426 write!(fmt, "Total run time: {}\r\n", self.total_run_time)?;
427 }
428
429 Ok(())
430 }
431}
432
433#[derive(Debug)]
434pub struct FreeRtosTaskStatus {
435 pub task: Task,
436 pub name: String,
437 pub task_number: FreeRtosUBaseType,
438 pub task_state: FreeRtosTaskState,
439 pub current_priority: TaskPriority,
440 pub base_priority: TaskPriority,
441 pub run_time_counter: FreeRtosUnsignedLong,
442 pub stack_high_water_mark: FreeRtosUnsignedShort,
443}
444
445pub struct FreeRtosUtils;
446
447#[derive(Debug, Clone, Copy, PartialEq)]
448pub enum FreeRtosSchedulerState {
449 Suspended,
450 NotStarted,
451 Running,
452}
453
454impl FreeRtosUtils {
455 pub fn invoke_assert() {
457 unsafe {
458 freertos_rs_invoke_configASSERT();
459 }
460 }
461 pub fn start_scheduler() -> ! {
462 unsafe {
463 freertos_rs_vTaskStartScheduler();
464 }
465 }
466
467 pub fn scheduler_state() -> FreeRtosSchedulerState {
468 unsafe {
469 match freertos_rt_xTaskGetSchedulerState() {
470 0 => FreeRtosSchedulerState::Suspended,
471 1 => FreeRtosSchedulerState::NotStarted,
472 2 => FreeRtosSchedulerState::Running,
473 _ => unreachable!(),
474 }
475 }
476 }
477
478 #[inline]
479 pub fn get_tick_count() -> FreeRtosTickType {
480 unsafe {
481 if is_in_isr() {
482 freertos_rs_xTaskGetTickCountFromISR()
483 } else {
484 freertos_rs_xTaskGetTickCount()
485 }
486 }
487 }
488
489 pub fn get_tick_count_duration() -> Duration {
490 Duration::ticks(Self::get_tick_count())
491 }
492
493 pub fn get_number_of_tasks() -> usize {
494 unsafe { freertos_rs_get_number_of_tasks() as usize }
495 }
496
497 #[cfg(feature = "trace-facility")]
498 pub fn get_all_tasks(tasks_len: Option<usize>) -> FreeRtosSystemState {
499 let tasks_len = tasks_len.unwrap_or(Self::get_number_of_tasks());
500 let mut tasks = Vec::with_capacity(tasks_len as usize);
501 let mut total_run_time = 0;
502
503 unsafe {
504 let filled = freertos_rs_get_system_state(
505 tasks.as_mut_ptr(),
506 tasks_len as FreeRtosUBaseType,
507 &mut total_run_time,
508 );
509 tasks.set_len(filled as usize);
510 }
511
512 let tasks = tasks
513 .into_iter()
514 .map(|t| FreeRtosTaskStatus {
515 task: Task {
516 task_handle: t.handle,
517 },
518 name: unsafe { str_from_c_string(t.task_name) }
519 .unwrap_or_else(|_| "?")
520 .to_string(),
521 task_number: t.task_number,
522 task_state: t.task_state,
523 current_priority: TaskPriority(t.current_priority as u8),
524 base_priority: TaskPriority(t.base_priority as u8),
525 run_time_counter: t.run_time_counter,
526 stack_high_water_mark: t.stack_high_water_mark,
527 })
528 .collect();
529
530 FreeRtosSystemState {
531 tasks: tasks,
532 total_run_time: total_run_time,
533 }
534 }
535}