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