Merge branch 'backport/openthread_uart_api_refactor' into 'release/v5.1'

feat(openthread): Host connection logic refactor(Backport V5.1)

See merge request espressif/esp-idf!26486
This commit is contained in:
Jiang Jiang Jian 2023-10-18 14:44:11 +08:00
commit 6cc6ece701
11 changed files with 170 additions and 47 deletions

View File

@ -13,6 +13,21 @@ menu "OpenThread"
help
Select this option to enable dynamic log level control for OpenThread
choice OPENTHREAD_CONSOLE_TYPE
prompt "OpenThread console type"
depends on OPENTHREAD_ENABLED
default OPENTHREAD_CONSOLE_TYPE_UART
help
Select OpenThread console type
config OPENTHREAD_CONSOLE_TYPE_UART
depends on ESP_CONSOLE_UART_DEFAULT || ESP_CONSOLE_UART_CUSTOM
bool "OpenThread console type UART"
config OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
depends on ESP_CONSOLE_USB_SERIAL_JTAG || ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG
bool "OpenThread console type USB Serial/JTAG Controller"
endchoice #OPENTHREAD_CONSOLE_TYPE
choice OPENTHREAD_LOG_LEVEL
prompt "OpenThread log verbosity"
depends on OPENTHREAD_ENABLED && !OPENTHREAD_LOG_LEVEL_DYNAMIC

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -15,6 +15,7 @@
#include "driver/spi_master.h"
#include "driver/spi_slave.h"
#include "driver/uart.h"
#include "driver/usb_serial_jtag.h"
#include "hal/gpio_types.h"
#include "hal/uart_types.h"
#include "openthread/thread.h"
@ -112,8 +113,9 @@ typedef struct {
*/
typedef enum {
RADIO_MODE_NATIVE = 0x0, /*!< Use the native 15.4 radio */
RADIO_MODE_UART_RCP = 0x1, /*!< UART connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_SPI_RCP = 0x2, /*!< SPI connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_UART_RCP, /*!< UART connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_SPI_RCP, /*!< SPI connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_MAX, /*!< Using for parameter check */
} esp_openthread_radio_mode_t;
/**
@ -122,9 +124,11 @@ typedef enum {
*/
typedef enum {
HOST_CONNECTION_MODE_NONE = 0x0, /*!< Disable host connection */
HOST_CONNECTION_MODE_CLI_UART = 0x1, /*!< CLI UART connection to the host */
HOST_CONNECTION_MODE_RCP_UART = 0x2, /*!< RCP UART connection to the host */
HOST_CONNECTION_MODE_RCP_SPI = 0x3, /*!< RCP SPI connection to the host */
HOST_CONNECTION_MODE_CLI_UART, /*!< CLI UART connection to the host */
HOST_CONNECTION_MODE_CLI_USB, /*!< CLI USB connection to the host */
HOST_CONNECTION_MODE_RCP_UART, /*!< RCP UART connection to the host */
HOST_CONNECTION_MODE_RCP_SPI, /*!< RCP SPI connection to the host */
HOST_CONNECTION_MODE_MAX, /*!< Using for parameter check */
} esp_openthread_host_connection_mode_t;
/**
@ -147,6 +151,7 @@ typedef struct {
esp_openthread_host_connection_mode_t host_connection_mode; /*!< The host connection mode */
union {
esp_openthread_uart_config_t host_uart_config; /*!< The uart configuration to host */
usb_serial_jtag_driver_config_t host_usb_config; /*!< The usb configuration to host */
esp_openthread_spi_slave_config_t spi_slave_config; /*!< The spi configuration to host */
};
} esp_openthread_host_connection_config_t;

View File

