mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(openthread): modification of uart and spi spinel based on openthread 41ef807
This commit is contained in:
parent
0281aa844b
commit
e88dc25226
@ -18,6 +18,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
||||
"openthread/include/openthread"
|
||||
"openthread/src"
|
||||
"openthread/src/core"
|
||||
"openthread/src/lib"
|
||||
"openthread/src/lib/hdlc"
|
||||
"openthread/src/lib/spinel"
|
||||
"openthread/src/ncp"
|
||||
@ -31,6 +32,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
||||
"openthread/src/core/common"
|
||||
"openthread/src/core/crypto"
|
||||
"openthread/src/core/diags"
|
||||
"openthread/src/core/instance"
|
||||
"openthread/src/core/mac"
|
||||
"openthread/src/core/radio"
|
||||
"openthread/src/core/thread"
|
||||
@ -41,7 +43,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
||||
set(exclude_srcs
|
||||
"openthread/examples/platforms/utils/logging_rtt.c"
|
||||
"openthread/examples/platforms/utils/soft_source_match_table.c"
|
||||
"openthread/src/core/common/extension_example.cpp")
|
||||
"openthread/src/core/instance/extension_example.cpp")
|
||||
|
||||
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
|
||||
list(APPEND src_dirs
|
||||
|
@ -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
|
||||
*/
|
||||
@ -69,8 +69,22 @@ void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_hand
|
||||
/**
|
||||
* @brief Deinitializes the conneciton to RCP.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if fail to deinitialize RCP
|
||||
*
|
||||
*/
|
||||
void esp_openthread_rcp_deinit(void);
|
||||
esp_err_t esp_openthread_rcp_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes the conneciton to RCP.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL if fail to initialize RCP
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_openthread_rcp_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 12f563ee490236f7332eb22f568e71c7c1d4a3b7
|
||||
Subproject commit 648c28e792567bc00602c92e43518c1784599251
|
@ -1 +1 @@
|
||||
Subproject commit af5938e389be40650507748272bb6c6b3a2de2cf
|
||||
Subproject commit 41ef80717f4b757440125932723cc8721ef42f7f
|
@ -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
|
||||
*/
|
||||
|
@ -14,18 +14,12 @@
|
||||
namespace esp {
|
||||
namespace openthread {
|
||||
|
||||
class SpiSpinelInterface {
|
||||
class SpiSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||
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.
|
||||
*
|
||||
*/
|
||||
SpiSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback, void *callback_context,
|
||||
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
|
||||
SpiSpinelInterface();
|
||||
|
||||
/**
|
||||
* @brief This destructor of the object.
|
||||
@ -34,24 +28,26 @@ public:
|
||||
~SpiSpinelInterface(void);
|
||||
|
||||
/**
|
||||
* @brief This method initializes the spinel interface.
|
||||
* 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.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if already initialized
|
||||
* - ESP_ERR_NO_MEM if allocation has failed
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Init(const esp_openthread_spi_host_config_t &spi_config);
|
||||
otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
/**
|
||||
* @brief This method deinitializes the HDLC interface.
|
||||
* Deinitializes the interface to the RCP.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Deinit(void);
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
|
||||
@ -80,20 +76,42 @@ public:
|
||||
otError WaitForFrame(uint64_t timeout_us);
|
||||
|
||||
/**
|
||||
* This method performs spi processing to the RCP.
|
||||
* Updates the file descriptor sets with file descriptors used by the radio driver.
|
||||
*
|
||||
* @param[in] mainloop The mainloop context
|
||||
* @param[in,out] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Process(const void *mainloop);
|
||||
void UpdateFdSet(void *aMainloopContext);
|
||||
|
||||
/**
|
||||
* This methods updates the mainloop context.
|
||||
* Performs radio driver processing.
|
||||
*
|
||||
* @param[inout] mainloop The mainloop context.
|
||||
* @param[in] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Update(void *mainloop);
|
||||
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;
|
||||
|
||||
/**
|
||||
* This method is called when RCP failure detected and resets internal states of the interface.
|
||||
*
|
||||
*/
|
||||
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.
|
||||
@ -111,10 +129,33 @@ public:
|
||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
||||
|
||||
/**
|
||||
* This method is called when RCP failure detected and resets internal states of the interface.
|
||||
* @brief This method enable the spinel interface.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if already initialized
|
||||
* - ESP_ERR_NO_MEM if allocation has failed
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
otError HardwareReset(void);
|
||||
esp_err_t Enable(const esp_openthread_spi_host_config_t &spi_config);
|
||||
|
||||
/**
|
||||
* @brief This method disable the spinel interface.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t Disable(void);
|
||||
|
||||
/**
|
||||
* @brief This method should be called after radio is initialized.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on failure
|
||||
*/
|
||||
esp_err_t AfterRadioInit(void);
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kSPIFrameHeaderSize = 5;
|
||||
@ -130,14 +171,16 @@ private:
|
||||
int m_event_fd;
|
||||
volatile uint16_t m_pending_data_len;
|
||||
|
||||
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback;
|
||||
ReceiveFrameCallback m_receiver_frame_callback;
|
||||
void *m_receiver_frame_context;
|
||||
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer;
|
||||
RxFrameBuffer *m_receive_frame_buffer;
|
||||
bool m_has_pending_device_frame;
|
||||
|
||||
spi_device_handle_t m_device;
|
||||
|
||||
esp_openthread_rcp_failure_handler mRcpFailureHandler;
|
||||
|
||||
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||
};
|
||||
|
||||
} // namespace openthread
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "lib/hdlc/hdlc.hpp"
|
||||
#include "openthread/error.h"
|
||||
|
||||
namespace esp {
|
||||
namespace openthread {
|
||||
|
||||
/**
|
||||
* This class defines an template to adapt both UartSpinelInterface and SpiSpinelInterface.
|
||||
*
|
||||
*/
|
||||
template <typename InterfaceType> class SpinelInterfaceAdapter {
|
||||
public:
|
||||
/**
|
||||
* @brief This constructor of object.
|
||||
*/
|
||||
SpinelInterfaceAdapter(void) {}
|
||||
|
||||
/**
|
||||
* @brief This destructor of the object.
|
||||
*
|
||||
*/
|
||||
~SpinelInterfaceAdapter(void) {}
|
||||
|
||||
/**
|
||||
* @brief This method return the underlying spinel interface.
|
||||
*
|
||||
* @return The underlying spinel interface.
|
||||
*
|
||||
*/
|
||||
InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
|
||||
|
||||
private:
|
||||
InterfaceType mSpinelInterface;
|
||||
};
|
||||
|
||||
} // namespace openthread
|
||||
} // namespace esp
|
@ -21,18 +21,12 @@ namespace openthread {
|
||||
* This class defines an UART interface to the Radio Co-processor (RCP).
|
||||
*
|
||||
*/
|
||||
class UartSpinelInterface {
|
||||
class UartSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||
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);
|
||||
UartSpinelInterface(void);
|
||||
|
||||
/**
|
||||
* @brief This destructor of the object.
|
||||
@ -41,65 +35,92 @@ public:
|
||||
~UartSpinelInterface(void);
|
||||
|
||||
/**
|
||||
* @brief This method initializes the HDLC interface.
|
||||
* 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.
|
||||
*
|
||||
* @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);
|
||||
otError Init(ReceiveFrameCallback aCallback, void *aCallbackContext, RxFrameBuffer &aFrameBuffer);
|
||||
|
||||
/**
|
||||
* @brief This method deinitializes the HDLC interface.
|
||||
* Deinitializes the interface to the RCP.
|
||||
*
|
||||
*/
|
||||
esp_err_t Deinit(void);
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* @brief This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
|
||||
* 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] aFrame A pointer to buffer containing the spinel frame to send.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @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`.
|
||||
* @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 *frame, uint16_t length);
|
||||
otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method waits for receiving part or all of spinel frame within specified timeout.
|
||||
* Waits for receiving part or all of spinel frame within specified interval.
|
||||
*
|
||||
* @param[in] timeout_us The timeout value in microseconds.
|
||||
* @param[in] aTimeout 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.
|
||||
* @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 timeout_us);
|
||||
otError WaitForFrame(uint64_t aTimeoutUs);
|
||||
|
||||
/**
|
||||
* This method performs uart processing to the RCP.
|
||||
* Updates the file descriptor sets with file descriptors used by the radio driver.
|
||||
*
|
||||
* @param[in] mainloop The mainloop context
|
||||
* @param[in,out] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Process(const void *mainloop);
|
||||
void UpdateFdSet(void *aMainloopContext);
|
||||
|
||||
/**
|
||||
* This methods updates the mainloop context.
|
||||
* Performs radio driver processing.
|
||||
*
|
||||
* @param[inout] mainloop The mainloop context.
|
||||
* @param[in] aMainloopContext A pointer to the mainloop context.
|
||||
*
|
||||
*/
|
||||
void Update(void *mainloop);
|
||||
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.
|
||||
@ -109,12 +130,6 @@ public:
|
||||
*/
|
||||
void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; }
|
||||
|
||||
/**
|
||||
* This method is called when RCP failure detected and resets internal states of the interface.
|
||||
*
|
||||
*/
|
||||
otError HardwareReset(void);
|
||||
|
||||
/**
|
||||
* This method is called when RCP is reset to recreate the connection with it.
|
||||
* Intentionally empty.
|
||||
@ -122,14 +137,25 @@ public:
|
||||
*/
|
||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
||||
|
||||
private:
|
||||
enum {
|
||||
/**
|
||||
* Maximum spinel frame size.
|
||||
*
|
||||
*/
|
||||
kMaxFrameSize = ot::Spinel::SpinelInterface::kMaxFrameSize,
|
||||
/**
|
||||
* @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_openthread_uart_config_t &radio_uart_config);
|
||||
|
||||
/**
|
||||
* @brief This method disable the HDLC interface.
|
||||
*
|
||||
*/
|
||||
esp_err_t Disable(void);
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
/**
|
||||
* Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||
*
|
||||
@ -152,9 +178,9 @@ private:
|
||||
static void HandleHdlcFrame(void *context, otError error);
|
||||
void HandleHdlcFrame(otError error);
|
||||
|
||||
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback;
|
||||
ReceiveFrameCallback m_receiver_frame_callback;
|
||||
void *m_receiver_frame_context;
|
||||
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer;
|
||||
RxFrameBuffer *m_receive_frame_buffer;
|
||||
|
||||
ot::Hdlc::Decoder m_hdlc_decoder;
|
||||
uint8_t *m_uart_rx_buffer;
|
||||
@ -162,6 +188,8 @@ private:
|
||||
esp_openthread_uart_config_t m_uart_config;
|
||||
int m_uart_fd;
|
||||
|
||||
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||
|
||||
// Non-copyable, intentionally not implemented.
|
||||
UartSpinelInterface(const UartSpinelInterface &);
|
||||
UartSpinelInterface &operator=(const UartSpinelInterface &);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "esp_partition.h"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "core/common/instance.hpp"
|
||||
#include "core/instance/instance.hpp"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "openthread/cli.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "esp_openthread_platform.h"
|
||||
#include "esp_openthread_types.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_spinel_interface.hpp"
|
||||
#include "esp_spi_spinel_interface.hpp"
|
||||
#include "esp_uart_spinel_interface.hpp"
|
||||
#include "openthread-core-config.h"
|
||||
@ -20,41 +21,100 @@
|
||||
#include "lib/spinel/spinel.h"
|
||||
#include "openthread/platform/diag.h"
|
||||
#include "openthread/platform/radio.h"
|
||||
#include "platform/exit_code.h"
|
||||
|
||||
using ot::Spinel::RadioSpinel;
|
||||
using esp::openthread::SpinelInterfaceAdapter;
|
||||
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
using esp::openthread::UartSpinelInterface;
|
||||
static RadioSpinel<UartSpinelInterface> s_radio;
|
||||
static SpinelInterfaceAdapter<UartSpinelInterface> s_spinel_interface;
|
||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||
using esp::openthread::SpiSpinelInterface;
|
||||
static RadioSpinel<SpiSpinelInterface> s_radio;
|
||||
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
static SpinelInterfaceAdapter<SpiSpinelInterface> s_spinel_interface;
|
||||
#endif
|
||||
|
||||
static RadioSpinel s_radio;
|
||||
|
||||
static const char *radiospinel_workflow = "radio_spinel";
|
||||
|
||||
static const esp_openthread_radio_config_t *s_esp_openthread_radio_config = NULL;
|
||||
|
||||
static void esp_openthread_radio_config_set(const esp_openthread_radio_config_t *config)
|
||||
{
|
||||
s_esp_openthread_radio_config = config;
|
||||
}
|
||||
|
||||
static const esp_openthread_radio_config_t *esp_openthread_radio_config_get(void)
|
||||
{
|
||||
return s_esp_openthread_radio_config;
|
||||
}
|
||||
|
||||
esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config)
|
||||
{
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG,
|
||||
spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||
iidList[0] = 0;
|
||||
|
||||
ot::Spinel::RadioSpinelCallbacks callbacks;
|
||||
#if CONFIG_OPENTHREAD_DIAG
|
||||
callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone;
|
||||
callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone;
|
||||
#endif // OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone;
|
||||
callbacks.mReceiveDone = otPlatRadioReceiveDone;
|
||||
callbacks.mTransmitDone = otPlatRadioTxDone;
|
||||
callbacks.mTxStarted = otPlatRadioTxStarted;
|
||||
s_radio.SetCallbacks(callbacks);
|
||||
|
||||
esp_openthread_radio_config_set(&config->radio_config);
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG,
|
||||
"Spinel interface init falied");
|
||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG,
|
||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG,
|
||||
"Spinel interface init failed");
|
||||
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
s_radio.Init(/*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false);
|
||||
#endif
|
||||
s_radio.Init(s_spinel_interface.GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid);
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_SPI // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().AfterRadioInit(), OT_PLAT_LOG_TAG, "Spinel interface init falied");
|
||||
#endif
|
||||
return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process,
|
||||
radiospinel_workflow);
|
||||
}
|
||||
|
||||
void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler)
|
||||
{
|
||||
s_radio.GetSpinelInterface().RegisterRcpFailureHandler(handler);
|
||||
s_spinel_interface.GetSpinelInterface().RegisterRcpFailureHandler(handler);
|
||||
}
|
||||
|
||||
void esp_openthread_rcp_deinit(void)
|
||||
esp_err_t esp_openthread_rcp_deinit(void)
|
||||
{
|
||||
s_radio.GetSpinelInterface().Deinit();
|
||||
ESP_RETURN_ON_FALSE(otThreadGetDeviceRole(esp_openthread_get_instance()) == OT_DEVICE_ROLE_DISABLED, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Thread is enabled, failed to deinitialize RCP");
|
||||
ESP_RETURN_ON_FALSE(!otIp6IsEnabled(esp_openthread_get_instance()), ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OT interface is up, failed to deinitialize RCP");
|
||||
if (s_radio.IsEnabled()) {
|
||||
ESP_RETURN_ON_FALSE(s_radio.Sleep() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Radio fails to sleep");
|
||||
ESP_RETURN_ON_FALSE(s_radio.Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Fail to disable radio");
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(s_spinel_interface.GetSpinelInterface().Disable() == OT_ERROR_NONE, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "Fail to deinitialize UART");
|
||||
esp_openthread_platform_workflow_unregister(radiospinel_workflow);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_openthread_rcp_init(void)
|
||||
{
|
||||
const esp_openthread_radio_config_t *radio_config = esp_openthread_radio_config_get();
|
||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_uart_config), OT_PLAT_LOG_TAG,
|
||||
"Spinel interface init falied");
|
||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_spi_config), OT_PLAT_LOG_TAG,
|
||||
"Spinel interface init failed");
|
||||
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
||||
|
||||
ESP_RETURN_ON_FALSE(s_radio.Enable(esp_openthread_get_instance()) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, "Fail to enable radio");
|
||||
s_radio.RestoreProperties();
|
||||
return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process,
|
||||
radiospinel_workflow);
|
||||
}
|
||||
|
||||
void esp_openthread_radio_deinit(void)
|
||||
@ -72,7 +132,7 @@ esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthrea
|
||||
|
||||
void esp_openthread_radio_update(esp_openthread_mainloop_context_t *mainloop)
|
||||
{
|
||||
s_radio.GetSpinelInterface().Update((void *)mainloop);
|
||||
s_spinel_interface.GetSpinelInterface().UpdateFdSet((void *)mainloop);
|
||||
}
|
||||
|
||||
void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64)
|
||||
|
@ -25,17 +25,39 @@ using ot::Spinel::SpinelInterface;
|
||||
namespace esp {
|
||||
namespace openthread {
|
||||
|
||||
SpiSpinelInterface::SpiSpinelInterface(SpinelInterface::ReceiveFrameCallback callback, void *callback_context,
|
||||
SpinelInterface::RxFrameBuffer &frame_buffer)
|
||||
SpiSpinelInterface::SpiSpinelInterface(void)
|
||||
: m_event_fd(-1)
|
||||
, m_receiver_frame_callback(callback)
|
||||
, m_receiver_frame_context(callback_context)
|
||||
, m_receive_frame_buffer(frame_buffer)
|
||||
, m_receiver_frame_callback(nullptr)
|
||||
, m_receiver_frame_context(nullptr)
|
||||
, m_receive_frame_buffer(nullptr)
|
||||
, mRcpFailureHandler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t SpiSpinelInterface::Init(const esp_openthread_spi_host_config_t &spi_config)
|
||||
SpiSpinelInterface::~SpiSpinelInterface(void)
|
||||
{
|
||||
Deinit();
|
||||
}
|
||||
|
||||
otError SpiSpinelInterface::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;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void SpiSpinelInterface::Deinit(void)
|
||||
{
|
||||
m_receiver_frame_callback = nullptr;
|
||||
m_receiver_frame_context = nullptr;
|
||||
m_receive_frame_buffer = nullptr;
|
||||
}
|
||||
|
||||
esp_err_t SpiSpinelInterface::Enable(const esp_openthread_spi_host_config_t &spi_config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(m_event_fd < 0, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "event fd was initialized");
|
||||
m_spi_config = spi_config;
|
||||
@ -62,10 +84,16 @@ esp_err_t SpiSpinelInterface::Init(const esp_openthread_spi_host_config_t &spi_c
|
||||
|
||||
ESP_LOGI(OT_PLAT_LOG_TAG, "spinel SPI interface initialization completed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t SpiSpinelInterface::AfterRadioInit(void)
|
||||
{
|
||||
return ConductSPITransaction(true, 0, 0);
|
||||
}
|
||||
|
||||
esp_err_t SpiSpinelInterface::Deinit(void)
|
||||
|
||||
esp_err_t SpiSpinelInterface::Disable(void)
|
||||
{
|
||||
if (m_event_fd >= 0) {
|
||||
close(m_event_fd);
|
||||
@ -80,11 +108,6 @@ esp_err_t SpiSpinelInterface::Deinit(void)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
SpiSpinelInterface::~SpiSpinelInterface(void)
|
||||
{
|
||||
Deinit();
|
||||
}
|
||||
|
||||
otError SpiSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(frame, OT_ERROR_INVALID_ARGS, OT_PLAT_LOG_TAG, "empty frame");
|
||||
@ -113,13 +136,13 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
|
||||
tx_frame.SetHeaderAcceptLen(rx_data_size);
|
||||
|
||||
uint8_t *rx_buffer;
|
||||
otError err = m_receive_frame_buffer.SetSkipLength(kSPIFrameHeaderSize);
|
||||
otError err = m_receive_frame_buffer->SetSkipLength(kSPIFrameHeaderSize);
|
||||
|
||||
ESP_RETURN_ON_FALSE(err == OT_ERROR_NONE, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "buffer space is insufficient");
|
||||
|
||||
rx_buffer = m_receive_frame_buffer.GetFrame() - kSPIFrameHeaderSize;
|
||||
if (m_receive_frame_buffer.GetFrameMaxLength() < rx_data_size) {
|
||||
rx_data_size = m_receive_frame_buffer.GetFrameMaxLength();
|
||||
rx_buffer = m_receive_frame_buffer->GetFrame() - kSPIFrameHeaderSize;
|
||||
if (m_receive_frame_buffer->GetFrameMaxLength() < rx_data_size) {
|
||||
rx_data_size = m_receive_frame_buffer->GetFrameMaxLength();
|
||||
}
|
||||
uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size;
|
||||
data_size += kSPIFrameHeaderSize;
|
||||
@ -143,7 +166,7 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
|
||||
|
||||
if (rx_frame.IsResetFlagSet()) {
|
||||
ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset");
|
||||
m_receive_frame_buffer.DiscardFrame();
|
||||
m_receive_frame_buffer->DiscardFrame();
|
||||
return ESP_OK;
|
||||
}
|
||||
if (rx_frame.GetHeaderDataLen() == 0 && rx_frame.GetHeaderAcceptLen() == 0) {
|
||||
@ -156,16 +179,16 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
|
||||
if (gpio_get_level(m_spi_config.intr_pin) == 1) {
|
||||
m_pending_data_len = 0;
|
||||
}
|
||||
if (m_receive_frame_buffer.SetLength(rx_frame.GetHeaderDataLen()) != OT_ERROR_NONE) {
|
||||
if (m_receive_frame_buffer->SetLength(rx_frame.GetHeaderDataLen()) != OT_ERROR_NONE) {
|
||||
ESP_LOGW(OT_PLAT_LOG_TAG, "insufficient buffer space to hold a frame of length %d...",
|
||||
rx_frame.GetHeaderDataLen());
|
||||
m_receive_frame_buffer.DiscardFrame();
|
||||
m_receive_frame_buffer->DiscardFrame();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
m_receiver_frame_callback(m_receiver_frame_context);
|
||||
} else {
|
||||
m_pending_data_len = 0;
|
||||
m_receive_frame_buffer.DiscardFrame();
|
||||
m_receive_frame_buffer->DiscardFrame();
|
||||
}
|
||||
m_pending_data_len = 0;
|
||||
|
||||
@ -180,26 +203,26 @@ void SpiSpinelInterface::GpioIntrHandler(void *arg)
|
||||
write(instance->m_event_fd, &event, sizeof(event));
|
||||
}
|
||||
|
||||
void SpiSpinelInterface::Update(void *mainloop)
|
||||
void SpiSpinelInterface::UpdateFdSet(void *aMainloopContext)
|
||||
{
|
||||
if (m_pending_data_len > 0) {
|
||||
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_sec = 0;
|
||||
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_usec = 0;
|
||||
((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_sec = 0;
|
||||
((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_usec = 0;
|
||||
}
|
||||
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds);
|
||||
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->error_fds);
|
||||
if (m_event_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) {
|
||||
((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_event_fd;
|
||||
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds);
|
||||
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds);
|
||||
if (m_event_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd) {
|
||||
((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd = m_event_fd;
|
||||
}
|
||||
}
|
||||
|
||||
void SpiSpinelInterface::Process(const void *mainloop)
|
||||
void SpiSpinelInterface::Process(const void *aMainloopContext)
|
||||
{
|
||||
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->error_fds)) {
|
||||
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds)) {
|
||||
ESP_LOGE(OT_PLAT_LOG_TAG, "SPI INTR GPIO error event");
|
||||
return;
|
||||
}
|
||||
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds)) {
|
||||
if (FD_ISSET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds)) {
|
||||
uint64_t event;
|
||||
read(m_event_fd, &event, sizeof(event));
|
||||
m_pending_data_len = SpinelInterface::kMaxFrameSize;
|
||||
@ -249,5 +272,10 @@ otError SpiSpinelInterface::HardwareReset(void)
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint32_t SpiSpinelInterface::GetBusSpeed(void) const
|
||||
{
|
||||
return m_spi_config.spi_device.clock_speed_hz;
|
||||
}
|
||||
|
||||
} // namespace openthread
|
||||
} // namespace esp
|
||||
|
@ -27,13 +27,10 @@
|
||||
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)
|
||||
UartSpinelInterface::UartSpinelInterface(void)
|
||||
: m_receiver_frame_callback(nullptr)
|
||||
, m_receiver_frame_context(nullptr)
|
||||
, m_receive_frame_buffer(nullptr)
|
||||
, m_uart_fd(-1)
|
||||
, mRcpFailureHandler(nullptr)
|
||||
{
|
||||
@ -41,9 +38,29 @@ UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFra
|
||||
|
||||
UartSpinelInterface::~UartSpinelInterface(void)
|
||||
{
|
||||
Deinit();
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_uart_config)
|
||||
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_openthread_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));
|
||||
@ -56,7 +73,7 @@ esp_err_t UartSpinelInterface::Init(const esp_openthread_uart_config_t &radio_ua
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t UartSpinelInterface::Deinit(void)
|
||||
esp_err_t UartSpinelInterface::Disable(void)
|
||||
{
|
||||
if (m_uart_rx_buffer) {
|
||||
heap_caps_free(m_uart_rx_buffer);
|
||||
@ -88,24 +105,14 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void UartSpinelInterface::Process(const void *mainloop)
|
||||
void UartSpinelInterface::Process(const void *aMainloopContext)
|
||||
{
|
||||
if (FD_ISSET(m_uart_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds)) {
|
||||
if (FD_ISSET(m_uart_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->read_fds)) {
|
||||
ESP_LOGD(OT_PLAT_LOG_TAG, "radio uart read event");
|
||||
TryReadAndDecode();
|
||||
}
|
||||
}
|
||||
|
||||
void UartSpinelInterface::Update(void *mainloop)
|
||||
{
|
||||
// Register only READ events for radio UART and always wait
|
||||
// for a radio WRITE to complete.
|
||||
FD_SET(m_uart_fd, &((esp_openthread_mainloop_context_t *)mainloop)->read_fds);
|
||||
if (m_uart_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) {
|
||||
((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_uart_fd;
|
||||
}
|
||||
}
|
||||
|
||||
int UartSpinelInterface::TryReadAndDecode(void)
|
||||
{
|
||||
uint8_t buffer[UART_HW_FIFO_LEN(m_uart_config.port)];
|
||||
@ -246,7 +253,7 @@ void UartSpinelInterface::HandleHdlcFrame(otError error)
|
||||
m_receiver_frame_callback(m_receiver_frame_context);
|
||||
} else {
|
||||
ESP_LOGE(OT_PLAT_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error));
|
||||
m_receive_frame_buffer.DiscardFrame();
|
||||
m_receive_frame_buffer->DiscardFrame();
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,5 +301,20 @@ otError UartSpinelInterface::HardwareReset(void)
|
||||
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_openthread_mainloop_context_t *)aMainloopContext)->read_fds);
|
||||
if (m_uart_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd) {
|
||||
((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd = m_uart_fd;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t UartSpinelInterface::GetBusSpeed(void) const
|
||||
{
|
||||
return m_uart_config.uart_config.baud_rate;
|
||||
}
|
||||
|
||||
} // namespace openthread
|
||||
} // namespace esp
|
||||
|
Loading…
Reference in New Issue
Block a user