adding mutexes, cleaning up types

This commit is contained in:
Ulrich Mohr 2023-12-11 22:44:06 +01:00
parent bae91a61d4
commit e585ecafcc
13 changed files with 165 additions and 70 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
@ -49,3 +52,27 @@ uint8_t queue_send(void *queue, void *message) {
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;
}
}

View File

@ -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",
]

View File

@ -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"

View File

@ -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<T: Reflection + Copy> {
actual_data: T,
mutex: mutex::RawMutex,
}
pub struct ReferencedDataset<T: Reflection + Copy> {
//we use a pointer here to avoid lifetimes
actual_data: Option<*const T>,
mutex: Option<mutex::RawMutex>,
}
impl<T: Reflection + Copy> DataSetIF for OwnedDataset<T> {
@ -44,33 +47,54 @@ impl<T: Reflection + Copy> DataSetIF for OwnedDataset<T> {
fn get_actual_data(&self) -> &dyn Reflection {
&self.actual_data
}
fn get_mutex(&self) -> mutex::RawMutex {
return self.mutex;
}
}
impl<T: Reflection + Copy + Default> OwnedDataset<T> {
pub fn new() -> OwnedDataset<T> {
OwnedDataset::<T> {
actual_data: T::default(),
mutex: mutex::RawMutex::new(),
}
}
pub fn read(&mut self) -> T {
//mutex
self.actual_data
pub fn read(&mut self) -> Result<T, ()> {
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<T: Reflection + Copy + Default> ReferencedDataset<T> {
pub fn new() -> ReferencedDataset<T> {
ReferencedDataset::<T> { actual_data: None }
ReferencedDataset::<T> {
actual_data: None,
mutex: None,
}
}
pub fn read(&mut self) -> Result<T, ()> {
//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<T: Reflection + Copy + Default> ReferencedDataset<T> {
//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(())
}
}

View File

@ -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;
mod mutex;

View File

@ -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<RawMutexGuard,()> {
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
// }
// }
}

View File

@ -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;
}

View File

@ -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::<Message>());
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 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<Message, ()> {
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 {

View File

@ -1,3 +1,5 @@
// TODO this is platform specific
pub struct Outbytes {}
use core::fmt::{Error, Write};

View File

@ -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);

View File

@ -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 {