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}
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 priority(&mut self, priority: TaskPriority) -> &mut Self {
79 self.task_priority = priority;
80 self
81 }
82
83 pub fn start<F>(&self, func: F) -> Result<Task, FreeRtosError>
85 where
86 F: FnOnce(Task) -> (),
87 F: Send + 'static,
88 {
89 Task::spawn(
90 &self.task_name,
91 self.task_stack_size,
92 self.task_priority,
93 func,
94 )
95 }
96}
97
98impl Task {
99 pub fn new() -> TaskBuilder {
101 TaskBuilder {
102 task_name: "rust_task".into(),
103 task_stack_size: 1024,
104 task_priority: TaskPriority(1),
105 }
106 }
107
108 #[inline]
112 pub unsafe fn from_raw_handle(handle: FreeRtosTaskHandle) -> Self {
113 Self { task_handle: handle }
114 }
115 #[inline]
116 pub fn raw_handle(&self) -> FreeRtosTaskHandle {
117 self.task_handle
118 }
119
120 pub fn suspend_all() {
121 unsafe {
122 freertos_rs_vTaskSuspendAll();
123 }
124 }
125
126 pub unsafe fn resume_all() {
131 unsafe {
132 freertos_rs_xTaskResumeAll();
133 }
134 }
135
136 unsafe fn spawn_inner<'a>(
137 f: Box<dyn FnOnce(Task)>,
138 name: &str,
139 stack_size: u16,
140 priority: TaskPriority,
141 ) -> Result<Task, FreeRtosError> {
142 let f = Box::new(f);
143 let param_ptr = &*f as *const _ as *mut _;
144
145 let (success, task_handle) = {
146 let name = name.as_bytes();
147 let name_len = name.len();
148 let mut task_handle = core::ptr::null();
149
150 let ret = freertos_rs_spawn_task(
151 thread_start,
152 param_ptr,
153 name.as_ptr(),
154 name_len as u8,
155 stack_size,
156 priority.to_freertos(),
157 &mut task_handle,
158 );
159
160 (ret == 0, task_handle)
161 };
162
163 if success {
164 mem::forget(f);
165 } else {
166 return Err(FreeRtosError::OutOfMemory);
167 }
168
169 use core::ffi::c_void;
170 extern "C" fn thread_start(main: *mut c_void) -> *mut c_void {
171 unsafe {
172 {
173 let b = Box::from_raw(main as *mut Box<dyn FnOnce(Task)>);
174 b(Task {
175 task_handle: freertos_rs_get_current_task(),
176 });
177 }
178
179 #[cfg(feature = "delete_task")]
180 freertos_rs_delete_task(0 as *const _);
181 }
182
183 #[cfg(feature = "delete_task")]
184 return 0 as *mut _;
185 #[cfg(not(feature = "delete_task"))]
186 panic!("Not allowed to quit the task!");
187 }
188
189 Ok(Task { task_handle })
190 }
191
192 fn spawn<F>(
193 name: &str,
194 stack_size: u16,
195 priority: TaskPriority,
196 f: F,
197 ) -> Result<Task, FreeRtosError>
198 where
199 F: FnOnce(Task) -> (),
200 F: Send + 'static,
201 {
202 unsafe {
203 return Task::spawn_inner(Box::new(f), name, stack_size, priority);
204 }
205 }
206
207 pub fn get_name(&self) -> Result<String, ()> {
209 unsafe {
210 let name_ptr = freertos_rs_task_get_name(self.task_handle);
211 let name = str_from_c_string(name_ptr);
212 if let Ok(name) = name {
213 return Ok(name.to_string());
214 }
215
216 Err(())
217 }
218 }
219
220 pub fn current() -> Result<Task, FreeRtosError> {
222 unsafe {
223 let t = freertos_rs_get_current_task();
224 if t != 0 as *const _ {
225 Ok(Task { task_handle: t })
226 } else {
227 Err(FreeRtosError::TaskNotFound)
228 }
229 }
230 }
231
232 pub fn set_notification_value(&self, val: u32) {
234 self.notify(TaskNotification::OverwriteValue(val))
235 }
236
237 pub fn abort_delay(&self) {
240 unsafe { freertos_rs_task_abort_delay(self.task_handle); }
241 }
242
243 pub fn notify(&self, notification: TaskNotification) {
245 unsafe {
246 let n = notification.to_freertos();
247 freertos_rs_task_notify(self.task_handle, n.0, n.1);
248 }
249 }
250
251 pub fn notify_from_isr(
253 &self,
254 context: &mut InterruptContext,
255 notification: TaskNotification,
256 ) -> Result<(), FreeRtosError> {
257 unsafe {
258 let n = notification.to_freertos();
259 let t = freertos_rs_task_notify_isr(
260 self.task_handle,
261 n.0,
262 n.1,
263 context.get_task_field_mut(),
264 );
265 if t != 0 {
266 Err(FreeRtosError::QueueFull)
267 } else {
268 Ok(())
269 }
270 }
271 }
272
273 pub fn wait_for_notification<D: DurationTicks>(
275 &self,
276 clear_bits_enter: u32,
277 clear_bits_exit: u32,
278 wait_for: D,
279 ) -> Result<u32, FreeRtosError> {
280 let mut val = 0;
281 let r = unsafe {
282 freertos_rs_task_notify_wait(
283 clear_bits_enter,
284 clear_bits_exit,
285 &mut val as *mut _,
286 wait_for.to_ticks(),
287 )
288 };
289
290 if r == 0 {
291 Ok(val)
292 } else {
293 Err(FreeRtosError::Timeout)
294 }
295 }
296
297 pub fn get_stack_high_water_mark(&self) -> u32 {
299 unsafe { freertos_rs_get_stack_high_water_mark(self.task_handle) as u32 }
300 }
301
302 pub fn get_id(&self) -> Result<FreeRtosBaseType, FreeRtosError> {
303 let task_id = unsafe { freertos_rs_uxTaskGetTaskNumber(self.task_handle) };
304 if task_id == 0 {
305 Err(FreeRtosError::TaskNotFound)
306 } else {
307 Ok(task_id)
308 }
309 }
310
311 pub fn set_id(&mut self, value: FreeRtosUBaseType) {
312 unsafe { freertos_rs_vTaskSetTaskNumber(self.task_handle, value) };
313 }
314}
315
316pub struct CurrentTask;
318
319impl CurrentTask {
320 pub fn delay<D: DurationTicks>(delay: D) {
322 unsafe {
323 freertos_rs_vTaskDelay(delay.to_ticks());
324 }
325 }
326
327 pub fn suspend() {
328 unsafe {
329 freertos_rs_suspend_task(0 as FreeRtosTaskHandle)
330 }
331 }
332
333 pub fn take_notification<D: DurationTicks>(clear: bool, wait_for: D) -> u32 {
335 unsafe { freertos_rs_task_notify_take(if clear { 1 } else { 0 }, wait_for.to_ticks()) }
336 }
337
338 pub fn get_stack_high_water_mark() -> u32 {
340 unsafe { freertos_rs_get_stack_high_water_mark(0 as FreeRtosTaskHandle) as u32 }
341 }
342}
343
344#[derive(Debug)]
345pub struct FreeRtosSystemState {
346 pub tasks: Vec<FreeRtosTaskStatus>,
347 pub total_run_time: u32,
348}
349
350impl fmt::Display for FreeRtosSystemState {
351 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
352 fmt.write_str("FreeRTOS tasks\r\n")?;
353
354 write!(fmt, "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
355 id = "ID",
356 name = "Name",
357 state = "State",
358 priority = "Priority",
359 stack = "Stack left",
360 cpu_abs = "CPU",
361 cpu_rel = "%"
362 )?;
363
364 for task in &self.tasks {
365 write!(fmt, "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
366 id = task.task_number,
367 name = task.name,
368 state = format!("{:?}", task.task_state),
369 priority = task.current_priority.0,
370 stack = task.stack_high_water_mark,
371 cpu_abs = task.run_time_counter,
372 cpu_rel = if self.total_run_time > 0 && task.run_time_counter <= self.total_run_time {
373 let p = (((task.run_time_counter as u64) * 100) / self.total_run_time as u64) as u32;
374 let ps = if p == 0 && task.run_time_counter > 0 {
375 "<1".to_string()
376 } else {
377 p.to_string()
378 };
379 format!("{: >3}%", ps)
380 } else {
381 "-".to_string()
382 }
383 )?;
384 }
385
386 if self.total_run_time > 0 {
387 write!(fmt, "Total run time: {}\r\n", self.total_run_time)?;
388 }
389
390 Ok(())
391 }
392}
393
394#[derive(Debug)]
395pub struct FreeRtosTaskStatus {
396 pub task: Task,
397 pub name: String,
398 pub task_number: FreeRtosUBaseType,
399 pub task_state: FreeRtosTaskState,
400 pub current_priority: TaskPriority,
401 pub base_priority: TaskPriority,
402 pub run_time_counter: FreeRtosUnsignedLong,
403 pub stack_high_water_mark: FreeRtosUnsignedShort,
404}
405
406pub struct FreeRtosUtils;
407
408#[derive(Debug, Clone, Copy, PartialEq)]
409pub enum FreeRtosSchedulerState {
410 Suspended,
411 NotStarted,
412 Running
413}
414
415impl FreeRtosUtils {
416 pub fn invoke_assert() {
418 unsafe {
419 freertos_rs_invoke_configASSERT();
420 }
421 }
422 pub fn start_scheduler() -> ! {
423 unsafe {
424 freertos_rs_vTaskStartScheduler();
425 }
426 }
427
428 pub fn scheduler_state() -> FreeRtosSchedulerState {
429 unsafe {
430 match freertos_rt_xTaskGetSchedulerState() {
431 0 => FreeRtosSchedulerState::Suspended,
432 1 => FreeRtosSchedulerState::NotStarted,
433 2 => FreeRtosSchedulerState::Running,
434 _ => unreachable!(),
435 }
436 }
437 }
438
439 pub fn get_tick_count() -> FreeRtosTickType {
440 unsafe { freertos_rs_xTaskGetTickCount() }
441 }
442
443 pub fn get_tick_count_duration() -> Duration {
444 Duration::ticks(Self::get_tick_count())
445 }
446
447 pub fn get_number_of_tasks() -> usize {
448 unsafe { freertos_rs_get_number_of_tasks() as usize }
449 }
450
451 pub fn get_all_tasks(tasks_len: Option<usize>) -> FreeRtosSystemState {
452 let tasks_len = tasks_len.unwrap_or(Self::get_number_of_tasks());
453 let mut tasks = Vec::with_capacity(tasks_len as usize);
454 let mut total_run_time = 0;
455
456 unsafe {
457 let filled = freertos_rs_get_system_state(
458 tasks.as_mut_ptr(),
459 tasks_len as FreeRtosUBaseType,
460 &mut total_run_time,
461 );
462 tasks.set_len(filled as usize);
463 }
464
465 let tasks = tasks
466 .into_iter()
467 .map(|t| FreeRtosTaskStatus {
468 task: Task {
469 task_handle: t.handle,
470 },
471 name: unsafe { str_from_c_string(t.task_name) }
472 .unwrap_or_else(|_| "?").to_string(),
473 task_number: t.task_number,
474 task_state: t.task_state,
475 current_priority: TaskPriority(t.current_priority as u8),
476 base_priority: TaskPriority(t.base_priority as u8),
477 run_time_counter: t.run_time_counter,
478 stack_high_water_mark: t.stack_high_water_mark,
479 })
480 .collect();
481
482 FreeRtosSystemState {
483 tasks: tasks,
484 total_run_time: total_run_time,
485 }
486 }
487}