@ -18,7 +18,7 @@ extern "C" {
* @brief This function initializes the OpenThread spinel SPI slave.
*
*/
esp_err_t esp_openthread_spi_slave_init(const esp_openthread_platform_config_t *config);
esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config);
/**
* @brief This function deinitializes the OpenThread spinel SPI slave.

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -29,16 +29,40 @@ extern "C" {
esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *config);
/**
* @brief Initializes the uart for OpenThread host connection.
* @brief Initializes the console UART for OpenThread host connection.
*
* @param[in] config The uart configuration.
* @param[in] config The platform configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_uart_init(const esp_openthread_platform_config_t *config);
esp_err_t esp_openthread_host_cli_uart_init(const esp_openthread_platform_config_t *config);
/**
* @brief Initializes the console USB JTAG for OpenThread host connection.
*
* @param[in] config The platform configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_host_cli_usb_init(const esp_openthread_platform_config_t *config);
/**
* @brief Initializes the RCP UART for OpenThread host connection.
*
* @param[in] config The platform configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_host_rcp_uart_init(const esp_openthread_platform_config_t *config);
/**
* @brief Deintializes the uart for OpenThread host connection.

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -84,16 +84,46 @@ void esp_openthread_platform_workflow_unregister(const char *name)
}
}
static inline esp_openthread_host_connection_mode_t get_host_connection_mode(void)
{
return s_platform_config.host_config.host_connection_mode;
}
static esp_err_t esp_openthread_host_interface_init(const esp_openthread_platform_config_t *config)
{
esp_openthread_host_connection_mode_t host_mode = get_host_connection_mode();
switch (host_mode) {
case HOST_CONNECTION_MODE_RCP_SPI:
ESP_RETURN_ON_ERROR(esp_openthread_host_rcp_spi_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_rcp_spi_init failed");
break;
case HOST_CONNECTION_MODE_RCP_UART:
ESP_RETURN_ON_ERROR(esp_openthread_host_rcp_uart_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_rcp_uart_init failed");
break;
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
case HOST_CONNECTION_MODE_CLI_UART:
ESP_RETURN_ON_ERROR(esp_openthread_host_cli_uart_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_cli_uart_init failed");
break;
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
case HOST_CONNECTION_MODE_CLI_USB:
ESP_RETURN_ON_ERROR(esp_openthread_host_cli_usb_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_cli_usb_init failed");
break;
#endif
default:
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *config)
{
ESP_RETURN_ON_FALSE(config->radio_config.radio_mode == RADIO_MODE_NATIVE ||
config->radio_config.radio_mode == RADIO_MODE_UART_RCP ||
config->radio_config.radio_mode == RADIO_MODE_SPI_RCP,
ESP_RETURN_ON_FALSE(config->radio_config.radio_mode < RADIO_MODE_MAX,
ESP_ERR_INVALID_ARG, OT_PLAT_LOG_TAG, "Radio mode not supported");
ESP_RETURN_ON_FALSE(config->host_config.host_connection_mode == HOST_CONNECTION_MODE_NONE ||
config->host_config.host_connection_mode == HOST_CONNECTION_MODE_CLI_UART ||
config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_UART ||
config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_SPI,
ESP_RETURN_ON_FALSE(config->host_config.host_connection_mode < HOST_CONNECTION_MODE_MAX,
ESP_ERR_INVALID_ARG, OT_PLAT_LOG_TAG, "Host connection mode not supported");
ESP_RETURN_ON_FALSE(!s_openthread_platform_initialized, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG,
"OpenThread platform already initialized");
@ -107,13 +137,8 @@ esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *c
esp_openthread_set_storage_name(config->port_config.storage_partition_name);
if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_SPI) {
ESP_GOTO_ON_ERROR(esp_openthread_spi_slave_init(config), exit, OT_PLAT_LOG_TAG,
"esp_openthread_spi_slave_init failed");
}else if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_CLI_UART ||
config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_UART) {
ESP_GOTO_ON_ERROR(esp_openthread_uart_init(config), exit, OT_PLAT_LOG_TAG, "esp_openthread_uart_init failed");
}
ESP_GOTO_ON_ERROR(esp_openthread_host_interface_init(config), exit, OT_PLAT_LOG_TAG,
"esp_openthread_host_interface_init failed");
ESP_GOTO_ON_ERROR(esp_openthread_task_queue_init(config), exit, OT_PLAT_LOG_TAG,
"esp_openthread_task_queue_init failed");
@ -140,10 +165,10 @@ esp_err_t esp_openthread_platform_deinit(void)
esp_openthread_task_queue_deinit();
esp_openthread_radio_deinit();
if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_SPI){
if (get_host_connection_mode() == HOST_CONNECTION_MODE_RCP_SPI){
esp_openthread_spi_slave_deinit();
}else if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_CLI_UART ||
s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_UART) {
} else if (get_host_connection_mode() == HOST_CONNECTION_MODE_CLI_UART ||
get_host_connection_mode() == HOST_CONNECTION_MODE_RCP_UART) {
esp_openthread_uart_deinit();
}

View File

@ -70,7 +70,7 @@ static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans
trans = NULL;
}
esp_err_t esp_openthread_spi_slave_init(const esp_openthread_platform_config_t *config)
esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config)
{
s_spi_config = config->host_config.spi_slave_config;
gpio_config_t io_conf = {

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -21,6 +21,8 @@
#include "common/logging.hpp"
#include "driver/uart.h"
#include "utils/uart.h"
#include "esp_vfs_usb_serial_jtag.h"
#include "driver/usb_serial_jtag.h"
static int s_uart_port;
static int s_uart_fd;
@ -70,28 +72,54 @@ esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *conf
return ESP_OK;
}
esp_err_t esp_openthread_uart_init(const esp_openthread_platform_config_t *config)
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
esp_err_t esp_openthread_host_cli_usb_init(const esp_openthread_platform_config_t *config)
{
char uart_path[16];
esp_err_t ret = ESP_OK;
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
/* Enable non-blocking mode on stdin and stdout */
fcntl(fileno(stdout), F_SETFL, O_NONBLOCK);
fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
ret = usb_serial_jtag_driver_install((usb_serial_jtag_driver_config_t *)&config->host_config.host_usb_config);
esp_vfs_usb_serial_jtag_use_driver();
esp_vfs_dev_uart_register();
return ret;
}
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
esp_err_t esp_openthread_host_cli_uart_init(const esp_openthread_platform_config_t *config)
{
ESP_RETURN_ON_ERROR(esp_openthread_uart_init_port(&config->host_config.host_uart_config), OT_PLAT_LOG_TAG,
"esp_openthread_uart_init_port failed");
return ESP_OK;
}
#endif
esp_err_t esp_openthread_host_rcp_uart_init(const esp_openthread_platform_config_t *config)
{
esp_err_t ret = ESP_OK;
// Install UART driver for interrupt-driven reads and writes.
ESP_RETURN_ON_FALSE(config->host_config.host_connection_mode == HOST_CONNECTION_MODE_CLI_UART ||
config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_UART,
ESP_FAIL, OT_PLAT_LOG_TAG, "unsupport host connect mode");
char uart_path[16];
s_uart_port = config->host_config.host_uart_config.port;
ESP_RETURN_ON_ERROR(esp_openthread_uart_init_port(&config->host_config.host_uart_config), OT_PLAT_LOG_TAG,
"esp_openthread_uart_init_port failed");
if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_UART) {
esp_vfs_dev_uart_port_set_rx_line_endings(s_uart_port, ESP_LINE_ENDINGS_LF);
esp_vfs_dev_uart_port_set_tx_line_endings(s_uart_port, ESP_LINE_ENDINGS_LF);
snprintf(uart_path, sizeof(uart_path), "/dev/uart/%d", s_uart_port);
s_uart_fd = open(uart_path, O_RDWR | O_NONBLOCK);
ESP_RETURN_ON_FALSE(s_uart_fd >= 0, ESP_FAIL, OT_PLAT_LOG_TAG, "open uart_path failed");
ret = esp_openthread_platform_workflow_register(&esp_openthread_uart_update, &esp_openthread_uart_process,
uart_workflow);
}
esp_vfs_dev_uart_port_set_rx_line_endings(s_uart_port, ESP_LINE_ENDINGS_LF);
esp_vfs_dev_uart_port_set_tx_line_endings(s_uart_port, ESP_LINE_ENDINGS_LF);
snprintf(uart_path, sizeof(uart_path), "/dev/uart/%d", s_uart_port);
s_uart_fd = open(uart_path, O_RDWR | O_NONBLOCK);
ESP_RETURN_ON_FALSE(s_uart_fd >= 0, ESP_FAIL, OT_PLAT_LOG_TAG, "open uart_path failed");
ret = esp_openthread_platform_workflow_register(&esp_openthread_uart_update, &esp_openthread_uart_process,
uart_workflow);
return ret;
}

