forked from ROMEO/obsw
portable device access api based on unix file descriptors
This commit is contained in:
parent
49c19ba675
commit
cbe8184fab
@ -1 +1,3 @@
|
|||||||
|
add_subdirectory(hardware)
|
||||||
|
|
||||||
target_sources(${TARGET_NAME} PRIVATE main.c)
|
target_sources(${TARGET_NAME} PRIVATE main.c)
|
1
bsp_linux/hardware/CMakeLists.txt
Normal file
1
bsp_linux/hardware/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
target_sources(${TARGET_NAME} PRIVATE hardware.c)
|
28
bsp_linux/hardware/hardware.c
Normal file
28
bsp_linux/hardware/hardware.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hardware/interfaces.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -1,27 +1,52 @@
|
|||||||
#include <stdio.h>
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
const char *device_root = "./";
|
||||||
|
|
||||||
void mission(void);
|
void mission(void);
|
||||||
|
|
||||||
int get_descriptor_rw() {
|
int get_descriptor_rw() { return 1; }
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void done() {
|
void done() {
|
||||||
printf("done.\n");
|
printf("done.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_socket();
|
||||||
|
|
||||||
// Don't ask me, it makes the linker happy and does not seem
|
// Don't ask me, it makes the linker happy and does not seem
|
||||||
// to break anything ¯\_(ツ)_/¯
|
// to break anything ¯\_(ツ)_/¯
|
||||||
void rust_eh_personality() {
|
void rust_eh_personality() { puts("eh_personality"); }
|
||||||
puts("eh_personality");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **argv) {
|
||||||
mission();
|
static struct option long_options[] = {
|
||||||
return 0;
|
/* 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;
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
add_subdirectory(freeRTOS)
|
add_subdirectory(freeRTOS)
|
||||||
add_subdirectory(ps7_cortexa9_0)
|
add_subdirectory(ps7_cortexa9_0)
|
||||||
add_subdirectory(newlib)
|
add_subdirectory(newlib)
|
||||||
|
add_subdirectory(hardware)
|
||||||
|
|
||||||
target_sources(${TARGET_NAME} PRIVATE main.c)
|
target_sources(${TARGET_NAME} PRIVATE main.c)
|
||||||
|
1
bsp_z7/hardware/CMakeLists.txt
Normal file
1
bsp_z7/hardware/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
target_sources(${TARGET_NAME} PRIVATE interfaces.c)
|
5
bsp_z7/hardware/interface_access.h
Normal file
5
bsp_z7/hardware/interface_access.h
Normal file
@ -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);
|
7
bsp_z7/hardware/interface_fds.h
Normal file
7
bsp_z7/hardware/interface_fds.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum InterfaceFileDescriptors {
|
||||||
|
UART_0 = 3,
|
||||||
|
UART_1,
|
||||||
|
INTERFACE_FDS_NEXT
|
||||||
|
};
|
70
bsp_z7/hardware/interfaces.c
Normal file
70
bsp_z7/hardware/interfaces.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include <hardware/interfaces.h>
|
||||||
|
#include <xparameters_ps.h>
|
||||||
|
#include <xuartps.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
@ -47,6 +47,10 @@ XScuGic xInterruptController;
|
|||||||
|
|
||||||
extern SemaphoreHandle_t malloc_mutex;
|
extern SemaphoreHandle_t malloc_mutex;
|
||||||
|
|
||||||
|
int get_descriptor_rw() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
void mission(void);
|
void mission(void);
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
target_sources(${TARGET_NAME} PRIVATE write.c)
|
target_sources(${TARGET_NAME} PRIVATE close.c read.c write.c)
|
0
bsp_z7/newlib/close.c
Normal file
0
bsp_z7/newlib/close.c
Normal file
5
bsp_z7/newlib/read.c
Normal file
5
bsp_z7/newlib/read.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
int _read(int file, char *ptr, int len) {
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,15 +1,41 @@
|
|||||||
#include "xil_printf.h"
|
#include "xil_printf.h"
|
||||||
#include "xparameters.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) {
|
if (ptr == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// TODO file descriptors
|
|
||||||
int todo;
|
// 0 is stdin, do not write to it
|
||||||
|
if (fd < 1) {
|
||||||
for (todo = 0; todo < len; todo++) {
|
return -1; // TODO error
|
||||||
outbyte(*ptr++);
|
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
@ -1,3 +1 @@
|
|||||||
target_sources(
|
target_include_directories(${TARGET_NAME} PRIVATE include)
|
||||||
${TARGET_NAME} PRIVATE
|
|
||||||
printChar.c)
|
|
37
common/include/hardware/interfaces.h
Normal file
37
common/include/hardware/interfaces.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
@ -1,10 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void printChar(const char* character, bool errStream) {
|
|
||||||
if (errStream) {
|
|
||||||
fprintf(stderr, "%c", *character);
|
|
||||||
} else {
|
|
||||||
printf("%c", *character);
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,7 +25,14 @@ void init_task(void *) {
|
|||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <hardware/interfaces.h>
|
||||||
|
|
||||||
void mission(void) {
|
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;
|
int taskParameters = 0;
|
||||||
|
|
||||||
|
34
mission_rust/Cargo.lock
generated
34
mission_rust/Cargo.lock
generated
@ -2,40 +2,6 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "descriptor_procmac"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mission_rust"
|
name = "mission_rust"
|
||||||
version = "0.1.0"
|
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"
|
|
||||||
|
@ -10,7 +10,4 @@ crate-type = ["staticlib"]
|
|||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
descriptor_procmac = { path = "./descriptor_procmac" }
|
|
@ -1,10 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "descriptor_procmac"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
quote = "1.0"
|
|
@ -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<core::ffi::c_int,()>{
|
|
||||||
unsafe {
|
|
||||||
let fd = #getter_name( );
|
|
||||||
let written = write(fd, buf.as_ptr() as *const core::ffi::c_void, buf.len());
|
|
||||||
Ok(written)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
tokens.into()
|
|
||||||
}
|
|
@ -11,14 +11,6 @@ use core::panic::PanicInfo;
|
|||||||
use fsrc::objectmanager::SystemObjectIF;
|
use fsrc::objectmanager::SystemObjectIF;
|
||||||
use fsrc::*;
|
use fsrc::*;
|
||||||
|
|
||||||
use descriptor_procmac::Device_Descriptor;
|
|
||||||
|
|
||||||
trait Hardware_Write {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<core::ffi::c_int,()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
Device_Descriptor!("rw");
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn done();
|
fn done();
|
||||||
}
|
}
|
||||||
@ -78,9 +70,6 @@ extern "C" fn rust_alloc_failed(){
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn rust_main() {
|
extern "C" fn rust_main() {
|
||||||
sifln!("Rust startup 🚀");
|
sifln!("Rust startup 🚀");
|
||||||
let mut rw = Descriptor_rw{};
|
|
||||||
let data: &[u8] = &[0x30,0x31,10];
|
|
||||||
_ = rw.write(data);
|
|
||||||
mission();
|
mission();
|
||||||
sifln!("Mission done");
|
sifln!("Mission done");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user