forked from ROMEO/fsw-ws
Merge branch 'main' into hinkel/readme
This commit is contained in:
+2
-1
@@ -4,4 +4,5 @@
|
||||
.vscode
|
||||
__pycache__/*
|
||||
**/__pycache__/*
|
||||
*.elf
|
||||
*.elf
|
||||
.cache
|
||||
|
||||
+9
-1
@@ -15,7 +15,7 @@ set(ROMEO_WARNING_FLAGS
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Werror)
|
||||
-Werror) # TODO so far, this only affects mission code, not bsp
|
||||
|
||||
# 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(ARM_SEMIHOSTING "enable semihosting for emulation" OFF)
|
||||
|
||||
if(${ARM_SEMIHOSTING})
|
||||
add_compile_definitions(ARM_SEMIHOSTING)
|
||||
endif()
|
||||
else()
|
||||
unset(ZYNQ_UART)
|
||||
unset(ZYNQ_UART CACHE)
|
||||
unset(ARM_SEMIHOSTING)
|
||||
unset(ARM_SEMIHOSTING CACHE)
|
||||
endif()
|
||||
|
||||
# Add main executable
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -1 +1 @@
|
||||
target_sources(bsp PRIVATE hardware.c)
|
||||
target_sources(bsp PRIVATE hardware.c serial.c)
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <hardware/interfaces.h>
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
extern const char *sim_ip;
|
||||
extern int ai_family;
|
||||
|
||||
@@ -39,6 +41,13 @@ const char *get_port_number(const char *path, size_t path_len) {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -67,7 +76,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;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 -1;
|
||||
}
|
||||
|
||||
struct termios termios;
|
||||
|
||||
// initialize termios struct
|
||||
int ret = tcgetattr(fd, &termios);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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 -1;
|
||||
}
|
||||
|
||||
ret = tcsetattr(fd, TCSANOW, &termios);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
if (compare_string_chars("debug/uart🚀", path, path_len) == 1) {
|
||||
return serial_open_actual("/dev/ttyUSB0", B115200);
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
@@ -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);
|
||||
+11
-9
@@ -14,23 +14,26 @@ int ai_family = AF_UNSPEC;
|
||||
|
||||
void mission(void);
|
||||
|
||||
int get_descriptor_rw() { return 1; }
|
||||
void done() { exit(0); }
|
||||
|
||||
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?
|
||||
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 <hardware/interfaces.h>
|
||||
|
||||
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'},
|
||||
@@ -56,9 +59,8 @@ int main(int argc, char **argv) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mission();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
int hw_interface_write(int fd, const char *ptr, int len);
|
||||
#include <stddef.h>
|
||||
|
||||
int hw_interface_read(int fd, char *ptr, int len);
|
||||
int hw_interface_write(int fd, const char *ptr, size_t len);
|
||||
|
||||
int hw_interface_read(int fd, char *ptr, size_t len);
|
||||
@@ -7,6 +7,10 @@
|
||||
#include "interface_fds.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int compare_string_chars(const char *c_string, const char *chars,
|
||||
size_t chars_len) {
|
||||
for(int i = 0; i < chars_len; i++) {
|
||||
@@ -26,11 +30,16 @@ 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;
|
||||
}
|
||||
|
||||
_REENT_ERRNO(_REENT) = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -39,17 +48,19 @@ 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
|
||||
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:
|
||||
@@ -59,10 +70,11 @@ 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;
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
@@ -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);
|
||||
@@ -144,8 +143,9 @@ void uart1_enable_receiver() {
|
||||
XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_1_INTR);
|
||||
}
|
||||
|
||||
int uart0_read(char *ptr, int len) {
|
||||
// TODO for blocking, if first call was successfull, further calls need to be delay=0
|
||||
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;
|
||||
while (len > 0) {
|
||||
BaseType_t result = xQueueReceive(uart0_receive_queue, ptr, 0);
|
||||
@@ -159,8 +159,9 @@ int uart0_read(char *ptr, int len) {
|
||||
return received;
|
||||
}
|
||||
|
||||
int uart1_read(char *ptr, int len) {
|
||||
// TODO for blocking, if first call was successfull, further calls need to be delay=0
|
||||
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;
|
||||
while (len > 0) {
|
||||
BaseType_t result = xQueueReceive(uart1_receive_queue, ptr, 0);
|
||||
|
||||
@@ -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);
|
||||
int uart1_read(char *ptr, int size_t);
|
||||
+52
-10
@@ -47,10 +47,6 @@ XScuGic xInterruptController;
|
||||
|
||||
extern SemaphoreHandle_t malloc_mutex;
|
||||
|
||||
int get_descriptor_rw() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
void mission(void);
|
||||
|
||||
@@ -58,10 +54,17 @@ 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();
|
||||
|
||||
mission();
|
||||
mission();
|
||||
}
|
||||
|
||||
static void prvSetupHardware(void) {
|
||||
@@ -120,8 +123,44 @@ void vInitialiseTimerForRunTimeStats(void) {
|
||||
XScuWdt_Start(&xWatchDogInstance);
|
||||
}
|
||||
|
||||
// Marker for debugging sessions
|
||||
__attribute__((noinline)) void done() { asm(""); }
|
||||
#ifndef ARM_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
|
||||
reg1 = 0x20026; // ADP_Stopped_ApplicationExit
|
||||
|
||||
asm("svc 0x123456"); // syscall to semihosting interface
|
||||
}
|
||||
|
||||
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
|
||||
reg1 = 0x20023; // ADP_Stopped_RunTimeErrorUnknown
|
||||
|
||||
asm("svc 0x123456"); // syscall to semihosting interface
|
||||
}
|
||||
|
||||
#endif /* SEMIHOSTING */
|
||||
|
||||
void vApplicationIdleHook(void) {
|
||||
volatile size_t xFreeHeapSpace, xMinimumEverFreeHeapSpace;
|
||||
@@ -168,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
|
||||
@@ -179,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);
|
||||
@@ -188,4 +231,3 @@ is BAD! */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+22
-14
@@ -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 <errno.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
+21
-13
@@ -4,39 +4,47 @@
|
||||
#include "../hardware/interface_access.h"
|
||||
#include "../hardware/interface_fds.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.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) {
|
||||
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;
|
||||
}
|
||||
@@ -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 *****************************/
|
||||
|
||||
|
||||
@@ -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 *****************************/
|
||||
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
# TODO directly referencing bsp is not correct
|
||||
target_include_directories(bsp PUBLIC include)
|
||||
target_include_directories(bsp PUBLIC include)
|
||||
|
||||
add_subdirectory(git_version)
|
||||
@@ -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()
|
||||
@@ -0,0 +1,3 @@
|
||||
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})
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#cmakedefine GIT_VERSION_STRING "@GIT_VERSION_STRING@"
|
||||
#cmakedefine BUILD_TIME_STRING "@BUILD_TIME_STRING@"
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -9,23 +11,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 +32,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 +155,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 +170,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 +184,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 +234,20 @@ uint8_t freertos_simple_once(uint8_t *once_data) {
|
||||
// TODO assert global_once_mutex != NULL
|
||||
|
||||
uint8_t result = 0;
|
||||
|
||||
// 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 +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;
|
||||
}
|
||||
+17
-35
@@ -1,55 +1,37 @@
|
||||
/* Standard includes. */
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "freeRTOS_rust_helper.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <hardware/interfaces.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <git_version.h>
|
||||
#include <string.h>
|
||||
|
||||
void rust_main();
|
||||
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 (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* _) {
|
||||
rust_main(_);
|
||||
void init_task(void *_) {
|
||||
(void)_;
|
||||
rust_main();
|
||||
}
|
||||
|
||||
#define STARTUP_MESSAGE1 "\nROMEO embedded obsw\nRelease: "
|
||||
#define STARTUP_MESSAGE2 "\nBuild time: "
|
||||
|
||||
void mission(void) {
|
||||
|
||||
|
||||
test_hardware();
|
||||
|
||||
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);
|
||||
|
||||
freertos_init_and_start_scheduling(init_task);
|
||||
|
||||
@@ -62,7 +44,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 (;;)
|
||||
;
|
||||
|
||||
@@ -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
|
||||
@@ -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}/$<IF:$<CONFIG:Release>,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/$<IF:$<CONFIG:Release>,release,debug>/)
|
||||
|
||||
add_library(mission_rust INTERFACE)
|
||||
|
||||
add_dependencies(mission_rust mission_rust_internal)
|
||||
|
||||
@@ -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<Self::DeviceReply>, &'a [u8]) {
|
||||
if data.len() == 0 {
|
||||
return (None, data);
|
||||
}
|
||||
|
||||
(Some(Reply(data[0])), &data[1..])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
use core::fmt::Write;
|
||||
use core::{fmt::Display, time::Duration};
|
||||
|
||||
use crate::{
|
||||
fsrc::{
|
||||
dh::DeviceCom,
|
||||
osal::{
|
||||
self,
|
||||
io::{HardwareInterface, Read, Write as DeviceWrite},
|
||||
},
|
||||
},
|
||||
sifln,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
IoError(osal::io::Error),
|
||||
ToDo
|
||||
}
|
||||
|
||||
impl From<osal::io::Error> for Error {
|
||||
fn from(value: osal::io::Error) -> Self {
|
||||
Self::IoError(value)
|
||||
}
|
||||
}
|
||||
|
||||
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<T> = core::result::Result<T, Error>;
|
||||
|
||||
pub struct DeviceHandlerDebugger<'a, T: DeviceCom> {
|
||||
implementation: T,
|
||||
init_commands: &'a [<T as DeviceCom>::DeviceCommand],
|
||||
periodic_commands: &'a [<T as DeviceCom>::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 [<T as DeviceCom>::DeviceCommand],
|
||||
periodic_commands: &'a [<T as DeviceCom>::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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Self::DeviceReply>, &'a [u8]);
|
||||
|
||||
// Advance State Machine?
|
||||
// Write into Datapool
|
||||
// fn handle_reply(&mut self, reply: Self::DeviceReply);
|
||||
}
|
||||
@@ -8,4 +8,5 @@ pub mod osal;
|
||||
//pub mod datasets;
|
||||
//pub mod store;
|
||||
//pub mod mutex;
|
||||
pub mod introspection;
|
||||
pub mod introspection;
|
||||
pub mod dh;
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
use crate::fsrc::osal::ffi;
|
||||
|
||||
// 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() }
|
||||
}
|
||||
|
||||
// This is a merge of newlib and x86_64-glibc-linux
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub enum OsError {
|
||||
ArgumentListTooLong,
|
||||
PermissionDenied,
|
||||
AddressAlreadyInUse,
|
||||
AddressNotAvailable,
|
||||
AdvertiseError,
|
||||
AddressFamilyNotSupportedByProtocol,
|
||||
OperationWouldBlock,
|
||||
OperationAlreadyInProgress,
|
||||
InvalidExchange,
|
||||
BadFileDescriptor,
|
||||
FileDescriptorInBadState,
|
||||
BadMessage,
|
||||
InvalidRequestDescriptor,
|
||||
InvalidRequestCode,
|
||||
InvalidSlot,
|
||||
BadFontFileFormat,
|
||||
DeviceOrResourceBusy,
|
||||
OperationCanceled,
|
||||
FilenameExistsWithDifferentCase,
|
||||
NoChildProcesses,
|
||||
ChannelNumberOutOfRange,
|
||||
CommunicationErrorOnSend,
|
||||
SoftwareCausedConnectionAbort,
|
||||
ConnectionRefused,
|
||||
ConnectionResetByPeer,
|
||||
Deadlock,
|
||||
DestinationAddressRequired,
|
||||
NumericalArgumentOutOfDomain,
|
||||
FsError,
|
||||
DiskQuotaExceeded,
|
||||
FileExists,
|
||||
BadAddress,
|
||||
FileTooLarge,
|
||||
InappropriateFileTypeOrFormat,
|
||||
HostIsDown,
|
||||
NoRouteToHost,
|
||||
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),
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
|
||||
#[cfg(target_env = "newlib")]
|
||||
mod newlib;
|
||||
|
||||
// #[cfg(target_os = "linux")]
|
||||
// pub use linux::*;
|
||||
|
||||
// #[cfg(target_env = "newlib")]
|
||||
// pub use linux::*;
|
||||
@@ -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<i32> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<i32> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
//TODO verify uXX == uintXX_t
|
||||
|
||||
// TODO verify uXX == uintXX_t
|
||||
// TODO Document size_t != usize problems better
|
||||
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")]
|
||||
@@ -15,8 +13,9 @@ impl Sizes {
|
||||
pub const TASK_MINIMAL_STACK_SIZE: usize = 16424;
|
||||
}
|
||||
|
||||
// We use none for bare metal, as we only support one architecture so far
|
||||
#[cfg(target_os = "none")]
|
||||
// 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;
|
||||
pub const MUTEX_DATA_SIZE: usize = 168;
|
||||
@@ -24,8 +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(
|
||||
@@ -44,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;
|
||||
|
||||
@@ -55,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,
|
||||
@@ -65,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,
|
||||
@@ -82,5 +92,23 @@ 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: core::ffi::c_size_t) -> 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::*;
|
||||
@@ -0,0 +1,15 @@
|
||||
extern "C" {
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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(
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
use core::fmt::Display;
|
||||
|
||||
pub use super::error::OsError;
|
||||
use super::ffi;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Os(OsError),
|
||||
IncompleteWrite(usize),
|
||||
InvalidPath,
|
||||
Unknown(i32),
|
||||
InternalError,
|
||||
}
|
||||
|
||||
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<T> = core::result::Result<T, Error>;
|
||||
|
||||
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 HardwareInterface {
|
||||
fd: core::ffi::c_int,
|
||||
}
|
||||
|
||||
impl HardwareInterface {
|
||||
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, 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,
|
||||
len_converted,
|
||||
)
|
||||
};
|
||||
if fd >= 0 {
|
||||
Ok(Self { fd })
|
||||
} else {
|
||||
// Safe: getter on os
|
||||
let errno = unsafe { ffi::freertos_get_sys_error() };
|
||||
Err(Error::Os(errno.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for HardwareInterface {
|
||||
fn write(&mut self, data: &[u8]) -> Result<()> {
|
||||
#[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,
|
||||
data.as_ptr() as *const core::ffi::c_void,
|
||||
len_converted,
|
||||
)
|
||||
};
|
||||
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::Os(OsError::NumericalResultOutOfRange));
|
||||
};
|
||||
if written_unsigned < data.len() {
|
||||
return Err(Error::IncompleteWrite(written_unsigned));
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
len_converted,
|
||||
)
|
||||
};
|
||||
if read < 0 {
|
||||
// Safe: getter on os
|
||||
let errno = unsafe { ffi::freertos_get_sys_error() };
|
||||
let error = errno.into();
|
||||
if error == OsError::OperationWouldBlock {
|
||||
// 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::Os(OsError::NumericalResultOutOfRange));
|
||||
};
|
||||
Ok(&buffer[..read_unsigned])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,11 @@ impl<T> Mutex<T> {
|
||||
}
|
||||
|
||||
// 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<T> {
|
||||
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<T> Mutex<T> {
|
||||
// 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<T> MutexClone<T> {
|
||||
// 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 },
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -26,12 +26,16 @@ impl<T: 'static> StaticReadOnceLock<T> {
|
||||
|
||||
impl<T: 'static + StaticInit> StaticReadOnceLock<T> {
|
||||
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<T> Sync for StaticReadOnceLock<T> {}
|
||||
@@ -6,71 +6,73 @@ 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;
|
||||
}
|
||||
|
||||
impl Write for Stdout {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), 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);
|
||||
};
|
||||
// Safe because write will only read the pointer an then return
|
||||
let result = unsafe {
|
||||
write(
|
||||
let written = unsafe {
|
||||
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() {
|
||||
Ok(count)=> count,
|
||||
Err(_) => return Err(Error)
|
||||
let Ok(written_unsigned): Result<usize, _> = 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> {
|
||||
|
||||
#[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);
|
||||
};
|
||||
// Safe because write will only read the pointer an then return
|
||||
let result = unsafe {
|
||||
write(
|
||||
let written = unsafe {
|
||||
crate::fsrc::osal::ffi::write(
|
||||
2,
|
||||
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() {
|
||||
Ok(count)=> count,
|
||||
Err(_) => return Err(Error)
|
||||
let Ok(written_unsigned): Result<usize, _> = 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)*);
|
||||
{let _alwaysok = writeln!(crate::fsrc::sif::Stdout {}, $($arg)*);}
|
||||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! sif {
|
||||
($(,)?) => (
|
||||
{let _alwaysok = writeln!(crate::fsrc::sif::Stdout {});}
|
||||
);
|
||||
($($arg:tt)*) => (
|
||||
let _alwaysok = write!(crate::fsrc::sif::Stdout {}, $($arg)*);
|
||||
);
|
||||
|
||||
+23
-7
@@ -1,22 +1,29 @@
|
||||
#![no_std]
|
||||
#![feature(never_type)]
|
||||
#![feature(c_size_t)] // for ffi, tracking issue [88345]
|
||||
//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::{
|
||||
dh::EchoHandler,
|
||||
fsrc::{
|
||||
dh::debug::DeviceHandlerDebugger,
|
||||
osal::io::HardwareInterface,
|
||||
},
|
||||
};
|
||||
|
||||
static THREAD_INIT: StaticReadOnceLock<
|
||||
thread::StaticThread<{ thread::Sizes::MINIMAL_STACK_SIZE + 2024 }>,
|
||||
@@ -182,6 +189,17 @@ 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("debug/uart🚀").unwrap(),
|
||||
&commands,
|
||||
&[],
|
||||
Duration::from_millis(500),
|
||||
0.5,
|
||||
);
|
||||
|
||||
debugger.run().unwrap();
|
||||
|
||||
let test1 = TEST1.take().unwrap();
|
||||
let test2 = TEST2.take().unwrap();
|
||||
@@ -197,8 +215,6 @@ fn init_task() -> ! {
|
||||
test2.run(mutex_copy, a);
|
||||
});
|
||||
|
||||
|
||||
|
||||
THREAD_1.take_no_init().unwrap().spawn(move || {
|
||||
test1.run();
|
||||
sender.run(clone);
|
||||
@@ -207,7 +223,7 @@ fn init_task() -> ! {
|
||||
THREAD_3.take_no_init().unwrap().spawn(move || {
|
||||
receiver.run();
|
||||
});
|
||||
|
||||
|
||||
sifln!("=====================Mission delete");
|
||||
osal::thread::current().delete();
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user