OpenThread: add OpenThread and porting

* Adds the OpenThread submodule.
* Adds porting on ESP32.
* Adds the OpenThread cli example.
This commit is contained in:
Guo Jia Cheng 2021-04-02 14:49:49 +08:00 committed by Chen Shu
parent 793771e744
commit 7c38989309
35 changed files with 2593 additions and 0 deletions

View File

@ -116,6 +116,7 @@
/components/nghttp/ @esp-idf-codeowners/app-utilities
/components/nvs_flash/ @esp-idf-codeowners/storage
/components/openssl/ @esp-idf-codeowners/network
/components/openthread/ @esp-idf-codeowners/ieee802154
/components/partition_table/ @esp-idf-codeowners/system
/components/perfmon/ @esp-idf-codeowners/tools
/components/protobuf-c/ @esp-idf-codeowners/app-utilities
@ -147,6 +148,7 @@
/examples/ethernet/ @esp-idf-codeowners/network
/examples/get-started/ @esp-idf-codeowners/system
/examples/mesh/ @esp-idf-codeowners/wifi
/examples/openthread/ @esp-idf-codeowners/ieee802154
/examples/peripherals/ @esp-idf-codeowners/peripherals
/examples/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
/examples/provisioning/ @esp-idf-codeowners/app-utilities

4
.gitmodules vendored
View File

@ -90,3 +90,7 @@
[submodule "components/cmock/CMock"]
path = components/cmock/CMock
url = ../../ThrowTheSwitch/CMock.git
[submodule "components/openthread/openthread"]
path = components/openthread/openthread
url = ../../espressif/openthread.git

View File

@ -0,0 +1,67 @@
if(CONFIG_OPENTHREAD_ENABLED)
set(public_include_dirs
"include"
"openthread/include")
set(private_include_dirs
"openthread/include/openthread"
"openthread/src"
"openthread/src/core"
"openthread/src/lib/hdlc"
"openthread/src/lib/spinel"
"openthread/src/ncp"
"private_include")
set(src_dirs
"openthread/src/cli"
"openthread/src/core/api"
"openthread/src/core/coap"
"openthread/src/core/common"
"openthread/src/core/crypto"
"openthread/src/core/diags"
"openthread/src/core/mac"
"openthread/src/core/meshcop"
"openthread/src/core/net"
"openthread/src/core/radio"
"openthread/src/core/thread"
"openthread/src/core/utils"
"openthread/src/lib/platform"
"openthread/src/lib/hdlc"
"openthread/src/lib/spinel"
"port")
set(exclude_srcs "openthread/src/core/common/extension_example.cpp")
if(CONFIG_OPENTHREAD_FTD)
set(device_type "OPENTHREAD_FTD=1")
elseif(CONFIG_OPENTHREAD_MTD)
set(device_type "OPENTHREAD_MTD=1")
elseif(CONFIG_OPENTHREAD_RADIO)
set(device_type "OPENTHREAD_RADIO=1")
endif()
endif()
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE IDF_VERSION_FOR_OPENTHREAD_PACKAGE OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/openthread
OUTPUT_VARIABLE OPENTHREAD_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE
)
idf_component_register(SRC_DIRS "${src_dirs}"
EXCLUDE_SRCS "${exclude_srcs}"
INCLUDE_DIRS "${public_include_dirs}"
PRIV_INCLUDE_DIRS "${private_include_dirs}"
REQUIRES mbedtls spi_flash)
if(CONFIG_OPENTHREAD_ENABLED)
target_compile_definitions(${COMPONENT_LIB} PRIVATE
"OPENTHREAD_CONFIG_FILE=\"openthread-core-esp32x-config.h\""
"PACKAGE_VERSION=\"${IDF_VERSION_FOR_OPENTHREAD_PACKAGE}-${OPENTHREAD_VERSION}\""
"${device_type}")
endif()

View File

@ -0,0 +1,68 @@
menu "OpenThread"
config OPENTHREAD_ENABLED
bool "OpenThread"
default n
help
Select this option to enable OpenThread and show the submenu with OpenThread configuration choices.
choice OPENTHREAD_DEVICE_TYPE
prompt "Config the Thread device type"
depends on OPENTHREAD_ENABLED
default OPENTHREAD_FTD
help
OpenThread can be configured to different device types (FTD, MTD, Radio)
config OPENTHREAD_FTD
bool "Full Thread Device"
help
Select this to enable Full Thread Device which can act as router and leader in a Thread network.
config OPENTHREAD_MTD
bool "Minimal Thread Device"
help
Select this to enable Minimal Thread Device which can only act as end device in a Thread network.
This will reduce the code size of the OpenThread stack.
config OPENTHREAD_RADIO
bool "Radio Only Device"
help
Select this to enable Radio Only Device which cannot can only forward 15.4 packets to the host.
The OpenThread stack will be run on the host and OpenThread will have minimal footprint on the
radio only device.
endchoice
config OPENTHREAD_DIAG
bool "Enable diag"
depends on OPENTHREAD_ENABLED
default y
help
Select this option to enable Diag in OpenThread. This will enable diag mode and a series of diag commands
in the OpenThread command line. These commands allow users to manipulate low-level features of the storage
and 15.4 radio.
config OPENTHREAD_COMMISSIONER
bool "Enable Commissioner"
depends on OPENTHREAD_ENABLED
default n
help
Select this option to enable commissioner in OpenThread. This will enable the device to act as a
commissioner in the Thread network. A commissioner checks the pre-shared key from a joining device with
the Thread commissioning protocol and shares the network parameter with the joining device upon success.
config OPENTHREAD_JOINER
bool "Enable Joiner"
depends on OPENTHREAD_ENABLED
default n
help
Select this option to enable Joiner in OpenThread. This allows a device to join the Thread network with a
pre-shared key using the Thread commissioning protocol.
config OPENTHREAD_PARTITION_NAME
string "The partition for OpenThread to store its network data"
depends on OPENTHREAD_ENABLED
default "ot_storage"
help
The storage size should be at least 8192 bytes.
endmenu

View File

@ -0,0 +1,59 @@
ifdef CONFIG_OPENTHREAD_ENABLED
COMPONENT_ADD_INCLUDEDIRS := \
openthread/include \
include
COMPONENT_PRIV_INCLUDEDIRS := \
openthread/src \
openthread/src/core \
openthread/src/lib/hdlc \
openthread/src/lib/spinel \
openthread/src/ncp \
private_include
COMPONENT_SRCDIRS := \
openthread/src/cli \
openthread/src/core \
openthread/src/core/api \
openthread/src/core/coap \
openthread/src/core/common \
openthread/src/core/crypto \
openthread/src/core/diags \
openthread/src/core/mac \
openthread/src/core/meshcop \
openthread/src/core/net \
openthread/src/core/radio \
openthread/src/core/thread \
openthread/src/core/utils \
openthread/src/lib/hdlc \
openthread/src/lib/platform \
openthread/src/lib/spinel \
port
COMPONENT_OBJEXCLUDE := \
openthread/src/core/common/extension_example.o
IDF_VERSION_FOR_OPENTHREAD_PACKAGE := $(shell git -C $(COMPONENT_PATH) rev-parse --short HEAD)
OPENTHREAD_VERSION := $(shell git -C $(COMPONENT_PATH)/openthread rev-parse --short HEAD)
OPENTHREAD_PACKAGE_VERSION := $(IDF_VERSION_FOR_OPENTHREAD_PACKAGE)-$(OPENTHREAD_VERSION)
COMMON_FLAGS := \
-DOPENTHREAD_CONFIG_FILE=\<openthread-core-esp32x-config.h\> \
-DPACKAGE_VERSION=\"OPENTHREAD_PACKAGE_VERSION\"
ifdef CONFIG_OPENTHREAD_FTD
COMMON_FLAGS += -DOPENTHREAD_FTD=1
else ifdef CONFIG_OPENTHREAD_MTD
COMMON_FLAGS += -DOPENTHREAD_MTD=1
else ifdef CONFIG_OPENTHREAD_RADIO
COMMON_FLAGS += -DOPENTHREAD_RADIO=1
endif
CFLAGS += $(COMMON_FLAGS)
CXXFLAGS += $(COMMON_FLAGS)
CPPFLAGS += $(COMMON_FLAGS)
endif

