1use crate::prelude::v1::*;
2use crate::base::*;
3use crate::shim::*;
4use crate::units::*;
5use crate::utils::*;
6use crate::isr::*;
7
8unsafe impl Send for Task {}
9
10#[derive(Debug)]
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 F: FnOnce() -> (),
86 F: Send + 'static
87 {
88
89 Task::spawn(&self.task_name,
90 self.task_stack_size,
91 self.task_priority,
92 func)
93
94 }
95}
96
97
98
99impl Task {
100 pub fn new() -> TaskBuilder {
102 TaskBuilder {
103 task_name: "rust_task".into(),
104 task_stack_size: 1024,
105 task_priority: TaskPriority(1),
106 }
107 }
108
109 unsafe fn spawn_inner<'a>(f: Box<dyn FnOnce()>,
110 name: &str,
111 stack_size: u16,
112 priority: TaskPriority)
113 -> Result<Task, FreeRtosError> {
114 let f = Box::new(f);
115 let param_ptr = &*f as *const _ as *mut _;
116
117 let (success, task_handle) = {
118 let name = name.as_bytes();
119 let name_len = name.len();
120 let mut task_handle = mem::zeroed::<CVoid>();
121
122 let ret = freertos_rs_spawn_task(thread_start,
123 param_ptr,
124 name.as_ptr(),
125 name_len as u8,
126 stack_size,
127 priority.to_freertos(),
128 &mut task_handle);
129
130 (ret == 0, task_handle)
131 };
132
133 if success {
134 mem::forget(f);
135 } else {
136 return Err(FreeRtosError::OutOfMemory);
137 }
138
139 extern "C" fn thread_start(main: *mut CVoid) -> *mut CVoid {
140 unsafe {
141 {
142 let b = Box::from_raw(main as *mut Box<dyn FnOnce()>);
143 b();
144 }
145
146 freertos_rs_delete_task(0 as *const _);
147 }
148
149 0 as *mut _
150 }
151
152 Ok(Task { task_handle: task_handle as usize as *const _ })
153 }
154
155 fn spawn<F>(name: &str,
156 stack_size: u16,
157 priority: TaskPriority,
158 f: F)
159 -> Result<Task, FreeRtosError>
160 where F: FnOnce() -> (),
161 F: Send + 'static
162 {
163 unsafe {
164 return Task::spawn_inner(Box::new(f), name, stack_size, priority);
165 }
166 }
167
168
169 pub fn get_name(&self) -> Result<String, ()> {
171 unsafe {
172 let name_ptr = freertos_rs_task_get_name(self.task_handle);
173 let name = str_from_c_string(name_ptr);
174 if let Ok(name) = name {
175 return Ok(name);
176 }
177
178 Err(())
179 }
180 }
181
182 pub fn current() -> Result<Task, FreeRtosError> {
184 unsafe {
185 let t = freertos_rs_get_current_task();
186 if t != 0 as *const _ {
187 Ok(Task { task_handle: t })
188 } else {
189 Err(FreeRtosError::TaskNotFound)
190 }
191 }
192 }
193
194 pub fn set_notification_value(&self, val: u32) {
196 self.notify(TaskNotification::OverwriteValue(val))
197 }
198
199 pub fn notify(&self, notification: TaskNotification) {
201 unsafe {
202 let n = notification.to_freertos();
203 freertos_rs_task_notify(self.task_handle, n.0, n.1);
204 }
205 }
206
207 pub fn notify_from_isr(&self,
209 context: &InterruptContext,
210 notification: TaskNotification)
211 -> Result<(), FreeRtosError> {
212 unsafe {
213 let n = notification.to_freertos();
214 let t = freertos_rs_task_notify_isr(self.task_handle,
215 n.0,
216 n.1,
217 context.get_task_field_mut());
218 if t != 0 {
219 Err(FreeRtosError::QueueFull)
220 } else {
221 Ok(())
222 }
223 }
224 }
225
226 pub fn take_notification<D: DurationTicks>(&self, clear: bool, wait_for: D) -> u32 {
228 unsafe { freertos_rs_task_notify_take(if clear { 1 } else { 0 }, wait_for.to_ticks()) }
229 }
230
231 pub fn wait_for_notification<D: DurationTicks>(&self,
233 clear_bits_enter: u32,
234 clear_bits_exit: u32,
235 wait_for: D)
236 -> Result<u32, FreeRtosError>
237 {
238 let mut val = 0;
239 let r = unsafe {
240 freertos_rs_task_notify_wait(clear_bits_enter,
241 clear_bits_exit,
242 &mut val as *mut _,
243 wait_for.to_ticks())
244 };
245
246 if r == 0 {
247 Ok(val)
248 } else {
249 Err(FreeRtosError::Timeout)
250 }
251 }
252
253 pub fn get_stack_high_water_mark(&self) -> u32 {
255 unsafe {
256 freertos_rs_get_stack_high_water_mark(self.task_handle) as u32
257 }
258 }
259}
260
261pub struct CurrentTask;
263impl CurrentTask {
264 pub fn delay<D: DurationTicks>(delay: D) {
266 unsafe {
267 freertos_rs_vTaskDelay(delay.to_ticks());
268 }
269 }
270
271 pub fn get_stack_high_water_mark() -> u32 {
273 unsafe {
274 freertos_rs_get_stack_high_water_mark(0 as FreeRtosTaskHandle) as u32
275 }
276 }
277}
278
279#[derive(Debug)]
280pub struct FreeRtosSchedulerState {
281 pub tasks: Vec<FreeRtosTaskStatus>,
282 pub total_run_time: u32
283}
284
285impl fmt::Display for FreeRtosSchedulerState {
286 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
287 fmt.write_str("FreeRTOS tasks\r\n")?;
288
289 write!(fmt, "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
290 id = "ID",
291 name = "Name",
292 state = "State",
293 priority = "Priority",
294 stack = "Stack left",
295 cpu_abs = "CPU",
296 cpu_rel = "%"
297 )?;
298
299 for task in &self.tasks {
300 write!(fmt, "{id: <6} | {name: <16} | {state: <9} | {priority: <8} | {stack: >10} | {cpu_abs: >10} | {cpu_rel: >4}\r\n",
301 id = task.task_number,
302 name = task.name,
303 state = format!("{:?}", task.task_state),
304 priority = task.current_priority.0,
305 stack = task.stack_high_water_mark,
306 cpu_abs = task.run_time_counter,
307 cpu_rel = if self.total_run_time > 0 && task.run_time_counter <= self.total_run_time {
308 let p = (((task.run_time_counter as u64) * 100) / self.total_run_time as u64) as u32;
309 let ps = if p == 0 && task.run_time_counter > 0 {
310 "<1".to_string()
311 } else {
312 p.to_string()
313 };
314 format!("{: >3}%", ps)
315 } else {
316 "-".to_string()
317 }
318 )?;
319 }
320
321 if self.total_run_time > 0 {
322 write!(fmt, "Total run time: {}\r\n", self.total_run_time)?;
323 }
324
325 Ok(())
326 }
327}
328
329#[derive(Debug)]
330pub struct FreeRtosTaskStatus {
331 pub task: Task,
332 pub name: String,
333 pub task_number: FreeRtosUBaseType,
334 pub task_state: FreeRtosTaskState,
335 pub current_priority: TaskPriority,
336 pub base_priority: TaskPriority,
337 pub run_time_counter: FreeRtosUnsignedLong,
338 pub stack_high_water_mark: FreeRtosUnsignedShort
339}
340
341
342pub struct FreeRtosUtils;
343impl FreeRtosUtils {
344 pub fn get_tick_count() -> FreeRtosTickType {
345 unsafe { freertos_rs_xTaskGetTickCount() }
346 }
347
348 pub fn get_tick_count_duration() -> Duration {
349 Duration::ticks(Self::get_tick_count())
350 }
351
352 pub fn get_number_of_tasks() -> usize {
353 unsafe { freertos_rs_get_number_of_tasks() as usize }
354 }
355
356 pub fn get_all_tasks(tasks_len: Option<usize>) -> FreeRtosSchedulerState {
357 let tasks_len = tasks_len.unwrap_or(Self::get_number_of_tasks());
358 let mut tasks = Vec::with_capacity(tasks_len as usize);
359 let mut total_run_time = 0;
360
361 unsafe {
362 let filled = freertos_rs_get_system_state(tasks.as_mut_ptr(), tasks_len as FreeRtosUBaseType, &mut total_run_time);
363 tasks.set_len(filled as usize);
364 }
365
366 let tasks = tasks.into_iter().map(|t| {
367 FreeRtosTaskStatus {
368 task: Task { task_handle: t.handle },
369 name: unsafe { str_from_c_string(t.task_name) }.unwrap_or_else(|_| String::from("?")),
370 task_number: t.task_number,
371 task_state: t.task_state,
372 current_priority: TaskPriority(t.current_priority as u8),
373 base_priority: TaskPriority(t.base_priority as u8),
374 run_time_counter: t.run_time_counter,
375 stack_high_water_mark: t.stack_high_water_mark
376 }
377 }).collect();
378
379 FreeRtosSchedulerState {
380 tasks: tasks,
381 total_run_time: total_run_time
382 }
383 }
384}