diff --git a/components/cxx/test/test_cxx.cpp b/components/cxx/test/test_cxx.cpp index 03ee89075e..de61845c3d 100644 --- a/components/cxx/test/test_cxx.cpp +++ b/components/cxx/test/test_cxx.cpp @@ -57,7 +57,7 @@ TEST_CASE("can use std::vector", "[cxx]") #elif CONFIG_IDF_TARGET_ESP32S2 #define LEAKS "800" #elif CONFIG_IDF_TARGET_ESP32C3 -#define LEAKS "600" +#define LEAKS "700" #else #error "unknown target in CXX tests, can't set leaks threshold" #endif diff --git a/components/esp_common/Kconfig b/components/esp_common/Kconfig index 39fa9ae6b6..2192710887 100644 --- a/components/esp_common/Kconfig +++ b/components/esp_common/Kconfig @@ -95,8 +95,30 @@ menu "Common ESP-related" bool "None" endchoice - # Internal option, indicates that console UART is used (and not USB, for example) + choice ESP_CONSOLE_SECONDARY + depends on IDF_TARGET_ESP32C3 + prompt "Channel for console secondary output" + default ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + help + This secondary option supports output through other specific port like USB_SERIAL_JTAG + when UART0 port as a primary is selected but not connected. This secondary output currently only supports + non-blocking mode without using REPL. If you want to output in blocking mode with REPL or + input through this secondary port, please change the primary config to this port + in `Channel for console output` menu. + config ESP_CONSOLE_SECONDARY_NONE + bool "No secondary console" + config ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + bool "USB_SERIAL_JTAG PORT" + depends on !ESP_CONSOLE_USB_SERIAL_JTAG + help + This option supports output through USB_SERIAL_JTAG port when the UART0 port is not connected. + The output currently only supports non-blocking mode without using the console. + If you want to output in blocking mode with REPL or input through USB_SERIAL_JTAG port, + please change the primary config to ESP_CONSOLE_USB_SERIAL_JTAG above. + endchoice + config ESP_CONSOLE_UART + # Internal option, indicates that console UART is used (and not USB, for example) bool default y if ESP_CONSOLE_UART_DEFAULT || ESP_CONSOLE_UART_CUSTOM diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 5007b3e55a..7540ca94cc 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -53,9 +53,7 @@ #include "esp_pm.h" #include "esp_private/pm_impl.h" #include "esp_pthread.h" -#include "esp_private/usb_console.h" -#include "esp_vfs_cdcacm.h" -#include "esp_vfs_usb_serial_jtag.h" +#include "esp_vfs_console.h" #include "esp_rom_sys.h" @@ -86,9 +84,6 @@ #error "System has been configured to run on multiple cores, but target SoC only has a single core." #endif -#define STRINGIFY(s) STRINGIFY2(s) -#define STRINGIFY2(s) #s - uint64_t g_startup_time = 0; #if SOC_APB_BACKUP_DMA @@ -273,23 +268,14 @@ static void do_core_init(void) esp_timer_early_init(); esp_newlib_time_init(); -#ifdef CONFIG_VFS_SUPPORT_IO -#ifdef CONFIG_ESP_CONSOLE_UART - esp_vfs_dev_uart_register(); - const char *default_stdio_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); -#endif // CONFIG_ESP_CONSOLE_UART -#ifdef CONFIG_ESP_CONSOLE_USB_CDC - ESP_ERROR_CHECK(esp_usb_console_init()); - ESP_ERROR_CHECK(esp_vfs_dev_cdcacm_register()); - const char *default_stdio_dev = "/dev/cdcacm"; -#endif // CONFIG_ESP_CONSOLE_USB_CDC -#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG - ESP_ERROR_CHECK(esp_vfs_dev_usb_serial_jtag_register()); - const char *default_stdio_dev = "/dev/usbserjtag"; -#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG -#endif // CONFIG_VFS_SUPPORT_IO +#if CONFIG_VFS_SUPPORT_IO + // VFS console register. + esp_err_t vfs_err = esp_vfs_console_register(); + assert(vfs_err == ESP_OK && "Failed to register vfs console"); +#endif #if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_NONE) + const static char *default_stdio_dev = "/dev/console/"; esp_reent_init(_GLOBAL_REENT); _GLOBAL_REENT->_stdin = fopen(default_stdio_dev, "r"); _GLOBAL_REENT->_stdout = fopen(default_stdio_dev, "w"); diff --git a/components/vfs/CMakeLists.txt b/components/vfs/CMakeLists.txt index 48b69be182..7f51dbeeff 100644 --- a/components/vfs/CMakeLists.txt +++ b/components/vfs/CMakeLists.txt @@ -1,13 +1,15 @@ idf_component_register(SRCS "vfs.c" "vfs_uart.c" "vfs_semihost.c" + "vfs_console.c" + PRIV_INCLUDE_DIRS private_include INCLUDE_DIRS include) if(CONFIG_ESP_CONSOLE_USB_CDC) target_sources(${COMPONENT_LIB} PRIVATE "vfs_cdcacm.c") endif() -if(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) +if(CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG OR CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) target_sources(${COMPONENT_LIB} PRIVATE "vfs_usb_serial_jtag.c") endif() diff --git a/components/vfs/component.mk b/components/vfs/component.mk index e880793520..d9adffb06c 100644 --- a/components/vfs/component.mk +++ b/components/vfs/component.mk @@ -1,3 +1,4 @@ +COMPONENT_PRIV_INCLUDEDIRS := private_include ifndef CONFIG_ESP_CONSOLE_USB_CDC COMPONENT_OBJEXCLUDE := vfs_cdcacm.o endif diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 7303af4b65..36f0320dc8 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -246,7 +246,6 @@ typedef struct #endif // CONFIG_VFS_SUPPORT_SELECT } esp_vfs_t; - /** * Register a virtual filesystem for given path prefix. * diff --git a/components/vfs/include/esp_vfs_cdcacm.h b/components/vfs/include/esp_vfs_cdcacm.h index b8dd03d92a..416efb35a4 100644 --- a/components/vfs/include/esp_vfs_cdcacm.h +++ b/components/vfs/include/esp_vfs_cdcacm.h @@ -1,16 +1,8 @@ -// Copyright 2015-2017 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. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/components/vfs/include/esp_vfs_console.h b/components/vfs/include/esp_vfs_console.h new file mode 100644 index 0000000000..bc5ce6733d --- /dev/null +++ b/components/vfs/include/esp_vfs_console.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief add uart/usb_serial_jtag/usb_otg_acmcdc virtual filesystem driver + * + * This function is called from startup code to enable serial output + */ +esp_err_t esp_vfs_console_register(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/vfs/include/esp_vfs_dev.h b/components/vfs/include/esp_vfs_dev.h index dc33fe746d..91e9374972 100644 --- a/components/vfs/include/esp_vfs_dev.h +++ b/components/vfs/include/esp_vfs_dev.h @@ -1,16 +1,8 @@ -// Copyright 2015-2017 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. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/components/vfs/include/esp_vfs_usb_serial_jtag.h b/components/vfs/include/esp_vfs_usb_serial_jtag.h index 54ff1f4e44..c53a671be8 100644 --- a/components/vfs/include/esp_vfs_usb_serial_jtag.h +++ b/components/vfs/include/esp_vfs_usb_serial_jtag.h @@ -1,16 +1,8 @@ -// Copyright 2021 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. +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/components/vfs/private_include/esp_vfs_private.h b/components/vfs/private_include/esp_vfs_private.h new file mode 100644 index 0000000000..7a3f9e1e65 --- /dev/null +++ b/components/vfs/private_include/esp_vfs_private.h @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_vfs.h" +#include "esp_vfs_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct vfs_entry_ { + esp_vfs_t vfs; // contains pointers to VFS functions + char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS + size_t path_prefix_len; // micro-optimization to avoid doing extra strlen + void* ctx; // optional pointer which can be passed to VFS + int offset; // index of this structure in s_vfs array +} vfs_entry_t; + + +/** + * @brief get pointer of uart vfs. + * + * This function is called in vfs_console in order to get the vfs implementation + * of uart. + * + * @return pointer to structure esp_vfs_t + */ +const esp_vfs_t *esp_vfs_uart_get_vfs(void); + +/** + * @brief get pointer of cdcacm vfs. + * + * This function is called in vfs_console in order to get the vfs implementation + * of cdcacm. + * + * @return pointer to structure esp_vfs_t + */ +const esp_vfs_t *esp_vfs_cdcacm_get_vfs(void); + +/** + * @brief get pointer of usb_serial_jtag vfs. + * + * This function is called in vfs_console in order to get the vfs implementation + * of usb_serial_jtag. + * + * @return pointer to structure esp_vfs_nonblocking_console_t + */ +const esp_vfs_t *esp_vfs_usb_serial_jtag_get_vfs(void); + +/** + * Register a virtual filesystem. + * + * @param base_path file path prefix associated with the filesystem. + * Must be a zero-terminated C string, may be empty. + * If not empty, must be up to ESP_VFS_PATH_MAX + * characters long, and at least 2 characters long. + * Name must start with a "/" and must not end with "/". + * For example, "/data" or "/dev/spi" are valid. + * These VFSes would then be called to handle file paths such as + * "/data/myfile.txt" or "/dev/spi/0". + * In the special case of an empty base_path, a "fallback" + * VFS is registered. Such VFS will handle paths which are not + * matched by any other registered VFS. + * @param len Length of the base_path. + * @param vfs Pointer to esp_vfs_t, a structure which maps syscalls to + * the filesystem driver functions. VFS component doesn't + * assume ownership of this pointer. + * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer + * which should be passed to VFS functions. Otherwise, NULL. + * @param vfs_index Index for getting the vfs content. + * + * @return ESP_OK if successful. + * ESP_ERR_NO_MEM if too many VFSes are registered. + * ESP_ERR_INVALID_ARG if given an invalid parameter. + */ +esp_err_t esp_vfs_register_common(const char *base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index); + +/** + * Get vfs fd with given path. + * + * @param path file path prefix associated with the filesystem. + * + * @return Pointer to the `vfs_entry_t` corresponding to the given path, which cannot be NULL. + */ +const vfs_entry_t *get_vfs_for_path(const char *path); + +/** + * Get vfs fd with given vfs index. + * + * @param index VFS index. + * + * @return Pointer to the `vfs_entry_t` corresponding to the given path, which cannot be NULL. + */ +const vfs_entry_t *get_vfs_for_index(int index); + +#ifdef __cplusplus +} +#endif diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 24a2f1ebc0..4b997ea66b 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -18,6 +18,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "esp_vfs.h" +#include "esp_vfs_private.h" #include "sdkconfig.h" #ifdef CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT @@ -44,14 +45,6 @@ typedef struct { local_fd_t local_fd; } fd_table_t; -typedef struct vfs_entry_ { - esp_vfs_t vfs; // contains pointers to VFS functions - char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS - size_t path_prefix_len; // micro-optimization to avoid doing extra strlen - void* ctx; // optional pointer which can be passed to VFS - int offset; // index of this structure in s_vfs array -} vfs_entry_t; - typedef struct { bool isset; // none or at least one bit is set in the following 3 fd sets fd_set readfds; @@ -65,7 +58,7 @@ static size_t s_vfs_count = 0; static fd_table_t s_fd_table[MAX_FDS] = { [0 ... MAX_FDS-1] = FD_TABLE_ENTRY_UNUSED }; static _lock_t s_fd_table_lock; -static esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index) +esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index) { if (len != LEN_PATH_PREFIX_IGNORED) { /* empty prefix is allowed, "/" is not allowed */ @@ -240,7 +233,7 @@ esp_err_t esp_vfs_unregister_fd(esp_vfs_id_t vfs_id, int fd) return ret; } -static inline const vfs_entry_t *get_vfs_for_index(int index) +const vfs_entry_t *get_vfs_for_index(int index) { if (index < 0 || index >= s_vfs_count) { return NULL; @@ -285,7 +278,7 @@ static const char* translate_path(const vfs_entry_t* vfs, const char* src_path) return src_path + vfs->path_prefix_len; } -static const vfs_entry_t* get_vfs_for_path(const char* path) +const vfs_entry_t* get_vfs_for_path(const char* path) { const vfs_entry_t* best_match = NULL; ssize_t best_match_prefix_len = -1; diff --git a/components/vfs/vfs_cdcacm.c b/components/vfs/vfs_cdcacm.c index cd14d212dd..fb590a445d 100644 --- a/components/vfs/vfs_cdcacm.c +++ b/components/vfs/vfs_cdcacm.c @@ -1,16 +1,8 @@ -// Copyright 2015-2020 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. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -309,17 +301,23 @@ void esp_vfs_dev_cdcacm_set_rx_line_endings(esp_line_endings_t mode) s_rx_mode = mode; } +static const esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &cdcacm_write, + .open = &cdcacm_open, + .fstat = &cdcacm_fstat, + .close = &cdcacm_close, + .read = &cdcacm_read, + .fcntl = &cdcacm_fcntl, + .fsync = &cdcacm_fsync +}; + +const esp_vfs_t *esp_vfs_cdcacm_get_vfs(void) +{ + return &vfs; +} + esp_err_t esp_vfs_dev_cdcacm_register(void) { - const esp_vfs_t vfs = { - .flags = ESP_VFS_FLAG_DEFAULT, - .write = &cdcacm_write, - .open = &cdcacm_open, - .fstat = &cdcacm_fstat, - .close = &cdcacm_close, - .read = &cdcacm_read, - .fcntl = &cdcacm_fcntl, - .fsync = &cdcacm_fsync - }; return esp_vfs_register("/dev/cdcacm", &vfs, NULL); } diff --git a/components/vfs/vfs_console.c b/components/vfs/vfs_console.c new file mode 100644 index 0000000000..be10600b87 --- /dev/null +++ b/components/vfs/vfs_console.c @@ -0,0 +1,218 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_vfs_console.h" +#include "esp_rom_sys.h" +#include "esp_vfs_cdcacm.h" +#include "esp_vfs_private.h" +#include "esp_vfs_usb_serial_jtag.h" +#include "esp_vfs_dev.h" +#include "esp_private/usb_console.h" +#include "sdkconfig.h" + +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + +/** + * This file is to concentrate all the vfs(UART, USB_SERIAL_JTAG, CDCACM) console into one single file. + * Get the vfs information from their component (i.e. vfs_uart.c) through `esp_vfs_usb_xxx_get_console()`, + * which can help us to output some string to two different ports(i.e both through uart and usb_serial_jtag). + * Usually, we set a port as primary and another as secondary. For primary, it is used for all the features supported by each vfs implementation, + * while the secondary is only used for output. + */ + +typedef struct { + int fd_primary; + int fd_secondary; +} vfs_console_context_t; + +#if CONFIG_VFS_SUPPORT_IO +// Primary register part. +#ifdef CONFIG_ESP_CONSOLE_UART +const static char *primary_path = "/dev/uart"; +#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG +const static char *primary_path = "/dev/usbserjtag"; +#elif CONFIG_ESP_CONSOLE_USB_CDC +const static char *primary_path = "/dev/cdcacm"; +#endif + +// Secondary register part. +#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG +const static char *secondary_path = "/dev/secondary"; +static int secondary_vfs_index; +#endif // Secondary part + +static int primary_vfs_index; + +static vfs_console_context_t vfs_console= {0}; + +int console_open(const char * path, int flags, int mode) +{ +// Primary port open +#if CONFIG_ESP_CONSOLE_UART + vfs_console.fd_primary = get_vfs_for_path(primary_path)->vfs.open("/"STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM), flags, mode); +#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + vfs_console.fd_primary = esp_vfs_usb_serial_jtag_get_vfs()->open("/", flags, mode); +#elif CONFIG_ESP_CONSOLE_USB_CDC + vfs_console.fd_primary = esp_vfs_cdcacm_get_vfs()->open("/", flags, mode); +#endif + +// Secondary port open +#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + vfs_console.fd_secondary = get_vfs_for_path(secondary_path)->vfs.open("/", flags, mode); +#endif + return 0; +} + +ssize_t console_write(int fd, const void *data, size_t size) +{ + // All function calls are to primary, except from write and close, which will be forwarded to both primary and secondary. + get_vfs_for_index(primary_vfs_index)->vfs.write(vfs_console.fd_primary, data, size); +#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + get_vfs_for_index(secondary_vfs_index)->vfs.write(vfs_console.fd_secondary, data, size); +#endif + return size; +} + +int console_fstat(int fd, struct stat * st) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.fstat(fd, st); +} + +int console_close(int fd) +{ + // All function calls are to primary, except from write and close, which will be forwarded to both primary and secondary. + get_vfs_for_index(primary_vfs_index)->vfs.close(vfs_console.fd_primary); +#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + get_vfs_for_index(secondary_vfs_index)->vfs.close(vfs_console.fd_secondary); +#endif + return 0; +} + +ssize_t console_read(int fd, void * dst, size_t size) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.read(vfs_console.fd_primary, dst, size); +} + +int console_fcntl(int fd, int cmd, int arg) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.fcntl(vfs_console.fd_primary, cmd, arg); +} + +int console_fsync(int fd) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.fsync(vfs_console.fd_primary); +} + +#ifdef CONFIG_VFS_SUPPORT_DIR +int console_access(const char *path, int amode) +{ + // currently only UART support DIR. + return get_vfs_for_index(primary_vfs_index)->vfs.access("/"STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM), amode); +} +#endif // CONFIG_VFS_SUPPORT_DIR + +#ifdef CONFIG_VFS_SUPPORT_SELECT +static esp_err_t console_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + esp_vfs_select_sem_t select_sem, void **end_select_args) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.start_select(nfds, readfds, writefds, exceptfds, select_sem, end_select_args); +} + +esp_err_t console_end_select(void *end_select_args) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.end_select(end_select_args); +} + +#endif // CONFIG_VFS_SUPPORT_SELECT + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + +int console_tcsetattr(int fd, int optional_actions, const struct termios *p) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.tcsetattr(vfs_console.fd_primary, optional_actions, p); +} + +int console_tcgetattr(int fd, struct termios *p) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.tcgetattr(vfs_console.fd_primary, p); +} + +int console_tcdrain(int fd) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.tcdrain(vfs_console.fd_primary); +} + +int console_tcflush(int fd, int select) +{ + return get_vfs_for_index(primary_vfs_index)->vfs.tcflush(vfs_console.fd_primary, select); +} +#endif // CONFIG_VFS_SUPPORT_TERMIOS + +static const esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &console_write, + .open = &console_open, + .fstat = &console_fstat, + .close = &console_close, + .read = &console_read, + .fcntl = &console_fcntl, + .fsync = &console_fsync, +#ifdef CONFIG_VFS_SUPPORT_DIR + .access = &console_access, +#endif // CONFIG_VFS_SUPPORT_DIR +#ifdef CONFIG_VFS_SUPPORT_SELECT + .start_select = &console_start_select, + .end_select = &console_end_select, +#endif // CONFIG_VFS_SUPPORT_SELECT +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + .tcsetattr = &console_tcsetattr, + .tcgetattr = &console_tcgetattr, + .tcdrain = &console_tcdrain, + .tcflush = &console_tcflush, +#endif // CONFIG_VFS_SUPPORT_TERMIOS +}; + +esp_err_t esp_vfs_dev_console_register(void) +{ + return esp_vfs_register("/dev/console", &vfs, NULL); +} + +esp_err_t esp_vfs_console_register(void) +{ + esp_err_t err = ESP_OK; +// Primary register part. +#ifdef CONFIG_ESP_CONSOLE_UART + const esp_vfs_t *uart_vfs = esp_vfs_uart_get_vfs(); + err = esp_vfs_register_common(primary_path, strlen(primary_path), uart_vfs, NULL, &primary_vfs_index); +#elif CONFIG_ESP_CONSOLE_USB_CDC + const esp_vfs_t *cdcacm_vfs = esp_vfs_cdcacm_get_vfs(); + err = esp_usb_console_init(); + if (err != ESP_OK) { + return err; + } + err = esp_vfs_register_common(primary_path, strlen(primary_path), cdcacm_vfs, NULL, &primary_vfs_index); +#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + const esp_vfs_t *usb_serial_jtag_vfs = esp_vfs_usb_serial_jtag_get_vfs(); + err = esp_vfs_register_common(primary_path, strlen(primary_path), usb_serial_jtag_vfs, NULL, &primary_vfs_index); +#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + if (err != ESP_OK) { + return err; + } + +// Secondary register part. +#if CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG + const esp_vfs_t *usb_serial_jtag_vfs = esp_vfs_usb_serial_jtag_get_vfs(); + err = esp_vfs_register_common(secondary_path, strlen(secondary_path), usb_serial_jtag_vfs, NULL, &secondary_vfs_index); + if(err != ESP_OK) { + return err; + } +#endif + err = esp_vfs_dev_console_register(); + return err; +} + +#endif // CONFIG_VFS_SUPPORT_IO diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index ffd864506e..90786f1564 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -1,16 +1,8 @@ -// Copyright 2015-2017 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. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -969,31 +961,37 @@ static int uart_tcflush(int fd, int select) } #endif // CONFIG_VFS_SUPPORT_TERMIOS -void esp_vfs_dev_uart_register(void) -{ - esp_vfs_t vfs = { - .flags = ESP_VFS_FLAG_DEFAULT, - .write = &uart_write, - .open = &uart_open, - .fstat = &uart_fstat, - .close = &uart_close, - .read = &uart_read, - .fcntl = &uart_fcntl, - .fsync = &uart_fsync, +static const esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &uart_write, + .open = &uart_open, + .fstat = &uart_fstat, + .close = &uart_close, + .read = &uart_read, + .fcntl = &uart_fcntl, + .fsync = &uart_fsync, #ifdef CONFIG_VFS_SUPPORT_DIR - .access = &uart_access, + .access = &uart_access, #endif // CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_SELECT - .start_select = &uart_start_select, - .end_select = &uart_end_select, + .start_select = &uart_start_select, + .end_select = &uart_end_select, #endif // CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_TERMIOS - .tcsetattr = &uart_tcsetattr, - .tcgetattr = &uart_tcgetattr, - .tcdrain = &uart_tcdrain, - .tcflush = &uart_tcflush, + .tcsetattr = &uart_tcsetattr, + .tcgetattr = &uart_tcgetattr, + .tcdrain = &uart_tcdrain, + .tcflush = &uart_tcflush, #endif // CONFIG_VFS_SUPPORT_TERMIOS - }; +}; + +const esp_vfs_t* esp_vfs_uart_get_vfs(void) +{ + return &vfs; +} + +void esp_vfs_dev_uart_register(void) +{ ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); } diff --git a/components/vfs/vfs_usb_serial_jtag.c b/components/vfs/vfs_usb_serial_jtag.c index ae1b4f599b..20bb4dd4db 100644 --- a/components/vfs/vfs_usb_serial_jtag.c +++ b/components/vfs/vfs_usb_serial_jtag.c @@ -1,16 +1,8 @@ -// Copyright 2015-2017 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. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ //This is a simple non-blocking (well, tx may spin for a bit if the buffer //is full) USB-serial-jtag driver. Select etc is not supported yet. @@ -113,23 +105,21 @@ static int usb_serial_jtag_open(const char * path, int flags, int mode) static void usb_serial_jtag_tx_char(int fd, int c) { uint8_t cc=(uint8_t)c; - if (usb_serial_jtag_ll_txfifo_writable()) { - //We can write to the buffer. Immediately do so. - usb_serial_jtag_ll_write_txfifo(&cc, 1); - s_ctx.last_tx_ts = esp_timer_get_time(); - } else { - //Try to write to the buffer as long as we still expect the buffer to have - //a chance of being emptied by an active host. Just drop the data if there's - //no chance anymore. - while ((esp_timer_get_time() - s_ctx.last_tx_ts) < TX_FLUSH_TIMEOUT_US) { - if (usb_serial_jtag_ll_txfifo_writable()) { - //Woohoo, we can write again. Do so and exit the while loop. - usb_serial_jtag_ll_write_txfifo(&cc, 1); - s_ctx.last_tx_ts = esp_timer_get_time(); - break; - } + // Try to write to the buffer as long as we still expect the buffer to have + // a chance of being emptied by an active host. Just drop the data if there's + // no chance anymore. + // When we first try to send a character and the buffer is not accessible yet, + // we wait until the time has been more than TX_FLUSH_TIMEOUT_US since we successfully + // sent the last byte. If it takes longer than TX_FLUSH_TIMEOUT_US, we drop every + // byte until the buffer can be accessible again. + do { + if (usb_serial_jtag_ll_txfifo_writable()) { + usb_serial_jtag_ll_write_txfifo(&cc, 1); + s_ctx.last_tx_ts = esp_timer_get_time(); + break; } - } + } while ((esp_timer_get_time() - s_ctx.last_tx_ts) < TX_FLUSH_TIMEOUT_US); + } static int usb_serial_jtag_rx_char(int fd) @@ -364,25 +354,30 @@ void esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(esp_line_endings_t mode) s_ctx.rx_mode = mode; } +static const esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &usb_serial_jtag_write, + .open = &usb_serial_jtag_open, + .fstat = &usb_serial_jtag_fstat, + .close = &usb_serial_jtag_close, + .read = &usb_serial_jtag_read, + .fcntl = &usb_serial_jtag_fcntl, + .fsync = &usb_serial_jtag_fsync, +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + .tcsetattr = &usb_serial_jtag_tcsetattr, + .tcgetattr = &usb_serial_jtag_tcgetattr, + .tcdrain = &usb_serial_jtag_tcdrain, + .tcflush = &usb_serial_jtag_tcflush, +#endif // CONFIG_VFS_SUPPORT_TERMIOS +}; + +const esp_vfs_t* esp_vfs_usb_serial_jtag_get_vfs(void) +{ + return &vfs; +} esp_err_t esp_vfs_dev_usb_serial_jtag_register(void) { - esp_vfs_t vfs = { - .flags = ESP_VFS_FLAG_DEFAULT, - .write = &usb_serial_jtag_write, - .open = &usb_serial_jtag_open, - .fstat = &usb_serial_jtag_fstat, - .close = &usb_serial_jtag_close, - .read = &usb_serial_jtag_read, - .fcntl = &usb_serial_jtag_fcntl, - .fsync = &usb_serial_jtag_fsync, -#ifdef CONFIG_VFS_SUPPORT_TERMIOS - .tcsetattr = &usb_serial_jtag_tcsetattr, - .tcgetattr = &usb_serial_jtag_tcgetattr, - .tcdrain = &usb_serial_jtag_tcdrain, - .tcflush = &usb_serial_jtag_tcflush, -#endif // CONFIG_VFS_SUPPORT_TERMIOS - }; // "/dev/usb_serial_jtag" unfortunately is too long for vfs return esp_vfs_register("/dev/usbserjtag", &vfs, NULL); }