View File

@ -0,0 +1,97 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "esp_err.h"
#include "esp_openthread_types.h"
#include "openthread/error.h"
#include "openthread/instance.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes the platform-specific support for the OpenThread stack.
*
* @note This function is not called by and will not call the OpenThread library.
* The user needs to call otInstanceInitSingle to intialize the OpenThread
* stack after calling this fucntion.
*
* @param[in] init_config The initialization configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_ERR_INVALID_ARG if radio or host connection mode not supported
* - ESP_ERR_INVALID_STATE if already initialized
*
*/
esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *init_config);
/**
* This function performs all platform-specific deinitialization for OpenThread's drivers.
*
* @note This function is not called by the OpenThread library. Instead, the user should
* call this function when deinitialization of OpenThread's drivers is most appropriate.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if not initialized
*
*/
esp_err_t esp_openthread_platform_deinit(void);
/**
* @brief This function acquires the underlying OpenThread instance.
*
* @note This function can be called on other tasks without lock.
*
* @return The OpenThread instance pointer
*
*/
otInstance *esp_openthread_get_instance(void);
/**
* @brief This function updates the platform fds and timeouts
*
* @note This function will not update the OpenThread core stack pending events.
* The users need to call `otTaskletsArePending` to check whether there being
* pending OpenThread tasks.
*
* @param[inout] mainloop The main loop context.
*
*/
void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop);
/**
* @brief This function performs the OpenThread related platform process (radio, uart, alarm etc.)
*
* @note This function will call the OpenThread core stack process functions.
* The users need to call `otTaskletsProcess` by self.
*
* @param[in] instance The OpenThread instance.
* @param[in] mainloop The main loop context.
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*
*/
esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop);
#ifdef __cplusplus
} // end of extern "C"
#endif

View File

@ -0,0 +1,67 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief This function initializes the OpenThread API lock.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_ERR_INVALID_STATE if already initialized
*
*/
esp_err_t esp_openthread_lock_init(void);
/**
* This function deinitializes the OpenThread API lock.
*
*/
void esp_openthread_lock_deinit(void);
/**
* @brief This functions acquires the OpenThread API lock.
*
* @note Every OT APIs that takes an otInstance argument MUST be protected with this API lock
* except that the call site is in OT callbacks.
*
* @param[in] block_ticks The maxinum number of RTOS ticks to wait for the lock.
*
* @return
* - True on lock acquired
* - False on failing to acquire the lock with the timeout.
*
*/
bool esp_openthread_lock_acquire(TickType_t block_ticks);
/**
* @brief This function releases the OpenThread API lock.
*
*/
void esp_openthread_lock_release(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,93 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "hal/uart_types.h"
#include "sys/select.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This structure represents a context for a select() based mainloop.
*
*/
typedef struct {
fd_set read_fds; /*!< The read file descriptors.*/
fd_set write_fds; /*!< The write file descriptors.*/
fd_set error_fds; /*!< The error file descriptors.*/
int max_fd; /*!< The max file descriptor.*/
struct timeval timeout; /*!< The timeout.*/
} esp_openthread_mainloop_context_t;
/**
* @brief The uart port config for OpenThread.
*
*/
typedef struct {
uart_port_t port; /*!< UART port number*/
uart_config_t uart_config; /*!< UART configuration, see uart_config_t docs*/
int rx_pin; /*!< UART RX pin */
int tx_pin; /*!< UART TX pin */
} esp_openthread_uart_config_t;
/**
* @brief The radio mode of OpenThread.
*
*/
typedef enum {
RADIO_MODE_UART_RCP = 0x0, /*!< UART connection to a 15.4 capable radio co-processor(RCP)*/
} esp_openthread_radio_mode_t;
/**
* @brief How OpenThread connects to the host.
*
*/
typedef enum {
HOST_CONNECTION_MODE_NONE = 0x0, /*!< Disable host connection*/
HOST_CONNECTION_MODE_UART = 0x1, /*!< UART connection to the host*/
} esp_openthread_host_connection_mode_t;
/**
* @brief The OpenThread radio configuration
*
*/
typedef struct {
esp_openthread_radio_mode_t radio_mode; /*!< The radio mode*/
esp_openthread_uart_config_t radio_uart_config; /*!< The uart configuration to RCP*/
} esp_openthread_radio_config_t;
/**
* @brief The OpenThread host connection configuration
*
*/
typedef struct {
esp_openthread_host_connection_mode_t host_connection_mode; /*!< The host connection mode*/
esp_openthread_uart_config_t host_uart_config; /*!< The uart configuration to host*/
} esp_openthread_host_connection_config_t;
/**
* @brief The OpenThread platform configuration
*
*/
typedef struct {
esp_openthread_radio_config_t radio_config; /*!< The radio configuration*/
esp_openthread_host_connection_config_t host_config; /*!< The host connection configuration*/
} esp_openthread_platform_config_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,281 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "sdkconfig.h"
/**
* @def OPENTHREAD_CONFIG_PLATFORM_INFO
*
* The platform-specific string to insert into the OpenThread version string.
*
*/
#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_IDF_TARGET
/**
* @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT
*
* The assert is managed by platform defined logic when this flag is set.
*
*/
#define OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT 1
/**
* @def OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
*
* Define to 1 to enable otPlatFlash* APIs to support non-volatile storage.
*
* When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs.
*
*/
#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_LOG_OUTPUT
*
* The ESP-IDF platform provides an otPlatLog() function.
*/
#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
/**
* @def OPENTHREAD_CONFIG_LOG_LEVEL
*
* The log level (used at compile time). If `OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE` is set, this defines the most
* verbose log level possible. See `OPENTHREAD_CONFIG_LOG_LEVEL_INIT` to set the initial log level.
*
*/
#ifndef OPENTHREAD_CONFIG_LOG_LEVEL
#if CONFIG_LOG_DEFAULT_LEVEL_NONE
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_NONE
#elif CONFIG_LOG_DEFAULT_LEVEL_ERROR
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_CRIT
#elif CONFIG_LOG_DEFAULT_LEVEL_WARN
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_WARN
#elif CONFIG_LOG_DEFAULT_LEVEL_INFO
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO
#elif CONFIG_LOG_DEFAULT_LEVEL_DEBUG
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_DEBG
#elif CONFIG_LOG_DEFAULT_LEVEL_VERBOSE
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_DEBG
#endif
#endif
#define OPENTHREAD_CONFIG_LOG_API 1
#define OPENTHREAD_CONFIG_LOG_ARP 1
#define OPENTHREAD_CONFIG_LOG_BBR 1
#define OPENTHREAD_CONFIG_LOG_CLI 1
#define OPENTHREAD_CONFIG_LOG_COAP 1
#define OPENTHREAD_CONFIG_LOG_DUA 1
#define OPENTHREAD_CONFIG_LOG_ICMP 1
#define OPENTHREAD_CONFIG_LOG_IP6 1
#define OPENTHREAD_CONFIG_LOG_MAC 1
#define OPENTHREAD_CONFIG_LOG_MEM 1
#define OPENTHREAD_CONFIG_LOG_MESHCOP 1
#define OPENTHREAD_CONFIG_LOG_MLE 1
#define OPENTHREAD_CONFIG_LOG_MLR 1
#define OPENTHREAD_CONFIG_LOG_NETDATA 1
#define OPENTHREAD_CONFIG_LOG_NETDIAG 1
#define OPENTHREAD_CONFIG_LOG_PKT_DUMP 1
#define OPENTHREAD_CONFIG_LOG_PLATFORM 1
/**
* @def OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS
*
* The number of message buffers in buffer pool
*/
#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 50
/**
* @def OPENTHREAD_CONFIG_COAP_API_ENABLE
*
* Define to 1 to enable the CoAP API.
*
*/
#define OPENTHREAD_CONFIG_COAP_API_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
*
* Define to 1 to enable Border Router support.
*
*/
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
*
* Define to 1 to enable Thread Test Harness reference device support.
*
*/
#define OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
*
* Define to 1 to enable Child Supervision support.
*
*/
#ifndef OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE
*
* Define to 1 to enable DHCPv6 Client support.
*
*/
#ifndef OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE
#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
*
* Define to 1 to enable DHCPv6 Server support.
*
*/
#ifndef OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
*
* Define to 1 to enable DNS Client support.
*
*/
#ifndef OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_NCP_SPI_ENABLE
*
* Define to 1 to enable NCP SPI support.
*
*/
#define OPENTHREAD_CONFIG_NCP_SPI_ENABLE 0
/**
* @def OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
*
* Define to 1 to enable NCP Spinel Encrypter.
*
*/
#define OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER 0
/**
* @def OPENTHREAD_CONFIG_NCP_UART_ENABLE
*
* Define to 1 to enable NCP UART support.
*
*/
#define OPENTHREAD_CONFIG_NCP_UART_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
*
* Define to 1 to support injecting Service entries into the Thread Network Data.
*
*/
#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 1
/**
* @def PACKAGE_NAME
*
* Define to the full name of this package.
*
*/
#define PACKAGE_NAME "openthread-esp32"
/**
* @def PACKAGE_STRING
*
* Define to the full name and version of this package.
*
*/
#define PACKAGE_STRING (PACKAGE_NAME " - " PACKAGE_VERSION)
/**
* @def OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS
*
* Define as 1 to enable bultin-mbedtls.
*
* Note that the OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS determines whether to use bultin-mbedtls as well as
* whether to manage mbedTLS internally, such as memory allocation and debug.
*
*/
#define OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS 0
/**
* @def OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
*
* Define as 1 to enable support for adding of auto-configured SLAAC addresses by OpenThread.
*
*/
#define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1
/**
* @def OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS
*
* The maximum number of state-changed callback handlers (set using `otSetStateChangedCallback()`).
*
*/
#define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 3
/**
* @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE
*
* Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when
* `RadioSpinel` platform is used.
*
*/
#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE 1024
/**
* @def OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN
*
* The max length of the OpenThread dtls content buffer.
*
*/
#ifndef OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN
#define OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN 768
#endif
/**
* The configurable definitions via Kconfig
*/
#if CONFIG_OPENTHREAD_COMMISSIONER
#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 1
#endif
#if CONFIG_OPENTHREAD_JOINER
#define OPENTHREAD_CONFIG_JOINER_ENABLE 1
#endif
#if CONFIG_OPENTHREAD_DIAG
#define OPENTHREAD_CONFIG_DIAG_ENABLE 1
#endif
#if CONFIG_OPENTHREAD_FTD
#define OPENTHREAD_FTD 1
#elif CONFIG_OPENTHREAD_MTD
#define OPENTHREAD_MTD 1
#elif CONFIG_OPENTHREAD_RADIO
#define OPENTHREAD_RADIO 1
#endif

@ -0,0 +1 @@
Subproject commit 93b6fea3aa10e26f17ad2b877f002ca2cd81b745

View File

@ -0,0 +1,106 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_openthread_alarm.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_radio_uart.h"
#include "esp_openthread_types.h"
#include "esp_openthread_uart.h"
#include "common/code_utils.hpp"
#include "common/logging.hpp"
#include "core/common/instance.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "openthread/cli.h"
#include "openthread/instance.h"
#include "openthread/platform/alarm-milli.h"
#include "openthread/platform/time.h"
#include "openthread/tasklet.h"
static esp_openthread_platform_config_t s_platform_config;
static bool s_openthread_platform_initialized = false;
esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *config)
{
if (config->radio_config.radio_mode != RADIO_MODE_UART_RCP) {
otLogCritPlat("Radio mode not supported");
return ESP_ERR_INVALID_ARG;
}
if (config->host_config.host_connection_mode != HOST_CONNECTION_MODE_NONE &&
config->host_config.host_connection_mode != HOST_CONNECTION_MODE_UART) {
otLogCritPlat("Host connection mode not supported");
return ESP_ERR_INVALID_ARG;
}
if (s_openthread_platform_initialized) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t error = ESP_OK;
s_platform_config = *config;
SuccessOrExit(error = esp_openthread_lock_init());
if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) {
SuccessOrExit(error = esp_openthread_uart_init(config));
}
SuccessOrExit(error = esp_openthread_radio_init(config));
exit:
if (error != ESP_OK) {
esp_openthread_platform_deinit();
}
return error;
}
otInstance *esp_openthread_get_instance(void)
{
return &ot::Instance::Get();
}
esp_err_t esp_openthread_platform_deinit(void)
{
if (!s_openthread_platform_initialized) {
return ESP_ERR_INVALID_STATE;
}
esp_openthread_radio_deinit();
if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) {
esp_openthread_uart_deinit();
}
esp_openthread_lock_deinit();
return ESP_OK;
}
void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop)
{
esp_openthread_alarm_update(mainloop);
if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) {
esp_openthread_uart_update(mainloop);
}
esp_openthread_radio_update(mainloop);
}
esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop)
{
if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) {
ESP_RETURN_ON_ERROR(esp_openthread_uart_process(), OT_PLAT_LOG_TAG, "esp_openthread_uart_process failed");
}
esp_openthread_radio_process(instance, mainloop);
esp_openthread_alarm_process(instance);
return ESP_OK;
}

