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