From ba2c7d88123081f927195a6359c16833f7c8def7 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 10:43:37 +0300 Subject: [PATCH 01/33] Files with task manager --- src/lib.rs | 41 ++++++++++---------- src/main.rs | 33 ++++++++++------- src/task_manager.rs | 38 +++++++++++-------- src/timer.rs | 76 ++++++++++++++++---------------------- tests/integration_tests.rs | 30 +-------------- tests/unit_tests.rs | 66 +++++---------------------------- 6 files changed, 104 insertions(+), 180 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ccb8ae3..ffa0039 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,25 +4,26 @@ use std::thread; use std::time::Duration; pub mod connection; +pub mod task_manager; pub mod timer; -lazy_static! { - static ref TIMER: Timer = Timer::new(0, 5, 0.1); -} - -#[no_mangle] -pub extern "C" fn init_timer() { - TIMER.start(); - thread::sleep(Duration::from_millis(5)); -} - -#[no_mangle] -pub extern "C" fn stop_timer() { - thread::sleep(Duration::from_millis(5)); - TIMER.stop(); -} - -#[no_mangle] -pub extern "C" fn get_tick_counter() -> TickType { - TIMER.get_tick_counter() -} +// lazy_static! { +// static ref TIMER: Timer = Timer::new(0, 5, 0.1); +// } +// +// #[no_mangle] +// pub extern "C" fn init_timer() { +// TIMER.start(); +// thread::sleep(Duration::from_millis(5)); +// } +// +// #[no_mangle] +// pub extern "C" fn stop_timer() { +// thread::sleep(Duration::from_millis(5)); +// TIMER.stop(); +// } +// +// #[no_mangle] +// pub extern "C" fn get_tick_counter() -> TickType { +// TIMER.get_tick_counter() +// } diff --git a/src/main.rs b/src/main.rs index 30c14d0..443319f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ use crate::timer::Timer; use core::sync::atomic::{AtomicU32, Ordering}; -use std::thread; -use std::time::Duration; mod connection; mod task_manager; @@ -45,20 +43,29 @@ fn stop_condition_fn2() -> bool { return false; } -fn main() { - let timer = Timer::new(0, 5, 0.1); - - timer.start(); - println!("Ticks time: {}", timer.get_tick_counter()); - thread::sleep(Duration::from_millis(5)); - println!("Ticks time: {}", timer.get_tick_counter()); - thread::sleep(Duration::from_millis(3)); - timer.stop(); - - println!("Final ticks time: {}", timer.get_tick_counter()); +fn setup_time() {} +fn loop_time() { + println!("{}", Timer::get_tick_counter()) +} +fn stop_condition_time() -> bool { + if Timer::get_tick_counter() == 100 { + return true; + } + return false; +} +fn main() { let mut task_executor = task_manager::TaskExecutor::new(); task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); task_executor.add_task(setup_fn2, loop_fn2, stop_condition_fn2); + + // Timer execution + task_executor.add_task( + Timer::setup_timer, + Timer::loop_timer, + Timer::stop_condition_timer, + ); + task_executor.add_task(setup_time, loop_time, stop_condition_time); + task_executor.start_task_manager(); } diff --git a/src/task_manager.rs b/src/task_manager.rs index 4df327e..60f90dd 100644 --- a/src/task_manager.rs +++ b/src/task_manager.rs @@ -11,13 +11,13 @@ struct Task { setup_fn: fn() -> (), /// Loop function, that is called in loop. loop_fn: fn() -> (), - /// Condition for stopping loop function execution. + /// Condition function for stopping loop function execution. stop_condition_fn: fn() -> bool, } -/// Future shell for task for execution +/// Future shell for task for execution. struct FutureTask { - /// Task to execute. + /// Task to execute in task manager. task: Task, /// Marker for setup function completion. is_setup_completed: bool, @@ -60,9 +60,11 @@ fn task_waker() -> Waker { unsafe { Waker::from_raw(raw_waker) } } -/// Task executor representation. +/// Task executor representation. Based on round-robin scheduling without priorities. pub struct TaskExecutor { + /// Vector of tasks to execute. tasks: Vec, + /// Index of task, that should be executed. task_to_execute_index: TaskNumberType, } @@ -75,7 +77,8 @@ impl TaskExecutor { } } - /// Add task to task executor. You should pass setup and loop functions. + /// Add task to task executor. You should pass setup, loop and condition functions. + // TODO: Maybe it is better to pass tasks here. Functions are done for C compatibility. pub fn add_task( &mut self, setup_fn: fn() -> (), @@ -95,19 +98,22 @@ impl TaskExecutor { } /// Starts task manager work. + // TODO: Support priorities. pub fn start_task_manager(&mut self) -> ! { loop { - let waker = task_waker(); - let task = &mut self.tasks[self.task_to_execute_index]; - let mut task_future_pin = Pin::new(task); - let _ = task_future_pin - .as_mut() - .poll(&mut Context::from_waker(&waker)); - - if self.task_to_execute_index < self.tasks.len() - 1 { - self.task_to_execute_index += 1; - } else { - self.task_to_execute_index = 0; + if !self.tasks.is_empty() { + let waker = task_waker(); + let task = &mut self.tasks[self.task_to_execute_index]; + let mut task_future_pin = Pin::new(task); + let _ = task_future_pin + .as_mut() + .poll(&mut Context::from_waker(&waker)); + + if self.task_to_execute_index + 1 < self.tasks.len() { + self.task_to_execute_index += 1; + } else { + self.task_to_execute_index = 0; + } } } } diff --git a/src/timer.rs b/src/timer.rs index 53bddb3..d239ae0 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,7 +1,3 @@ -use std::sync::{Arc, Mutex, MutexGuard}; -use std::thread; -use std::time::Duration; - use crate::connection; /// Type for tick counting. It is signed for synchronization. It should be u128. @@ -10,15 +6,19 @@ pub type TickType = i64; /// The definition of the timers themselves. pub struct Timer { /// Number of ticks in timer. - tick_counter: Arc>, - /// Flag is timer running. - running: Arc>, + tick_counter: TickType, /// Synchronization period in ticks. synchronization_period: TickType, /// Scale coefficient for local vote protocol. synchronization_scale: f64, } +static mut TIMER: Timer = Timer { + tick_counter: 0, + synchronization_period: 5, + synchronization_scale: 0.1, +}; + impl Timer { /// Creates new timer. pub fn new( @@ -27,56 +27,42 @@ impl Timer { synchronization_scale: f64, ) -> Timer { Timer { - tick_counter: Arc::new(Mutex::new(tick_counter)), - running: Arc::new(Mutex::new(false)), + tick_counter, synchronization_period, synchronization_scale, } } - /// Starts timer ticking. - pub fn start(&self) { - let counter = self.tick_counter.clone(); - let running = self.running.clone(); - let synchronization_period = self.synchronization_period.clone(); - let synchronization_scale = self.synchronization_scale.clone(); - - *running.lock().unwrap() = true; - - // TODO: this ticking should be added as a privilege task in task manager. Now it is in a separate thread. - thread::spawn(move || { - while *running.lock().unwrap() { - thread::sleep(Duration::from_millis(1)); - let mut count = counter.lock().unwrap(); - // TODO: this ticking should work with hardware ticks or with system ticks, not '+1' - *count += 1; - if *count % synchronization_period == 0 { - Timer::synchronize(&mut count, synchronization_scale); - } + pub fn setup_timer() {} - connection::send_timer_information(*count); - } - }); + /// Starts timer ticking. + pub fn loop_timer() { + unsafe { + TIMER.tick_counter += 1; + } } /// Stops timer ticking. - pub fn stop(&self) { - *self.running.lock().unwrap() = false; + pub fn stop_condition_timer() -> bool { + if (unsafe { TIMER.tick_counter }) == 100 { + return true; + } + return false; } /// Returns tick counter. - pub fn get_tick_counter(&self) -> TickType { - *self.tick_counter.lock().unwrap() + pub fn get_tick_counter() -> TickType { + return unsafe { TIMER.tick_counter }; } - /// Synchronizes tick counter by information from other timers - fn synchronize(_count: &mut MutexGuard, synchronization_scale: f64) { - let timers_information = connection::get_timers_information(); - // Local vote protocol. - let old_count = **_count; - for info in timers_information { - **_count += - (synchronization_scale * (old_count - info).abs() as f64).round() as TickType; - } - } + // /// Synchronizes tick counter by information from other timers + // fn synchronize(count: TickType, synchronization_scale: f64) { + // let timers_information = connection::get_timers_information(); + // // Local vote protocol. + // let old_count = *count; + // for info in timers_information { + // *count += + // (synchronization_scale * (old_count - info).abs() as f64).round() as TickType; + // } + // } } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 4270386..57cf4be 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,30 +1,2 @@ #[cfg(test)] -mod integration_tests { - use ma_rtos::timer::Timer; - use std::thread; - use std::time::Duration; - - #[test] - /// Tests work of several timers. - fn test_several_timers() { - let timer1 = Timer::new(0, 10000, 0.1); - let timer2 = Timer::new(10, 10000, 0.1); - - timer1.start(); - thread::sleep(Duration::from_millis(2)); - let count1 = timer1.get_tick_counter(); - - timer2.start(); - thread::sleep(Duration::from_millis(3)); - let count2 = timer2.get_tick_counter(); - - timer2.stop(); - let count3 = timer1.get_tick_counter(); - timer1.stop(); - - // Exact values cannot be presented because of threads - assert!(count1 <= 2); - assert!(count2 <= 12); - assert!(count3 <= 5); - } -} +mod integration_tests {} diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index c6657c9..a5cc349 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -1,63 +1,15 @@ #[cfg(test)] mod unit_tests { - use ma_rtos::timer::Timer; - use std::thread; - use std::time::Duration; + use ma_rtos::task_manager; #[test] - /// Tests new function of timer. - fn test_timer_new() { - let timer1 = Timer::new(0, 10000, 0.1); - let timer2 = Timer::new(42, 10000, 0.1); - let count1 = timer1.get_tick_counter(); - let count2 = timer2.get_tick_counter(); - - assert_eq!(count1, 0); - assert_eq!(count2, 42); - } - - #[test] - /// Tests start function of timer. - fn test_timer_start() { - let timer = Timer::new(0, 10000, 0.1); - timer.start(); - thread::sleep(Duration::from_millis(2)); - let count = timer.get_tick_counter(); - - // Exact values cannot be presented because of threads - assert!(count <= 2); - } - - #[test] - /// Tests stop function of timer. - fn test_timer_stop() { - let timer = Timer::new(0, 10000, 0.1); - timer.start(); - thread::sleep(Duration::from_millis(3)); - timer.stop(); - let count = timer.get_tick_counter(); - - // Exact values cannot be presented because of threads - assert!(count <= 3); - } - - #[test] - /// Tests get_tick_counter function of timer. - fn test_timer_get_tick_counter() { - let timer = Timer::new(0, 10000, 0.1); - timer.start(); - let count0 = timer.get_tick_counter(); - thread::sleep(Duration::from_millis(3)); - let count1 = timer.get_tick_counter(); - thread::sleep(Duration::from_millis(4)); - let count2 = timer.get_tick_counter(); - timer.stop(); - let count3 = timer.get_tick_counter(); - - assert_eq!(count0, 0); - // Exact values cannot be presented because of threads - assert!(count1 <= 3); - assert!(count2 <= 7); - assert!(count3 <= 7); + /// Tests if task manager without tasks works during 1 second without panic. + fn test_task_manager() { + let fun_thread = std::thread::spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.start_task_manager() + }); + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(dbg!(fun_thread.is_finished()), false); } } From 362d39995430d3039d2792612e90678193aa76ac Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 10:49:11 +0300 Subject: [PATCH 02/33] Add test --- tests/unit_tests.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index a5cc349..b807d28 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -1,10 +1,11 @@ #[cfg(test)] mod unit_tests { + use core::sync::atomic::{AtomicU32, Ordering}; use ma_rtos::task_manager; #[test] /// Tests if task manager without tasks works during 1 second without panic. - fn test_task_manager() { + fn test_empty_task_manager() { let fun_thread = std::thread::spawn(|| { let mut task_executor = task_manager::TaskExecutor::new(); task_executor.start_task_manager() @@ -12,4 +13,32 @@ mod unit_tests { std::thread::sleep(std::time::Duration::from_secs(1)); assert_eq!(dbg!(fun_thread.is_finished()), false); } + + static COUNTER: AtomicU32 = AtomicU32::new(1); + + fn setup_fn() {} + fn loop_fn() { + COUNTER.fetch_add(1, Ordering::Relaxed); + } + + fn stop_condition_fn() -> bool { + let value = unsafe { COUNTER.as_ptr().read() }; + if value % 50 == 0 { + return true; + } + return false; + } + + #[test] + /// Tests if task manager with task works during 1 second without panic. + fn test_one_task_task_manager() { + let fun_thread = std::thread::spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); + task_executor.start_task_manager() + }); + std::thread::sleep(std::time::Duration::from_secs(1)); + assert_eq!(dbg!(fun_thread.is_finished()), false); + assert_eq!(unsafe { COUNTER.as_ptr().read() }, 50); + } } From 52c866ea25f629868224e05707f50e8d1a0099bd Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 10:52:52 +0300 Subject: [PATCH 03/33] Add test --- tests/unit_tests.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index b807d28..b8eda09 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -11,18 +11,23 @@ mod unit_tests { task_executor.start_task_manager() }); std::thread::sleep(std::time::Duration::from_secs(1)); - assert_eq!(dbg!(fun_thread.is_finished()), false); + assert_eq!(fun_thread.is_finished(), false); } - static COUNTER: AtomicU32 = AtomicU32::new(1); + /// Counter for task for test_one_task_task_manager. + static TEST_ONE_TASK_TASK_MANAGER_COUNTER: AtomicU32 = AtomicU32::new(1); - fn setup_fn() {} - fn loop_fn() { - COUNTER.fetch_add(1, Ordering::Relaxed); + /// Setup function for task for test_one_task_task_manager. + fn test_one_task_task_manager_setup_fn() {} + + /// Loop function for task for test_one_task_task_manager. + fn test_one_task_task_manager_loop_fn() { + TEST_ONE_TASK_TASK_MANAGER_COUNTER.fetch_add(1, Ordering::Relaxed); } - fn stop_condition_fn() -> bool { - let value = unsafe { COUNTER.as_ptr().read() }; + /// Stop function for task for test_one_task_task_manager. + fn test_one_task_task_manager_stop_condition_fn() -> bool { + let value = unsafe { TEST_ONE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }; if value % 50 == 0 { return true; } @@ -30,15 +35,22 @@ mod unit_tests { } #[test] - /// Tests if task manager with task works during 1 second without panic. + /// Tests if task manager with task works correctly during 1 second without panic. fn test_one_task_task_manager() { let fun_thread = std::thread::spawn(|| { let mut task_executor = task_manager::TaskExecutor::new(); - task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); + task_executor.add_task( + test_one_task_task_manager_setup_fn, + test_one_task_task_manager_loop_fn, + test_one_task_task_manager_stop_condition_fn, + ); task_executor.start_task_manager() }); std::thread::sleep(std::time::Duration::from_secs(1)); - assert_eq!(dbg!(fun_thread.is_finished()), false); - assert_eq!(unsafe { COUNTER.as_ptr().read() }, 50); + assert_eq!(fun_thread.is_finished(), false); + assert_eq!( + unsafe { TEST_ONE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }, + 50 + ); } } From 9b602045ec8c7f5aa797e29f52e64d5af54b1a76 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 11:25:19 +0300 Subject: [PATCH 04/33] Add more tests --- tests/unit_tests.rs | 135 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 22 deletions(-) diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index b8eda09..67b8ab8 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -1,56 +1,147 @@ #[cfg(test)] mod unit_tests { - use core::sync::atomic::{AtomicU32, Ordering}; use ma_rtos::task_manager; + use std::sync::atomic::{AtomicU32, Ordering}; + use std::thread::{sleep, spawn}; + use std::time::Duration; #[test] /// Tests if task manager without tasks works during 1 second without panic. fn test_empty_task_manager() { - let fun_thread = std::thread::spawn(|| { + let fun_thread = spawn(|| { let mut task_executor = task_manager::TaskExecutor::new(); task_executor.start_task_manager() }); - std::thread::sleep(std::time::Duration::from_secs(1)); + sleep(Duration::from_secs(1)); + assert_eq!(fun_thread.is_finished(), false); } - /// Counter for task for test_one_task_task_manager. - static TEST_ONE_TASK_TASK_MANAGER_COUNTER: AtomicU32 = AtomicU32::new(1); + /// Counter for task for test_one_finite_task_task_manager. + static TEST_ONE_FINITE_TASK_TASK_MANAGER_COUNTER: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_one_finite_task_task_manager. + fn test_one_finite_task_task_manager_setup_fn() {} + /// Loop function for task for test_one_finite_task_task_manager. + fn test_one_finite_task_task_manager_loop_fn() { + TEST_ONE_FINITE_TASK_TASK_MANAGER_COUNTER.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_one_finite_task_task_manager. + fn test_one_finite_task_task_manager_stop_condition_fn() -> bool { + let value = unsafe { TEST_ONE_FINITE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }; + if value % 50 == 0 { + return true; + } + return false; + } + #[test] + /// Tests if task manager with one finite task works correctly during 1 second without panic. + fn test_one_finite_task_task_manager() { + let fun_thread = spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task( + test_one_finite_task_task_manager_setup_fn, + test_one_finite_task_task_manager_loop_fn, + test_one_finite_task_task_manager_stop_condition_fn, + ); + task_executor.start_task_manager() + }); + sleep(Duration::from_secs(1)); - /// Setup function for task for test_one_task_task_manager. - fn test_one_task_task_manager_setup_fn() {} + assert_eq!(fun_thread.is_finished(), false); + assert_eq!( + unsafe { TEST_ONE_FINITE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }, + 50 + ); + } - /// Loop function for task for test_one_task_task_manager. - fn test_one_task_task_manager_loop_fn() { - TEST_ONE_TASK_TASK_MANAGER_COUNTER.fetch_add(1, Ordering::Relaxed); + /// Counter for task for test_one_infinite_task_task_manager. + static TEST_ONE_INFINITE_TASK_TASK_MANAGER_COUNTER: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_one_infinite_task_task_manager. + fn test_one_infinite_task_task_manager_setup_fn() {} + /// Loop function for task for test_one_infinite_task_task_manager. + fn test_one_infinite_task_task_manager_loop_fn() { + TEST_ONE_INFINITE_TASK_TASK_MANAGER_COUNTER.fetch_add(1, Ordering::Relaxed); } + /// Stop function for task for test_one_infinite_task_task_manager. + fn test_one_infinite_task_task_manager_stop_condition_fn() -> bool { + return false; + } + #[test] + /// Tests if task manager with one infinite task works correctly during 1 second without panic. + fn test_one_infinite_task_task_manager() { + let fun_thread = spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task( + test_one_infinite_task_task_manager_setup_fn, + test_one_infinite_task_task_manager_loop_fn, + test_one_infinite_task_task_manager_stop_condition_fn, + ); + task_executor.start_task_manager() + }); + sleep(Duration::from_secs(1)); - /// Stop function for task for test_one_task_task_manager. - fn test_one_task_task_manager_stop_condition_fn() -> bool { - let value = unsafe { TEST_ONE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }; + assert_eq!(fun_thread.is_finished(), false); + } + + /// Counter for task for test_two_finite_tasks_task_manager. + static TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER1: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_setup_fn1() {} + /// Loop function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_loop_fn1() { + TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER1.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_stop_condition_fn1() -> bool { + let value = unsafe { TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER1.as_ptr().read() }; if value % 50 == 0 { return true; } return false; } - + /// Counter for task for test_two_finite_tasks_task_manager. + static TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER2: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_setup_fn2() {} + /// Loop function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_loop_fn2() { + TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER2.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_finite_tasks_task_manager. + fn test_two_finite_tasks_task_manager_stop_condition_fn2() -> bool { + let value = unsafe { TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER2.as_ptr().read() }; + if value % 25 == 0 { + return true; + } + return false; + } #[test] - /// Tests if task manager with task works correctly during 1 second without panic. - fn test_one_task_task_manager() { - let fun_thread = std::thread::spawn(|| { + /// Tests if task manager with two finite tasks works correctly during 1 second without panic. + fn test_two_finite_tasks_task_manager() { + let fun_thread = spawn(|| { let mut task_executor = task_manager::TaskExecutor::new(); task_executor.add_task( - test_one_task_task_manager_setup_fn, - test_one_task_task_manager_loop_fn, - test_one_task_task_manager_stop_condition_fn, + test_two_finite_tasks_task_manager_setup_fn1, + test_two_finite_tasks_task_manager_loop_fn1, + test_two_finite_tasks_task_manager_stop_condition_fn1, + ); + task_executor.add_task( + test_two_finite_tasks_task_manager_setup_fn2, + test_two_finite_tasks_task_manager_loop_fn2, + test_two_finite_tasks_task_manager_stop_condition_fn2, ); task_executor.start_task_manager() }); - std::thread::sleep(std::time::Duration::from_secs(1)); + sleep(Duration::from_secs(1)); + assert_eq!(fun_thread.is_finished(), false); assert_eq!( - unsafe { TEST_ONE_TASK_TASK_MANAGER_COUNTER.as_ptr().read() }, + unsafe { TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER1.as_ptr().read() }, 50 ); + assert_eq!( + unsafe { TEST_TWO_FINITE_TASK_TASK_MANAGER_COUNTER2.as_ptr().read() }, + 25 + ); } } From 1ad4c54272ad4b1f35ad618da64fc5d75c6b556c Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 17:43:04 +0300 Subject: [PATCH 05/33] Add more tests --- tests/unit_tests.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index 67b8ab8..3724d18 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -144,4 +144,66 @@ mod unit_tests { 25 ); } + + /// Counter for task for test_two_different_tasks_task_manager. + static TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER1: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_setup_fn1() {} + /// Loop function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_loop_fn1() { + TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER1.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_stop_condition_fn1() -> bool { + let value = unsafe { + TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER1 + .as_ptr() + .read() + }; + if value % 50 == 0 { + return true; + } + return false; + } + /// Counter for task for test_two_different_tasks_task_manager. + static TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER2: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_setup_fn2() {} + /// Loop function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_loop_fn2() { + TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER2.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_different_tasks_task_manager. + fn test_two_different_tasks_task_manager_stop_condition_fn2() -> bool { + return false; + } + #[test] + /// Tests if task manager with two different (finite and infinite) tasks works correctly during 1 second without panic. + fn test_two_different_tasks_task_manager() { + let fun_thread = spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task( + test_two_different_tasks_task_manager_setup_fn1, + test_two_different_tasks_task_manager_loop_fn1, + test_two_different_tasks_task_manager_stop_condition_fn1, + ); + task_executor.add_task( + test_two_different_tasks_task_manager_setup_fn2, + test_two_different_tasks_task_manager_loop_fn2, + test_two_different_tasks_task_manager_stop_condition_fn2, + ); + task_executor.start_task_manager() + }); + sleep(Duration::from_secs(1)); + + assert_eq!(fun_thread.is_finished(), false); + assert_eq!( + unsafe { + TEST_TWO_DIFFERENT_TASK_TASK_MANAGER_COUNTER1 + .as_ptr() + .read() + }, + 50 + ); + } } From 7d51646b65fdb61857f721c8dd9db80f32f9008e Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 21:53:31 +0300 Subject: [PATCH 06/33] Tests for task manager --- tests/unit_tests.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index 3724d18..8ee4750 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -206,4 +206,83 @@ mod unit_tests { 50 ); } + + /// Counter for task for test_two_infinite_tasks_task_manager. + static TEST_TWO_INFINITE_TASK_TASK_MANAGER_COUNTER1: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_setup_fn1() {} + /// Loop function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_loop_fn1() { + TEST_TWO_INFINITE_TASK_TASK_MANAGER_COUNTER1.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_stop_condition_fn1() -> bool { + return false; + } + /// Counter for task for test_two_infinite_tasks_task_manager. + static TEST_TWO_INFINITE_TASK_TASK_MANAGER_COUNTER2: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_setup_fn2() {} + /// Loop function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_loop_fn2() { + TEST_TWO_INFINITE_TASK_TASK_MANAGER_COUNTER2.fetch_add(1, Ordering::Relaxed); + } + /// Stop function for task for test_two_infinite_tasks_task_manager. + fn test_two_infinite_tasks_task_manager_stop_condition_fn2() -> bool { + return false; + } + #[test] + /// Tests if task manager with two infinite tasks works correctly during 1 second without panic. + fn test_two_infinite_tasks_task_manager() { + let fun_thread = spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task( + test_two_infinite_tasks_task_manager_setup_fn1, + test_two_infinite_tasks_task_manager_loop_fn1, + test_two_infinite_tasks_task_manager_stop_condition_fn1, + ); + task_executor.add_task( + test_two_infinite_tasks_task_manager_setup_fn2, + test_two_infinite_tasks_task_manager_loop_fn2, + test_two_infinite_tasks_task_manager_stop_condition_fn2, + ); + task_executor.start_task_manager() + }); + sleep(Duration::from_secs(1)); + + assert_eq!(fun_thread.is_finished(), false); + } + + /// Counter for task for test_setup_task_manager. + static TEST_SETUP_TASK_MANAGER_COUNTER: AtomicU32 = AtomicU32::new(1); + /// Setup function for task for test_setup_task_manager. + fn test_setup_task_manager_setup_fn() { + TEST_SETUP_TASK_MANAGER_COUNTER.store(42, Ordering::Relaxed); + } + /// Loop function for task for test_setup_task_manager. + fn test_setup_task_manager_loop_fn() {} + /// Stop function for task for test_setup_task_manager. + fn test_setup_task_manager_stop_condition_fn() -> bool { + return false; + } + #[test] + /// Tests if task manager works correctly with setup function during 1 second without panic. + fn test_setup_task_manager() { + let fun_thread = spawn(|| { + let mut task_executor = task_manager::TaskExecutor::new(); + task_executor.add_task( + test_setup_task_manager_setup_fn, + test_setup_task_manager_loop_fn, + test_setup_task_manager_stop_condition_fn, + ); + task_executor.start_task_manager() + }); + sleep(Duration::from_secs(1)); + + assert_eq!(fun_thread.is_finished(), false); + assert_eq!( + unsafe { TEST_SETUP_TASK_MANAGER_COUNTER.as_ptr().read() }, + 42 + ); + } } From f74cce8d29479f1dd9dbf6cbabacdd9ef06ec18e Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 21:56:32 +0300 Subject: [PATCH 07/33] Add todos --- src/task_manager.rs | 1 + tests/unit_tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/task_manager.rs b/src/task_manager.rs index 60f90dd..c607e5f 100644 --- a/src/task_manager.rs +++ b/src/task_manager.rs @@ -99,6 +99,7 @@ impl TaskExecutor { /// Starts task manager work. // TODO: Support priorities. + // TODO: Delete tasks from task vector if they are pending pub fn start_task_manager(&mut self) -> ! { loop { if !self.tasks.is_empty() { diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index 8ee4750..29bb66e 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -5,6 +5,8 @@ mod unit_tests { use std::thread::{sleep, spawn}; use std::time::Duration; + // TODO: refactor unit tests. They should check less. Separate tests for setup, loop and stop functions. + #[test] /// Tests if task manager without tasks works during 1 second without panic. fn test_empty_task_manager() { From 4a87729874e3c3c3f4e60c4fbcd4bf01704c98cc Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Thu, 22 Feb 2024 22:11:05 +0300 Subject: [PATCH 08/33] Refactor timer and delete some dead code --- src/connection.rs | 17 ----------------- src/lib.rs | 27 --------------------------- src/main.rs | 1 - src/timer.rs | 47 ++++++++--------------------------------------- 4 files changed, 8 insertions(+), 84 deletions(-) delete mode 100644 src/connection.rs diff --git a/src/connection.rs b/src/connection.rs deleted file mode 100644 index 8529bd7..0000000 --- a/src/connection.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::timer::TickType; - -/// Type for information from one timer -type TimerInformation = TickType; -/// Type for information from several timers -type TimersInformation = Vec; - -/// Sends timer information to neighbours (or adds it into package to send). -pub fn send_timer_information(_timer_information: TimerInformation) { - // TODO: Some code for sending information or adding it into package to send. It may be hardware dependent. -} - -/// Gets timer information from neighbour timers. -pub fn get_timers_information() -> TimersInformation { - // TODO: Some code, receiving information from other timers. It may be hardware dependent. - vec![10, 2, 3] -} diff --git a/src/lib.rs b/src/lib.rs index ffa0039..6315ed3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,29 +1,2 @@ -use crate::timer::{TickType, Timer}; -use lazy_static::lazy_static; -use std::thread; -use std::time::Duration; - -pub mod connection; pub mod task_manager; pub mod timer; - -// lazy_static! { -// static ref TIMER: Timer = Timer::new(0, 5, 0.1); -// } -// -// #[no_mangle] -// pub extern "C" fn init_timer() { -// TIMER.start(); -// thread::sleep(Duration::from_millis(5)); -// } -// -// #[no_mangle] -// pub extern "C" fn stop_timer() { -// thread::sleep(Duration::from_millis(5)); -// TIMER.stop(); -// } -// -// #[no_mangle] -// pub extern "C" fn get_tick_counter() -> TickType { -// TIMER.get_tick_counter() -// } diff --git a/src/main.rs b/src/main.rs index 443319f..21ecb9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use crate::timer::Timer; use core::sync::atomic::{AtomicU32, Ordering}; -mod connection; mod task_manager; mod timer; diff --git a/src/timer.rs b/src/timer.rs index d239ae0..653606c 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,52 +1,32 @@ -use crate::connection; - /// Type for tick counting. It is signed for synchronization. It should be u128. pub type TickType = i64; /// The definition of the timers themselves. +/// TODO: Should contain synchronization period and synchronization scale. pub struct Timer { /// Number of ticks in timer. tick_counter: TickType, - /// Synchronization period in ticks. - synchronization_period: TickType, - /// Scale coefficient for local vote protocol. - synchronization_scale: f64, } -static mut TIMER: Timer = Timer { - tick_counter: 0, - synchronization_period: 5, - synchronization_scale: 0.1, -}; +/// Operating system timer. +// TODO: Maybe it can be non static. It is static to make functions to pass to task manager. +// TODO: Default parameters should be read from config file. +static mut TIMER: Timer = Timer { tick_counter: 0 }; impl Timer { - /// Creates new timer. - pub fn new( - tick_counter: TickType, - synchronization_period: TickType, - synchronization_scale: f64, - ) -> Timer { - Timer { - tick_counter, - synchronization_period, - synchronization_scale, - } - } - + /// Setup function. May be used for setting configuration parameters. pub fn setup_timer() {} /// Starts timer ticking. + // TODO: What should happen after overflow? pub fn loop_timer() { unsafe { TIMER.tick_counter += 1; } } - /// Stops timer ticking. + /// Stops timer ticking. By default, it does not stop. pub fn stop_condition_timer() -> bool { - if (unsafe { TIMER.tick_counter }) == 100 { - return true; - } return false; } @@ -54,15 +34,4 @@ impl Timer { pub fn get_tick_counter() -> TickType { return unsafe { TIMER.tick_counter }; } - - // /// Synchronizes tick counter by information from other timers - // fn synchronize(count: TickType, synchronization_scale: f64) { - // let timers_information = connection::get_timers_information(); - // // Local vote protocol. - // let old_count = *count; - // for info in timers_information { - // *count += - // (synchronization_scale * (old_count - info).abs() as f64).round() as TickType; - // } - // } } From 825402d439923f6b4b457b178fef430bc397e16b Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Fri, 23 Feb 2024 19:44:23 +0300 Subject: [PATCH 09/33] Add timer tests --- Cargo.toml | 2 -- src/main.rs | 2 +- src/timer.rs | 6 +++++- tests/integration_tests.rs | 2 -- tests/unit_tests.rs | 29 +++++++++++++++++++++++++++++ 5 files changed, 35 insertions(+), 6 deletions(-) delete mode 100644 tests/integration_tests.rs diff --git a/Cargo.toml b/Cargo.toml index bb26b5b..1a4e120 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,3 @@ name = "ma_rtos" version = "0.1.0" edition = "2021" -[dependencies] -lazy_static = "1.4" diff --git a/src/main.rs b/src/main.rs index 21ecb9a..3419690 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,7 +47,7 @@ fn loop_time() { println!("{}", Timer::get_tick_counter()) } fn stop_condition_time() -> bool { - if Timer::get_tick_counter() == 100 { + if Timer::get_tick_counter() > 100 { return true; } return false; diff --git a/src/timer.rs b/src/timer.rs index 653606c..509cf1a 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -15,7 +15,11 @@ static mut TIMER: Timer = Timer { tick_counter: 0 }; impl Timer { /// Setup function. May be used for setting configuration parameters. - pub fn setup_timer() {} + pub fn setup_timer() { + unsafe { + TIMER.tick_counter = 0; + } + } /// Starts timer ticking. // TODO: What should happen after overflow? diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs deleted file mode 100644 index 57cf4be..0000000 --- a/tests/integration_tests.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod integration_tests {} diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index 29bb66e..c9e38ff 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -1,11 +1,13 @@ #[cfg(test)] mod unit_tests { use ma_rtos::task_manager; + use ma_rtos::timer::Timer; use std::sync::atomic::{AtomicU32, Ordering}; use std::thread::{sleep, spawn}; use std::time::Duration; // TODO: refactor unit tests. They should check less. Separate tests for setup, loop and stop functions. + // TODO: refactor unit tests. Task manager and timer tests should be in different files in one directory. #[test] /// Tests if task manager without tasks works during 1 second without panic. @@ -287,4 +289,31 @@ mod unit_tests { 42 ); } + + #[test] + /// Tests getting tick counter. + fn test_get_tick_counter_timer() { + assert_eq!(Timer::get_tick_counter(), 0); + } + + #[test] + /// Tests setup timer function. + fn test_setup_timer() { + Timer::setup_timer(); + assert_eq!(Timer::get_tick_counter(), 0); + } + + #[test] + /// Tests loop timer function. + fn test_loop_timer() { + Timer::setup_timer(); + Timer::loop_timer(); + assert_eq!(Timer::get_tick_counter(), 1); + } + + #[test] + /// Tests stop condition timer function. + fn test_stop_condition_timer() { + assert_eq!(Timer::stop_condition_timer(), false); + } } From 3a05996184770b00fd41b0abbcb7354edda3e1d4 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Fri, 23 Feb 2024 20:11:22 +0300 Subject: [PATCH 10/33] Creating simple example --- Cargo.toml | 1 - examples/rust-examples/xtensa-esp32/Cargo.toml | 8 ++++++++ examples/rust-examples/xtensa-esp32/src/main.rs | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 examples/rust-examples/xtensa-esp32/Cargo.toml create mode 100644 examples/rust-examples/xtensa-esp32/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 1a4e120..077a8d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,3 @@ name = "ma_rtos" version = "0.1.0" edition = "2021" - diff --git a/examples/rust-examples/xtensa-esp32/Cargo.toml b/examples/rust-examples/xtensa-esp32/Cargo.toml new file mode 100644 index 0000000..8dc8f7b --- /dev/null +++ b/examples/rust-examples/xtensa-esp32/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "example_xtensa_esp32" +version = "0.1.0" +edition = "2021" + +[dependencies] +# TODO: path should be from git, then from crates.io +ma_rtos = { path = "../../../" } \ No newline at end of file diff --git a/examples/rust-examples/xtensa-esp32/src/main.rs b/examples/rust-examples/xtensa-esp32/src/main.rs new file mode 100644 index 0000000..1c5df2f --- /dev/null +++ b/examples/rust-examples/xtensa-esp32/src/main.rs @@ -0,0 +1,5 @@ +use ma_rtos::timer::Timer; + +fn main() { + println!("Timer {}", Timer::get_tick_counter()); +} \ No newline at end of file From 390f8f37ad5551eaedbd6d1ca472f4fc1fba75b1 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Fri, 23 Feb 2024 20:27:53 +0300 Subject: [PATCH 11/33] Simple example for esp32 --- .../xtensa-esp32/.cargo/config.toml | 19 +++++++++++++++++++ .../rust-examples/xtensa-esp32/Cargo.toml | 11 ++++++++++- .../xtensa-esp32/rust-toolchain.toml | 2 ++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 examples/rust-examples/xtensa-esp32/.cargo/config.toml create mode 100644 examples/rust-examples/xtensa-esp32/rust-toolchain.toml diff --git a/examples/rust-examples/xtensa-esp32/.cargo/config.toml b/examples/rust-examples/xtensa-esp32/.cargo/config.toml new file mode 100644 index 0000000..20da577 --- /dev/null +++ b/examples/rust-examples/xtensa-esp32/.cargo/config.toml @@ -0,0 +1,19 @@ +[target.xtensa-esp32-none-elf] +runner = "espflash flash --monitor" + + +[build] +rustflags = [ + "-C", "link-arg=-Tlinkall.x", + + "-C", "link-arg=-nostartfiles", +] + +target = "xtensa-esp32-none-elf" + +[unstable] +build-std = ["core"] + +[target.'cfg(any(target_arch = "riscv32", target_arch = "xtensa"))'] +runner = "espflash flash --monitor" + diff --git a/examples/rust-examples/xtensa-esp32/Cargo.toml b/examples/rust-examples/xtensa-esp32/Cargo.toml index 8dc8f7b..5e8dba1 100644 --- a/examples/rust-examples/xtensa-esp32/Cargo.toml +++ b/examples/rust-examples/xtensa-esp32/Cargo.toml @@ -3,6 +3,15 @@ name = "example_xtensa_esp32" version = "0.1.0" edition = "2021" +[profile.release] +debug = true + [dependencies] # TODO: path should be from git, then from crates.io -ma_rtos = { path = "../../../" } \ No newline at end of file +ma_rtos = { path = "../../../" } +esp32-hal = "0.18.0" +esp-backtrace = { version = "0.11.0", features = ["esp32", "panic-handler", "exception-handler", "println"] } +esp-println = { version = "0.9.0", features = ["esp32"] } + +[features] +default = ["esp32-hal/xtal-40mhz"] \ No newline at end of file diff --git a/examples/rust-examples/xtensa-esp32/rust-toolchain.toml b/examples/rust-examples/xtensa-esp32/rust-toolchain.toml new file mode 100644 index 0000000..a2f5ab5 --- /dev/null +++ b/examples/rust-examples/xtensa-esp32/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "esp" From 51a80697c2bac910b28cbc0076c4f98c0c6d347f Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Fri, 23 Feb 2024 21:23:12 +0300 Subject: [PATCH 12/33] Simple example for esp32 works --- .../rust-examples/xtensa-esp32/src/main.rs | 10 ++++- src/lib.rs | 2 + src/task_manager.rs | 37 +++++++++++++++++-- tests/unit_tests.rs | 8 +--- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/examples/rust-examples/xtensa-esp32/src/main.rs b/examples/rust-examples/xtensa-esp32/src/main.rs index 1c5df2f..38eb107 100644 --- a/examples/rust-examples/xtensa-esp32/src/main.rs +++ b/examples/rust-examples/xtensa-esp32/src/main.rs @@ -1,5 +1,13 @@ +#![no_std] +#![no_main] + +use esp32_hal::entry; +use esp_backtrace as _; +use esp_println::println; use ma_rtos::timer::Timer; -fn main() { +#[entry] +fn main() -> ! { println!("Timer {}", Timer::get_tick_counter()); + loop {} } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 6315ed3..1f58ee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ +#![no_std] + pub mod task_manager; pub mod timer; diff --git a/src/task_manager.rs b/src/task_manager.rs index c607e5f..9a9b9c9 100644 --- a/src/task_manager.rs +++ b/src/task_manager.rs @@ -1,3 +1,4 @@ +use core::array::from_fn; use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; @@ -5,6 +6,10 @@ use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; /// The number of tasks can fit into a type usize. pub type TaskNumberType = usize; +/// Max number of tasks. +// TODO: Should be dynamic array of tasks. +const MAX_NUMBER_OF_TASKS: TaskNumberType = 20; + /// Task representation for task manager. struct Task { /// Setup function, that is called once at the beginning of task. @@ -27,6 +32,8 @@ impl Future for FutureTask { type Output = (); fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let mut array: [usize; 8] = core::array::from_fn(|i| i); + array[0] = 5; if (self.task.stop_condition_fn)() { Poll::Ready(()) } else { @@ -62,18 +69,39 @@ fn task_waker() -> Waker { /// Task executor representation. Based on round-robin scheduling without priorities. pub struct TaskExecutor { - /// Vector of tasks to execute. - tasks: Vec, + /// Static array of tasks to execute. + tasks: [FutureTask; MAX_NUMBER_OF_TASKS], /// Index of task, that should be executed. task_to_execute_index: TaskNumberType, + /// Number of tasks to execute. + tasks_number: TaskNumberType, } impl TaskExecutor { /// Creates new task executor. pub fn new() -> TaskExecutor { + fn setup_fn() {} + fn loop_fn() {} + fn stop_condition_fn() -> bool { + return true; + } + + let tasks: [FutureTask; MAX_NUMBER_OF_TASKS] = from_fn(|_| { + let task = Task { + setup_fn: setup_fn, + loop_fn: loop_fn, + stop_condition_fn: stop_condition_fn, + }; + FutureTask { + task: task, + is_setup_completed: true, + } + }); + TaskExecutor { - tasks: vec![], + tasks: tasks, task_to_execute_index: 0, + tasks_number: 0, } } @@ -94,7 +122,8 @@ impl TaskExecutor { task, is_setup_completed: false, }; - self.tasks.push(future_task) + self.tasks[self.tasks_number] = future_task; + self.tasks_number += 1 } /// Starts task manager work. diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index c9e38ff..a7cfc0d 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -291,13 +291,7 @@ mod unit_tests { } #[test] - /// Tests getting tick counter. - fn test_get_tick_counter_timer() { - assert_eq!(Timer::get_tick_counter(), 0); - } - - #[test] - /// Tests setup timer function. + /// Tests setup timer function and getting tick counter (bad unit test). fn test_setup_timer() { Timer::setup_timer(); assert_eq!(Timer::get_tick_counter(), 0); From 8bcb66e95758b61f4080ad1f1d16cfe3329d3136 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 12:30:43 +0300 Subject: [PATCH 13/33] Simple example for esp32 with task manager --- .../rust-examples/xtensa-esp32/src/main.rs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/examples/rust-examples/xtensa-esp32/src/main.rs b/examples/rust-examples/xtensa-esp32/src/main.rs index 38eb107..9986b2f 100644 --- a/examples/rust-examples/xtensa-esp32/src/main.rs +++ b/examples/rust-examples/xtensa-esp32/src/main.rs @@ -1,13 +1,42 @@ #![no_std] #![no_main] +use core::sync::atomic::{AtomicU32, Ordering}; use esp32_hal::entry; use esp_backtrace as _; use esp_println::println; -use ma_rtos::timer::Timer; +use ma_rtos::task_manager; + +/// Counter to work with in loop. +static COUNTER: AtomicU32 = AtomicU32::new(1); + +/// Setup function for task to execute. +fn setup_fn() { + println!("Setup hello world!") +} + +/// Loop function for task to execute. +fn loop_fn() { + COUNTER.fetch_add(1, Ordering::Relaxed); + println!("Loop hello world!"); + println!("Counter = {}", unsafe { COUNTER.as_ptr().read() }); +} + +/// Stop condition function for task to execute. +fn stop_condition_fn() -> bool { + let value = unsafe { COUNTER.as_ptr().read() }; + if value % 50 == 0 { + return true; + } + return false; +} #[entry] fn main() -> ! { - println!("Timer {}", Timer::get_tick_counter()); - loop {} + // Creating task executer. + let mut task_executor = task_manager::TaskExecutor::new(); + // Add task to execute. + task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); + // Start task manager. + task_executor.start_task_manager(); } \ No newline at end of file From 21360e95b9c5b6bf426ed4a60243a44580c65059 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 12:41:36 +0300 Subject: [PATCH 14/33] Build example in ci --- .github/workflows/rust.yml | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a4071a3..6a1d355 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,10 +1,10 @@ name: Rust -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] +#on: +# push: +# branches: [ "main" ] +# pull_request: +# branches: [ "main" ] env: CARGO_TERM_COLOR: always @@ -13,20 +13,33 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose + - name: Build + uses: actions/checkout@v3 + run: cargo build --verbose test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - name: Run tests + uses: actions/checkout@v3 run: cargo test --verbose fmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - name: Fmt + uses: actions/checkout@v3 run: cargo fmt --all -- --check + + xtensa-esp32-example: + runs-on: ubuntu-latest + steps: + - name: Setup build env + uses: actions/checkout@v3 + run: cargo install espup && espup install + - name: Build + uses: actions/checkout@v3 + run: cd ./examples/rust-examples/xtensa-esp32 && . $HOME/export-esp.sh && cargo build + - name: Fmt + uses: actions/checkout@v3 + run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check From d60cb4efbf03c9373206ec89fbcc63a05ebcafd1 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 12:43:46 +0300 Subject: [PATCH 15/33] Fix ci --- .github/workflows/rust.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6a1d355..10e2b08 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,33 +13,31 @@ jobs: build: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - name: Build - uses: actions/checkout@v3 run: cargo build --verbose test: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - name: Run tests - uses: actions/checkout@v3 run: cargo test --verbose fmt: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - name: Fmt - uses: actions/checkout@v3 run: cargo fmt --all -- --check xtensa-esp32-example: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - name: Setup build env - uses: actions/checkout@v3 run: cargo install espup && espup install - name: Build - uses: actions/checkout@v3 run: cd ./examples/rust-examples/xtensa-esp32 && . $HOME/export-esp.sh && cargo build - name: Fmt - uses: actions/checkout@v3 run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check From cf6d7ffbb13fc09c047c5241e9d0666b710aab95 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 12:45:14 +0300 Subject: [PATCH 16/33] Fix ci --- .github/workflows/rust.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 10e2b08..1f222a3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -5,6 +5,8 @@ name: Rust # branches: [ "main" ] # pull_request: # branches: [ "main" ] +on: + - push env: CARGO_TERM_COLOR: always From 6393d540c4fa0b155be6c76a40ca212e8db7c0d0 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 12:55:23 +0300 Subject: [PATCH 17/33] Fix fmt --- examples/rust-examples/xtensa-esp32/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rust-examples/xtensa-esp32/src/main.rs b/examples/rust-examples/xtensa-esp32/src/main.rs index 9986b2f..716cdd3 100644 --- a/examples/rust-examples/xtensa-esp32/src/main.rs +++ b/examples/rust-examples/xtensa-esp32/src/main.rs @@ -39,4 +39,4 @@ fn main() -> ! { task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); // Start task manager. task_executor.start_task_manager(); -} \ No newline at end of file +} From c7f0b24d97ae26daf405bba0af18362af2661d14 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 13:08:28 +0300 Subject: [PATCH 18/33] Some ci improvements --- .github/workflows/rust.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1f222a3..cac69f6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -37,9 +37,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Setup build env + - name: Fmt + run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check + - name: Setup build environment run: cargo install espup && espup install - name: Build run: cd ./examples/rust-examples/xtensa-esp32 && . $HOME/export-esp.sh && cargo build - - name: Fmt - run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check From d766010e3897aefc57aa5c2d74e684a0c782edee Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 13:11:16 +0300 Subject: [PATCH 19/33] Some todo in ci --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cac69f6..5543c3c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,6 +39,7 @@ jobs: - uses: actions/checkout@v3 - name: Fmt run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check + # TODO: to avoid setupping, ci should pass on prepared dockers on self-hosted runners - name: Setup build environment run: cargo install espup && espup install - name: Build From 43573a4a2cc0346322d577d50237132c6cdaef98 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 13:17:52 +0300 Subject: [PATCH 20/33] Fix ci --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5543c3c..5c16277 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -37,10 +37,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Fmt - run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check # TODO: to avoid setupping, ci should pass on prepared dockers on self-hosted runners - name: Setup build environment run: cargo install espup && espup install - name: Build run: cd ./examples/rust-examples/xtensa-esp32 && . $HOME/export-esp.sh && cargo build + - name: Fmt + run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check From 8bb66d0c8556f2b04e31ad00db8b4a0869815683 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 13:32:37 +0300 Subject: [PATCH 21/33] Change ci not to run --- .github/workflows/rust.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5c16277..eb653e3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,12 +1,12 @@ name: Rust -#on: -# push: -# branches: [ "main" ] -# pull_request: -# branches: [ "main" ] on: - - push + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] +#on: +# - push env: CARGO_TERM_COLOR: always From 81f4ef588a3a982725288f043aabbd6f9b43aea4 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 13:33:18 +0300 Subject: [PATCH 22/33] Simple dynamic lib --- c-library/xtensa-esp32/Cargo.toml | 12 ++++++++++++ c-library/xtensa-esp32/src/lib.rs | 6 ++++++ 2 files changed, 18 insertions(+) create mode 100644 c-library/xtensa-esp32/Cargo.toml create mode 100644 c-library/xtensa-esp32/src/lib.rs diff --git a/c-library/xtensa-esp32/Cargo.toml b/c-library/xtensa-esp32/Cargo.toml new file mode 100644 index 0000000..a7ffa39 --- /dev/null +++ b/c-library/xtensa-esp32/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "xtensa_esp32_dynamic_lib" +version = "0.1.0" +edition = "2021" + +[lib] +name = "xtensa_esp32_dynamic_lib" +crate-type = ["cdylib"] + +[dependencies] +# TODO: path should be from git, then from crates.io +ma_rtos = { path = "../../" } \ No newline at end of file diff --git a/c-library/xtensa-esp32/src/lib.rs b/c-library/xtensa-esp32/src/lib.rs new file mode 100644 index 0000000..34eca87 --- /dev/null +++ b/c-library/xtensa-esp32/src/lib.rs @@ -0,0 +1,6 @@ +use ma_rtos::timer::{Timer, TickType}; + +#[no_mangle] +pub extern "C" fn get_tick_counter() -> TickType { + Timer::get_tick_counter() +} \ No newline at end of file From 83a2ca870949f133d216233542d0565eca59e9a6 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Sun, 25 Feb 2024 15:45:21 +0300 Subject: [PATCH 23/33] Simple static lib --- c-library/xtensa-esp32/.cargo/config.toml | 19 +++++++++++++++++++ c-library/xtensa-esp32/Cargo.toml | 17 +++++++++++++---- c-library/xtensa-esp32/rust-toolchain.toml | 2 ++ c-library/xtensa-esp32/src/lib.rs | 7 +++++++ 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 c-library/xtensa-esp32/.cargo/config.toml create mode 100644 c-library/xtensa-esp32/rust-toolchain.toml diff --git a/c-library/xtensa-esp32/.cargo/config.toml b/c-library/xtensa-esp32/.cargo/config.toml new file mode 100644 index 0000000..20da577 --- /dev/null +++ b/c-library/xtensa-esp32/.cargo/config.toml @@ -0,0 +1,19 @@ +[target.xtensa-esp32-none-elf] +runner = "espflash flash --monitor" + + +[build] +rustflags = [ + "-C", "link-arg=-Tlinkall.x", + + "-C", "link-arg=-nostartfiles", +] + +target = "xtensa-esp32-none-elf" + +[unstable] +build-std = ["core"] + +[target.'cfg(any(target_arch = "riscv32", target_arch = "xtensa"))'] +runner = "espflash flash --monitor" + diff --git a/c-library/xtensa-esp32/Cargo.toml b/c-library/xtensa-esp32/Cargo.toml index a7ffa39..6ac93e8 100644 --- a/c-library/xtensa-esp32/Cargo.toml +++ b/c-library/xtensa-esp32/Cargo.toml @@ -1,12 +1,21 @@ [package] -name = "xtensa_esp32_dynamic_lib" +name = "xtensa_esp32_static_lib" version = "0.1.0" edition = "2021" [lib] -name = "xtensa_esp32_dynamic_lib" -crate-type = ["cdylib"] +name = "xtensa_esp32_static_lib" +crate-type = ["staticlib"] + +[profile.release] +debug = true [dependencies] # TODO: path should be from git, then from crates.io -ma_rtos = { path = "../../" } \ No newline at end of file +ma_rtos = { path = "../../" } +esp32-hal = "0.18.0" +esp-backtrace = { version = "0.11.0", features = ["esp32", "panic-handler", "exception-handler", "println"] } +esp-println = { version = "0.9.0", features = ["esp32"] } + +[features] +default = ["esp32-hal/xtal-40mhz"] \ No newline at end of file diff --git a/c-library/xtensa-esp32/rust-toolchain.toml b/c-library/xtensa-esp32/rust-toolchain.toml new file mode 100644 index 0000000..a2f5ab5 --- /dev/null +++ b/c-library/xtensa-esp32/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "esp" diff --git a/c-library/xtensa-esp32/src/lib.rs b/c-library/xtensa-esp32/src/lib.rs index 34eca87..2672cd3 100644 --- a/c-library/xtensa-esp32/src/lib.rs +++ b/c-library/xtensa-esp32/src/lib.rs @@ -1,5 +1,12 @@ +#![no_std] + use ma_rtos::timer::{Timer, TickType}; +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + #[no_mangle] pub extern "C" fn get_tick_counter() -> TickType { Timer::get_tick_counter() From 7057a81d03727be629e236a51c2a1bb16e7bc2d8 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 06:46:58 +0300 Subject: [PATCH 24/33] Add simple c example --- .gitignore | 6 +++++- examples/c-examples/xtensa-esp32/CMakeLists.txt | 6 ++++++ examples/c-examples/xtensa-esp32/README.md | 1 + examples/c-examples/xtensa-esp32/main/CMakeLists.txt | 6 ++++++ .../c-examples/xtensa-esp32/main/hello_world_main.c | 11 +++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 examples/c-examples/xtensa-esp32/CMakeLists.txt create mode 100644 examples/c-examples/xtensa-esp32/README.md create mode 100644 examples/c-examples/xtensa-esp32/main/CMakeLists.txt create mode 100644 examples/c-examples/xtensa-esp32/main/hello_world_main.c diff --git a/.gitignore b/.gitignore index ada8be9..8e809c5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,8 @@ Cargo.lock **/*.rs.bk # MSVC Windows builds of rustc generate these, which store debugging information -*.pdb \ No newline at end of file +*.pdb + +# Espessif generated files and directories +sdkconfig +build/ \ No newline at end of file diff --git a/examples/c-examples/xtensa-esp32/CMakeLists.txt b/examples/c-examples/xtensa-esp32/CMakeLists.txt new file mode 100644 index 0000000..0a454d0 --- /dev/null +++ b/examples/c-examples/xtensa-esp32/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(hello_world) diff --git a/examples/c-examples/xtensa-esp32/README.md b/examples/c-examples/xtensa-esp32/README.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/c-examples/xtensa-esp32/README.md @@ -0,0 +1 @@ + diff --git a/examples/c-examples/xtensa-esp32/main/CMakeLists.txt b/examples/c-examples/xtensa-esp32/main/CMakeLists.txt new file mode 100644 index 0000000..96f934d --- /dev/null +++ b/examples/c-examples/xtensa-esp32/main/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register(SRCS "hello_world_main.c" + INCLUDE_DIRS "") + +# Linking with martos static library. Set here path to it in your project. +# Here path is so for ci. +target_link_libraries(${COMPONENT_LIB} ${CMAKE_CURRENT_LIST_DIR}/../../../../c-library/xtensa-esp32/target/xtensa-esp32-none-elf/debug/libxtensa_esp32_static_lib.a -Wl,--allow-multiple-definition) diff --git a/examples/c-examples/xtensa-esp32/main/hello_world_main.c b/examples/c-examples/xtensa-esp32/main/hello_world_main.c new file mode 100644 index 0000000..50b7f5b --- /dev/null +++ b/examples/c-examples/xtensa-esp32/main/hello_world_main.c @@ -0,0 +1,11 @@ +#include + +extern long get_tick_counter(); + +void app_main(void) +{ + long tick = get_tick_counter(); + printf("tick in c = %ld\n", tick); + + for (;;) {} +} From 58e1117e4e06a8cd77e4bc588bb1cc40e2ebbb5e Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 06:59:07 +0300 Subject: [PATCH 25/33] Ci for static library and c example --- .github/workflows/rust.yml | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index eb653e3..0908dc6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,12 +1,12 @@ name: Rust -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] #on: -# - push +# push: +# branches: [ "main" ] +# pull_request: +# branches: [ "main" ] +on: + - push env: CARGO_TERM_COLOR: always @@ -33,7 +33,7 @@ jobs: - name: Fmt run: cargo fmt --all -- --check - xtensa-esp32-example: + xtensa-esp32-rust-example: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -44,3 +44,26 @@ jobs: run: cd ./examples/rust-examples/xtensa-esp32 && . $HOME/export-esp.sh && cargo build - name: Fmt run: cd ./examples/rust-examples/xtensa-esp32 && cargo fmt --all -- --check + + xtensa-esp32-static-library: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # TODO: to avoid setupping, ci should pass on prepared dockers on self-hosted runners + - name: Setup build environment + run: cargo install espup && espup install + - name: Build + run: cd ./c-library/xtensa-esp32 && . $HOME/export-esp.sh && cargo build + - name: Fmt + run: cd ./c-library/xtensa-esp32 && cargo fmt --all -- --check + + xtensa-esp32-c-example: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # TODO: to avoid setupping, ci should pass on prepared dockers on self-hosted runners + - name: Setup build environment + run: cargo install espup && espup install && apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 && mkdir -p ~/esp && cd ~/esp && git clone -b v5.2 --recursive https://github.com/espressif/esp-idf.git && cd ~/esp/esp-idf && ./install.sh esp32 + # TODO: to avoid building static library, this job should use artifacts from xtensa-esp32-static-library job + - name: Build + run: cd ./c-library/xtensa-esp32 && . $HOME/export-esp.sh && cargo build && cd ../../examples/c-examples/xtensa-esp32 && . $HOME/esp/esp-idf/export.sh && idf.py build \ No newline at end of file From b0939eb5d56b0790668c29099f6877d30f471ac2 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 07:24:34 +0300 Subject: [PATCH 26/33] Fix ci --- .github/workflows/rust.yml | 2 +- c-library/xtensa-esp32/src/lib.rs | 4 ++-- examples/c-examples/xtensa-esp32/main/CMakeLists.txt | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0908dc6..4be25d3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -63,7 +63,7 @@ jobs: - uses: actions/checkout@v3 # TODO: to avoid setupping, ci should pass on prepared dockers on self-hosted runners - name: Setup build environment - run: cargo install espup && espup install && apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 && mkdir -p ~/esp && cd ~/esp && git clone -b v5.2 --recursive https://github.com/espressif/esp-idf.git && cd ~/esp/esp-idf && ./install.sh esp32 + run: cargo install espup && espup install && sudo apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 && mkdir -p ~/esp && cd ~/esp && git clone -b v5.2 --recursive https://github.com/espressif/esp-idf.git && cd ~/esp/esp-idf && ./install.sh esp32 # TODO: to avoid building static library, this job should use artifacts from xtensa-esp32-static-library job - name: Build run: cd ./c-library/xtensa-esp32 && . $HOME/export-esp.sh && cargo build && cd ../../examples/c-examples/xtensa-esp32 && . $HOME/esp/esp-idf/export.sh && idf.py build \ No newline at end of file diff --git a/c-library/xtensa-esp32/src/lib.rs b/c-library/xtensa-esp32/src/lib.rs index 2672cd3..82c542a 100644 --- a/c-library/xtensa-esp32/src/lib.rs +++ b/c-library/xtensa-esp32/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use ma_rtos::timer::{Timer, TickType}; +use ma_rtos::timer::{TickType, Timer}; #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { @@ -10,4 +10,4 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[no_mangle] pub extern "C" fn get_tick_counter() -> TickType { Timer::get_tick_counter() -} \ No newline at end of file +} diff --git a/examples/c-examples/xtensa-esp32/main/CMakeLists.txt b/examples/c-examples/xtensa-esp32/main/CMakeLists.txt index 96f934d..b4a1240 100644 --- a/examples/c-examples/xtensa-esp32/main/CMakeLists.txt +++ b/examples/c-examples/xtensa-esp32/main/CMakeLists.txt @@ -3,4 +3,5 @@ idf_component_register(SRCS "hello_world_main.c" # Linking with martos static library. Set here path to it in your project. # Here path is so for ci. +# TODO: should be more beautiful linking target_link_libraries(${COMPONENT_LIB} ${CMAKE_CURRENT_LIST_DIR}/../../../../c-library/xtensa-esp32/target/xtensa-esp32-none-elf/debug/libxtensa_esp32_static_lib.a -Wl,--allow-multiple-definition) From 8a26a64c54c2c313e50a677534e5ce8093e0d68e Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 07:42:33 +0300 Subject: [PATCH 27/33] Comment ci --- .github/workflows/rust.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4be25d3..32f3d5c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,12 +1,12 @@ name: Rust -#on: -# push: -# branches: [ "main" ] -# pull_request: -# branches: [ "main" ] on: - - push + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] +#on: +# - push env: CARGO_TERM_COLOR: always From 3f99fd84d1b71d34df2674d08e744dd1729c90ae Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 07:55:01 +0300 Subject: [PATCH 28/33] Add some functions --- c-library/xtensa-esp32/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/c-library/xtensa-esp32/src/lib.rs b/c-library/xtensa-esp32/src/lib.rs index 82c542a..7fea164 100644 --- a/c-library/xtensa-esp32/src/lib.rs +++ b/c-library/xtensa-esp32/src/lib.rs @@ -1,5 +1,8 @@ +// TODO: maybe all this should be in martos, not in c-library folder + #![no_std] +// use ma_rtos::task_manager::TaskExecutor; use ma_rtos::timer::{TickType, Timer}; #[panic_handler] @@ -7,6 +10,21 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } +#[no_mangle] +pub extern "C" fn setup_timer() { + Timer::setup_timer() +} + +#[no_mangle] +pub extern "C" fn loop_timer() { + Timer::loop_timer() +} + +#[no_mangle] +pub extern "C" fn stop_condition_timer() -> bool { + Timer::stop_condition_timer() +} + #[no_mangle] pub extern "C" fn get_tick_counter() -> TickType { Timer::get_tick_counter() From cd8b2eeae893d226e057bd8f2cf1cf3c6f5b328b Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 08:44:24 +0300 Subject: [PATCH 29/33] Some fixes --- .github/workflows/rust.yml | 2 +- src/main.rs | 70 -------------------------------------- 2 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 src/main.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 32f3d5c..7cb73f3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Build + - name: Build --lib run: cargo build --verbose test: diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 3419690..0000000 --- a/src/main.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::timer::Timer; - -use core::sync::atomic::{AtomicU32, Ordering}; - -mod task_manager; -mod timer; - -static COUNTER: AtomicU32 = AtomicU32::new(1); -static COUNTER2: AtomicU32 = AtomicU32::new(1); - -fn setup_fn() { - println!("Setup!") -} -fn loop_fn() { - COUNTER.fetch_add(1, Ordering::Relaxed); - println!("Counter {}", unsafe { COUNTER.as_ptr().read() }); - println!("Loop!") -} - -fn stop_condition_fn() -> bool { - let value = unsafe { COUNTER.as_ptr().read() }; - if value % 50 == 0 { - return true; - } - return false; -} - -fn setup_fn2() { - println!("Setup2!") -} -fn loop_fn2() { - COUNTER2.fetch_add(1, Ordering::Relaxed); - println!("Counter2 {}", unsafe { COUNTER2.as_ptr().read() }); - println!("Loop2!") -} - -fn stop_condition_fn2() -> bool { - let value = unsafe { COUNTER2.as_ptr().read() }; - if value % 55 == 0 { - return true; - } - return false; -} - -fn setup_time() {} -fn loop_time() { - println!("{}", Timer::get_tick_counter()) -} -fn stop_condition_time() -> bool { - if Timer::get_tick_counter() > 100 { - return true; - } - return false; -} - -fn main() { - let mut task_executor = task_manager::TaskExecutor::new(); - task_executor.add_task(setup_fn, loop_fn, stop_condition_fn); - task_executor.add_task(setup_fn2, loop_fn2, stop_condition_fn2); - - // Timer execution - task_executor.add_task( - Timer::setup_timer, - Timer::loop_timer, - Timer::stop_condition_timer, - ); - task_executor.add_task(setup_time, loop_time, stop_condition_time); - - task_executor.start_task_manager(); -} From 089b3ea5d35a3b452caab60cff03f9d987e9dbd8 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Tue, 5 Mar 2024 08:58:22 +0300 Subject: [PATCH 30/33] Todo in ci --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7cb73f3..e5c80d2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,6 +33,7 @@ jobs: - name: Fmt run: cargo fmt --all -- --check +# TODO: change to cargo build --example xtensa-esp32-rust-example: runs-on: ubuntu-latest steps: From 47b832422ffe79f486ad7e601d50c19fb0f37bef Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Wed, 6 Mar 2024 20:42:42 +0300 Subject: [PATCH 31/33] C support --- .github/workflows/rust.yml | 12 ++++---- Cargo.toml | 4 +++ c-library/xtensa-esp32/Cargo.toml | 2 +- c-library/xtensa-esp32/src/lib.rs | 7 ++++- src/task_manager.rs | 46 +++++++++++++++++++++++++++---- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e5c80d2..30503de 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,12 +1,12 @@ name: Rust -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] #on: -# - push +# push: +# branches: [ "main" ] +# pull_request: +# branches: [ "main" ] +on: + - push env: CARGO_TERM_COLOR: always diff --git a/Cargo.toml b/Cargo.toml index 077a8d7..0ec132a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,7 @@ name = "ma_rtos" version = "0.1.0" edition = "2021" + +[features] +default = [] +c-library = [] \ No newline at end of file diff --git a/c-library/xtensa-esp32/Cargo.toml b/c-library/xtensa-esp32/Cargo.toml index 6ac93e8..e0c5131 100644 --- a/c-library/xtensa-esp32/Cargo.toml +++ b/c-library/xtensa-esp32/Cargo.toml @@ -12,7 +12,7 @@ debug = true [dependencies] # TODO: path should be from git, then from crates.io -ma_rtos = { path = "../../" } +ma_rtos = { path = "../../", features = ["c-library"] } esp32-hal = "0.18.0" esp-backtrace = { version = "0.11.0", features = ["esp32", "panic-handler", "exception-handler", "println"] } esp-println = { version = "0.9.0", features = ["esp32"] } diff --git a/c-library/xtensa-esp32/src/lib.rs b/c-library/xtensa-esp32/src/lib.rs index 7fea164..a7eb650 100644 --- a/c-library/xtensa-esp32/src/lib.rs +++ b/c-library/xtensa-esp32/src/lib.rs @@ -2,7 +2,7 @@ #![no_std] -// use ma_rtos::task_manager::TaskExecutor; +use ma_rtos::task_manager::TaskExecutor; use ma_rtos::timer::{TickType, Timer}; #[panic_handler] @@ -29,3 +29,8 @@ pub extern "C" fn stop_condition_timer() -> bool { pub extern "C" fn get_tick_counter() -> TickType { Timer::get_tick_counter() } + +#[no_mangle] +pub extern "C" fn new_task_executor() -> TaskExecutor { + TaskExecutor::new() +} diff --git a/src/task_manager.rs b/src/task_manager.rs index 9a9b9c9..5eb8524 100644 --- a/src/task_manager.rs +++ b/src/task_manager.rs @@ -6,20 +6,42 @@ use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; /// The number of tasks can fit into a type usize. pub type TaskNumberType = usize; +// TODO: rewrite with cfg! +#[cfg(not(feature = "c-library"))] +/// Type of setup function, that is called once at the beginning of task. +type TaskSetupFunctionType = fn() -> (); +#[cfg(feature = "c-library")] +/// Type of setup function, that is called once at the beginning of task. +type TaskSetupFunctionType = extern "C" fn() -> (); +#[cfg(not(feature = "c-library"))] +/// Type of loop function, that is called in loop. +type TaskLoopFunctionType = fn() -> (); +#[cfg(feature = "c-library")] +/// Type of loop function, that is called in loop. +type TaskLoopFunctionType = extern "C" fn() -> (); +#[cfg(not(feature = "c-library"))] +/// Type of condition function for stopping loop function execution. +type TaskStopConditionFunctionType = fn() -> bool; +#[cfg(feature = "c-library")] +/// Type of condition function for stopping loop function execution. +type TaskStopConditionFunctionType = extern "C" fn() -> bool; + /// Max number of tasks. // TODO: Should be dynamic array of tasks. const MAX_NUMBER_OF_TASKS: TaskNumberType = 20; +#[repr(C)] /// Task representation for task manager. struct Task { /// Setup function, that is called once at the beginning of task. - setup_fn: fn() -> (), + setup_fn: TaskSetupFunctionType, /// Loop function, that is called in loop. - loop_fn: fn() -> (), + loop_fn: TaskLoopFunctionType, /// Condition function for stopping loop function execution. - stop_condition_fn: fn() -> bool, + stop_condition_fn: TaskStopConditionFunctionType, } +#[repr(C)] /// Future shell for task for execution. struct FutureTask { /// Task to execute in task manager. @@ -67,6 +89,7 @@ fn task_waker() -> Waker { unsafe { Waker::from_raw(raw_waker) } } +#[repr(C)] /// Task executor representation. Based on round-robin scheduling without priorities. pub struct TaskExecutor { /// Static array of tasks to execute. @@ -80,11 +103,22 @@ pub struct TaskExecutor { impl TaskExecutor { /// Creates new task executor. pub fn new() -> TaskExecutor { + #[cfg(not(feature = "c-library"))] fn setup_fn() {} + #[cfg(not(feature = "c-library"))] fn loop_fn() {} + #[cfg(not(feature = "c-library"))] fn stop_condition_fn() -> bool { return true; } + #[cfg(feature = "c-library")] + extern "C" fn setup_fn() {} + #[cfg(feature = "c-library")] + extern "C" fn loop_fn() {} + #[cfg(feature = "c-library")] + extern "C" fn stop_condition_fn() -> bool { + return true; + } let tasks: [FutureTask; MAX_NUMBER_OF_TASKS] = from_fn(|_| { let task = Task { @@ -109,9 +143,9 @@ impl TaskExecutor { // TODO: Maybe it is better to pass tasks here. Functions are done for C compatibility. pub fn add_task( &mut self, - setup_fn: fn() -> (), - loop_fn: fn() -> (), - stop_condition_fn: fn() -> bool, + setup_fn: TaskSetupFunctionType, + loop_fn: TaskLoopFunctionType, + stop_condition_fn: TaskStopConditionFunctionType, ) { let task = Task { setup_fn, From b3be3de202eb4bae966ba25c472998c1f2e1bf24 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Wed, 6 Mar 2024 21:29:09 +0300 Subject: [PATCH 32/33] Some readme --- .github/workflows/rust.yml | 12 ++++++------ README.md | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 30503de..e5c80d2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,12 +1,12 @@ name: Rust -#on: -# push: -# branches: [ "main" ] -# pull_request: -# branches: [ "main" ] on: - - push + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] +#on: +# - push env: CARGO_TERM_COLOR: always diff --git a/README.md b/README.md index 3b82cf9..f738f9d 100644 --- a/README.md +++ b/README.md @@ -1 +1,23 @@ -# MA-RTOS +# Martos + +Martos is a simple RTOS for developing multiagent realtime systems. +Software for Martos can be written on both Rust (recommended) and C languages. + +In current version it has only primitive task manager and timer counter. + +## Programming on Rust +For writing software on Rust you can use Martos as dependency: +``` +[dependencies] +ma_rtos = ... +``` + +Rust examples for different architecures you can see in examples/rust-examples. + +## Programming on C +For writing software on C you can link your project with Martos static library. +You can get Martos static library from release artifacts. +If you want to build Martos static library yourself, see c-library directory. +It contains static library targets for different architectures. + +C examples for different architecures you can see in examples/c-examples. From f8e888cca9e40c6f7f21ccf0052dea27bb2c3b02 Mon Sep 17 00:00:00 2001 From: Ivan Arkhipov Date: Wed, 6 Mar 2024 21:33:49 +0300 Subject: [PATCH 33/33] Fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f738f9d..4232430 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Martos -Martos is a simple RTOS for developing multiagent realtime systems. +Martos is a simple RTOS for developing multi-agent real-time systems. Software for Martos can be written on both Rust (recommended) and C languages. In current version it has only primitive task manager and timer counter.