kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'feature/termios' into 'master'
Add basic support for termios.h See merge request idf/esp-idf!3085pull/2386/head
commit
6d865c6104
|
@ -0,0 +1,296 @@
|
|||
// Copyright 2018 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.
|
||||
//
|
||||
// This header file is based on the termios header of
|
||||
// "The Single UNIX (r) Specification, Version 2, Copyright (c) 1997 The Open Group".
|
||||
|
||||
#ifndef __ESP_SYS_TERMIOS_H__
|
||||
#define __ESP_SYS_TERMIOS_H__
|
||||
|
||||
// ESP-IDF NOTE: This header provides only a compatibility layer for macros and functions defined in sys/termios.h.
|
||||
// Not everything has a defined meaning for ESP-IDF (e.g. process leader IDs) and therefore are likely to be stubbed
|
||||
// in actual implementations.
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
|
||||
// subscripts for the array c_cc:
|
||||
#define VEOF 0 /** EOF character */
|
||||
#define VEOL 1 /** EOL character */
|
||||
#define VERASE 2 /** ERASE character */
|
||||
#define VINTR 3 /** INTR character */
|
||||
#define VKILL 4 /** KILL character */
|
||||
#define VMIN 5 /** MIN value */
|
||||
#define VQUIT 6 /** QUIT character */
|
||||
#define VSTART 7 /** START character */
|
||||
#define VSTOP 8 /** STOP character */
|
||||
#define VSUSP 9 /** SUSP character */
|
||||
#define VTIME 10 /** TIME value */
|
||||
#define NCCS (VTIME + 1) /** Size of the array c_cc for control characters */
|
||||
|
||||
// input modes for use as flags in the c_iflag field
|
||||
#define BRKINT (1u << 0) /** Signal interrupt on break. */
|
||||
#define ICRNL (1u << 1) /** Map CR to NL on input. */
|
||||
#define IGNBRK (1u << 2) /** Ignore break condition. */
|
||||
#define IGNCR (1u << 3) /** Ignore CR. */
|
||||
#define IGNPAR (1u << 4) /** Ignore characters with parity errors. */
|
||||
#define INLCR (1u << 5) /** Map NL to CR on input. */
|
||||
#define INPCK (1u << 6) /** Enable input parity check. */
|
||||
#define ISTRIP (1u << 7) /** Strip character. */
|
||||
#define IUCLC (1u << 8) /** Map upper-case to lower-case on input (LEGACY). */
|
||||
#define IXANY (1u << 9) /** Enable any character to restart output. */
|
||||
#define IXOFF (1u << 10) /** Enable start/stop input control. */
|
||||
#define IXON (1u << 11) /** Enable start/stop output control. */
|
||||
#define PARMRK (1u << 12) /** Mark parity errors. */
|
||||
|
||||
// output Modes for use as flags in the c_oflag field
|
||||
#define OPOST (1u << 0) /** Post-process output */
|
||||
#define OLCUC (1u << 1) /** Map lower-case to upper-case on output (LEGACY). */
|
||||
#define ONLCR (1u << 2) /** Map NL to CR-NL on output. */
|
||||
#define OCRNL (1u << 3) /** Map CR to NL on output. */
|
||||
#define ONOCR (1u << 4) /** No CR output at column 0. */
|
||||
#define ONLRET (1u << 5) /** NL performs CR function. */
|
||||
#define OFILL (1u << 6) /** Use fill characters for delay. */
|
||||
#define NLDLY (1u << 7) /** Select newline delays: */
|
||||
#define NL0 (0u << 7) /** Newline character type 0. */
|
||||
#define NL1 (1u << 7) /** Newline character type 1. */
|
||||
#define CRDLY (3u << 8) /** Select carriage-return delays: */
|
||||
#define CR0 (0u << 8) /** Carriage-return delay type 0. */
|
||||
#define CR1 (1u << 8) /** Carriage-return delay type 1. */
|
||||
#define CR2 (2u << 8) /** Carriage-return delay type 2. */
|
||||
#define CR3 (3u << 8) /** Carriage-return delay type 3. */
|
||||
#define TABDLY (3u << 10) /** Select horizontal-tab delays: */
|
||||
#define TAB0 (0u << 10) /** Horizontal-tab delay type 0. */
|
||||
#define TAB1 (1u << 10) /** Horizontal-tab delay type 1. */
|
||||
#define TAB2 (2u << 10) /** Horizontal-tab delay type 2. */
|
||||
#define TAB3 (3u << 10) /** Expand tabs to spaces. */
|
||||
#define BSDLY (1u << 12) /** Select backspace delays: */
|
||||
#define BS0 (0u << 12) /** Backspace-delay type 0. */
|
||||
#define BS1 (1u << 12) /** Backspace-delay type 1. */
|
||||
#define VTDLY (1u << 13) /** Select vertical-tab delays: */
|
||||
#define VT0 (0u << 13) /** Vertical-tab delay type 0. */
|
||||
#define VT1 (1u << 13) /** Vertical-tab delay type 1. */
|
||||
#define FFDLY (1u << 14) /** Select form-feed delays: */
|
||||
#define FF0 (0u << 14) /** Form-feed delay type 0. */
|
||||
#define FF1 (1u << 14) /** Form-feed delay type 1. */
|
||||
|
||||
// Baud Rate Selection. Valid values for objects of type speed_t:
|
||||
// CBAUD range B0 - B38400
|
||||
#define B0 0 /** Hang up */
|
||||
#define B50 1
|
||||
#define B75 2
|
||||
#define B110 3
|
||||
#define B134 4
|
||||
#define B150 5
|
||||
#define B200 6
|
||||
#define B300 7
|
||||
#define B600 8
|
||||
#define B1200 9
|
||||
#define B1800 10
|
||||
#define B2400 11
|
||||
#define B4800 12
|
||||
#define B9600 13
|
||||
#define B19200 14
|
||||
#define B38400 15
|
||||
// CBAUDEX range B57600 - B4000000
|
||||
#define B57600 16
|
||||
#define B115200 17
|
||||
#define B230400 18
|
||||
#define B460800 19
|
||||
#define B500000 20
|
||||
#define B576000 21
|
||||
#define B921600 22
|
||||
#define B1000000 23
|
||||
#define B1152000 24
|
||||
#define B1500000 25
|
||||
#define B2000000 26
|
||||
#define B2500000 27
|
||||
#define B3000000 28
|
||||
#define B3500000 29
|
||||
#define B4000000 30
|
||||
|
||||
// Control Modes for the c_cflag field:
|
||||
#define CSIZE (3u << 0) /* Character size: */
|
||||
#define CS5 (0u << 0) /** 5 bits. */
|
||||
#define CS6 (1u << 0) /** 6 bits. */
|
||||
#define CS7 (2u << 0) /** 7 bits. */
|
||||
#define CS8 (3u << 0) /** 8 bits. */
|
||||
#define CSTOPB (1u << 2) /** Send two stop bits, else one. */
|
||||
#define CREAD (1u << 3) /** Enable receiver. */
|
||||
#define PARENB (1u << 4) /** Parity enable. */
|
||||
#define PARODD (1u << 5) /** Odd parity, else even. */
|
||||
#define HUPCL (1u << 6) /** Hang up on last close. */
|
||||
#define CLOCAL (1u << 7) /** Ignore modem status lines. */
|
||||
#define CBAUD (1u << 8) /** Use baud rates defined by B0-B38400 macros. */
|
||||
#define CBAUDEX (1u << 9) /** Use baud rates defined by B57600-B4000000 macros. */
|
||||
#define BOTHER (1u << 10) /** Use custom baud rates */
|
||||
|
||||
// Local Modes for c_lflag field:
|
||||
#define ECHO (1u << 0) /** Enable echo. */
|
||||
#define ECHOE (1u << 1) /** Echo erase character as error-correcting backspace. */
|
||||
#define ECHOK (1u << 2) /** Echo KILL. */
|
||||
#define ECHONL (1u << 3) /** Echo NL. */
|
||||
#define ICANON (1u << 4) /** Canonical input (erase and kill processing). */
|
||||
#define IEXTEN (1u << 5) /** Enable extended input character processing. */
|
||||
#define ISIG (1u << 6) /** Enable signals. */
|
||||
#define NOFLSH (1u << 7) /** Disable flush after interrupt or quit. */
|
||||
#define TOSTOP (1u << 8) /** Send SIGTTOU for background output. */
|
||||
#define XCASE (1u << 9) /** Canonical upper/lower presentation (LEGACY). */
|
||||
|
||||
// Attribute Selection constants for use with tcsetattr():
|
||||
#define TCSANOW 0 /** Change attributes immediately. */
|
||||
#define TCSADRAIN 1 /** Change attributes when output has drained. */
|
||||
#define TCSAFLUSH 2 /** Change attributes when output has drained; also flush pending input. */
|
||||
|
||||
// Line Control constants for use with tcflush():
|
||||
#define TCIFLUSH 0 /** Flush pending input. Flush untransmitted output. */
|
||||
#define TCIOFLUSH 1 /** Flush both pending input and untransmitted output. */
|
||||
#define TCOFLUSH 2 /** Flush untransmitted output. */
|
||||
|
||||
// constants for use with tcflow():
|
||||
#define TCIOFF 0 /** Transmit a STOP character, intended to suspend input data. */
|
||||
#define TCION 1 /** Transmit a START character, intended to restart input data. */
|
||||
#define TCOOFF 2 /** Suspend output. */
|
||||
#define TCOON 3 /** Restart output. */
|
||||
|
||||
typedef uint8_t cc_t;
|
||||
typedef uint32_t speed_t;
|
||||
typedef uint16_t tcflag_t;
|
||||
|
||||
struct termios
|
||||
{
|
||||
tcflag_t c_iflag; /** Input modes */
|
||||
tcflag_t c_oflag; /** Output modes */
|
||||
tcflag_t c_cflag; /** Control modes */
|
||||
tcflag_t c_lflag; /** Local modes */
|
||||
cc_t c_cc[NCCS]; /** Control characters */
|
||||
speed_t c_ispeed; /** input baud rate */
|
||||
speed_t c_ospeed; /** output baud rate */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Extracts the input baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return input baud rate
|
||||
*/
|
||||
speed_t cfgetispeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Extracts the output baud rate from the input structure exactly (without interpretation).
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @return output baud rate
|
||||
*/
|
||||
speed_t cfgetospeed(const struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Set input baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp input baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetispeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Set output baud rate in the termios structure
|
||||
*
|
||||
* There is no effect in hardware until a subsequent call of tcsetattr().
|
||||
*
|
||||
* @param p input termios structure
|
||||
* @param sp output baud rate
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int cfsetospeed(struct termios *p, speed_t sp);
|
||||
|
||||
/**
|
||||
* @brief Wait for transmission of output
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcdrain(int fd);
|
||||
|
||||
/**
|
||||
* @brief Suspend or restart the transmission or reception of data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param action selects actions to do
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflow(int fd, int action);
|
||||
|
||||
/**
|
||||
* @brief Flush non-transmitted output data and non-read input data
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param select selects what should be flushed
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcflush(int fd, int select);
|
||||
|
||||
/**
|
||||
* @brief Gets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param p output termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcgetattr(int fd, struct termios *p);
|
||||
|
||||
/**
|
||||
* @brief Get process group ID for session leader for controlling terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @return process group ID when successful, -1 otherwise with errno set
|
||||
*/
|
||||
pid_t tcgetsid(int fd);
|
||||
|
||||
/**
|
||||
* @brief Send a break for a specific duration
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param duration duration of break
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsendbreak(int fd, int duration);
|
||||
|
||||
/**
|
||||
* @brief Sets the parameters of the terminal
|
||||
*
|
||||
* @param fd file descriptor of the terminal
|
||||
* @param optional_actions optional actions
|
||||
* @param p input termios structure
|
||||
* @return 0 when successful, -1 otherwise with errno set
|
||||
*/
|
||||
int tcsetattr(int fd, int optional_actions, const struct termios *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
|
||||
#endif //__ESP_SYS_TERMIOS_H__
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
|
||||
#include <sys/termios.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
speed_t cfgetispeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ispeed : B0;
|
||||
}
|
||||
|
||||
speed_t cfgetospeed(const struct termios *p)
|
||||
{
|
||||
return p ? p->c_ospeed : B0;
|
||||
}
|
||||
|
||||
int cfsetispeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ispeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int cfsetospeed(struct termios *p, speed_t sp)
|
||||
{
|
||||
if (p) {
|
||||
p->c_ospeed = sp;
|
||||
return 0;
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
|
@ -9,4 +9,10 @@ config SUPPRESS_SELECT_DEBUG_OUTPUT
|
|||
It is possible to suppress these debug outputs by enabling this
|
||||
option.
|
||||
|
||||
config SUPPORT_TERMIOS
|
||||
bool "Add support for termios.h"
|
||||
default y
|
||||
help
|
||||
Disabling this option can save memory when the support for termios.h is not required.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -26,8 +26,10 @@
|
|||
#include <sys/reent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/termios.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -178,6 +180,37 @@ typedef struct
|
|||
int (*truncate_p)(void* ctx, const char *path, off_t length);
|
||||
int (*truncate)(const char *path, off_t length);
|
||||
};
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
union {
|
||||
int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p);
|
||||
int (*tcsetattr)(int fd, int optional_actions, const struct termios *p);
|
||||
};
|
||||
union {
|
||||
int (*tcgetattr_p)(void *ctx, int fd, struct termios *p);
|
||||
int (*tcgetattr)(int fd, struct termios *p);
|
||||
};
|
||||
union {
|
||||
int (*tcdrain_p)(void *ctx, int fd);
|
||||
int (*tcdrain)(int fd);
|
||||
};
|
||||
union {
|
||||
int (*tcflush_p)(void *ctx, int fd, int select);
|
||||
int (*tcflush)(int fd, int select);
|
||||
};
|
||||
union {
|
||||
int (*tcflow_p)(void *ctx, int fd, int action);
|
||||
int (*tcflow)(int fd, int action);
|
||||
};
|
||||
union {
|
||||
pid_t (*tcgetsid_p)(void *ctx, int fd);
|
||||
pid_t (*tcgetsid)(int fd);
|
||||
};
|
||||
union {
|
||||
int (*tcsendbreak_p)(void *ctx, int fd, int duration);
|
||||
int (*tcsendbreak)(int fd, int duration);
|
||||
};
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
|
||||
/** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */
|
||||
esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, SemaphoreHandle_t *signal_sem);
|
||||
/** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/errno.h>
|
||||
#include "unity.h"
|
||||
#include "rom/uart.h"
|
||||
#include "soc/uart_struct.h"
|
||||
|
@ -23,6 +26,7 @@
|
|||
#include "freertos/semphr.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static void fwrite_str_loopback(const char* str, size_t size)
|
||||
|
@ -198,3 +202,131 @@ TEST_CASE("can write to UART while another task is reading", "[vfs]")
|
|||
vSemaphoreDelete(read_arg.done);
|
||||
vSemaphoreDelete(write_arg.done);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
TEST_CASE("Can use termios for UART", "[vfs]")
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
|
||||
};
|
||||
uart_param_config(UART_NUM_1, &uart_config);
|
||||
uart_driver_install(UART_NUM_1, 256, 256, 0, NULL, 0);
|
||||
|
||||
const int uart_fd = open("/dev/uart/1", O_RDWR);
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(uart_fd, -1, "Cannot open UART");
|
||||
esp_vfs_dev_uart_use_driver(1);
|
||||
|
||||
TEST_ASSERT_EQUAL(-1, tcgetattr(uart_fd, NULL));
|
||||
TEST_ASSERT_EQUAL(EINVAL, errno);
|
||||
|
||||
struct termios tios, tios_result;
|
||||
|
||||
TEST_ASSERT_EQUAL(-1, tcgetattr(-1, &tios));
|
||||
TEST_ASSERT_EQUAL(EBADF, errno);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSADRAIN, &tios));
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSAFLUSH, &tios));
|
||||
|
||||
tios.c_iflag |= IGNCR;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
tios.c_iflag &= (~IGNCR);
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(IGNCR, tios_result.c_iflag & IGNCR);
|
||||
memset(&tios_result, 0xFF, sizeof(struct termios));
|
||||
|
||||
tios.c_iflag |= ICRNL;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
tios.c_iflag &= (~ICRNL);
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(ICRNL, tios_result.c_iflag & ICRNL);
|
||||
memset(&tios_result, 0xFF, sizeof(struct termios));
|
||||
|
||||
{
|
||||
uart_word_length_t data_bit;
|
||||
uart_stop_bits_t stop_bits;
|
||||
uart_parity_t parity_mode;
|
||||
|
||||
tios.c_cflag &= (~CSIZE);
|
||||
tios.c_cflag &= (~CSTOPB);
|
||||
tios.c_cflag &= (~PARENB);
|
||||
tios.c_cflag |= CS6;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
tios.c_cflag &= (~CSIZE);
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(CS6, tios_result.c_cflag & CS6);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_word_length(UART_NUM_1, &data_bit));
|
||||
TEST_ASSERT_EQUAL(UART_DATA_6_BITS, data_bit);
|
||||
TEST_ASSERT_EQUAL(0, tios_result.c_cflag & CSTOPB);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_stop_bits(UART_NUM_1, &stop_bits));
|
||||
TEST_ASSERT_EQUAL(UART_STOP_BITS_1, stop_bits);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_parity(UART_NUM_1, &parity_mode));
|
||||
TEST_ASSERT_EQUAL(UART_PARITY_DISABLE, parity_mode);
|
||||
memset(&tios_result, 0xFF, sizeof(struct termios));
|
||||
}
|
||||
|
||||
{
|
||||
uart_stop_bits_t stop_bits;
|
||||
uart_parity_t parity_mode;
|
||||
|
||||
tios.c_cflag |= CSTOPB;
|
||||
tios.c_cflag |= (PARENB | PARODD);
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
tios.c_cflag &= (~(CSTOPB | PARENB | PARODD));
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(CSTOPB, tios_result.c_cflag & CSTOPB);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_stop_bits(UART_NUM_1, &stop_bits));
|
||||
TEST_ASSERT_EQUAL(UART_STOP_BITS_2, stop_bits);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_parity(UART_NUM_1, &parity_mode));
|
||||
TEST_ASSERT_EQUAL(UART_PARITY_ODD, parity_mode);
|
||||
memset(&tios_result, 0xFF, sizeof(struct termios));
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t baudrate;
|
||||
|
||||
tios.c_cflag &= (~BOTHER);
|
||||
tios.c_cflag |= CBAUD;
|
||||
tios.c_ispeed = tios.c_ospeed = B38400;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(CBAUD, tios_result.c_cflag & CBAUD);
|
||||
TEST_ASSERT_EQUAL(B38400, tios_result.c_ispeed);
|
||||
TEST_ASSERT_EQUAL(B38400, tios_result.c_ospeed);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
|
||||
TEST_ASSERT_EQUAL(38400, baudrate);
|
||||
|
||||
tios.c_cflag |= CBAUDEX;
|
||||
tios.c_ispeed = tios.c_ospeed = B230400;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(BOTHER, tios_result.c_cflag & BOTHER);
|
||||
// Setting the speed to 230400 will set it actually to 230423
|
||||
TEST_ASSERT_EQUAL(230423, tios_result.c_ispeed);
|
||||
TEST_ASSERT_EQUAL(230423, tios_result.c_ospeed);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
|
||||
TEST_ASSERT_EQUAL(230423, baudrate);
|
||||
|
||||
tios.c_cflag |= BOTHER;
|
||||
tios.c_ispeed = tios.c_ospeed = 213;
|
||||
TEST_ASSERT_EQUAL(0, tcsetattr(uart_fd, TCSANOW, &tios));
|
||||
TEST_ASSERT_EQUAL(0, tcgetattr(uart_fd, &tios_result));
|
||||
TEST_ASSERT_EQUAL(BOTHER, tios_result.c_cflag & BOTHER);
|
||||
TEST_ASSERT_EQUAL(213, tios_result.c_ispeed);
|
||||
TEST_ASSERT_EQUAL(213, tios_result.c_ospeed);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, uart_get_baudrate(UART_NUM_1, &baudrate));
|
||||
TEST_ASSERT_EQUAL(213, baudrate);
|
||||
|
||||
memset(&tios_result, 0xFF, sizeof(struct termios));
|
||||
}
|
||||
|
||||
esp_vfs_dev_uart_use_nonblocking(1);
|
||||
close(uart_fd);
|
||||
uart_driver_delete(UART_NUM_1);
|
||||
}
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
|
|
|
@ -994,3 +994,103 @@ void esp_vfs_select_triggered_isr(SemaphoreHandle_t *signal_sem, BaseType_t *wok
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
int tcgetattr(int fd, struct termios *p)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcgetattr, local_fd, p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcsetattr(int fd, int optional_actions, const struct termios *p)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcsetattr, local_fd, optional_actions, p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcdrain(int fd)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcdrain, local_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcflush(int fd, int select)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcflush, local_fd, select);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcflow(int fd, int action)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcflow, local_fd, action);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pid_t tcgetsid(int fd)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcgetsid, local_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tcsendbreak(int fd, int duration)
|
||||
{
|
||||
const vfs_entry_t* vfs = get_vfs_for_fd(fd);
|
||||
const int local_fd = get_local_fd(vfs, fd);
|
||||
struct _reent* r = __getreent();
|
||||
if (vfs == NULL || local_fd < 0) {
|
||||
__errno_r(r) = EBADF;
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
CHECK_AND_CALL(ret, r, vfs, tcsendbreak, local_fd, duration);
|
||||
return ret;
|
||||
}
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
|
|
|
@ -80,14 +80,15 @@ static esp_line_endings_t s_tx_mode =
|
|||
#endif
|
||||
|
||||
// Newline conversion mode when receiving
|
||||
static esp_line_endings_t s_rx_mode =
|
||||
static esp_line_endings_t s_rx_mode[UART_NUM] = { [0 ... UART_NUM-1] =
|
||||
#if CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF
|
||||
ESP_LINE_ENDINGS_CRLF;
|
||||
ESP_LINE_ENDINGS_CRLF
|
||||
#elif CONFIG_NEWLIB_STDIN_LINE_ENDING_CR
|
||||
ESP_LINE_ENDINGS_CR;
|
||||
ESP_LINE_ENDINGS_CR
|
||||
#else
|
||||
ESP_LINE_ENDINGS_LF;
|
||||
ESP_LINE_ENDINGS_LF
|
||||
#endif
|
||||
};
|
||||
|
||||
static void uart_end_select();
|
||||
|
||||
|
@ -213,9 +214,9 @@ static ssize_t uart_read(int fd, void* data, size_t size)
|
|||
while (received < size) {
|
||||
int c = uart_read_char(fd);
|
||||
if (c == '\r') {
|
||||
if (s_rx_mode == ESP_LINE_ENDINGS_CR) {
|
||||
if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) {
|
||||
c = '\n';
|
||||
} else if (s_rx_mode == ESP_LINE_ENDINGS_CRLF) {
|
||||
} else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) {
|
||||
/* look ahead */
|
||||
int c2 = uart_read_char(fd);
|
||||
if (c2 == NONE) {
|
||||
|
@ -420,6 +421,456 @@ static void uart_end_select()
|
|||
_lock_release(&s_one_select_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
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;
|
||||
}
|
||||
// intentional fall-through to the next case
|
||||
case TCSAFLUSH:
|
||||
if (uart_flush_input(fd) != ESP_OK) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p->c_iflag & IGNCR) {
|
||||
s_rx_mode[fd] = ESP_LINE_ENDINGS_CRLF;
|
||||
} else if (p->c_iflag & ICRNL) {
|
||||
s_rx_mode[fd] = ESP_LINE_ENDINGS_CR;
|
||||
} else {
|
||||
s_rx_mode[fd] = ESP_LINE_ENDINGS_LF;
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CRLF) {
|
||||
p->c_iflag |= IGNCR;
|
||||
} else if (s_rx_mode[fd] == ESP_LINE_ENDINGS_CR) {
|
||||
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;
|
||||
}
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
|
||||
void esp_vfs_dev_uart_register()
|
||||
{
|
||||
esp_vfs_t vfs = {
|
||||
|
@ -433,13 +884,21 @@ void esp_vfs_dev_uart_register()
|
|||
.access = &uart_access,
|
||||
.start_select = &uart_start_select,
|
||||
.end_select = &uart_end_select,
|
||||
#ifdef CONFIG_SUPPORT_TERMIOS
|
||||
.tcsetattr = &uart_tcsetattr,
|
||||
.tcgetattr = &uart_tcgetattr,
|
||||
.tcdrain = &uart_tcdrain,
|
||||
.tcflush = &uart_tcflush,
|
||||
#endif // CONFIG_SUPPORT_TERMIOS
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_vfs_register("/dev/uart", &vfs, NULL));
|
||||
}
|
||||
|
||||
void esp_vfs_dev_uart_set_rx_line_endings(esp_line_endings_t mode)
|
||||
{
|
||||
s_rx_mode = mode;
|
||||
for (int i = 0; i < UART_NUM; ++i) {
|
||||
s_rx_mode[i] = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_vfs_dev_uart_set_tx_line_endings(esp_line_endings_t mode)
|
||||
|
|
Ładowanie…
Reference in New Issue