mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(openthread): support esp openthread radio spinel
This commit is contained in:
parent
6f053704dc
commit
ea8799eef7
@ -4,7 +4,7 @@ if(${idf_target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_IDF_DOC_BUILD)
|
||||
if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_IDF_DOC_BUILD OR CONFIG_OPENTHREAD_SPINEL_ONLY)
|
||||
|
||||
set(public_include_dirs
|
||||
"include"
|
||||
@ -149,6 +149,11 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
||||
-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
|
||||
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
|
||||
list(APPEND src_dirs
|
||||
"src/ncp")
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT)
|
||||
list(APPEND exclude_srcs
|
||||
"src/esp_openthread_dns64.c")
|
||||
@ -171,6 +176,48 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
||||
elseif(CONFIG_OPENTHREAD_RADIO)
|
||||
set(device_type "OPENTHREAD_RADIO=1")
|
||||
endif()
|
||||
elseif(CONFIG_OPENTHREAD_SPINEL_ONLY)
|
||||
|
||||
set(src_dirs
|
||||
"src/spinel"
|
||||
"src/port"
|
||||
"openthread/src/lib/spinel"
|
||||
"openthread/src/lib/hdlc"
|
||||
"openthread/src/lib/platform"
|
||||
"openthread/src/core/api"
|
||||
"openthread/src/core/common"
|
||||
"openthread/src/core/mac")
|
||||
|
||||
set(private_include_dirs
|
||||
"private_include"
|
||||
"openthread/src"
|
||||
"openthread/src/core"
|
||||
"openthread/src/lib"
|
||||
"openthread/src/lib/hdlc"
|
||||
"openthread/src/lib/spinel")
|
||||
|
||||
file(GLOB_RECURSE exclude_srcs_list
|
||||
"src/port/*"
|
||||
"openthread/src/core/api/*.cpp"
|
||||
"openthread/src/core/common/*"
|
||||
"openthread/src/core/mac/*")
|
||||
|
||||
list(REMOVE_ITEM exclude_srcs_list
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/port/esp_openthread_alarm.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/port/esp_openthread_logging.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/api/error_api.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/api/logging_api.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/error.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/error.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/log.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/log.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/logging.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/string.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/common/string.hpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/mac/mac_frame.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openthread/src/core/mac/mac_frame.hpp")
|
||||
|
||||
list(APPEND exclude_srcs ${exclude_srcs_list})
|
||||
|
||||
endif()
|
||||
|
||||
@ -201,13 +248,15 @@ idf_component_register(SRC_DIRS "${src_dirs}"
|
||||
PRIV_REQUIRES console esp_event esp_partition esp_timer
|
||||
ieee802154 mbedtls nvs_flash)
|
||||
|
||||
if(CONFIG_OPENTHREAD_ENABLED)
|
||||
if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_OPENTHREAD_SPINEL_ONLY)
|
||||
if(CONFIG_OPENTHREAD_RADIO)
|
||||
set(CONFIG_FILE_TYPE "radio")
|
||||
elseif(CONFIG_OPENTHREAD_FTD)
|
||||
set(CONFIG_FILE_TYPE "ftd")
|
||||
elseif(CONFIG_OPENTHREAD_MTD)
|
||||
set(CONFIG_FILE_TYPE "mtd")
|
||||
elseif(CONFIG_OPENTHREAD_SPINEL_ONLY)
|
||||
set(CONFIG_FILE_TYPE "spinel")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(
|
||||
|
@ -168,6 +168,13 @@ menu "OpenThread"
|
||||
Select this to enable SPI connection to host.
|
||||
endchoice
|
||||
|
||||
config OPENTHREAD_NCP_VENDOR_HOOK
|
||||
bool "Enable vendor command for RCP"
|
||||
depends on OPENTHREAD_RADIO
|
||||
default n
|
||||
help
|
||||
Select this to enable OpenThread NCP vendor commands.
|
||||
|
||||
config OPENTHREAD_CLI
|
||||
bool "Enable Openthread Command-Line Interface"
|
||||
depends on OPENTHREAD_ENABLED
|
||||
@ -362,4 +369,10 @@ menu "OpenThread"
|
||||
Select this option to enable the radio statistics feature, you can use radio command to print some radio
|
||||
Statistics informations.
|
||||
|
||||
config OPENTHREAD_SPINEL_ONLY
|
||||
bool "Enable OpenThread External Radio Spinel feature"
|
||||
default n
|
||||
help
|
||||
Select this option to enable the OpenThread Radio Spinel for external protocol stack, such as Zigbee.
|
||||
|
||||
endmenu
|
||||
|
331
components/openthread/include/esp_radio_spinel.h
Normal file
331
components/openthread/include/esp_radio_spinel.h
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/select.h>
|
||||
#include "esp_ieee802154_types.h"
|
||||
#include "driver/uart.h"
|
||||
#include "soc/gpio_num.h"
|
||||
|
||||
#define ESP_SPINEL_LOG_TAG "ESP_RADIO_SPINEL"
|
||||
|
||||
#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) /* Vendor command for coordinator.*/
|
||||
|
||||
#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) /* Vendor command for pending mode.*/
|
||||
|
||||
typedef enum {
|
||||
ESP_RADIO_SPINEL_ZIGBEE = 0x0, /* The index of Zigbee.*/
|
||||
ESP_RADIO_SPINEL_OPENTHREAD = 0x1, /* The index of OpenThread.*/
|
||||
ESP_RADIO_SPINEL_MAX,
|
||||
} esp_radio_spinel_idx_t; /* The index of 802.15.4 related protocol stack for ESP radio spinel.*/
|
||||
|
||||
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_radio_spinel_mainloop_context_t;
|
||||
|
||||
typedef struct {
|
||||
uart_port_t port; /*!< UART port number */
|
||||
uart_config_t uart_config; /*!< UART configuration, see uart_config_t docs */
|
||||
gpio_num_t rx_pin; /*!< UART RX pin */
|
||||
gpio_num_t tx_pin; /*!< UART TX pin */
|
||||
} esp_radio_spinel_uart_config_t; /*This structure represents a context for ESP radio spinel. */
|
||||
|
||||
typedef void (*esp_radio_spinel_rcp_failure_handler)(void); /* The handler for rcp failure.*/
|
||||
typedef esp_err_t (*esp_radio_spinel_uart_init_handler)(const esp_radio_spinel_uart_config_t *uart_config_t, int *uart_fd); /* The handler for UART initialization.*/
|
||||
typedef esp_err_t (*esp_radio_spinel_uart_deinit_handler)(const esp_radio_spinel_uart_config_t *uart_config_t, int *uart_fd); /* The handler for UART deinitialization.*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*receive_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Receive Done.*/
|
||||
void (*transmit_done)(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info); /* Callback for Transmit Done.*/
|
||||
void (*transmit_failed)(esp_ieee802154_tx_error_t error); /* Callback for Transmit Failed.*/
|
||||
void (*energy_scan_done)(int8_t max_rssi); /* Callback for Energy Scan Done.*/
|
||||
void (*transmit_started)(const uint8_t *frame); /* Callback for Transmit Started.*/
|
||||
void (*switchover_done)(bool success); /* Callback for Switchover Done.*/
|
||||
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
void (*diag_receive_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Receive Done (diag).*/
|
||||
void (*diag_transmit_done)(const uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); /* Callback for Transmit Done (diag).*/
|
||||
void (*diag_transmit_failed)(esp_ieee802154_tx_error_t error); /* Callback for Transmit Failed (diag).*/
|
||||
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
} esp_radio_spinel_callbacks_t; /* ESP Radio Spinel Callbacks.*/
|
||||
|
||||
/**
|
||||
* @brief Set callkbacks of ESP radio spinel.
|
||||
*
|
||||
* @note This function should be called before `esp_radio_spinel_init`.
|
||||
*
|
||||
* @param[in] aCallbacks The callbacks struct.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_callbacks(const esp_radio_spinel_callbacks_t aCallbacks, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Enable the UART interface for ESP radio spinel
|
||||
*
|
||||
* @note This function should be called before `esp_radio_spinel_init`.
|
||||
*
|
||||
* @param[in] radio_uart_config The config of UART for radio spinel.
|
||||
* @param[in] aUartInitHandler The function for UART initialization
|
||||
* @param[in] aUartDeinitHandler The function for UART deinitialization
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failures
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_uart_interface_enable(const esp_radio_spinel_uart_config_t *radio_uart_config,
|
||||
esp_radio_spinel_uart_init_handler aUartInitHandler,
|
||||
esp_radio_spinel_uart_deinit_handler aUartDeinitHandler,
|
||||
esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Initialize ESP radio spinel.
|
||||
*
|
||||
* @note This function should be called after `esp_radio_spinel_set_callbacks` and `esp_radio_spinel_uart_interface_enable`.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_init(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Enavle ESP radio spinel.
|
||||
*
|
||||
* @note This function should be called after `esp_radio_spinel_init`.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_enable(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the pending mode.
|
||||
*
|
||||
* @param[in] pending_mode The pending mode.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Get the EUI-64.
|
||||
*
|
||||
* @param[in] eui64 A pointer to the EUI-64.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the panid.
|
||||
*
|
||||
* @param[in] panid The panid.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_panid(uint16_t panid, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the short address.
|
||||
*
|
||||
* @param[in] short_address The short address.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_short_address(uint16_t short_address, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the extended address.
|
||||
*
|
||||
* @param[in] ext_address The extended address.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the coordinator mode.
|
||||
*
|
||||
* @param[in] enable Enable or disable the coordinator mode.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Enable the RCP reception.
|
||||
*
|
||||
* @param[in] channel The channel of reception.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Perform the energy scan.
|
||||
*
|
||||
* @param[in] scan_channel The channel of energy scan (usually the range is 11~26, scan all channels if it's set to 0).
|
||||
* @param[in] scan_duration The duration for energy scan.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_energy_scan(uint8_t scan_channel, uint16_t scan_duration, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Perform the transmission.
|
||||
*
|
||||
* @param[in] frame A pointer to the frame.
|
||||
* @param[in] channel The channel to use for transmitting.
|
||||
* @param[in] cca Perform clear channel assessment(if it's true) or not(if it's false)
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_transmit(uint8_t *frame, uint8_t channel, bool cca, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Clear all short addresses from the source address match table.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_clear_short_entries(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Add a short address to the source address match table.
|
||||
*
|
||||
* @param[in] short_address The short address to be added.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failures
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_add_short_entry(uint16_t short_address, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Clear the pending table, remove all extended/long addresses.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_clear_extened_entries(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Add an extended address to the source address match table.
|
||||
*
|
||||
* @param[in] ext_address The extended address to be added.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failures
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_add_extened_entry(uint8_t *ext_address, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Sets the status of promiscuous mode.
|
||||
*
|
||||
* @param[in] enable Whether to enable or disable promiscuous mode.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Update the ESP radio spinel.
|
||||
*
|
||||
* @param[in] mainloop_context The context for ESP radio spinel.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Process the ESP radio spinel.
|
||||
*
|
||||
* @param[in] mainloop_context The context for ESP radio spinel.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Switch the radio state to Sleep.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_sleep(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Set the radio's transmit power in dBm.
|
||||
*
|
||||
* @param[in] power The transmit power in dBm.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_set_tx_power(int8_t power, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Get the radio's transmit power in dBm.
|
||||
*
|
||||
* @param[in] power A pointer to the transmit power.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_get_tx_power(int8_t *power, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Register a handler to process the RCP failure.
|
||||
*
|
||||
* @param[in] handler The RCP failure handler.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
*/
|
||||
void esp_radio_spinel_register_rcp_failure_handler(esp_radio_spinel_rcp_failure_handler handler, esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the RCP.
|
||||
*
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failures
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_rcp_deinit(esp_radio_spinel_idx_t idx);
|
||||
|
||||
/**
|
||||
* @brief Get the version of RCP.
|
||||
*
|
||||
* @param[in] running_rcp_version A pointer to the RCP version string.
|
||||
* @param[in] idx The index of 802.15.4 related protocol stack.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failures
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_spinel_idx_t idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
15
components/openthread/private_include/esp_openthread_ncp.h
Normal file
15
components/openthread/private_include/esp_openthread_ncp.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <spinel.h>
|
||||
|
||||
#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK
|
||||
|
||||
#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1)
|
||||
|
||||
#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2)
|
||||
|
||||
#endif
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace esp {
|
||||
namespace radio_spinel {
|
||||
|
||||
/**
|
||||
* This class defines an template to adapt both UartSpinelInterface and SpiSpinelInterface.
|
||||
*
|
||||
*/
|
||||
template <typename InterfaceType> class SpinelInterfaceAdapter {
|
||||
public:
|
||||
SpinelInterfaceAdapter(void) {}
|
||||
|
||||
~SpinelInterfaceAdapter(void) {}
|
||||
|
||||
InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
|
||||
|
||||
private:
|
||||
InterfaceType mSpinelInterface;
|
||||
};
|
||||
|
||||
} // namespace radio_spinel
|
||||
} // namespace esp
|
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_radio_spinel.h"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "openthread/error.h"
|
||||
|
||||
namespace esp {
|
||||
namespace radio_spinel {
|
||||
|
||||
/**
|
||||
* This class defines an UART interface to the Radio Co-processor (RCP).
|
||||
*
|
||||
*/
|
||||
class UartSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||
public:
|
||||
/**
|
||||
* @brief This constructor of object.
|
||||
*/
|
||||
UartSpinelInterface(void);
|
||||
|
||||
/**
|
||||
* @brief This destructor of the object.
|
||||
*
|
||||
*/
|
||||
~UartSpinelInterface(void);
|
||||
|
||||
/**
|
||||
* Initializes the interface to the Radio Co-processor (RCP).
|
||||
*
|
||||
* @note This method should be called before reading and sending spinel frames to the interface.
|
||||
*
|
||||
* @param[in] aCallback Callback on frame received
|
||||
* @param[in] aCallbackContext Callback context
|
||||
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The interface is initialized successfully
|
||||
* @retval OT_ERROR_ALREADY The interface is already initialized.
|
||||
* @retval OT_ERROR_FAILED Failed to initialize the interface.
|
||||
*
|
||||
*/
|
||||
otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
/**
|
||||
* Deinitializes the interface to the RCP.
|
||||
*
|
||||
*/
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* Encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the spinel frame to send.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame.
|
||||
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
|
||||
* @retval OT_ERROR_FAILED Failed to call the SPI driver to send the frame.
|
||||
*
|
||||
*/
|
||||
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Waits for receiving part or all of spinel frame within specified interval.
|
||||
*
|
||||
* @param[in] aTimeout The timeout value in microseconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Part or all of spinel frame is received.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
|
||||
*
|
||||
*/
|
||||
otError WaitForFrame(uint64_t aTimeoutUs);
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the radio driver.
|
||||
*
|
||||
* @param[in,out] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void UpdateFdSet(void *aMainloopContext);
|
||||
|
||||
/**
|
||||
* Performs radio driver processing.
|
||||
*
|
||||
* @param[in] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Process(const void *aMainloopContext);
|
||||
|
||||
/**
|
||||
* Returns the bus speed between the host and the radio.
|
||||
*
|
||||
* @returns Bus speed in bits/second.
|
||||
*
|
||||
*/
|
||||
uint32_t GetBusSpeed(void) const;
|
||||
|
||||
/**
|
||||
* Hardware resets the RCP.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully reset the RCP.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented.
|
||||
*
|
||||
*/
|
||||
otError HardwareReset(void);
|
||||
|
||||
/**
|
||||
* Returns the RCP interface metrics.
|
||||
*
|
||||
* @returns The RCP interface metrics.
|
||||
*
|
||||
*/
|
||||
const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
|
||||
|
||||
/**
|
||||
* This methods registers the callback for RCP failure.
|
||||
*
|
||||
* @param[in] handler The RCP failure handler.
|
||||
*
|
||||
*/
|
||||
void RegisterRcpFailureHandler(esp_radio_spinel_rcp_failure_handler handler) { mRcpFailureHandler = handler; }
|
||||
|
||||
/**
|
||||
* This method is called when RCP is reset to recreate the connection with it.
|
||||
* Intentionally empty.
|
||||
*
|
||||
*/
|
||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
||||
|
||||
/**
|
||||
* @brief This method enable the HDLC interface.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM if allocation has failed
|
||||
* - ESP_ERROR on failure
|
||||
*/
|
||||
esp_err_t Enable(const esp_radio_spinel_uart_config_t &radio_uart_config);
|
||||
|
||||
/**
|
||||
* @brief This method disable the HDLC interface.
|
||||
*
|
||||
*/
|
||||
esp_err_t Disable(void);
|
||||
|
||||
void RegisterUartInitHandler(esp_radio_spinel_uart_init_handler handler) { mUartInitHandler = handler; }
|
||||
|
||||
void RegisterUartDeinitHandler(esp_radio_spinel_uart_deinit_handler handler) { mUartDeinitHandler = handler; }
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
/**
|
||||
* Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||
*
|
||||
*/
|
||||
kMaxWaitTime = 2000,
|
||||
};
|
||||
|
||||
esp_err_t InitUart(const esp_radio_spinel_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);
|
||||
|
||||
ReceiveFrameCallback m_receiver_frame_callback;
|
||||
void *m_receiver_frame_context;
|
||||
RxFrameBuffer *m_receive_frame_buffer;
|
||||
|
||||
ot::Hdlc::Decoder m_hdlc_decoder;
|
||||
uint8_t *m_uart_rx_buffer;
|
||||
|
||||
esp_radio_spinel_uart_config_t m_uart_config;
|
||||
int m_uart_fd;
|
||||
|
||||
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||
|
||||
// Non-copyable, intentionally not implemented.
|
||||
UartSpinelInterface(const UartSpinelInterface &);
|
||||
UartSpinelInterface &operator=(const UartSpinelInterface &);
|
||||
|
||||
esp_radio_spinel_rcp_failure_handler mRcpFailureHandler;
|
||||
esp_radio_spinel_uart_init_handler mUartInitHandler;
|
||||
esp_radio_spinel_uart_deinit_handler mUartDeinitHandler;
|
||||
};
|
||||
|
||||
} // namespace radio_spinel
|
||||
} // namespace esp
|
@ -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
|
||||
*/
|
||||
@ -218,3 +218,15 @@
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1
|
||||
#endif
|
||||
#endif //CONFIG_OPENTHREAD_LINK_METRICS
|
||||
|
||||
#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK
|
||||
/**
|
||||
* @def OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
||||
*
|
||||
* Define as 1 to support ESP OpenThread NCP vendor commands
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
||||
#define OPENTHREAD_ENABLE_NCP_VENDOR_HOOK 1
|
||||
#endif
|
||||
#endif //CONFIG_OPENTHREAD_NCP_VENDOR_HOOK
|
||||
|
@ -4,13 +4,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes compile-time configuration constants for OpenThread.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_SPINEL_CONFIG_H_
|
||||
#define OPENTHREAD_SPINEL_CONFIG_H_
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
|
||||
@ -30,6 +24,7 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT
|
||||
// TZ-567: Set OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT to 3 after adding rcp failure notification mechanism
|
||||
#define OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT 0
|
||||
#endif
|
||||
|
||||
@ -42,5 +37,3 @@
|
||||
#ifndef OPENTHREAD_SPINEL_CONFIG_RCP_CUSTOM_RESTORATION
|
||||
#define OPENTHREAD_SPINEL_CONFIG_RCP_CUSTOM_RESTORATION 0
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_SPINEL_CONFIG_H_
|
111
components/openthread/src/ncp/esp_openthread_ncp.cpp
Normal file
111
components/openthread/src/ncp/esp_openthread_ncp.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_ieee802154.h"
|
||||
#include "esp_openthread_ncp.h"
|
||||
#include "ncp_base.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
||||
|
||||
#if CONFIG_OPENTHREAD_RCP_UART
|
||||
#include "utils/uart.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_OPENTHREAD_RCP_UART
|
||||
extern "C" {
|
||||
static int NcpSend(const uint8_t *aBuf, uint16_t aBufLength)
|
||||
{
|
||||
IgnoreError(otPlatUartSend(aBuf, aBufLength));
|
||||
return aBufLength;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void otAppNcpInit(otInstance *aInstance)
|
||||
{
|
||||
#if CONFIG_OPENTHREAD_RCP_SPI
|
||||
otNcpSpiInit(aInstance);
|
||||
#else
|
||||
IgnoreError(otPlatUartEnable());
|
||||
|
||||
otNcpHdlcInit(aInstance, NcpSend);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace ot {
|
||||
namespace Ncp {
|
||||
|
||||
otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
otPlatLog(OT_LOG_LEVEL_WARN, OT_LOG_REGION_NCP, "VendorCommandHandler Not Implemented");
|
||||
|
||||
switch (aCommand)
|
||||
{
|
||||
|
||||
default:
|
||||
error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_INVALID_COMMAND);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void NcpBase::VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aFrameTag);
|
||||
}
|
||||
|
||||
otError NcpBase::VendorGetPropertyHandler(spinel_prop_key_t aPropKey)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
switch (aPropKey)
|
||||
{
|
||||
|
||||
default:
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
switch (aPropKey)
|
||||
{
|
||||
|
||||
// TZ-566: Add mechanism to allow users to register callback functions.
|
||||
case SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR: {
|
||||
bool coordinator = false;
|
||||
mDecoder.ReadBool(coordinator);
|
||||
esp_ieee802154_set_coordinator(coordinator);
|
||||
break;
|
||||
}
|
||||
case SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE: {
|
||||
|
||||
int32_t pending_mode = 0;
|
||||
mDecoder.ReadInt32(pending_mode);
|
||||
esp_ieee802154_set_pending_mode(static_cast<esp_ieee802154_pending_mode_t>(pending_mode));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
33
components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp
Normal file
33
components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "common/new.hpp"
|
||||
#include "ncp_hdlc.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
||||
|
||||
namespace ot {
|
||||
namespace Ncp {
|
||||
|
||||
static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpHdlc), uint64_t);
|
||||
|
||||
extern "C" void otNcpHdlcInit(otInstance *aInstance, otNcpHdlcSendCallback aSendCallback)
|
||||
{
|
||||
NcpHdlc *ncpHdlc = nullptr;
|
||||
Instance *instance = static_cast<Instance *>(aInstance);
|
||||
|
||||
ncpHdlc = new (&sNcpRaw) NcpHdlc(instance, aSendCallback);
|
||||
|
||||
if (ncpHdlc == nullptr || ncpHdlc != NcpBase::GetNcpInstance())
|
||||
{
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
352
components/openthread/src/spinel/esp_radio_spinel.cpp
Normal file
352
components/openthread/src/spinel/esp_radio_spinel.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "platform/exit_code.h"
|
||||
#include "radio_spinel.hpp"
|
||||
#include "esp_radio_spinel.h"
|
||||
#include "esp_radio_spinel_adapter.hpp"
|
||||
#include "esp_radio_spinel_uart_interface.hpp"
|
||||
|
||||
using ot::Spinel::RadioSpinel;
|
||||
using ot::Spinel::RadioSpinelCallbacks;
|
||||
using esp::radio_spinel::SpinelInterfaceAdapter;
|
||||
using esp::radio_spinel::UartSpinelInterface;
|
||||
|
||||
static SpinelInterfaceAdapter<UartSpinelInterface> s_spinel_interface[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||
static RadioSpinel s_radio[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||
static esp_radio_spinel_callbacks_t s_esp_radio_spinel_callbacks[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||
otRadioFrame s_transmit_frame;
|
||||
|
||||
static esp_radio_spinel_idx_t get_index_from_instance(otInstance *instance)
|
||||
{
|
||||
// TZ-563: Implement the function to get the esp radio spinel idx from otInstance for multipan rcp
|
||||
return ESP_RADIO_SPINEL_ZIGBEE;
|
||||
}
|
||||
|
||||
static otInstance* get_instance_from_index(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
// TZ-563: Implement the function to get otInstance pointer from esp radio spinel idx
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].receive_done);
|
||||
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
||||
esp_ieee802154_frame_info_t frame_info;
|
||||
if (frame) {
|
||||
frame[0] = aFrame->mLength;
|
||||
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
||||
frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi;
|
||||
frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp;
|
||||
frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending;
|
||||
s_esp_radio_spinel_callbacks[idx].receive_done(frame, &frame_info);
|
||||
free(frame);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
||||
}
|
||||
}
|
||||
|
||||
void TransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].transmit_done && s_esp_radio_spinel_callbacks[idx].transmit_failed);
|
||||
if (aError == OT_ERROR_NONE) {
|
||||
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
||||
uint8_t *ack = nullptr;
|
||||
if (frame) {
|
||||
esp_ieee802154_frame_info_t ack_info;
|
||||
frame[0] = aFrame->mLength;
|
||||
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
||||
if (aAckFrame) {
|
||||
ack = (uint8_t *)malloc(aAckFrame->mLength + 1);
|
||||
if (ack) {
|
||||
ack[0] = aAckFrame->mLength;
|
||||
memcpy((void *)(ack + 1), aAckFrame->mPsdu, ack[0]);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for ack");
|
||||
}
|
||||
}
|
||||
s_esp_radio_spinel_callbacks[idx].transmit_done(frame, ack, &ack_info);
|
||||
free(frame);
|
||||
free(ack);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
||||
}
|
||||
} else {
|
||||
switch (aError) {
|
||||
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
|
||||
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
||||
break;
|
||||
case OT_ERROR_NO_ACK:
|
||||
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK);
|
||||
break;
|
||||
default:
|
||||
s_esp_radio_spinel_callbacks[idx].transmit_failed(ESP_IEEE802154_TX_ERR_ABORT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnergyScanDone(otInstance *aInstance, int8_t aMaxRssi)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].energy_scan_done);
|
||||
s_esp_radio_spinel_callbacks[idx].energy_scan_done(aMaxRssi);
|
||||
}
|
||||
|
||||
void TxStarted(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].transmit_started);
|
||||
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
||||
if (frame) {
|
||||
frame[0] = aFrame->mLength;
|
||||
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
||||
s_esp_radio_spinel_callbacks[idx].transmit_started(frame);
|
||||
free(frame);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchoverDone(otInstance *aInstance, bool aSuccess)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].switchover_done);
|
||||
s_esp_radio_spinel_callbacks[idx].switchover_done(aSuccess);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
void DiagReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].diag_receive_done);
|
||||
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
||||
esp_ieee802154_frame_info_t frame_info;
|
||||
if (frame) {
|
||||
frame[0] = aFrame->mLength;
|
||||
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
||||
frame_info.rssi = aFrame->mInfo.mRxInfo.mRssi;
|
||||
frame_info.timestamp = aFrame->mInfo.mRxInfo.mTimestamp;
|
||||
frame_info.pending = aFrame->mInfo.mRxInfo.mAckedWithFramePending;
|
||||
s_esp_radio_spinel_callbacks[idx].diag_receive_done(frame, &frame_info);
|
||||
free(frame);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
||||
}
|
||||
}
|
||||
|
||||
void DiagTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance);
|
||||
assert(s_esp_radio_spinel_callbacks[idx].diag_transmit_done && s_esp_radio_spinel_callbacks[idx].diag_transmit_failed);
|
||||
if (aError == OT_ERROR_NONE) {
|
||||
uint8_t *frame = (uint8_t *)malloc(aFrame->mLength + 1);
|
||||
if (frame) {
|
||||
esp_ieee802154_frame_info_t ack_info;
|
||||
frame[0] = aFrame->mLength;
|
||||
memcpy((void *)(frame + 1), aFrame->mPsdu, frame[0]);
|
||||
s_esp_radio_spinel_callbacks[idx].diag_transmit_done(frame, &ack_info);
|
||||
free(frame);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to alloc memory for frame");
|
||||
}
|
||||
} else {
|
||||
switch (aError) {
|
||||
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
|
||||
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
||||
break;
|
||||
case OT_ERROR_NO_ACK:
|
||||
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_NO_ACK);
|
||||
break;
|
||||
default:
|
||||
s_esp_radio_spinel_callbacks[idx].diag_transmit_failed(ESP_IEEE802154_TX_ERR_CCA_BUSY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
|
||||
|
||||
void esp_radio_spinel_set_callbacks(const esp_radio_spinel_callbacks_t aCallbacks, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_esp_radio_spinel_callbacks[idx] = aCallbacks;
|
||||
RadioSpinelCallbacks Callbacks;
|
||||
Callbacks.mReceiveDone = ReceiveDone;
|
||||
Callbacks.mTransmitDone = TransmitDone;
|
||||
Callbacks.mEnergyScanDone = EnergyScanDone;
|
||||
Callbacks.mTxStarted = TxStarted;
|
||||
Callbacks.mSwitchoverDone = SwitchoverDone;
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
Callbacks.mDiagReceiveDone = DiagReceiveDone;
|
||||
Callbacks.mDiagTransmitDone = DiagTransmitDone;
|
||||
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
|
||||
s_radio[idx].SetCallbacks(Callbacks);
|
||||
}
|
||||
|
||||
esp_err_t esp_radio_spinel_uart_interface_enable(const esp_radio_spinel_uart_config_t *radio_uart_config,
|
||||
esp_radio_spinel_uart_init_handler aUartInitHandler,
|
||||
esp_radio_spinel_uart_deinit_handler aUartDeinitHandler,
|
||||
esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(aUartInitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartInitHandler can not be set to NULL");
|
||||
ESP_RETURN_ON_FALSE(aUartDeinitHandler != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "UartDeinitHandler can not be set to NULL");
|
||||
s_spinel_interface[idx].GetSpinelInterface().RegisterUartInitHandler(aUartInitHandler);
|
||||
s_spinel_interface[idx].GetSpinelInterface().RegisterUartDeinitHandler(aUartDeinitHandler);
|
||||
ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Enable(*radio_uart_config) == OT_ERROR_NONE, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Spinel UART interface failed to enable");
|
||||
ESP_LOGI(ESP_SPINEL_LOG_TAG, "Spinel UART interface has been successfully enabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_radio_spinel_init(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||
|
||||
// Multipan is not currently supported
|
||||
iidList[0] = 0;
|
||||
s_radio[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_enable(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
otInstance *instance = get_instance_from_index(idx);
|
||||
s_radio[idx].Enable(instance);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE, SPINEL_DATATYPE_INT32_S, static_cast<int32_t>(pending_mode));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].GetIeeeEui64(eui64));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_panid(uint16_t panid, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].SetPanId(panid));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_short_address(uint16_t short_address, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].SetShortAddress(short_address));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
otExtAddress aExtAddress;
|
||||
memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE);
|
||||
SuccessOrDie(s_radio[idx].SetExtendedAddress(aExtAddress));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR, SPINEL_DATATYPE_BOOL_S, enable);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].Receive(channel);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_energy_scan(uint8_t scan_channel, uint16_t scan_duration, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].EnergyScan(scan_channel, scan_duration);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_transmit(uint8_t *frame, uint8_t channel, bool cca, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_transmit_frame.mLength = frame[0];
|
||||
s_transmit_frame.mPsdu = frame + 1;
|
||||
s_transmit_frame.mInfo.mTxInfo.mCsmaCaEnabled = cca;
|
||||
s_transmit_frame.mChannel = channel;
|
||||
s_transmit_frame.mInfo.mTxInfo.mRxChannelAfterTxDone = channel;
|
||||
SuccessOrDie(s_radio[idx].Transmit(s_transmit_frame));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_clear_short_entries(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].ClearSrcMatchShortEntries());
|
||||
}
|
||||
|
||||
esp_err_t esp_radio_spinel_add_short_entry(uint16_t short_address, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
return (s_radio[idx].AddSrcMatchShortEntry(short_address) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
void esp_radio_spinel_clear_extened_entries(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].ClearSrcMatchExtEntries());
|
||||
}
|
||||
|
||||
esp_err_t esp_radio_spinel_add_extened_entry(uint8_t *ext_address, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
otExtAddress aExtAddress;
|
||||
memcpy(aExtAddress.m8, (void *)ext_address, OT_EXT_ADDRESS_SIZE);
|
||||
return (s_radio[idx].AddSrcMatchExtEntry(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
SuccessOrDie(s_radio[idx].SetPromiscuous(enable));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_spinel_interface[idx].GetSpinelInterface().UpdateFdSet(static_cast<void *>(mainloop_context));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].Process(static_cast<void *>(mainloop_context));
|
||||
}
|
||||
|
||||
void esp_radio_spinel_sleep(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].Sleep();
|
||||
}
|
||||
|
||||
void esp_radio_spinel_set_tx_power(int8_t power, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_radio[idx].SetTransmitPower(power);
|
||||
}
|
||||
|
||||
void esp_radio_spinel_get_tx_power(int8_t *power, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
int8_t aPower;
|
||||
s_radio[idx].GetTransmitPower(aPower);
|
||||
*power = aPower;
|
||||
}
|
||||
|
||||
void esp_radio_spinel_register_rcp_failure_handler(esp_radio_spinel_rcp_failure_handler handler, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
s_spinel_interface[idx].GetSpinelInterface().RegisterRcpFailureHandler(handler);
|
||||
}
|
||||
|
||||
esp_err_t esp_radio_spinel_rcp_deinit(esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
if (s_radio[idx].IsEnabled()) {
|
||||
ESP_RETURN_ON_FALSE(s_radio[idx].Sleep() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Radio fails to sleep");
|
||||
ESP_RETURN_ON_FALSE(s_radio[idx].Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to disable radio");
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(s_spinel_interface[idx].GetSpinelInterface().Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, ESP_SPINEL_LOG_TAG, "Fail to deinitialize UART");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_spinel_idx_t idx)
|
||||
{
|
||||
const char *rcp_version = s_radio[idx].GetVersion();
|
||||
ESP_RETURN_ON_FALSE(rcp_version != nullptr, ESP_FAIL, ESP_SPINEL_LOG_TAG, "Fail to get rcp version");
|
||||
strcpy(running_rcp_version, rcp_version);
|
||||
return ESP_OK;
|
||||
}
|
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_radio_spinel_uart_interface.hpp"
|
||||
#include <errno.h>
|
||||
#include <sys/unistd.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_openthread_common_macro.h"
|
||||
#include "openthread/platform/time.h"
|
||||
#include "hdlc.hpp"
|
||||
|
||||
namespace esp {
|
||||
namespace radio_spinel {
|
||||
|
||||
UartSpinelInterface::UartSpinelInterface(void)
|
||||
: m_receiver_frame_callback(nullptr)
|
||||
, m_receiver_frame_context(nullptr)
|
||||
, m_receive_frame_buffer(nullptr)
|
||||
, m_uart_fd(-1)
|
||||
, mRcpFailureHandler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
UartSpinelInterface::~UartSpinelInterface(void)
|
||||
{
|
||||
Deinit();
|
||||
}
|
||||
|
||||
otError UartSpinelInterface::Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
m_receiver_frame_callback = aCallback;
|
||||
m_receiver_frame_context = aCallbackContext;
|
||||
m_receive_frame_buffer = &aFrameBuffer;
|
||||
m_hdlc_decoder.Init(aFrameBuffer, HandleHdlcFrame, this);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void UartSpinelInterface::Deinit(void)
|
||||
{
|
||||
m_receiver_frame_callback = nullptr;
|
||||
m_receiver_frame_context = nullptr;
|
||||
m_receive_frame_buffer = nullptr;
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::Enable(const esp_radio_spinel_uart_config_t &radio_uart_config)
|
||||
{
|
||||
esp_err_t error = ESP_OK;
|
||||
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;
|
||||
}
|
||||
|
||||
error = InitUart(radio_uart_config);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGI(ESP_SPINEL_LOG_TAG, "spinel UART interface initialization completed");
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::Disable(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::Spinel::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) {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "send radio frame failed");
|
||||
} else {
|
||||
ESP_LOGD(ESP_SPINEL_LOG_TAG, "sent radio frame");
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void UartSpinelInterface::Process(const void *aMainloopContext)
|
||||
{
|
||||
if (FD_ISSET(m_uart_fd, &((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->read_fds)) {
|
||||
ESP_LOGD(ESP_SPINEL_LOG_TAG, "radio uart read event");
|
||||
TryReadAndDecode();
|
||||
}
|
||||
}
|
||||
|
||||
int UartSpinelInterface::TryReadAndDecode(void)
|
||||
{
|
||||
uint8_t buffer[UART_HW_FIFO_LEN(m_uart_config.port)];
|
||||
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) {
|
||||
ESP_LOGD(ESP_SPINEL_LOG_TAG, "received hdlc radio frame");
|
||||
m_receiver_frame_callback(m_receiver_frame_context);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error));
|
||||
m_receive_frame_buffer->DiscardFrame();
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::InitUart(const esp_radio_spinel_uart_config_t &radio_uart_config)
|
||||
{
|
||||
if (mUartInitHandler) {
|
||||
m_uart_config = radio_uart_config;
|
||||
return mUartInitHandler(&m_uart_config, &m_uart_fd);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "None mUartInitHandler");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::DeinitUart(void)
|
||||
{
|
||||
if (mUartDeinitHandler) {
|
||||
return mUartDeinitHandler(&m_uart_config, &m_uart_fd);
|
||||
} else {
|
||||
ESP_LOGE(ESP_SPINEL_LOG_TAG, "None mUartDeinitHandler");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::TryRecoverUart(void)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(DeinitUart(), ESP_SPINEL_LOG_TAG, "DeInitUart failed");
|
||||
ESP_RETURN_ON_ERROR(InitUart(m_uart_config), ESP_SPINEL_LOG_TAG, "InitUart failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
otError UartSpinelInterface::HardwareReset(void)
|
||||
{
|
||||
if (mRcpFailureHandler) {
|
||||
mRcpFailureHandler();
|
||||
TryRecoverUart();
|
||||
}
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
void UartSpinelInterface::UpdateFdSet(void *aMainloopContext)
|
||||
{
|
||||
// Register only READ events for radio UART and always wait
|
||||
// for a radio WRITE to complete.
|
||||
FD_SET(m_uart_fd, &((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->read_fds);
|
||||
if (m_uart_fd > ((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->max_fd) {
|
||||
((esp_radio_spinel_mainloop_context_t *)aMainloopContext)->max_fd = m_uart_fd;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t UartSpinelInterface::GetBusSpeed(void) const
|
||||
{
|
||||
return m_uart_config.uart_config.baud_rate;
|
||||
}
|
||||
} // namespace radio_spinel
|
||||
} // namespace esp
|
Loading…
Reference in New Issue
Block a user