| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-10-26 14:05:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | #include <stdbool.h>
 | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <sys/errno.h>
 | 
					
						
							|  |  |  | #include <sys/lock.h>
 | 
					
						
							|  |  |  | #include <sys/fcntl.h>
 | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | #include <sys/param.h>
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | #include "esp_vfs.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | #include "esp_vfs_dev.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | #include "esp_attr.h"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 20:19:44 +08:00
										 |  |  | #include "soc/uart_periph.h"
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | #include "driver/uart.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-28 16:16:12 +08:00
										 |  |  | #include "sdkconfig.h"
 | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | #include "driver/uart_select.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-13 21:33:23 +08:00
										 |  |  | #include "esp_rom_uart.h"
 | 
					
						
							| 
									
										
										
										
											2021-03-17 18:48:05 +08:00
										 |  |  | #include "soc/soc_caps.h"
 | 
					
						
							| 
									
										
										
										
											2021-06-08 10:47:49 +08:00
										 |  |  | #include "hal/uart_ll.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | // TODO: make the number of UARTs chip dependent
 | 
					
						
							| 
									
										
										
										
											2019-06-14 11:01:30 +08:00
										 |  |  | #define UART_NUM SOC_UART_NUM
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | // Token signifying that no character is available
 | 
					
						
							|  |  |  | #define NONE -1
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  | #if CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF
 | 
					
						
							|  |  |  | #   define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CRLF
 | 
					
						
							|  |  |  | #elif CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR
 | 
					
						
							|  |  |  | #   define DEFAULT_TX_MODE ESP_LINE_ENDINGS_CR
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #   define DEFAULT_TX_MODE ESP_LINE_ENDINGS_LF
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF
 | 
					
						
							|  |  |  | #   define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CRLF
 | 
					
						
							|  |  |  | #elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR
 | 
					
						
							|  |  |  | #   define DEFAULT_RX_MODE ESP_LINE_ENDINGS_CR
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #   define DEFAULT_RX_MODE ESP_LINE_ENDINGS_LF
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | // UART write bytes function type
 | 
					
						
							|  |  |  | typedef void (*tx_func_t)(int, int); | 
					
						
							|  |  |  | // UART read bytes function type
 | 
					
						
							|  |  |  | typedef int (*rx_func_t)(int); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Basic functions for sending and receiving bytes over UART
 | 
					
						
							|  |  |  | static void uart_tx_char(int fd, int c); | 
					
						
							|  |  |  | static int uart_rx_char(int fd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Functions for sending and receiving bytes which use UART driver
 | 
					
						
							|  |  |  | static void uart_tx_char_via_driver(int fd, int c); | 
					
						
							|  |  |  | static int uart_rx_char_via_driver(int fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     // Pointers to UART peripherals
 | 
					
						
							|  |  |  |     uart_dev_t* uart; | 
					
						
							|  |  |  |     // One-character buffer used for newline conversion code, per UART
 | 
					
						
							|  |  |  |     int peek_char; | 
					
						
							|  |  |  |     // per-UART locks, lazily initialized
 | 
					
						
							|  |  |  |     _lock_t read_lock; | 
					
						
							|  |  |  |     _lock_t write_lock; | 
					
						
							|  |  |  |     // 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.
 | 
					
						
							|  |  |  |     bool non_blocking; | 
					
						
							|  |  |  |     // Newline conversion mode when transmitting
 | 
					
						
							|  |  |  |     esp_line_endings_t tx_mode; | 
					
						
							|  |  |  |     // Newline conversion mode when receiving
 | 
					
						
							|  |  |  |     esp_line_endings_t rx_mode; | 
					
						
							|  |  |  |     // Functions used to write bytes to UART. Default to "basic" functions.
 | 
					
						
							|  |  |  |     tx_func_t tx_func; | 
					
						
							|  |  |  |     // Functions used to read bytes from UART. Default to "basic" functions.
 | 
					
						
							|  |  |  |     rx_func_t rx_func; | 
					
						
							|  |  |  | } vfs_uart_context_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define VFS_CTX_DEFAULT_VAL(uart_dev) (vfs_uart_context_t) {\
 | 
					
						
							|  |  |  |     .uart = (uart_dev),\ | 
					
						
							|  |  |  |     .peek_char = NONE,\ | 
					
						
							|  |  |  |     .tx_mode = DEFAULT_TX_MODE,\ | 
					
						
							|  |  |  |     .rx_mode = DEFAULT_RX_MODE,\ | 
					
						
							|  |  |  |     .tx_func = uart_tx_char,\ | 
					
						
							|  |  |  |     .rx_func = uart_rx_char,\ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //If the context should be dynamically initialized, remove this structure
 | 
					
						
							|  |  |  | //and point s_ctx to allocated data.
 | 
					
						
							|  |  |  | static vfs_uart_context_t s_context[UART_NUM] = { | 
					
						
							|  |  |  |     VFS_CTX_DEFAULT_VAL(&UART0), | 
					
						
							|  |  |  |     VFS_CTX_DEFAULT_VAL(&UART1), | 
					
						
							| 
									
										
										
										
											2019-06-14 11:01:30 +08:00
										 |  |  | #if UART_NUM > 2
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     VFS_CTX_DEFAULT_VAL(&UART2), | 
					
						
							| 
									
										
										
										
											2019-06-14 11:01:30 +08:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  | static vfs_uart_context_t* s_ctx[UART_NUM] = { | 
					
						
							|  |  |  |     &s_context[0], | 
					
						
							|  |  |  |     &s_context[1], | 
					
						
							| 
									
										
										
										
											2019-06-14 11:01:30 +08:00
										 |  |  | #if UART_NUM > 2
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     &s_context[2], | 
					
						
							| 
									
										
										
										
											2019-06-14 11:01:30 +08:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     esp_vfs_select_sem_t select_sem; | 
					
						
							|  |  |  |     fd_set *readfds; | 
					
						
							|  |  |  |     fd_set *writefds; | 
					
						
							|  |  |  |     fd_set *errorfds; | 
					
						
							|  |  |  |     fd_set readfds_orig; | 
					
						
							|  |  |  |     fd_set writefds_orig; | 
					
						
							|  |  |  |     fd_set errorfds_orig; | 
					
						
							|  |  |  | } uart_select_args_t; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static uart_select_args_t **s_registered_selects = NULL; | 
					
						
							|  |  |  | static int s_registered_select_num = 0; | 
					
						
							|  |  |  | static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED; | 
					
						
							| 
									
										
										
										
											2018-05-29 11:01:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static esp_err_t uart_end_select(void *end_select_args); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static int uart_open(const char * path, int flags, int mode) | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     // this is fairly primitive, we should check if file is opened read only,
 | 
					
						
							|  |  |  |     // and error out if write is requested
 | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  |     int fd = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     if (strcmp(path, "/0") == 0) { | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  |         fd = 0; | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     } else if (strcmp(path, "/1") == 0) { | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  |         fd = 1; | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     } else if (strcmp(path, "/2") == 0) { | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  |         fd = 2; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         errno = ENOENT; | 
					
						
							|  |  |  |         return fd; | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     s_ctx[fd]->non_blocking = ((flags & O_NONBLOCK) == O_NONBLOCK); | 
					
						
							| 
									
										
										
										
											2018-03-29 14:18:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return fd; | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static void uart_tx_char(int fd, int c) | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     uart_dev_t* uart = s_ctx[fd]->uart; | 
					
						
							| 
									
										
										
										
											2021-06-08 10:47:49 +08:00
										 |  |  |     const uint8_t ch = (uint8_t) c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (uart_ll_get_txfifo_len(uart) < 2) { | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |         ; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-08 10:47:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     uart_ll_write_txfifo(uart, &ch, 1); | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static void uart_tx_char_via_driver(int fd, int c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char ch = (char) c; | 
					
						
							|  |  |  |     uart_write_bytes(fd, &ch, 1); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static int uart_rx_char(int fd) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     uart_dev_t* uart = s_ctx[fd]->uart; | 
					
						
							| 
									
										
										
										
											2021-06-08 10:47:49 +08:00
										 |  |  |     uint8_t ch; | 
					
						
							|  |  |  |     if (uart_ll_get_rxfifo_len(uart) == 0) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         return NONE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-06-08 10:47:49 +08:00
										 |  |  |     uart_ll_read_rxfifo(uart, &ch, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ch; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int uart_rx_char_via_driver(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t c; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     int timeout = s_ctx[fd]->non_blocking ? 0 : portMAX_DELAY; | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  |     int n = uart_read_bytes(fd, &c, 1, timeout); | 
					
						
							|  |  |  |     if (n <= 0) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         return NONE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t uart_write(int fd, const void * data, size_t size) | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(fd >=0 && fd < 3); | 
					
						
							|  |  |  |     const char *data_c = (const char *)data; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |     /*  Even though newlib does stream locking on each individual stream, we need
 | 
					
						
							| 
									
										
										
										
											2016-10-26 14:05:56 +08:00
										 |  |  |      *  a dedicated UART lock if two streams (stdout and stderr) point to the | 
					
						
							|  |  |  |      *  same UART. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_acquire_recursive(&s_ctx[fd]->write_lock); | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     for (size_t i = 0; i < size; i++) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         int c = data_c[i]; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         if (c == '\n' && s_ctx[fd]->tx_mode != ESP_LINE_ENDINGS_LF) { | 
					
						
							|  |  |  |             s_ctx[fd]->tx_func(fd, '\r'); | 
					
						
							|  |  |  |             if (s_ctx[fd]->tx_mode == ESP_LINE_ENDINGS_CR) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[fd]->tx_func(fd, c); | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_release_recursive(&s_ctx[fd]->write_lock); | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | /* Helper function which returns a previous character or reads a new one from
 | 
					
						
							|  |  |  |  * UART. Previous character can be returned ("pushed back") using | 
					
						
							|  |  |  |  * uart_return_char function. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int uart_read_char(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* return character from peek buffer, if it is there */ | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     if (s_ctx[fd]->peek_char != NONE) { | 
					
						
							|  |  |  |         int c = s_ctx[fd]->peek_char; | 
					
						
							|  |  |  |         s_ctx[fd]->peek_char = NONE; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         return c; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     return s_ctx[fd]->rx_func(fd); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Push back a character; it will be returned by next call to uart_read_char */ | 
					
						
							|  |  |  | static void uart_return_char(int fd, int c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     assert(s_ctx[fd]->peek_char == NONE); | 
					
						
							|  |  |  |     s_ctx[fd]->peek_char = c; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t uart_read(int fd, void* data, size_t size) | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(fd >=0 && fd < 3); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |     char *data_c = (char *) data; | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |     size_t received = 0; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_acquire_recursive(&s_ctx[fd]->read_lock); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |     while (received < size) { | 
					
						
							|  |  |  |         int c = uart_read_char(fd); | 
					
						
							|  |  |  |         if (c == '\r') { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |             if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CR) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |                 c = '\n'; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |             } else if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CRLF) { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |                 /* look ahead */ | 
					
						
							|  |  |  |                 int c2 = uart_read_char(fd); | 
					
						
							|  |  |  |                 if (c2 == NONE) { | 
					
						
							|  |  |  |                     /* could not look ahead, put the current character back */ | 
					
						
							|  |  |  |                     uart_return_char(fd, c); | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |                 if (c2 == '\n') { | 
					
						
							|  |  |  |                     /* this was \r\n sequence. discard \r, return \n */ | 
					
						
							|  |  |  |                     c = '\n'; | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                     /* \r followed by something else. put the second char back,
 | 
					
						
							|  |  |  |                      * it will be processed on next iteration. return \r now. | 
					
						
							|  |  |  |                      */ | 
					
						
							|  |  |  |                     uart_return_char(fd, c2); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  |         } else if (c == NONE) { | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         data_c[received] = (char) c; | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |         ++received; | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  |         if (c == '\n') { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_release_recursive(&s_ctx[fd]->read_lock); | 
					
						
							| 
									
										
										
										
											2017-01-09 22:50:42 +08:00
										 |  |  |     if (received > 0) { | 
					
						
							|  |  |  |         return received; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     errno = EWOULDBLOCK; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static int uart_fstat(int fd, struct stat * st) | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(fd >=0 && fd < 3); | 
					
						
							| 
									
										
										
										
											2020-11-05 17:38:22 +01:00
										 |  |  |     memset(st, 0, sizeof(*st)); | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     st->st_mode = S_IFCHR; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | static int uart_close(int fd) | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(fd >=0 && fd < 3); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-11 17:45:31 +08:00
										 |  |  | static int uart_fcntl(int fd, int cmd, int arg) | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(fd >=0 && fd < 3); | 
					
						
							|  |  |  |     int result = 0; | 
					
						
							|  |  |  |     if (cmd == F_GETFL) { | 
					
						
							| 
									
										
										
										
											2022-07-21 16:16:44 +08:00
										 |  |  |         result |= O_RDWR; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         if (s_ctx[fd]->non_blocking) { | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  |             result |= O_NONBLOCK; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (cmd == F_SETFL) { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[fd]->non_blocking = (arg & O_NONBLOCK) != 0; | 
					
						
							| 
									
										
										
										
											2017-08-16 14:58:06 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         // unsupported operation
 | 
					
						
							|  |  |  |         result = -1; | 
					
						
							|  |  |  |         errno = ENOSYS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_DIR
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 11:44:38 +02:00
										 |  |  | static int uart_access(const char *path, int amode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (strcmp(path, "/0") == 0 || strcmp(path, "/1") == 0 || strcmp(path, "/2") == 0) { | 
					
						
							|  |  |  |         if (F_OK == amode) { | 
					
						
							|  |  |  |             ret = 0; //path exists
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             if ((((amode & R_OK) == R_OK) || ((amode & W_OK) == W_OK)) && ((amode & X_OK) != X_OK)) { | 
					
						
							|  |  |  |                 ret = 0; //path is readable and/or writable but not executable
 | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 errno = EACCES; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         errno = ENOENT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_DIR
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 12:54:53 +08:00
										 |  |  | static int uart_fsync(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(fd >= 0 && fd < 3); | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_acquire_recursive(&s_ctx[fd]->write_lock); | 
					
						
							| 
									
										
										
										
											2020-07-13 21:33:23 +08:00
										 |  |  |     esp_rom_uart_tx_wait_idle((uint8_t) fd); | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_release_recursive(&s_ctx[fd]->write_lock); | 
					
						
							| 
									
										
										
										
											2018-10-25 12:54:53 +08:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static esp_err_t register_select(uart_select_args_t *args) | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     esp_err_t ret = ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (args) { | 
					
						
							|  |  |  |         portENTER_CRITICAL(&s_registered_select_lock); | 
					
						
							|  |  |  |         const int new_size = s_registered_select_num + 1; | 
					
						
							| 
									
										
										
										
											2021-07-20 13:52:53 -06:00
										 |  |  |         uart_select_args_t **new_selects; | 
					
						
							|  |  |  |         if ((new_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *))) == NULL) { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |             ret = ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-07-20 13:52:53 -06:00
										 |  |  |             s_registered_selects = new_selects; | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |             s_registered_selects[s_registered_select_num] = args; | 
					
						
							|  |  |  |             s_registered_select_num = new_size; | 
					
						
							|  |  |  |             ret = ESP_OK; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         portEXIT_CRITICAL(&s_registered_select_lock); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static esp_err_t unregister_select(uart_select_args_t *args) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     esp_err_t ret = ESP_OK; | 
					
						
							|  |  |  |     if (args) { | 
					
						
							|  |  |  |         ret = ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |         portENTER_CRITICAL(&s_registered_select_lock); | 
					
						
							|  |  |  |         for (int i = 0; i < s_registered_select_num; ++i) { | 
					
						
							|  |  |  |             if (s_registered_selects[i] == args) { | 
					
						
							|  |  |  |                 const int new_size = s_registered_select_num - 1; | 
					
						
							|  |  |  |                 // The item is removed by overwriting it with the last item. The subsequent rellocation will drop the
 | 
					
						
							|  |  |  |                 // last item.
 | 
					
						
							|  |  |  |                 s_registered_selects[i] = s_registered_selects[new_size]; | 
					
						
							|  |  |  |                 s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *)); | 
					
						
							| 
									
										
										
										
											2021-07-20 13:52:53 -06:00
										 |  |  |                 // Shrinking a buffer with realloc is guaranteed to succeed.
 | 
					
						
							|  |  |  |                 s_registered_select_num = new_size; | 
					
						
							|  |  |  |                 ret = ESP_OK; | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         portEXIT_CRITICAL(&s_registered_select_lock); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static void select_notif_callback_isr(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     portENTER_CRITICAL_ISR(&s_registered_select_lock); | 
					
						
							|  |  |  |     for (int i = 0; i < s_registered_select_num; ++i) { | 
					
						
							|  |  |  |         uart_select_args_t *args = s_registered_selects[i]; | 
					
						
							|  |  |  |         if (args) { | 
					
						
							|  |  |  |             switch (uart_select_notif) { | 
					
						
							|  |  |  |                 case UART_SELECT_READ_NOTIF: | 
					
						
							|  |  |  |                     if (FD_ISSET(uart_num, &args->readfds_orig)) { | 
					
						
							|  |  |  |                         FD_SET(uart_num, args->readfds); | 
					
						
							|  |  |  |                         esp_vfs_select_triggered_isr(args->select_sem, task_woken); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case UART_SELECT_WRITE_NOTIF: | 
					
						
							|  |  |  |                     if (FD_ISSET(uart_num, &args->writefds_orig)) { | 
					
						
							|  |  |  |                         FD_SET(uart_num, args->writefds); | 
					
						
							|  |  |  |                         esp_vfs_select_triggered_isr(args->select_sem, task_woken); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case UART_SELECT_ERROR_NOTIF: | 
					
						
							|  |  |  |                     if (FD_ISSET(uart_num, &args->errorfds_orig)) { | 
					
						
							|  |  |  |                         FD_SET(uart_num, args->errorfds); | 
					
						
							|  |  |  |                         esp_vfs_select_triggered_isr(args->select_sem, task_woken); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-05-29 11:01:25 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     portEXIT_CRITICAL_ISR(&s_registered_select_lock); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-29 11:01:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | 
					
						
							|  |  |  |         esp_vfs_select_sem_t select_sem, void **end_select_args) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |     const int max_fds = MIN(nfds, UART_NUM); | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     *end_select_args = NULL; | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-14 13:48:36 +01:00
										 |  |  |     for (int i = 0; i < max_fds; ++i) { | 
					
						
							|  |  |  |         if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) { | 
					
						
							|  |  |  |             if (!uart_is_driver_installed(i)) { | 
					
						
							|  |  |  |                 return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     uart_select_args_t *args = malloc(sizeof(uart_select_args_t)); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     if (args == NULL) { | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |         return ESP_ERR_NO_MEM; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     args->select_sem = select_sem; | 
					
						
							|  |  |  |     args->readfds = readfds; | 
					
						
							|  |  |  |     args->writefds = writefds; | 
					
						
							|  |  |  |     args->errorfds = exceptfds; | 
					
						
							|  |  |  |     args->readfds_orig = *readfds; // store the original values because they will be set to zero
 | 
					
						
							|  |  |  |     args->writefds_orig = *writefds; | 
					
						
							|  |  |  |     args->errorfds_orig = *exceptfds; | 
					
						
							|  |  |  |     FD_ZERO(readfds); | 
					
						
							|  |  |  |     FD_ZERO(writefds); | 
					
						
							|  |  |  |     FD_ZERO(exceptfds); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     portENTER_CRITICAL(uart_get_selectlock()); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     //uart_set_select_notif_callback sets the callbacks in UART ISR
 | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |     for (int i = 0; i < max_fds; ++i) { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |         if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { | 
					
						
							|  |  |  |             uart_set_select_notif_callback(i, select_notif_callback_isr); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-27 12:53:19 +01:00
										 |  |  |     for (int i = 0; i < max_fds; ++i) { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |         if (FD_ISSET(i, &args->readfds_orig)) { | 
					
						
							| 
									
										
										
										
											2018-11-27 12:53:19 +01:00
										 |  |  |             size_t buffered_size; | 
					
						
							|  |  |  |             if (uart_get_buffered_data_len(i, &buffered_size) == ESP_OK && buffered_size > 0) { | 
					
						
							|  |  |  |                 // signalize immediately when data is buffered
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |                 FD_SET(i, readfds); | 
					
						
							|  |  |  |                 esp_vfs_select_triggered(args->select_sem); | 
					
						
							| 
									
										
										
										
											2018-11-27 12:53:19 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     esp_err_t ret = register_select(args); | 
					
						
							|  |  |  |     if (ret != ESP_OK) { | 
					
						
							|  |  |  |         portEXIT_CRITICAL(uart_get_selectlock()); | 
					
						
							|  |  |  |         free(args); | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-07 11:40:52 +05:30
										 |  |  |     portEXIT_CRITICAL(uart_get_selectlock()); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     *end_select_args = args; | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | static esp_err_t uart_end_select(void *end_select_args) | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     uart_select_args_t *args = end_select_args; | 
					
						
							| 
									
										
										
										
											2018-05-29 11:01:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     portENTER_CRITICAL(uart_get_selectlock()); | 
					
						
							|  |  |  |     esp_err_t ret = unregister_select(args); | 
					
						
							|  |  |  |     for (int i = 0; i < UART_NUM; ++i) { | 
					
						
							|  |  |  |         uart_set_select_notif_callback(i, NULL); | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-07 11:40:52 +05:30
										 |  |  |     portEXIT_CRITICAL(uart_get_selectlock()); | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-09 15:02:38 +02:00
										 |  |  |     if (args) { | 
					
						
							|  |  |  |         free(args); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 14:08:21 +02:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2018-05-03 10:41:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 17:14:58 +02:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_TERMIOS
 | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  | static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fd < 0 || fd >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (p == NULL) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (optional_actions) { | 
					
						
							|  |  |  |         case TCSANOW: | 
					
						
							|  |  |  |             // nothing to do
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case TCSADRAIN: | 
					
						
							|  |  |  |             if (uart_wait_tx_done(fd, portMAX_DELAY) != ESP_OK) { | 
					
						
							|  |  |  |                 errno = EINVAL; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-09-07 16:13:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             /* FALLTHRU */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |         case TCSAFLUSH: | 
					
						
							|  |  |  |             if (uart_flush_input(fd) != ESP_OK) { | 
					
						
							|  |  |  |                 errno = EINVAL; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (p->c_iflag & IGNCR) { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_CRLF; | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |     } else if (p->c_iflag & ICRNL) { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_CR; | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[fd]->rx_mode = ESP_LINE_ENDINGS_LF; | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // output line endings are not supported because there is no alternative in termios for converting LF to CR
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uart_word_length_t data_bits; | 
					
						
							|  |  |  |         const tcflag_t csize_bits = p->c_cflag & CSIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (csize_bits) { | 
					
						
							|  |  |  |             case CS5: | 
					
						
							|  |  |  |                 data_bits = UART_DATA_5_BITS; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case CS6: | 
					
						
							|  |  |  |                 data_bits = UART_DATA_6_BITS; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case CS7: | 
					
						
							|  |  |  |                 data_bits = UART_DATA_7_BITS; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case CS8: | 
					
						
							|  |  |  |                 data_bits = UART_DATA_8_BITS; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 errno = EINVAL; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (uart_set_word_length(fd, data_bits) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (uart_set_stop_bits(fd, (p->c_cflag & CSTOPB) ? UART_STOP_BITS_2 : UART_STOP_BITS_1) != ESP_OK) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (uart_set_parity(fd, (p->c_cflag & PARENB) ? | 
					
						
							|  |  |  |                 ((p->c_cflag & PARODD) ? UART_PARITY_ODD : UART_PARITY_EVEN) | 
					
						
							|  |  |  |                 : | 
					
						
							|  |  |  |                 UART_PARITY_DISABLE) != ESP_OK) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (p->c_cflag & (CBAUD | CBAUDEX)) { | 
					
						
							|  |  |  |         if (p->c_ispeed != p->c_ospeed) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             uint32_t b; | 
					
						
							|  |  |  |             if (p->c_cflag & BOTHER) { | 
					
						
							|  |  |  |                 b = p->c_ispeed; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 switch (p->c_ispeed) { | 
					
						
							|  |  |  |                     case B0: | 
					
						
							|  |  |  |                         b = 0; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B50: | 
					
						
							|  |  |  |                         b = 50; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B75: | 
					
						
							|  |  |  |                         b = 75; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B110: | 
					
						
							|  |  |  |                         b = 110; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B134: | 
					
						
							|  |  |  |                         b = 134; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B150: | 
					
						
							|  |  |  |                         b = 150; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B200: | 
					
						
							|  |  |  |                         b = 200; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B300: | 
					
						
							|  |  |  |                         b = 300; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B600: | 
					
						
							|  |  |  |                         b = 600; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B1200: | 
					
						
							|  |  |  |                         b = 1200; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B1800: | 
					
						
							|  |  |  |                         b = 1800; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B2400: | 
					
						
							|  |  |  |                         b = 2400; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B4800: | 
					
						
							|  |  |  |                         b = 4800; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B9600: | 
					
						
							|  |  |  |                         b = 9600; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B19200: | 
					
						
							|  |  |  |                         b = 19200; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B38400: | 
					
						
							|  |  |  |                         b = 38400; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B57600: | 
					
						
							|  |  |  |                         b = 57600; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B115200: | 
					
						
							|  |  |  |                         b = 115200; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B230400: | 
					
						
							|  |  |  |                         b = 230400; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B460800: | 
					
						
							|  |  |  |                         b = 460800; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B500000: | 
					
						
							|  |  |  |                         b = 500000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B576000: | 
					
						
							|  |  |  |                         b = 576000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B921600: | 
					
						
							|  |  |  |                         b = 921600; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B1000000: | 
					
						
							|  |  |  |                         b = 1000000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B1152000: | 
					
						
							|  |  |  |                         b = 1152000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B1500000: | 
					
						
							|  |  |  |                         b = 1500000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B2000000: | 
					
						
							|  |  |  |                         b = 2000000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B2500000: | 
					
						
							|  |  |  |                         b = 2500000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B3000000: | 
					
						
							|  |  |  |                         b = 3000000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B3500000: | 
					
						
							|  |  |  |                         b = 3500000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     case B4000000: | 
					
						
							|  |  |  |                         b = 4000000; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     default: | 
					
						
							|  |  |  |                         errno = EINVAL; | 
					
						
							|  |  |  |                         return -1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (uart_set_baudrate(fd, b) != ESP_OK) { | 
					
						
							|  |  |  |                 errno = EINVAL; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int uart_tcgetattr(int fd, struct termios *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fd < 0 || fd >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (p == NULL) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memset(p, 0, sizeof(struct termios)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CRLF) { | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |         p->c_iflag |= IGNCR; | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     } else if (s_ctx[fd]->rx_mode == ESP_LINE_ENDINGS_CR) { | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |         p->c_iflag |= ICRNL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uart_word_length_t data_bits; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (uart_get_word_length(fd, &data_bits) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p->c_cflag &= (~CSIZE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (data_bits) { | 
					
						
							|  |  |  |             case UART_DATA_5_BITS: | 
					
						
							|  |  |  |                 p->c_cflag |= CS5; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_DATA_6_BITS: | 
					
						
							|  |  |  |                 p->c_cflag |= CS6; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_DATA_7_BITS: | 
					
						
							|  |  |  |                 p->c_cflag |= CS7; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_DATA_8_BITS: | 
					
						
							|  |  |  |                 p->c_cflag |= CS8; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 errno = ENOSYS; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uart_stop_bits_t stop_bits; | 
					
						
							|  |  |  |         if (uart_get_stop_bits(fd, &stop_bits) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (stop_bits) { | 
					
						
							|  |  |  |             case UART_STOP_BITS_1: | 
					
						
							|  |  |  |                 // nothing to do
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_STOP_BITS_2: | 
					
						
							|  |  |  |                 p->c_cflag |= CSTOPB; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 // UART_STOP_BITS_1_5 is unsupported by termios
 | 
					
						
							|  |  |  |                 errno = ENOSYS; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uart_parity_t parity_mode; | 
					
						
							|  |  |  |         if (uart_get_parity(fd, &parity_mode) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (parity_mode) { | 
					
						
							|  |  |  |             case UART_PARITY_EVEN: | 
					
						
							|  |  |  |                 p->c_cflag |= PARENB; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_PARITY_ODD: | 
					
						
							|  |  |  |                 p->c_cflag |= (PARENB | PARODD); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case UART_PARITY_DISABLE: | 
					
						
							|  |  |  |                 // nothing to do
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 errno = ENOSYS; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uint32_t baudrate; | 
					
						
							|  |  |  |         if (uart_get_baudrate(fd, &baudrate) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p->c_cflag |= (CBAUD | CBAUDEX); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         speed_t sp; | 
					
						
							|  |  |  |         switch (baudrate) { | 
					
						
							|  |  |  |             case 0: | 
					
						
							|  |  |  |                 sp = B0; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 50: | 
					
						
							|  |  |  |                 sp = B50; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 75: | 
					
						
							|  |  |  |                 sp = B75; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 110: | 
					
						
							|  |  |  |                 sp = B110; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 134: | 
					
						
							|  |  |  |                 sp = B134; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 150: | 
					
						
							|  |  |  |                 sp = B150; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 200: | 
					
						
							|  |  |  |                 sp = B200; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 300: | 
					
						
							|  |  |  |                 sp = B300; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 600: | 
					
						
							|  |  |  |                 sp = B600; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1200: | 
					
						
							|  |  |  |                 sp = B1200; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1800: | 
					
						
							|  |  |  |                 sp = B1800; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2400: | 
					
						
							|  |  |  |                 sp = B2400; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 4800: | 
					
						
							|  |  |  |                 sp = B4800; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 9600: | 
					
						
							|  |  |  |                 sp = B9600; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 19200: | 
					
						
							|  |  |  |                 sp = B19200; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 38400: | 
					
						
							|  |  |  |                 sp = B38400; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 57600: | 
					
						
							|  |  |  |                 sp = B57600; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 115200: | 
					
						
							|  |  |  |                 sp = B115200; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 230400: | 
					
						
							|  |  |  |                 sp = B230400; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 460800: | 
					
						
							|  |  |  |                 sp = B460800; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 500000: | 
					
						
							|  |  |  |                 sp = B500000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 576000: | 
					
						
							|  |  |  |                 sp = B576000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 921600: | 
					
						
							|  |  |  |                 sp = B921600; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1000000: | 
					
						
							|  |  |  |                 sp = B1000000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1152000: | 
					
						
							|  |  |  |                 sp = B1152000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1500000: | 
					
						
							|  |  |  |                 sp = B1500000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2000000: | 
					
						
							|  |  |  |                 sp = B2000000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2500000: | 
					
						
							|  |  |  |                 sp = B2500000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 3000000: | 
					
						
							|  |  |  |                 sp = B3000000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 3500000: | 
					
						
							|  |  |  |                 sp = B3500000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 4000000: | 
					
						
							|  |  |  |                 sp = B4000000; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 p->c_cflag |= BOTHER; | 
					
						
							|  |  |  |                 sp = baudrate; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         p->c_ispeed = p->c_ospeed = sp; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int uart_tcdrain(int fd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fd < 0 || fd >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (uart_wait_tx_done(fd, portMAX_DELAY) != ESP_OK) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int uart_tcflush(int fd, int select) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (fd < 0 || fd >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (select == TCIFLUSH) { | 
					
						
							|  |  |  |         if (uart_flush_input(fd) != ESP_OK) { | 
					
						
							|  |  |  |             errno = EINVAL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // output flushing is not supported
 | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-02 17:14:58 +02:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_TERMIOS
 | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  | 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, | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_DIR
 | 
					
						
							| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  |     .access = &uart_access, | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_DIR
 | 
					
						
							|  |  |  | #ifdef CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  |     .start_select = &uart_start_select, | 
					
						
							|  |  |  |     .end_select = &uart_end_select, | 
					
						
							| 
									
										
										
										
											2020-03-20 13:35:00 +01:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_SELECT
 | 
					
						
							| 
									
										
										
										
											2019-07-02 17:14:58 +02:00
										 |  |  | #ifdef CONFIG_VFS_SUPPORT_TERMIOS
 | 
					
						
							| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  |     .tcsetattr = &uart_tcsetattr, | 
					
						
							|  |  |  |     .tcgetattr = &uart_tcgetattr, | 
					
						
							|  |  |  |     .tcdrain = &uart_tcdrain, | 
					
						
							|  |  |  |     .tcflush = &uart_tcflush, | 
					
						
							| 
									
										
										
										
											2019-07-02 17:14:58 +02:00
										 |  |  | #endif // CONFIG_VFS_SUPPORT_TERMIOS
 | 
					
						
							| 
									
										
										
										
											2021-10-21 12:46:24 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const esp_vfs_t* esp_vfs_uart_get_vfs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return &vfs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void esp_vfs_dev_uart_register(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-25 22:01:50 +08:00
										 |  |  |     ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 17:00:47 +08:00
										 |  |  | int esp_vfs_dev_uart_port_set_rx_line_endings(int uart_num, esp_line_endings_t mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (uart_num < 0 || uart_num >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s_ctx[uart_num]->rx_mode = mode; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int esp_vfs_dev_uart_port_set_tx_line_endings(int uart_num, esp_line_endings_t mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (uart_num < 0 || uart_num >= UART_NUM) { | 
					
						
							|  |  |  |         errno = EBADF; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s_ctx[uart_num]->tx_mode = mode; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | void esp_vfs_dev_uart_set_rx_line_endings(esp_line_endings_t mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |     for (int i = 0; i < UART_NUM; ++i) { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |         s_ctx[i]->rx_mode = mode; | 
					
						
							| 
									
										
										
										
											2018-08-14 13:39:30 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void esp_vfs_dev_uart_set_tx_line_endings(esp_line_endings_t mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     for (int i = 0; i < UART_NUM; ++i) { | 
					
						
							|  |  |  |         s_ctx[i]->tx_mode = mode; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 09:01:56 +02:00
										 |  |  | void esp_vfs_dev_uart_use_nonblocking(int uart_num) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_acquire_recursive(&s_ctx[uart_num]->read_lock); | 
					
						
							|  |  |  |     _lock_acquire_recursive(&s_ctx[uart_num]->write_lock); | 
					
						
							|  |  |  |     s_ctx[uart_num]->tx_func = uart_tx_char; | 
					
						
							|  |  |  |     s_ctx[uart_num]->rx_func = uart_rx_char; | 
					
						
							|  |  |  |     _lock_release_recursive(&s_ctx[uart_num]->write_lock); | 
					
						
							|  |  |  |     _lock_release_recursive(&s_ctx[uart_num]->read_lock); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 09:01:56 +02:00
										 |  |  | void esp_vfs_dev_uart_use_driver(int uart_num) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 01:18:20 +08:00
										 |  |  |     _lock_acquire_recursive(&s_ctx[uart_num]->read_lock); | 
					
						
							|  |  |  |     _lock_acquire_recursive(&s_ctx[uart_num]->write_lock); | 
					
						
							|  |  |  |     s_ctx[uart_num]->tx_func = uart_tx_char_via_driver; | 
					
						
							|  |  |  |     s_ctx[uart_num]->rx_func = uart_rx_char_via_driver; | 
					
						
							|  |  |  |     _lock_release_recursive(&s_ctx[uart_num]->write_lock); | 
					
						
							|  |  |  |     _lock_release_recursive(&s_ctx[uart_num]->read_lock); | 
					
						
							| 
									
										
										
										
											2017-08-15 16:23:23 +08:00
										 |  |  | } |