View File

@ -40,6 +40,12 @@ Similar to the previous Wi-Fi based Thread Border Route setup, but a device with
```
idf.py menuconfig
```
OpenThread Command Line is enabled with UART as the default interface. Additionally, USB JTAG is also supported and can be activated through the menuconfig:
```
Component config → ESP System Settings → Channel for console output → USB Serial/JTAG Controller
```
In order to run the example on single SoC which supports both Wi-Fi and Thread, the option `CONFIG_ESP_COEX_SW_COEXIST_ENABLE` and option `CONFIG_OPENTHREAD_RADIO_NATIVE` should be enabled. The two options are enabled by default for ESP32-C6 target.
Two ways are provided to setup the Thread Border Router in this example:

View File

@ -74,6 +74,7 @@
#define HOST_BAUD_RATE 115200
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
@ -93,6 +94,13 @@
.tx_pin = UART_PIN_NO_CHANGE, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
}
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \

View File

@ -17,7 +17,11 @@ To run this example, a board with IEEE 802.15.4 module (for example ESP32-H2) is
idf.py menuconfig
```
The example can run with the default configuration.
The example can run with the default configuration. OpenThread Command Line is enabled with UART as the default interface. Additionally, USB JTAG is also supported and can be activated through the menuconfig:
```
Component config → ESP System Settings → Channel for console output → USB Serial/JTAG Controller
```
### Build, Flash, and Run

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
@ -44,6 +44,7 @@
}
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
@ -63,6 +64,13 @@
.tx_pin = UART_PIN_NO_CHANGE, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
}
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \