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