From e585ecafcc253f9a47bc2c986be29cde2c173875 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 11 Dec 2023 22:44:06 +0100 Subject: [PATCH] adding mutexes, cleaning up types --- bsp_z7/ps7_cortexa9_0/include/xil_printf.h | 2 +- .../libsrc/standalone/src/outbyte.c | 4 +- mission/freeRTOS_rust_helper.c | 31 ++++++++++++- mission_rust/Cargo.lock | 9 ---- mission_rust/Cargo.toml | 1 - mission_rust/src/fsrc/datasets/mod.rs | 42 ++++++++++++++---- mission_rust/src/fsrc/mod.rs | 5 ++- mission_rust/src/fsrc/mutex.rs | 44 +++++++++++++++++++ mission_rust/src/fsrc/osal/mod.rs | 28 +++++++----- mission_rust/src/fsrc/queues/mod.rs | 31 ++++++------- mission_rust/src/fsrc/sif.rs | 2 + mission_rust/src/fsrc/tasks/mod.rs | 34 +++++++------- mission_rust/src/lib.rs | 2 +- 13 files changed, 165 insertions(+), 70 deletions(-) create mode 100644 mission_rust/src/fsrc/mutex.rs diff --git a/bsp_z7/ps7_cortexa9_0/include/xil_printf.h b/bsp_z7/ps7_cortexa9_0/include/xil_printf.h index 062ad6b..4906e2a 100644 --- a/bsp_z7/ps7_cortexa9_0/include/xil_printf.h +++ b/bsp_z7/ps7_cortexa9_0/include/xil_printf.h @@ -43,7 +43,7 @@ typedef s32 (*func_ptr)(int c); void xil_printf( const char8 *ctrl1, ...); void xil_vprintf(const char8 *ctrl1, va_list argp); void print( const char8 *ptr); -extern void outbyte (char c); +extern void outbyte (uint8_t c); extern char inbyte(void); #ifdef __cplusplus diff --git a/bsp_z7/ps7_cortexa9_0/libsrc/standalone/src/outbyte.c b/bsp_z7/ps7_cortexa9_0/libsrc/standalone/src/outbyte.c index db60e6d..1080862 100644 --- a/bsp_z7/ps7_cortexa9_0/libsrc/standalone/src/outbyte.c +++ b/bsp_z7/ps7_cortexa9_0/libsrc/standalone/src/outbyte.c @@ -8,12 +8,12 @@ #ifdef __cplusplus extern "C" { #endif -void outbyte(char c); +void outbyte(uint8_t c); #ifdef __cplusplus } #endif -void outbyte(char c) { +void outbyte(uint8_t c) { XUartPs_SendByte(STDOUT_BASEADDRESS, c); } diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index 7fc3fbb..21b5c51 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -10,7 +10,8 @@ void stop_it() { taskENTER_CRITICAL(); } // TODO return some error code? void *create_task(TaskFunction_t taskFunction, void *parameter, - size_t stack_size) { + uint32_t stack_size) { + //TODO verify uint32_t vs configSTACK_DEPTH_TYPE TaskHandle_t newTask; BaseType_t result = xTaskCreate(taskFunction, "rust", stack_size, parameter, 4, &newTask); @@ -22,6 +23,7 @@ void *create_task(TaskFunction_t taskFunction, void *parameter, } void task_delay(uint32_t milliseconds) { + //TODO verify uint32_t vs TickType_t vTaskDelay(pdMS_TO_TICKS(milliseconds)); } @@ -29,7 +31,8 @@ void delete_task(void * task){ vTaskSuspend(task); //we can not use vDeleteTask as it would free the allocated memory which is forbidden using heap1 (which we use) } -void *create_queue(size_t length, size_t element_size) { +void *create_queue(uint32_t length, uint32_t element_size) { + //TODO verify uint32_t vs UBaseType_t QueueHandle_t newQueue = xQueueCreate(length, element_size); return newQueue; } @@ -48,4 +51,28 @@ uint8_t queue_send(void *queue, void *message) { } else { return 0; } +} + +void *create_mutex() { + return xSemaphoreCreateRecursiveMutex(); +} + +uint8_t take_mutex(void * handle) { + // TODO check if global semaphore is free (ie, we are doing multitasking) + // if not, pointers are invalid, bail out + if (xSemaphoreTakeRecursive(handle, portMAX_DELAY) == pdPASS) { + return 1; + } else { + return 0; + } +} + +uint8_t give_mutex(void * handle) { + // TODO check if global semaphore is free (ie, we are doing multitasking) + // if not, pointers are invalid, bail out + if (xSemaphoreGiveRecursive(handle) == pdPASS) { + return 1; + } else { + return 0; + } } \ No newline at end of file diff --git a/mission_rust/Cargo.lock b/mission_rust/Cargo.lock index 4427a22..c0a15a2 100644 --- a/mission_rust/Cargo.lock +++ b/mission_rust/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "mission_rust" version = "0.1.0" -dependencies = [ - "cty", -] diff --git a/mission_rust/Cargo.toml b/mission_rust/Cargo.toml index a625263..5f705b3 100644 --- a/mission_rust/Cargo.toml +++ b/mission_rust/Cargo.toml @@ -9,4 +9,3 @@ crate-type = ["staticlib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cty = "0.2.2" diff --git a/mission_rust/src/fsrc/datasets/mod.rs b/mission_rust/src/fsrc/datasets/mod.rs index 8883b04..a2304be 100644 --- a/mission_rust/src/fsrc/datasets/mod.rs +++ b/mission_rust/src/fsrc/datasets/mod.rs @@ -1,3 +1,4 @@ +use super::mutex; use super::objectmanager::SystemObjectIF; #[derive(Copy, Clone, PartialEq)] @@ -24,16 +25,18 @@ pub trait DatapoolOwnerIF { pub trait DataSetIF { fn get_type_id(&self) -> TypeId; fn get_actual_data(&self) -> &dyn Reflection; - //fn get_mutex_handle(&self) -> TODO + fn get_mutex(&self) -> mutex::RawMutex; } pub struct OwnedDataset { actual_data: T, + mutex: mutex::RawMutex, } pub struct ReferencedDataset { //we use a pointer here to avoid lifetimes actual_data: Option<*const T>, + mutex: Option, } impl DataSetIF for OwnedDataset { @@ -44,33 +47,54 @@ impl DataSetIF for OwnedDataset { fn get_actual_data(&self) -> &dyn Reflection { &self.actual_data } + + fn get_mutex(&self) -> mutex::RawMutex { + return self.mutex; + } } impl OwnedDataset { pub fn new() -> OwnedDataset { OwnedDataset:: { actual_data: T::default(), + mutex: mutex::RawMutex::new(), } } - pub fn read(&mut self) -> T { - //mutex - self.actual_data + pub fn read(&mut self) -> Result { + let _mutex_guard = match self.mutex.take() { + Err(()) => return Err(()), + Ok(guard) => guard, + }; + Ok(self.actual_data) } + //TODO do we want to know if it fails? pub fn commit(&mut self, data: T) { - //mutex + let _mutex_guard = match self.mutex.take() { + Err(()) => return, + Ok(guard) => guard, + }; self.actual_data = data; } } impl ReferencedDataset { pub fn new() -> ReferencedDataset { - ReferencedDataset:: { actual_data: None } + ReferencedDataset:: { + actual_data: None, + mutex: None, + } } - + pub fn read(&mut self) -> Result { - //mutex + let _mutex_guard = match self.mutex { + None => return Err(()), + Some(mutex) => match mutex.take() { + Err(()) => return Err(()), + Ok(guard) => guard, + }, + }; match self.actual_data { None => Err(()), Some(data) => Ok(unsafe { *data }), @@ -92,7 +116,7 @@ impl ReferencedDataset { //pointer cast is safe because we checked the type_id //getting pointer to avoid lifetime check self.actual_data = Some(other_set.get_actual_data() as *const dyn Reflection as *const T); - //self.mutex = other.mutex + self.mutex = Some(other_set.get_mutex()); Ok(()) } } diff --git a/mission_rust/src/fsrc/mod.rs b/mission_rust/src/fsrc/mod.rs index cc5c015..f56e588 100644 --- a/mission_rust/src/fsrc/mod.rs +++ b/mission_rust/src/fsrc/mod.rs @@ -1,6 +1,9 @@ +//TODO control visibility of internal structs + pub mod sif; pub mod queues; pub mod osal; pub mod tasks; pub mod objectmanager; -pub mod datasets; \ No newline at end of file +pub mod datasets; +mod mutex; \ No newline at end of file diff --git a/mission_rust/src/fsrc/mutex.rs b/mission_rust/src/fsrc/mutex.rs new file mode 100644 index 0000000..c1e926b --- /dev/null +++ b/mission_rust/src/fsrc/mutex.rs @@ -0,0 +1,44 @@ +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, +} + +pub struct RawMutexGuard { + handle: *const core::ffi::c_void, +} + +impl Drop for RawMutexGuard { + fn drop(&mut self) { + //TODO do we need some check here? + unsafe{osal::give_mutex(self.handle)}; + } +} + +//TODO for non allocating, keep handle as option, to be set either in an initialize() call +// 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 + } + } + + pub fn take(&self) -> Result { + match unsafe {osal::take_mutex(self.handle)} { + 1 => Ok(RawMutexGuard { handle: self.handle }), + _ => Err(()) //TODO error code + } + } + + // pub fn give(&self) -> Result<(),()> { + // match unsafe {osal::give_mutex(self.handle)} { + // 1 => Ok(()), + // _ => Err(()) //TODO error code + // } + // } +} \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal/mod.rs b/mission_rust/src/fsrc/osal/mod.rs index 241de2e..3710125 100644 --- a/mission_rust/src/fsrc/osal/mod.rs +++ b/mission_rust/src/fsrc/osal/mod.rs @@ -1,25 +1,33 @@ -type TaskFunction = unsafe extern "C" fn(*mut cty::c_void); +type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void); + +//TODO verify uXX == uintXX_t extern "C" { - pub fn outbyte(c: cty::c_char); + pub fn outbyte(c: u8); //void *create_task(TaskFunction_t taskFunction, void *parameter, size_t stack_size) pub fn create_task( taskFunction: TaskFunction, - parameter: *const cty::c_void, - stack_size: cty::size_t, - ) -> *const cty::c_void; + parameter: *const core::ffi::c_void, + stack_size: u32, + ) -> *const core::ffi::c_void; pub fn get_task_name() -> *const core::ffi::c_char; pub fn stop_it(); - pub fn delete_task(handle: *const cty::c_void); + pub fn delete_task(handle: *const core::ffi::c_void); - pub fn task_delay(milliseconds: cty::uint32_t); + pub fn task_delay(milliseconds: u32); //void *create_queue(size_t length, size_t element_size) - pub fn create_queue(length: cty::size_t, element_size: cty::size_t) -> *const cty::c_void; + pub fn create_queue(length: u32, element_size: u32) -> *const core::ffi::c_void; + + pub fn queue_receive(queue: *const core::ffi::c_void, message: *const core::ffi::c_void) -> u8; + pub fn queue_send(queue: *const core::ffi::c_void, message: *const core::ffi::c_void) -> u8; + + pub fn create_mutex() -> *const core::ffi::c_void; + + pub fn take_mutex(mutex: *const core::ffi::c_void) -> u8; + pub fn give_mutex(mutex: *const core::ffi::c_void) -> u8; - pub fn queue_receive(queue: *const cty::c_void, message: *const cty::c_void) -> cty::uint8_t; - pub fn queue_send(queue: *const cty::c_void, message: *const cty::c_void) -> cty::uint8_t; } \ No newline at end of file diff --git a/mission_rust/src/fsrc/queues/mod.rs b/mission_rust/src/fsrc/queues/mod.rs index 950a567..890d6b6 100644 --- a/mission_rust/src/fsrc/queues/mod.rs +++ b/mission_rust/src/fsrc/queues/mod.rs @@ -1,25 +1,24 @@ pub struct MessageQueue { - queue_id: *const cty::c_void, + queue_id: *const core::ffi::c_void, } pub struct MessageQueueSender { - queue_id: Option<*const cty::c_void>, + queue_id: Option<*const core::ffi::c_void>, } impl MessageQueue { pub fn new(depth: usize) -> Self { - let mut instance: Self; unsafe { - instance = Self { - queue_id: 0 as *const cty::c_void, - }; //TODO check cast of depth - instance.queue_id = crate::fsrc::osal::create_queue(depth, core::mem::size_of::()); + let cast_depth: u32 = u32::try_from(depth).unwrap(); //TODO check these + let element_size: u32 = u32::try_from(core::mem::size_of::()).unwrap(); + let queue_id = crate::fsrc::osal::create_queue(cast_depth, element_size); - if instance.queue_id == 0 as *mut cty::c_void { + if queue_id == 0 as *mut core::ffi::c_void { panic!("could not create Queue"); } - instance + + Self { queue_id: queue_id } } } @@ -32,10 +31,10 @@ impl MessageQueue { pub fn receive(&self) -> Result { let mut message: Message = Message::default(); - let res: cty::uint8_t; + let res: u8; unsafe { //message = core::mem::MaybeUninit::zeroed().assume_init(); // We only return it if the queue received something - let message_pointer: *mut cty::c_void = &mut message as *mut _ as *mut cty::c_void; + 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); } if res == 1 { @@ -48,16 +47,14 @@ impl MessageQueue { impl MessageQueueSender { pub fn new() -> Self { - Self { - queue_id: None, - } + Self { queue_id: None } } pub fn send(&self, message: Message) -> Result<(), ()> { let queue_id = self.queue_id.expect("unitialized Message Queue"); - let res: cty::uint8_t; + let res: u8; unsafe { - let message_pointer: *const cty::c_void = &message as *const _ as *const cty::c_void; + 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); } if res == 1 { @@ -80,4 +77,4 @@ pub enum Message { #[default] FAILED, DATA(GenericMessageData), -} \ No newline at end of file +} diff --git a/mission_rust/src/fsrc/sif.rs b/mission_rust/src/fsrc/sif.rs index a1801a3..f56438b 100644 --- a/mission_rust/src/fsrc/sif.rs +++ b/mission_rust/src/fsrc/sif.rs @@ -1,3 +1,5 @@ +// TODO this is platform specific + pub struct Outbytes {} use core::fmt::{Error, Write}; diff --git a/mission_rust/src/fsrc/tasks/mod.rs b/mission_rust/src/fsrc/tasks/mod.rs index 253dfb0..936a43c 100644 --- a/mission_rust/src/fsrc/tasks/mod.rs +++ b/mission_rust/src/fsrc/tasks/mod.rs @@ -3,7 +3,7 @@ use core::slice; use super::objectmanager::ObjectManager; #[no_mangle] -extern "C" fn task_entry(task_object: *mut cty::c_void) { +extern "C" fn task_entry(task_object: *mut core::ffi::c_void) { let task: &mut dyn TaskIF; unsafe { let pointer = task_object as *mut PeriodicTask; @@ -18,29 +18,29 @@ pub trait ExecutableObjectIF { pub trait TaskIF<'a> { fn run(&mut self); - fn get_stack_size(&self) -> cty::size_t; - fn set_handle(&mut self, task_handle: *const cty::c_void); - fn get_handle(&self) -> *const cty::c_void; + fn get_stack_size(&self) -> u32; + fn set_handle(&mut self, task_handle: *const core::ffi::c_void); + fn get_handle(&self) -> *const core::ffi::c_void; fn get_objects(&'a self) -> &'a [&'a mut dyn crate::objectmanager::SystemObjectIF]; fn initialize(&mut self, object_manager: &dyn ObjectManager) -> Result<(), ()>; } pub struct PeriodicTask<'a> { - pub stack_size: cty::size_t, //TODO generic type and safety - pub task_handle: *const cty::c_void, - pub period: usize, + pub stack_size: u32, //TODO generic type and safety + pub task_handle: *const core::ffi::c_void, + pub period: u32, pub task_objects: &'a mut [&'a mut dyn crate::objectmanager::SystemObjectIF], } impl<'a> PeriodicTask<'a> { pub fn new( objects: &'a mut [&'a mut dyn crate::objectmanager::SystemObjectIF], - stack_size: usize, - period: usize, + stack_size: u32, + period: u32, ) -> PeriodicTask<'a> { let instance: PeriodicTask<'a> = Self { stack_size: stack_size, - task_handle: 0 as *const cty::c_void, + task_handle: 0 as *const core::ffi::c_void, period: period, task_objects: objects, }; @@ -56,17 +56,17 @@ impl<'a> TaskIF<'a> for PeriodicTask<'a> { } //TODO make this exact unsafe { - crate::fsrc::osal::task_delay(self.period as cty::uint32_t); //TODO type of delay should be generic but safe (cap to max in C) + crate::fsrc::osal::task_delay(self.period); //TODO type of delay should be generic but safe (cap to max in C) } } } - fn get_stack_size(&self) -> cty::size_t { + fn get_stack_size(&self) -> u32 { self.stack_size } - fn set_handle(&mut self, task_handle: *const cty::c_void) { + fn set_handle(&mut self, task_handle: *const core::ffi::c_void) { self.task_handle = task_handle; } - fn get_handle(&self) -> *const cty::c_void { + fn get_handle(&self) -> *const core::ffi::c_void { self.task_handle } fn get_objects(&'a self) -> &'a [&'a mut dyn crate::objectmanager::SystemObjectIF] { @@ -104,13 +104,13 @@ impl<'a> TaskExecutor<'a> { // to our own lifetime and destroy the task when we get dropped // this way, the reference is guaranteed to be valid over our // lifetime while the task is deleted at the end of our lifetime - let task_pointer: *const cty::c_void = *task as *mut _ as *const cty::c_void; //TODO this does work without the "*" in front of the task -> Why?? + let task_pointer: *const core::ffi::c_void = *task as *mut _ as *const core::ffi::c_void; //TODO this does work without the "*" in front of the task -> Why?? let handle; unsafe { handle = - crate::fsrc::osal::create_task(task_entry, task_pointer, task.get_stack_size()); + crate::fsrc::osal::create_task(task_entry, task_pointer, u32::try_from(task.get_stack_size()).unwrap()); } - if handle == 0 as *mut cty::c_void { + if handle == 0 as *mut core::ffi::c_void { panic!("could not create Task"); } else { task.set_handle(handle); diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 94794c7..4a56dbd 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -192,7 +192,7 @@ fn mission() { task_objects: &mut [&mut h2], stack_size: 512, period: 400, - task_handle: 0 as *const cty::c_void, + task_handle: 0 as *const core::ffi::c_void, }; let mut task_executor = tasks::TaskExecutor {