View File

@ -0,0 +1,103 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread_alarm.h"
#include <stdbool.h>
#include <stdint.h>
#include <sys/time.h>
#include "esp_log.h"
#include "esp_openthread_common_macro.h"
#include "esp_timer.h"
#include "common/logging.hpp"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "openthread/platform/alarm-milli.h"
#include "openthread/platform/diag.h"
#include "openthread/platform/time.h"
static uint64_t s_alarm_t0 = 0;
static uint64_t s_alarm_dt = 0;
static bool s_is_running = false;
uint64_t otPlatTimeGet(void)
{
struct timeval tv_now;
int err = gettimeofday(&tv_now, NULL);
assert(err == 0);
return (uint64_t)tv_now.tv_sec * US_PER_S + tv_now.tv_usec;
}
void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
{
OT_UNUSED_VARIABLE(aInstance);
s_alarm_t0 = aT0;
s_alarm_dt = aDt;
s_is_running = true;
otLogDebgPlat("alarm start running, t0=%llu, dt=%llu", s_alarm_t0, s_alarm_dt);
}
void otPlatAlarmMilliStop(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
s_is_running = false;
}
uint32_t otPlatAlarmMilliGetNow(void)
{
return esp_timer_get_time() / US_PER_MS;
}
void esp_openthread_alarm_update(esp_openthread_mainloop_context_t *mainloop)
{
struct timeval *timeout = &mainloop->timeout;
uint32_t now = otPlatAlarmMilliGetNow();
if (!s_is_running) {
timeout->tv_sec = INT32_MAX;
timeout->tv_usec = 0;
} else if (s_alarm_t0 + s_alarm_dt > now) {
uint64_t remaining = s_alarm_dt + s_alarm_t0 - now;
timeout->tv_sec = remaining / MS_PER_S;
timeout->tv_usec = (remaining % MS_PER_S) * US_PER_MS;
} else {
timeout->tv_sec = 0;
timeout->tv_usec = 0;
}
}
void esp_openthread_alarm_process(otInstance *aInstance)
{
if (s_is_running && s_alarm_t0 + s_alarm_dt <= otPlatAlarmMilliGetNow()) {
s_is_running = false;
#if OPENTHREAD_CONFIG_DIAG_ENABLE
if (otPlatDiagModeGet()) {
otPlatDiagAlarmFired(aInstance);
} else
#endif
{
otPlatAlarmMilliFired(aInstance);
}
otLogDebgPlat("alarm fired");
}
}

View File

