forked from espressif/esp-idf
Merge branch 'feat/usb-serial-jtag-select' into 'master'
feat(usb_serial_jtag): Add select functionality to the driver Closes IDF-7415 and IDFGH-8509 See merge request espressif/esp-idf!30919
This commit is contained in:
@@ -18,6 +18,7 @@ endif()
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include}
|
||||
PRIV_REQUIRES "${priv_requires}"
|
||||
LDFRAGMENTS "linker.lf"
|
||||
)
|
||||
|
||||
if(CONFIG_VFS_SUPPORT_IO AND CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED)
|
||||
|
@@ -105,6 +105,13 @@ esp_err_t usb_serial_jtag_driver_uninstall(void);
|
||||
*/
|
||||
bool usb_serial_jtag_is_connected(void);
|
||||
|
||||
/**
|
||||
* @brief Get information whether the USB serial JTAG driver is installed or not
|
||||
*
|
||||
* @return True if driver is installed and False if driver not installed
|
||||
*/
|
||||
bool usb_serial_jtag_is_driver_installed(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,46 @@
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
|
||||
typedef enum {
|
||||
USJ_SELECT_READ_NOTIF,
|
||||
USJ_SELECT_WRITE_NOTIF,
|
||||
USJ_SELECT_ERROR_NOTIF,
|
||||
} usj_select_notif_t;
|
||||
|
||||
typedef void (*usj_select_notif_callback_t)(usj_select_notif_t usb_serial_jtag_select_notif, BaseType_t *task_woken);
|
||||
|
||||
/**
|
||||
* @brief Set notification callback function for select() events
|
||||
* @param usb_serial_jtag_select_notif_callback callback function
|
||||
*/
|
||||
void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usb_serial_jtag_select_notif_callback);
|
||||
|
||||
/**
|
||||
* @brief Return the readiness status of the driver for read operation
|
||||
*
|
||||
* @return true if driver read ready, false if not
|
||||
*/
|
||||
bool usb_serial_jtag_read_ready(void);
|
||||
|
||||
/**
|
||||
* @brief Return the readiness status of the driver for write operation
|
||||
*
|
||||
* @return true if driver is write ready, false if not
|
||||
*/
|
||||
bool usb_serial_jtag_write_ready(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
5
components/esp_driver_usb_serial_jtag/linker.lf
Normal file
5
components/esp_driver_usb_serial_jtag/linker.lf
Normal file
@@ -0,0 +1,5 @@
|
||||
[mapping:usb_serial_jtag_vfs]
|
||||
archive: libesp_driver_usb_serial_jtag.a
|
||||
entries:
|
||||
if VFS_SELECT_IN_RAM = y:
|
||||
usb_serial_jtag_vfs: select_notif_callback_isr (noflash)
|
@@ -14,6 +14,7 @@
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
#include "driver/usb_serial_jtag_select.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_check.h"
|
||||
@@ -49,6 +50,8 @@ typedef struct {
|
||||
//Synchronization stuff, only used for flush for now
|
||||
SemaphoreHandle_t tx_mux;
|
||||
SemaphoreHandle_t tx_idle_sem;
|
||||
|
||||
usj_select_notif_callback_t usj_select_notif_callback; /*!< Notification about select() events */
|
||||
} usb_serial_jtag_obj_t;
|
||||
|
||||
static usb_serial_jtag_obj_t *p_usb_serial_jtag_obj = NULL;
|
||||
@@ -103,6 +106,12 @@ static void usb_serial_jtag_isr_handler_default(void *arg)
|
||||
// Return the buffer if we got it from the ring buffer.
|
||||
if (queued_buf != p_usb_serial_jtag_obj->tx_stash_buf) {
|
||||
vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buf, &xTaskWoken);
|
||||
|
||||
// We just moved items out of the TX ring buffer, the driver is considered write ready, since
|
||||
// the TX ring buffer is assured to be not full.
|
||||
if (p_usb_serial_jtag_obj->usj_select_notif_callback) {
|
||||
p_usb_serial_jtag_obj->usj_select_notif_callback(USJ_SELECT_WRITE_NOTIF, &xTaskWoken);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No data to send.
|
||||
@@ -139,6 +148,10 @@ static void usb_serial_jtag_isr_handler_default(void *arg)
|
||||
uint8_t buf[USB_SER_JTAG_RX_MAX_SIZE];
|
||||
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(buf, USB_SER_JTAG_RX_MAX_SIZE);
|
||||
xRingbufferSendFromISR(p_usb_serial_jtag_obj->rx_ring_buf, buf, rx_fifo_len, &xTaskWoken);
|
||||
|
||||
if (p_usb_serial_jtag_obj->usj_select_notif_callback) {
|
||||
p_usb_serial_jtag_obj->usj_select_notif_callback(USJ_SELECT_READ_NOTIF, &xTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
if (xTaskWoken == pdTRUE) {
|
||||
@@ -341,3 +354,29 @@ esp_err_t usb_serial_jtag_driver_uninstall(void)
|
||||
p_usb_serial_jtag_obj = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool usb_serial_jtag_is_driver_installed(void)
|
||||
{
|
||||
return (p_usb_serial_jtag_obj != NULL);
|
||||
}
|
||||
|
||||
void usb_serial_jtag_set_select_notif_callback(usj_select_notif_callback_t usj_select_notif_callback)
|
||||
{
|
||||
if (usb_serial_jtag_is_driver_installed()) {
|
||||
p_usb_serial_jtag_obj->usj_select_notif_callback = usj_select_notif_callback;
|
||||
}
|
||||
}
|
||||
|
||||
bool usb_serial_jtag_read_ready(void)
|
||||
{
|
||||
// sign the the driver is read ready is that data is waiting in the RX ringbuffer
|
||||
UBaseType_t items_waiting = 0;
|
||||
vRingbufferGetInfo(p_usb_serial_jtag_obj->rx_ring_buf, NULL, NULL, NULL, NULL, &items_waiting);
|
||||
return items_waiting != 0;
|
||||
}
|
||||
|
||||
bool usb_serial_jtag_write_ready(void)
|
||||
{
|
||||
// sign that the driver is write ready is that the TX ring buffer is not full
|
||||
return (xRingbufferGetCurFreeSize(p_usb_serial_jtag_obj->tx_ring_buf) > 0);
|
||||
}
|
||||
|
@@ -23,9 +23,14 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
#include "driver/usb_serial_jtag_select.h"
|
||||
#include "driver/usb_serial_jtag_vfs.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// local file descriptor value for the USJ
|
||||
#define USJ_LOCAL_FD 0
|
||||
|
||||
// Token signifying that no character is available
|
||||
#define NONE -1
|
||||
@@ -46,6 +51,12 @@
|
||||
# define DEFAULT_RX_MODE ESP_LINE_ENDINGS_LF
|
||||
#endif
|
||||
|
||||
#if CONFIG_VFS_SELECT_IN_RAM
|
||||
#define USJ_VFS_MALLOC_FLAGS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define USJ_VFS_MALLOC_FLAGS MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
// write bytes function type
|
||||
typedef void (*tx_func_t)(int, int);
|
||||
// read bytes function type
|
||||
@@ -108,10 +119,30 @@ static usb_serial_jtag_vfs_context_t s_ctx = {
|
||||
.fsync_func = usb_serial_jtag_wait_tx_done_no_driver
|
||||
};
|
||||
|
||||
#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;
|
||||
} usb_serial_jtag_select_args_t;
|
||||
|
||||
static usb_serial_jtag_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 usb_serial_jtag_end_select(void *end_select_args);
|
||||
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static int usb_serial_jtag_open(const char * path, int flags, int mode)
|
||||
{
|
||||
s_ctx.non_blocking = ((flags & O_NONBLOCK) == O_NONBLOCK);
|
||||
return 0;
|
||||
return USJ_LOCAL_FD;
|
||||
}
|
||||
|
||||
static void usb_serial_jtag_tx_char_no_driver(int fd, int c)
|
||||
@@ -300,6 +331,164 @@ static int usb_serial_jtag_fsync(int fd)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
|
||||
static void select_notif_callback_isr(usj_select_notif_t usj_select_notif, BaseType_t *task_woken)
|
||||
{
|
||||
portENTER_CRITICAL_ISR(&s_registered_select_lock);
|
||||
for (int i = 0; i < s_registered_select_num; ++i) {
|
||||
usb_serial_jtag_select_args_t *args = s_registered_selects[i];
|
||||
if (args) {
|
||||
switch (usj_select_notif) {
|
||||
case USJ_SELECT_READ_NOTIF:
|
||||
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig)) {
|
||||
FD_SET(USJ_LOCAL_FD, args->readfds);
|
||||
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
|
||||
}
|
||||
break;
|
||||
case USJ_SELECT_WRITE_NOTIF:
|
||||
if (FD_ISSET(USJ_LOCAL_FD, &args->writefds_orig)) {
|
||||
FD_SET(USJ_LOCAL_FD, args->writefds);
|
||||
esp_vfs_select_triggered_isr(args->select_sem, task_woken);
|
||||
}
|
||||
break;
|
||||
case USJ_SELECT_ERROR_NOTIF:
|
||||
if (FD_ISSET(USJ_LOCAL_FD, &args->errorfds_orig)) {
|
||||
FD_SET(USJ_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(usb_serial_jtag_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;
|
||||
usb_serial_jtag_select_args_t **new_selects;
|
||||
if ((new_selects = heap_caps_realloc(s_registered_selects, new_size * sizeof(usb_serial_jtag_select_args_t *), USJ_VFS_MALLOC_FLAGS)) == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
} else {
|
||||
/* on first select registration register the callback */
|
||||
if (s_registered_select_num == 0) {
|
||||
usb_serial_jtag_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(usb_serial_jtag_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(usb_serial_jtag_select_args_t *), USJ_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) {
|
||||
usb_serial_jtag_set_select_notif_callback(NULL);
|
||||
}
|
||||
|
||||
ret = ESP_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&s_registered_select_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t usb_serial_jtag_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 serial jtag port, this parameter is useless */
|
||||
*end_select_args = NULL;
|
||||
if (!usb_serial_jtag_is_driver_installed()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
usb_serial_jtag_select_args_t *args = heap_caps_malloc(sizeof(usb_serial_jtag_select_args_t), USJ_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;
|
||||
|
||||
// check if the select should return instantly if the bus is read ready
|
||||
if (FD_ISSET(USJ_LOCAL_FD, &args->readfds_orig) && usb_serial_jtag_read_ready()) {
|
||||
// signal immediately when data is buffered
|
||||
FD_SET(USJ_LOCAL_FD, readfds);
|
||||
trigger_select = true;
|
||||
}
|
||||
|
||||
// check if the select should return instantly if the bus is write ready
|
||||
if (FD_ISSET(USJ_LOCAL_FD, &args->writefds_orig) && usb_serial_jtag_write_ready()) {
|
||||
// signal immediately when data can be written
|
||||
FD_SET(USJ_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 usb_serial_jtag_end_select(void *end_select_args)
|
||||
{
|
||||
usb_serial_jtag_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
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
static int usb_serial_jtag_tcsetattr(int fd, int optional_actions, const struct termios *p)
|
||||
{
|
||||
@@ -391,6 +580,10 @@ static const esp_vfs_t usj_vfs = {
|
||||
.read = &usb_serial_jtag_read,
|
||||
.fcntl = &usb_serial_jtag_fcntl,
|
||||
.fsync = &usb_serial_jtag_fsync,
|
||||
#ifdef CONFIG_VFS_SUPPORT_SELECT
|
||||
.start_select = &usb_serial_jtag_start_select,
|
||||
.end_select = &usb_serial_jtag_end_select,
|
||||
#endif // CONFIG_VFS_SUPPORT_SELECT
|
||||
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
|
||||
.tcsetattr = &usb_serial_jtag_tcsetattr,
|
||||
.tcgetattr = &usb_serial_jtag_tcgetattr,
|
||||
|
@@ -11,3 +11,14 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag:
|
||||
- vfs
|
||||
- esp_driver_gpio
|
||||
- esp_driver_usb_serial_jtag
|
||||
|
||||
components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs:
|
||||
disable:
|
||||
- if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32c61"]
|
||||
temporary: true
|
||||
reason: No runners.
|
||||
depends_components:
|
||||
- vfs
|
||||
- esp_driver_usb_serial_jtag
|
||||
|
@@ -0,0 +1,11 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
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_serial_jtag_vfs_test)
|
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
|
@@ -0,0 +1,9 @@
|
||||
set(src "test_app_main.c"
|
||||
"test_vfs_usb_serial_jtag.c"
|
||||
)
|
||||
|
||||
idf_component_register(SRCS ${src}
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES esp_driver_usb_serial_jtag unity test_utils esp_psram
|
||||
WHOLE_ARCHIVE
|
||||
)
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated, the threadhold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (500)
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
|
||||
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/usb_serial_jtag_vfs.h"
|
||||
#include "driver/usb_serial_jtag.h"
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "test_utils.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
struct task_arg_t {
|
||||
FILE* stream;
|
||||
SemaphoreHandle_t done;
|
||||
};
|
||||
|
||||
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, buf_len - total_read);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* In this test, the select returning on timeout, write and read ready functionalities
|
||||
* are under test. To achieve that, the testing environment:
|
||||
* 0) Starts the test
|
||||
* 1) Waits for the select to timeout (read_bytes_with_select returns timeout error which
|
||||
* triggers the sending of the timeout message back to the testing environment)
|
||||
* 2) Sends the test message (read_bytes_with_select returns with the received message that
|
||||
* is sent back to the testing environment to be checked)
|
||||
* 3) A parallel tasks calls select on stdout for writing and decrement a variable for every
|
||||
* write calls. At the end of the test, the variable is check to make sure the select returned
|
||||
* for each of the write calls.
|
||||
*/
|
||||
TEST_CASE("test select read, write and timeout", "[usb_serial_jtag]")
|
||||
{
|
||||
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
|
||||
usb_serial_jtag_driver_config_t usj_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usj_config));
|
||||
usb_serial_jtag_vfs_use_driver();
|
||||
|
||||
// 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);
|
||||
|
||||
// wait for the string to send
|
||||
vTaskDelay(10);
|
||||
|
||||
usb_serial_jtag_vfs_use_nonblocking();
|
||||
usb_serial_jtag_driver_uninstall();
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
# 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.esp32c3
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.usb_serial_jtag
|
||||
@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_usj_vfs_release(dut: Dut, test_message: list) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests')
|
||||
dut.write('\"test select read, write and timeout\"')
|
||||
dut.expect_exact('select timed out', timeout=2)
|
||||
dut.write(test_message)
|
||||
dut.expect_exact(test_message, timeout=2)
|
||||
dut.expect(r'\d{1} Tests 0 Failures 0 Ignored', timeout=10)
|
@@ -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_SERIAL_JTAG=y
|
Reference in New Issue
Block a user