forked from espressif/esp-idf
feat(usb_cdc): Add select functionality
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CDCACM_SELECT_READ_NOTIF,
|
||||
CDCACM_SELECT_WRITE_NOTIF,
|
||||
CDCACM_SELECT_ERROR_NOTIF,
|
||||
} cdcacm_select_notif_t;
|
||||
|
||||
typedef void (*cdcacm_select_notif_callback_t)(cdcacm_select_notif_t cdcacm_select_notif, BaseType_t *task_woken);
|
||||
|
||||
/**
|
||||
* @brief Set notification callback function for select() events
|
||||
* @param cdcacm_select_notif_callback callback function
|
||||
*/
|
||||
void cdcacm_set_select_notif_callback(cdcacm_select_notif_callback_t cdcacm_select_notif_callback);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,5 +1,6 @@
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -91,6 +92,15 @@ bool esp_usb_console_write_available(void);
|
||||
*/
|
||||
esp_err_t esp_usb_console_set_cb(esp_usb_console_cb_t rx_cb, esp_usb_console_cb_t tx_cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the USB console is installed or not
|
||||
*
|
||||
* @return
|
||||
* - true USB console is installed
|
||||
* - false USB console is not installed
|
||||
*/
|
||||
bool esp_usb_console_is_installed(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -46,6 +46,8 @@
|
||||
#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h"
|
||||
#endif
|
||||
|
||||
#include "esp_private/esp_vfs_cdcacm_select.h"
|
||||
|
||||
#define CDC_WORK_BUF_SIZE (ESP_ROM_CDC_ACM_WORK_BUF_MIN + CONFIG_ESP_CONSOLE_USB_CDC_RX_BUF_SIZE)
|
||||
|
||||
typedef enum {
|
||||
@@ -55,6 +57,7 @@ typedef enum {
|
||||
REBOOT_BOOTLOADER_DFU,
|
||||
} reboot_type_t;
|
||||
|
||||
static bool s_usb_installed = false;
|
||||
static reboot_type_t s_queue_reboot = REBOOT_NONE;
|
||||
static int s_prev_rts_state;
|
||||
static intr_handle_t s_usb_int_handle;
|
||||
@@ -131,6 +134,18 @@ int esp_usb_console_osglue_wait_proc(int delay_us)
|
||||
}
|
||||
}
|
||||
|
||||
/* USB interrupt handler, forward the call to the ROM driver.
|
||||
* Non-static to allow placement into IRAM by ldgen.
|
||||
*/
|
||||
static cdcacm_select_notif_callback_t s_cdcacm_select_notif_callback = NULL;
|
||||
|
||||
void cdcacm_set_select_notif_callback(cdcacm_select_notif_callback_t cdcacm_select_notif_callback)
|
||||
{
|
||||
if (esp_usb_console_is_installed()) {
|
||||
s_cdcacm_select_notif_callback = cdcacm_select_notif_callback;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called by ROM CDC ACM driver from interrupt context./
|
||||
* Non-static to allow placement into IRAM by ldgen.
|
||||
*/
|
||||
@@ -168,6 +183,8 @@ void esp_usb_console_dfu_detach_cb(int timeout)
|
||||
*/
|
||||
void esp_usb_console_interrupt(void *arg)
|
||||
{
|
||||
BaseType_t xTaskWoken = 0;
|
||||
|
||||
usb_dc_check_poll_for_interrupts();
|
||||
/* Restart can be requested from esp_usb_console_cdc_acm_cb or esp_usb_console_dfu_detach_cb */
|
||||
if (s_queue_reboot != REBOOT_NONE) {
|
||||
@@ -192,6 +209,21 @@ void esp_usb_console_interrupt(void *arg)
|
||||
esp_restart_noos();
|
||||
}
|
||||
}
|
||||
|
||||
if (esp_usb_console_available_for_read() > 0) {
|
||||
if (s_cdcacm_select_notif_callback != NULL) {
|
||||
s_cdcacm_select_notif_callback(CDCACM_SELECT_READ_NOTIF, &xTaskWoken);
|
||||
}
|
||||
}
|
||||
if (esp_usb_console_write_available()) {
|
||||
if (s_cdcacm_select_notif_callback != NULL) {
|
||||
s_cdcacm_select_notif_callback(CDCACM_SELECT_WRITE_NOTIF, &xTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
if (xTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
/* Called as esp_timer callback when the restart timeout expires.
|
||||
@@ -299,6 +331,7 @@ esp_err_t esp_usb_console_init(void)
|
||||
esp_rom_install_channel_putc(1, &esp_usb_console_write_char);
|
||||
#endif // CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF
|
||||
|
||||
s_usb_installed = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -422,6 +455,11 @@ esp_err_t esp_usb_console_set_cb(esp_usb_console_cb_t rx_cb, esp_usb_console_cb_
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool esp_usb_console_is_installed(void)
|
||||
{
|
||||
return s_usb_installed;
|
||||
}
|
||||
|
||||
ssize_t esp_usb_console_available_for_read(void)
|
||||
{
|
||||
if (s_cdc_acm_device == NULL) {
|
||||
|
@@ -0,0 +1,4 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
components/esp_vfs_console/test_apps/usb_cdc_vfs:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32s3"] # reason: console components is only implemented on these targets. TODO P4: IDF-9120
|
@@ -0,0 +1,9 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
list(PREPEND SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" "sdkconfig.defaults")
|
||||
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(usb_cdc_vfs_test)
|
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-S3 |
|
||||
| ----------------- | -------- |
|
@@ -0,0 +1,7 @@
|
||||
set(src "test_app_main.c")
|
||||
|
||||
idf_component_register(SRCS ${src}
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES esp_system esp_vfs_console unity
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/errno.h>
|
||||
#include "unity.h"
|
||||
#include "esp_private/usb_console.h"
|
||||
#include "esp_vfs_cdcacm.h"
|
||||
|
||||
static int read_bytes_with_select(FILE *stream, void *buf, size_t buf_len, struct timeval tv)
|
||||
{
|
||||
int fd = fileno(stream);
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fd, &read_fds);
|
||||
|
||||
/* call select with to wait for either a read ready or timeout to happen */
|
||||
int nread = select(fd + 1, &read_fds, NULL, NULL, &tv);
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
} else if (FD_ISSET(fd, &read_fds)) {
|
||||
int read_count = 0;
|
||||
int total_read = 0;
|
||||
|
||||
do {
|
||||
read_count = read(fileno(stream), buf + total_read, 1);
|
||||
if (read_count < 0 && errno != EWOULDBLOCK) {
|
||||
return -1;
|
||||
} else if (read_count > 0) {
|
||||
total_read += read_count;
|
||||
if (total_read > buf_len) {
|
||||
fflush(stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (read_count > 0);
|
||||
|
||||
return total_read;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
char out_buffer[32];
|
||||
memset(out_buffer, 0, sizeof(out_buffer));
|
||||
size_t out_buffer_len = sizeof(out_buffer);
|
||||
|
||||
// stdin needs to be non blocking to properly call read after select returns
|
||||
// with read ready on stdin.
|
||||
int fd = fileno(stdin);
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
int res = fcntl(fd, F_SETFL, flags);
|
||||
TEST_ASSERT(res == 0);
|
||||
|
||||
// init driver
|
||||
// ESP_ERROR_CHECK(esp_usb_console_init());
|
||||
// esp_vfs_dev_cdcacm_register();
|
||||
|
||||
// send the message from pytest environment and make sure it can be read
|
||||
bool message_received = false;
|
||||
size_t char_read = 0;
|
||||
while (!message_received && out_buffer_len > char_read) {
|
||||
int nread = read_bytes_with_select(stdin, out_buffer + char_read, out_buffer_len - char_read, tv);
|
||||
if (nread > 0) {
|
||||
char_read += nread;
|
||||
if (out_buffer[char_read - 1] == '\n') {
|
||||
message_received = true;
|
||||
}
|
||||
} else if (nread == -2) {
|
||||
// time out occurred, send the expected message back to the testing
|
||||
// environment to trigger the testing environment into sending the
|
||||
// test message. don't update this message without updating the pytest
|
||||
// function since the string is expected as is by the test environment
|
||||
char timeout_msg[] = "select timed out\n";
|
||||
write(fileno(stdout), timeout_msg, sizeof(timeout_msg));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the received message back to the test environment. The test
|
||||
// environment will check that the message received matches the one sent
|
||||
write(fileno(stdout), out_buffer, char_read);
|
||||
|
||||
vTaskDelay(10); // wait for the string to send
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.usb_device
|
||||
@pytest.mark.parametrize(
|
||||
'port, flash_port, config',
|
||||
[
|
||||
pytest.param('/dev/serial_ports/ttyACM-esp32', '/dev/serial_ports/ttyUSB-esp32', 'release'),
|
||||
],
|
||||
indirect=True,)
|
||||
@pytest.mark.parametrize('test_message', ['test123456789!@#%^&*'])
|
||||
def test_usb_cdc_vfs_default(dut: Dut, test_message: str) -> None:
|
||||
dut.expect_exact('select timed out', timeout=2)
|
||||
dut.write(test_message)
|
||||
dut.expect_exact(test_message, timeout=2)
|
@@ -0,0 +1,6 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
@@ -0,0 +1,8 @@
|
||||
# Enable Unity fixture support
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=n
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
|
||||
# Custom partition table for this test app
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
CONFIG_ESP_CONSOLE_USB_CDC=y
|
@@ -15,9 +15,13 @@
|
||||
#include "esp_vfs_cdcacm.h"
|
||||
#include "esp_attr.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#include "esp_private/esp_vfs_cdcacm_select.h"
|
||||
#include "esp_private/usb_console.h"
|
||||
|
||||
#define USB_CDC_LOCAL_FD 0
|
||||
|
||||
// Newline conversion mode when transmitting
|
||||
static esp_line_endings_t s_tx_mode =
|
||||
#if CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF
|
||||
@@ -38,6 +42,12 @@ static esp_line_endings_t s_rx_mode =
|
||||
ESP_LINE_ENDINGS_LF;
|
||||
#endif
|
||||
|
||||
#if CONFIG_VFS_SELECT_IN_RAM
|
||||
#define CDCACM_VFS_MALLOC_FLAGS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define CDCACM_VFS_MALLOC_FLAGS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#define NONE -1
|
||||
|
||||
//Read and write lock, lazily initialized
|
||||
@@ -48,6 +58,26 @@ static bool s_blocking;
|
||||
static SemaphoreHandle_t s_rx_semaphore;
|
||||
static SemaphoreHandle_t s_tx_semaphore;
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
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;
|
||||
} cdcacm_select_args_t;
|
||||
|
||||
static cdcacm_select_args_t **s_registered_selects = NULL;
|
||||
static int s_registered_select_num = 0;
|
||||
static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static esp_err_t cdcacm_end_select(void *end_select_args);
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static ssize_t cdcacm_write(int fd, const void *data, size_t size)
|
||||
{
|
||||
assert(fd == 0);
|
||||
@@ -82,7 +112,7 @@ static int cdcacm_fsync(int fd)
|
||||
|
||||
static int cdcacm_open(const char *path, int flags, int mode)
|
||||
{
|
||||
return 0; // fd 0
|
||||
return USB_CDC_LOCAL_FD; // fd 0
|
||||
}
|
||||
|
||||
static int cdcacm_fstat(int fd, struct stat *st)
|
||||
@@ -290,6 +320,167 @@ static int cdcacm_fcntl(int fd, int cmd, int arg)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static void select_notif_callback_isr(cdcacm_select_notif_t cdcacm_select_notif, BaseType_t *task_woken)
|
||||
{
|
||||
portENTER_CRITICAL_ISR(&s_registered_select_lock);
|
||||
for (int i = 0; i < s_registered_select_num; ++i) {
|
||||
cdcacm_select_args_t *args = s_registered_selects[i];
|
||||
if (args) {
|
||||
switch (cdcacm_select_notif) {
|
||||
case CDCACM_SELECT_READ_NOTIF:
|
||||
if (FD_ISSET(USB_CDC_LOCAL_FD, &args->readfds_orig)) {
|
||||
FD_SET(USB_CDC_LOCAL_FD, args->readfds);
|
||||
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
|
||||
}
|
||||
break;
|
||||
case CDCACM_SELECT_WRITE_NOTIF:
|
||||
if (FD_ISSET(USB_CDC_LOCAL_FD, &args->writefds_orig)) {
|
||||
FD_SET(USB_CDC_LOCAL_FD, args->writefds);
|
||||
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
|
||||
}
|
||||
break;
|
||||
case CDCACM_SELECT_ERROR_NOTIF:
|
||||
if (FD_ISSET(USB_CDC_LOCAL_FD, &args->errorfds_orig)) {
|
||||
FD_SET(USB_CDC_LOCAL_FD, args->errorfds);
|
||||
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL_ISR(&s_registered_select_lock);
|
||||
}
|
||||
|
||||
static esp_err_t register_select(cdcacm_select_args_t *args)
|
||||
{
|
||||
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;
|
||||
cdcacm_select_args_t **new_selects;
|
||||
if ((new_selects = heap_caps_realloc(s_registered_selects, new_size * sizeof(cdcacm_select_args_t *), CDCACM_VFS_MALLOC_FLAGS)) == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
} else {
|
||||
/* on first select registration register the callback */
|
||||
if (s_registered_select_num == 0) {
|
||||
cdcacm_set_select_notif_callback(select_notif_callback_isr);
|
||||
}
|
||||
|
||||
s_registered_selects = new_selects;
|
||||
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(cdcacm_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 = heap_caps_realloc(s_registered_selects, new_size * sizeof(cdcacm_select_args_t *), CDCACM_VFS_MALLOC_FLAGS);
|
||||
// Shrinking a buffer with realloc is guaranteed to succeed.
|
||||
s_registered_select_num = new_size;
|
||||
|
||||
/* when the last select is unregistered, also unregister the callback */
|
||||
if (s_registered_select_num == 0) {
|
||||
cdcacm_set_select_notif_callback(NULL);
|
||||
}
|
||||
|
||||
ret = ESP_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&s_registered_select_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t cdcacm_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
esp_vfs_select_sem_t select_sem, void **end_select_args)
|
||||
{
|
||||
(void)nfds; /* Since there is only 1 USB OTG, this parameter is useless */
|
||||
*end_select_args = NULL;
|
||||
|
||||
if (!esp_usb_console_is_installed()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
cdcacm_select_args_t *args = heap_caps_malloc(sizeof(cdcacm_select_args_t), CDCACM_VFS_MALLOC_FLAGS);
|
||||
|
||||
if (args == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
esp_err_t ret = register_select(args);
|
||||
if (ret != ESP_OK) {
|
||||
free(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool trigger_select = false;
|
||||
if (FD_ISSET(USB_CDC_LOCAL_FD, &args->readfds_orig) &&
|
||||
esp_usb_console_available_for_read() > 0) {
|
||||
|
||||
// signalize immediately when read is ready
|
||||
FD_SET(USB_CDC_LOCAL_FD, readfds);
|
||||
trigger_select = true;
|
||||
}
|
||||
|
||||
if (FD_ISSET(USB_CDC_LOCAL_FD, &args->writefds_orig) &&
|
||||
esp_usb_console_write_available()) {
|
||||
|
||||
// signalize immediately when write is ready
|
||||
FD_SET(USB_CDC_LOCAL_FD, writefds);
|
||||
trigger_select = true;
|
||||
}
|
||||
|
||||
if (trigger_select) {
|
||||
esp_vfs_select_triggered(args->select_sem);
|
||||
}
|
||||
|
||||
*end_select_args = args;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cdcacm_end_select(void *end_select_args)
|
||||
{
|
||||
cdcacm_select_args_t *args = end_select_args;
|
||||
esp_err_t ret = unregister_select(args);
|
||||
if (args) {
|
||||
free(args);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
void esp_vfs_dev_cdcacm_set_tx_line_endings(esp_line_endings_t mode)
|
||||
{
|
||||
s_tx_mode = mode;
|
||||
@@ -300,6 +491,13 @@ void esp_vfs_dev_cdcacm_set_rx_line_endings(esp_line_endings_t mode)
|
||||
s_rx_mode = mode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
static const esp_vfs_select_ops_t s_cdcacm_vfs_select = {
|
||||
.start_select = &cdcacm_start_select,
|
||||
.end_select = &cdcacm_end_select,
|
||||
};
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static const esp_vfs_fs_ops_t s_cdcacm_vfs = {
|
||||
.write = &cdcacm_write,
|
||||
.open = &cdcacm_open,
|
||||
@@ -307,7 +505,10 @@ static const esp_vfs_fs_ops_t s_cdcacm_vfs = {
|
||||
.close = &cdcacm_close,
|
||||
.read = &cdcacm_read,
|
||||
.fcntl = &cdcacm_fcntl,
|
||||
.fsync = &cdcacm_fsync
|
||||
.fsync = &cdcacm_fsync,
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
.select = &s_cdcacm_vfs_select,
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
};
|
||||
|
||||
const esp_vfs_fs_ops_t *esp_vfs_cdcacm_get_vfs(void)
|
||||
|
Reference in New Issue
Block a user