@ -0,0 +1,70 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 Licens
#include "esp_partition.h"
#include "esp_spi_flash.h"
#include "openthread/instance.h"
#include "openthread/platform/flash.h"
#include "openthread/platform/settings.h"
#define ESP_OT_FLASH_PAGE_NUM 2
#define ESP_OT_FLASH_PAGE_SIZE 4096
static const esp_partition_t *s_ot_partition = NULL;
void otPlatFlashInit(otInstance *instance)
{
s_ot_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, CONFIG_OPENTHREAD_PARTITION_NAME);
assert(s_ot_partition != NULL);
assert(s_ot_partition->size >= otPlatFlashGetSwapSize(instance));
}
uint32_t otPlatFlashGetSwapSize(otInstance *instance)
{
return ESP_OT_FLASH_PAGE_SIZE;
}
void otPlatFlashErase(otInstance *instance, uint8_t index)
{
uint32_t address = ESP_OT_FLASH_PAGE_SIZE * (index != 0);
uint32_t size = ESP_OT_FLASH_PAGE_SIZE;
esp_err_t err = ESP_OK;
err = esp_partition_erase_range(s_ot_partition, address, size);
assert(err == ESP_OK);
}
void otPlatFlashRead(otInstance *instance, uint8_t index, uint32_t offset, void *data, uint32_t size)
{
esp_err_t err = ESP_OK;
offset += ESP_OT_FLASH_PAGE_SIZE * (index != 0);
err = esp_partition_read(s_ot_partition, offset, data, size);
assert(err == ESP_OK);
}
void otPlatFlashWrite(otInstance *instance, uint8_t index, uint32_t offset, const void *data, uint32_t size)
{
esp_err_t err = ESP_OK;
offset += ESP_OT_FLASH_PAGE_SIZE * (index != 0);
err = esp_partition_write(s_ot_partition, offset, data, size);
assert(err == ESP_OK);
}

View File

@ -0,0 +1,52 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread_lock.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
static SemaphoreHandle_t s_openthread_mutex = NULL;
bool esp_openthread_lock_acquire(TickType_t block_ticks)
{
BaseType_t ret = xSemaphoreTake(s_openthread_mutex, block_ticks);
return (ret == pdTRUE);
}
void esp_openthread_lock_release(void)
{
xSemaphoreGive(s_openthread_mutex);
}
esp_err_t esp_openthread_lock_init(void)
{
if (s_openthread_mutex != NULL) {
return ESP_ERR_INVALID_STATE;
}
s_openthread_mutex = xSemaphoreCreateMutex();
if (s_openthread_mutex == NULL) {
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
void esp_openthread_lock_deinit(void)
{
if (s_openthread_mutex) {
vSemaphoreDelete(s_openthread_mutex);
s_openthread_mutex = NULL;
}
}

View File

@ -0,0 +1,68 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread.h"
#include <stdio.h>
#include "esp_log.h"
#include "esp_openthread_common_macro.h"
#include "openthread/platform/logging.h"
/**
* The default platform logging tag.
*
*/
#if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED) || \
(OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_NCP_SPINEL)
OT_TOOL_WEAK void otPlatLog(otLogLevel log_level, otLogRegion log_region, const char *format, ...)
{
va_list args;
va_start(args, format);
switch (log_level) {
case OT_LOG_LEVEL_CRIT:
if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) {
esp_log_write(ESP_LOG_ERROR, OT_PLAT_LOG_TAG, LOG_COLOR_E "E(%u) %s:", esp_log_timestamp(), OT_PLAT_LOG_TAG);
esp_log_writev(ESP_LOG_ERROR, OT_PLAT_LOG_TAG, format, args);
esp_log_write(ESP_LOG_ERROR, OT_PLAT_LOG_TAG, LOG_RESET_COLOR "\n");
}
break;
case OT_LOG_LEVEL_WARN:
if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) {
esp_log_write(ESP_LOG_WARN, OT_PLAT_LOG_TAG, LOG_COLOR_W "W(%u) %s:", esp_log_timestamp(), OT_PLAT_LOG_TAG);
esp_log_writev(ESP_LOG_WARN, OT_PLAT_LOG_TAG, format, args);
esp_log_write(ESP_LOG_WARN, OT_PLAT_LOG_TAG, LOG_RESET_COLOR "\n");
}
break;
case OT_LOG_LEVEL_NOTE:
case OT_LOG_LEVEL_INFO:
if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {
esp_log_write(ESP_LOG_INFO, OT_PLAT_LOG_TAG, LOG_COLOR_I "I(%u) %s:", esp_log_timestamp(), OT_PLAT_LOG_TAG);
esp_log_writev(ESP_LOG_INFO, OT_PLAT_LOG_TAG, format, args);
esp_log_write(ESP_LOG_INFO, OT_PLAT_LOG_TAG, LOG_RESET_COLOR "\n");
}
break;
default:
if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
esp_log_write(ESP_LOG_DEBUG, OT_PLAT_LOG_TAG, LOG_COLOR_D "D(%u) %s:", esp_log_timestamp(), OT_PLAT_LOG_TAG);
esp_log_writev(ESP_LOG_DEBUG, OT_PLAT_LOG_TAG, format, args);
esp_log_write(ESP_LOG_DEBUG, OT_PLAT_LOG_TAG, LOG_RESET_COLOR "\n");
}
break;
}
va_end(args);
}
#endif

View File

@ -0,0 +1,87 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_log.h"
#include "esp_openthread.h"
#include "esp_system.h"
#include "common/logging.hpp"
#include "openthread/platform/misc.h"
static otPlatMcuPowerState s_mcu_power_state = OT_PLAT_MCU_POWER_STATE_ON;
void otPlatReset(otInstance *aInstance)
{
esp_restart();
}
otPlatResetReason otPlatGetResetReason(otInstance *instance)
{
switch (esp_reset_reason()) {
case ESP_RST_UNKNOWN:
return OT_PLAT_RESET_REASON_UNKNOWN;
case ESP_RST_POWERON:
return OT_PLAT_RESET_REASON_POWER_ON;
case ESP_RST_EXT:
return OT_PLAT_RESET_REASON_EXTERNAL;
case ESP_RST_SW:
return OT_PLAT_RESET_REASON_SOFTWARE;
case ESP_RST_PANIC:
return OT_PLAT_RESET_REASON_FAULT;
case ESP_RST_INT_WDT:
return OT_PLAT_RESET_REASON_WATCHDOG;
case ESP_RST_TASK_WDT:
return OT_PLAT_RESET_REASON_WATCHDOG;
case ESP_RST_WDT:
return OT_PLAT_RESET_REASON_WATCHDOG;
default:
return OT_PLAT_RESET_REASON_OTHER;
}
}
void otPlatWakeHost(void)
{
// Not Implemented.
}
otError otPlatSetMcuPowerState(otInstance *instance, otPlatMcuPowerState state)
{
otError error = OT_ERROR_NONE;
OT_UNUSED_VARIABLE(instance);
switch (state) {
case OT_PLAT_MCU_POWER_STATE_ON:
case OT_PLAT_MCU_POWER_STATE_LOW_POWER:
s_mcu_power_state = state;
break;
default:
error = OT_ERROR_FAILED;
break;
}
return error;
}
otPlatMcuPowerState otPlatGetMcuPowerState(otInstance *instance)
{
OT_UNUSED_VARIABLE(instance);
return s_mcu_power_state;
}
void otPlatAssertFail(const char *filename, int line)
{
otLogCritPlat("Assert failed at %s:%d", filename, line);
assert(false);
}

View File

