From cbe8184fab31101976fbbd1e340fe9962794100d Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Sat, 20 Jul 2024 00:27:24 +0200 Subject: [PATCH] portable device access api based on unix file descriptors --- bsp_linux/CMakeLists.txt | 2 + bsp_linux/hardware/CMakeLists.txt | 1 + bsp_linux/hardware/hardware.c | 28 +++++++++ bsp_linux/main.c | 47 +++++++++++---- bsp_z7/CMakeLists.txt | 3 +- bsp_z7/hardware/CMakeLists.txt | 1 + bsp_z7/hardware/interface_access.h | 5 ++ bsp_z7/hardware/interface_fds.h | 7 +++ bsp_z7/hardware/interfaces.c | 70 ++++++++++++++++++++++ bsp_z7/main.c | 4 ++ bsp_z7/newlib/CMakeLists.txt | 2 +- bsp_z7/newlib/close.c | 0 bsp_z7/newlib/read.c | 5 ++ bsp_z7/newlib/write.c | 40 ++++++++++--- common/CMakeLists.txt | 4 +- common/include/hardware/interfaces.h | 37 ++++++++++++ common/printChar.c | 10 ---- mission/mission.c | 7 +++ mission_rust/Cargo.lock | 34 ----------- mission_rust/Cargo.toml | 5 +- mission_rust/descriptor_procmac/Cargo.toml | 10 ---- mission_rust/descriptor_procmac/src/lib.rs | 41 ------------- mission_rust/src/lib.rs | 11 ---- 23 files changed, 241 insertions(+), 133 deletions(-) create mode 100644 bsp_linux/hardware/CMakeLists.txt create mode 100644 bsp_linux/hardware/hardware.c create mode 100644 bsp_z7/hardware/CMakeLists.txt create mode 100644 bsp_z7/hardware/interface_access.h create mode 100644 bsp_z7/hardware/interface_fds.h create mode 100644 bsp_z7/hardware/interfaces.c create mode 100644 bsp_z7/newlib/close.c create mode 100644 bsp_z7/newlib/read.c create mode 100644 common/include/hardware/interfaces.h delete mode 100644 common/printChar.c delete mode 100644 mission_rust/descriptor_procmac/Cargo.toml delete mode 100644 mission_rust/descriptor_procmac/src/lib.rs diff --git a/bsp_linux/CMakeLists.txt b/bsp_linux/CMakeLists.txt index 43c1760..86fefb8 100644 --- a/bsp_linux/CMakeLists.txt +++ b/bsp_linux/CMakeLists.txt @@ -1 +1,3 @@ +add_subdirectory(hardware) + target_sources(${TARGET_NAME} PRIVATE main.c) \ No newline at end of file diff --git a/bsp_linux/hardware/CMakeLists.txt b/bsp_linux/hardware/CMakeLists.txt new file mode 100644 index 0000000..8ca523c --- /dev/null +++ b/bsp_linux/hardware/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${TARGET_NAME} PRIVATE hardware.c) \ No newline at end of file diff --git a/bsp_linux/hardware/hardware.c b/bsp_linux/hardware/hardware.c new file mode 100644 index 0000000..973dcd6 --- /dev/null +++ b/bsp_linux/hardware/hardware.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +extern const char *device_root; + +int hw_device_open(const char *path, size_t path_len) { + int sock; + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + perror(NULL); + exit(-1); + } + struct sockaddr_un address; + address.sun_family = AF_UNIX; + snprintf(address.sun_path, sizeof(address.sun_path), "%s%.*s", device_root, + path_len, path); + if (connect(sock, (struct sockaddr *)&address, sizeof(address)) != 0) { + perror(NULL); + exit(-1); + } + return sock; +} \ No newline at end of file diff --git a/bsp_linux/main.c b/bsp_linux/main.c index 2d8ba34..4b81135 100644 --- a/bsp_linux/main.c +++ b/bsp_linux/main.c @@ -1,27 +1,52 @@ -#include +#include +#include #include +#include #include - +#include +#include +#include #include +const char *device_root = "./"; + void mission(void); -int get_descriptor_rw() { - return 1; -} +int get_descriptor_rw() { return 1; } void done() { printf("done.\n"); exit(0); } +int test_socket(); + // Don't ask me, it makes the linker happy and does not seem // to break anything ¯\_(ツ)_/¯ -void rust_eh_personality() { - puts("eh_personality"); -} +void rust_eh_personality() { puts("eh_personality"); } -int main(void) { - mission(); - return 0; +int main(int argc, char **argv) { + static struct option long_options[] = { + /* NAME ARGUMENT FLAG SHORTNAME */ + {"device-root", required_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}}; + int c; + int option_index = 0; + while ((c = getopt_long(argc, argv, "hd:", long_options, &option_index)) != + -1) { + switch (c) { + case 'd': + if (optarg != NULL) { + device_root = optarg; + break; + default: + fprintf(stderr, "Usage: %s -d device-root\n", argv[0]); + exit(EXIT_FAILURE); + } + } + } + + mission(); + return 0; } \ No newline at end of file diff --git a/bsp_z7/CMakeLists.txt b/bsp_z7/CMakeLists.txt index d5d3e3d..c3ab00e 100644 --- a/bsp_z7/CMakeLists.txt +++ b/bsp_z7/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(freeRTOS) add_subdirectory(ps7_cortexa9_0) add_subdirectory(newlib) +add_subdirectory(hardware) -target_sources(${TARGET_NAME} PRIVATE main.c) \ No newline at end of file +target_sources(${TARGET_NAME} PRIVATE main.c) diff --git a/bsp_z7/hardware/CMakeLists.txt b/bsp_z7/hardware/CMakeLists.txt new file mode 100644 index 0000000..e3fa27e --- /dev/null +++ b/bsp_z7/hardware/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${TARGET_NAME} PRIVATE interfaces.c) \ No newline at end of file diff --git a/bsp_z7/hardware/interface_access.h b/bsp_z7/hardware/interface_access.h new file mode 100644 index 0000000..5578958 --- /dev/null +++ b/bsp_z7/hardware/interface_access.h @@ -0,0 +1,5 @@ +#pragma once + +int hw_interface_write(int fd, const char *ptr, int len); + +int hw_interface_read(int fd, char *ptr, int len); \ No newline at end of file diff --git a/bsp_z7/hardware/interface_fds.h b/bsp_z7/hardware/interface_fds.h new file mode 100644 index 0000000..d0ff4a9 --- /dev/null +++ b/bsp_z7/hardware/interface_fds.h @@ -0,0 +1,7 @@ +#pragma once + +enum InterfaceFileDescriptors { + UART_0 = 3, + UART_1, + INTERFACE_FDS_NEXT +}; \ No newline at end of file diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c new file mode 100644 index 0000000..c067f78 --- /dev/null +++ b/bsp_z7/hardware/interfaces.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include "interface_access.h" +#include "interface_fds.h" + +int compare_string_chars(const char *c_string, const char *chars, + size_t chars_len) { + for(int i = 0; i < chars_len; i++) { + if (c_string[i] == 0) { + return 0; + } + if (c_string[i] != chars[i]) {; + return 0; + } + } + return 1; +} + +int hw_device_open(const char *path, size_t path_len) { + if (compare_string_chars("uart0", path, path_len) == 1) { + return UART_0; + } + if (compare_string_chars("uart1", path, path_len) == 1) { + return UART_1; + } + + return -1; +} + +ssize_t hw_device_transfer(int fd, void *sendbuffer, void *receivebuffer, + size_t buffer_len) { + return -1; +} + +// 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 send_uart(uint32_t BaseAddress, const char *data, int 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) { + enum InterfaceFileDescriptors fd_enum = fd; + switch (fd) { + case UART_0: + send_uart(XPS_UART0_BASEADDR, ptr, len); + return len; + case UART_1: + send_uart(XPS_UART1_BASEADDR, ptr, len); + return len; + } + return -1; +} + +int hw_interface_read(int fd, char *ptr, int len) { + enum InterfaceFileDescriptors fd_enum = fd; + switch (fd) { + case UART_0: + return 0; + case UART_1: + return 0; + } + return -1; +} \ No newline at end of file diff --git a/bsp_z7/main.c b/bsp_z7/main.c index 0dbb160..39cf8d6 100644 --- a/bsp_z7/main.c +++ b/bsp_z7/main.c @@ -47,6 +47,10 @@ XScuGic xInterruptController; extern SemaphoreHandle_t malloc_mutex; +int get_descriptor_rw() { + return 1; +} + /*-----------------------------------------------------------*/ void mission(void); diff --git a/bsp_z7/newlib/CMakeLists.txt b/bsp_z7/newlib/CMakeLists.txt index 09d4bd8..d8479a2 100644 --- a/bsp_z7/newlib/CMakeLists.txt +++ b/bsp_z7/newlib/CMakeLists.txt @@ -1 +1 @@ -target_sources(${TARGET_NAME} PRIVATE write.c) \ No newline at end of file +target_sources(${TARGET_NAME} PRIVATE close.c read.c write.c) \ No newline at end of file diff --git a/bsp_z7/newlib/close.c b/bsp_z7/newlib/close.c new file mode 100644 index 0000000..e69de29 diff --git a/bsp_z7/newlib/read.c b/bsp_z7/newlib/read.c new file mode 100644 index 0000000..f0538ce --- /dev/null +++ b/bsp_z7/newlib/read.c @@ -0,0 +1,5 @@ + + +int _read(int file, char *ptr, int len) { + return 0; +} \ No newline at end of file diff --git a/bsp_z7/newlib/write.c b/bsp_z7/newlib/write.c index 365fb29..8d76e1b 100644 --- a/bsp_z7/newlib/write.c +++ b/bsp_z7/newlib/write.c @@ -1,15 +1,41 @@ #include "xil_printf.h" #include "xparameters.h" -int write(int file, char *ptr, int len) { +#include "../hardware/interface_access.h" +#include "../hardware/interface_fds.h" + + +// 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) { if (ptr == NULL) { return 0; } - // TODO file descriptors - int todo; - - for (todo = 0; todo < len; todo++) { - outbyte(*ptr++); + + // 0 is stdin, do not write to it + if (fd < 1) { + return -1; // TODO error } - return len; + // we only support a single debug UART, so + // stdout and stderr are the same and go to the xiling stdout UART + // TODO switch to a hw_interface_write() instead? + if (fd < 3) { + int todo; + + for (todo = 0; todo < len; todo++) { + outbyte(*ptr++); + } + return len; + } + + if (fd < INTERFACE_FDS_NEXT) { + return hw_interface_write(fd, ptr, len); + } + + // we do not have dynamic fds, so fd is invalid + return -1; } \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index f513753..e76b650 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,3 +1 @@ -target_sources( - ${TARGET_NAME} PRIVATE - printChar.c) \ No newline at end of file +target_include_directories(${TARGET_NAME} PRIVATE include) \ No newline at end of file diff --git a/common/include/hardware/interfaces.h b/common/include/hardware/interfaces.h new file mode 100644 index 0000000..c01f920 --- /dev/null +++ b/common/include/hardware/interfaces.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +/** + * Access to hardware interfaces local to the machine the code is running on. + * + * The file descriptor returned by hw_decvice_open() is to be used by the standard + * read/write calls and to be closed by close(). + * + * For some specific hardware interfaces specific transactional calls are provided here + * to increase realtime performance. + * + * So far the only example is an SPI interface, which performs synchronous transfers of + * n bytes in, n bytes out. If a write call is performed on such an interface, the number + * of bytes transfered equals the size of the hardware send buffer. For a read() call, the + * bytes contained in the hardware's receive buffer are returned. + */ + +/** + * open a hardware device + * + * if successful, returns a file descriptor to be used with read/write/transfer/close calls + * otherwise returns -1 + */ +int hw_device_open(const char * path, size_t path_len); + +/** + * Perform a transfer of buffer_len bytes in and out. + * + * sendbuffer and receivebuffer may be equal, where received bytes overwrite + * send bytes. + * + * returns actual number of bytes transfered + */ +ssize_t hw_device_transfer(int fd, void* sendbuffer, void* receivebuffer, size_t buffer_len); \ No newline at end of file diff --git a/common/printChar.c b/common/printChar.c deleted file mode 100644 index d5cc34c..0000000 --- a/common/printChar.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -void printChar(const char* character, bool errStream) { - if (errStream) { - fprintf(stderr, "%c", *character); - } else { - printf("%c", *character); - } -} diff --git a/mission/mission.c b/mission/mission.c index bfb0a3b..5e404b7 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -25,7 +25,14 @@ void init_task(void *) { vTaskDelete(NULL); } +#include +#include + void mission(void) { + int fd0 = hw_device_open("uart0", 5); + write(fd0, "uart0\n", 6); + int fd1 = hw_device_open("uart1", 5); + write(fd1, "uart1\n", 6); int taskParameters = 0; diff --git a/mission_rust/Cargo.lock b/mission_rust/Cargo.lock index 3d7ef28..c0a15a2 100644 --- a/mission_rust/Cargo.lock +++ b/mission_rust/Cargo.lock @@ -2,40 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "descriptor_procmac" -version = "0.1.0" -dependencies = [ - "quote", -] - [[package]] name = "mission_rust" version = "0.1.0" -dependencies = [ - "descriptor_procmac", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/mission_rust/Cargo.toml b/mission_rust/Cargo.toml index 8dc6e3d..78f6b6b 100644 --- a/mission_rust/Cargo.toml +++ b/mission_rust/Cargo.toml @@ -10,7 +10,4 @@ crate-type = ["staticlib"] panic = 'abort' [profile.release] -panic = 'abort' - -[dependencies] -descriptor_procmac = { path = "./descriptor_procmac" } \ No newline at end of file +panic = 'abort' \ No newline at end of file diff --git a/mission_rust/descriptor_procmac/Cargo.toml b/mission_rust/descriptor_procmac/Cargo.toml deleted file mode 100644 index 24704c8..0000000 --- a/mission_rust/descriptor_procmac/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "descriptor_procmac" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -quote = "1.0" \ No newline at end of file diff --git a/mission_rust/descriptor_procmac/src/lib.rs b/mission_rust/descriptor_procmac/src/lib.rs deleted file mode 100644 index b04c0b5..0000000 --- a/mission_rust/descriptor_procmac/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![crate_type = "proc-macro"] -extern crate proc_macro; -use proc_macro::TokenStream; - -#[proc_macro] -pub fn Device_Descriptor(input: TokenStream) -> TokenStream { - let first_token = input.into_iter().next().unwrap(); // Do proper error handling! - let raw_string = first_token.to_string(); - let raw_string_len = raw_string.len(); - let identifier = &first_token.to_string()[1..raw_string_len-1]; - println!("first: {}", identifier); - // let value = match first_token { - // Literal { symbol, kind: Str, ..} => {println!("yes: {}", symbol); "12"}, - // _ => "13", - // }; - // let string_value = match litrs::StringLit::try_from(first_token) { - // Ok(string_lit) => string_lit, - // Err(e) => return e.to_compile_error(), - // }; - let getter_name = quote::format_ident!("get_descriptor_{}", identifier); - let struct_name = quote::format_ident!("Descriptor_{}", identifier); - let tokens = quote::quote!( - extern "C" { - pub fn #getter_name() -> core::ffi::c_int; - pub fn write(fd: core::ffi::c_int, buffer: *const core::ffi::c_void, count: usize) -> core::ffi::c_int; - } - - struct #struct_name {} - - impl Hardware_Write for #struct_name { - fn write(&mut self, buf: &[u8]) -> Result{ - unsafe { - let fd = #getter_name( ); - let written = write(fd, buf.as_ptr() as *const core::ffi::c_void, buf.len()); - Ok(written) - } - } - } - ); - tokens.into() -} diff --git a/mission_rust/src/lib.rs b/mission_rust/src/lib.rs index ee59741..6ce067a 100644 --- a/mission_rust/src/lib.rs +++ b/mission_rust/src/lib.rs @@ -11,14 +11,6 @@ use core::panic::PanicInfo; use fsrc::objectmanager::SystemObjectIF; use fsrc::*; -use descriptor_procmac::Device_Descriptor; - -trait Hardware_Write { - fn write(&mut self, buf: &[u8]) -> Result; -} - -Device_Descriptor!("rw"); - extern "C" { fn done(); } @@ -78,9 +70,6 @@ extern "C" fn rust_alloc_failed(){ #[no_mangle] extern "C" fn rust_main() { sifln!("Rust startup 🚀"); - let mut rw = Descriptor_rw{}; - let data: &[u8] = &[0x30,0x31,10]; - _ = rw.write(data); mission(); sifln!("Mission done"); }