mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(openthread): support multipan feature for host device
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_OPENTHREAD_MULTIPAN_HOST_ENABLE
|
||||
#define ESP_RADIO_SPINEL_IID_LIST_LEN 2
|
||||
#define ESP_RADIO_SPINEL_HOST_INTERFACE_COUNT CONFIG_OPENTHREAD_MULTIPLE_INTERFACES_COUNT
|
||||
#else
|
||||
#define ESP_RADIO_SPINEL_IID_LIST_LEN 1
|
||||
#endif
|
||||
@@ -7,8 +7,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_radio_spinel.h"
|
||||
#include "esp_radio_spinel_uart_transport.hpp"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "openthread/error.h"
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
#include "esp_openthread_types.h"
|
||||
@@ -18,7 +18,11 @@ namespace esp {
|
||||
namespace radio_spinel {
|
||||
|
||||
/**
|
||||
* This class defines an UART interface to the Radio Co-processor (RCP).
|
||||
* This class defines a UART spinel interface to the Radio Co-processor (RCP).
|
||||
*
|
||||
* HDLC and UART I/O are owned by the transport layer. This class only waits on
|
||||
* the transport wait fd. Complete spinel frames are delivered by the transport
|
||||
* into the RxFrameBuffer bound at Init, via the receive callback.
|
||||
*
|
||||
*/
|
||||
class UartSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||
@@ -65,7 +69,7 @@ public:
|
||||
* @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.
|
||||
* @retval OT_ERROR_FAILED Failed to call the UART driver to send the frame.
|
||||
*
|
||||
*/
|
||||
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
@@ -73,10 +77,10 @@ public:
|
||||
/**
|
||||
* Waits for receiving part or all of spinel frame within specified interval.
|
||||
*
|
||||
* @param[in] aTimeout The timeout value in microseconds.
|
||||
* @param[in] aTimeoutUs 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.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeoutUs.
|
||||
*
|
||||
*/
|
||||
otError WaitForFrame(uint64_t aTimeoutUs);
|
||||
@@ -138,80 +142,69 @@ public:
|
||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
||||
|
||||
/**
|
||||
* @brief This method enable the HDLC interface.
|
||||
* Enable the spinel UART transport.
|
||||
*
|
||||
* Multipan: allocates a free spinel IID. Use GetIid() after Enable succeeds.
|
||||
*
|
||||
* @param[in] radio_uart_config UART configuration.
|
||||
* @param[in] hooks Optional UART init/deinit hooks. May be nullptr.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NO_MEM if allocation has failed
|
||||
* - ESP_ERROR on failure
|
||||
* - ESP_ERR_INVALID_STATE if already enabled
|
||||
* - ESP_ERR_NO_MEM if a multipan host slot or rx queue cannot be allocated
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Enable(const esp_radio_spinel_uart_config_t &radio_uart_config);
|
||||
esp_err_t Enable(const esp_radio_spinel_uart_config_t &radio_uart_config,
|
||||
const esp_radio_spinel_uart_transport_hooks_t *hooks = nullptr);
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
esp_err_t Enable(const esp_openthread_uart_config_t &radio_uart_config);
|
||||
/**
|
||||
* Enable the spinel UART transport using OpenThread UART config.
|
||||
*
|
||||
* @param[in] radio_uart_config OpenThread UART configuration.
|
||||
* @param[in] hooks Optional UART init/deinit hooks. May be nullptr.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if already enabled
|
||||
* - ESP_ERR_NO_MEM if a multipan host slot or rx queue cannot be allocated
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Enable(const esp_openthread_uart_config_t &radio_uart_config,
|
||||
const esp_radio_spinel_uart_transport_hooks_t *hooks = nullptr);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This method disable the HDLC interface.
|
||||
* Disable the spinel UART transport.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Disable(void);
|
||||
|
||||
void RegisterUartInitHandler(esp_radio_spinel_uart_init_handler handler)
|
||||
{
|
||||
if (mUartInitHandler != NULL) {
|
||||
ESP_LOGW(ESP_SPINEL_LOG_TAG, "UartInitHandler already registered, will overwrite (prev=%p, new=%p)", mUartInitHandler, handler);
|
||||
}
|
||||
mUartInitHandler = handler;
|
||||
}
|
||||
|
||||
void RegisterUartDeinitHandler(esp_radio_spinel_uart_deinit_handler handler) { mUartDeinitHandler = handler; }
|
||||
/**
|
||||
* Returns the allocated spinel IID.
|
||||
*
|
||||
* Valid after Enable() succeeds. Returns -1 if the interface is not enabled.
|
||||
*
|
||||
*/
|
||||
int8_t GetIid(void) const { return m_iid; }
|
||||
|
||||
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);
|
||||
int TryReadSpinel(void);
|
||||
|
||||
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;
|
||||
|
||||
int m_wait_fd;
|
||||
int8_t m_iid;
|
||||
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||
esp_radio_spinel_rcp_failure_handler mRcpFailureHandler;
|
||||
|
||||
// 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;
|
||||
|
||||
ot::Spinel::FrameBuffer<kMaxFrameSize> encoder_buffer;
|
||||
};
|
||||
|
||||
} // namespace radio_spinel
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_radio_spinel.h"
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
|
||||
/**
|
||||
* Optional UART open/close hooks. Used by the non-multipan transport.
|
||||
* The multipan transport ignores them (UART is owned by esp_radio_spinel_multipan_init()).
|
||||
*/
|
||||
typedef struct {
|
||||
esp_radio_spinel_uart_init_handler uart_init; /* May be NULL. */
|
||||
esp_radio_spinel_uart_deinit_handler uart_deinit; /* May be NULL. */
|
||||
} esp_radio_spinel_uart_transport_hooks_t;
|
||||
|
||||
/**
|
||||
* Open the UART spinel transport.
|
||||
*
|
||||
* Non-multipan: opens the real UART and returns that fd as wait_fd. @p iid is set to 0.
|
||||
* Multipan: allocates a free IID slot and returns an eventfd as wait_fd.
|
||||
*
|
||||
* @param[in] config UART config. Non-multipan uses it to open the port.
|
||||
* Multipan may ignore it if esp_radio_spinel_multipan_init() already ran.
|
||||
* @param[in] hooks Optional UART init/deinit hooks. May be NULL.
|
||||
* @param[out] iid Allocated spinel interface id.
|
||||
* @param[out] wait_fd Fd to select for a readable spinel frame.
|
||||
*
|
||||
* @return ESP_OK on success, an error code otherwise.
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_uart_transport_open(const esp_radio_spinel_uart_config_t *config,
|
||||
const esp_radio_spinel_uart_transport_hooks_t *hooks, int8_t *iid,
|
||||
int *wait_fd);
|
||||
|
||||
/**
|
||||
* Close the transport opened for @p iid.
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_uart_transport_close(int8_t iid);
|
||||
|
||||
/**
|
||||
* Bind the RadioSpinel receive buffer and callback for @p iid.
|
||||
*
|
||||
* Called from UartSpinelInterface::Init (and Enable if Init already ran).
|
||||
* Non-multipan attaches the buffer to the HDLC decoder.
|
||||
* Multipan stores them on the host slot and invokes the callback from read().
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_uart_transport_bind_rx(int8_t iid,
|
||||
ot::Spinel::SpinelInterface::ReceiveFrameCallback callback,
|
||||
void *context,
|
||||
ot::Spinel::SpinelInterface::RxFrameBuffer *frame_buffer);
|
||||
|
||||
/**
|
||||
* Undo bind_rx for @p iid.
|
||||
*
|
||||
* Non-multipan detaches the HDLC decoder from the RxFrameBuffer.
|
||||
* Multipan clears the host slot's buffer and callback.
|
||||
* Safe to call if nothing is bound.
|
||||
*/
|
||||
void esp_radio_spinel_uart_transport_unbind_rx(int8_t iid);
|
||||
|
||||
/**
|
||||
* Drain the transport for @p iid.
|
||||
*
|
||||
* Non-multipan: reads UART and HDLC-decodes into the bound RxFrameBuffer.
|
||||
* Complete frames are delivered via the callback registered with bind_rx.
|
||||
* Multipan: dequeues pending spinel frames, copies each into the bound
|
||||
* RxFrameBuffer, then invokes the same callback.
|
||||
*
|
||||
* @return 0 on success (including no complete frame), -1 on error.
|
||||
*/
|
||||
int esp_radio_spinel_uart_transport_read(int8_t iid);
|
||||
|
||||
/**
|
||||
* Write one complete spinel frame (HDLC-encoded internally).
|
||||
*
|
||||
* @return @p len on success, -1 on error.
|
||||
*/
|
||||
ssize_t esp_radio_spinel_uart_transport_write(int8_t iid, const void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Re-install the UART after a bus error. Client wait fds stay valid.
|
||||
*/
|
||||
esp_err_t esp_radio_spinel_uart_transport_recover(int8_t iid);
|
||||
|
||||
/**
|
||||
* UART baud rate in bits/second.
|
||||
*/
|
||||
uint32_t esp_radio_spinel_uart_transport_get_bus_speed(int8_t iid);
|
||||
@@ -469,6 +469,49 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CONFIG_OPENTHREAD_MULTIPAN_HOST_ENABLE
|
||||
/**
|
||||
* @def OPENTHREAD_SPINEL_CONFIG_BROADCAST_IID
|
||||
*
|
||||
* Define broadcast IID for spinel frames dedicated to all hosts in multipan configuration.
|
||||
*/
|
||||
#ifdef OPENTHREAD_SPINEL_CONFIG_BROADCAST_IID
|
||||
#error `OPENTHREAD_SPINEL_CONFIG_BROADCAST_IID` is redefined.
|
||||
#endif
|
||||
#define OPENTHREAD_SPINEL_CONFIG_BROADCAST_IID SPINEL_HEADER_IID(CONFIG_OPENTHREAD_MULTIPLE_INTERFACES_COUNT)
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_SPINEL_CONFIG_MAX_INTERFACE_ID
|
||||
*
|
||||
* Specifies the maximum number of Spinel interface IDs.
|
||||
*/
|
||||
#ifdef OPENTHREAD_SPINEL_CONFIG_MAX_INTERFACE_ID
|
||||
#error `OPENTHREAD_SPINEL_CONFIG_MAX_INTERFACE_ID` is redefined.
|
||||
#endif
|
||||
#define OPENTHREAD_SPINEL_CONFIG_MAX_INTERFACE_ID 2
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
|
||||
*
|
||||
* Enables compilation of vendor specific code for Spinel
|
||||
*/
|
||||
#ifdef OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
|
||||
#error `OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE` is redefined.
|
||||
#endif
|
||||
#define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 1
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
|
||||
*
|
||||
* Define to 1 to enable multipan RCP support.
|
||||
*/
|
||||
#ifdef OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
|
||||
#error `OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE` is redefined.
|
||||
#endif
|
||||
#define OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE 1
|
||||
|
||||
#endif // CONFIG_OPENTHREAD_MULTIPAN_HOST_ENABLE
|
||||
|
||||
/*----The following options set fixed default values but can be overridden by the user header file.----*/
|
||||
|
||||
#if CONFIG_OPENTHREAD_BORDER_ROUTER
|
||||
|
||||
Reference in New Issue
Block a user