@ -0,0 +1,284 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread_radio_uart.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_types.h"
#include "esp_uart_spinel_interface.hpp"
#include "lib/spinel/radio_spinel.hpp"
#include "openthread/platform/diag.h"
#include "openthread/platform/radio.h"
using ot::Spinel::RadioSpinel;
using esp::openthread::UartSpinelInterface;
static RadioSpinel<UartSpinelInterface, esp_openthread_mainloop_context_t> s_radio;
esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config)
{
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG,
"Spinel interface init falied");
s_radio.Init(/*reset_radio=*/true, /*restore_dataset_from_ncp=*/false, /*skip_rcp_compatibility_check=*/false);
return ESP_OK;
}
void esp_openthread_radio_deinit(void)
{
s_radio.Deinit();
}
esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop)
{
s_radio.Process(*mainloop);
return ESP_OK;
}
void esp_openthread_radio_update(esp_openthread_mainloop_context_t *mainloop)
{
s_radio.GetSpinelInterface().Update(*mainloop);
}
void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64)
{
SuccessOrDie(s_radio.GetIeeeEui64(ieee_eui64));
}
void otPlatRadioSetPanId(otInstance *instance, uint16_t pan_id)
{
SuccessOrDie(s_radio.SetPanId(pan_id));
}
void otPlatRadioSetExtendedAddress(otInstance *instance, const otExtAddress *address)
{
otExtAddress addr;
for (size_t i = 0; i < sizeof(addr); i++) {
addr.m8[i] = address->m8[sizeof(addr) - 1 - i];
}
SuccessOrDie(s_radio.SetExtendedAddress(addr));
}
void otPlatRadioSetShortAddress(otInstance *instance, uint16_t address)
{
SuccessOrDie(s_radio.SetShortAddress(address));
}
void otPlatRadioSetPromiscuous(otInstance *instance, bool enable)
{
SuccessOrDie(s_radio.SetPromiscuous(enable));
}
bool otPlatRadioIsEnabled(otInstance *instance)
{
return s_radio.IsEnabled();
}
otError otPlatRadioEnable(otInstance *instance)
{
return s_radio.Enable(instance);
}
otError otPlatRadioDisable(otInstance *instance)
{
return s_radio.Disable();
}
otError otPlatRadioSleep(otInstance *instance)
{
return s_radio.Sleep();
}
otError otPlatRadioReceive(otInstance *instance, uint8_t channel)
{
return s_radio.Receive(channel);
}
otError otPlatRadioTransmit(otInstance *instance, otRadioFrame *frame)
{
return s_radio.Transmit(*frame);
}
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *instance)
{
return &s_radio.GetTransmitFrame();
}
int8_t otPlatRadioGetRssi(otInstance *instance)
{
return s_radio.GetRssi();
}
otRadioCaps otPlatRadioGetCaps(otInstance *instance)
{
return s_radio.GetRadioCaps();
}
bool otPlatRadioGetPromiscuous(otInstance *instance)
{
return s_radio.IsPromiscuous();
}
void otPlatRadioEnableSrcMatch(otInstance *instance, bool enable)
{
SuccessOrDie(s_radio.EnableSrcMatch(enable));
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *instance, uint16_t short_address)
{
return s_radio.AddSrcMatchShortEntry(short_address);
}
otError otPlatRadioAddSrcMatchExtEntry(otInstance *instance, const otExtAddress *ext_address)
{
otExtAddress addr;
for (size_t i = 0; i < sizeof(addr); i++) {
addr.m8[i] = ext_address->m8[sizeof(addr) - 1 - i];
}
return s_radio.AddSrcMatchExtEntry(addr);
}
otError otPlatRadioClearSrcMatchShortEntry(otInstance *instance, uint16_t short_address)
{
return s_radio.ClearSrcMatchShortEntry(short_address);
}
otError otPlatRadioClearSrcMatchExtEntry(otInstance *instance, const otExtAddress *ext_address)
{
otExtAddress addr;
for (size_t i = 0; i < sizeof(addr); i++) {
addr.m8[i] = ext_address->m8[sizeof(addr) - 1 - i];
}
return s_radio.ClearSrcMatchExtEntry(addr);
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *instance)
{
SuccessOrDie(s_radio.ClearSrcMatchShortEntries());
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *instance)
{
SuccessOrDie(s_radio.ClearSrcMatchExtEntries());
}
otError otPlatRadioEnergyScan(otInstance *instance, uint8_t channel, uint16_t duration)
{
return s_radio.EnergyScan(channel, duration);
}
otError otPlatRadioGetTransmitPower(otInstance *instance, int8_t *power)
{
otError error;
VerifyOrExit(power != NULL, error = OT_ERROR_INVALID_ARGS);
error = s_radio.GetTransmitPower(*power);
exit:
return error;
}
otError otPlatRadioSetTransmitPower(otInstance *instance, int8_t power)
{
return s_radio.SetTransmitPower(power);
}
otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *instance, int8_t *threshold)
{
otError error;
VerifyOrExit(threshold != NULL, error = OT_ERROR_INVALID_ARGS);
error = s_radio.GetCcaEnergyDetectThreshold(*threshold);
exit:
return error;
}
otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *instance, int8_t threshold)
{
return s_radio.SetCcaEnergyDetectThreshold(threshold);
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *instance)
{
return s_radio.GetReceiveSensitivity();
}
#if OPENTHREAD_CONFIG_DIAG_ENABLE
otError otPlatDiagProcess(otInstance *instance, int argc, char *argv[], char *output, size_t output_max_len)
{
// deliver the platform specific diags commands to radio only ncp.
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
char *cur = cmd;
char *end = cmd + sizeof(cmd);
for (int index = 0; index < argc; index++) {
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", argv[index]);
}
return s_radio.PlatDiagProcess(cmd, output, output_max_len);
}
void otPlatDiagModeSet(bool aMode)
{
SuccessOrExit(s_radio.PlatDiagProcess(aMode ? "start" : "stop", NULL, 0));
s_radio.SetDiagEnabled(aMode);
exit:
return;
}
bool otPlatDiagModeGet(void)
{
return s_radio.IsDiagEnabled();
}
void otPlatDiagTxPowerSet(int8_t tx_power)
{
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
snprintf(cmd, sizeof(cmd), "power %d", tx_power);
SuccessOrExit(s_radio.PlatDiagProcess(cmd, NULL, 0));
exit:
return;
}
void otPlatDiagChannelSet(uint8_t channel)
{
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE];
snprintf(cmd, sizeof(cmd), "channel %d", channel);
SuccessOrExit(s_radio.PlatDiagProcess(cmd, NULL, 0));
exit:
return;
}
void otPlatDiagRadioReceived(otInstance *instance, otRadioFrame *frame, otError error)
{
}
void otPlatDiagAlarmCallback(otInstance *instance)
{
}
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE

View File

@ -0,0 +1,129 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_openthread_uart.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_openthread.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_types.h"
#include "esp_vfs_dev.h"
#include "common/logging.hpp"
#include "driver/uart.h"
#include "openthread/platform/uart.h"
static int s_uart_port;
static int s_uart_fd;
static uint8_t s_uart_buffer[ESP_OPENTHREAD_UART_BUFFER_SIZE];
otError otPlatUartEnable(void)
{
return OT_ERROR_NONE;
}
otError otPlatUartDisable(void)
{
return OT_ERROR_NONE;
}
otError otPlatUartFlush(void)
{
return OT_ERROR_NONE;
}
otError otPlatUartSend(const uint8_t *buf, uint16_t buf_length)
{
int rval = write(s_uart_fd, buf, buf_length);
if (rval != (int)buf_length) {
return OT_ERROR_FAILED;
}
otPlatUartSendDone();
return OT_ERROR_NONE;
}
esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *config)
{
ESP_RETURN_ON_ERROR(uart_param_config(config->port, &config->uart_config), OT_PLAT_LOG_TAG,
"uart_param_config failed");
ESP_RETURN_ON_ERROR(
uart_set_pin(config->port, config->tx_pin, config->rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE),
OT_PLAT_LOG_TAG, "uart_set_pin failed");
ESP_RETURN_ON_ERROR(uart_driver_install(config->port, ESP_OPENTHREAD_UART_BUFFER_SIZE, 0, 0, NULL, 0),
OT_PLAT_LOG_TAG, "uart_driver_install failed");
esp_vfs_dev_uart_use_driver(config->port);
return ESP_OK;
}
esp_err_t esp_openthread_uart_init(const esp_openthread_platform_config_t *config)
{
char uart_path[16];
// Disable IO buffer.
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
// Install UART driver for interrupt-driven reads and writes.
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");
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_CRLF);
snprintf(uart_path, sizeof(uart_path), "/dev/uart/%d", s_uart_port);
s_uart_fd = open(uart_path, O_RDWR | O_NONBLOCK);
return s_uart_fd >= 0 ? ESP_OK : ESP_FAIL;
}
void esp_openthread_uart_deinit()
{
if (s_uart_fd != -1) {
close(s_uart_fd);
s_uart_fd = -1;
}
uart_driver_delete(s_uart_port);
}
void esp_openthread_uart_update(esp_openthread_mainloop_context_t *mainloop)
{
FD_SET(s_uart_fd, &mainloop->read_fds);
if (s_uart_fd > mainloop->max_fd) {
mainloop->max_fd = s_uart_fd;
}
}
esp_err_t esp_openthread_uart_process()
{
int rval = read(s_uart_fd, s_uart_buffer, sizeof(s_uart_buffer));
if (rval > 0) {
otPlatUartReceived(s_uart_buffer, (uint16_t)rval);
} else if (rval > 0) {
if (errno != EAGAIN) {
otLogWarnPlat("read uart failed: %d", errno);
return ESP_FAIL;
}
}
return ESP_OK;
}

