]> granicus.if.org Git - esp-idf/commitdiff
vfs: implement fcntl via VFS interface
authorIvan Grokhotkov <ivan@espressif.com>
Wed, 16 Aug 2017 06:58:06 +0000 (14:58 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Mon, 21 Aug 2017 07:58:28 +0000 (15:58 +0800)
components/vfs/include/esp_vfs.h
components/vfs/vfs.c
components/vfs/vfs_uart.c

index a3ce6b95cfcaea6f77bf21c7ac2d245dce384f27..6ced2ce2b84130070bf98295a79ac45cfc060b8b 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <stdarg.h>
 #include "esp_err.h"
 #include <sys/types.h>
 #include <sys/reent.h>
@@ -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;
 
 
index f99465e4fd1bb82165d874c3409911a095d9027b..f07bf7c37a13c8f2accfd98c3576297642121aed 100644 (file)
@@ -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;
+}
index a03f59ac8653c70edb3b6ceb34bb35125e0de62b..0ec6cf6b0d62edb87c21b3cca5bc913e17ab0d90 100644 (file)
 
 #include <string.h>
 #include <stdbool.h>
+#include <stdarg.h>
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/fcntl.h>
 #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));
 }