From 6c937fa8b0155ccde7f863ee3cd532d0da49dbe5 Mon Sep 17 00:00:00 2001 From: paul nehlich Date: Wed, 7 May 2025 18:03:10 +0200 Subject: [PATCH 01/19] slightly less unsafe take --- mission/freeRTOS_rust_helper.c | 2 +- .../src/fsrc/osal/sync/static_read_once_lock.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index c3814a8..08bd8d3 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -241,7 +241,7 @@ uint8_t freertos_simple_once(uint8_t *once_data) { // TODO assert global_once_mutex != NULL uint8_t result = 0; - + // Todo: Replace Mutex with critical section // This function is basically a flag stored in once_data, protected by the // global_once_mutex if (xSemaphoreTakeRecursive(global_once_mutex, portMAX_DELAY) != pdTRUE) { diff --git a/mission_rust/src/fsrc/osal/sync/static_read_once_lock.rs b/mission_rust/src/fsrc/osal/sync/static_read_once_lock.rs index bf9b38a..c72127e 100644 --- a/mission_rust/src/fsrc/osal/sync/static_read_once_lock.rs +++ b/mission_rust/src/fsrc/osal/sync/static_read_once_lock.rs @@ -26,12 +26,16 @@ impl StaticReadOnceLock { impl StaticReadOnceLock { pub fn take(&'static self) -> Option<&'static mut T> { - let inner = unsafe{&mut *self.inner.get()}; - inner.static_init(); - // Re-Borrow inner. - // TODO Is unsafe by leaking static references via static_init() - self.take_no_init() + + if self.once.once() { + // SAFE: Prozected by once + let inner: &mut T = unsafe{&mut *self.inner.get()}; + inner.static_init(); + // Re-Borrow inner. + // TODO Is unsafe by leaking static references via static_init() + return Some(unsafe{&mut *self.inner.get()}) + } + None } } - unsafe impl Sync for StaticReadOnceLock {} \ No newline at end of file From 20ca676e632eb0ee5a8dd0cb7cb8a9216852533f Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 6 May 2025 11:34:32 +0200 Subject: [PATCH 02/19] git version at startup --- common/CMakeLists.txt | 4 +++- common/git_version/CMakeLists.txt | 17 +++++++++++++++++ common/git_version/get_version.cmake | 3 +++ common/git_version/git_version.h.in | 4 ++++ mission/mission.c | 13 +++++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 common/git_version/CMakeLists.txt create mode 100644 common/git_version/get_version.cmake create mode 100644 common/git_version/git_version.h.in diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index ca7b46a..06a623e 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,2 +1,4 @@ # TODO directly referencing bsp is not correct -target_include_directories(bsp PUBLIC include) \ No newline at end of file +target_include_directories(bsp PUBLIC include) + +add_subdirectory(git_version) \ No newline at end of file diff --git a/common/git_version/CMakeLists.txt b/common/git_version/CMakeLists.txt new file mode 100644 index 0000000..4d5bee1 --- /dev/null +++ b/common/git_version/CMakeLists.txt @@ -0,0 +1,17 @@ +find_package(Git) +if(Git_FOUND) + message("Git found: ${GIT_EXECUTABLE}") + + add_custom_target( get_git_version + COMMAND ${CMAKE_COMMAND} + -D GIT_EXECUTABLE=${GIT_EXECUTABLE} + -D INPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/git_version.h.in + -D OUTPUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/git_version.h + -P ${CMAKE_CURRENT_SOURCE_DIR}/get_version.cmake + ) + + add_dependencies(${OBSW_NAME} get_git_version) + target_include_directories(${OBSW_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +else() + message( FATAL_ERROR "Building outside of git is not supported yet") +endif() \ No newline at end of file diff --git a/common/git_version/get_version.cmake b/common/git_version/get_version.cmake new file mode 100644 index 0000000..f8e96db --- /dev/null +++ b/common/git_version/get_version.cmake @@ -0,0 +1,3 @@ +execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --dirty OUTPUT_VARIABLE GIT_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE) +string(TIMESTAMP BUILD_TIME_STRING UTC) +configure_file(${INPUT_FILE} ${OUTPUT_FILE}) \ No newline at end of file diff --git a/common/git_version/git_version.h.in b/common/git_version/git_version.h.in new file mode 100644 index 0000000..f0dbf83 --- /dev/null +++ b/common/git_version/git_version.h.in @@ -0,0 +1,4 @@ +#pragma once + +#cmakedefine GIT_VERSION_STRING "@GIT_VERSION_STRING@" +#cmakedefine BUILD_TIME_STRING "@BUILD_TIME_STRING@" \ No newline at end of file diff --git a/mission/mission.c b/mission/mission.c index 2deb2f9..0354a2d 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -10,6 +10,8 @@ #include #include +#include + void rust_main(); @@ -41,12 +43,23 @@ void test_hardware() { // to be implemented by bsp (do not return from it!) void done(); + void init_task(void* _) { rust_main(_); } +#define STARTUP_MESSAGE1 "\nROMEO embedded obsw\nRelease: " +#define STARTUP_MESSAGE2 "\nBuild time: " + + void mission(void) { + write(1, STARTUP_MESSAGE1, strlen(STARTUP_MESSAGE1)); + write(1, GIT_VERSION_STRING, strlen(GIT_VERSION_STRING)); + write(1, STARTUP_MESSAGE2, strlen(STARTUP_MESSAGE2)); + write(1, BUILD_TIME_STRING, strlen(BUILD_TIME_STRING)); + write(1, "\n", 1); + test_hardware(); From 243fd19827f841220af790e7dae4332fa3567337 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 12 Aug 2025 14:34:45 +0200 Subject: [PATCH 03/19] cleanup --- .gitignore | 3 ++- mission/mission.c | 7 ++++--- mission_rust/src/fsrc/osal/sync/mutex.rs | 7 ++++--- mission_rust/src/fsrc/osal/sync/mutex_raw.rs | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 8018673..4903d8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .vscode __pycache__/* **/__pycache__/* -*.elf \ No newline at end of file +*.elf +.cache diff --git a/mission/mission.c b/mission/mission.c index 0354a2d..4c5b2ea 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -11,9 +11,9 @@ #include #include +#include - -void rust_main(); +void rust_main(void); void test_hardware() { int fd0 = hw_device_open("uart0", 5); @@ -45,7 +45,8 @@ void done(); void init_task(void* _) { - rust_main(_); + (void)_; + rust_main(); } #define STARTUP_MESSAGE1 "\nROMEO embedded obsw\nRelease: " diff --git a/mission_rust/src/fsrc/osal/sync/mutex.rs b/mission_rust/src/fsrc/osal/sync/mutex.rs index 6450c80..8158eba 100644 --- a/mission_rust/src/fsrc/osal/sync/mutex.rs +++ b/mission_rust/src/fsrc/osal/sync/mutex.rs @@ -28,10 +28,11 @@ impl Mutex { } // takes &mut self to be able to work in uninitialized state + // where we do not have a raw pointer to get a mut ref from // other than std::sync::Mutex, this Mutex is never to be cloned // (the clone() fn returns MutexClone), so it is assumed that the // owner will have mut access - pub fn lock(&mut self) -> MutexGuard { + pub fn lock(&mut self) -> MutexGuard<'_,T> { let guard = self.mutex.take(); // Threadsafety is ensured by the inner RawMutex, which will @@ -41,7 +42,7 @@ impl Mutex { // As clone() checks for initialization, this can only happen if no // clones exist. In this case, threadsafety is no concern, as only // One instance and no Clone of this Mutex can exist (it does not impl - // Copy). Borrowing rules ensure in case that only one guard exits + // Copy). Borrowing rules ensure in that case that only one guard exits // per Mutex, making access via &mut self.data safe. MutexGuard { _guard: guard, @@ -92,7 +93,7 @@ impl MutexClone { // so, from here on, this guard is the only holder of the reference // and owns it until it is dropped, when it also gives back // the mutex - // Calling take() twice will deadlock, as does std::sync::Mutex + // Borrowing rules ensure that only one guard exits per Mutex MutexGuard { _guard: guard, data: unsafe { &mut *self.data }, diff --git a/mission_rust/src/fsrc/osal/sync/mutex_raw.rs b/mission_rust/src/fsrc/osal/sync/mutex_raw.rs index 13723b6..1d0d44b 100644 --- a/mission_rust/src/fsrc/osal/sync/mutex_raw.rs +++ b/mission_rust/src/fsrc/osal/sync/mutex_raw.rs @@ -27,7 +27,7 @@ impl Copy for RawMutexClone{} impl RawMutexClone { pub fn take(&self) -> RawMutexGuard { - // Safe: Option is set only when create call succeeded + // Safe: Clones can only be made from initialized Mutexes unsafe { freertos_mutex_take(self.mutex_handle) }; RawMutexGuard { mutex_handle: Some(self.mutex_handle), From bb5fbf19cf98e44d2c7d43a42ab9025d996e0ac9 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 12 Aug 2025 15:10:56 +0200 Subject: [PATCH 04/19] once without global mutex --- mission/freeRTOS_rust_helper.c | 61 +++++++++++++--------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index 08bd8d3..96db555 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -9,23 +9,11 @@ // TODO panic if able, but not in runtime calls -StaticSemaphore_t global_once_mutex_data; -SemaphoreHandle_t global_once_mutex = NULL; - -void freertos_init_once() { - global_once_mutex = - xSemaphoreCreateRecursiveMutexStatic(&global_once_mutex_data); - if (global_once_mutex == NULL) { - // TODO panic - } -} - - // Wraps xTaskGetCurrentTaskHandle and returns NULL if no Task is running // // xTaskGetCurrentTaskHandle() will return a handle even if no task is // running as long as one has been created already. -void *freertos_task_current() { +void *freertos_task_current(void) { // If scheduler is not running, xTaskGetCurrentTaskHandle() might return a // valid handle of a already created task, so we check for Scheduler state // before calling it @@ -42,7 +30,6 @@ StaticTask_t init_task_data; StackType_t init_task_stack[configMINIMAL_STACK_SIZE * 10]; void freertos_init_and_start_scheduling(TaskFunction_t init_task) { - freertos_init_once(); // TaskHandle_t handle = xTaskCreateStatic(init_task, "c_init", configMINIMAL_STACK_SIZE * 10, NULL, configMAX_PRIORITIES - 1, init_task_stack, &init_task_data); @@ -166,8 +153,8 @@ typedef struct { /** * mimics pthread_once() * - * uses a global mutex to threadsafely check if the passed local mutex - * was created already, creating it if not. + * uses a mutex to guard the state, to allow threads to block waiting + * until function has been called. * * After that, the local mutex guards once_data, which is used to only * call the function once. All calls sharing the local_mutex and @@ -181,6 +168,9 @@ typedef struct { */ uint8_t freertos_once(char *once_data_in, uint32_t once_data_len, void *function(void)) { + if (once_data_in == NULL) { + return 0; + } if (once_data_len < sizeof(StaticOnceData_t)) { // TODO panic // printf("freertos_once: data needs to be %zu long\n", @@ -192,21 +182,22 @@ uint8_t freertos_once(char *once_data_in, uint32_t once_data_len, // TODO assert global_once_mutex != NULL // first, we need to check if the local mutex was already created - // this needs to be protected by a mutex to be threadsafe - if (xSemaphoreTakeRecursive(global_once_mutex, portMAX_DELAY) != pdTRUE) { - // TODO panic - } + // this needs to be protected to be threadsafe + // Documentation says that we must not call APIs from within a critical + // Section but I think we are safe in the case of creating a mutex + // which basically only intializes the fields + // TODO verify? + taskENTER_CRITICAL(); if (once_data->once_state == UNINIT) { once_data->local_mutex = xSemaphoreCreateRecursiveMutexStatic(&once_data->local_mutex_data); - if (once_data->local_mutex == NULL) { - // TODO panic - } + // if (once_data->local_mutex == NULL) { + // // will not happen, xSemaphoreCreateRecursiveMutexStatic returns its parameter + // // which we checked above to be != NULL + // } once_data->once_state = INIT; } - if (xSemaphoreGiveRecursive(global_once_mutex) != pdTRUE) { - // TODO panic - } + taskEXIT_CRITICAL(); // Now, we know local mutex is valid, so we use it to guard access to // the once_state @@ -241,24 +232,20 @@ uint8_t freertos_simple_once(uint8_t *once_data) { // TODO assert global_once_mutex != NULL uint8_t result = 0; - // Todo: Replace Mutex with critical section - // This function is basically a flag stored in once_data, protected by the - // global_once_mutex - if (xSemaphoreTakeRecursive(global_once_mutex, portMAX_DELAY) != pdTRUE) { - // TODO panic - } + // This function is basically a flag stored in once_data, protected by + // a critical section + // Critical section is ok, because simple arithmetic is bounded in execution time + taskENTER_CRITICAL(); if (*once_data == 0) { *once_data = 1; result = 1; } - if (xSemaphoreGiveRecursive(global_once_mutex) != pdTRUE) { - // TODO panic - } + taskEXIT_CRITICAL(); return result; } -uint32_t freertos_task_priority_max() { +uint32_t freertos_task_priority_max(void) { // -1 is the max to be used per documentation return configMAX_PRIORITIES - 1; } @@ -301,4 +288,4 @@ void *freertos_mutex_create_static(char *mutex_data, uint32_t mutex_data_len) { return NULL; } return xSemaphoreCreateRecursiveMutexStatic((StaticSemaphore_t *)mutex_data); -} \ No newline at end of file +} From 556faaba0854de9b6eb9bb26fbaf77025850dd35 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 22 Oct 2025 21:31:40 +0200 Subject: [PATCH 05/19] starting interface access from rust --- bsp_linux/hardware/CMakeLists.txt | 2 +- bsp_linux/hardware/hardware.c | 11 +++++ bsp_linux/hardware/serial.c | 68 +++++++++++++++++++++++++++++ bsp_linux/hardware/serial.h | 6 +++ mission/freeRTOS_rust_helper.c | 4 +- mission_rust/src/fsrc/osal.rs | 5 ++- mission_rust/src/fsrc/osal/error.rs | 14 ++++++ mission_rust/src/fsrc/osal/ffi.rs | 30 ++++++++++++- mission_rust/src/fsrc/osal/io.rs | 46 +++++++++++++++++++ mission_rust/src/fsrc/sif.rs | 31 ++++++++----- mission_rust/src/lib.rs | 4 ++ 11 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 bsp_linux/hardware/serial.c create mode 100644 bsp_linux/hardware/serial.h create mode 100644 mission_rust/src/fsrc/osal/error.rs create mode 100644 mission_rust/src/fsrc/osal/io.rs diff --git a/bsp_linux/hardware/CMakeLists.txt b/bsp_linux/hardware/CMakeLists.txt index 794e7de..ad120f8 100644 --- a/bsp_linux/hardware/CMakeLists.txt +++ b/bsp_linux/hardware/CMakeLists.txt @@ -1 +1 @@ -target_sources(bsp PRIVATE hardware.c) \ No newline at end of file +target_sources(bsp PRIVATE hardware.c serial.c) \ No newline at end of file diff --git a/bsp_linux/hardware/hardware.c b/bsp_linux/hardware/hardware.c index 8d7e032..e29bcb8 100644 --- a/bsp_linux/hardware/hardware.c +++ b/bsp_linux/hardware/hardware.c @@ -11,6 +11,8 @@ #include +#include "serial.h" + extern const char *sim_ip; extern int ai_family; @@ -38,7 +40,16 @@ const char *get_port_number(const char *path, size_t path_len) { return NULL; } + + int hw_device_open(const char *path, size_t path_len) { + + int serial_fd = serial_open(path, path_len); + + if (serial_fd != -1) { + return serial_fd; + } + const char *port_number = get_port_number(path, path_len); if (port_number == NULL) { return -1; diff --git a/bsp_linux/hardware/serial.c b/bsp_linux/hardware/serial.c new file mode 100644 index 0000000..82bb1e5 --- /dev/null +++ b/bsp_linux/hardware/serial.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +// TODO FIXME +int compare_string_chars(const char *c_string, const char *chars, + size_t chars_len); + +int convert_errno(int errno_value) { + // errno on linux will always be >0 + if (errno <= 0) { + // something is very wrong + return -1; + } else { + return -errno - 1; + } +} + +// returns fd if ok, converted errno if error +int serial_open_actual(const char *path, speed_t speed) { + // open serial + int fd = open(path, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + return convert_errno(errno); + } + + struct termios termios; + + // initialize termios struct + int ret = tcgetattr(fd, &termios); + if (ret < 0) { + return convert_errno(errno); + } + + // configure for raw input + cfmakeraw(&termios); + + // make it non-blocking + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 0; + + // set speed + ret = cfsetspeed(&termios, speed); + if (ret < 0) { + return convert_errno(errno); + } + + ret = tcsetattr(fd, TCSANOW, &termios); + if (ret < 0) { + return convert_errno(errno); + } + + return fd; +} + + +// returns fd if success, -1 if no path match <-1 if error +int serial_open(const char *path, size_t path_len) { + if (compare_string_chars("ps/uart_mtg", path, path_len) == 1) { + return serial_open_actual("/dev/ttyUSB0", B921600); + } + if (compare_string_chars("debug/uart🚀", path, path_len) == 1) { + return serial_open_actual("/dev/ttyUSB0", B115200); + } + return -1; +} \ No newline at end of file diff --git a/bsp_linux/hardware/serial.h b/bsp_linux/hardware/serial.h new file mode 100644 index 0000000..7fe74b9 --- /dev/null +++ b/bsp_linux/hardware/serial.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +// returns fd if success, -1 if no path match <-1 if error +int serial_open(const char *path, size_t path_len); \ No newline at end of file diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index 96db555..ac3cf81 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -2,6 +2,8 @@ #include "semphr.h" #include "task.h" +#include + #include #include @@ -288,4 +290,4 @@ void *freertos_mutex_create_static(char *mutex_data, uint32_t mutex_data_len) { return NULL; } return xSemaphoreCreateRecursiveMutexStatic((StaticSemaphore_t *)mutex_data); -} +} \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal.rs b/mission_rust/src/fsrc/osal.rs index 9e11ab8..d9e00e5 100644 --- a/mission_rust/src/fsrc/osal.rs +++ b/mission_rust/src/fsrc/osal.rs @@ -1,6 +1,7 @@ -mod ffi; +pub(crate) mod ffi; pub mod sync; pub mod once; pub mod thread; pub mod queue; - +pub mod error; +pub mod io; diff --git a/mission_rust/src/fsrc/osal/error.rs b/mission_rust/src/fsrc/osal/error.rs new file mode 100644 index 0000000..88dc0b2 --- /dev/null +++ b/mission_rust/src/fsrc/osal/error.rs @@ -0,0 +1,14 @@ +#[derive(Debug)] +pub enum UnixError{ + NoSuchFileOrDirectory, + Unknown(i32) +} + +impl From for UnixError{ + fn from(value: i32) -> Self { + match value { + 2 => UnixError::NoSuchFileOrDirectory, + any => Self::Unknown(any) + } + } +} \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal/ffi.rs b/mission_rust/src/fsrc/osal/ffi.rs index 56e87e5..f5c2322 100644 --- a/mission_rust/src/fsrc/osal/ffi.rs +++ b/mission_rust/src/fsrc/osal/ffi.rs @@ -1,4 +1,5 @@ -//TODO verify uXX == uintXX_t +// TODO verify uXX == uintXX_t +// TODO track current state of usize == size_t (needed for some) type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void) -> !; @@ -26,6 +27,10 @@ impl Sizes { extern "C" { + //////////////////////// + /// FreeRTOS API + /// shimmed in mission/freeRTOS_rust_helper.c + //void *create_task_static(TaskFunction_t taskFunction, void *parameter, // char *task_data, uint32_t task_data_len, char *stack, uint32_t stack_size) pub fn freertos_create_task_static( @@ -82,5 +87,28 @@ extern "C" { //uint8_t freertos_simple_once(uint8_t *once_data) pub fn freertos_simple_once(once_data: *const u8) -> u8; + + //////////////////////// + /// Harware Abstraction API in common/include/interfaces.h + /// Used for access to peripherals to make switching between linux and embedded easier + + //int hw_device_open(const char * path, size_t path_len); + pub fn hw_device_open(path: *const core::ffi::c_char, path_len: usize) -> core::ffi::c_int; + + //////////////////////// + /// POSIX/UNIX/LINUX API + + //TODO, linux seems to use ssize_t (confirm!), newlib int as return value and count + #[cfg(target_os = "linux")] + pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; + + #[cfg(target_os = "linux")] + pub fn read(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; + + #[cfg(target_os = "none")] + pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: core::ffi::c_int) -> core::ffi::c_int; + + #[cfg(target_os = "none")] + pub fn read(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: core::ffi::c_int) -> core::ffi::c_int; } diff --git a/mission_rust/src/fsrc/osal/io.rs b/mission_rust/src/fsrc/osal/io.rs new file mode 100644 index 0000000..17c0589 --- /dev/null +++ b/mission_rust/src/fsrc/osal/io.rs @@ -0,0 +1,46 @@ +pub use super::error::UnixError; + +#[derive(Debug)] +pub enum Error{ + Unix(UnixError), + AlreadyOpen, + InvalidPath, + Unknown(i32) +} + +// TODO error values should be in ffi +impl From for Error { + fn from(value: i32) -> Self { + match value { + -2 => Error::AlreadyOpen, + -3 => Error::InvalidPath, + any => Error::Unknown(any) + } + } +} + +pub type Result = core::result::Result; + +#[derive(Debug)] +pub struct Interface{ + fd: core::ffi::c_int, +} + +impl Interface { + pub fn new(path: &str) -> Result { + // Safe: we trust our own implementation to only read + // as we cut our string into bytes, conversion to c_char is correct, as C will compare bit value + let fd = unsafe{ crate::osal::ffi::hw_device_open(path.as_bytes().as_ptr() as *const core::ffi::c_char, path.as_bytes().len())}; + if fd >= 0 { + Ok(Self { fd }) + } else { + // revert errno conversion done by hw_device_open + let errno = -fd -1; + Err(Error::Unix(errno.into())) + } + } + + pub fn write(&mut self, data: &[u8]) { + + } +} \ No newline at end of file diff --git a/mission_rust/src/fsrc/sif.rs b/mission_rust/src/fsrc/sif.rs index 8daaf27..0641902 100644 --- a/mission_rust/src/fsrc/sif.rs +++ b/mission_rust/src/fsrc/sif.rs @@ -6,23 +6,29 @@ pub struct Stderr {} // TODO why or how does pub work (users from same crate need to use core::fmt::... ) pub use core::fmt::{Error, Write}; -extern "C" { - pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> core::ffi::c_int; -} +// TODO this is already in osal +// extern "C" { +// pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> core::ffi::c_int; +// } impl Write for Stdout { fn write_str(&mut self, s: &str) -> Result<(), Error> { // Safe because write will only read the pointer an then return + // try_into is used as write call is different depending on platform + let len_converted = match s.as_bytes().len().try_into(){ + Ok(value) => value, + Err(_) => return Err(Error) + }; let result = unsafe { - write( + crate::fsrc::osal::ffi::write( 1, s.as_bytes().as_ptr() as *const core::ffi::c_void, - s.as_bytes().len(), + len_converted, ) }; // We do not retry incomplete writes, this is stdout after all... - let safe_count: i32 = match s.as_bytes().len().try_into() { + let safe_count = match s.as_bytes().len().try_into() { Ok(count)=> count, Err(_) => return Err(Error) }; @@ -38,15 +44,20 @@ impl Write for Stderr { fn write_str(&mut self, s: &str) -> Result<(), Error> { // Safe because write will only read the pointer an then return + // try_into is used as write call is different depending on platform + let len_converted = match s.as_bytes().len().try_into(){ + Ok(value) => value, + Err(_) => return Err(Error) + }; let result = unsafe { - write( - 2, + crate::fsrc::osal::ffi::write( + 1, s.as_bytes().as_ptr() as *const core::ffi::c_void, - s.as_bytes().len(), + len_converted, ) }; // We do not retry incomplete writes, this is stdout after all... - let safe_count: i32 = match s.as_bytes().len().try_into() { + let safe_count = match s.as_bytes().len().try_into() { Ok(count)=> count, Err(_) => return Err(Error) }; diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 081fde4..18ddc08 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -16,6 +16,8 @@ use osal::{ thread, }; +use crate::fsrc::osal::io::Interface; + static THREAD_INIT: StaticReadOnceLock< @@ -182,6 +184,8 @@ static THREAD_3: StaticReadOnceLock< fn init_task() -> ! { sifln!("Mission enter"); + sifln!("{:?}", Interface::new("debug/uart🚀")); + let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); From 3af76b93b261dfd4c62b9663a143df06d8fb19fa Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 23 Oct 2025 16:26:17 +0200 Subject: [PATCH 06/19] First Version of IO --- bsp_linux/hardware/hardware.c | 4 +- bsp_linux/hardware/serial.c | 15 +- mission/freeRTOS_rust_helper.c | 5 + mission/mission.c | 2 +- mission_rust/.cargo/config.toml | 2 + mission_rust/src/fsrc/osal/error.rs | 653 +++++++++++++++++++++++++++- mission_rust/src/fsrc/osal/ffi.rs | 49 ++- mission_rust/src/fsrc/osal/io.rs | 112 ++++- mission_rust/src/fsrc/sif.rs | 2 +- mission_rust/src/lib.rs | 26 +- 10 files changed, 809 insertions(+), 61 deletions(-) diff --git a/bsp_linux/hardware/hardware.c b/bsp_linux/hardware/hardware.c index e29bcb8..890e6e0 100644 --- a/bsp_linux/hardware/hardware.c +++ b/bsp_linux/hardware/hardware.c @@ -46,7 +46,7 @@ int hw_device_open(const char *path, size_t path_len) { int serial_fd = serial_open(path, path_len); - if (serial_fd != -1) { + if (serial_fd >= -1) { return serial_fd; } @@ -78,7 +78,7 @@ int hw_device_open(const char *path, size_t path_len) { for (current_candidate = addr_candidates; current_candidate != NULL; current_candidate = current_candidate->ai_next) { - sock = socket(current_candidate->ai_family, current_candidate->ai_socktype, + sock = socket(current_candidate->ai_family, current_candidate->ai_socktype | SOCK_NONBLOCK, current_candidate->ai_protocol); if (sock == -1) { continue; diff --git a/bsp_linux/hardware/serial.c b/bsp_linux/hardware/serial.c index 82bb1e5..7e2ece2 100644 --- a/bsp_linux/hardware/serial.c +++ b/bsp_linux/hardware/serial.c @@ -18,12 +18,13 @@ int convert_errno(int errno_value) { } } -// returns fd if ok, converted errno if error +// TODO: can we extend errno safely? +// returns fd if ok, -1 on error 0 if no match int serial_open_actual(const char *path, speed_t speed) { // open serial int fd = open(path, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { - return convert_errno(errno); + return -1; } struct termios termios; @@ -31,7 +32,7 @@ int serial_open_actual(const char *path, speed_t speed) { // initialize termios struct int ret = tcgetattr(fd, &termios); if (ret < 0) { - return convert_errno(errno); + return -1; } // configure for raw input @@ -44,19 +45,19 @@ int serial_open_actual(const char *path, speed_t speed) { // set speed ret = cfsetspeed(&termios, speed); if (ret < 0) { - return convert_errno(errno); + return -1; } ret = tcsetattr(fd, TCSANOW, &termios); if (ret < 0) { - return convert_errno(errno); + return -1; } return fd; } -// returns fd if success, -1 if no path match <-1 if error +// returns fd if success, -1 on error, -2 if no match int serial_open(const char *path, size_t path_len) { if (compare_string_chars("ps/uart_mtg", path, path_len) == 1) { return serial_open_actual("/dev/ttyUSB0", B921600); @@ -64,5 +65,5 @@ int serial_open(const char *path, size_t path_len) { if (compare_string_chars("debug/uart🚀", path, path_len) == 1) { return serial_open_actual("/dev/ttyUSB0", B115200); } - return -1; + return -2; } \ No newline at end of file diff --git a/mission/freeRTOS_rust_helper.c b/mission/freeRTOS_rust_helper.c index ac3cf81..37cf13a 100644 --- a/mission/freeRTOS_rust_helper.c +++ b/mission/freeRTOS_rust_helper.c @@ -290,4 +290,9 @@ void *freertos_mutex_create_static(char *mutex_data, uint32_t mutex_data_len) { return NULL; } return xSemaphoreCreateRecursiveMutexStatic((StaticSemaphore_t *)mutex_data); +} + +// TODO: might be the wrong place +int freertos_get_sys_error(){ + return errno; } \ No newline at end of file diff --git a/mission/mission.c b/mission/mission.c index 4c5b2ea..c151dd0 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -62,7 +62,7 @@ void mission(void) { write(1, "\n", 1); - test_hardware(); + //test_hardware(); freertos_init_and_start_scheduling(init_task); diff --git a/mission_rust/.cargo/config.toml b/mission_rust/.cargo/config.toml index e69de29..b697f11 100644 --- a/mission_rust/.cargo/config.toml +++ b/mission_rust/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.armv7a-none-eabihf] +rustflags = ['-A', 'explicit_builtin_cfgs_in_flags','--cfg', 'target_env="newlib"'] # We use gcc/newlib to link this lib crate \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal/error.rs b/mission_rust/src/fsrc/osal/error.rs index 88dc0b2..c9a7d1a 100644 --- a/mission_rust/src/fsrc/osal/error.rs +++ b/mission_rust/src/fsrc/osal/error.rs @@ -1,14 +1,651 @@ -#[derive(Debug)] -pub enum UnixError{ - NoSuchFileOrDirectory, - Unknown(i32) +use core::fmt; + +use crate::fsrc::osal::ffi; + +// wrap helper shim +pub fn errno() -> i32 { + unsafe { ffi::freertos_get_sys_error() } } -impl From for UnixError{ +#[cfg(target_os = "linux")] +mod libc { + // We assume a gnu x86_64: + use core::ffi::c_int; + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + //pub const EWOULDBLOCK: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EDEADLOCK: c_int = 35; + pub const ENAMETOOLONG: c_int = 36; + pub const ENOLCK: c_int = 37; + pub const ENOSYS: c_int = 38; + pub const ENOTEMPTY: c_int = 39; + pub const ELOOP: c_int = 40; + pub const ENOMSG: c_int = 42; + pub const EIDRM: c_int = 43; + pub const ECHRNG: c_int = 44; + pub const ELNRNG: c_int = 48; + pub const EUNATCH: c_int = 49; + pub const ENOCSI: c_int = 50; + pub const EBADE: c_int = 52; + pub const EBADR: c_int = 53; + pub const EXFULL: c_int = 54; + pub const ENOANO: c_int = 55; + pub const EBADRQC: c_int = 56; + pub const EBADSLT: c_int = 57; + pub const EBFONT: c_int = 59; + pub const ENOSTR: c_int = 60; + pub const ENODATA: c_int = 61; + pub const ETIME: c_int = 62; + pub const ENOSR: c_int = 63; + pub const ENONET: c_int = 64; + pub const ENOPKG: c_int = 65; + pub const EREMOTE: c_int = 66; + pub const ENOLINK: c_int = 67; + pub const EADV: c_int = 68; + pub const ESRMNT: c_int = 69; + pub const ECOMM: c_int = 70; + pub const EPROTO: c_int = 71; + pub const EMULTIHOP: c_int = 72; + pub const EDOTDOT: c_int = 73; + pub const EBADMSG: c_int = 74; + pub const EOVERFLOW: c_int = 75; + pub const ENOTUNIQ: c_int = 76; + pub const EBADFD: c_int = 77; + pub const EREMCHG: c_int = 78; + pub const ELIBACC: c_int = 79; + pub const ELIBBAD: c_int = 80; + pub const ELIBSCN: c_int = 81; + pub const ELIBMAX: c_int = 82; + pub const ELIBEXEC: c_int = 83; + pub const EILSEQ: c_int = 84; + pub const ERESTART: c_int = 85; + pub const ESTRPIPE: c_int = 86; + pub const EUSERS: c_int = 87; + pub const ENOTSOCK: c_int = 88; + pub const EDESTADDRREQ: c_int = 89; + pub const EMSGSIZE: c_int = 90; + pub const EPROTOTYPE: c_int = 91; + pub const ENOPROTOOPT: c_int = 92; + pub const EPROTONOSUPPORT: c_int = 93; + pub const ESOCKTNOSUPPORT: c_int = 94; + pub const EOPNOTSUPP: c_int = 95; + pub const EPFNOSUPPORT: c_int = 96; + pub const EAFNOSUPPORT: c_int = 97; + pub const EADDRINUSE: c_int = 98; + pub const EADDRNOTAVAIL: c_int = 99; + pub const ENETDOWN: c_int = 100; + pub const ENETUNREACH: c_int = 101; + pub const ENETRESET: c_int = 102; + pub const ECONNABORTED: c_int = 103; + pub const ECONNRESET: c_int = 104; + pub const ENOBUFS: c_int = 105; + pub const EISCONN: c_int = 106; + pub const ENOTCONN: c_int = 107; + pub const ESHUTDOWN: c_int = 108; + pub const ETOOMANYREFS: c_int = 109; + pub const ETIMEDOUT: c_int = 110; + pub const ECONNREFUSED: c_int = 111; + pub const EHOSTDOWN: c_int = 112; + pub const EHOSTUNREACH: c_int = 113; + pub const EALREADY: c_int = 114; + pub const EINPROGRESS: c_int = 115; + pub const ESTALE: c_int = 116; + pub const EUCLEAN: c_int = 117; + pub const ENOTNAM: c_int = 118; + pub const ENAVAIL: c_int = 119; + pub const EISNAM: c_int = 120; + pub const EREMOTEIO: c_int = 121; + pub const EDQUOT: c_int = 122; + pub const ENOMEDIUM: c_int = 123; + pub const EMEDIUMTYPE: c_int = 124; + pub const ECANCELED: c_int = 125; + pub const ENOKEY: c_int = 126; + pub const EKEYEXPIRED: c_int = 127; + pub const EKEYREVOKED: c_int = 128; + pub const EKEYREJECTED: c_int = 129; + pub const EOWNERDEAD: c_int = 130; + pub const ENOTRECOVERABLE: c_int = 131; + pub const ERFKILL: c_int = 132; + pub const EHWPOISON: c_int = 133; +} + +#[cfg(target_env = "newlib")] +mod libc { + // taken from rust-lang/libc/src/unix/newlib/mod.rs + use core::ffi::c_int; + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const ENOMSG: c_int = 35; + pub const EIDRM: c_int = 36; + pub const EDEADLK: c_int = 45; + pub const ENOLCK: c_int = 46; + pub const ENOSTR: c_int = 60; + pub const ENODATA: c_int = 61; + pub const ETIME: c_int = 62; + pub const ENOSR: c_int = 63; + pub const ENOLINK: c_int = 67; + pub const EPROTO: c_int = 71; + pub const EMULTIHOP: c_int = 74; + pub const EBADMSG: c_int = 77; + pub const EFTYPE: c_int = 79; + pub const ENOSYS: c_int = 88; + pub const ENOTEMPTY: c_int = 90; + pub const ENAMETOOLONG: c_int = 91; + pub const ELOOP: c_int = 92; + pub const EOPNOTSUPP: c_int = 95; + pub const EPFNOSUPPORT: c_int = 96; + pub const ECONNRESET: c_int = 104; + pub const ENOBUFS: c_int = 105; + pub const EAFNOSUPPORT: c_int = 106; + pub const EPROTOTYPE: c_int = 107; + pub const ENOTSOCK: c_int = 108; + pub const ENOPROTOOPT: c_int = 109; + pub const ECONNREFUSED: c_int = 111; + pub const EADDRINUSE: c_int = 112; + pub const ECONNABORTED: c_int = 113; + pub const ENETUNREACH: c_int = 114; + pub const ENETDOWN: c_int = 115; + pub const ETIMEDOUT: c_int = 116; + pub const EHOSTDOWN: c_int = 117; + pub const EHOSTUNREACH: c_int = 118; + pub const EINPROGRESS: c_int = 119; + pub const EALREADY: c_int = 120; + pub const EDESTADDRREQ: c_int = 121; + pub const EMSGSIZE: c_int = 122; + pub const EPROTONOSUPPORT: c_int = 123; + pub const EADDRNOTAVAIL: c_int = 125; + pub const ENETRESET: c_int = 126; + pub const EISCONN: c_int = 127; + pub const ENOTCONN: c_int = 128; + pub const ETOOMANYREFS: c_int = 129; + pub const EDQUOT: c_int = 132; + pub const ESTALE: c_int = 133; + pub const ENOTSUP: c_int = 134; + pub const EILSEQ: c_int = 138; + pub const EOVERFLOW: c_int = 139; + pub const ECANCELED: c_int = 140; + pub const ENOTRECOVERABLE: c_int = 141; + pub const EOWNERDEAD: c_int = 142; + pub const EWOULDBLOCK: c_int = 11; +} + +#[derive(Debug, PartialEq)] +pub enum OsError { + OperationNotPermitted, + NoSuchFileOrDirectory, + NoSuchProcess, + InterruptedSystemCall, + InputOutputError, + NoSuchDeviceOrAddress, + ArgumentListTooLong, + ExecFormatError, + BadFileDescriptor, + NoChildProcesses, + ResourceTemporarilyUnavailable, + CannotAllocateMemory, + PermissionDenied, + BadAddress, + BlockDeviceRequired, + DeviceOrResourceBusy, + FileExists, + InvalidCrossDeviceLink, + NoSuchDevice, + NotADirectory, + IsADirectory, + InvalidArgument, + TooManyOpenFilesInSystem, + TooManyOpenFiles, + InappropriateIoctlForDevice, + TextFileBusy, + FileTooLarge, + NoSpaceLeftOnDevice, + IllegalSeek, + ReadOnlyFileSystem, + TooManyLinks, + BrokenPipe, + NumericalArgumentOutOfDomain, + NumericalResultOutOfRange, + ResourceDeadlockAvoided, + FileNameTooLong, + NoLocksAvailable, + FunctionNotImplemented, + DirectoryNotEmpty, + TooManyLevelsOfSymbolicLinks, + NoMessageOfDesiredType, + IdentifierRemoved, + ChannelNumberOutOfRange, + LinkNumberOutOfRange, + ProtocolDriverNotAttached, + NoCsiStructureAvailable, + InvalidExchange, + InvalidRequestDescriptor, + ExchangeFull, + NoAnode, + InvalidRequestCode, + InvalidSlot, + BadFontFileFormat, + DeviceNotAStream, + NoDataAvailable, + TimerExpired, + OutOfStreamsResources, + MachineIsNotOnTheNetwork, + PackageNotInstalled, + ObjectIsRemote, + LinkHasBeenSevered, + AdvertiseError, + SrmountError, + CommunicationErrorOnSend, + ProtocolError, + MultihopAttempted, + RfsSpecificError, + BadMessage, + ValueTooLargeForDefinedDataType, + NameNotUniqueOnNetwork, + FileDescriptorInBadState, + RemoteAddressChanged, + CanNotAccessANeededSharedLibrary, + AccessingACorruptedSharedLibrary, + LibSectionCorrupted, + AttemptingToLinkInTooManySharedLibraries, + CannotExecASharedLibraryDirectly, + InvalidOrIncompleteMultibyteOrWideCharacter, + InterruptedSystemCallShouldBeRestarted, + StreamsPipeError, + TooManyUsers, + SocketOperationOnNonSocket, + DestinationAddressRequired, + MessageTooLong, + ProtocolWrongTypeForSocket, + ProtocolNotAvailable, + ProtocolNotSupported, + SocketTypeNotSupported, + OperationNotSupported, + ProtocolFamilyNotSupported, + AddressFamilyNotSupportedByProtocol, + AddressAlreadyInUse, + CannotAssignRequestedAddress, + NetworkIsDown, + NetworkIsUnreachable, + NetworkDroppedConnectionOnReset, + SoftwareCausedConnectionAbort, + ConnectionResetByPeer, + NoBufferSpaceAvailable, + TransportEndpointIsAlreadyConnected, + TransportEndpointIsNotConnected, + CannotSendAfterTransportEndpointShutdown, + TooManyReferencesCannotSplice, + ConnectionTimedOut, + ConnectionRefused, + HostIsDown, + NoRouteToHost, + OperationAlreadyInProgress, + OperationNowInProgress, + StaleFileHandle, + StructureNeedsCleaning, + NotAXenixNamedTypeFile, + NoXenixSemaphoresAvailable, + IsANamedTypeFile, + RemoteIOError, + DiskQuotaExceeded, + NoMediumFound, + WrongMediumType, + OperationCanceled, + RequiredKeyNotAvailable, + KeyHasExpired, + KeyHasBeenRevoked, + KeyWasRejectedByService, + OwnerDied, + StateNotRecoverable, + OperationNotPossibleDueToRfKill, + MemoryPageHasHardwareError, + Other(i32), +} + +impl From for OsError { fn from(value: i32) -> Self { + use crate::osal::io::OsError::*; match value { - 2 => UnixError::NoSuchFileOrDirectory, - any => Self::Unknown(any) + libc::EPERM => OperationNotPermitted, + libc::ENOENT => NoSuchFileOrDirectory, + libc::ESRCH => NoSuchProcess, + libc::EINTR => InterruptedSystemCall, + libc::EIO => InputOutputError, + libc::ENXIO => NoSuchDeviceOrAddress, + libc::E2BIG => ArgumentListTooLong, + libc::ENOEXEC => ExecFormatError, + libc::EBADF => BadFileDescriptor, + libc::ECHILD => NoChildProcesses, + libc::EAGAIN => ResourceTemporarilyUnavailable, + //libc::EWOULDBLOCK => ResourceTemporarilyUnavailable, == EAGAIN + libc::ENOMEM => CannotAllocateMemory, + libc::EACCES => PermissionDenied, + libc::EFAULT => BadAddress, + libc::ENOTBLK => BlockDeviceRequired, + libc::EBUSY => DeviceOrResourceBusy, + libc::EEXIST => FileExists, + libc::EXDEV => InvalidCrossDeviceLink, + libc::ENODEV => NoSuchDevice, + libc::ENOTDIR => NotADirectory, + libc::EISDIR => IsADirectory, + libc::EINVAL => InvalidArgument, + libc::ENFILE => TooManyOpenFilesInSystem, + libc::EMFILE => TooManyOpenFiles, + libc::ENOTTY => InappropriateIoctlForDevice, + libc::ETXTBSY => TextFileBusy, + libc::EFBIG => FileTooLarge, + libc::ENOSPC => NoSpaceLeftOnDevice, + libc::ESPIPE => IllegalSeek, + libc::EROFS => ReadOnlyFileSystem, + libc::EMLINK => TooManyLinks, + libc::EPIPE => BrokenPipe, + libc::EDOM => NumericalArgumentOutOfDomain, + libc::ERANGE => NumericalResultOutOfRange, + libc::EDEADLOCK => ResourceDeadlockAvoided, + libc::ENAMETOOLONG => FileNameTooLong, + libc::ENOLCK => NoLocksAvailable, + libc::ENOSYS => FunctionNotImplemented, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::ELOOP => TooManyLevelsOfSymbolicLinks, + libc::ENOMSG => NoMessageOfDesiredType, + libc::EIDRM => IdentifierRemoved, + libc::ECHRNG => ChannelNumberOutOfRange, + libc::ELNRNG => LinkNumberOutOfRange, + libc::EUNATCH => ProtocolDriverNotAttached, + libc::ENOCSI => NoCsiStructureAvailable, + libc::EBADE => InvalidExchange, + libc::EBADR => InvalidRequestDescriptor, + libc::EXFULL => ExchangeFull, + libc::ENOANO => NoAnode, + libc::EBADRQC => InvalidRequestCode, + libc::EBADSLT => InvalidSlot, + libc::EBFONT => BadFontFileFormat, + libc::ENOSTR => DeviceNotAStream, + libc::ENODATA => NoDataAvailable, + libc::ETIME => TimerExpired, + libc::ENOSR => OutOfStreamsResources, + libc::ENONET => MachineIsNotOnTheNetwork, + libc::ENOPKG => PackageNotInstalled, + libc::EREMOTE => ObjectIsRemote, + libc::ENOLINK => LinkHasBeenSevered, + libc::EADV => AdvertiseError, + libc::ESRMNT => SrmountError, + libc::ECOMM => CommunicationErrorOnSend, + libc::EPROTO => ProtocolError, + libc::EMULTIHOP => MultihopAttempted, + libc::EDOTDOT => RfsSpecificError, + libc::EBADMSG => BadMessage, + libc::EOVERFLOW => ValueTooLargeForDefinedDataType, + libc::ENOTUNIQ => NameNotUniqueOnNetwork, + libc::EBADFD => FileDescriptorInBadState, + libc::EREMCHG => RemoteAddressChanged, + libc::ELIBACC => CanNotAccessANeededSharedLibrary, + libc::ELIBBAD => AccessingACorruptedSharedLibrary, + libc::ELIBSCN => LibSectionCorrupted, + libc::ELIBMAX => AttemptingToLinkInTooManySharedLibraries, + libc::ELIBEXEC => CannotExecASharedLibraryDirectly, + libc::EILSEQ => InvalidOrIncompleteMultibyteOrWideCharacter, + libc::ERESTART => InterruptedSystemCallShouldBeRestarted, + libc::ESTRPIPE => StreamsPipeError, + libc::EUSERS => TooManyUsers, + libc::ENOTSOCK => SocketOperationOnNonSocket, + libc::EDESTADDRREQ => DestinationAddressRequired, + libc::EMSGSIZE => MessageTooLong, + libc::EPROTOTYPE => ProtocolWrongTypeForSocket, + libc::ENOPROTOOPT => ProtocolNotAvailable, + libc::EPROTONOSUPPORT => ProtocolNotSupported, + libc::ESOCKTNOSUPPORT => SocketTypeNotSupported, + libc::EOPNOTSUPP => OperationNotSupported, + // libc::ENOTSUP => OperationNotSupported, == EOPNOTSUPP + libc::EPFNOSUPPORT => ProtocolFamilyNotSupported, + libc::EAFNOSUPPORT => AddressFamilyNotSupportedByProtocol, + libc::EADDRINUSE => AddressAlreadyInUse, + libc::EADDRNOTAVAIL => CannotAssignRequestedAddress, + libc::ENETDOWN => NetworkIsDown, + libc::ENETUNREACH => NetworkIsUnreachable, + libc::ENETRESET => NetworkDroppedConnectionOnReset, + libc::ECONNABORTED => SoftwareCausedConnectionAbort, + libc::ECONNRESET => ConnectionResetByPeer, + libc::ENOBUFS => NoBufferSpaceAvailable, + libc::EISCONN => TransportEndpointIsAlreadyConnected, + libc::ENOTCONN => TransportEndpointIsNotConnected, + libc::ESHUTDOWN => CannotSendAfterTransportEndpointShutdown, + libc::ETOOMANYREFS => TooManyReferencesCannotSplice, + libc::ETIMEDOUT => ConnectionTimedOut, + libc::ECONNREFUSED => ConnectionRefused, + libc::EHOSTDOWN => HostIsDown, + libc::EHOSTUNREACH => NoRouteToHost, + libc::EALREADY => OperationAlreadyInProgress, + libc::EINPROGRESS => OperationNowInProgress, + libc::ESTALE => StaleFileHandle, + libc::EUCLEAN => StructureNeedsCleaning, + libc::ENOTNAM => NotAXenixNamedTypeFile, + libc::ENAVAIL => NoXenixSemaphoresAvailable, + libc::EISNAM => IsANamedTypeFile, + libc::EREMOTEIO => RemoteIOError, + libc::EDQUOT => DiskQuotaExceeded, + libc::ENOMEDIUM => NoMediumFound, + libc::EMEDIUMTYPE => WrongMediumType, + libc::ECANCELED => OperationCanceled, + libc::ENOKEY => RequiredKeyNotAvailable, + libc::EKEYEXPIRED => KeyHasExpired, + libc::EKEYREVOKED => KeyHasBeenRevoked, + libc::EKEYREJECTED => KeyWasRejectedByService, + libc::EOWNERDEAD => OwnerDied, + libc::ENOTRECOVERABLE => StateNotRecoverable, + libc::ERFKILL => OperationNotPossibleDueToRfKill, + libc::EHWPOISON => MemoryPageHasHardwareError, + value => Other(value), } } -} \ No newline at end of file +} + +impl fmt::Display for OsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use OsError::*; + match self { + OperationNotPermitted => write!(f, "Operation not permitted"), + NoSuchFileOrDirectory => write!(f, "No such file or directory"), + NoSuchProcess => write!(f, "No such process"), + InterruptedSystemCall => write!(f, "Interrupted system call"), + InputOutputError => write!(f, "Input/output error"), + NoSuchDeviceOrAddress => write!(f, "No such device or address"), + ArgumentListTooLong => write!(f, "Argument list too long"), + ExecFormatError => write!(f, "Exec format error"), + BadFileDescriptor => write!(f, "Bad file descriptor"), + NoChildProcesses => write!(f, "No child processes"), + ResourceTemporarilyUnavailable => write!(f, "Resource temporarily unavailable"), + CannotAllocateMemory => write!(f, "Cannot allocate memory"), + PermissionDenied => write!(f, "Permission denied"), + BadAddress => write!(f, "Bad address"), + BlockDeviceRequired => write!(f, "Block device required"), + DeviceOrResourceBusy => write!(f, "Device or resource busy"), + FileExists => write!(f, "File exists"), + InvalidCrossDeviceLink => write!(f, "Invalid cross-device link"), + NoSuchDevice => write!(f, "No such device"), + NotADirectory => write!(f, "Not a directory"), + IsADirectory => write!(f, "Is a directory"), + InvalidArgument => write!(f, "Invalid argument"), + TooManyOpenFilesInSystem => write!(f, "Too many open files in system"), + TooManyOpenFiles => write!(f, "Too many open files"), + InappropriateIoctlForDevice => write!(f, "Inappropriate ioctl for device"), + TextFileBusy => write!(f, "Text file busy"), + FileTooLarge => write!(f, "File too large"), + NoSpaceLeftOnDevice => write!(f, "No space left on device"), + IllegalSeek => write!(f, "Illegal seek"), + ReadOnlyFileSystem => write!(f, "Read-only file system"), + TooManyLinks => write!(f, "Too many links"), + BrokenPipe => write!(f, "Broken pipe"), + NumericalArgumentOutOfDomain => write!(f, "Numerical argument out of domain"), + NumericalResultOutOfRange => write!(f, "Numerical result out of range"), + ResourceDeadlockAvoided => write!(f, "Resource deadlock avoided"), + FileNameTooLong => write!(f, "File name too long"), + NoLocksAvailable => write!(f, "No locks available"), + FunctionNotImplemented => write!(f, "Function not implemented"), + DirectoryNotEmpty => write!(f, "Directory not empty"), + TooManyLevelsOfSymbolicLinks => write!(f, "Too many levels of symbolic links"), + NoMessageOfDesiredType => write!(f, "No message of desired type"), + IdentifierRemoved => write!(f, "Identifier removed"), + ChannelNumberOutOfRange => write!(f, "Channel number out of range"), + LinkNumberOutOfRange => write!(f, "Link number out of range"), + ProtocolDriverNotAttached => write!(f, "Protocol driver not attached"), + NoCsiStructureAvailable => write!(f, "No CSI structure available"), + InvalidExchange => write!(f, "Invalid exchange"), + InvalidRequestDescriptor => write!(f, "Invalid request descriptor"), + ExchangeFull => write!(f, "Exchange full"), + NoAnode => write!(f, "No anode"), + InvalidRequestCode => write!(f, "Invalid request code"), + InvalidSlot => write!(f, "Invalid slot"), + BadFontFileFormat => write!(f, "Bad font file format"), + DeviceNotAStream => write!(f, "Device not a stream"), + NoDataAvailable => write!(f, "No data available"), + TimerExpired => write!(f, "Timer expired"), + OutOfStreamsResources => write!(f, "Out of streams resources"), + MachineIsNotOnTheNetwork => write!(f, "Machine is not on the network"), + PackageNotInstalled => write!(f, "Package not installed"), + ObjectIsRemote => write!(f, "Object is remote"), + LinkHasBeenSevered => write!(f, "Link has been severed"), + AdvertiseError => write!(f, "Advertise error"), + SrmountError => write!(f, "Srmount error"), + CommunicationErrorOnSend => write!(f, "Communication error on send"), + ProtocolError => write!(f, "Protocol error"), + MultihopAttempted => write!(f, "Multihop attempted"), + RfsSpecificError => write!(f, "RFS specific error"), + BadMessage => write!(f, "Bad message"), + ValueTooLargeForDefinedDataType => write!(f, "Value too large for defined data type"), + NameNotUniqueOnNetwork => write!(f, "Name not unique on network"), + FileDescriptorInBadState => write!(f, "File descriptor in bad state"), + RemoteAddressChanged => write!(f, "Remote address changed"), + CanNotAccessANeededSharedLibrary => write!(f, "Can not access a needed shared library"), + AccessingACorruptedSharedLibrary => write!(f, "Accessing a corrupted shared library"), + LibSectionCorrupted => write!(f, ".lib section in a.out corrupted"), + AttemptingToLinkInTooManySharedLibraries => { + write!(f, "Attempting to link in too many shared libraries") + } + CannotExecASharedLibraryDirectly => write!(f, "Cannot exec a shared library directly"), + InvalidOrIncompleteMultibyteOrWideCharacter => { + write!(f, "Invalid or incomplete multibyte or wide character") + } + InterruptedSystemCallShouldBeRestarted => { + write!(f, "Interrupted system call should be restarted") + } + StreamsPipeError => write!(f, "Streams pipe error"), + TooManyUsers => write!(f, "Too many users"), + SocketOperationOnNonSocket => write!(f, "Socket operation on non-socket"), + DestinationAddressRequired => write!(f, "Destination address required"), + MessageTooLong => write!(f, "Message too long"), + ProtocolWrongTypeForSocket => write!(f, "Protocol wrong type for socket"), + ProtocolNotAvailable => write!(f, "Protocol not available"), + ProtocolNotSupported => write!(f, "Protocol not supported"), + SocketTypeNotSupported => write!(f, "Socket type not supported"), + OperationNotSupported => write!(f, "Operation not supported"), + ProtocolFamilyNotSupported => write!(f, "Protocol family not supported"), + AddressFamilyNotSupportedByProtocol => { + write!(f, "Address family not supported by protocol") + } + AddressAlreadyInUse => write!(f, "Address already in use"), + CannotAssignRequestedAddress => write!(f, "Cannot assign requested address"), + NetworkIsDown => write!(f, "Network is down"), + NetworkIsUnreachable => write!(f, "Network is unreachable"), + NetworkDroppedConnectionOnReset => write!(f, "Network dropped connection on reset"), + SoftwareCausedConnectionAbort => write!(f, "Software caused connection abort"), + ConnectionResetByPeer => write!(f, "Connection reset by peer"), + NoBufferSpaceAvailable => write!(f, "No buffer space available"), + TransportEndpointIsAlreadyConnected => { + write!(f, "Transport endpoint is already connected") + } + TransportEndpointIsNotConnected => write!(f, "Transport endpoint is not connected"), + CannotSendAfterTransportEndpointShutdown => { + write!(f, "Cannot send after transport endpoint shutdown") + } + TooManyReferencesCannotSplice => write!(f, "Too many references: cannot splice"), + ConnectionTimedOut => write!(f, "Connection timed out"), + ConnectionRefused => write!(f, "Connection refused"), + HostIsDown => write!(f, "Host is down"), + NoRouteToHost => write!(f, "No route to host"), + OperationAlreadyInProgress => write!(f, "Operation already in progress"), + OperationNowInProgress => write!(f, "Operation now in progress"), + StaleFileHandle => write!(f, "Stale file handle"), + StructureNeedsCleaning => write!(f, "Structure needs cleaning"), + NotAXenixNamedTypeFile => write!(f, "Not a XENIX named type file"), + NoXenixSemaphoresAvailable => write!(f, "No XENIX semaphores available"), + IsANamedTypeFile => write!(f, "Is a named type file"), + RemoteIOError => write!(f, "Remote I/O error"), + DiskQuotaExceeded => write!(f, "Disk quota exceeded"), + NoMediumFound => write!(f, "No medium found"), + WrongMediumType => write!(f, "Wrong medium type"), + OperationCanceled => write!(f, "Operation canceled"), + RequiredKeyNotAvailable => write!(f, "Required key not available"), + KeyHasExpired => write!(f, "Key has expired"), + KeyHasBeenRevoked => write!(f, "Key has been revoked"), + KeyWasRejectedByService => write!(f, "Key was rejected by service"), + OwnerDied => write!(f, "Owner died"), + StateNotRecoverable => write!(f, "State not recoverable"), + OperationNotPossibleDueToRfKill => write!(f, "Operation not possible due to RF-kill"), + MemoryPageHasHardwareError => write!(f, "Memory page has hardware error"), + Other(value) => write!(f, "Other error: {}", value), + } + } +} diff --git a/mission_rust/src/fsrc/osal/ffi.rs b/mission_rust/src/fsrc/osal/ffi.rs index f5c2322..6229a2d 100644 --- a/mission_rust/src/fsrc/osal/ffi.rs +++ b/mission_rust/src/fsrc/osal/ffi.rs @@ -3,9 +3,7 @@ type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void) -> !; - -pub struct Sizes { -} +pub struct Sizes {} // TODO these should be passed by compile time value #[cfg(target_os = "linux")] @@ -17,7 +15,7 @@ impl Sizes { } // We use none for bare metal, as we only support one architecture so far -#[cfg(target_os = "none")] +#[cfg(target_env = "newlib")] impl Sizes { pub const TASK_DATA_SIZE: usize = 184; pub const MUTEX_DATA_SIZE: usize = 168; @@ -25,12 +23,10 @@ impl Sizes { pub const TASK_MINIMAL_STACK_SIZE: usize = 10240; } - extern "C" { //////////////////////// /// FreeRTOS API /// shimmed in mission/freeRTOS_rust_helper.c - //void *create_task_static(TaskFunction_t taskFunction, void *parameter, // char *task_data, uint32_t task_data_len, char *stack, uint32_t stack_size) pub fn freertos_create_task_static( @@ -49,7 +45,10 @@ extern "C" { pub fn freertos_task_delete(handle: *const core::ffi::c_void) -> !; - pub fn freertos_task_storage_set(handle: *const core::ffi::c_void, data: *const core::ffi::c_void); + pub fn freertos_task_storage_set( + handle: *const core::ffi::c_void, + data: *const core::ffi::c_void, + ); pub fn freertos_task_storage_get(handle: *const core::ffi::c_void) -> *const core::ffi::c_void; @@ -60,7 +59,7 @@ extern "C" { pub fn freertos_task_current() -> *const core::ffi::c_void; // TODO this should be passed by compile time value - pub fn freertos_task_priority_max()-> u32; + pub fn freertos_task_priority_max() -> u32; //void *freertos_queue_create_static(uint32_t depth, uint32_t element_size, // char *queue_data, uint32_t queue_data_len, @@ -70,11 +69,17 @@ extern "C" { element_size: u32, queue_data: *mut core::ffi::c_char, queue_data_len: u32, - queue: *mut u8 + queue: *mut u8, ) -> *const core::ffi::c_void; - pub fn freertos_queue_receive(queue: *const core::ffi::c_void, message: *const core::ffi::c_void) -> u8; - pub fn freertos_queue_send(queue: *const core::ffi::c_void, message: *const core::ffi::c_void) -> u8; + pub fn freertos_queue_receive( + queue: *const core::ffi::c_void, + message: *const core::ffi::c_void, + ) -> u8; + pub fn freertos_queue_send( + queue: *const core::ffi::c_void, + message: *const core::ffi::c_void, + ) -> u8; pub fn freertos_mutex_create_static( mutex_data: *const core::ffi::c_char, @@ -87,17 +92,18 @@ extern "C" { //uint8_t freertos_simple_once(uint8_t *once_data) pub fn freertos_simple_once(once_data: *const u8) -> u8; + //int freertos_get_sys_error() + pub fn freertos_get_sys_error() -> core::ffi::c_int; //////////////////////// /// Harware Abstraction API in common/include/interfaces.h /// Used for access to peripherals to make switching between linux and embedded easier - //int hw_device_open(const char * path, size_t path_len); pub fn hw_device_open(path: *const core::ffi::c_char, path_len: usize) -> core::ffi::c_int; //////////////////////// /// POSIX/UNIX/LINUX API - + //TODO, linux seems to use ssize_t (confirm!), newlib int as return value and count #[cfg(target_os = "linux")] pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; @@ -105,10 +111,17 @@ extern "C" { #[cfg(target_os = "linux")] pub fn read(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; - #[cfg(target_os = "none")] - pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: core::ffi::c_int) -> core::ffi::c_int; + #[cfg(target_env = "newlib")] + pub fn write( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_int, + ) -> core::ffi::c_int; - #[cfg(target_os = "none")] - pub fn read(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: core::ffi::c_int) -> core::ffi::c_int; + #[cfg(target_env = "newlib")] + pub fn read( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_int, + ) -> core::ffi::c_int; } - diff --git a/mission_rust/src/fsrc/osal/io.rs b/mission_rust/src/fsrc/osal/io.rs index 17c0589..f4e1c18 100644 --- a/mission_rust/src/fsrc/osal/io.rs +++ b/mission_rust/src/fsrc/osal/io.rs @@ -1,46 +1,114 @@ -pub use super::error::UnixError; +use core::fmt::Display; + +pub use super::error::OsError; +use super::ffi; #[derive(Debug)] -pub enum Error{ - Unix(UnixError), - AlreadyOpen, +pub enum Error { + Os(OsError), + IncompleteWrite(usize), InvalidPath, - Unknown(i32) + Unknown(i32), + InternalError, } -// TODO error values should be in ffi -impl From for Error { - fn from(value: i32) -> Self { - match value { - -2 => Error::AlreadyOpen, - -3 => Error::InvalidPath, - any => Error::Unknown(any) +impl Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "😢")?; + match self { + Error::Os(os_error) => write!(f, "Os::{}", os_error), + _ => write!(f, "not implemented"), } } } -pub type Result = core::result::Result; +pub type Result = core::result::Result; + +pub trait Read { + fn read<'a>(&self, buffer: &'a [u8]) -> Result<&'a [u8]>; +} + +pub trait Write { + fn write(&mut self, data: &[u8]) -> Result<()>; +} #[derive(Debug)] -pub struct Interface{ +pub struct HardwareInterface { fd: core::ffi::c_int, } -impl Interface { +impl HardwareInterface { pub fn new(path: &str) -> Result { // Safe: we trust our own implementation to only read // as we cut our string into bytes, conversion to c_char is correct, as C will compare bit value - let fd = unsafe{ crate::osal::ffi::hw_device_open(path.as_bytes().as_ptr() as *const core::ffi::c_char, path.as_bytes().len())}; + let fd = unsafe { + crate::osal::ffi::hw_device_open( + path.as_bytes().as_ptr() as *const core::ffi::c_char, + path.as_bytes().len(), + ) + }; if fd >= 0 { Ok(Self { fd }) } else { - // revert errno conversion done by hw_device_open - let errno = -fd -1; - Err(Error::Unix(errno.into())) + // Safe: getter on os + let errno = unsafe { ffi::freertos_get_sys_error() }; + Err(Error::Os(errno.into())) } } +} - pub fn write(&mut self, data: &[u8]) { - +impl Write for HardwareInterface { + fn write(&mut self, data: &[u8]) -> Result<()> { + let written = unsafe { + ffi::write( + self.fd, + data.as_ptr() as *const core::ffi::c_void, + data.len().into(), + ) + }; + if written < 0 { + // Safe: getter on os + let errno = unsafe { ffi::freertos_get_sys_error() }; + return Err(Error::Os(errno.into())); + } else { + let Ok(written_unsigned) = written.try_into() else { + // we are in written >=0, this should never happen + return Err(Error::InternalError); + }; + if written_unsigned < data.len() { + return Err(Error::IncompleteWrite(written_unsigned)); + } else { + return Ok(()); + } + } } -} \ No newline at end of file +} + +impl Read for HardwareInterface { + fn read<'a>(&self, buffer: &'a [u8]) -> Result<&'a [u8]> { + // Safe as we trust the OS + let read = unsafe { + ffi::read( + self.fd, + buffer.as_ptr() as *const core::ffi::c_void, + buffer.len().into(), + ) + }; + if read < 0 { + // Safe: getter on os + let errno = unsafe { ffi::freertos_get_sys_error() }; + let error = errno.into(); + if error == OsError::ResourceTemporarilyUnavailable { + // non blocking call returned + return Ok(&[]); + } + return Err(Error::Os(error)); + } else { + let Ok(read_unsigned) = read.try_into() else { + // we are in read >=0, this should never happen + return Err(Error::InternalError); + }; + Ok(&buffer[..read_unsigned]) + } + } +} diff --git a/mission_rust/src/fsrc/sif.rs b/mission_rust/src/fsrc/sif.rs index 0641902..8d9074e 100644 --- a/mission_rust/src/fsrc/sif.rs +++ b/mission_rust/src/fsrc/sif.rs @@ -76,7 +76,7 @@ macro_rules! sifln { writeln!(Stdout {}); ); ($($arg:tt)*) => ( - let _alwaysok = writeln!(crate::fsrc::sif::Stdout {}, $($arg)*); + {let _alwaysok = writeln!(crate::fsrc::sif::Stdout {}, $($arg)*);} ); } diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 18ddc08..aee4dfa 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -16,7 +16,7 @@ use osal::{ thread, }; -use crate::fsrc::osal::io::Interface; +use crate::fsrc::osal::io::{self, HardwareInterface, Read, Write as IoWrite}; @@ -184,8 +184,30 @@ static THREAD_3: StaticReadOnceLock< fn init_task() -> ! { sifln!("Mission enter"); - sifln!("{:?}", Interface::new("debug/uart🚀")); + let interface = HardwareInterface::new("ps/uart_mtg"); + let Ok(mut interface) = interface else { + let error : io::Error = interface.err().unwrap(); + sifln!("open: {error}"); + panic!(); + }; + let buffer = [1,2,3,4]; + interface.write(&buffer).unwrap_or_else(|e| sifln!("write: {e}")); + + let mut buffer = [0u8;30]; + + let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); + sifln!("{res:?}"); + + osal::thread::current().delay(Duration::from_millis(500)); + + let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); + sifln!("{res:?}"); + + osal::thread::current().delay(Duration::from_millis(500)); + + let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); + sifln!("{res:?}"); let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); From f9aacd4c91eb95d56197ed3c29017183f07be870 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 23 Oct 2025 16:26:41 +0200 Subject: [PATCH 07/19] Removed Demo Code --- mission_rust/src/lib.rs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index aee4dfa..f4cd634 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -184,31 +184,6 @@ static THREAD_3: StaticReadOnceLock< fn init_task() -> ! { sifln!("Mission enter"); - let interface = HardwareInterface::new("ps/uart_mtg"); - let Ok(mut interface) = interface else { - let error : io::Error = interface.err().unwrap(); - sifln!("open: {error}"); - panic!(); - }; - - let buffer = [1,2,3,4]; - interface.write(&buffer).unwrap_or_else(|e| sifln!("write: {e}")); - - let mut buffer = [0u8;30]; - - let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); - sifln!("{res:?}"); - - osal::thread::current().delay(Duration::from_millis(500)); - - let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); - sifln!("{res:?}"); - - osal::thread::current().delay(Duration::from_millis(500)); - - let res = interface.read(&mut buffer).unwrap_or_else(|e| {sifln!("read: {e}"); &[]}); - sifln!("{res:?}"); - let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); let receiver = RECEIVER.take().unwrap(); From f8dbe305d68ab483d3deb1703a2ea67c6c4307ad Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 23 Oct 2025 18:13:14 +0200 Subject: [PATCH 08/19] DH Debugger --- mission_rust/src/dh.rs | 35 ++++++++++++ mission_rust/src/fsrc/dh/debug.rs | 94 +++++++++++++++++++++++++++++++ mission_rust/src/fsrc/dh/mod.rs | 25 ++++++++ mission_rust/src/fsrc/mod.rs | 3 +- mission_rust/src/lib.rs | 30 +++++++--- 5 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 mission_rust/src/dh.rs create mode 100644 mission_rust/src/fsrc/dh/debug.rs create mode 100644 mission_rust/src/fsrc/dh/mod.rs diff --git a/mission_rust/src/dh.rs b/mission_rust/src/dh.rs new file mode 100644 index 0000000..97940a1 --- /dev/null +++ b/mission_rust/src/dh.rs @@ -0,0 +1,35 @@ +use crate::fsrc::dh::DeviceCom; + +pub struct EchoHandler { + pub buffer: [u8; 10], +} + +#[derive(Debug, Copy, Clone)] +pub struct Command(pub u8); + +#[derive(Debug, Copy, Clone)] +pub struct Reply(pub u8); + +impl DeviceCom for EchoHandler { + type DeviceCommand = Command; + type DeviceReply = Reply; + + fn get_rx_buffer(&mut self) -> &mut [u8] { + &mut self.buffer + } + + fn build_command<'a>(command: Self::DeviceCommand, tx_buffer: &'a mut [u8]) -> &'a [u8] { + tx_buffer[0] = command.0; + &tx_buffer[0..1] + } + + fn parse_device_reply_and_return_remainder<'a>( + data: &'a [u8], + ) -> (Option, &'a [u8]) { + if data.len() == 0 { + return (None, data); + } + + (Some(Reply(data[0])), &data[1..]) + } +} diff --git a/mission_rust/src/fsrc/dh/debug.rs b/mission_rust/src/fsrc/dh/debug.rs new file mode 100644 index 0000000..8af36e0 --- /dev/null +++ b/mission_rust/src/fsrc/dh/debug.rs @@ -0,0 +1,94 @@ +use core::time::Duration; +use core::fmt::Write; + + +use crate::{fsrc::{ + dh::DeviceCom, + osal::{ + self, + io::{HardwareInterface, Read, Write as DeviceWrite}, + }, +}, sifln}; + +pub enum Error { + IoError(osal::io::Error), +} + +impl From for Error { + fn from(value: osal::io::Error) -> Self { + Self::IoError(value) + } +} + +type Result = core::result::Result; + +pub struct DeviceHandlerDebugger<'a, T: DeviceCom> { + implementation: T, + init_commands: &'a [::DeviceCommand], + periodic_commands: &'a [::DeviceCommand], + wait_until_read: Duration, + wait_after_read: Duration, + interface: HardwareInterface, +} + +impl<'a, T: DeviceCom> DeviceHandlerDebugger<'a, T> { + pub fn new( + handler: T, + interface: HardwareInterface, + init_commands: &'a [::DeviceCommand], + periodic_commands: &'a [::DeviceCommand], + period: Duration, + mut read_percentage: f32, + ) -> Self { + if read_percentage > 1.0 { + read_percentage = 1.0; + } + + let period_ms = period.as_millis() as f32; + let wait_until_read_ms = period_ms * read_percentage; + let wait_until_read_ms = wait_until_read_ms as u32; + let period_ms = period_ms as u32; + let wait_after_read_ms = period_ms - wait_until_read_ms; + + let wait_until_read = Duration::from_millis(wait_until_read_ms as u64); + let wait_after_read = Duration::from_millis(wait_after_read_ms as u64); + + Self { + implementation: handler, + interface, + init_commands, + periodic_commands, + wait_until_read, + wait_after_read, + } + } + + fn run_one_iteration(&mut self, command: T::DeviceCommand) -> Result<()> { + let tx_buffer = self.implementation.get_tx_buffer(); + let binary_command = T::build_command(command, tx_buffer); + self.interface.write(binary_command)?; + sifln!("sent {binary_command:?}"); + osal::thread::current().delay(self.wait_until_read); + let rx_buffer = self.implementation.get_rx_buffer(); + let rx_buffer = self.interface.read(rx_buffer)?; + let (reply,remainder) = T::parse_device_reply_and_return_remainder(rx_buffer); + sifln!("got reply: {reply:?}, remainder {remainder:?}"); + osal::thread::current().delay(self.wait_after_read); + Ok(()) + } + + pub fn run(&mut self) -> Result<()> { + for command in self.init_commands.iter() { + self.run_one_iteration(*command)?; + } + + if self.periodic_commands.len() == 0 { + return Ok(()); + } + loop { + for command in self.periodic_commands.iter() { + self.run_one_iteration(*command)?; + } + } + } +} diff --git a/mission_rust/src/fsrc/dh/mod.rs b/mission_rust/src/fsrc/dh/mod.rs new file mode 100644 index 0000000..4f94d1a --- /dev/null +++ b/mission_rust/src/fsrc/dh/mod.rs @@ -0,0 +1,25 @@ +pub mod debug; + +use core::fmt::Debug; + + +pub trait DeviceCom{ + type DeviceCommand: Copy + Debug; + type DeviceReply: Copy + Debug; + + fn build_command<'a>(command: Self::DeviceCommand, tx_buffer: &'a mut [u8]) -> &'a [u8]; + + fn get_rx_buffer(&mut self) -> & mut [u8]; + + fn get_tx_buffer(&mut self) -> &mut [u8] { + self.get_rx_buffer() + } + + fn parse_device_reply_and_return_remainder<'a>( + data: &'a [u8], + ) -> (Option, &'a [u8]); + + // Advance State Machine? + // Write into Datapool + // fn handle_reply(&mut self, reply: Self::DeviceReply); +} \ No newline at end of file diff --git a/mission_rust/src/fsrc/mod.rs b/mission_rust/src/fsrc/mod.rs index 4c8f4fd..105141b 100644 --- a/mission_rust/src/fsrc/mod.rs +++ b/mission_rust/src/fsrc/mod.rs @@ -8,4 +8,5 @@ pub mod osal; //pub mod datasets; //pub mod store; //pub mod mutex; -pub mod introspection; \ No newline at end of file +pub mod introspection; +pub mod dh; \ No newline at end of file diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index f4cd634..32e9aec 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -2,23 +2,27 @@ #![feature(never_type)] //TODO os errors in API calls +mod dh; pub mod fsrc; mod panic; - -use core::time::Duration; use core::fmt::Write; +use core::time::Duration; use fsrc::*; use osal::{ - sync::{Mutex, MutexClone, StaticInit, StaticReadOnceLock}, queue::{MessageQueue, MessageQueueSender}, + sync::{Mutex, MutexClone, StaticInit, StaticReadOnceLock}, thread, }; -use crate::fsrc::osal::io::{self, HardwareInterface, Read, Write as IoWrite}; - - +use crate::{ + dh::EchoHandler, + fsrc::{ + dh::debug::DeviceHandlerDebugger, + osal::io::{self, HardwareInterface, Read, Write as IoWrite}, + }, +}; static THREAD_INIT: StaticReadOnceLock< thread::StaticThread<{ thread::Sizes::MINIMAL_STACK_SIZE + 2024 }>, @@ -184,6 +188,18 @@ static THREAD_3: StaticReadOnceLock< 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("ps/uart_mtg").unwrap(), + &commands, + &[], + Duration::from_secs(2), + 0.5, + ); + + debugger.run(); + let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); let receiver = RECEIVER.take().unwrap(); @@ -198,8 +214,6 @@ fn init_task() -> ! { test2.run(mutex_copy, a); }); - - THREAD_1.take_no_init().unwrap().spawn(move || { test1.run(); sender.run(clone); From a5267b11bf0a93d35920a4933888498bcb649571 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 24 Oct 2025 14:23:35 +0200 Subject: [PATCH 09/19] reworked OsError --- mission_rust/src/fsrc/dh/debug.rs | 1 + mission_rust/src/fsrc/osal/error.rs | 764 ++++----------------- mission_rust/src/fsrc/osal/error/linux.rs | 425 ++++++++++++ mission_rust/src/fsrc/osal/error/newlib.rs | 414 +++++++++++ mission_rust/src/fsrc/osal/io.rs | 3 +- mission_rust/src/lib.rs | 2 +- 6 files changed, 980 insertions(+), 629 deletions(-) create mode 100644 mission_rust/src/fsrc/osal/error/linux.rs create mode 100644 mission_rust/src/fsrc/osal/error/newlib.rs diff --git a/mission_rust/src/fsrc/dh/debug.rs b/mission_rust/src/fsrc/dh/debug.rs index 8af36e0..6eb7d24 100644 --- a/mission_rust/src/fsrc/dh/debug.rs +++ b/mission_rust/src/fsrc/dh/debug.rs @@ -10,6 +10,7 @@ use crate::{fsrc::{ }, }, sifln}; +#[derive(Debug)] pub enum Error { IoError(osal::io::Error), } diff --git a/mission_rust/src/fsrc/osal/error.rs b/mission_rust/src/fsrc/osal/error.rs index c9a7d1a..af67ce1 100644 --- a/mission_rust/src/fsrc/osal/error.rs +++ b/mission_rust/src/fsrc/osal/error.rs @@ -1,651 +1,161 @@ -use core::fmt; - use crate::fsrc::osal::ffi; -// wrap helper shim +// wrap helper shim, we use c to call errno to make sure we do it right pub fn errno() -> i32 { unsafe { ffi::freertos_get_sys_error() } } -#[cfg(target_os = "linux")] -mod libc { - // We assume a gnu x86_64: - use core::ffi::c_int; - pub const EPERM: c_int = 1; - pub const ENOENT: c_int = 2; - pub const ESRCH: c_int = 3; - pub const EINTR: c_int = 4; - pub const EIO: c_int = 5; - pub const ENXIO: c_int = 6; - pub const E2BIG: c_int = 7; - pub const ENOEXEC: c_int = 8; - pub const EBADF: c_int = 9; - pub const ECHILD: c_int = 10; - pub const EAGAIN: c_int = 11; - //pub const EWOULDBLOCK: c_int = 11; - pub const ENOMEM: c_int = 12; - pub const EACCES: c_int = 13; - pub const EFAULT: c_int = 14; - pub const ENOTBLK: c_int = 15; - pub const EBUSY: c_int = 16; - pub const EEXIST: c_int = 17; - pub const EXDEV: c_int = 18; - pub const ENODEV: c_int = 19; - pub const ENOTDIR: c_int = 20; - pub const EISDIR: c_int = 21; - pub const EINVAL: c_int = 22; - pub const ENFILE: c_int = 23; - pub const EMFILE: c_int = 24; - pub const ENOTTY: c_int = 25; - pub const ETXTBSY: c_int = 26; - pub const EFBIG: c_int = 27; - pub const ENOSPC: c_int = 28; - pub const ESPIPE: c_int = 29; - pub const EROFS: c_int = 30; - pub const EMLINK: c_int = 31; - pub const EPIPE: c_int = 32; - pub const EDOM: c_int = 33; - pub const ERANGE: c_int = 34; - pub const EDEADLOCK: c_int = 35; - pub const ENAMETOOLONG: c_int = 36; - pub const ENOLCK: c_int = 37; - pub const ENOSYS: c_int = 38; - pub const ENOTEMPTY: c_int = 39; - pub const ELOOP: c_int = 40; - pub const ENOMSG: c_int = 42; - pub const EIDRM: c_int = 43; - pub const ECHRNG: c_int = 44; - pub const ELNRNG: c_int = 48; - pub const EUNATCH: c_int = 49; - pub const ENOCSI: c_int = 50; - pub const EBADE: c_int = 52; - pub const EBADR: c_int = 53; - pub const EXFULL: c_int = 54; - pub const ENOANO: c_int = 55; - pub const EBADRQC: c_int = 56; - pub const EBADSLT: c_int = 57; - pub const EBFONT: c_int = 59; - pub const ENOSTR: c_int = 60; - pub const ENODATA: c_int = 61; - pub const ETIME: c_int = 62; - pub const ENOSR: c_int = 63; - pub const ENONET: c_int = 64; - pub const ENOPKG: c_int = 65; - pub const EREMOTE: c_int = 66; - pub const ENOLINK: c_int = 67; - pub const EADV: c_int = 68; - pub const ESRMNT: c_int = 69; - pub const ECOMM: c_int = 70; - pub const EPROTO: c_int = 71; - pub const EMULTIHOP: c_int = 72; - pub const EDOTDOT: c_int = 73; - pub const EBADMSG: c_int = 74; - pub const EOVERFLOW: c_int = 75; - pub const ENOTUNIQ: c_int = 76; - pub const EBADFD: c_int = 77; - pub const EREMCHG: c_int = 78; - pub const ELIBACC: c_int = 79; - pub const ELIBBAD: c_int = 80; - pub const ELIBSCN: c_int = 81; - pub const ELIBMAX: c_int = 82; - pub const ELIBEXEC: c_int = 83; - pub const EILSEQ: c_int = 84; - pub const ERESTART: c_int = 85; - pub const ESTRPIPE: c_int = 86; - pub const EUSERS: c_int = 87; - pub const ENOTSOCK: c_int = 88; - pub const EDESTADDRREQ: c_int = 89; - pub const EMSGSIZE: c_int = 90; - pub const EPROTOTYPE: c_int = 91; - pub const ENOPROTOOPT: c_int = 92; - pub const EPROTONOSUPPORT: c_int = 93; - pub const ESOCKTNOSUPPORT: c_int = 94; - pub const EOPNOTSUPP: c_int = 95; - pub const EPFNOSUPPORT: c_int = 96; - pub const EAFNOSUPPORT: c_int = 97; - pub const EADDRINUSE: c_int = 98; - pub const EADDRNOTAVAIL: c_int = 99; - pub const ENETDOWN: c_int = 100; - pub const ENETUNREACH: c_int = 101; - pub const ENETRESET: c_int = 102; - pub const ECONNABORTED: c_int = 103; - pub const ECONNRESET: c_int = 104; - pub const ENOBUFS: c_int = 105; - pub const EISCONN: c_int = 106; - pub const ENOTCONN: c_int = 107; - pub const ESHUTDOWN: c_int = 108; - pub const ETOOMANYREFS: c_int = 109; - pub const ETIMEDOUT: c_int = 110; - pub const ECONNREFUSED: c_int = 111; - pub const EHOSTDOWN: c_int = 112; - pub const EHOSTUNREACH: c_int = 113; - pub const EALREADY: c_int = 114; - pub const EINPROGRESS: c_int = 115; - pub const ESTALE: c_int = 116; - pub const EUCLEAN: c_int = 117; - pub const ENOTNAM: c_int = 118; - pub const ENAVAIL: c_int = 119; - pub const EISNAM: c_int = 120; - pub const EREMOTEIO: c_int = 121; - pub const EDQUOT: c_int = 122; - pub const ENOMEDIUM: c_int = 123; - pub const EMEDIUMTYPE: c_int = 124; - pub const ECANCELED: c_int = 125; - pub const ENOKEY: c_int = 126; - pub const EKEYEXPIRED: c_int = 127; - pub const EKEYREVOKED: c_int = 128; - pub const EKEYREJECTED: c_int = 129; - pub const EOWNERDEAD: c_int = 130; - pub const ENOTRECOVERABLE: c_int = 131; - pub const ERFKILL: c_int = 132; - pub const EHWPOISON: c_int = 133; -} - -#[cfg(target_env = "newlib")] -mod libc { - // taken from rust-lang/libc/src/unix/newlib/mod.rs - use core::ffi::c_int; - pub const EPERM: c_int = 1; - pub const ENOENT: c_int = 2; - pub const ESRCH: c_int = 3; - pub const EINTR: c_int = 4; - pub const EIO: c_int = 5; - pub const ENXIO: c_int = 6; - pub const E2BIG: c_int = 7; - pub const ENOEXEC: c_int = 8; - pub const EBADF: c_int = 9; - pub const ECHILD: c_int = 10; - pub const EAGAIN: c_int = 11; - pub const ENOMEM: c_int = 12; - pub const EACCES: c_int = 13; - pub const EFAULT: c_int = 14; - pub const EBUSY: c_int = 16; - pub const EEXIST: c_int = 17; - pub const EXDEV: c_int = 18; - pub const ENODEV: c_int = 19; - pub const ENOTDIR: c_int = 20; - pub const EISDIR: c_int = 21; - pub const EINVAL: c_int = 22; - pub const ENFILE: c_int = 23; - pub const EMFILE: c_int = 24; - pub const ENOTTY: c_int = 25; - pub const ETXTBSY: c_int = 26; - pub const EFBIG: c_int = 27; - pub const ENOSPC: c_int = 28; - pub const ESPIPE: c_int = 29; - pub const EROFS: c_int = 30; - pub const EMLINK: c_int = 31; - pub const EPIPE: c_int = 32; - pub const EDOM: c_int = 33; - pub const ERANGE: c_int = 34; - pub const ENOMSG: c_int = 35; - pub const EIDRM: c_int = 36; - pub const EDEADLK: c_int = 45; - pub const ENOLCK: c_int = 46; - pub const ENOSTR: c_int = 60; - pub const ENODATA: c_int = 61; - pub const ETIME: c_int = 62; - pub const ENOSR: c_int = 63; - pub const ENOLINK: c_int = 67; - pub const EPROTO: c_int = 71; - pub const EMULTIHOP: c_int = 74; - pub const EBADMSG: c_int = 77; - pub const EFTYPE: c_int = 79; - pub const ENOSYS: c_int = 88; - pub const ENOTEMPTY: c_int = 90; - pub const ENAMETOOLONG: c_int = 91; - pub const ELOOP: c_int = 92; - pub const EOPNOTSUPP: c_int = 95; - pub const EPFNOSUPPORT: c_int = 96; - pub const ECONNRESET: c_int = 104; - pub const ENOBUFS: c_int = 105; - pub const EAFNOSUPPORT: c_int = 106; - pub const EPROTOTYPE: c_int = 107; - pub const ENOTSOCK: c_int = 108; - pub const ENOPROTOOPT: c_int = 109; - pub const ECONNREFUSED: c_int = 111; - pub const EADDRINUSE: c_int = 112; - pub const ECONNABORTED: c_int = 113; - pub const ENETUNREACH: c_int = 114; - pub const ENETDOWN: c_int = 115; - pub const ETIMEDOUT: c_int = 116; - pub const EHOSTDOWN: c_int = 117; - pub const EHOSTUNREACH: c_int = 118; - pub const EINPROGRESS: c_int = 119; - pub const EALREADY: c_int = 120; - pub const EDESTADDRREQ: c_int = 121; - pub const EMSGSIZE: c_int = 122; - pub const EPROTONOSUPPORT: c_int = 123; - pub const EADDRNOTAVAIL: c_int = 125; - pub const ENETRESET: c_int = 126; - pub const EISCONN: c_int = 127; - pub const ENOTCONN: c_int = 128; - pub const ETOOMANYREFS: c_int = 129; - pub const EDQUOT: c_int = 132; - pub const ESTALE: c_int = 133; - pub const ENOTSUP: c_int = 134; - pub const EILSEQ: c_int = 138; - pub const EOVERFLOW: c_int = 139; - pub const ECANCELED: c_int = 140; - pub const ENOTRECOVERABLE: c_int = 141; - pub const EOWNERDEAD: c_int = 142; - pub const EWOULDBLOCK: c_int = 11; -} - -#[derive(Debug, PartialEq)] +// This is a merge of newlib and x86_64-glibc-linux +#[derive(Debug,PartialEq)] pub enum OsError { - OperationNotPermitted, - NoSuchFileOrDirectory, - NoSuchProcess, - InterruptedSystemCall, - InputOutputError, - NoSuchDeviceOrAddress, ArgumentListTooLong, - ExecFormatError, - BadFileDescriptor, - NoChildProcesses, - ResourceTemporarilyUnavailable, - CannotAllocateMemory, PermissionDenied, - BadAddress, - BlockDeviceRequired, - DeviceOrResourceBusy, - FileExists, - InvalidCrossDeviceLink, - NoSuchDevice, - NotADirectory, - IsADirectory, - InvalidArgument, - TooManyOpenFilesInSystem, - TooManyOpenFiles, - InappropriateIoctlForDevice, - TextFileBusy, - FileTooLarge, - NoSpaceLeftOnDevice, - IllegalSeek, - ReadOnlyFileSystem, - TooManyLinks, - BrokenPipe, - NumericalArgumentOutOfDomain, - NumericalResultOutOfRange, - ResourceDeadlockAvoided, - FileNameTooLong, - NoLocksAvailable, - FunctionNotImplemented, - DirectoryNotEmpty, - TooManyLevelsOfSymbolicLinks, - NoMessageOfDesiredType, - IdentifierRemoved, - ChannelNumberOutOfRange, - LinkNumberOutOfRange, - ProtocolDriverNotAttached, - NoCsiStructureAvailable, + AddressAlreadyInUse, + AddressNotAvailable, + AdvertiseError, + AddressFamilyNotSupportedByProtocol, + OperationWouldBlock, + OperationAlreadyInProgress, InvalidExchange, + BadFileDescriptor, + FileDescriptorInBadState, + BadMessage, InvalidRequestDescriptor, - ExchangeFull, - NoAnode, InvalidRequestCode, InvalidSlot, BadFontFileFormat, - DeviceNotAStream, - NoDataAvailable, - TimerExpired, - OutOfStreamsResources, - MachineIsNotOnTheNetwork, - PackageNotInstalled, - ObjectIsRemote, - LinkHasBeenSevered, - AdvertiseError, - SrmountError, + DeviceOrResourceBusy, + OperationCanceled, + FilenameExistsWithDifferentCase, + NoChildProcesses, + ChannelNumberOutOfRange, CommunicationErrorOnSend, - ProtocolError, - MultihopAttempted, - RfsSpecificError, - BadMessage, - ValueTooLargeForDefinedDataType, - NameNotUniqueOnNetwork, - FileDescriptorInBadState, - RemoteAddressChanged, - CanNotAccessANeededSharedLibrary, - AccessingACorruptedSharedLibrary, - LibSectionCorrupted, - AttemptingToLinkInTooManySharedLibraries, - CannotExecASharedLibraryDirectly, - InvalidOrIncompleteMultibyteOrWideCharacter, - InterruptedSystemCallShouldBeRestarted, - StreamsPipeError, - TooManyUsers, - SocketOperationOnNonSocket, - DestinationAddressRequired, - MessageTooLong, - ProtocolWrongTypeForSocket, - ProtocolNotAvailable, - ProtocolNotSupported, - SocketTypeNotSupported, - OperationNotSupported, - ProtocolFamilyNotSupported, - AddressFamilyNotSupportedByProtocol, - AddressAlreadyInUse, - CannotAssignRequestedAddress, - NetworkIsDown, - NetworkIsUnreachable, - NetworkDroppedConnectionOnReset, SoftwareCausedConnectionAbort, - ConnectionResetByPeer, - NoBufferSpaceAvailable, - TransportEndpointIsAlreadyConnected, - TransportEndpointIsNotConnected, - CannotSendAfterTransportEndpointShutdown, - TooManyReferencesCannotSplice, - ConnectionTimedOut, ConnectionRefused, + ConnectionResetByPeer, + Deadlock, + DestinationAddressRequired, + NumericalArgumentOutOfDomain, + FsError, + DiskQuotaExceeded, + FileExists, + BadAddress, + FileTooLarge, + InappropriateFileTypeOrFormat, HostIsDown, NoRouteToHost, - OperationAlreadyInProgress, - OperationNowInProgress, - StaleFileHandle, - StructureNeedsCleaning, - NotAXenixNamedTypeFile, - NoXenixSemaphoresAvailable, - IsANamedTypeFile, - RemoteIOError, - DiskQuotaExceeded, - NoMediumFound, - WrongMediumType, - OperationCanceled, - RequiredKeyNotAvailable, - KeyHasExpired, - KeyHasBeenRevoked, - KeyWasRejectedByService, - OwnerDied, - StateNotRecoverable, - OperationNotPossibleDueToRfKill, MemoryPageHasHardwareError, + IdentifierRemoved, + InvalidOrIncompleteMultibyteOrWideCharacter, + OperationNowInProgress, + InterruptedSystemCall, + InvalidArgument, + InputOutputError, + TransportEndpointIsAlreadyConnected, + IsADirectory, + IsANamedTypeFile, + KeyHasExpired, + KeyWasRejectedByService, + KeyHasBeenRevoked, + Level2Halted, + Level2NotSynchronized, + Level3Halted, + Level3Reset, + InodeIsRemote, + CanNotAccessANeededSharedLibrary, + AccessingACorruptedSharedLibrary, + CannotExecASharedLibraryDirectly, + AttemptingToLinkInTooManySharedLibraries, + LibSectionInAOutCorrupted, + LinkNumberOutOfRange, + TooManySymbolicLinks, + WrongMediumType, + TooManyOpenFiles, + TooManyLinks, + MessageTooLong, + MultihopAttempted, + FileNameTooLong, + NoXenixSemaphoresAvailable, + NetworkIsDown, + NetworkDroppedConnectionOnReset, + HostIsUnreachable, + TooManyOpenFilesInSystem, + NoMoreFiles, + NoAnode, + NoBufferSpaceAvailable, + NoCsiStructureAvailable, + NoDataAvailable, + NoSuchDevice, + NoSuchFileOrDirectory, + ExecFormatError, + RequiredKeyNotAvailable, + NoLocksAvailable, + LinkHasBeenSevered, + NoMediumFound, + CannotAllocateMemory, + NoMessageOfDesiredType, + MachineIsNotOnTheNetwork, + PackageNotInstalled, + ProtocolNotAvailable, + NoShare, + NoSpaceLeftOnDevice, + OutOfStreamsResources, + DeviceNotAStream, + FunctionNotImplemented, + BlockDeviceRequired, + TransportEndpointIsNotConnected, + NotADirectory, + DirectoryNotEmpty, + NotAXenixNamedTypeFile, + StateNotRecoverable, + SocketOperationOnNonSocket, + OperationNotSupported, + NotACharacterDevice, + NameNotUniqueOnNetwork, + NoSuchDeviceOrAddress, + ValueTooLargeForDefinedDataType, + OwnerDied, + OperationNotPermitted, + ProtocolFamilyNotSupported, + BrokenPipe, + LimitOnNewProcessesReached, + ProtocolError, + ProtocolNotSupported, + ProtocolWrongTypeForSocket, + NumericalResultOutOfRange, + RemoteAddressChanged, + ObjectIsRemote, + RemoteIOError, + InterruptedSystemCallShouldBeRestarted, + OperationNotPossibleDueToRfKill, + ReadOnlyFileSystem, + CannotSendAfterShutdown, + SocketTypeNotSupported, + IllegalSeek, + NoSuchProcess, + SrmountError, + StaleFileHandle, + StreamsPipeError, + TimerExpired, + ConnectionTimedOut, + TooManyReferencesCannotSplice, + TextFileBusy, + StructureNeedsCleaning, + ProtocolDriverNotAttached, + TooManyUsers, + InvalidCrossDeviceLink, + ExchangeFull, Other(i32), } -impl From for OsError { - fn from(value: i32) -> Self { - use crate::osal::io::OsError::*; - match value { - libc::EPERM => OperationNotPermitted, - libc::ENOENT => NoSuchFileOrDirectory, - libc::ESRCH => NoSuchProcess, - libc::EINTR => InterruptedSystemCall, - libc::EIO => InputOutputError, - libc::ENXIO => NoSuchDeviceOrAddress, - libc::E2BIG => ArgumentListTooLong, - libc::ENOEXEC => ExecFormatError, - libc::EBADF => BadFileDescriptor, - libc::ECHILD => NoChildProcesses, - libc::EAGAIN => ResourceTemporarilyUnavailable, - //libc::EWOULDBLOCK => ResourceTemporarilyUnavailable, == EAGAIN - libc::ENOMEM => CannotAllocateMemory, - libc::EACCES => PermissionDenied, - libc::EFAULT => BadAddress, - libc::ENOTBLK => BlockDeviceRequired, - libc::EBUSY => DeviceOrResourceBusy, - libc::EEXIST => FileExists, - libc::EXDEV => InvalidCrossDeviceLink, - libc::ENODEV => NoSuchDevice, - libc::ENOTDIR => NotADirectory, - libc::EISDIR => IsADirectory, - libc::EINVAL => InvalidArgument, - libc::ENFILE => TooManyOpenFilesInSystem, - libc::EMFILE => TooManyOpenFiles, - libc::ENOTTY => InappropriateIoctlForDevice, - libc::ETXTBSY => TextFileBusy, - libc::EFBIG => FileTooLarge, - libc::ENOSPC => NoSpaceLeftOnDevice, - libc::ESPIPE => IllegalSeek, - libc::EROFS => ReadOnlyFileSystem, - libc::EMLINK => TooManyLinks, - libc::EPIPE => BrokenPipe, - libc::EDOM => NumericalArgumentOutOfDomain, - libc::ERANGE => NumericalResultOutOfRange, - libc::EDEADLOCK => ResourceDeadlockAvoided, - libc::ENAMETOOLONG => FileNameTooLong, - libc::ENOLCK => NoLocksAvailable, - libc::ENOSYS => FunctionNotImplemented, - libc::ENOTEMPTY => DirectoryNotEmpty, - libc::ELOOP => TooManyLevelsOfSymbolicLinks, - libc::ENOMSG => NoMessageOfDesiredType, - libc::EIDRM => IdentifierRemoved, - libc::ECHRNG => ChannelNumberOutOfRange, - libc::ELNRNG => LinkNumberOutOfRange, - libc::EUNATCH => ProtocolDriverNotAttached, - libc::ENOCSI => NoCsiStructureAvailable, - libc::EBADE => InvalidExchange, - libc::EBADR => InvalidRequestDescriptor, - libc::EXFULL => ExchangeFull, - libc::ENOANO => NoAnode, - libc::EBADRQC => InvalidRequestCode, - libc::EBADSLT => InvalidSlot, - libc::EBFONT => BadFontFileFormat, - libc::ENOSTR => DeviceNotAStream, - libc::ENODATA => NoDataAvailable, - libc::ETIME => TimerExpired, - libc::ENOSR => OutOfStreamsResources, - libc::ENONET => MachineIsNotOnTheNetwork, - libc::ENOPKG => PackageNotInstalled, - libc::EREMOTE => ObjectIsRemote, - libc::ENOLINK => LinkHasBeenSevered, - libc::EADV => AdvertiseError, - libc::ESRMNT => SrmountError, - libc::ECOMM => CommunicationErrorOnSend, - libc::EPROTO => ProtocolError, - libc::EMULTIHOP => MultihopAttempted, - libc::EDOTDOT => RfsSpecificError, - libc::EBADMSG => BadMessage, - libc::EOVERFLOW => ValueTooLargeForDefinedDataType, - libc::ENOTUNIQ => NameNotUniqueOnNetwork, - libc::EBADFD => FileDescriptorInBadState, - libc::EREMCHG => RemoteAddressChanged, - libc::ELIBACC => CanNotAccessANeededSharedLibrary, - libc::ELIBBAD => AccessingACorruptedSharedLibrary, - libc::ELIBSCN => LibSectionCorrupted, - libc::ELIBMAX => AttemptingToLinkInTooManySharedLibraries, - libc::ELIBEXEC => CannotExecASharedLibraryDirectly, - libc::EILSEQ => InvalidOrIncompleteMultibyteOrWideCharacter, - libc::ERESTART => InterruptedSystemCallShouldBeRestarted, - libc::ESTRPIPE => StreamsPipeError, - libc::EUSERS => TooManyUsers, - libc::ENOTSOCK => SocketOperationOnNonSocket, - libc::EDESTADDRREQ => DestinationAddressRequired, - libc::EMSGSIZE => MessageTooLong, - libc::EPROTOTYPE => ProtocolWrongTypeForSocket, - libc::ENOPROTOOPT => ProtocolNotAvailable, - libc::EPROTONOSUPPORT => ProtocolNotSupported, - libc::ESOCKTNOSUPPORT => SocketTypeNotSupported, - libc::EOPNOTSUPP => OperationNotSupported, - // libc::ENOTSUP => OperationNotSupported, == EOPNOTSUPP - libc::EPFNOSUPPORT => ProtocolFamilyNotSupported, - libc::EAFNOSUPPORT => AddressFamilyNotSupportedByProtocol, - libc::EADDRINUSE => AddressAlreadyInUse, - libc::EADDRNOTAVAIL => CannotAssignRequestedAddress, - libc::ENETDOWN => NetworkIsDown, - libc::ENETUNREACH => NetworkIsUnreachable, - libc::ENETRESET => NetworkDroppedConnectionOnReset, - libc::ECONNABORTED => SoftwareCausedConnectionAbort, - libc::ECONNRESET => ConnectionResetByPeer, - libc::ENOBUFS => NoBufferSpaceAvailable, - libc::EISCONN => TransportEndpointIsAlreadyConnected, - libc::ENOTCONN => TransportEndpointIsNotConnected, - libc::ESHUTDOWN => CannotSendAfterTransportEndpointShutdown, - libc::ETOOMANYREFS => TooManyReferencesCannotSplice, - libc::ETIMEDOUT => ConnectionTimedOut, - libc::ECONNREFUSED => ConnectionRefused, - libc::EHOSTDOWN => HostIsDown, - libc::EHOSTUNREACH => NoRouteToHost, - libc::EALREADY => OperationAlreadyInProgress, - libc::EINPROGRESS => OperationNowInProgress, - libc::ESTALE => StaleFileHandle, - libc::EUCLEAN => StructureNeedsCleaning, - libc::ENOTNAM => NotAXenixNamedTypeFile, - libc::ENAVAIL => NoXenixSemaphoresAvailable, - libc::EISNAM => IsANamedTypeFile, - libc::EREMOTEIO => RemoteIOError, - libc::EDQUOT => DiskQuotaExceeded, - libc::ENOMEDIUM => NoMediumFound, - libc::EMEDIUMTYPE => WrongMediumType, - libc::ECANCELED => OperationCanceled, - libc::ENOKEY => RequiredKeyNotAvailable, - libc::EKEYEXPIRED => KeyHasExpired, - libc::EKEYREVOKED => KeyHasBeenRevoked, - libc::EKEYREJECTED => KeyWasRejectedByService, - libc::EOWNERDEAD => OwnerDied, - libc::ENOTRECOVERABLE => StateNotRecoverable, - libc::ERFKILL => OperationNotPossibleDueToRfKill, - libc::EHWPOISON => MemoryPageHasHardwareError, - value => Other(value), - } - } -} +#[cfg(target_os = "linux")] +mod linux; -impl fmt::Display for OsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use OsError::*; - match self { - OperationNotPermitted => write!(f, "Operation not permitted"), - NoSuchFileOrDirectory => write!(f, "No such file or directory"), - NoSuchProcess => write!(f, "No such process"), - InterruptedSystemCall => write!(f, "Interrupted system call"), - InputOutputError => write!(f, "Input/output error"), - NoSuchDeviceOrAddress => write!(f, "No such device or address"), - ArgumentListTooLong => write!(f, "Argument list too long"), - ExecFormatError => write!(f, "Exec format error"), - BadFileDescriptor => write!(f, "Bad file descriptor"), - NoChildProcesses => write!(f, "No child processes"), - ResourceTemporarilyUnavailable => write!(f, "Resource temporarily unavailable"), - CannotAllocateMemory => write!(f, "Cannot allocate memory"), - PermissionDenied => write!(f, "Permission denied"), - BadAddress => write!(f, "Bad address"), - BlockDeviceRequired => write!(f, "Block device required"), - DeviceOrResourceBusy => write!(f, "Device or resource busy"), - FileExists => write!(f, "File exists"), - InvalidCrossDeviceLink => write!(f, "Invalid cross-device link"), - NoSuchDevice => write!(f, "No such device"), - NotADirectory => write!(f, "Not a directory"), - IsADirectory => write!(f, "Is a directory"), - InvalidArgument => write!(f, "Invalid argument"), - TooManyOpenFilesInSystem => write!(f, "Too many open files in system"), - TooManyOpenFiles => write!(f, "Too many open files"), - InappropriateIoctlForDevice => write!(f, "Inappropriate ioctl for device"), - TextFileBusy => write!(f, "Text file busy"), - FileTooLarge => write!(f, "File too large"), - NoSpaceLeftOnDevice => write!(f, "No space left on device"), - IllegalSeek => write!(f, "Illegal seek"), - ReadOnlyFileSystem => write!(f, "Read-only file system"), - TooManyLinks => write!(f, "Too many links"), - BrokenPipe => write!(f, "Broken pipe"), - NumericalArgumentOutOfDomain => write!(f, "Numerical argument out of domain"), - NumericalResultOutOfRange => write!(f, "Numerical result out of range"), - ResourceDeadlockAvoided => write!(f, "Resource deadlock avoided"), - FileNameTooLong => write!(f, "File name too long"), - NoLocksAvailable => write!(f, "No locks available"), - FunctionNotImplemented => write!(f, "Function not implemented"), - DirectoryNotEmpty => write!(f, "Directory not empty"), - TooManyLevelsOfSymbolicLinks => write!(f, "Too many levels of symbolic links"), - NoMessageOfDesiredType => write!(f, "No message of desired type"), - IdentifierRemoved => write!(f, "Identifier removed"), - ChannelNumberOutOfRange => write!(f, "Channel number out of range"), - LinkNumberOutOfRange => write!(f, "Link number out of range"), - ProtocolDriverNotAttached => write!(f, "Protocol driver not attached"), - NoCsiStructureAvailable => write!(f, "No CSI structure available"), - InvalidExchange => write!(f, "Invalid exchange"), - InvalidRequestDescriptor => write!(f, "Invalid request descriptor"), - ExchangeFull => write!(f, "Exchange full"), - NoAnode => write!(f, "No anode"), - InvalidRequestCode => write!(f, "Invalid request code"), - InvalidSlot => write!(f, "Invalid slot"), - BadFontFileFormat => write!(f, "Bad font file format"), - DeviceNotAStream => write!(f, "Device not a stream"), - NoDataAvailable => write!(f, "No data available"), - TimerExpired => write!(f, "Timer expired"), - OutOfStreamsResources => write!(f, "Out of streams resources"), - MachineIsNotOnTheNetwork => write!(f, "Machine is not on the network"), - PackageNotInstalled => write!(f, "Package not installed"), - ObjectIsRemote => write!(f, "Object is remote"), - LinkHasBeenSevered => write!(f, "Link has been severed"), - AdvertiseError => write!(f, "Advertise error"), - SrmountError => write!(f, "Srmount error"), - CommunicationErrorOnSend => write!(f, "Communication error on send"), - ProtocolError => write!(f, "Protocol error"), - MultihopAttempted => write!(f, "Multihop attempted"), - RfsSpecificError => write!(f, "RFS specific error"), - BadMessage => write!(f, "Bad message"), - ValueTooLargeForDefinedDataType => write!(f, "Value too large for defined data type"), - NameNotUniqueOnNetwork => write!(f, "Name not unique on network"), - FileDescriptorInBadState => write!(f, "File descriptor in bad state"), - RemoteAddressChanged => write!(f, "Remote address changed"), - CanNotAccessANeededSharedLibrary => write!(f, "Can not access a needed shared library"), - AccessingACorruptedSharedLibrary => write!(f, "Accessing a corrupted shared library"), - LibSectionCorrupted => write!(f, ".lib section in a.out corrupted"), - AttemptingToLinkInTooManySharedLibraries => { - write!(f, "Attempting to link in too many shared libraries") - } - CannotExecASharedLibraryDirectly => write!(f, "Cannot exec a shared library directly"), - InvalidOrIncompleteMultibyteOrWideCharacter => { - write!(f, "Invalid or incomplete multibyte or wide character") - } - InterruptedSystemCallShouldBeRestarted => { - write!(f, "Interrupted system call should be restarted") - } - StreamsPipeError => write!(f, "Streams pipe error"), - TooManyUsers => write!(f, "Too many users"), - SocketOperationOnNonSocket => write!(f, "Socket operation on non-socket"), - DestinationAddressRequired => write!(f, "Destination address required"), - MessageTooLong => write!(f, "Message too long"), - ProtocolWrongTypeForSocket => write!(f, "Protocol wrong type for socket"), - ProtocolNotAvailable => write!(f, "Protocol not available"), - ProtocolNotSupported => write!(f, "Protocol not supported"), - SocketTypeNotSupported => write!(f, "Socket type not supported"), - OperationNotSupported => write!(f, "Operation not supported"), - ProtocolFamilyNotSupported => write!(f, "Protocol family not supported"), - AddressFamilyNotSupportedByProtocol => { - write!(f, "Address family not supported by protocol") - } - AddressAlreadyInUse => write!(f, "Address already in use"), - CannotAssignRequestedAddress => write!(f, "Cannot assign requested address"), - NetworkIsDown => write!(f, "Network is down"), - NetworkIsUnreachable => write!(f, "Network is unreachable"), - NetworkDroppedConnectionOnReset => write!(f, "Network dropped connection on reset"), - SoftwareCausedConnectionAbort => write!(f, "Software caused connection abort"), - ConnectionResetByPeer => write!(f, "Connection reset by peer"), - NoBufferSpaceAvailable => write!(f, "No buffer space available"), - TransportEndpointIsAlreadyConnected => { - write!(f, "Transport endpoint is already connected") - } - TransportEndpointIsNotConnected => write!(f, "Transport endpoint is not connected"), - CannotSendAfterTransportEndpointShutdown => { - write!(f, "Cannot send after transport endpoint shutdown") - } - TooManyReferencesCannotSplice => write!(f, "Too many references: cannot splice"), - ConnectionTimedOut => write!(f, "Connection timed out"), - ConnectionRefused => write!(f, "Connection refused"), - HostIsDown => write!(f, "Host is down"), - NoRouteToHost => write!(f, "No route to host"), - OperationAlreadyInProgress => write!(f, "Operation already in progress"), - OperationNowInProgress => write!(f, "Operation now in progress"), - StaleFileHandle => write!(f, "Stale file handle"), - StructureNeedsCleaning => write!(f, "Structure needs cleaning"), - NotAXenixNamedTypeFile => write!(f, "Not a XENIX named type file"), - NoXenixSemaphoresAvailable => write!(f, "No XENIX semaphores available"), - IsANamedTypeFile => write!(f, "Is a named type file"), - RemoteIOError => write!(f, "Remote I/O error"), - DiskQuotaExceeded => write!(f, "Disk quota exceeded"), - NoMediumFound => write!(f, "No medium found"), - WrongMediumType => write!(f, "Wrong medium type"), - OperationCanceled => write!(f, "Operation canceled"), - RequiredKeyNotAvailable => write!(f, "Required key not available"), - KeyHasExpired => write!(f, "Key has expired"), - KeyHasBeenRevoked => write!(f, "Key has been revoked"), - KeyWasRejectedByService => write!(f, "Key was rejected by service"), - OwnerDied => write!(f, "Owner died"), - StateNotRecoverable => write!(f, "State not recoverable"), - OperationNotPossibleDueToRfKill => write!(f, "Operation not possible due to RF-kill"), - MemoryPageHasHardwareError => write!(f, "Memory page has hardware error"), - Other(value) => write!(f, "Other error: {}", value), - } - } -} +#[cfg(target_env = "newlib")] +mod newlib; + +// #[cfg(target_os = "linux")] +// pub use linux::*; + +// #[cfg(target_env = "newlib")] +// pub use linux::*; diff --git a/mission_rust/src/fsrc/osal/error/linux.rs b/mission_rust/src/fsrc/osal/error/linux.rs new file mode 100644 index 0000000..7847c54 --- /dev/null +++ b/mission_rust/src/fsrc/osal/error/linux.rs @@ -0,0 +1,425 @@ +use core::fmt; + +mod libc { + // taken from a glibc x86_64 linux: + use core::ffi::c_int; + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + #[allow(unused)] + pub const EWOULDBLOCK: c_int = 11; // equals EAGAIN + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const EDEADLOCK: c_int = 35; + pub const ENAMETOOLONG: c_int = 36; + pub const ENOLCK: c_int = 37; + pub const ENOSYS: c_int = 38; + pub const ENOTEMPTY: c_int = 39; + pub const ELOOP: c_int = 40; + pub const ENOMSG: c_int = 42; + pub const EIDRM: c_int = 43; + pub const ECHRNG: c_int = 44; + pub const ELNRNG: c_int = 48; + pub const EUNATCH: c_int = 49; + pub const ENOCSI: c_int = 50; + pub const EBADE: c_int = 52; + pub const EBADR: c_int = 53; + pub const EXFULL: c_int = 54; + pub const ENOANO: c_int = 55; + pub const EBADRQC: c_int = 56; + pub const EBADSLT: c_int = 57; + pub const EBFONT: c_int = 59; + pub const ENOSTR: c_int = 60; + pub const ENODATA: c_int = 61; + pub const ETIME: c_int = 62; + pub const ENOSR: c_int = 63; + pub const ENONET: c_int = 64; + pub const ENOPKG: c_int = 65; + pub const EREMOTE: c_int = 66; + pub const ENOLINK: c_int = 67; + pub const EADV: c_int = 68; + pub const ESRMNT: c_int = 69; + pub const ECOMM: c_int = 70; + pub const EPROTO: c_int = 71; + pub const EMULTIHOP: c_int = 72; + pub const EDOTDOT: c_int = 73; + pub const EBADMSG: c_int = 74; + pub const EOVERFLOW: c_int = 75; + pub const ENOTUNIQ: c_int = 76; + pub const EBADFD: c_int = 77; + pub const EREMCHG: c_int = 78; + pub const ELIBACC: c_int = 79; + pub const ELIBBAD: c_int = 80; + pub const ELIBSCN: c_int = 81; + pub const ELIBMAX: c_int = 82; + pub const ELIBEXEC: c_int = 83; + pub const EILSEQ: c_int = 84; + pub const ERESTART: c_int = 85; + pub const ESTRPIPE: c_int = 86; + pub const EUSERS: c_int = 87; + pub const ENOTSOCK: c_int = 88; + pub const EDESTADDRREQ: c_int = 89; + pub const EMSGSIZE: c_int = 90; + pub const EPROTOTYPE: c_int = 91; + pub const ENOPROTOOPT: c_int = 92; + pub const EPROTONOSUPPORT: c_int = 93; + pub const ESOCKTNOSUPPORT: c_int = 94; + pub const EOPNOTSUPP: c_int = 95; + #[allow(unused)] + pub const ENOTSUP: c_int = 95; // equals EOPNOTSUPP + pub const EPFNOSUPPORT: c_int = 96; + pub const EAFNOSUPPORT: c_int = 97; + pub const EADDRINUSE: c_int = 98; + pub const EADDRNOTAVAIL: c_int = 99; + pub const ENETDOWN: c_int = 100; + pub const ENETUNREACH: c_int = 101; + pub const ENETRESET: c_int = 102; + pub const ECONNABORTED: c_int = 103; + pub const ECONNRESET: c_int = 104; + pub const ENOBUFS: c_int = 105; + pub const EISCONN: c_int = 106; + pub const ENOTCONN: c_int = 107; + pub const ESHUTDOWN: c_int = 108; + pub const ETOOMANYREFS: c_int = 109; + pub const ETIMEDOUT: c_int = 110; + pub const ECONNREFUSED: c_int = 111; + pub const EHOSTDOWN: c_int = 112; + pub const EHOSTUNREACH: c_int = 113; + pub const EALREADY: c_int = 114; + pub const EINPROGRESS: c_int = 115; + pub const ESTALE: c_int = 116; + pub const EUCLEAN: c_int = 117; + pub const ENOTNAM: c_int = 118; + pub const ENAVAIL: c_int = 119; + pub const EISNAM: c_int = 120; + pub const EREMOTEIO: c_int = 121; + pub const EDQUOT: c_int = 122; + pub const ENOMEDIUM: c_int = 123; + pub const EMEDIUMTYPE: c_int = 124; + pub const ECANCELED: c_int = 125; + pub const ENOKEY: c_int = 126; + pub const EKEYEXPIRED: c_int = 127; + pub const EKEYREVOKED: c_int = 128; + pub const EKEYREJECTED: c_int = 129; + pub const EOWNERDEAD: c_int = 130; + pub const ENOTRECOVERABLE: c_int = 131; + pub const ERFKILL: c_int = 132; + pub const EHWPOISON: c_int = 133; +} + + +impl From for super::OsError { + fn from(value: i32) -> Self { + use super::OsError::*; + match value { + libc::EPERM => OperationNotPermitted, + libc::ENOENT => NoSuchFileOrDirectory, + libc::ESRCH => NoSuchProcess, + libc::EINTR => InterruptedSystemCall, + libc::EIO => InputOutputError, + libc::ENXIO => NoSuchDeviceOrAddress, + libc::E2BIG => ArgumentListTooLong, + libc::ENOEXEC => ExecFormatError, + libc::EBADF => BadFileDescriptor, + libc::ECHILD => NoChildProcesses, + libc::EAGAIN => OperationWouldBlock, + //libc::EWOULDBLOCK => OperationWouldBlock, == EAGAIN + libc::ENOMEM => CannotAllocateMemory, + libc::EACCES => PermissionDenied, + libc::EFAULT => BadAddress, + libc::ENOTBLK => BlockDeviceRequired, + libc::EBUSY => DeviceOrResourceBusy, + libc::EEXIST => FileExists, + libc::EXDEV => InvalidCrossDeviceLink, + libc::ENODEV => NoSuchDevice, + libc::ENOTDIR => NotADirectory, + libc::EISDIR => IsADirectory, + libc::EINVAL => InvalidArgument, + libc::ENFILE => TooManyOpenFilesInSystem, + libc::EMFILE => TooManyOpenFiles, + libc::ENOTTY => NotACharacterDevice, + libc::ETXTBSY => TextFileBusy, + libc::EFBIG => FileTooLarge, + libc::ENOSPC => NoSpaceLeftOnDevice, + libc::ESPIPE => IllegalSeek, + libc::EROFS => ReadOnlyFileSystem, + libc::EMLINK => TooManyLinks, + libc::EPIPE => BrokenPipe, + libc::EDOM => NumericalArgumentOutOfDomain, + libc::ERANGE => NumericalResultOutOfRange, + libc::EDEADLOCK => Deadlock, + libc::ENAMETOOLONG => FileNameTooLong, + libc::ENOLCK => NoLocksAvailable, + libc::ENOSYS => FunctionNotImplemented, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::ELOOP => TooManySymbolicLinks, + libc::ENOMSG => NoMessageOfDesiredType, + libc::EIDRM => IdentifierRemoved, + libc::ECHRNG => ChannelNumberOutOfRange, + libc::ELNRNG => LinkNumberOutOfRange, + libc::EUNATCH => ProtocolDriverNotAttached, + libc::ENOCSI => NoCsiStructureAvailable, + libc::EBADE => InvalidExchange, + libc::EBADR => InvalidRequestDescriptor, + libc::EXFULL => ExchangeFull, + libc::ENOANO => NoAnode, + libc::EBADRQC => InvalidRequestCode, + libc::EBADSLT => InvalidSlot, + libc::EBFONT => BadFontFileFormat, + libc::ENOSTR => DeviceNotAStream, + libc::ENODATA => NoDataAvailable, + libc::ETIME => TimerExpired, + libc::ENOSR => OutOfStreamsResources, + libc::ENONET => MachineIsNotOnTheNetwork, + libc::ENOPKG => PackageNotInstalled, + libc::EREMOTE => ObjectIsRemote, + libc::ENOLINK => LinkHasBeenSevered, + libc::EADV => AdvertiseError, + libc::ESRMNT => SrmountError, + libc::ECOMM => CommunicationErrorOnSend, + libc::EPROTO => ProtocolError, + libc::EMULTIHOP => MultihopAttempted, + libc::EDOTDOT => FsError, + libc::EBADMSG => BadMessage, + libc::EOVERFLOW => ValueTooLargeForDefinedDataType, + libc::ENOTUNIQ => NameNotUniqueOnNetwork, + libc::EBADFD => FileDescriptorInBadState, + libc::EREMCHG => RemoteAddressChanged, + libc::ELIBACC => CanNotAccessANeededSharedLibrary, + libc::ELIBBAD => AccessingACorruptedSharedLibrary, + libc::ELIBSCN => LibSectionInAOutCorrupted, + libc::ELIBMAX => AttemptingToLinkInTooManySharedLibraries, + libc::ELIBEXEC => CannotExecASharedLibraryDirectly, + libc::EILSEQ => InvalidOrIncompleteMultibyteOrWideCharacter, + libc::ERESTART => InterruptedSystemCallShouldBeRestarted, + libc::ESTRPIPE => StreamsPipeError, + libc::EUSERS => TooManyUsers, + libc::ENOTSOCK => SocketOperationOnNonSocket, + libc::EDESTADDRREQ => DestinationAddressRequired, + libc::EMSGSIZE => MessageTooLong, + libc::EPROTOTYPE => ProtocolWrongTypeForSocket, + libc::ENOPROTOOPT => ProtocolNotAvailable, + libc::EPROTONOSUPPORT => ProtocolNotSupported, + libc::ESOCKTNOSUPPORT => SocketTypeNotSupported, + libc::EOPNOTSUPP => OperationNotSupported, + // libc::ENOTSUP => OperationNotSupported, == EOPNOTSUPP + libc::EPFNOSUPPORT => ProtocolFamilyNotSupported, + libc::EAFNOSUPPORT => AddressFamilyNotSupportedByProtocol, + libc::EADDRINUSE => AddressAlreadyInUse, + libc::EADDRNOTAVAIL => AddressNotAvailable, + libc::ENETDOWN => NetworkIsDown, + libc::ENETUNREACH => HostIsUnreachable, + libc::ENETRESET => NetworkDroppedConnectionOnReset, + libc::ECONNABORTED => SoftwareCausedConnectionAbort, + libc::ECONNRESET => ConnectionResetByPeer, + libc::ENOBUFS => NoBufferSpaceAvailable, + libc::EISCONN => TransportEndpointIsAlreadyConnected, + libc::ENOTCONN => TransportEndpointIsNotConnected, + libc::ESHUTDOWN => CannotSendAfterShutdown, + libc::ETOOMANYREFS => TooManyReferencesCannotSplice, + libc::ETIMEDOUT => ConnectionTimedOut, + libc::ECONNREFUSED => ConnectionRefused, + libc::EHOSTDOWN => HostIsDown, + libc::EHOSTUNREACH => NoRouteToHost, + libc::EALREADY => OperationAlreadyInProgress, + libc::EINPROGRESS => OperationNowInProgress, + libc::ESTALE => StaleFileHandle, + libc::EUCLEAN => StructureNeedsCleaning, + libc::ENOTNAM => NotAXenixNamedTypeFile, + libc::ENAVAIL => NoXenixSemaphoresAvailable, + libc::EISNAM => IsANamedTypeFile, + libc::EREMOTEIO => RemoteIOError, + libc::EDQUOT => DiskQuotaExceeded, + libc::ENOMEDIUM => NoMediumFound, + libc::EMEDIUMTYPE => WrongMediumType, + libc::ECANCELED => OperationCanceled, + libc::ENOKEY => RequiredKeyNotAvailable, + libc::EKEYEXPIRED => KeyHasExpired, + libc::EKEYREVOKED => KeyHasBeenRevoked, + libc::EKEYREJECTED => KeyWasRejectedByService, + libc::EOWNERDEAD => OwnerDied, + libc::ENOTRECOVERABLE => StateNotRecoverable, + libc::ERFKILL => OperationNotPossibleDueToRfKill, + libc::EHWPOISON => MemoryPageHasHardwareError, + value => Other(value), + } + } +} + +impl fmt::Display for super::OsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use super::OsError::*; + match self { + OperationNotPermitted => write!(f, "Operation not permitted"), + NoSuchFileOrDirectory => write!(f, "No such file or directory"), + NoSuchProcess => write!(f, "No such process"), + InterruptedSystemCall => write!(f, "Interrupted system call"), + InputOutputError => write!(f, "Input/output error"), + NoSuchDeviceOrAddress => write!(f, "No such device or address"), + ArgumentListTooLong => write!(f, "Argument list too long"), + ExecFormatError => write!(f, "Exec format error"), + BadFileDescriptor => write!(f, "Bad file descriptor"), + NoChildProcesses => write!(f, "No child processes"), + OperationWouldBlock => write!(f, "Resource temporarily unavailable"), + CannotAllocateMemory => write!(f, "Cannot allocate memory"), + PermissionDenied => write!(f, "Permission denied"), + BadAddress => write!(f, "Bad address"), + BlockDeviceRequired => write!(f, "Block device required"), + DeviceOrResourceBusy => write!(f, "Device or resource busy"), + FileExists => write!(f, "File exists"), + InvalidCrossDeviceLink => write!(f, "Invalid cross-device link"), + NoSuchDevice => write!(f, "No such device"), + NotADirectory => write!(f, "Not a directory"), + IsADirectory => write!(f, "Is a directory"), + InvalidArgument => write!(f, "Invalid argument"), + TooManyOpenFilesInSystem => write!(f, "Too many open files in system"), + TooManyOpenFiles => write!(f, "Too many open files"), + NotACharacterDevice => write!(f, "Inappropriate ioctl for device"), + TextFileBusy => write!(f, "Text file busy"), + FileTooLarge => write!(f, "File too large"), + NoSpaceLeftOnDevice => write!(f, "No space left on device"), + IllegalSeek => write!(f, "Illegal seek"), + ReadOnlyFileSystem => write!(f, "Read-only file system"), + TooManyLinks => write!(f, "Too many links"), + BrokenPipe => write!(f, "Broken pipe"), + NumericalArgumentOutOfDomain => write!(f, "Numerical argument out of domain"), + NumericalResultOutOfRange => write!(f, "Numerical result out of range"), + Deadlock => write!(f, "Resource deadlock avoided"), + FileNameTooLong => write!(f, "File name too long"), + NoLocksAvailable => write!(f, "No locks available"), + FunctionNotImplemented => write!(f, "Function not implemented"), + DirectoryNotEmpty => write!(f, "Directory not empty"), + TooManySymbolicLinks => write!(f, "Too many levels of symbolic links"), + NoMessageOfDesiredType => write!(f, "No message of desired type"), + IdentifierRemoved => write!(f, "Identifier removed"), + ChannelNumberOutOfRange => write!(f, "Channel number out of range"), + LinkNumberOutOfRange => write!(f, "Link number out of range"), + ProtocolDriverNotAttached => write!(f, "Protocol driver not attached"), + NoCsiStructureAvailable => write!(f, "No CSI structure available"), + InvalidExchange => write!(f, "Invalid exchange"), + InvalidRequestDescriptor => write!(f, "Invalid request descriptor"), + ExchangeFull => write!(f, "Exchange full"), + NoAnode => write!(f, "No anode"), + InvalidRequestCode => write!(f, "Invalid request code"), + InvalidSlot => write!(f, "Invalid slot"), + BadFontFileFormat => write!(f, "Bad font file format"), + DeviceNotAStream => write!(f, "Device not a stream"), + NoDataAvailable => write!(f, "No data available"), + TimerExpired => write!(f, "Timer expired"), + OutOfStreamsResources => write!(f, "Out of streams resources"), + MachineIsNotOnTheNetwork => write!(f, "Machine is not on the network"), + PackageNotInstalled => write!(f, "Package not installed"), + ObjectIsRemote => write!(f, "Object is remote"), + LinkHasBeenSevered => write!(f, "Link has been severed"), + AdvertiseError => write!(f, "Advertise error"), + SrmountError => write!(f, "Srmount error"), + CommunicationErrorOnSend => write!(f, "Communication error on send"), + ProtocolError => write!(f, "Protocol error"), + MultihopAttempted => write!(f, "Multihop attempted"), + FsError => write!(f, "RFS specific error"), + BadMessage => write!(f, "Bad message"), + ValueTooLargeForDefinedDataType => write!(f, "Value too large for defined data type"), + NameNotUniqueOnNetwork => write!(f, "Name not unique on network"), + FileDescriptorInBadState => write!(f, "File descriptor in bad state"), + RemoteAddressChanged => write!(f, "Remote address changed"), + CanNotAccessANeededSharedLibrary => write!(f, "Can not access a needed shared library"), + AccessingACorruptedSharedLibrary => write!(f, "Accessing a corrupted shared library"), + LibSectionInAOutCorrupted => write!(f, ".lib section in a.out corrupted"), + AttemptingToLinkInTooManySharedLibraries => { + write!(f, "Attempting to link in too many shared libraries") + } + CannotExecASharedLibraryDirectly => write!(f, "Cannot exec a shared library directly"), + InvalidOrIncompleteMultibyteOrWideCharacter => { + write!(f, "Invalid or incomplete multibyte or wide character") + } + InterruptedSystemCallShouldBeRestarted => { + write!(f, "Interrupted system call should be restarted") + } + StreamsPipeError => write!(f, "Streams pipe error"), + TooManyUsers => write!(f, "Too many users"), + SocketOperationOnNonSocket => write!(f, "Socket operation on non-socket"), + DestinationAddressRequired => write!(f, "Destination address required"), + MessageTooLong => write!(f, "Message too long"), + ProtocolWrongTypeForSocket => write!(f, "Protocol wrong type for socket"), + ProtocolNotAvailable => write!(f, "Protocol not available"), + ProtocolNotSupported => write!(f, "Protocol not supported"), + SocketTypeNotSupported => write!(f, "Socket type not supported"), + OperationNotSupported => write!(f, "Operation not supported"), + ProtocolFamilyNotSupported => write!(f, "Protocol family not supported"), + AddressFamilyNotSupportedByProtocol => { + write!(f, "Address family not supported by protocol") + } + AddressAlreadyInUse => write!(f, "Address already in use"), + AddressNotAvailable => write!(f, "Cannot assign requested address"), + NetworkIsDown => write!(f, "Network is down"), + HostIsUnreachable => write!(f, "Network is unreachable"), + NetworkDroppedConnectionOnReset => write!(f, "Network dropped connection on reset"), + SoftwareCausedConnectionAbort => write!(f, "Software caused connection abort"), + ConnectionResetByPeer => write!(f, "Connection reset by peer"), + NoBufferSpaceAvailable => write!(f, "No buffer space available"), + TransportEndpointIsAlreadyConnected => { + write!(f, "Transport endpoint is already connected") + } + TransportEndpointIsNotConnected => write!(f, "Transport endpoint is not connected"), + CannotSendAfterShutdown => { + write!(f, "Cannot send after transport endpoint shutdown") + } + TooManyReferencesCannotSplice => write!(f, "Too many references: cannot splice"), + ConnectionTimedOut => write!(f, "Connection timed out"), + ConnectionRefused => write!(f, "Connection refused"), + HostIsDown => write!(f, "Host is down"), + NoRouteToHost => write!(f, "No route to host"), + OperationAlreadyInProgress => write!(f, "Operation already in progress"), + OperationNowInProgress => write!(f, "Operation now in progress"), + StaleFileHandle => write!(f, "Stale file handle"), + StructureNeedsCleaning => write!(f, "Structure needs cleaning"), + NotAXenixNamedTypeFile => write!(f, "Not a XENIX named type file"), + NoXenixSemaphoresAvailable => write!(f, "No XENIX semaphores available"), + IsANamedTypeFile => write!(f, "Is a named type file"), + RemoteIOError => write!(f, "Remote I/O error"), + DiskQuotaExceeded => write!(f, "Disk quota exceeded"), + NoMediumFound => write!(f, "No medium found"), + WrongMediumType => write!(f, "Wrong medium type"), + OperationCanceled => write!(f, "Operation canceled"), + RequiredKeyNotAvailable => write!(f, "Required key not available"), + KeyHasExpired => write!(f, "Key has expired"), + KeyHasBeenRevoked => write!(f, "Key has been revoked"), + KeyWasRejectedByService => write!(f, "Key was rejected by service"), + OwnerDied => write!(f, "Owner died"), + StateNotRecoverable => write!(f, "State not recoverable"), + OperationNotPossibleDueToRfKill => write!(f, "Operation not possible due to RF-kill"), + MemoryPageHasHardwareError => write!(f, "Memory page has hardware error"), + Other(value) => write!(f, "Other error: {}", value), + _ => write!(f, "Unknown Error"), // Errors not present in linux + } + } +} diff --git a/mission_rust/src/fsrc/osal/error/newlib.rs b/mission_rust/src/fsrc/osal/error/newlib.rs new file mode 100644 index 0000000..569dcf6 --- /dev/null +++ b/mission_rust/src/fsrc/osal/error/newlib.rs @@ -0,0 +1,414 @@ +use core::fmt::Display; + +mod libc { + // taken from newlib source code + use core::ffi::c_int; + pub const EPERM: c_int = 1; + pub const ENOENT: c_int = 2; + pub const ESRCH: c_int = 3; + pub const EINTR: c_int = 4; + pub const EIO: c_int = 5; + pub const ENXIO: c_int = 6; + pub const E2BIG: c_int = 7; + pub const ENOEXEC: c_int = 8; + pub const EBADF: c_int = 9; + pub const ECHILD: c_int = 10; + pub const EAGAIN: c_int = 11; + pub const ENOMEM: c_int = 12; + pub const EACCES: c_int = 13; + pub const EFAULT: c_int = 14; + pub const ENOTBLK: c_int = 15; + pub const EBUSY: c_int = 16; + pub const EEXIST: c_int = 17; + pub const EXDEV: c_int = 18; + pub const ENODEV: c_int = 19; + pub const ENOTDIR: c_int = 20; + pub const EISDIR: c_int = 21; + pub const EINVAL: c_int = 22; + pub const ENFILE: c_int = 23; + pub const EMFILE: c_int = 24; + pub const ENOTTY: c_int = 25; + pub const ETXTBSY: c_int = 26; + pub const EFBIG: c_int = 27; + pub const ENOSPC: c_int = 28; + pub const ESPIPE: c_int = 29; + pub const EROFS: c_int = 30; + pub const EMLINK: c_int = 31; + pub const EPIPE: c_int = 32; + pub const EDOM: c_int = 33; + pub const ERANGE: c_int = 34; + pub const ENOMSG: c_int = 35; + pub const EIDRM: c_int = 36; + pub const ECHRNG: c_int = 37; + pub const EL2NSYNC: c_int = 38; + pub const EL3HLT: c_int = 39; + pub const EL3RST: c_int = 40; + pub const ELNRNG: c_int = 41; + pub const EUNATCH: c_int = 42; + pub const ENOCSI: c_int = 43; + pub const EL2HLT: c_int = 44; + pub const EDEADLK: c_int = 45; + pub const ENOLCK: c_int = 46; + pub const EBADE: c_int = 50; + pub const EBADR: c_int = 51; + pub const EXFULL: c_int = 52; + pub const ENOANO: c_int = 53; + pub const EBADRQC: c_int = 54; + pub const EBADSLT: c_int = 55; + pub const EDEADLOCK: c_int = 56; + pub const EBFONT: c_int = 57; + pub const ENOSTR: c_int = 60; + pub const ENODATA: c_int = 61; + pub const ETIME: c_int = 62; + pub const ENOSR: c_int = 63; + pub const ENONET: c_int = 64; + pub const ENOPKG: c_int = 65; + pub const EREMOTE: c_int = 66; + pub const ENOLINK: c_int = 67; + pub const EADV: c_int = 68; + pub const ESRMNT: c_int = 69; + pub const ECOMM: c_int = 70; + pub const EPROTO: c_int = 71; + pub const EMULTIHOP: c_int = 74; + pub const ELBIN: c_int = 75; + pub const EDOTDOT: c_int = 76; + pub const EBADMSG: c_int = 77; + pub const EFTYPE: c_int = 79; + pub const ENOTUNIQ: c_int = 80; + pub const EBADFD: c_int = 81; + pub const EREMCHG: c_int = 82; + pub const ELIBACC: c_int = 83; + pub const ELIBBAD: c_int = 84; + pub const ELIBSCN: c_int = 85; + pub const ELIBMAX: c_int = 86; + pub const ELIBEXEC: c_int = 87; + pub const ENOSYS: c_int = 88; + pub const ENMFILE: c_int = 89; + pub const ENOTEMPTY: c_int = 90; + pub const ENAMETOOLONG: c_int = 91; + pub const ELOOP: c_int = 92; + pub const EOPNOTSUPP: c_int = 95; + pub const EPFNOSUPPORT: c_int = 96; + pub const ECONNRESET: c_int = 104; + pub const ENOBUFS: c_int = 105; + pub const EAFNOSUPPORT: c_int = 106; + pub const EPROTOTYPE: c_int = 107; + pub const ENOTSOCK: c_int = 108; + pub const ENOPROTOOPT: c_int = 109; + pub const ESHUTDOWN: c_int = 110; + pub const ECONNREFUSED: c_int = 111; + pub const EADDRINUSE: c_int = 112; + pub const ECONNABORTED: c_int = 113; + pub const ENETUNREACH: c_int = 114; + pub const ENETDOWN: c_int = 115; + pub const ETIMEDOUT: c_int = 116; + pub const EHOSTDOWN: c_int = 117; + pub const EHOSTUNREACH: c_int = 118; + pub const EINPROGRESS: c_int = 119; + pub const EALREADY: c_int = 120; + pub const EDESTADDRREQ: c_int = 121; + pub const EMSGSIZE: c_int = 122; + pub const EPROTONOSUPPORT: c_int = 123; + pub const ESOCKTNOSUPPORT: c_int = 124; + pub const EADDRNOTAVAIL: c_int = 125; + pub const ENETRESET: c_int = 126; + pub const EISCONN: c_int = 127; + pub const ENOTCONN: c_int = 128; + pub const ETOOMANYREFS: c_int = 129; + pub const EPROCLIM: c_int = 130; + pub const EUSERS: c_int = 131; + pub const EDQUOT: c_int = 132; + pub const ESTALE: c_int = 133; + pub const ENOTSUP: c_int = 134; + pub const ENOMEDIUM: c_int = 135; + pub const ENOSHARE: c_int = 136; + pub const ECASECLASH: c_int = 137; + pub const EILSEQ: c_int = 138; + pub const EOVERFLOW: c_int = 139; + pub const ECANCELED: c_int = 140; + pub const ENOTRECOVERABLE: c_int = 141; + pub const EOWNERDEAD: c_int = 142; + pub const ESTRPIPE: c_int = 143; + #[allow(unused)] + pub const ELASTERROR: c_int = 2000; //User Errors start here + #[allow(unused)] + pub const EWOULDBLOCK: c_int = EAGAIN; +} + +impl From for super::OsError { + fn from(value: i32) -> Self { + use super::OsError::*; + match value { + libc::EPERM => OperationNotPermitted, + libc::ENOENT => NoSuchFileOrDirectory, + libc::ESRCH => NoSuchProcess, + libc::EINTR => InterruptedSystemCall, + libc::EIO => InputOutputError, + libc::ENXIO => NoSuchDeviceOrAddress, + libc::E2BIG => ArgumentListTooLong, + libc::ENOEXEC => ExecFormatError, + libc::EBADF => BadFileDescriptor, + libc::ECHILD => NoChildProcesses, + libc::EAGAIN => OperationWouldBlock, + // libc::EWOULDBLOCK => OperationWouldBlock == EAGAIN + libc::ENOMEM => CannotAllocateMemory, + libc::EACCES => PermissionDenied, + libc::EFAULT => BadAddress, + libc::ENOTBLK => BlockDeviceRequired, + libc::EBUSY => DeviceOrResourceBusy, + libc::EEXIST => FileExists, + libc::EXDEV => InvalidCrossDeviceLink, + libc::ENODEV => NoSuchDevice, + libc::ENOTDIR => NotADirectory, + libc::EISDIR => IsADirectory, + libc::EINVAL => InvalidArgument, + libc::ENFILE => TooManyOpenFilesInSystem, + libc::EMFILE => TooManyOpenFiles, + libc::ENOTTY => NotACharacterDevice, + libc::ETXTBSY => TextFileBusy, + libc::EFBIG => FileTooLarge, + libc::ENOSPC => NoSpaceLeftOnDevice, + libc::ESPIPE => IllegalSeek, + libc::EROFS => ReadOnlyFileSystem, + libc::EMLINK => TooManyLinks, + libc::EPIPE => BrokenPipe, + libc::EDOM => NumericalArgumentOutOfDomain, + libc::ERANGE => NumericalResultOutOfRange, + libc::ENOMSG => NoMessageOfDesiredType, + libc::EIDRM => IdentifierRemoved, + libc::ECHRNG => ChannelNumberOutOfRange, + libc::EL2NSYNC => Level2NotSynchronized, + libc::EL3HLT => Level3Halted, + libc::EL3RST => Level3Reset, + libc::ELNRNG => LinkNumberOutOfRange, + libc::EUNATCH => ProtocolDriverNotAttached, + libc::ENOCSI => NoCsiStructureAvailable, + libc::EL2HLT => Level2Halted, + libc::EDEADLK => Deadlock, + libc::ENOLCK => NoLocksAvailable, + libc::EBADE => InvalidExchange, + libc::EBADR => InvalidRequestDescriptor, + libc::EXFULL => ExchangeFull, + libc::ENOANO => NoAnode, + libc::EBADRQC => InvalidRequestCode, + libc::EBADSLT => InvalidSlot, + libc::EDEADLOCK => Deadlock, + libc::EBFONT => BadFontFileFormat, + libc::ENOSTR => DeviceNotAStream, + libc::ENODATA => NoDataAvailable, + libc::ETIME => TimerExpired, + libc::ENOSR => OutOfStreamsResources, + libc::ENONET => MachineIsNotOnTheNetwork, + libc::ENOPKG => PackageNotInstalled, + libc::EREMOTE => ObjectIsRemote, + libc::ENOLINK => LinkHasBeenSevered, + libc::EADV => AdvertiseError, + libc::ESRMNT => SrmountError, + libc::ECOMM => CommunicationErrorOnSend, + libc::EPROTO => ProtocolError, + libc::EMULTIHOP => MultihopAttempted, + libc::ELBIN => InodeIsRemote, + libc::EDOTDOT => FsError, + libc::EBADMSG => BadMessage, + libc::EFTYPE => InappropriateFileTypeOrFormat, + libc::ENOTUNIQ => NameNotUniqueOnNetwork, + libc::EBADFD => FileDescriptorInBadState, + libc::EREMCHG => RemoteAddressChanged, + libc::ELIBACC => CanNotAccessANeededSharedLibrary, + libc::ELIBBAD => AccessingACorruptedSharedLibrary, + libc::ELIBSCN => LibSectionInAOutCorrupted, + libc::ELIBMAX => AttemptingToLinkInTooManySharedLibraries, + libc::ELIBEXEC => CannotExecASharedLibraryDirectly, + libc::ENOSYS => FunctionNotImplemented, + libc::ENMFILE => NoMoreFiles, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::ENAMETOOLONG => FileNameTooLong, + libc::ELOOP => TooManySymbolicLinks, + libc::EOPNOTSUPP => OperationNotSupported, + libc::EPFNOSUPPORT => ProtocolFamilyNotSupported, + libc::ECONNRESET => ConnectionResetByPeer, + libc::ENOBUFS => NoBufferSpaceAvailable, + libc::EAFNOSUPPORT => AddressFamilyNotSupportedByProtocol, + libc::EPROTOTYPE => ProtocolWrongTypeForSocket, + libc::ENOTSOCK => SocketOperationOnNonSocket, + libc::ENOPROTOOPT => ProtocolNotAvailable, + libc::ESHUTDOWN => CannotSendAfterShutdown, + libc::ECONNREFUSED => ConnectionRefused, + libc::EADDRINUSE => AddressAlreadyInUse, + libc::ECONNABORTED => SoftwareCausedConnectionAbort, + libc::ENETUNREACH => HostIsUnreachable, + libc::ENETDOWN => NetworkIsDown, + libc::ETIMEDOUT => ConnectionTimedOut, + libc::EHOSTDOWN => HostIsDown, + libc::EHOSTUNREACH => HostIsUnreachable, + libc::EINPROGRESS => OperationNowInProgress, + libc::EALREADY => OperationAlreadyInProgress, + libc::EDESTADDRREQ => DestinationAddressRequired, + libc::EMSGSIZE => MessageTooLong, + libc::EPROTONOSUPPORT => ProtocolNotSupported, + libc::ESOCKTNOSUPPORT => SocketTypeNotSupported, + libc::EADDRNOTAVAIL => AddressNotAvailable, + libc::ENETRESET => NetworkDroppedConnectionOnReset, + libc::EISCONN => TransportEndpointIsAlreadyConnected, + libc::ENOTCONN => TransportEndpointIsNotConnected, + libc::ETOOMANYREFS => TooManyReferencesCannotSplice, + libc::EPROCLIM => LimitOnNewProcessesReached, + libc::EUSERS => TooManyUsers, + libc::EDQUOT => DiskQuotaExceeded, + libc::ESTALE => StaleFileHandle, + libc::ENOTSUP => OperationNotSupported, + libc::ENOMEDIUM => NoMediumFound, + libc::ENOSHARE => NoShare, + libc::ECASECLASH => FilenameExistsWithDifferentCase, + libc::EILSEQ => InvalidOrIncompleteMultibyteOrWideCharacter, + libc::EOVERFLOW => ValueTooLargeForDefinedDataType, + libc::ECANCELED => OperationCanceled, + libc::ENOTRECOVERABLE => StateNotRecoverable, + libc::EOWNERDEAD => OwnerDied, + libc::ESTRPIPE => StreamsPipeError, + value => Other(value), + } + } +} + +impl Display for super::OsError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use super::OsError::*; + match self { + AccessingACorruptedSharedLibrary => write!(f, "Accessing a corrupted shared lib"), + AddressAlreadyInUse => write!(f, "Address already in use"), + AddressFamilyNotSupportedByProtocol => { + write!(f, "Address family not supported by protocol family") + } + AddressNotAvailable => write!(f, "Address not available"), + AdvertiseError => write!(f, "Advertise error"), + ArgumentListTooLong => write!(f, "Arg list too long"), + AttemptingToLinkInTooManySharedLibraries => { + write!(f, "Attempting to link in too many libs") + } + BadAddress => write!(f, "Bad address"), + BadFileDescriptor => write!(f, "Bad file number"), + BadFontFileFormat => write!(f, "Bad font file fmt"), + BadMessage => write!(f, "Bad message"), + BlockDeviceRequired => write!(f, "Block device required"), + BrokenPipe => write!(f, "Broken pipe"), + CanNotAccessANeededSharedLibrary => write!(f, "Can't access a needed shared lib"), + CannotAllocateMemory => write!(f, "Not enough space"), + CannotExecASharedLibraryDirectly => write!(f, "Attempting to exec a shared library"), + CannotSendAfterShutdown => { + write!(f, "Can't send after socket shutdown") + } + ChannelNumberOutOfRange => write!(f, "Channel number out of range"), + CommunicationErrorOnSend => write!(f, "Communication error on send"), + ConnectionRefused => write!(f, "Connection refused"), + ConnectionResetByPeer => write!(f, "Connection reset by peer"), + ConnectionTimedOut => write!(f, "Connection timed out"), + Deadlock => write!(f, "Deadlock"), + DestinationAddressRequired => write!(f, "Destination address required"), + DeviceNotAStream => write!(f, "Not a stream"), + DeviceOrResourceBusy => write!(f, "Device or resource busy"), + DirectoryNotEmpty => write!(f, "Directory not empty"), + DiskQuotaExceeded => write!(f, "disk quota exceeded"), + ExchangeFull => write!(f, "Exchange full"), + ExecFormatError => write!(f, "Exec format error"), + FileDescriptorInBadState => write!(f, "f.d. invalid for this operation"), + FileExists => write!(f, "File exists"), + FilenameExistsWithDifferentCase => write!(f, "Filename exists with different case"), + FileNameTooLong => write!(f, "File or path name too long"), + FileTooLarge => write!(f, "File too large"), + FsError => write!(f, "Cross mount point (not really error)"), + FunctionNotImplemented => write!(f, "Function not implemented"), + HostIsDown => write!(f, "Host is down"), + IdentifierRemoved => write!(f, "Identifier removed"), + IllegalSeek => write!(f, "Illegal seek"), + InappropriateFileTypeOrFormat => write!(f, "Inappropriate file type or format"), + InodeIsRemote => write!(f, "Inode is remote (not really error)"), + InputOutputError => write!(f, "I/O error"), + InterruptedSystemCall => write!(f, "Interrupted system call"), + InvalidArgument => write!(f, "Invalid argument"), + InvalidCrossDeviceLink => write!(f, "Cross-device link"), + InvalidExchange => write!(f, "Invalid exchange"), + InvalidOrIncompleteMultibyteOrWideCharacter => write!(f, "Illegal byte sequence"), + InvalidRequestCode => write!(f, "Invalid request code"), + InvalidRequestDescriptor => write!(f, "Invalid request descriptor"), + InvalidSlot => write!(f, "Invalid slot"), + IsADirectory => write!(f, "Is a directory"), + Level2Halted => write!(f, "Level 2 halted"), + Level2NotSynchronized => write!(f, "Level 2 not synchronized"), + Level3Halted => write!(f, "Level 3 halted"), + Level3Reset => write!(f, "Level 3 reset"), + LibSectionInAOutCorrupted => write!(f, ".lib section in a.out corrupted"), + LimitOnNewProcessesReached => write!(f, "limit on new processes reached"), + LinkHasBeenSevered => write!(f, "Virtual circuit is gone"), + LinkNumberOutOfRange => write!(f, "Link number out of range"), + MachineIsNotOnTheNetwork => write!(f, "Machine is not on the network"), + MessageTooLong => write!(f, "Message too long"), + MultihopAttempted => write!(f, "Multihop attempted"), + NameNotUniqueOnNetwork => write!(f, "Given log. name not unique"), + NetworkDroppedConnectionOnReset => write!(f, "Connection aborted by network"), + NetworkIsDown => write!(f, "Network interface is not configured"), + HostIsUnreachable => write!(f, "Network is unreachable"), + NoAnode => write!(f, "No anode"), + NoBufferSpaceAvailable => write!(f, "No buffer space available"), + NoChildProcesses => write!(f, "No children"), + NoCsiStructureAvailable => write!(f, "No CSI structure available"), + NoDataAvailable => write!(f, "No data (for no delay io)"), + NoLocksAvailable => write!(f, "No lock"), + NoMediumFound => write!(f, "No medium (in tape drive)"), + NoMessageOfDesiredType => write!(f, "No message of desired type"), + NoMoreFiles => write!(f, "No more files"), + NoRouteToHost => write!(f, "Host is unreachable"), + NoShare => write!(f, "No Share"), + NoSpaceLeftOnDevice => write!(f, "No space left on device"), + NoSuchDevice => write!(f, "No such device"), + NoSuchDeviceOrAddress => write!(f, "No such device or address"), + NoSuchFileOrDirectory => write!(f, "No such file or directory"), + NoSuchProcess => write!(f, "No such process"), + NotACharacterDevice => write!(f, "Not a character device"), + NotADirectory => write!(f, "Not a directory"), + NumericalArgumentOutOfDomain => { + write!(f, "Mathematics argument out of domain of function") + } + NumericalResultOutOfRange => write!(f, "Result too large"), + ObjectIsRemote => write!(f, "The object is remote"), + OperationAlreadyInProgress => write!(f, "Socket already connected"), + OperationCanceled => write!(f, "Operation canceled"), + OperationNotPermitted => write!(f, "Not owner"), + OperationNotSupported => write!(f, "Not supported"), + OperationNowInProgress => write!(f, "Connection already in progress"), + OperationWouldBlock => write!(f, "Operation would block"), + OutOfStreamsResources => write!(f, "No stream resources"), + OwnerDied => write!(f, "Previous owner died"), + PackageNotInstalled => write!(f, "Package not installed"), + PermissionDenied => write!(f, "Permission denied"), + ProtocolDriverNotAttached => write!(f, "Protocol driver not attached"), + ProtocolError => write!(f, "Protocol error"), + ProtocolFamilyNotSupported => write!(f, "Protocol family not supported"), + ProtocolNotAvailable => write!(f, "Protocol not available"), + ProtocolNotSupported => write!(f, "Unknown protocol"), + ProtocolWrongTypeForSocket => write!(f, "Protocol wrong type for socket"), + ReadOnlyFileSystem => write!(f, "Read-only file system"), + RemoteAddressChanged => write!(f, "Remote address changed"), + SocketOperationOnNonSocket => write!(f, "Socket operation on non-socket"), + SocketTypeNotSupported => write!(f, "Socket type not supported"), + SoftwareCausedConnectionAbort => write!(f, "Software caused connection abort"), + SrmountError => write!(f, "Srmount error"), + StaleFileHandle => write!(f, "Stale NFS file handle"), + StateNotRecoverable => write!(f, "State not recoverable"), + StreamsPipeError => write!(f, "Streams pipe error"), + TextFileBusy => write!(f, "Text file busy"), + TimerExpired => write!(f, "Stream ioctl timeout"), + TooManyLinks => write!(f, "Too many links"), + TooManyOpenFiles => write!(f, "File descriptor value too large"), + TooManyOpenFilesInSystem => write!(f, "Too many open files in system"), + TooManyReferencesCannotSplice => write!(f, "Too many references: cannot splice."), + TooManySymbolicLinks => write!(f, "Too many symbolic links"), + TooManyUsers => write!(f, "file quota system confused too many users"), + TransportEndpointIsAlreadyConnected => write!(f, "Socket is already connected"), + TransportEndpointIsNotConnected => write!(f, "Socket is not connected"), + ValueTooLargeForDefinedDataType => write!(f, "Value too large for defined data type"), + Other(value) => write!(f, "Other error: {}", value), + _ => write!(f, "Unknown Error"), // Errors not present in newlib + } + } +} diff --git a/mission_rust/src/fsrc/osal/io.rs b/mission_rust/src/fsrc/osal/io.rs index f4e1c18..2c0ec60 100644 --- a/mission_rust/src/fsrc/osal/io.rs +++ b/mission_rust/src/fsrc/osal/io.rs @@ -22,6 +22,7 @@ impl Display for Error { } } + pub type Result = core::result::Result; pub trait Read { @@ -98,7 +99,7 @@ impl Read for HardwareInterface { // Safe: getter on os let errno = unsafe { ffi::freertos_get_sys_error() }; let error = errno.into(); - if error == OsError::ResourceTemporarilyUnavailable { + if error == OsError::OperationWouldBlock { // non blocking call returned return Ok(&[]); } diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 32e9aec..15670f5 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -198,7 +198,7 @@ fn init_task() -> ! { 0.5, ); - debugger.run(); + debugger.run().unwrap(); let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); From cead8ba50bed2a4e0d1dfbd0e5dd2358b4bfb163 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 24 Oct 2025 15:49:28 +0200 Subject: [PATCH 10/19] cleanup --- mission_rust/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 15670f5..8ca909b 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -20,7 +20,7 @@ use crate::{ dh::EchoHandler, fsrc::{ dh::debug::DeviceHandlerDebugger, - osal::io::{self, HardwareInterface, Read, Write as IoWrite}, + osal::io::HardwareInterface, }, }; @@ -185,6 +185,7 @@ static THREAD_3: StaticReadOnceLock< Duration::from_millis(200), )); + fn init_task() -> ! { sifln!("Mission enter"); @@ -222,7 +223,7 @@ fn init_task() -> ! { THREAD_3.take_no_init().unwrap().spawn(move || { receiver.run(); }); - + sifln!("=====================Mission delete"); osal::thread::current().delete(); } From 84fa8721c2b089f5b1f071f10ba5ce4065e79f17 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 24 Oct 2025 16:02:06 +0200 Subject: [PATCH 11/19] fixed for arm --- mission_rust/src/fsrc/osal/io.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mission_rust/src/fsrc/osal/io.rs b/mission_rust/src/fsrc/osal/io.rs index 2c0ec60..4f03438 100644 --- a/mission_rust/src/fsrc/osal/io.rs +++ b/mission_rust/src/fsrc/osal/io.rs @@ -60,11 +60,15 @@ impl HardwareInterface { impl Write for HardwareInterface { fn write(&mut self, data: &[u8]) -> Result<()> { + #[allow(irrefutable_let_patterns)] // is refutable on some targets + let Ok(len_converted) = data.len().try_into() else { + return Err(Error::Os(OsError::NumericalResultOutOfRange)); + }; let written = unsafe { ffi::write( self.fd, data.as_ptr() as *const core::ffi::c_void, - data.len().into(), + len_converted, ) }; if written < 0 { @@ -74,7 +78,7 @@ impl Write for HardwareInterface { } else { let Ok(written_unsigned) = written.try_into() else { // we are in written >=0, this should never happen - return Err(Error::InternalError); + return Err(Error::Os(OsError::NumericalResultOutOfRange)); }; if written_unsigned < data.len() { return Err(Error::IncompleteWrite(written_unsigned)); @@ -89,10 +93,14 @@ impl Read for HardwareInterface { fn read<'a>(&self, buffer: &'a [u8]) -> Result<&'a [u8]> { // Safe as we trust the OS let read = unsafe { + #[allow(irrefutable_let_patterns)] // is refutable on some targets + let Ok(len_converted) = buffer.len().try_into() else { + return Err(Error::Os(OsError::NumericalResultOutOfRange)) + }; ffi::read( self.fd, buffer.as_ptr() as *const core::ffi::c_void, - buffer.len().into(), + len_converted, ) }; if read < 0 { @@ -107,7 +115,7 @@ impl Read for HardwareInterface { } else { let Ok(read_unsigned) = read.try_into() else { // we are in read >=0, this should never happen - return Err(Error::InternalError); + return Err(Error::Os(OsError::NumericalResultOutOfRange)); }; Ok(&buffer[..read_unsigned]) } From c5d2c65a2ec06cdb000869fc319e790ce742b155 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 24 Oct 2025 17:46:01 +0200 Subject: [PATCH 12/19] working on threadsafe syscalls --- bsp_z7/hardware/interfaces.c | 7 +++++++ bsp_z7/newlib/read.c | 36 ++++++++++++++++++++++-------------- bsp_z7/newlib/write.c | 34 +++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index 7e6b638..ff852b3 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -7,6 +7,10 @@ #include "interface_fds.h" #include "uart.h" +#include +#include +#include + int compare_string_chars(const char *c_string, const char *chars, size_t chars_len) { for(int i = 0; i < chars_len; i++) { @@ -39,6 +43,8 @@ ssize_t hw_device_transfer(int fd, void *sendbuffer, void *receivebuffer, return -1; } + +// TODO move into uart.c // we could implement interrupt based nonblocking sending using a queue // like we do receiving (where we need it for the small hw buffer) // but in the end, we do not want too many interrupts, so we do it blocking @@ -59,6 +65,7 @@ int hw_interface_write(int fd, const char *ptr, int len) { uart_send(XPS_UART1_BASEADDR, ptr, len); return len; } + _REENT_ERRNO(_REENT) = EBADF; return -1; } diff --git a/bsp_z7/newlib/read.c b/bsp_z7/newlib/read.c index c76c6d9..4cd4631 100644 --- a/bsp_z7/newlib/read.c +++ b/bsp_z7/newlib/read.c @@ -4,31 +4,39 @@ #include "../hardware/interface_access.h" #include "../hardware/interface_fds.h" -// newlib offers a (weak) write implementation which -// is reentrant by calling _read_r which in turn -// relies on _read which we implement here. -// This way, we get a global, reentrant read implementation -// NOTE: This might be architecture dependent, so check your -// newlib implementation! -int _read(int fd, char *ptr, int len) { +#include +#include +#include + +int read(int fd, void *ptr, size_t len) { if (ptr == NULL) { - return 0; - } - - // 0 is stdin, TODO: do we support it? - if (fd < 1) { + _REENT_ERRNO(_REENT) = EINVAL; return -1; } - + + // 0 is stdin, TODO: do we support it? + if (fd < 1) { + _REENT_ERRNO(_REENT) = EBADF; + return -1; + } + // stdout and stderr if (fd < 3) { + _REENT_ERRNO(_REENT) = EBADF; return -1; } if (fd < INTERFACE_FDS_NEXT) { - return hw_interface_read(fd, ptr, len); + int result = hw_interface_read(fd, ptr, len); + if (result >= 0) { + return result; + } else if (_REENT_ERRNO(_REENT) != EBADF) { + return result; + } + // continue if fd did not match to try other fd providers } // we do not have dynamic fds, so fd is invalid + _REENT_ERRNO(_REENT) = EBADF; return -1; } \ No newline at end of file diff --git a/bsp_z7/newlib/write.c b/bsp_z7/newlib/write.c index ef1e502..6e397d4 100644 --- a/bsp_z7/newlib/write.c +++ b/bsp_z7/newlib/write.c @@ -4,39 +4,47 @@ #include "../hardware/interface_access.h" #include "../hardware/interface_fds.h" +#include +#include +#include -// newlib offers a (weak) write implementation which -// is reentrant by calling _write_r which in turn -// relies on _write which we implement here. -// This way, we get a global, reentrant write implementation -// NOTE: This might be architecture dependent, so check your -// newlib implementation! -int _write(int fd, const char *ptr, int len) { +int write(int fd, const void *ptr, size_t len) { if (ptr == NULL) { - return 0; + _REENT_ERRNO(_REENT) = EINVAL; + return -1; } //TODO check len // 0 is stdin, do not write to it if (fd < 1) { - return -1; // TODO error + _REENT_ERRNO(_REENT) = EBADF; + return -1; } // we only support a single debug UART, so // stdout and stderr are the same and go to the xilinx stdout UART // We output directely to avoid loops and allow debugging (not via a write) if (fd < 3) { - int todo; + size_t todo; + + const char *data = ptr; for (todo = 0; todo < len; todo++) { - outbyte(*ptr++); + outbyte(*data++); } return len; } if (fd < INTERFACE_FDS_NEXT) { - return hw_interface_write(fd, ptr, len); + int result = hw_interface_write(fd, ptr, len); + if (result >= 0) { + return result; + } else if (_REENT_ERRNO(_REENT) != EBADF) { + return result; + } + // continue if fd did not match to try other fd providers } // we do not have dynamic fds, so fd is invalid - return -1; + _REENT_ERRNO(_REENT) = EBADF; + return -1; } \ No newline at end of file From c7062407e0e192a73a8095a4f8510a58af65e4b7 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 27 Oct 2025 18:03:40 +0100 Subject: [PATCH 13/19] working on qemu; LINUX BUILD BROKEN! --- CMakeLists.txt | 4 ++-- bsp_z7/hardware/interfaces.c | 1 + bsp_z7/main.c | 32 +++++++++++++++++++++++++++++++- mission/mission.c | 19 ++++++++++++++----- mission_rust/src/lib.rs | 13 +++++++++++-- mission_rust/src/panic.rs | 4 ++-- 6 files changed, 61 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97ea101..92375df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ set(ROMEO_Z7_LINK_OPTIONS -Wl,--cref -Wl,-Map=${OBSW_NAME}.map -mcpu=cortex-a9 - set(ROMEO_WARNING_FLAGS -Wall -Wextra - -Wpedantic - -Werror) + -Wpedantic) + #-Werror) # CMake options which are only available when crosscompiling if (${CMAKE_CROSSCOMPILING}) diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index ff852b3..76fa071 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -35,6 +35,7 @@ int hw_device_open(const char *path, size_t path_len) { return UART_1; } + _REENT_ERRNO(_REENT) = ENOENT; return -1; } diff --git a/bsp_z7/main.c b/bsp_z7/main.c index 0d5bcf5..ed9b8b6 100644 --- a/bsp_z7/main.c +++ b/bsp_z7/main.c @@ -56,8 +56,15 @@ void mission(void); void initFreeRTOSHelper(); + int main(void) { + // Enable UARTs, so qemu knows we use them (should already be enabled by fsbl on actual hw) + XUartPs_WriteReg(XPS_UART0_BASEADDR, XUARTPS_CR_OFFSET, XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_CR_OFFSET, XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); + + + /* Configure the hardware ready to run. */ prvSetupHardware(); @@ -121,7 +128,30 @@ void vInitialiseTimerForRunTimeStats(void) { } // Marker for debugging sessions -__attribute__((noinline)) void done() { asm(""); } +// __attribute__((noinline)) void done() { asm(""); } + +// For qemu +// see https://github.com/ARM-software/abi-aa -> Miscellaneous material -> Semihosting for AArch32 and AArch64 +void done() { + register int reg0 asm("r0"); + register int reg1 asm("r1"); + + reg0 = 0x18; // SYS_EXIT + reg1 = 0x20026; // ADP_Stopped_ApplicationExit + + asm("svc 0x123456"); +} + +// same as done, will make qemu return 1 +void done_error() { + register int reg0 asm("r0"); + register int reg1 asm("r1"); + + reg0 = 0x18; // SYS_EXIT + reg1 = 0x20023; // ADP_Stopped_RunTimeErrorUnknown + + asm("svc 0x123456"); +} void vApplicationIdleHook(void) { volatile size_t xFreeHeapSpace, xMinimumEverFreeHeapSpace; diff --git a/mission/mission.c b/mission/mission.c index c151dd0..64f52b0 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -15,11 +15,20 @@ void rust_main(void); + + + + + + + void test_hardware() { + + int fd0 = hw_device_open("uart0", 5); write(fd0, "UART0\n", 6); int fd1 = hw_device_open("uart1", 5); - write(fd1, "uart1\n", 6); + write(fd1, "UART1\n", 6); // uint8_t buffer[255]; @@ -39,9 +48,9 @@ void test_hardware() { // write(1, buffer, read_bytes); } -// called to stop execution (either a panic or program ended) +// called to stop execution on error // to be implemented by bsp (do not return from it!) -void done(); +void done_error(); void init_task(void* _) { @@ -62,7 +71,7 @@ void mission(void) { write(1, "\n", 1); - //test_hardware(); + test_hardware(); freertos_init_and_start_scheduling(init_task); @@ -76,7 +85,7 @@ void mission(void) { mode from which main() is called is set in the C start up code and must be a privileged mode (not user mode). */ - done(); + done_error(); for (;;) ; diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 8ca909b..21cc3e5 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -185,22 +185,31 @@ static THREAD_3: StaticReadOnceLock< Duration::from_millis(200), )); +extern "C" { + fn done(); +} fn init_task() -> ! { sifln!("Mission enter"); + unsafe{done()}; + + panic!("tests done"); + let commands = [dh::Command(0), dh::Command(1), dh::Command(2)]; let mut debugger = DeviceHandlerDebugger::new( EchoHandler { buffer: [0; 10] }, - HardwareInterface::new("ps/uart_mtg").unwrap(), + HardwareInterface::new("uart0").unwrap(), &commands, &[], - Duration::from_secs(2), + Duration::from_millis(500), 0.5, ); debugger.run().unwrap(); + + let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); let receiver = RECEIVER.take().unwrap(); diff --git a/mission_rust/src/panic.rs b/mission_rust/src/panic.rs index 1a10f3c..26f0205 100644 --- a/mission_rust/src/panic.rs +++ b/mission_rust/src/panic.rs @@ -2,7 +2,7 @@ use core::panic::PanicInfo; use core::fmt::Write; extern "C" { - fn done(); + fn done_error(); // exit code != 0 } #[cfg(not(test))] @@ -19,7 +19,7 @@ fn panic(panic: &PanicInfo<'_>) -> ! { panic ); //TODO: stop RTOS, exit if hosted - unsafe { done() }; + unsafe { done_error() }; loop {} } From 3379b39105134eb2e949dc7765dbeb7b6978079e Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 28 Oct 2025 14:53:43 +0100 Subject: [PATCH 14/19] fixed linux, enhanced qemu --- CMakeLists.txt | 10 +++++- DEBUG_ON_QEMU.md | 42 +++++++++++++++++++++++++ bsp_linux/main.c | 6 ++-- bsp_z7/hardware/interfaces.c | 4 +++ bsp_z7/hardware/uart.c | 9 +++--- bsp_z7/main.c | 60 +++++++++++++++++++++--------------- mission/mission.c | 15 ++------- mission_rust/src/lib.rs | 10 +++--- 8 files changed, 107 insertions(+), 49 deletions(-) create mode 100644 DEBUG_ON_QEMU.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 92375df..79fe3cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ set(ROMEO_WARNING_FLAGS -Wall -Wextra -Wpedantic) - #-Werror) + #-Werror) #TODO fix Xilinx stuff # CMake options which are only available when crosscompiling if (${CMAKE_CROSSCOMPILING}) @@ -25,9 +25,17 @@ if (${CMAKE_CROSSCOMPILING}) if(${ZYNQ_UART} STREQUAL UART0) add_compile_definitions(ZYNQ_USE_UART0) endif() + + option(ZYNQ_SEMIHOSTING "enable semihosting for emulation" OFF) + + if(${ZYNQ_SEMIHOSTING}) + add_compile_definitions(ZYNQ_SEMIHOSTING) + endif() else() unset(ZYNQ_UART) unset(ZYNQ_UART CACHE) + unset(ZYNQ_SEMIHOSTING) + unset(ZYNQ_SEMIHOSTING CACHE) endif() # Add main executable diff --git a/DEBUG_ON_QEMU.md b/DEBUG_ON_QEMU.md new file mode 100644 index 0000000..12cc1d6 --- /dev/null +++ b/DEBUG_ON_QEMU.md @@ -0,0 +1,42 @@ +# Qemu + +qemu is an emulator which can be used to run code compiled for a different architecture (say ARMv7 as on zynq) on the host architecture (the PC you are using). + +This is mainly useful for testing platform dependent code, in our case the operating system abstraction. This code can not be tested on linux, as the FreeRTOS port used is a different one. + +By selecting the `ZYNQ_SEMIHOSTING` in cmake, the semihosting interface is enabled. This allows the software to signal an exit condition to qemu, which in turn makes qemu exit with the corresponding exit code. This functionality is used for unit testing, where the exit condition is needed to signal success or failure of the unit tests. + +# Run on qemu + +The full call to run the romeo-obsw on qemu is: + +`qemu-system-arm -semihosting -nographic -monitor none -serial null -serial stdio -machine xilinx-zynq-a9 -m 500M -kernel romeo-obsw` + +Where the arguments are the following: +* `qemu-system-arm`: the qemu emulating arm processors +* `-semihosting`: enables the emulated software to communicate with the host. This is only used to allow the software to exit including returning an exit code +* `-nographic`: disable qemus graphical interface +* `-monitor none`: disable qemu monitoring (not used) +* `-serial null`: add first UART, do not connect it. +* `-serial stdio`: add second UART, connect it to the console of the host +* `-machine xilinx-zynq-a9`: select zynq as emulation target +* `-m 500M`: set RAM size +* `-device loader,addr=0x0000012c,data=0x00001234,data-len=4`: set data at the memory location `data`. This is used by the FSW to detect if it is runing on qemu or on a real zynq (where this memory location will not be 0x00001234) +* `-kernel romeo-obsw`: which program to run + +The first UART can be connected to a serial device on the host. Add `-chardev serial,id=serial0,path="/dev/ttyUSB0"` where `"/dev/ttyUSB0"` is the path to the serial device. Then, change the first invocation of `-serial` from `-serial null` to `-serial chardev:serial0` + + +# Debug on qemu + +Basically the same call as above, only `-kernel` is replaced by `-s -S`, which enables debugging and halts the CPU. + +`qemu-system-arm -semihosting -nographic -monitor none -serial null -serial stdio -machine xilinx-zynq-a9 -m 500M -device loader,addr=0x0000012c,data=0x00001234,data-len=4 -s -S` + +After qemu is started, connect to the gdb server: +```sh +arm-none-eabi-gdb romeo-obsw +>target remote :1234 +>load +>cont +``` \ No newline at end of file diff --git a/bsp_linux/main.c b/bsp_linux/main.c index bca8d6a..918acee 100644 --- a/bsp_linux/main.c +++ b/bsp_linux/main.c @@ -14,13 +14,15 @@ int ai_family = AF_UNSPEC; void mission(void); -int get_descriptor_rw() { return 1; } void done() { - printf("done.\n"); exit(0); } +void done_error() { + exit(1); +} + int test_socket(); // TODO link to GCC's personality or make the linux build not use it? diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index 76fa071..8e47112 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -30,6 +30,10 @@ int hw_device_open(const char *path, size_t path_len) { uart0_enable_receiver(); return UART_0; } + if (compare_string_chars("debug/uart🚀", path, path_len) == 1) { + uart0_enable_receiver(); + return UART_0; + } if (compare_string_chars("uart1", path, path_len) == 1) { uart1_enable_receiver(); return UART_1; diff --git a/bsp_z7/hardware/uart.c b/bsp_z7/hardware/uart.c index de9107c..da5b018 100644 --- a/bsp_z7/hardware/uart.c +++ b/bsp_z7/hardware/uart.c @@ -69,13 +69,12 @@ void uart1_handle_interrupt(void *) { // available into the stack uint8_t RecievedByte; BaseType_t xHigherPriorityTaskWoken; - + while (XUartPs_IsReceiveData(XPS_UART1_BASEADDR)) { RecievedByte = XUartPs_ReadReg(XPS_UART1_BASEADDR, XUARTPS_FIFO_OFFSET); xQueueSendToBackFromISR(uart1_receive_queue, &RecievedByte, &xHigherPriorityTaskWoken); } - /* Clear the interrupt status. */ XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_ISR_OFFSET, IsrStatus); @@ -145,7 +144,8 @@ void uart1_enable_receiver() { } int uart0_read(char *ptr, int len) { - // TODO for blocking, if first call was successfull, further calls need to be delay=0 + // TODO for blocking, if first call was successfull, further calls need to be + // delay=0 int received = 0; while (len > 0) { BaseType_t result = xQueueReceive(uart0_receive_queue, ptr, 0); @@ -160,7 +160,8 @@ int uart0_read(char *ptr, int len) { } int uart1_read(char *ptr, int len) { - // TODO for blocking, if first call was successfull, further calls need to be delay=0 + // TODO for blocking, if first call was successfull, further calls need to be + // delay=0 int received = 0; while (len > 0) { BaseType_t result = xQueueReceive(uart1_receive_queue, ptr, 0); diff --git a/bsp_z7/main.c b/bsp_z7/main.c index ed9b8b6..3c906be 100644 --- a/bsp_z7/main.c +++ b/bsp_z7/main.c @@ -47,28 +47,24 @@ XScuGic xInterruptController; extern SemaphoreHandle_t malloc_mutex; -int get_descriptor_rw() { - return 1; -} - /*-----------------------------------------------------------*/ void mission(void); void initFreeRTOSHelper(); - int main(void) { - // Enable UARTs, so qemu knows we use them (should already be enabled by fsbl on actual hw) - XUartPs_WriteReg(XPS_UART0_BASEADDR, XUARTPS_CR_OFFSET, XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); - XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_CR_OFFSET, XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); - - + // Enable UARTs, so qemu knows we use them (should already be enabled by fsbl + // on actual hw) + XUartPs_WriteReg(XPS_UART0_BASEADDR, XUARTPS_CR_OFFSET, + XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_CR_OFFSET, + XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); /* Configure the hardware ready to run. */ prvSetupHardware(); - mission(); + mission(); } static void prvSetupHardware(void) { @@ -127,32 +123,45 @@ void vInitialiseTimerForRunTimeStats(void) { XScuWdt_Start(&xWatchDogInstance); } -// Marker for debugging sessions -// __attribute__((noinline)) void done() { asm(""); } - -// For qemu -// see https://github.com/ARM-software/abi-aa -> Miscellaneous material -> Semihosting for AArch32 and AArch64 +#ifndef ZYNQ_SEMIHOSTING void done() { + while (1) + ; +} + +void done_error() { + // makes no difference + done(); +} + +#else // enable semihosting interface for done() +void done() { + + // Call semihosting interface to signal exit + // see https://github.com/ARM-software/abi-aa -> Miscellaneous material -> + // Semihosting for AArch32 and AArch64 register int reg0 asm("r0"); register int reg1 asm("r1"); - reg0 = 0x18; // SYS_EXIT + reg0 = 0x18; // SYS_EXIT reg1 = 0x20026; // ADP_Stopped_ApplicationExit - asm("svc 0x123456"); + asm("svc 0x123456"); // syscall to semihosting interface } -// same as done, will make qemu return 1 void done_error() { + // same as done(), will make qemu return 1 register int reg0 asm("r0"); register int reg1 asm("r1"); - reg0 = 0x18; // SYS_EXIT + reg0 = 0x18; // SYS_EXIT reg1 = 0x20023; // ADP_Stopped_RunTimeErrorUnknown - asm("svc 0x123456"); + asm("svc 0x123456"); // syscall to semihosting interface } +#endif /* SEMIHOSTING */ + void vApplicationIdleHook(void) { volatile size_t xFreeHeapSpace, xMinimumEverFreeHeapSpace; @@ -198,7 +207,9 @@ void vApplicationTickHook(void) { vBasicStreamBufferSendFromISR(); #if (configUSE_QUEUE_SETS == 1) - { vQueueSetAccessQueueSetFromISR(); } + { + vQueueSetAccessQueueSetFromISR(); + } #endif /* Test flop alignment in interrupts - calling printf from an interrupt @@ -209,7 +220,9 @@ is BAD! */ UBaseType_t uxSavedInterruptStatus; uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); - { sprintf(cBuf, "%1.3f", 1.234); } + { + sprintf(cBuf, "%1.3f", 1.234); + } portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus); configASSERT(strcmp(cBuf, "1.234") == 0); @@ -218,4 +231,3 @@ is BAD! */ } #endif } - diff --git a/mission/mission.c b/mission/mission.c index 64f52b0..4a8284b 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -8,6 +8,7 @@ #include "task.h" #include + #include #include @@ -15,16 +16,8 @@ void rust_main(void); - - - - - - - void test_hardware() { - int fd0 = hw_device_open("uart0", 5); write(fd0, "UART0\n", 6); int fd1 = hw_device_open("uart1", 5); @@ -52,8 +45,7 @@ void test_hardware() { // to be implemented by bsp (do not return from it!) void done_error(); - -void init_task(void* _) { +void init_task(void *_) { (void)_; rust_main(); } @@ -61,7 +53,6 @@ void init_task(void* _) { #define STARTUP_MESSAGE1 "\nROMEO embedded obsw\nRelease: " #define STARTUP_MESSAGE2 "\nBuild time: " - void mission(void) { write(1, STARTUP_MESSAGE1, strlen(STARTUP_MESSAGE1)); @@ -70,10 +61,8 @@ void mission(void) { write(1, BUILD_TIME_STRING, strlen(BUILD_TIME_STRING)); write(1, "\n", 1); - test_hardware(); - freertos_init_and_start_scheduling(init_task); /* If all is well, the scheduler will now be running, and the following diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 21cc3e5..bfcc749 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -186,20 +186,20 @@ static THREAD_3: StaticReadOnceLock< )); extern "C" { - fn done(); + fn done() -> !; } fn init_task() -> ! { sifln!("Mission enter"); - unsafe{done()}; + // unsafe{done()}; - panic!("tests done"); + // panic!("Oh no!"); let commands = [dh::Command(0), dh::Command(1), dh::Command(2)]; let mut debugger = DeviceHandlerDebugger::new( EchoHandler { buffer: [0; 10] }, - HardwareInterface::new("uart0").unwrap(), + HardwareInterface::new("debug/uart🚀").unwrap(), &commands, &[], Duration::from_millis(500), @@ -208,7 +208,7 @@ fn init_task() -> ! { debugger.run().unwrap(); - + panic!("done"); let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); From f3aa72b1cb940eaf33a863913da9ef4383512f7b Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 29 Oct 2025 09:53:01 +0100 Subject: [PATCH 15/19] More concise option name --- CMakeLists.txt | 10 +++++----- bsp_z7/main.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79fe3cd..4cfbd4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,16 +26,16 @@ if (${CMAKE_CROSSCOMPILING}) add_compile_definitions(ZYNQ_USE_UART0) endif() - option(ZYNQ_SEMIHOSTING "enable semihosting for emulation" OFF) + option(ARM_SEMIHOSTING "enable semihosting for emulation" OFF) - if(${ZYNQ_SEMIHOSTING}) - add_compile_definitions(ZYNQ_SEMIHOSTING) + if(${ARM_SEMIHOSTING}) + add_compile_definitions(ARM_SEMIHOSTING) endif() else() unset(ZYNQ_UART) unset(ZYNQ_UART CACHE) - unset(ZYNQ_SEMIHOSTING) - unset(ZYNQ_SEMIHOSTING CACHE) + unset(ARM_SEMIHOSTING) + unset(ARM_SEMIHOSTING CACHE) endif() # Add main executable diff --git a/bsp_z7/main.c b/bsp_z7/main.c index 3c906be..4e28bc4 100644 --- a/bsp_z7/main.c +++ b/bsp_z7/main.c @@ -123,7 +123,7 @@ void vInitialiseTimerForRunTimeStats(void) { XScuWdt_Start(&xWatchDogInstance); } -#ifndef ZYNQ_SEMIHOSTING +#ifndef ARM_SEMIHOSTING void done() { while (1) ; From 825c0d19119acd1b78ceb261e6a3009ee46394cc Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 5 Nov 2025 13:18:44 +0100 Subject: [PATCH 16/19] libc calls a bit more correct --- mission_rust/src/fsrc/osal/ffi.rs | 39 ++++++++---------------- mission_rust/src/fsrc/osal/ffi/gnu.rs | 13 ++++++++ mission_rust/src/fsrc/osal/ffi/newlib.rs | 15 +++++++++ mission_rust/src/lib.rs | 1 + 4 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 mission_rust/src/fsrc/osal/ffi/gnu.rs create mode 100644 mission_rust/src/fsrc/osal/ffi/newlib.rs diff --git a/mission_rust/src/fsrc/osal/ffi.rs b/mission_rust/src/fsrc/osal/ffi.rs index 6229a2d..3533645 100644 --- a/mission_rust/src/fsrc/osal/ffi.rs +++ b/mission_rust/src/fsrc/osal/ffi.rs @@ -1,6 +1,5 @@ // TODO verify uXX == uintXX_t // TODO track current state of usize == size_t (needed for some) - type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void) -> !; pub struct Sizes {} @@ -14,7 +13,8 @@ impl Sizes { pub const TASK_MINIMAL_STACK_SIZE: usize = 16424; } -// We use none for bare metal, as we only support one architecture so far +// We use target_os=none for bare metal, as we only support one platform so far +// so we select on target_env #[cfg(target_env = "newlib")] impl Sizes { pub const TASK_DATA_SIZE: usize = 184; @@ -100,28 +100,15 @@ extern "C" { /// Used for access to peripherals to make switching between linux and embedded easier //int hw_device_open(const char * path, size_t path_len); pub fn hw_device_open(path: *const core::ffi::c_char, path_len: usize) -> core::ffi::c_int; - - //////////////////////// - /// POSIX/UNIX/LINUX API - - //TODO, linux seems to use ssize_t (confirm!), newlib int as return value and count - #[cfg(target_os = "linux")] - pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; - - #[cfg(target_os = "linux")] - pub fn read(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> isize; - - #[cfg(target_env = "newlib")] - pub fn write( - fd: core::ffi::c_int, - buffer: *const core::ffi::c_void, - count: core::ffi::c_int, - ) -> core::ffi::c_int; - - #[cfg(target_env = "newlib")] - pub fn read( - fd: core::ffi::c_int, - buffer: *const core::ffi::c_void, - count: core::ffi::c_int, - ) -> core::ffi::c_int; } +//////////////////////// +/// libc API (read/write/etc) +#[cfg(target_env = "gnu")] +mod gnu; +#[cfg(target_env = "gnu")] +pub use gnu::*; + +#[cfg(target_env = "newlib")] +mod newlib; +#[cfg(target_env = "newlib")] +pub use newlib::*; \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal/ffi/gnu.rs b/mission_rust/src/fsrc/osal/ffi/gnu.rs new file mode 100644 index 0000000..24b43a7 --- /dev/null +++ b/mission_rust/src/fsrc/osal/ffi/gnu.rs @@ -0,0 +1,13 @@ +extern "C" { + pub fn write( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_ssize_t; + + pub fn read( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_ssize_t; + } \ No newline at end of file diff --git a/mission_rust/src/fsrc/osal/ffi/newlib.rs b/mission_rust/src/fsrc/osal/ffi/newlib.rs new file mode 100644 index 0000000..d87a96c --- /dev/null +++ b/mission_rust/src/fsrc/osal/ffi/newlib.rs @@ -0,0 +1,15 @@ +// TODO: newlib uses int only on some platforms (including arm) as read/write return +// see newlib:newlib/libc/include/sys/config.h for details + +extern "C" { + pub fn write( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_int; + pub fn read( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_int; +} diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index f4cd634..27fc055 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(never_type)] +#![feature(c_size_t)] // for ffi, tracking issue [88345] //TODO os errors in API calls pub mod fsrc; From 4769da31b757cdadf0d8b0fc7b3598e344ae859d Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 5 Nov 2025 14:27:32 +0100 Subject: [PATCH 17/19] force panic --- mission_rust/src/fsrc/dh/debug.rs | 30 +++++++++++++++++++++--------- mission_rust/src/lib.rs | 8 ++++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/mission_rust/src/fsrc/dh/debug.rs b/mission_rust/src/fsrc/dh/debug.rs index 6eb7d24..1a6cad4 100644 --- a/mission_rust/src/fsrc/dh/debug.rs +++ b/mission_rust/src/fsrc/dh/debug.rs @@ -1,14 +1,16 @@ -use core::time::Duration; use core::fmt::Write; +use core::{fmt::Display, time::Duration}; - -use crate::{fsrc::{ - dh::DeviceCom, - osal::{ - self, - io::{HardwareInterface, Read, Write as DeviceWrite}, +use crate::{ + fsrc::{ + dh::DeviceCom, + osal::{ + self, + io::{HardwareInterface, Read, Write as DeviceWrite}, + }, }, -}, sifln}; + sifln, +}; #[derive(Debug)] pub enum Error { @@ -21,6 +23,16 @@ impl From for Error { } } +impl Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "😢")?; + match self { + Error::IoError(os_error) => write!(f, "Io::{}", os_error), + _ => write!(f, "not implemented"), + } + } +} + type Result = core::result::Result; pub struct DeviceHandlerDebugger<'a, T: DeviceCom> { @@ -72,7 +84,7 @@ impl<'a, T: DeviceCom> DeviceHandlerDebugger<'a, T> { osal::thread::current().delay(self.wait_until_read); let rx_buffer = self.implementation.get_rx_buffer(); let rx_buffer = self.interface.read(rx_buffer)?; - let (reply,remainder) = T::parse_device_reply_and_return_remainder(rx_buffer); + let (reply, remainder) = T::parse_device_reply_and_return_remainder(rx_buffer); sifln!("got reply: {reply:?}, remainder {remainder:?}"); osal::thread::current().delay(self.wait_after_read); Ok(()) diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 90adb9f..b66fac4 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -193,14 +193,18 @@ fn init_task() -> ! { let commands = [dh::Command(0), dh::Command(1), dh::Command(2)]; let mut debugger = DeviceHandlerDebugger::new( EchoHandler { buffer: [0; 10] }, - HardwareInterface::new("ps/uart_mtg").unwrap(), + HardwareInterface::new("uart0").unwrap(), &commands, &[], Duration::from_secs(2), 0.5, ); - debugger.run().unwrap(); + let result = debugger.run(); + if let Err(e) = result { + sifln!("{e}"); + panic!(""); + } let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap(); From 0d69a52626f812a77860b8fb4a6532bf7f63bd75 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 5 Nov 2025 16:09:39 +0100 Subject: [PATCH 18/19] clarification on syscalls --- mission_rust/src/fsrc/osal/ffi/gnu.rs | 24 +++++++++++++----------- mission_rust/src/fsrc/osal/ffi/newlib.rs | 1 + 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/mission_rust/src/fsrc/osal/ffi/gnu.rs b/mission_rust/src/fsrc/osal/ffi/gnu.rs index 24b43a7..6ee652b 100644 --- a/mission_rust/src/fsrc/osal/ffi/gnu.rs +++ b/mission_rust/src/fsrc/osal/ffi/gnu.rs @@ -1,13 +1,15 @@ extern "C" { - pub fn write( - fd: core::ffi::c_int, - buffer: *const core::ffi::c_void, - count: core::ffi::c_size_t, - ) -> core::ffi::c_ssize_t; + // The GNU C Library Reference Manual 2.42, ch. 13.2 + pub fn write( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_ssize_t; - pub fn read( - fd: core::ffi::c_int, - buffer: *const core::ffi::c_void, - count: core::ffi::c_size_t, - ) -> core::ffi::c_ssize_t; - } \ No newline at end of file + // The GNU C Library Reference Manual 2.42, ch. 13.2 + pub fn read( + fd: core::ffi::c_int, + buffer: *const core::ffi::c_void, + count: core::ffi::c_size_t, + ) -> core::ffi::c_ssize_t; +} diff --git a/mission_rust/src/fsrc/osal/ffi/newlib.rs b/mission_rust/src/fsrc/osal/ffi/newlib.rs index d87a96c..a828a5c 100644 --- a/mission_rust/src/fsrc/osal/ffi/newlib.rs +++ b/mission_rust/src/fsrc/osal/ffi/newlib.rs @@ -1,5 +1,6 @@ // TODO: newlib uses int only on some platforms (including arm) as read/write return // see newlib:newlib/libc/include/sys/config.h for details +// count is size_t according to newlib:newlib/libc/include/sys/unistd.h, not int as the website shows in the syscall examples extern "C" { pub fn write( From e31b632bc8262c8a7e94d1399c1926709d5fb60b Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 5 Nov 2025 18:28:35 +0100 Subject: [PATCH 19/19] big box of fixes and cleanup --- CMakeLists.txt | 4 +- bsp_linux/hardware/hardware.c | 2 - bsp_linux/main.c | 22 +++---- bsp_z7/hardware/interface_access.h | 6 +- bsp_z7/hardware/interfaces.c | 6 +- bsp_z7/hardware/uart.c | 4 +- bsp_z7/hardware/uart.h | 4 +- bsp_z7/ps7_cortexa9_0/include/xuartps.h | 3 +- .../libsrc/uartps/src/xuartps.h | 3 +- common/git_version/get_version.cmake | 2 +- mission/mission.c | 30 --------- mission_rust/CMakeLists.txt | 5 +- mission_rust/src/fsrc/dh/debug.rs | 1 + mission_rust/src/fsrc/osal/ffi.rs | 4 +- mission_rust/src/fsrc/osal/io.rs | 20 +++--- mission_rust/src/fsrc/sif.rs | 65 ++++++++----------- mission_rust/src/lib.rs | 16 +---- 17 files changed, 77 insertions(+), 120 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cfbd4a..a59a412 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ set(ROMEO_Z7_LINK_OPTIONS -Wl,--cref -Wl,-Map=${OBSW_NAME}.map -mcpu=cortex-a9 - set(ROMEO_WARNING_FLAGS -Wall -Wextra - -Wpedantic) - #-Werror) #TODO fix Xilinx stuff + -Wpedantic + -Werror) # TODO so far, this only affects mission code, not bsp # CMake options which are only available when crosscompiling if (${CMAKE_CROSSCOMPILING}) diff --git a/bsp_linux/hardware/hardware.c b/bsp_linux/hardware/hardware.c index 890e6e0..f0e33ec 100644 --- a/bsp_linux/hardware/hardware.c +++ b/bsp_linux/hardware/hardware.c @@ -40,8 +40,6 @@ const char *get_port_number(const char *path, size_t path_len) { return NULL; } - - int hw_device_open(const char *path, size_t path_len) { int serial_fd = serial_open(path, path_len); diff --git a/bsp_linux/main.c b/bsp_linux/main.c index 918acee..6e80ac2 100644 --- a/bsp_linux/main.c +++ b/bsp_linux/main.c @@ -14,25 +14,26 @@ int ai_family = AF_UNSPEC; void mission(void); +void done() { exit(0); } -void done() { - exit(0); -} - -void done_error() { - exit(1); -} +void done_error() { exit(1); } int test_socket(); // TODO link to GCC's personality or make the linux build not use it? void rust_eh_personality() { puts("eh_personality"); } -void print_usage(const char * name) { -fprintf(stderr, "Usage: %s [-s sim_ip] [-4|6]\n", name); +void print_usage(const char *name) { + fprintf(stderr, "Usage: %s [-s sim_ip] [-4|6]\n", name); } +#include + int main(int argc, char **argv) { + hw_device_open( + "invalidpath", + 11); // TODO for some weird linker behaviour, if this function is not used + // here, it will not be found by the linker when linking the rust lib static struct option long_options[] = { /* NAME ARGUMENT FLAG SHORTNAME */ {"sim_ip", required_argument, NULL, 's'}, @@ -58,9 +59,8 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } } - } + } mission(); return 0; } - diff --git a/bsp_z7/hardware/interface_access.h b/bsp_z7/hardware/interface_access.h index 5578958..6eea8b3 100644 --- a/bsp_z7/hardware/interface_access.h +++ b/bsp_z7/hardware/interface_access.h @@ -1,5 +1,7 @@ #pragma once -int hw_interface_write(int fd, const char *ptr, int len); +#include -int hw_interface_read(int fd, char *ptr, int len); \ No newline at end of file +int hw_interface_write(int fd, const char *ptr, size_t len); + +int hw_interface_read(int fd, char *ptr, size_t len); \ No newline at end of file diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index 8e47112..8293038 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -53,14 +53,14 @@ ssize_t hw_device_transfer(int fd, void *sendbuffer, void *receivebuffer, // we could implement interrupt based nonblocking sending using a queue // like we do receiving (where we need it for the small hw buffer) // but in the end, we do not want too many interrupts, so we do it blocking -void uart_send(uint32_t BaseAddress, const char *data, int data_len) { +void uart_send(uint32_t BaseAddress, const char *data, size_t data_len) { int todo; for (todo = 0; todo < data_len; todo++) { XUartPs_SendByte(BaseAddress, *data++); } } -int hw_interface_write(int fd, const char *ptr, int len) { +int hw_interface_write(int fd, const char *ptr, size_t len) { enum InterfaceFileDescriptors fd_enum = fd; switch (fd) { case UART_0: @@ -74,7 +74,7 @@ int hw_interface_write(int fd, const char *ptr, int len) { return -1; } -int hw_interface_read(int fd, char *ptr, int len) { +int hw_interface_read(int fd, char *ptr, size_t len) { enum InterfaceFileDescriptors fd_enum = fd; switch (fd) { case UART_0: diff --git a/bsp_z7/hardware/uart.c b/bsp_z7/hardware/uart.c index da5b018..8e4db59 100644 --- a/bsp_z7/hardware/uart.c +++ b/bsp_z7/hardware/uart.c @@ -143,7 +143,7 @@ void uart1_enable_receiver() { XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_1_INTR); } -int uart0_read(char *ptr, int len) { +int uart0_read(char *ptr, size_t len) { // TODO for blocking, if first call was successfull, further calls need to be // delay=0 int received = 0; @@ -159,7 +159,7 @@ int uart0_read(char *ptr, int len) { return received; } -int uart1_read(char *ptr, int len) { +int uart1_read(char *ptr, size_t len) { // TODO for blocking, if first call was successfull, further calls need to be // delay=0 int received = 0; diff --git a/bsp_z7/hardware/uart.h b/bsp_z7/hardware/uart.h index 8ee06b2..b0e5176 100644 --- a/bsp_z7/hardware/uart.h +++ b/bsp_z7/hardware/uart.h @@ -1,6 +1,6 @@ #pragma once void uart0_enable_receiver(); -int uart0_read(char *ptr, int len); +int uart0_read(char *ptr, int size_t); void uart1_enable_receiver(); -int uart1_read(char *ptr, int len); \ No newline at end of file +int uart1_read(char *ptr, int size_t); \ No newline at end of file diff --git a/bsp_z7/ps7_cortexa9_0/include/xuartps.h b/bsp_z7/ps7_cortexa9_0/include/xuartps.h index 89ed5fd..9f52528 100644 --- a/bsp_z7/ps7_cortexa9_0/include/xuartps.h +++ b/bsp_z7/ps7_cortexa9_0/include/xuartps.h @@ -447,10 +447,11 @@ typedef struct { * u32 XUartPs_IsTransmitEmpty(XUartPs InstancePtr) * ******************************************************************************/ +#ifndef XUartPs_IsTransmitEmpty // Xilinx screwed up #define XUartPs_IsTransmitEmpty(InstancePtr) \ ((Xil_In32(((InstancePtr)->Config.BaseAddress) + (u32)XUARTPS_SR_OFFSET) & \ (u32)XUARTPS_SR_TXEMPTY) == (u32)XUARTPS_SR_TXEMPTY) - +#endif /************************** Function Prototypes *****************************/ diff --git a/bsp_z7/ps7_cortexa9_0/libsrc/uartps/src/xuartps.h b/bsp_z7/ps7_cortexa9_0/libsrc/uartps/src/xuartps.h index 89ed5fd..9f52528 100644 --- a/bsp_z7/ps7_cortexa9_0/libsrc/uartps/src/xuartps.h +++ b/bsp_z7/ps7_cortexa9_0/libsrc/uartps/src/xuartps.h @@ -447,10 +447,11 @@ typedef struct { * u32 XUartPs_IsTransmitEmpty(XUartPs InstancePtr) * ******************************************************************************/ +#ifndef XUartPs_IsTransmitEmpty // Xilinx screwed up #define XUartPs_IsTransmitEmpty(InstancePtr) \ ((Xil_In32(((InstancePtr)->Config.BaseAddress) + (u32)XUARTPS_SR_OFFSET) & \ (u32)XUARTPS_SR_TXEMPTY) == (u32)XUARTPS_SR_TXEMPTY) - +#endif /************************** Function Prototypes *****************************/ diff --git a/common/git_version/get_version.cmake b/common/git_version/get_version.cmake index f8e96db..584e598 100644 --- a/common/git_version/get_version.cmake +++ b/common/git_version/get_version.cmake @@ -1,3 +1,3 @@ -execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --dirty OUTPUT_VARIABLE GIT_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --dirty --always OUTPUT_VARIABLE GIT_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE) string(TIMESTAMP BUILD_TIME_STRING UTC) configure_file(${INPUT_FILE} ${OUTPUT_FILE}) \ No newline at end of file diff --git a/mission/mission.c b/mission/mission.c index 4a8284b..932d66b 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -1,14 +1,11 @@ /* Standard includes. */ #include -#include /* Scheduler include files. */ #include "freeRTOS_rust_helper.h" #include "semphr.h" #include "task.h" -#include - #include #include @@ -16,31 +13,6 @@ void rust_main(void); -void test_hardware() { - - int fd0 = hw_device_open("uart0", 5); - write(fd0, "UART0\n", 6); - int fd1 = hw_device_open("uart1", 5); - write(fd1, "UART1\n", 6); - - // uint8_t buffer[255]; - - // for (int i = 0; i< sizeof(buffer); i++) { - // buffer[i] = i; - // } - - // write(fd0, buffer, sizeof(buffer)); - - // vTaskDelay(10 / portTICK_PERIOD_MS); - - // write(1, "got:\n", 5); - - // int read_bytes = read(fd0, buffer, sizeof(buffer)); - // write(1, buffer, read_bytes); - // read_bytes = read(fd1, buffer, sizeof(buffer)); - // write(1, buffer, read_bytes); -} - // called to stop execution on error // to be implemented by bsp (do not return from it!) void done_error(); @@ -61,8 +33,6 @@ void mission(void) { write(1, BUILD_TIME_STRING, strlen(BUILD_TIME_STRING)); write(1, "\n", 1); - test_hardware(); - freertos_init_and_start_scheduling(init_task); /* If all is well, the scheduler will now be running, and the following diff --git a/mission_rust/CMakeLists.txt b/mission_rust/CMakeLists.txt index 06fbb87..c9eff4f 100644 --- a/mission_rust/CMakeLists.txt +++ b/mission_rust/CMakeLists.txt @@ -5,7 +5,6 @@ -#TODO can we get CMake to configure cmake --build --clean to run cargo clean? #TODO look into corrosion cmake plugin if (${CMAKE_CROSSCOMPILING}) @@ -16,6 +15,8 @@ if (${CMAKE_CROSSCOMPILING}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_CURRENT_SOURCE_DIR}/target/${CMAKE_SYSTEM_PROCESSOR}/$,release,debug>/) + add_library(mission_rust INTERFACE) add_dependencies(mission_rust mission_rust_internal) @@ -30,6 +31,8 @@ else() WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES ${CMAKE_CURRENT_SOURCE_DIR}/target/$,release,debug>/) + add_library(mission_rust INTERFACE) add_dependencies(mission_rust mission_rust_internal) diff --git a/mission_rust/src/fsrc/dh/debug.rs b/mission_rust/src/fsrc/dh/debug.rs index 1a6cad4..e3fc558 100644 --- a/mission_rust/src/fsrc/dh/debug.rs +++ b/mission_rust/src/fsrc/dh/debug.rs @@ -15,6 +15,7 @@ use crate::{ #[derive(Debug)] pub enum Error { IoError(osal::io::Error), + ToDo } impl From for Error { diff --git a/mission_rust/src/fsrc/osal/ffi.rs b/mission_rust/src/fsrc/osal/ffi.rs index 3533645..3c54ef4 100644 --- a/mission_rust/src/fsrc/osal/ffi.rs +++ b/mission_rust/src/fsrc/osal/ffi.rs @@ -1,5 +1,5 @@ // TODO verify uXX == uintXX_t -// TODO track current state of usize == size_t (needed for some) +// TODO Document size_t != usize problems better type TaskFunction = unsafe extern "C" fn(*mut core::ffi::c_void) -> !; pub struct Sizes {} @@ -99,7 +99,7 @@ extern "C" { /// Harware Abstraction API in common/include/interfaces.h /// Used for access to peripherals to make switching between linux and embedded easier //int hw_device_open(const char * path, size_t path_len); - pub fn hw_device_open(path: *const core::ffi::c_char, path_len: usize) -> core::ffi::c_int; + pub fn hw_device_open(path: *const core::ffi::c_char, path_len: core::ffi::c_size_t) -> core::ffi::c_int; } //////////////////////// /// libc API (read/write/etc) diff --git a/mission_rust/src/fsrc/osal/io.rs b/mission_rust/src/fsrc/osal/io.rs index 4f03438..55eb070 100644 --- a/mission_rust/src/fsrc/osal/io.rs +++ b/mission_rust/src/fsrc/osal/io.rs @@ -22,7 +22,6 @@ impl Display for Error { } } - pub type Result = core::result::Result; pub trait Read { @@ -41,11 +40,16 @@ pub struct HardwareInterface { impl HardwareInterface { pub fn new(path: &str) -> Result { // Safe: we trust our own implementation to only read - // as we cut our string into bytes, conversion to c_char is correct, as C will compare bit value + // as we cut our string into bytes, conversion to c_char is correct, C will compare bit value + #[allow(irrefutable_let_patterns)] + // is refutable on some exotic targets. If you wanna have fun: https://internals.rust-lang.org/t/pre-rfc-usize-is-not-size-t/15369 + let Ok(len_converted) = path.as_bytes().len().try_into() else { + panic!(); // TODO Abort + }; let fd = unsafe { crate::osal::ffi::hw_device_open( path.as_bytes().as_ptr() as *const core::ffi::c_char, - path.as_bytes().len(), + len_converted, ) }; if fd >= 0 { @@ -60,10 +64,10 @@ impl HardwareInterface { impl Write for HardwareInterface { fn write(&mut self, data: &[u8]) -> Result<()> { - #[allow(irrefutable_let_patterns)] // is refutable on some targets - let Ok(len_converted) = data.len().try_into() else { - return Err(Error::Os(OsError::NumericalResultOutOfRange)); - }; + #[allow(irrefutable_let_patterns)] // is refutable on some exotic targets. See above + let Ok(len_converted) = data.len().try_into() else { + return Err(Error::Os(OsError::NumericalResultOutOfRange)); + }; let written = unsafe { ffi::write( self.fd, @@ -95,7 +99,7 @@ impl Read for HardwareInterface { let read = unsafe { #[allow(irrefutable_let_patterns)] // is refutable on some targets let Ok(len_converted) = buffer.len().try_into() else { - return Err(Error::Os(OsError::NumericalResultOutOfRange)) + return Err(Error::Os(OsError::NumericalResultOutOfRange)); }; ffi::read( self.fd, diff --git a/mission_rust/src/fsrc/sif.rs b/mission_rust/src/fsrc/sif.rs index 8d9074e..3c5e46d 100644 --- a/mission_rust/src/fsrc/sif.rs +++ b/mission_rust/src/fsrc/sif.rs @@ -6,74 +6,62 @@ pub struct Stderr {} // TODO why or how does pub work (users from same crate need to use core::fmt::... ) pub use core::fmt::{Error, Write}; -// TODO this is already in osal -// extern "C" { -// pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> core::ffi::c_int; -// } impl Write for Stdout { fn write_str(&mut self, s: &str) -> Result<(), Error> { - - // Safe because write will only read the pointer an then return - // try_into is used as write call is different depending on platform - let len_converted = match s.as_bytes().len().try_into(){ - Ok(value) => value, - Err(_) => return Err(Error) + #[allow(irrefutable_let_patterns)] // is refutable on some exotic targets. See above + let Ok(len_converted) = s.as_bytes().len().try_into() else { + return Err(Error); }; - let result = unsafe { - crate::fsrc::osal::ffi::write( + // Safe because write will only read the pointer an then return + let written = unsafe { + crate::fsrc::osal::ffi::write( 1, s.as_bytes().as_ptr() as *const core::ffi::c_void, len_converted, ) }; - // We do not retry incomplete writes, this is stdout after all... - let safe_count = match s.as_bytes().len().try_into() { - Ok(count)=> count, - Err(_) => return Err(Error) + let Ok(written_unsigned): Result = written.try_into() else { + return Err(Error); }; - if result < safe_count { - Err(Error) + if written_unsigned < s.as_bytes().len() { + return Err(Error); } else { - Ok(()) + return Ok(()); } } } impl Write for Stderr { fn write_str(&mut self, s: &str) -> Result<(), Error> { - - // Safe because write will only read the pointer an then return - // try_into is used as write call is different depending on platform - let len_converted = match s.as_bytes().len().try_into(){ - Ok(value) => value, - Err(_) => return Err(Error) + #[allow(irrefutable_let_patterns)] // is refutable on some exotic targets. See above + let Ok(len_converted) = s.as_bytes().len().try_into() else { + return Err(Error); }; - let result = unsafe { - crate::fsrc::osal::ffi::write( - 1, + // Safe because write will only read the pointer an then return + let written = unsafe { + crate::fsrc::osal::ffi::write( + 2, s.as_bytes().as_ptr() as *const core::ffi::c_void, len_converted, ) }; - // We do not retry incomplete writes, this is stdout after all... - let safe_count = match s.as_bytes().len().try_into() { - Ok(count)=> count, - Err(_) => return Err(Error) + let Ok(written_unsigned): Result = written.try_into() else { + return Err(Error); }; - if result < safe_count { - Err(Error) + if written_unsigned < s.as_bytes().len() { + return Err(Error); } else { - Ok(()) + return Ok(()); } } } +// TODO I am not sure if crate::fsrc::sif::Stdout is the correct way here #[macro_export] macro_rules! sifln { ($(,)?) => ( - //let mut stdout = Outbytes {}; - writeln!(Stdout {}); + {let _alwaysok = writeln!(crate::fsrc::sif::Stdout {});} ); ($($arg:tt)*) => ( {let _alwaysok = writeln!(crate::fsrc::sif::Stdout {}, $($arg)*);} @@ -82,6 +70,9 @@ macro_rules! sifln { #[macro_export] macro_rules! sif { + ($(,)?) => ( + {let _alwaysok = writeln!(crate::fsrc::sif::Stdout {});} + ); ($($arg:tt)*) => ( let _alwaysok = write!(crate::fsrc::sif::Stdout {}, $($arg)*); ); diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index 1b63256..f05e40c 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -186,17 +186,9 @@ static THREAD_3: StaticReadOnceLock< Duration::from_millis(200), )); -extern "C" { - fn done() -> !; -} - fn init_task() -> ! { sifln!("Mission enter"); - // unsafe{done()}; - - // panic!("Oh no!"); - let commands = [dh::Command(0), dh::Command(1), dh::Command(2)]; let mut debugger = DeviceHandlerDebugger::new( EchoHandler { buffer: [0; 10] }, @@ -207,13 +199,7 @@ fn init_task() -> ! { 0.5, ); - let result = debugger.run(); - if let Err(e) = result { - sifln!("{e}"); - panic!(""); - } - - panic!("done"); + debugger.run().unwrap(); let test1 = TEST1.take().unwrap(); let test2 = TEST2.take().unwrap();