View File

@ -0,0 +1,295 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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 "esp_uart_spinel_interface.hpp"
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/unistd.h>
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_types.h"
#include "esp_openthread_uart.h"
#include "esp_vfs_dev.h"
#include "core/common/code_utils.hpp"
#include "core/common/logging.hpp"
#include "driver/uart.h"
#include "lib/platform/exit_code.h"
#include "openthread/platform/time.h"
namespace esp {
namespace openthread {
UartSpinelInterface::UartSpinelInterface(
ot::Spinel::SpinelInterface::ReceiveFrameCallback callback,
void *callback_context,
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer)
: m_receiver_frame_callback(callback)
, m_receiver_frame_context(callback_context)
, m_receive_frame_buffer(frame_buffer)
, m_hdlc_decoder(frame_buffer, HandleHdlcFrame, this)
, m_uart_fd(-1)
{
}
UartSpinelInterface::~UartSpinelInterface(void)
{
}
esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_uart_config)
{
m_uart_rx_buffer = static_cast<uint8_t *>(heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_8BIT));
if (m_uart_rx_buffer == NULL) {
return ESP_ERR_NO_MEM;
}
return InitUart(radio_uart_config);
}
esp_err_t UartSpinelInterface::Deinit(void)
{
if (m_uart_rx_buffer) {
heap_caps_free(m_uart_rx_buffer);
}
m_uart_rx_buffer = NULL;
return DeinitUart();
}
otError UartSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length)
{
otError error = OT_ERROR_NONE;
ot::Hdlc::FrameBuffer<kMaxFrameSize> encoder_buffer;
ot::Hdlc::Encoder hdlc_encoder(encoder_buffer);
SuccessOrExit(error = hdlc_encoder.BeginFrame());
SuccessOrExit(error = hdlc_encoder.Encode(frame, length));
SuccessOrExit(error = hdlc_encoder.EndFrame());
SuccessOrExit(error = Write(encoder_buffer.GetFrame(), encoder_buffer.GetLength()));
exit:
if (error != OT_ERROR_NONE) {
otLogCritPlat("send radio frame failed");
} else {
otLogDebgPlat("sent radio frame");
}
return error;
}
void UartSpinelInterface::Process(const esp_openthread_mainloop_context_t &mainloop)
{
if (FD_ISSET(m_uart_fd, &mainloop.read_fds)) {
otLogDebgPlat("radio uart read event");
TryReadAndDecode();
}
}
void UartSpinelInterface::Update(esp_openthread_mainloop_context_t &mainloop)
{
// Register only READ events for radio UART and always wait
// for a radio WRITE to complete.
FD_SET(m_uart_fd, &mainloop.read_fds);
if (m_uart_fd > mainloop.max_fd) {
mainloop.max_fd = m_uart_fd;
}
}
int UartSpinelInterface::TryReadAndDecode(void)
{
uint8_t buffer[UART_FIFO_LEN];
ssize_t rval;
do {
rval = read(m_uart_fd, buffer, sizeof(buffer));
if (rval > 0) {
m_hdlc_decoder.Decode(buffer, static_cast<uint16_t>(rval));
}
} while (rval > 0);
if ((rval < 0) && (errno != EAGAIN) && (errno != EWOULDBLOCK)) {
ESP_ERROR_CHECK(TryRecoverUart());
}
return rval;
}
otError UartSpinelInterface::WaitForWritable(void)
{
otError error = OT_ERROR_NONE;
struct timeval timeout = {kMaxWaitTime / MS_PER_S, (kMaxWaitTime % MS_PER_S) *US_PER_MS};
uint64_t now = otPlatTimeGet();
uint64_t end = now + kMaxWaitTime * US_PER_MS;
fd_set write_fds;
fd_set error_fds;
int rval;
while (true) {
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(m_uart_fd, &write_fds);
FD_SET(m_uart_fd, &error_fds);
rval = select(m_uart_fd + 1, NULL, &write_fds, &error_fds, &timeout);
if (rval > 0) {
if (FD_ISSET(m_uart_fd, &write_fds)) {
ExitNow();
} else if (FD_ISSET(m_uart_fd, &error_fds)) {
ExitNow(error = OT_ERROR_FAILED);
}
} else if ((rval < 0) && (errno != EINTR)) {
ESP_ERROR_CHECK(TryRecoverUart());
ExitNow(error = OT_ERROR_FAILED);
}
now = otPlatTimeGet();
if (end > now) {
uint64_t remain = end - now;
timeout.tv_sec = static_cast<time_t>(remain / 1000000);
timeout.tv_usec = static_cast<suseconds_t>(remain % 1000000);
} else {
break;
}
}
error = OT_ERROR_FAILED;
exit:
return error;
}
otError UartSpinelInterface::Write(const uint8_t *aFrame, uint16_t length)
{
otError error = OT_ERROR_NONE;
while (length) {
ssize_t rval;
rval = write(m_uart_fd, aFrame, length);
if (rval > 0) {
assert(rval <= length);
length -= static_cast<uint16_t>(rval);
aFrame += static_cast<uint16_t>(rval);
continue;
} else if (rval < 0) {
ESP_ERROR_CHECK(TryRecoverUart());
ExitNow(error = OT_ERROR_FAILED);
}
SuccessOrExit(error = WaitForWritable());
}
exit:
return error;
}
otError UartSpinelInterface::WaitForFrame(uint64_t timeout_us)
{
otError error = OT_ERROR_NONE;
struct timeval timeout;
fd_set read_fds;
fd_set error_fds;
int rval;
FD_ZERO(&read_fds);
FD_ZERO(&error_fds);
FD_SET(m_uart_fd, &read_fds);
FD_SET(m_uart_fd, &error_fds);
timeout.tv_sec = static_cast<time_t>(timeout_us / US_PER_S);
timeout.tv_usec = static_cast<suseconds_t>(timeout_us % US_PER_S);
rval = select(m_uart_fd + 1, &read_fds, NULL, &error_fds, &timeout);
if (rval > 0) {
if (FD_ISSET(m_uart_fd, &read_fds)) {
TryReadAndDecode();
} else if (FD_ISSET(m_uart_fd, &error_fds)) {
ESP_ERROR_CHECK(TryRecoverUart());
ExitNow(error = OT_ERROR_FAILED);
}
} else if (rval == 0) {
ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
} else {
ESP_ERROR_CHECK(TryRecoverUart());
ExitNow(error = OT_ERROR_FAILED);
}
exit:
return error;
}
void UartSpinelInterface::HandleHdlcFrame(void *context, otError error)
{
static_cast<UartSpinelInterface *>(context)->HandleHdlcFrame(error);
}
void UartSpinelInterface::HandleHdlcFrame(otError error)
{
if (error == OT_ERROR_NONE) {
otLogDebgPlat("received hdlc radio frame");
m_receiver_frame_callback(m_receiver_frame_context);
} else {
otLogCritPlat("dropping radio frame: %s", otThreadErrorToString(error));
m_receive_frame_buffer.DiscardFrame();
}
}
esp_err_t UartSpinelInterface::InitUart(const esp_openthread_uart_config_t &radio_uart_config)
{
char uart_path[16];
m_uart_config = radio_uart_config;
ESP_RETURN_ON_ERROR(esp_openthread_uart_init_port(&radio_uart_config), OT_PLAT_LOG_TAG,
"esp_openthread_uart_init_port failed");
// We have a driver now installed so set up the read/write functions to use driver also.
esp_vfs_dev_uart_port_set_tx_line_endings(m_uart_config.port, ESP_LINE_ENDINGS_LF);
esp_vfs_dev_uart_port_set_rx_line_endings(m_uart_config.port, ESP_LINE_ENDINGS_LF);
snprintf(uart_path, sizeof(uart_path), "/dev/uart/%d", radio_uart_config.port);
m_uart_fd = open(uart_path, O_RDWR | O_NONBLOCK);
return m_uart_fd >= 0 ? ESP_OK : ESP_FAIL;
}
esp_err_t UartSpinelInterface::DeinitUart(void)
{
if (m_uart_fd != -1) {
close(m_uart_fd);
m_uart_fd = -1;
return uart_driver_delete(m_uart_config.port);
} else {
return ESP_ERR_INVALID_STATE;
}
}
esp_err_t UartSpinelInterface::TryRecoverUart(void)
{
ESP_RETURN_ON_ERROR(DeinitUart(), OT_PLAT_LOG_TAG, "DeInitUart failed");
ESP_RETURN_ON_ERROR(InitUart(m_uart_config), OT_PLAT_LOG_TAG, "InitUart failed");
return ESP_OK;
}
} // namespace openthread
} // namespace esp

