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
6221119c2f
commit
7e469f1330
@ -10,6 +10,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
|||||||
"openthread/include/openthread"
|
"openthread/include/openthread"
|
||||||
"openthread/src"
|
"openthread/src"
|
||||||
"openthread/src/core"
|
"openthread/src/core"
|
||||||
|
"openthread/src/lib"
|
||||||
"openthread/src/lib/hdlc"
|
"openthread/src/lib/hdlc"
|
||||||
"openthread/src/lib/spinel"
|
"openthread/src/lib/spinel"
|
||||||
"openthread/src/ncp"
|
"openthread/src/ncp"
|
||||||
@ -23,6 +24,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
|||||||
"openthread/src/core/common"
|
"openthread/src/core/common"
|
||||||
"openthread/src/core/crypto"
|
"openthread/src/core/crypto"
|
||||||
"openthread/src/core/diags"
|
"openthread/src/core/diags"
|
||||||
|
"openthread/src/core/instance"
|
||||||
"openthread/src/core/mac"
|
"openthread/src/core/mac"
|
||||||
"openthread/src/core/radio"
|
"openthread/src/core/radio"
|
||||||
"openthread/src/core/thread"
|
"openthread/src/core/thread"
|
||||||
@ -33,7 +35,7 @@ if(CONFIG_OPENTHREAD_ENABLED)
|
|||||||
set(exclude_srcs
|
set(exclude_srcs
|
||||||
"openthread/examples/platforms/utils/logging_rtt.c"
|
"openthread/examples/platforms/utils/logging_rtt.c"
|
||||||
"openthread/examples/platforms/utils/soft_source_match_table.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)
|
if(CONFIG_OPENTHREAD_FTD OR CONFIG_OPENTHREAD_MTD)
|
||||||
list(APPEND src_dirs
|
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
|
* 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.
|
* @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
|
#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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -14,18 +14,12 @@
|
|||||||
namespace esp {
|
namespace esp {
|
||||||
namespace openthread {
|
namespace openthread {
|
||||||
|
|
||||||
class SpiSpinelInterface {
|
class SpiSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief This constructor of object.
|
* @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,
|
SpiSpinelInterface();
|
||||||
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This destructor of the object.
|
* @brief This destructor of the object.
|
||||||
@ -34,24 +28,26 @@ public:
|
|||||||
~SpiSpinelInterface(void);
|
~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.
|
* @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);
|
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.
|
* This methods registers the callback for RCP failure.
|
||||||
@ -111,10 +129,33 @@ public:
|
|||||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
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:
|
private:
|
||||||
static constexpr uint8_t kSPIFrameHeaderSize = 5;
|
static constexpr uint8_t kSPIFrameHeaderSize = 5;
|
||||||
@ -130,14 +171,16 @@ private:
|
|||||||
int m_event_fd;
|
int m_event_fd;
|
||||||
volatile uint16_t m_pending_data_len;
|
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;
|
void *m_receiver_frame_context;
|
||||||
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer;
|
RxFrameBuffer *m_receive_frame_buffer;
|
||||||
bool m_has_pending_device_frame;
|
bool m_has_pending_device_frame;
|
||||||
|
|
||||||
spi_device_handle_t m_device;
|
spi_device_handle_t m_device;
|
||||||
|
|
||||||
esp_openthread_rcp_failure_handler mRcpFailureHandler;
|
esp_openthread_rcp_failure_handler mRcpFailureHandler;
|
||||||
|
|
||||||
|
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace openthread
|
} // 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).
|
* This class defines an UART interface to the Radio Co-processor (RCP).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class UartSpinelInterface {
|
class UartSpinelInterface : public ot::Spinel::SpinelInterface {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief This constructor of object.
|
* @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,
|
UartSpinelInterface(void);
|
||||||
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This destructor of the object.
|
* @brief This destructor of the object.
|
||||||
@ -41,65 +35,92 @@ public:
|
|||||||
~UartSpinelInterface(void);
|
~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
|
* @param[in] aFrame A pointer to buffer containing the spinel frame to send.
|
||||||
* for up to `kMaxWaitTime` interval.
|
* @param[in] aLength The length (number of bytes) in the frame.
|
||||||
*
|
*
|
||||||
* @param[in] frame A pointer to buffer containing the spinel frame to send.
|
* @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame.
|
||||||
* @param[in] length The length (number of bytes) in the 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.
|
||||||
* @return
|
* @retval OT_ERROR_FAILED Failed to call the SPI driver to send the frame.
|
||||||
* -OT_ERROR_NONE Successfully encoded and sent the spinel frame.
|
|
||||||
* -OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame.
|
|
||||||
* -OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
otError SendFrame(const uint8_t *frame, uint16_t length);
|
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
|
* @retval OT_ERROR_NONE Part or all of spinel frame is received.
|
||||||
* -OT_ERROR_NONE Part or all of spinel frame is received.
|
* @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
|
||||||
* -OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p timeout_us.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
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.
|
* This methods registers the callback for RCP failure.
|
||||||
@ -109,12 +130,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void RegisterRcpFailureHandler(esp_openthread_rcp_failure_handler handler) { mRcpFailureHandler = handler; }
|
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.
|
* This method is called when RCP is reset to recreate the connection with it.
|
||||||
* Intentionally empty.
|
* Intentionally empty.
|
||||||
@ -122,14 +137,25 @@ public:
|
|||||||
*/
|
*/
|
||||||
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
otError ResetConnection(void) { return OT_ERROR_NONE; }
|
||||||
|
|
||||||
private:
|
/**
|
||||||
enum {
|
* @brief This method enable the HDLC interface.
|
||||||
/**
|
*
|
||||||
* Maximum spinel frame size.
|
* @return
|
||||||
*
|
* - ESP_OK on success
|
||||||
*/
|
* - ESP_ERR_NO_MEM if allocation has failed
|
||||||
kMaxFrameSize = ot::Spinel::SpinelInterface::kMaxFrameSize,
|
* - 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`).
|
* Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
|
||||||
*
|
*
|
||||||
@ -152,9 +178,9 @@ private:
|
|||||||
static void HandleHdlcFrame(void *context, otError error);
|
static void HandleHdlcFrame(void *context, otError error);
|
||||||
void HandleHdlcFrame(otError error);
|
void HandleHdlcFrame(otError error);
|
||||||
|
|
||||||
ot::Spinel::SpinelInterface::ReceiveFrameCallback m_receiver_frame_callback;
|
ReceiveFrameCallback m_receiver_frame_callback;
|
||||||
void *m_receiver_frame_context;
|
void *m_receiver_frame_context;
|
||||||
ot::Spinel::SpinelInterface::RxFrameBuffer &m_receive_frame_buffer;
|
RxFrameBuffer *m_receive_frame_buffer;
|
||||||
|
|
||||||
ot::Hdlc::Decoder m_hdlc_decoder;
|
ot::Hdlc::Decoder m_hdlc_decoder;
|
||||||
uint8_t *m_uart_rx_buffer;
|
uint8_t *m_uart_rx_buffer;
|
||||||
@ -162,6 +188,8 @@ private:
|
|||||||
esp_openthread_uart_config_t m_uart_config;
|
esp_openthread_uart_config_t m_uart_config;
|
||||||
int m_uart_fd;
|
int m_uart_fd;
|
||||||
|
|
||||||
|
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||||
|
|
||||||
// Non-copyable, intentionally not implemented.
|
// Non-copyable, intentionally not implemented.
|
||||||
UartSpinelInterface(const UartSpinelInterface &);
|
UartSpinelInterface(const UartSpinelInterface &);
|
||||||
UartSpinelInterface &operator=(const UartSpinelInterface &);
|
UartSpinelInterface &operator=(const UartSpinelInterface &);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "esp_partition.h"
|
#include "esp_partition.h"
|
||||||
#include "common/code_utils.hpp"
|
#include "common/code_utils.hpp"
|
||||||
#include "common/logging.hpp"
|
#include "common/logging.hpp"
|
||||||
#include "core/common/instance.hpp"
|
#include "core/instance/instance.hpp"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "openthread/cli.h"
|
#include "openthread/cli.h"
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "esp_openthread_platform.h"
|
#include "esp_openthread_platform.h"
|
||||||
#include "esp_openthread_types.h"
|
#include "esp_openthread_types.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
|
#include "esp_spinel_interface.hpp"
|
||||||
#include "esp_spi_spinel_interface.hpp"
|
#include "esp_spi_spinel_interface.hpp"
|
||||||
#include "esp_uart_spinel_interface.hpp"
|
#include "esp_uart_spinel_interface.hpp"
|
||||||
#include "openthread-core-config.h"
|
#include "openthread-core-config.h"
|
||||||
@ -20,41 +21,100 @@
|
|||||||
#include "lib/spinel/spinel.h"
|
#include "lib/spinel/spinel.h"
|
||||||
#include "openthread/platform/diag.h"
|
#include "openthread/platform/diag.h"
|
||||||
#include "openthread/platform/radio.h"
|
#include "openthread/platform/radio.h"
|
||||||
|
#include "platform/exit_code.h"
|
||||||
|
|
||||||
using ot::Spinel::RadioSpinel;
|
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;
|
using esp::openthread::UartSpinelInterface;
|
||||||
static RadioSpinel<UartSpinelInterface> s_radio;
|
static SpinelInterfaceAdapter<UartSpinelInterface> s_spinel_interface;
|
||||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||||
using esp::openthread::SpiSpinelInterface;
|
using esp::openthread::SpiSpinelInterface;
|
||||||
static RadioSpinel<SpiSpinelInterface> s_radio;
|
static SpinelInterfaceAdapter<SpiSpinelInterface> s_spinel_interface;
|
||||||
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
#endif
|
||||||
|
|
||||||
|
static RadioSpinel s_radio;
|
||||||
|
|
||||||
static const char *radiospinel_workflow = "radio_spinel";
|
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)
|
esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config)
|
||||||
{
|
{
|
||||||
#if CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
spinel_iid_t iidList[ot::Spinel::kSpinelHeaderMaxNumIid];
|
||||||
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG,
|
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");
|
"Spinel interface init falied");
|
||||||
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
#else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI
|
||||||
ESP_RETURN_ON_ERROR(s_radio.GetSpinelInterface().Init(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG,
|
ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG,
|
||||||
"Spinel interface init failed");
|
"Spinel interface init failed");
|
||||||
#endif // CONFIG_OPENTHREAD_RADIO_SPINEL_UART
|
#endif
|
||||||
s_radio.Init(/*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false);
|
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,
|
return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process,
|
||||||
radiospinel_workflow);
|
radiospinel_workflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler)
|
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)
|
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)
|
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)
|
void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64)
|
||||||
|
@ -25,17 +25,39 @@ using ot::Spinel::SpinelInterface;
|
|||||||
namespace esp {
|
namespace esp {
|
||||||
namespace openthread {
|
namespace openthread {
|
||||||
|
|
||||||
SpiSpinelInterface::SpiSpinelInterface(SpinelInterface::ReceiveFrameCallback callback, void *callback_context,
|
SpiSpinelInterface::SpiSpinelInterface(void)
|
||||||
SpinelInterface::RxFrameBuffer &frame_buffer)
|
|
||||||
: m_event_fd(-1)
|
: m_event_fd(-1)
|
||||||
, m_receiver_frame_callback(callback)
|
, m_receiver_frame_callback(nullptr)
|
||||||
, m_receiver_frame_context(callback_context)
|
, m_receiver_frame_context(nullptr)
|
||||||
, m_receive_frame_buffer(frame_buffer)
|
, m_receive_frame_buffer(nullptr)
|
||||||
, mRcpFailureHandler(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");
|
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;
|
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");
|
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);
|
return ConductSPITransaction(true, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t SpiSpinelInterface::Deinit(void)
|
|
||||||
|
esp_err_t SpiSpinelInterface::Disable(void)
|
||||||
{
|
{
|
||||||
if (m_event_fd >= 0) {
|
if (m_event_fd >= 0) {
|
||||||
close(m_event_fd);
|
close(m_event_fd);
|
||||||
@ -80,11 +108,6 @@ esp_err_t SpiSpinelInterface::Deinit(void)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpiSpinelInterface::~SpiSpinelInterface(void)
|
|
||||||
{
|
|
||||||
Deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
otError SpiSpinelInterface::SendFrame(const uint8_t *frame, uint16_t length)
|
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");
|
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);
|
tx_frame.SetHeaderAcceptLen(rx_data_size);
|
||||||
|
|
||||||
uint8_t *rx_buffer;
|
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");
|
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;
|
rx_buffer = m_receive_frame_buffer->GetFrame() - kSPIFrameHeaderSize;
|
||||||
if (m_receive_frame_buffer.GetFrameMaxLength() < rx_data_size) {
|
if (m_receive_frame_buffer->GetFrameMaxLength() < rx_data_size) {
|
||||||
rx_data_size = m_receive_frame_buffer.GetFrameMaxLength();
|
rx_data_size = m_receive_frame_buffer->GetFrameMaxLength();
|
||||||
}
|
}
|
||||||
uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size;
|
uint16_t data_size = tx_data_size > rx_data_size ? tx_data_size : rx_data_size;
|
||||||
data_size += kSPIFrameHeaderSize;
|
data_size += kSPIFrameHeaderSize;
|
||||||
@ -143,7 +166,7 @@ esp_err_t SpiSpinelInterface::ConductSPITransaction(bool reset, uint16_t tx_data
|
|||||||
|
|
||||||
if (rx_frame.IsResetFlagSet()) {
|
if (rx_frame.IsResetFlagSet()) {
|
||||||
ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset");
|
ESP_LOGW(OT_PLAT_LOG_TAG, "RCP Reset");
|
||||||
m_receive_frame_buffer.DiscardFrame();
|
m_receive_frame_buffer->DiscardFrame();
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
if (rx_frame.GetHeaderDataLen() == 0 && rx_frame.GetHeaderAcceptLen() == 0) {
|
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) {
|
if (gpio_get_level(m_spi_config.intr_pin) == 1) {
|
||||||
m_pending_data_len = 0;
|
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...",
|
ESP_LOGW(OT_PLAT_LOG_TAG, "insufficient buffer space to hold a frame of length %d...",
|
||||||
rx_frame.GetHeaderDataLen());
|
rx_frame.GetHeaderDataLen());
|
||||||
m_receive_frame_buffer.DiscardFrame();
|
m_receive_frame_buffer->DiscardFrame();
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
m_receiver_frame_callback(m_receiver_frame_context);
|
m_receiver_frame_callback(m_receiver_frame_context);
|
||||||
} else {
|
} else {
|
||||||
m_pending_data_len = 0;
|
m_pending_data_len = 0;
|
||||||
m_receive_frame_buffer.DiscardFrame();
|
m_receive_frame_buffer->DiscardFrame();
|
||||||
}
|
}
|
||||||
m_pending_data_len = 0;
|
m_pending_data_len = 0;
|
||||||
|
|
||||||
@ -180,26 +203,26 @@ void SpiSpinelInterface::GpioIntrHandler(void *arg)
|
|||||||
write(instance->m_event_fd, &event, sizeof(event));
|
write(instance->m_event_fd, &event, sizeof(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpiSpinelInterface::Update(void *mainloop)
|
void SpiSpinelInterface::UpdateFdSet(void *aMainloopContext)
|
||||||
{
|
{
|
||||||
if (m_pending_data_len > 0) {
|
if (m_pending_data_len > 0) {
|
||||||
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_sec = 0;
|
((esp_openthread_mainloop_context_t *)aMainloopContext)->timeout.tv_sec = 0;
|
||||||
((esp_openthread_mainloop_context_t *)mainloop)->timeout.tv_usec = 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 *)aMainloopContext)->read_fds);
|
||||||
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)mainloop)->error_fds);
|
FD_SET(m_event_fd, &((esp_openthread_mainloop_context_t *)aMainloopContext)->error_fds);
|
||||||
if (m_event_fd > ((esp_openthread_mainloop_context_t *)mainloop)->max_fd) {
|
if (m_event_fd > ((esp_openthread_mainloop_context_t *)aMainloopContext)->max_fd) {
|
||||||
((esp_openthread_mainloop_context_t *)mainloop)->max_fd = m_event_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");
|
ESP_LOGE(OT_PLAT_LOG_TAG, "SPI INTR GPIO error event");
|
||||||
return;
|
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;
|
uint64_t event;
|
||||||
read(m_event_fd, &event, sizeof(event));
|
read(m_event_fd, &event, sizeof(event));
|
||||||
m_pending_data_len = SpinelInterface::kMaxFrameSize;
|
m_pending_data_len = SpinelInterface::kMaxFrameSize;
|
||||||
@ -249,5 +272,10 @@ otError SpiSpinelInterface::HardwareReset(void)
|
|||||||
return OT_ERROR_NONE;
|
return OT_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SpiSpinelInterface::GetBusSpeed(void) const
|
||||||
|
{
|
||||||
|
return m_spi_config.spi_device.clock_speed_hz;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace openthread
|
} // namespace openthread
|
||||||
} // namespace esp
|
} // namespace esp
|
||||||
|
@ -27,13 +27,10 @@
|
|||||||
namespace esp {
|
namespace esp {
|
||||||
namespace openthread {
|
namespace openthread {
|
||||||
|
|
||||||
UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFrameCallback callback,
|
UartSpinelInterface::UartSpinelInterface(void)
|
||||||
void *callback_context,
|
: m_receiver_frame_callback(nullptr)
|
||||||
ot::Spinel::SpinelInterface::RxFrameBuffer &frame_buffer)
|
, m_receiver_frame_context(nullptr)
|
||||||
: m_receiver_frame_callback(callback)
|
, m_receive_frame_buffer(nullptr)
|
||||||
, m_receiver_frame_context(callback_context)
|
|
||||||
, m_receive_frame_buffer(frame_buffer)
|
|
||||||
, m_hdlc_decoder(frame_buffer, HandleHdlcFrame, this)
|
|
||||||
, m_uart_fd(-1)
|
, m_uart_fd(-1)
|
||||||
, mRcpFailureHandler(nullptr)
|
, mRcpFailureHandler(nullptr)
|
||||||
{
|
{
|
||||||
@ -41,9 +38,29 @@ UartSpinelInterface::UartSpinelInterface(ot::Spinel::SpinelInterface::ReceiveFra
|
|||||||
|
|
||||||
UartSpinelInterface::~UartSpinelInterface(void)
|
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;
|
esp_err_t error = ESP_OK;
|
||||||
m_uart_rx_buffer = static_cast<uint8_t *>(heap_caps_malloc(kMaxFrameSize, MALLOC_CAP_8BIT));
|
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;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t UartSpinelInterface::Deinit(void)
|
esp_err_t UartSpinelInterface::Disable(void)
|
||||||
{
|
{
|
||||||
if (m_uart_rx_buffer) {
|
if (m_uart_rx_buffer) {
|
||||||
heap_caps_free(m_uart_rx_buffer);
|
heap_caps_free(m_uart_rx_buffer);
|
||||||
@ -88,24 +105,14 @@ exit:
|
|||||||
return error;
|
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");
|
ESP_LOGD(OT_PLAT_LOG_TAG, "radio uart read event");
|
||||||
TryReadAndDecode();
|
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)
|
int UartSpinelInterface::TryReadAndDecode(void)
|
||||||
{
|
{
|
||||||
uint8_t buffer[UART_FIFO_LEN];
|
uint8_t buffer[UART_FIFO_LEN];
|
||||||
@ -246,7 +253,7 @@ void UartSpinelInterface::HandleHdlcFrame(otError error)
|
|||||||
m_receiver_frame_callback(m_receiver_frame_context);
|
m_receiver_frame_callback(m_receiver_frame_context);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(OT_PLAT_LOG_TAG, "dropping radio frame: %s", otThreadErrorToString(error));
|
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;
|
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 openthread
|
||||||
} // namespace esp
|
} // namespace esp
|
||||||
|
Loading…
x
Reference in New Issue
Block a user