From: Ivan Grokhotkov Date: Wed, 16 Aug 2017 06:58:06 +0000 (+0800) Subject: vfs: implement fcntl via VFS interface X-Git-Tag: v3.1-dev~398^2~2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1e4587a09fab187e53f51518b084ee9a707a4506;p=esp-idf vfs: implement fcntl via VFS interface --- diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index a3ce6b95cf..6ced2ce2b8 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -17,6 +17,7 @@ #include #include +#include #include "esp_err.h" #include #include @@ -140,6 +141,10 @@ typedef struct int (*rmdir_p)(void* ctx, const char* name); int (*rmdir)(const char* name); }; + union { + int (*fcntl_p)(void* ctx, int fd, int cmd, va_list args); + int (*fcntl)(int fd, int cmd, va_list args); + }; } esp_vfs_t; diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index f99465e4fd..f07bf7c37a 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -472,3 +472,20 @@ int rmdir(const char* name) CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs); return ret; } + +int fcntl(int fd, int cmd, ...) +{ + const vfs_entry_t* vfs = get_vfs_for_fd(fd); + struct _reent* r = __getreent(); + if (vfs == NULL) { + __errno_r(r) = EBADF; + return -1; + } + int local_fd = translate_fd(vfs, fd); + int ret; + va_list args; + va_start(args, cmd); + CHECK_AND_CALL(ret, r, vfs, fcntl, local_fd, cmd, args); + va_end(args); + return ret; +} diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index a03f59ac86..0ec6cf6b0d 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -14,11 +14,13 @@ #include #include +#include +#include +#include +#include #include "esp_vfs.h" #include "esp_vfs_dev.h" #include "esp_attr.h" -#include "sys/errno.h" -#include "sys/lock.h" #include "soc/uart_struct.h" #include "driver/uart.h" #include "sdkconfig.h" @@ -48,6 +50,10 @@ static uart_dev_t* s_uarts[UART_NUM] = {&UART0, &UART1, &UART2}; static _lock_t s_uart_locks[UART_NUM]; // One-character buffer used for newline conversion code, per UART static int s_peek_char[UART_NUM] = { NONE, NONE, NONE }; +// Per-UART non-blocking flag. Note: default implementation does not honor this +// flag, all reads are non-blocking. This option becomes effective if UART +// driver is used. +static bool s_non_blocking[UART_NUM]; // Newline conversion mode when transmitting static esp_line_endings_t s_tx_mode = @@ -122,8 +128,9 @@ static int uart_rx_char(int fd) static int uart_rx_char_via_driver(int fd) { uint8_t c; - int n = uart_read_bytes(fd, &c, 1, portMAX_DELAY); - if (n == 0) { + int timeout = s_non_blocking[fd] ? 0 : portMAX_DELAY; + int n = uart_read_bytes(fd, &c, 1, timeout); + if (n <= 0) { return NONE; } return c; @@ -203,6 +210,8 @@ static ssize_t uart_read(int fd, void* data, size_t size) uart_return_char(fd, c2); } } + } else if (c == NONE) { + break; } data_c[received] = (char) c; ++received; @@ -231,6 +240,25 @@ static int uart_close(int fd) return 0; } +static int uart_fcntl(int fd, int cmd, va_list args) +{ + assert(fd >=0 && fd < 3); + int result = 0; + if (cmd == F_GETFL) { + if (s_non_blocking[fd]) { + result |= O_NONBLOCK; + } + } else if (cmd == F_SETFL) { + int arg = va_arg(args, int); + s_non_blocking[fd] = (arg & O_NONBLOCK) != 0; + } else { + // unsupported operation + result = -1; + errno = ENOSYS; + } + return result; +} + void esp_vfs_dev_uart_register() { esp_vfs_t vfs = { @@ -241,11 +269,7 @@ void esp_vfs_dev_uart_register() .fstat = &uart_fstat, .close = &uart_close, .read = &uart_read, - .lseek = NULL, - .stat = NULL, - .link = NULL, - .unlink = NULL, - .rename = NULL + .fcntl = &uart_fcntl }; ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); }