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, PartialEq)]
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}
63
64impl TaskBuilder {
65 pub fn name(&mut self, name: &str) -> &mut Self {
67 self.task_name = name.into();
68 self
69 }
70
71 pub fn stack_size(&mut self, stack_size: u16) -> &mut Self {
73 self.task_stack_size = stack_size;
74 self
75 }
76
77 pub fn stack_size_bytes(&mut self, stack_size: u32) -> &mut Self {
79 self.task_stack_size = (stack_size / 4) as u16;
80 self
81 }
82
83 pub fn priority(&mut self, priority: TaskPriority) -> &mut Self {
85 self.task_priority = priority;
86 self
87 }
88
89 pub fn start<F>(&self, func: F) -> Result<Task, FreeRtosError>
91 where
92 F: FnOnce(Task) -> (),
93 F: Send + 'static,
94 {
95 Task::spawn(
96 &self.task_name,
97 self.task_stack_size,
98 self.task_priority,
99 func,
100 )
101 }
102}
103
104impl Task {
105 pub fn new() -> TaskBuilder {
107 TaskBuilder {
108 task_name: "rust_task".into(),
109 task_stack_size: 1024,
110 task_priority: TaskPriority(1),
111 }
112 }
113
114 #[inline]
118 pub unsafe fn from_raw_handle(handle: FreeRtosTaskHandle) -> Self {
119 Self {
120 task_handle: handle,
121 }
122 }
123 #[inline]
124 pub fn raw_handle(&self) -> FreeRtosTaskHandle {
125 self.task_handle
126 }
127
128 #[inline]
129 pub fn is_null(&self) -> bool {
130 self.task_handle.is_null()
131 }
132
133 pub fn suspend_all() {
134 unsafe {
135 freertos_rs_vTaskSuspendAll();
136 }
137 }
138
139 pub unsafe fn resume_all() {
144 unsafe {
145 freertos_rs_xTaskResumeAll();
146 }
147 }
148
149 unsafe fn spawn_inner<'a>(
150 f: Box<dyn FnOnce(Task)>,
151 name: &str,
152 stack_size: u16,
153 priority: TaskPriority,
154 ) -> Result<Task, FreeRtosError> {
155 let f = Box::new(f);
156 let param_ptr = &*f as *const _ as *mut _;
157
158 let (success, task_handle) = {
159 let name = name.as_bytes();
160 let name_len = name.len();
161 let mut task_handle = core::ptr::null();
162
163 let ret = unsafe {
164 freertos_rs_spawn_task(
165 thread_start,
166 param_ptr,
167 name.as_ptr(),
168 name_len as u8,
169 stack_size,
170 priority.to_freertos(),
171 &mut task_handle,
172 )
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 notify(&self, notification: TaskNotification) {
254 unsafe {
255 let n = notification.to_freertos();
256 freertos_rs_task_notify(self.task_handle, n.0, n.1);
257 }
258 }
259
260 pub fn notify_from_isr(
262 &self,
263 context: &mut InterruptContext,
264 notification: TaskNotification,
265 ) -> Result<(), FreeRtosError> {
266 unsafe {
267 let n = notification.to_freertos();
268 let t = freertos_rs_task_notify_isr(
269 self.task_handle,
270 n.0,
271 n.1,
272 context.get_task_field_mut(),
273 );
274 if t != 0 {
275 Err(FreeRtosError::QueueFull)
276 } else {
277 Ok(())
278 }
279 }
280 }
281
282 pub fn wait_for_notification<D: DurationTicks>(
284 &self,
285 clear_bits_enter: u32,
286 clear_bits_exit: u32,
287 wait_for: D,
288 ) -> Result<u32, FreeRtosError> {
289 let mut val = 0;
290 let r = unsafe {
291 freertos_rs_task_notify_wait(
292 clear_bits_enter,
293 clear_bits_exit,
294 &mut val as *mut _,
295 wait_for.to_ticks(),
296 )
297 };
298
299 if r == 0 {
300 Ok(val)
301 } else {
302 Err(FreeRtosError::Timeout)
303 }
304 }
305
306 pub fn get_stack_high_water_mark(&self) -> u32 {
308 unsafe { freertos_rs_get_stack_high_water_mark(self.task_handle) as u32 }
309 }
310
311 pub fn get_id(&self) -> Result<FreeRtosBaseType, FreeRtosError> {
312 let task_id = unsafe { freertos_rs_uxTaskGetTaskNumber(self.task_handle) };
313 if task_id == 0 {
314 Err(FreeRtosError::TaskNotFound)
315 } else {
316 Ok(task_id)
317 }
318 }
319
320 pub fn set_id(&mut self, value: FreeRtosUBaseType) {
321 unsafe { freertos_rs_vTaskSetTaskNumber(self.task_handle, value) };
322 }
323}
324
325pub struct CurrentTask;
327
328impl CurrentTask {
329 pub fn delay<D: DurationTicks>(delay: D) {
331 unsafe {
332 freertos_rs_vTaskDelay(delay.to_ticks());
333 }
334 }
335
336 pub fn suspend() {
337 unsafe { freertos_rs_suspend_task(0 as FreeRtosTaskHandle) }
338 }
339
340 pub fn yield_now() {
341 unsafe { freertos_rs_task_yield() }
342 }
343
344 pub fn take_notification<D: DurationTicks>(clear: bool, wait_for: D) -> u32 {
346 unsafe { freertos_rs_task_notify_take(if clear { 1 } else { 0 }, wait_for.to_ticks()) }
347 }
348
349 pub fn get_stack_high_water_mark() -> u32 {
351 unsafe { freertos_rs_get_stack_high_water_mark(0 as FreeRtosTaskHandle) as u32 }
352 }
353}
354
355#[derive(Debug)]
356pub struct FreeRtosSystemState {
357 pub tasks: Vec<FreeRtosTaskStatus>,
358 pub total_run_time: u32,
359}
360
361impl fmt::Display for FreeRtosSystemState {
362 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
363 fmt.write_str("FreeRTOS tasks\r\n")?;
364
365 write!(
366 fmt,
367 "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
368 id = "ID",
369 name = "Name",
370 state = "State",
371 priority = "Priority",
372 stack = "Stack left",
373 cpu_abs = "CPU",
374 cpu_rel = "%"
375 )?;
376
377 for task in &self.tasks {
378 write!(
379 fmt,
380 "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
381 id = task.task_number,
382 name = task.name,
383 state = format!("{:?}", task.task_state),
384 priority = task.current_priority.0,
385 stack = task.stack_high_water_mark,
386 cpu_abs = task.run_time_counter,
387 cpu_rel = if self.total_run_time > 0 && task.run_time_counter <= self.total_run_time
388 {
389 let p = (((task.run_time_counter as u64) * 100) / self.total_run_time as u64)
390 as u32;
391 let ps = if p == 0 && task.run_time_counter > 0 {
392 "<1".to_string()
393 } else {
394 p.to_string()
395 };
396 format!("{: >3}%", ps)
397 } else {
398 "-".to_string()
399 }
400 )?;
401 }
402
403 if self.total_run_time > 0 {
404 write!(fmt, "Total run time: {}\r\n", self.total_run_time)?;
405 }
406
407 Ok(())
408 }
409}
410
411#[derive(Debug)]
412pub struct FreeRtosTaskStatus {
413 pub task: Task,
414 pub name: String,
415 pub task_number: FreeRtosUBaseType,
416 pub task_state: FreeRtosTaskState,
417 pub current_priority: TaskPriority,
418 pub base_priority: TaskPriority,
419 pub run_time_counter: FreeRtosUnsignedLong,
420 pub stack_high_water_mark: FreeRtosUnsignedShort,
421}
422
423pub struct FreeRtosUtils;
424
425#[derive(Debug, Clone, Copy, PartialEq)]
426pub enum FreeRtosSchedulerState {
427 Suspended,
428 NotStarted,
429 Running,
430}
431
432impl FreeRtosUtils {
433 pub fn invoke_assert() {
435 unsafe {
436 freertos_rs_invoke_configASSERT();
437 }
438 }
439 pub fn start_scheduler() -> ! {
440 unsafe {
441 freertos_rs_vTaskStartScheduler();
442 }
443 }
444
445 pub fn scheduler_state() -> FreeRtosSchedulerState {
446 unsafe {
447 match freertos_rt_xTaskGetSchedulerState() {
448 0 => FreeRtosSchedulerState::Suspended,
449 1 => FreeRtosSchedulerState::NotStarted,
450 2 => FreeRtosSchedulerState::Running,
451 _ => unreachable!(),
452 }
453 }
454 }
455
456 #[inline]
457 pub fn get_tick_count() -> FreeRtosTickType {
458 unsafe {
459 if is_in_isr() {
460 freertos_rs_xTaskGetTickCountFromISR()
461 } else {
462 freertos_rs_xTaskGetTickCount()
463 }
464 }
465 }
466
467 pub fn get_tick_count_duration() -> Duration {
468 Duration::ticks(Self::get_tick_count())
469 }
470
471 pub fn get_number_of_tasks() -> usize {
472 unsafe { freertos_rs_get_number_of_tasks() as usize }
473 }
474
475 pub fn get_all_tasks(tasks_len: Option<usize>) -> FreeRtosSystemState {
476 let tasks_len = tasks_len.unwrap_or(Self::get_number_of_tasks());
477 let mut tasks = Vec::with_capacity(tasks_len as usize);
478 let mut total_run_time = 0;
479
480 unsafe {
481 let filled = freertos_rs_get_system_state(
482 tasks.as_mut_ptr(),
483 tasks_len as FreeRtosUBaseType,
484 &mut total_run_time,
485 );
486 tasks.set_len(filled as usize);
487 }
488
489 let tasks = tasks
490 .into_iter()
491 .map(|t| FreeRtosTaskStatus {
492 task: Task {
493 task_handle: t.handle,
494 },
495 name: unsafe { str_from_c_string(t.task_name) }
496 .unwrap_or_else(|_| "?")
497 .to_string(),
498 task_number: t.task_number,
499 task_state: t.task_state,
500 current_priority: TaskPriority(t.current_priority as u8),
501 base_priority: TaskPriority(t.base_priority as u8),
502 run_time_counter: t.run_time_counter,
503 stack_high_water_mark: t.stack_high_water_mark,
504 })
505 .collect();
506
507 FreeRtosSystemState {
508 tasks: tasks,
509 total_run_time: total_run_time,
510 }
511 }
512}