View File

@ -0,0 +1,43 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "esp_openthread_types.h"
#include "openthread/instance.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Updates the file descriptor with the OpenThread alarm timeout.
*
* @param[inout] mainloop The main loop context.
*
*/
void esp_openthread_alarm_update(esp_openthread_mainloop_context_t *mainloop);
/**
* @brief Performs the alarm process and triggers the fired timers for OpenThread.
*
* @param[in] instance The OpenThread instance.
*
*/
void esp_openthread_alarm_process(otInstance *instance);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,31 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#define OT_PLAT_LOG_TAG "OPENTHREAD"
#ifndef MS_PER_S
#define MS_PER_S 1000
#endif
#ifndef US_PER_MS
#define US_PER_MS 1000
#endif
#ifndef US_PER_S
#define US_PER_S (MS_PER_S * US_PER_MS)
#endif
#define ESP_OPENTHREAD_UART_BUFFER_SIZE (UART_FIFO_LEN * 2)

View File

@ -0,0 +1,66 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#include "esp_openthread_types.h"
#include "openthread/instance.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief This function initializes the OpenThread radio.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if allocation has failed
*
*/
esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config);
/**
* @brief This function deinitializes the OpenThread radio.
*
*/
void esp_openthread_radio_deinit(void);
/**
* @brief This function updates the radio fds and timeouts to the main loop.
*
* @param[inout] mainloop The main loop context.
*
*/
void esp_openthread_radio_update(esp_openthread_mainloop_context_t *mainloop);
/**
* @brief This function performs the OpenThread radio process.
*
* @param[in] instance The OpenThread instance.
* @param[in] mainloop The main loop context.
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failure
*
*/
esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,76 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "esp_err.h"
#include "esp_openthread_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes an uart port with the given config.
*
* @note The user still needs to open the file descriptor by self.
*
* @param[in] config The uart configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *config);
/**
* @brief Initializes the uart for OpenThread host connection.
*
* @param[in] config The uart configuration.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_uart_init(const esp_openthread_platform_config_t *config);
/**
* @brief Deintializes the uart for OpenThread host connection.
*
*/
void esp_openthread_uart_deinit(void);
/**
* @brief Deintializes the uart for OpenThread host connection.
*
* @param[inout] mainloop The main loop context.
*
*/
void esp_openthread_uart_update(esp_openthread_mainloop_context_t *context);
/**
* @brief Performs the uart I/O for OpenThread.
*
* @return
* - ESP_OK on success
* - ESP_ERROR on failure
*
*/
esp_err_t esp_openthread_uart_process(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,157 @@
// Copyright 2021 Espressif Systems (Shanghai) CO 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
#pragma once
#include "esp_err.h"
#include "esp_openthread.h"
#include "esp_openthread_types.h"
#include "hal/uart_types.h"
#include "lib/spinel/spinel_interface.hpp"
namespace esp {
namespace openthread {
/**
* This class defines an UART interface to the Radio Co-processor (RCP).
*
*/
class UartSpinelInterface {
public:
/**
* @brief This constructor of object.
*
* @param[in] callback Callback on frame received
* @param[in] callback_context Callback context
* @param[in] frame_buffer A reference to a `RxFrameBuffer` object.
*
*/
UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback,
void *callback_context,
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
/**
* @brief This destructor of the object.
*
*/
~UartSpinelInterface(void);
/**
* @brief This method initializes the HDLC interface.
*
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if allocation has failed
* - ESP_ERROR on failure
*/
esp_err_t Init(const esp_openthread_uart_config_t &radio_uart_config);
/**
* @brief This method deinitializes the HDLC interface.
*
*/
esp_err_t Deinit(void);
/**
* @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
*
* @note This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
* up to `kMaxWaitTime` interval.
*
* @param[in] frame A pointer to buffer containing the spinel frame to send.
* @param[in] length The length (number of bytes) in the frame.
*
* @return
* -OT_ERROR_NONE Successfully encoded and sent the spinel frame.
* -OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
* -OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`.
*
*/
otError SendFrame(const uint8_t *frame, uint16_t length);
/**
* This method waits for receiving part or all of spinel frame within specified timeout.
*
* @param[in] timeout_us The timeout value in microseconds.
*
* @return
* -OT_ERROR_NONE Part or all of spinel frame is received.
* -OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p timeout_us.
*
*/
otError WaitForFrame(uint64_t timeout_us);
/**
* This method performs uart processing to the RCP.
*
* @param[in] mainloop The mainloop context
*
*/
void Process(const esp_openthread_mainloop_context_t &mainloop);
/**
* This methods updates the mainloop context.
*
* @param[inout] mainloop The mainloop context.
*
*/
void Update(esp_openthread_mainloop_context_t &mainloop);
private:
enum {
/**
* Maximum spinel frame size.
*
*/
kMaxFrameSize = ot::Spinel::SpinelInterface::kMaxFrameSize,
/**
* Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
*
*/
kMaxWaitTime = 2000,
};
esp_err_t InitUart(const esp_openthread_uart_config_t &radio_uart_config);
esp_err_t DeinitUart(void);
int TryReadAndDecode(void);
otError WaitForWritable(void);
otError Write(const uint8_t *frame, uint16_t length);
esp_err_t TryRecoverUart(void);
static void HandleHdlcFrame(void *context, otError error);
void HandleHdlcFrame(otError error);
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback;
void *m_receiver_frame_context;
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer;
ot::Hdlc::Decoder m_hdlc_decoder;
uint8_t *m_uart_rx_buffer;
esp_openthread_uart_config_t m_uart_config;
int m_uart_fd;
// Non-copyable, intentionally not implemented.
UartSpinelInterface(const UartSpinelInterface &);
UartSpinelInterface &operator=(const UartSpinelInterface &);
};
} // namespace openthread
} // namespace esp

View File

@ -199,6 +199,11 @@ INPUT = \
## Non-Volatile Storage
$(IDF_PATH)/components/nvs_flash/include/nvs.h \
$(IDF_PATH)/components/nvs_flash/include/nvs_flash.h \
## OpenThread
$(IDF_PATH)/components/openthread/include/esp_openthread.h \
$(IDF_PATH)/components/openthread/include/esp_openthread_lock.h \
$(IDF_PATH)/components/openthread/include/esp_openthread_types.h \
$(IDF_PATH)/components/openthread/include/openthread-core-esp32x-config.h \
## Virtual Filesystem
$(IDF_PATH)/components/vfs/include/esp_vfs.h \
$(IDF_PATH)/components/vfs/include/esp_vfs_dev.h \

View File

@ -69,6 +69,8 @@ These third party libraries can be included into the application (firmware) prod
* `qrcode`_ QR Code generator library Copyright (c) Project Nayuki, is licensed under MIT license.
* :component:`openthread`, Copyright (c) The OpenThread Authors, is licensed under Apache License 2.0 as described in :component_file:`LICENSE file<openthread/openthread/LICENSE>`.
Build Tools
-----------

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ot_esp_cli)

