From 587360363c121d266b66271b10a60831b6ff9d40 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 25 Oct 2016 22:01:50 +0800 Subject: [PATCH] vfs: add UART device This should be integrated with UART driver once everything is merged --- components/vfs/include/esp_vfs_dev.h | 28 ++++++++ components/vfs/vfs_uart.c | 95 ++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 components/vfs/include/esp_vfs_dev.h create mode 100644 components/vfs/vfs_uart.c diff --git a/components/vfs/include/esp_vfs_dev.h b/components/vfs/include/esp_vfs_dev.h new file mode 100644 index 000000000..6eb63d852 --- /dev/null +++ b/components/vfs/include/esp_vfs_dev.h @@ -0,0 +1,28 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_VFS_H__ +#define __ESP_VFS_H__ + +#include "esp_vfs.h" + +/** + * @brief add /dev/uart virtual filesystem driver + * + * This function is called from startup code to enable serial output + */ +void esp_vfs_dev_uart_register(); + + +#endif //__ESP_VFS_H__ diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c new file mode 100644 index 000000000..179c5e258 --- /dev/null +++ b/components/vfs/vfs_uart.c @@ -0,0 +1,95 @@ +#include +#include "esp_vfs.h" +#include "esp_attr.h" +#include "sys/errno.h" +#include "sys/lock.h" +#include "soc/uart_struct.h" + +static uart_dev_t* s_uarts[3] = {&UART0, &UART1, &UART2}; + +static int IRAM_ATTR uart_open(const char * path, int flags, int mode) +{ + // this is fairly primitive, we should check if file is opened read only, + // and error out if write is requested + if (strcmp(path, "/0") == 0) { + return 0; + } else if (strcmp(path, "/1") == 0) { + return 1; + } else if (strcmp(path, "/2") == 0) { + return 2; + } + errno = ENOENT; + return -1; +} + +static void IRAM_ATTR uart_tx_char(uart_dev_t* uart, int c) +{ + while (uart->status.txfifo_cnt >= 127) { + ; + } + uart->fifo.rw_byte = c; +} + + +static size_t IRAM_ATTR uart_write(int fd, const void * data, size_t size) +{ + assert(fd >=0 && fd < 3); + const char *data_c = (const char *)data; + uart_dev_t* uart = s_uarts[fd]; + static _lock_t stdout_lock; /* lazily initialised */ + /* Even though newlib does stream locking on stdout, we need + a dedicated stdout UART lock... + + This is because each task has its own _reent structure with + unique FILEs for stdin/stdout/stderr, so these are + per-thread (lazily initialised by __sinit the first time a + stdio function is used, see findfp.c:235. + + It seems like overkill to allocate a FILE-per-task and lock + a thread-local stream, but I see no easy way to fix this + (pre-__sinit_, tasks have "fake" FILEs ie __sf_fake_stdout + which aren't fully valid.) + */ + _lock_acquire_recursive(&stdout_lock); + for (size_t i = 0; i < size; i++) { +#if CONFIG_NEWLIB_STDOUT_ADDCR + if (data_c[i]=='\n') { + uart_tx_char(uart, '\r'); + } +#endif + uart_tx_char(uart, data_c[i]); + } + _lock_release_recursive(&stdout_lock); + return size; +} + +static int IRAM_ATTR uart_fstat(int fd, struct stat * st) +{ + assert(fd >=0 && fd < 3); + st->st_mode = S_IFCHR; + return 0; +} + +static int IRAM_ATTR uart_close(int fd) +{ + assert(fd >=0 && fd < 3); + return 0; +} + +void esp_vfs_dev_uart_register() +{ + esp_vfs_t vfs = { + .fd_offset = 0, + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &uart_write, + .open = &uart_open, + .fstat = &uart_fstat, + .close = &uart_close, + .read = NULL, // TODO: implement reading from UART + .stat = NULL, + .link = NULL, + .unlink = NULL, + .rename = NULL + }; + ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); +}