starting interface access from rust

This commit is contained in:
2025-10-22 21:31:40 +02:00
parent bb5fbf19cf
commit 556faaba08
11 changed files with 206 additions and 15 deletions
+1 -1
View File
@@ -1 +1 @@
target_sources(bsp PRIVATE hardware.c)
target_sources(bsp PRIVATE hardware.c serial.c)
+11
View File
@@ -11,6 +11,8 @@
#include <hardware/interfaces.h>
#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;
+68
View File
@@ -0,0 +1,68 @@
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <termios.h>
#include <unistd.h>
// 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;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <stdlib.h>
// returns fd if success, -1 if no path match <-1 if error
int serial_open(const char *path, size_t path_len);
+3 -1
View File
@@ -2,6 +2,8 @@
#include "semphr.h"
#include "task.h"
#include <errno.h>
#include <inttypes.h>
#include <string.h>
@@ -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);
}
}
+3 -2
View File
@@ -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;
+14
View File
@@ -0,0 +1,14 @@
#[derive(Debug)]
pub enum UnixError{
NoSuchFileOrDirectory,
Unknown(i32)
}
impl From<i32> for UnixError{
fn from(value: i32) -> Self {
match value {
2 => UnixError::NoSuchFileOrDirectory,
any => Self::Unknown(any)
}
}
}
+29 -1
View File
@@ -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;
}
+46
View File
@@ -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<i32> for Error {
fn from(value: i32) -> Self {
match value {
-2 => Error::AlreadyOpen,
-3 => Error::InvalidPath,
any => Error::Unknown(any)
}
}
}
pub type Result<T> = core::result::Result<T,Error>;
#[derive(Debug)]
pub struct Interface{
fd: core::ffi::c_int,
}
impl Interface {
pub fn new(path: &str) -> Result<Self> {
// 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]) {
}
}
+21 -10
View File
@@ -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)
};
+4
View File
@@ -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();