forked from ROMEO/fsw-ws
230 lines
5.8 KiB
Rust
230 lines
5.8 KiB
Rust
#![no_std]
|
|
#![feature(never_type)]
|
|
#![feature(c_size_t)] // for ffi, tracking issue [88345]
|
|
//TODO os errors in API calls
|
|
|
|
mod dh;
|
|
pub mod fsrc;
|
|
mod panic;
|
|
|
|
use core::fmt::Write;
|
|
use core::time::Duration;
|
|
|
|
use fsrc::*;
|
|
use osal::{
|
|
queue::{MessageQueue, MessageQueueSender},
|
|
sync::{Mutex, MutexClone, StaticInit, StaticReadOnceLock},
|
|
thread,
|
|
};
|
|
|
|
use crate::{
|
|
dh::EchoHandler,
|
|
fsrc::{
|
|
dh::debug::DeviceHandlerDebugger,
|
|
osal::io::HardwareInterface,
|
|
},
|
|
};
|
|
|
|
static THREAD_INIT: StaticReadOnceLock<
|
|
thread::StaticThread<{ thread::Sizes::MINIMAL_STACK_SIZE + 2024 }>,
|
|
> = StaticReadOnceLock::new(thread::StaticThread::new("Init", u32::MAX));
|
|
|
|
#[no_mangle]
|
|
extern "C" fn rust_main() {
|
|
// we are already in a task (init task started by C), so we can use all APIs safely,
|
|
// but start a new init task anyway to be able to control that task's stack here
|
|
sifln!("Rust startup 🚀");
|
|
THREAD_INIT.take_no_init().unwrap().spawn(init_task);
|
|
// delete self, init task will take over
|
|
thread::current().delete();
|
|
}
|
|
|
|
struct Test {
|
|
a: u8,
|
|
block: Duration,
|
|
mutex: Mutex<u8>,
|
|
}
|
|
|
|
struct Test2 {
|
|
a: u8,
|
|
period: Duration,
|
|
}
|
|
|
|
impl Test {
|
|
fn run(&mut self) {
|
|
sifln!("Test: {} taking mutex", self.a);
|
|
let mut guard = self.mutex.lock();
|
|
let data: u8 = *guard;
|
|
sifln!("Test: {} took mutex, was {}", self.a, data);
|
|
osal::thread::current().delay(self.block);
|
|
*guard = self.a;
|
|
sifln!("Test: {} giving mutex, is now {}", self.a, *guard);
|
|
drop(guard);
|
|
sifln!("Test: {} gave mutex", self.a);
|
|
}
|
|
}
|
|
|
|
impl Test2 {
|
|
pub fn run(&mut self, mutex: MutexClone<u8>, block: Duration) -> ! {
|
|
sifln!(
|
|
"Stack watermark {}",
|
|
osal::thread::current().stack_watermark()
|
|
);
|
|
loop {
|
|
sifln!("Test2: {} taking mutex", self.a);
|
|
let mut guard = mutex.lock();
|
|
let data: u8 = *guard;
|
|
sifln!("{} took mutex, was {}", self.a, data);
|
|
sifln!(
|
|
"Test2: Stack watermark {}",
|
|
osal::thread::current().stack_watermark()
|
|
);
|
|
osal::thread::current().delay(block);
|
|
*guard = self.a;
|
|
sifln!("Test2: {} giving mutex, is now {}", self.a, *guard);
|
|
drop(guard);
|
|
sifln!("Test2: {} gave mutex", self.a);
|
|
osal::thread::current().delay(self.period);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl StaticInit for Test {
|
|
fn static_init(&'static mut self) {
|
|
self.mutex.static_init();
|
|
}
|
|
}
|
|
|
|
impl StaticInit for Test2 {
|
|
fn static_init(&'static mut self) {}
|
|
}
|
|
|
|
static TEST1: StaticReadOnceLock<Test> = StaticReadOnceLock::new(Test {
|
|
a: 1,
|
|
block: Duration::from_millis(1000),
|
|
mutex: Mutex::new(13),
|
|
});
|
|
static THREAD_1: StaticReadOnceLock<
|
|
thread::StaticThreadPeriodic<{ thread::Sizes::MINIMAL_STACK_SIZE + 512 }>,
|
|
> = StaticReadOnceLock::new(thread::StaticThreadPeriodic::new(
|
|
"Thread 1",
|
|
2,
|
|
Duration::from_millis(1000),
|
|
));
|
|
|
|
static TEST2: StaticReadOnceLock<Test2> = StaticReadOnceLock::new(Test2 {
|
|
a: 2,
|
|
period: Duration::from_millis(5000),
|
|
});
|
|
|
|
static THREAD_2: StaticReadOnceLock<
|
|
thread::StaticThread<{ thread::Sizes::MINIMAL_STACK_SIZE + 512 }>,
|
|
> = StaticReadOnceLock::new(thread::StaticThread::new("Thread 2", 2));
|
|
|
|
#[derive(Copy, Clone, Default)]
|
|
pub enum Message {
|
|
OK,
|
|
#[default]
|
|
NONE,
|
|
DATA(u8),
|
|
}
|
|
|
|
struct Receiver {
|
|
queue: MessageQueue<Message, 100>,
|
|
}
|
|
|
|
impl Receiver {
|
|
fn run(&self) {
|
|
let message = self.queue.receive();
|
|
let message = if let Ok(message) = message {
|
|
message
|
|
} else {
|
|
sifln!("receiver: got nothing");
|
|
return;
|
|
};
|
|
|
|
match message {
|
|
Message::OK => {
|
|
sifln!("receiver: ok");
|
|
}
|
|
Message::NONE => {
|
|
sifln!("receiver: NONE");
|
|
}
|
|
Message::DATA(data) => {
|
|
sifln!("receiver: {}", data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl StaticInit for Receiver {
|
|
fn static_init(&'static mut self) {
|
|
self.queue.static_init();
|
|
}
|
|
}
|
|
|
|
struct Sender {
|
|
count: u8,
|
|
}
|
|
|
|
impl Sender {
|
|
fn run(&mut self, queue: MessageQueueSender<Message>) {
|
|
let _ = queue.send(Message::DATA(self.count));
|
|
self.count += 1;
|
|
}
|
|
}
|
|
|
|
static SENDER: StaticReadOnceLock<Sender> = StaticReadOnceLock::new(Sender { count: 0 });
|
|
static RECEIVER: StaticReadOnceLock<Receiver> = StaticReadOnceLock::new(Receiver {
|
|
queue: MessageQueue::new(),
|
|
});
|
|
static THREAD_3: StaticReadOnceLock<
|
|
thread::StaticThreadPeriodic<{ thread::Sizes::MINIMAL_STACK_SIZE + 512 }>,
|
|
> = StaticReadOnceLock::new(thread::StaticThreadPeriodic::new(
|
|
"Thread 3",
|
|
2,
|
|
Duration::from_millis(200),
|
|
));
|
|
|
|
fn init_task() -> ! {
|
|
sifln!("Mission enter");
|
|
|
|
let commands = [dh::Command(0), dh::Command(1), dh::Command(2)];
|
|
let mut debugger = DeviceHandlerDebugger::new(
|
|
EchoHandler { buffer: [0; 10] },
|
|
HardwareInterface::new("debug/uart🚀").unwrap(),
|
|
&commands,
|
|
&[],
|
|
Duration::from_millis(500),
|
|
0.5,
|
|
);
|
|
|
|
debugger.run().unwrap();
|
|
|
|
let test1 = TEST1.take().unwrap();
|
|
let test2 = TEST2.take().unwrap();
|
|
let receiver = RECEIVER.take().unwrap();
|
|
let sender_handle = receiver.queue.sender();
|
|
let clone = sender_handle.clone();
|
|
let sender = SENDER.take_no_init().unwrap();
|
|
|
|
let mutex_copy = test1.mutex.clone();
|
|
let a = Duration::from_millis(10);
|
|
|
|
THREAD_2.take_no_init().unwrap().spawn(move || {
|
|
test2.run(mutex_copy, a);
|
|
});
|
|
|
|
THREAD_1.take_no_init().unwrap().spawn(move || {
|
|
test1.run();
|
|
sender.run(clone);
|
|
});
|
|
|
|
THREAD_3.take_no_init().unwrap().spawn(move || {
|
|
receiver.run();
|
|
});
|
|
|
|
sifln!("=====================Mission delete");
|
|
osal::thread::current().delete();
|
|
}
|