forked from ROMEO/obsw
working on thread safety, preparing for static RTOS
This commit is contained in:
parent
c3be10903b
commit
07d9f52b8d
@ -4,6 +4,29 @@
|
||||
|
||||
// TODO namespace the names
|
||||
|
||||
SemaphoreHandle_t * global_threading_semaphore = NULL;
|
||||
|
||||
uint8_t global_threading_available_c() {
|
||||
if (global_threading_semaphore == NULL) {
|
||||
|
||||
global_threading_semaphore = xSemaphoreCreateBinary();
|
||||
//xSemaphoreGive(global_threading_semaphore);
|
||||
}
|
||||
if (uxSemaphoreGetCount(global_threading_semaphore) == 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void enable_global_threading_c() {
|
||||
xSemaphoreGive(global_threading_semaphore);
|
||||
}
|
||||
|
||||
void disable_global_threading_c() {
|
||||
xSemaphoreTake(global_threading_semaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
const char *get_task_name() { return pcTaskGetName(NULL); }
|
||||
|
||||
void stop_it() { taskENTER_CRITICAL(); }
|
||||
|
@ -39,7 +39,7 @@ pub struct ReferencedDataset<T: HasTypeId + Copy> {
|
||||
mutex: Option<mutex::RawMutex>,
|
||||
}
|
||||
|
||||
impl<T: HasTypeId + Copy> DataSetIF for OwnedDataset<T> {
|
||||
impl<T: HasTypeId + Copy + Default> DataSetIF for OwnedDataset<T> {
|
||||
fn get_type_id(&self) -> TypeId {
|
||||
self.actual_data.get_type_id()
|
||||
}
|
||||
@ -49,6 +49,7 @@ impl<T: HasTypeId + Copy> DataSetIF for OwnedDataset<T> {
|
||||
}
|
||||
|
||||
fn get_mutex(&self) -> mutex::RawMutex {
|
||||
self.initialize();
|
||||
return self.mutex;
|
||||
}
|
||||
}
|
||||
@ -77,6 +78,10 @@ impl<T: HasTypeId + Copy + Default> OwnedDataset<T> {
|
||||
};
|
||||
self.actual_data = data;
|
||||
}
|
||||
|
||||
fn initialize(&mut self) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasTypeId + Copy + Default> ReferencedDataset<T> {
|
||||
|
@ -1,10 +1,7 @@
|
||||
use super::osal;
|
||||
|
||||
// We allow copy because we protext our pointer via a global mutex
|
||||
// when using static allocation (which is TBCoded)
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RawMutex {
|
||||
handle: *const core::ffi::c_void,
|
||||
handle: Option<*const core::ffi::c_void>
|
||||
}
|
||||
|
||||
pub struct RawMutexGuard {
|
||||
@ -22,23 +19,50 @@ impl Drop for RawMutexGuard {
|
||||
// or maybe lazy later on, TBD if lazy is needed or we can guarantee init to be called
|
||||
impl RawMutex {
|
||||
pub fn new() -> Self {
|
||||
let handle = unsafe {osal::create_mutex()};
|
||||
Self {
|
||||
handle: handle
|
||||
handle: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> Self {
|
||||
let mut_self = self as *const Self as *mut Self; //oh look, a C developer wrote this
|
||||
unsafe { (*mut_self).initialize() }; //TODO this might be safe (we are in init), but does not look very good
|
||||
Self {
|
||||
handle: self.handle
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&self) -> Result<RawMutexGuard,()> {
|
||||
match unsafe {osal::take_mutex(self.handle)} {
|
||||
1 => Ok(RawMutexGuard { handle: self.handle }),
|
||||
osal::check_global_threading_available();
|
||||
let handle = match self.handle {
|
||||
None => return Err(()), //TODO plan was that this failes silently -> implement an empty mutex guard?
|
||||
Some(handle) => handle
|
||||
};
|
||||
match unsafe {osal::take_mutex(handle)} {
|
||||
1 => Ok(RawMutexGuard { handle: handle }),
|
||||
_ => Err(()) //TODO error code
|
||||
}
|
||||
}
|
||||
|
||||
// Mutex guard takes care of this in its drop
|
||||
// Do not offer this in API to avoid duplicate give
|
||||
// pub fn give(&self) -> Result<(),()> {
|
||||
// match unsafe {osal::give_mutex(self.handle)} {
|
||||
// osal::check_global_threading_available();
|
||||
// let handle = match self.handle {
|
||||
// None => return Ok(()),
|
||||
// Some(handle) => handle
|
||||
// };
|
||||
// match unsafe {osal::give_mutex(handle)} {
|
||||
// 1 => Ok(()),
|
||||
// _ => Err(()) //TODO error code
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn initialize(&mut self) {
|
||||
let handle = unsafe {osal::create_mutex()};
|
||||
if handle == 0 as *const core::ffi::c_void {
|
||||
panic!("Could not create mutex")
|
||||
}
|
||||
self.handle = Some(handle);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void);
|
||||
|
||||
//TODO verify uXX == uintXX_t
|
||||
//TODO safe API
|
||||
|
||||
extern "C" {
|
||||
pub fn outbyte(c: u8);
|
||||
@ -30,4 +31,26 @@ extern "C" {
|
||||
pub fn take_mutex(mutex: *const core::ffi::c_void) -> u8;
|
||||
pub fn give_mutex(mutex: *const core::ffi::c_void) -> u8;
|
||||
|
||||
fn global_threading_available_c() -> u8;
|
||||
fn enable_global_threading_c();
|
||||
fn disable_global_threading_c();
|
||||
|
||||
}
|
||||
|
||||
pub fn global_threading_available() -> bool {
|
||||
unsafe{global_threading_available_c() == 1}
|
||||
}
|
||||
|
||||
pub fn check_global_threading_available() {
|
||||
if !global_threading_available() {
|
||||
panic!("using queue outside of threading environment")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_global_threading(){
|
||||
unsafe{enable_global_threading_c()};
|
||||
}
|
||||
|
||||
pub fn disable_global_threading(){
|
||||
unsafe{disable_global_threading_c()};
|
||||
}
|
@ -1,46 +1,63 @@
|
||||
pub struct MessageQueue {
|
||||
queue_id: *const core::ffi::c_void,
|
||||
use crate::osal;
|
||||
|
||||
pub struct MessageQueue<const DEPTH: usize> {
|
||||
queue_data: [Message; DEPTH],
|
||||
queue_id: Option<*const core::ffi::c_void>,
|
||||
}
|
||||
|
||||
pub struct MessageQueueSender {
|
||||
queue_id: Option<*const core::ffi::c_void>,
|
||||
}
|
||||
|
||||
impl MessageQueue {
|
||||
pub fn new(depth: usize) -> Self {
|
||||
unsafe {
|
||||
//TODO check cast of depth
|
||||
let cast_depth: u32 = u32::try_from(depth).unwrap(); //TODO check these
|
||||
let element_size: u32 = u32::try_from(core::mem::size_of::<Message>()).unwrap();
|
||||
let queue_id = crate::fsrc::osal::create_queue(cast_depth, element_size);
|
||||
|
||||
if queue_id == 0 as *mut core::ffi::c_void {
|
||||
panic!("could not create Queue");
|
||||
}
|
||||
|
||||
Self { queue_id: queue_id }
|
||||
impl<const DEPTH: usize> MessageQueue<DEPTH> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
queue_data: [Message::default(); DEPTH],
|
||||
queue_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> MessageQueueSender {
|
||||
let instance: MessageQueueSender = MessageQueueSender {
|
||||
queue_id: Some(self.queue_id),
|
||||
pub fn receive(&self) -> Option<Message> {
|
||||
osal::check_global_threading_available();
|
||||
let actual_id = match self.queue_id {
|
||||
None => return None,
|
||||
Some(id) => id,
|
||||
};
|
||||
instance
|
||||
}
|
||||
|
||||
pub fn receive(&self) -> Result<Message, ()> {
|
||||
let mut message: Message = Message::default();
|
||||
let res: u8;
|
||||
unsafe {
|
||||
//message = core::mem::MaybeUninit::zeroed().assume_init(); // We only return it if the queue received something
|
||||
let message_pointer: *mut core::ffi::c_void = &mut message as *mut _ as *mut core::ffi::c_void;
|
||||
res = crate::fsrc::osal::queue_receive(self.queue_id, message_pointer);
|
||||
let message_pointer: *mut core::ffi::c_void =
|
||||
&mut message as *mut _ as *mut core::ffi::c_void;
|
||||
res = osal::queue_receive(actual_id, message_pointer);
|
||||
}
|
||||
if res == 1 {
|
||||
Ok(message)
|
||||
Some(message)
|
||||
} else {
|
||||
Err(())
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize(&mut self) {
|
||||
if self.queue_id != None {
|
||||
return;
|
||||
}
|
||||
let cast_depth: u32 = u32::try_from(DEPTH).unwrap(); //TODO check these
|
||||
let element_size: u32 = u32::try_from(core::mem::size_of::<Message>()).unwrap();
|
||||
let queue_id = unsafe { osal::create_queue(cast_depth, element_size) };
|
||||
|
||||
if queue_id == 0 as *mut core::ffi::c_void {
|
||||
panic!("could not create Queue");
|
||||
}
|
||||
self.queue_id = Some(queue_id);
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> MessageQueueSender {
|
||||
let mut_self = self as *const Self as *mut Self; //oh look, a C developer wrote this
|
||||
unsafe { (*mut_self).initialize() }; //TODO this might be safe (we are in init), but does not look very good
|
||||
let queue_id = self.queue_id.expect("Queue uninitialized");
|
||||
MessageQueueSender {
|
||||
queue_id: Some(queue_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,11 +68,16 @@ impl MessageQueueSender {
|
||||
}
|
||||
|
||||
pub fn send(&self, message: Message) -> Result<(), ()> {
|
||||
let queue_id = self.queue_id.expect("unitialized Message Queue");
|
||||
osal::check_global_threading_available();
|
||||
let queue_id = match self.queue_id {
|
||||
None => return Err(()),
|
||||
Some(id) => id,
|
||||
};
|
||||
let res: u8;
|
||||
unsafe {
|
||||
let message_pointer: *const core::ffi::c_void = &message as *const _ as *const core::ffi::c_void;
|
||||
res = crate::fsrc::osal::queue_send(queue_id, message_pointer);
|
||||
let message_pointer: *const core::ffi::c_void =
|
||||
&message as *const _ as *const core::ffi::c_void;
|
||||
res = osal::queue_send(queue_id, message_pointer);
|
||||
}
|
||||
if res == 1 {
|
||||
Ok(())
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![no_std]
|
||||
|
||||
//TODO look into using core::ffi (some types do not seem to work)
|
||||
//TODO os errors in API calls
|
||||
//TODO look into a pattern for late initialized stuff, currently using Option (can we make it compile time safe?)
|
||||
|
||||
@ -60,7 +59,7 @@ impl datasets::HasTypeId for HandlerData {}
|
||||
|
||||
struct Handler {
|
||||
id: objectmanager::ObjectId,
|
||||
command_queue: queues::MessageQueue,
|
||||
command_queue: queues::MessageQueue<10>,
|
||||
data: datasets::OwnedDataset<HandlerData>
|
||||
}
|
||||
|
||||
@ -94,8 +93,8 @@ impl tasks::ExecutableObjectIF for Handler {
|
||||
sifln!("Handler {} performs", self.id);
|
||||
let result = self.command_queue.receive();
|
||||
match result {
|
||||
Ok(message) => self.handle_message(message),
|
||||
Err(_) => {
|
||||
Some(message) => self.handle_message(message),
|
||||
None => {
|
||||
sifln!("Handler {} got nothing", self.id);
|
||||
}
|
||||
}
|
||||
@ -149,8 +148,9 @@ impl DatapoolOwnerIF for HandlerSender {}
|
||||
|
||||
impl SystemObjectIF for HandlerSender {
|
||||
fn get_command_queue(&self) -> crate::fsrc::queues::MessageQueueSender {
|
||||
queues::MessageQueueSender::new()
|
||||
queues::MessageQueueSender::new() //TODO
|
||||
}
|
||||
|
||||
fn get_id(&self) -> objectmanager::ObjectId {
|
||||
self.id
|
||||
}
|
||||
@ -173,7 +173,7 @@ fn mission() {
|
||||
|
||||
let mut h1 = Handler {
|
||||
id: 1,
|
||||
command_queue: queues::MessageQueue::new(5),
|
||||
command_queue: queues::MessageQueue::new(),
|
||||
data: datasets::OwnedDataset::new()
|
||||
};
|
||||
let mut h2 = HandlerSender {
|
||||
|
Loading…
x
Reference in New Issue
Block a user