View File

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := ot_esp_cli
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,86 @@
# OpenThread command line example
## Overview
This example demonstrates a [basic OpenThread command line](https://github.com/openthread/openthread/blob/master/src/cli/README.md).
## How to use example
### Hardware connection
To run this example, it's used to use an DevKit C board and connect PIN4 and PIN5 to the UART TX and RX port of another 15.4 capable radio co-processor ([RCP](https://openthread.io/platforms/co-processor?hl=en))
### Configure the project
```
idf.py menuconfig
```
The example can run with the default configuration.
### Build, Flash, and Run
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT build flash monitor
```
Now you'll get an interactive OpenThread command line shell.
## Example Output
```bash
I (1540) OPENTHREAD: [INFO]-PLAT----: RCP reset: RESET_POWER_ON
I (1610) OPENTHREAD: [NOTE]-PLAT----: RCP API Version: 3
I (1840) OPENTHREAD: [INFO]-CORE----: Non-volatile: Read NetworkInfo {rloc:0x7404, extaddr:aee4a5cc7ed1ad88, role:Child, mode:0x0f, version:2, keyseq:0x0, ...
I (1850) OPENTHREAD: [INFO]-CORE----: Non-volatile: ... pid:0x1161bcdc, mlecntr:0x5a17, maccntr:0x5a91, mliid:33158c466ab576d4}
I (1900) OPENTHREAD: [INFO]-CORE----: Non-volatile: Read ParentInfo {extaddr:36505631b12ea5e3, version:2}
I (1900) OPENTHREAD: [INFO]-CORE----: Notifier: StateChanged (0x1007c300) [KeySeqCntr NetData Channel PanId NetName ExtPanId MstrKey ActDset]
> ifconfig up
I (11320) OPENTHREAD: [INFO]-CLI-----: execute command: ifconfig up
Done
I (11340) OPENTHREAD: [INFO]-CORE----: Notifier: StateChanged (0x01001009) [Ip6+ LLAddr Ip6Mult+ NetifState]
> dataset init new
I (105650) OPENTHREAD: [INFO]-CLI-----: execute command: dataset init new
Done
> dataset
I (107460) OPENTHREAD: [INFO]-CLI-----: execute command: dataset
Active Timestamp: 1
Channel: 14
Channel Mask: 0x07fff800
Ext PAN ID: d9d69bf6535735ec
Mesh Local Prefix: fd73:192f:f27:2a5c::/64
Master Key: 7ad0ec87abbd8c41f07d004922b480bf
Network Name: OpenThread-a5fe
PAN ID: 0xa5fe
PSKc: ef028c933febdeb226f6681cc780272a
Security Policy: 672, onrcb
Done
> dataset commit active
I (134350) OPENTHREAD: [INFO]-CLI-----: execute command: dataset commit active
I (134350) OPENTHREAD: [INFO]-MESH-CP-: Active dataset set
Done
I (134380) OPENTHREAD: [INFO]-CORE----: Notifier: StateChanged (0x101fc110) [MLAddr KeySeqCntr Channel PanId NetName ExtPanId MstrKey PSKc SecPolicy ...
I (134390) OPENTHREAD: [INFO]-CORE----: Notifier: StateChanged (0x101fc110) ... ActDset]
>thread start
I (177250) OPENTHREAD: [INFO]-CLI-----: execute command: thread start
I (177250) OPENTHREAD: [NOTE]-MLE-----: Role Disabled -> Detached
I (177280) OPENTHREAD: [INFO]-CORE----: Non-volatile: Read NetworkInfo {rloc:0x7404, extaddr:aee4a5cc7ed1ad88, role:Child, mode:0x0f, version:2, keyseq:0x0, ...
I (177290) OPENTHREAD: [INFO]-CORE----: Non-volatile: ... pid:0x1161bcdc, mlecntr:0x5a17, maccntr:0x5a91, mliid:33158c466ab576d4}
I (194054) OPENTHREAD: [INFO]-CORE----: Non-volatile: Saved NetworkInfo {rloc:0x7404, extaddr:aee4a5cc7ed1ad88, role:Child, mode:0x0f, version:2, keyseq:0x0, ...
I (194064) OPENTHREAD: [INFO]-CORE----: Non-volatile: ... pid:0x1161bcdc, mlecntr:0x5e00, maccntr:0x5e79, mliid:33158c466ab576d4}
I (194074) OPENTHREAD: [INFO]-MLE-----: Send Child Update Request to parent (fe80:0:0:0:3450:5631:b12e:a5e3)
Done
# After some seconds
> state
leader
Done
```

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "ot_esp_cli.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,8 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_ADD_INCLUDEDIRS := .
COMPONENT_PRIV_INCLUDEDIRS := .

View File

@ -0,0 +1,129 @@
// Copyright 2020 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 <stdio.h>
#include <unistd.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_openthread.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_types.h"
#include "sdkconfig.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
#include "freertos/task.h"
#include "hal/uart_types.h"
#include "openthread/cli.h"
#include "openthread/instance.h"
#include "openthread/tasklet.h"
#define TAG "ot_esp_cli"
static void ot_task_worker(void *aContext)
{
esp_openthread_platform_config_t config = {
.radio_config =
{
.radio_mode = RADIO_MODE_UART_RCP,
.radio_uart_config =
{
.port = 1,
.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,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_APB,
},
.rx_pin = 4,
.tx_pin = 5,
},
},
.host_config =
{
.host_connection_mode = HOST_CONNECTION_MODE_UART,
.host_uart_config =
{
.port = 0,
.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,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_APB,
},
.rx_pin = UART_PIN_NO_CHANGE,
.tx_pin = UART_PIN_NO_CHANGE,
},
},
};
esp_openthread_mainloop_context_t mainloop;
ESP_ERROR_CHECK(esp_openthread_platform_init(&config));
otInstance *instance = otInstanceInitSingle();
assert(instance != NULL);
esp_openthread_lock_acquire(portMAX_DELAY);
otCliUartInit(instance);
esp_openthread_lock_release();
while (true) {
FD_ZERO(&mainloop.read_fds);
FD_ZERO(&mainloop.write_fds);
FD_ZERO(&mainloop.error_fds);
mainloop.max_fd = -1;
mainloop.timeout.tv_sec = 10;
mainloop.timeout.tv_usec = 0;
esp_openthread_lock_acquire(portMAX_DELAY);
esp_openthread_platform_update(&mainloop);
if (otTaskletsArePending(instance)) {
mainloop.timeout.tv_sec = 0;
mainloop.timeout.tv_usec = 0;
}
esp_openthread_lock_release();
if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds,
&mainloop.timeout) >= 0) {
esp_openthread_lock_acquire(portMAX_DELAY);
otTaskletsProcess(instance);
if (esp_openthread_platform_process(instance, &mainloop)) {
ESP_LOGE(TAG, "esp_openthread_platform_process failed");
}
esp_openthread_lock_release();
} else {
ESP_LOGE(TAG, "OpenThread system polling failed");
break;
}
}
otInstanceFinalize(instance);
esp_openthread_platform_deinit();
vTaskDelete(NULL);
}
void app_main(void)
{
xTaskCreate(ot_task_worker, "ot_cli_main", 10240, xTaskGetCurrentTaskHandle(), 5, NULL);
}

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
ot_storage, data, 0x3a, , 0x2000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 ot_storage, data, 0x3a, , 0x2000,

View File

@ -0,0 +1,33 @@
#
# libsodium
#
CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y
# end of libsodium
#
# Partition Table
#
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
#
# mbedTLS
#
CONFIG_MBEDTLS_CMAC_C=y
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y
CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y
# end of TLS Key Exchange Methods
CONFIG_MBEDTLS_ECJPAKE_C=y
# end of mbedTLS
#
# OpenThread
#
CONFIG_OPENTHREAD_ENABLED=y
# end of OpenThread

View File

@ -92,6 +92,8 @@ components/cmock/CMock/src/cmock_internals.h
components/efuse/include/esp_efuse.h
components/openthread/openthread/
### Here are the files that do not compile for some reason
#
components/app_trace/include/esp_sysview_trace.h