From 366786dbed79745045fc47b1721e63a7f488ac57 Mon Sep 17 00:00:00 2001 From: Zhanglong Xia Date: Fri, 15 Jul 2022 04:10:51 +0800 Subject: [PATCH] [posix] add a vendor interface for the radio spinel layer (#7884) This commit adds a vendor interface for developers to implement the bus interface by themselves. --- script/check-posix-build-cmake | 3 + src/posix/platform/CMakeLists.txt | 4 + src/posix/platform/openthread-posix-config.h | 6 + src/posix/platform/radio.cpp | 7 +- src/posix/platform/vendor_interface.hpp | 174 ++++++++++++++++++ .../platform/vendor_interface_example.cpp | 167 +++++++++++++++++ 6 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 src/posix/platform/vendor_interface.hpp create mode 100644 src/posix/platform/vendor_interface_example.cpp diff --git a/script/check-posix-build-cmake b/script/check-posix-build-cmake index 11d8b95a7..cf9a4f506 100755 --- a/script/check-posix-build-cmake +++ b/script/check-posix-build-cmake @@ -63,6 +63,9 @@ main() reset_source build -DOT_POSIX_CONFIG_RCP_BUS=SPI "$@" fi + + reset_source + build -DOT_POSIX_CONFIG_RCP_BUS=VENDOR "$@" } main "$@" diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index 272b08e2d..701eb2183 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -80,6 +80,9 @@ if(NOT OT_CONFIG) set(OT_CONFIG "openthread-core-posix-config.h" PARENT_SCOPE) endif() +set(OT_POSIX_CONFIG_RCP_VENDOR_INTERFACE "vendor_interface_example.cpp" + CACHE STRING "vendor interface implementation") + add_library(openthread-posix alarm.cpp backbone.cpp @@ -103,6 +106,7 @@ add_library(openthread-posix udp.cpp utils.cpp virtual_time.cpp + ${OT_POSIX_CONFIG_RCP_VENDOR_INTERFACE} ) target_link_libraries(openthread-posix diff --git a/src/posix/platform/openthread-posix-config.h b/src/posix/platform/openthread-posix-config.h index 62e132468..191f5a007 100644 --- a/src/posix/platform/openthread-posix-config.h +++ b/src/posix/platform/openthread-posix-config.h @@ -85,6 +85,12 @@ */ #define OT_POSIX_RCP_BUS_SPI 2 +/** + * RCP bus defined by vendors. + * + */ +#define OT_POSIX_RCP_BUS_VENDOR 3 + /** * @def OPENTHREAD_POSIX_CONFIG_RCP_BUS * diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index 0b9d85c6a..8fb63bfb2 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -52,8 +52,13 @@ static ot::Spinel::RadioSpinel sR #include "spi_interface.hpp" static ot::Spinel::RadioSpinel sRadioSpinel; +#elif OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR +#include "vendor_interface.hpp" + +static ot::Spinel::RadioSpinel sRadioSpinel; #else -#error "OPENTHREAD_POSIX_CONFIG_RCP_BUS only allows OT_POSIX_RCP_BUS_UART and OT_POSIX_RCP_BUS_SPI!" +#error "OPENTHREAD_POSIX_CONFIG_RCP_BUS only allows OT_POSIX_RCP_BUS_UART, OT_POSIX_RCP_BUS_SPI and " \ + "OT_POSIX_RCP_BUS_VENDOR!" #endif namespace ot { diff --git a/src/posix/platform/vendor_interface.hpp b/src/posix/platform/vendor_interface.hpp new file mode 100644 index 000000000..7ece23487 --- /dev/null +++ b/src/posix/platform/vendor_interface.hpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for the vendor interface to radio (RCP). + */ + +#ifndef POSIX_APP_VENDOR_INTERFACE_HPP_ +#define POSIX_APP_VENDOR_INTERFACE_HPP_ + +#include "openthread-posix-config.h" + +#include + +#include "platform-posix.h" +#include "lib/spinel/spinel_interface.hpp" + +#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR + +namespace ot { +namespace Posix { + +/** + * This class defines a vendor interface to the Radio Co-processor (RCP). + * + */ +class VendorInterface +{ +public: + /** + * This constructor initializes the object. + * + * @param[in] aCallback A reference to a `Callback` object. + * @param[in] aCallbackContext The context pointer passed to the callback. + * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. + * + */ + VendorInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); + + /** + * This destructor deinitializes the object. + * + */ + ~VendorInterface(void); + + /** + * This method 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] aRadioUrl Arguments parsed from radio url. + * + * @retval OT_ERROR_NONE The interface is initialized successfully. + * @retval OT_ERROR_ALREADY The interface is already initialized. + * @retval OT_ERROR_INVALID_ARGS The UART device or executable cannot be found or failed to open/run. + * + */ + otError Init(const Url::Url &aRadioUrl); + + /** + * This method deinitializes the interface to the RCP. + * + */ + void Deinit(void); + + /** + * This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. + * + * @param[in] aFrame A pointer to buffer containing the spinel frame to send. + * @param[in] aLength The length (number of bytes) in the frame. + * + * @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame. + * @retval OT_ERROR_FAILED Failed to call the SPI driver to send the frame. + * + */ + otError SendFrame(const uint8_t *aFrame, uint16_t aLength); + + /** + * This method waits for receiving part or all of spinel frame within specified interval. + * + * @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. + * + */ + otError WaitForFrame(uint64_t aTimeoutUs); + + /** + * This method updates the file descriptor sets with file descriptors used by the radio driver. + * + * @param[inout] aReadFdSet A reference to the read file descriptors. + * @param[inout] aWriteFdSet A reference to the write file descriptors. + * @param[inout] aMaxFd A reference to the max file descriptor. + * @param[inout] aTimeout A reference to the timeout. + * + */ + void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout); + + /** + * This method performs radio driver processing. + * + * @param[in] aContext The context containing fd_sets. + * + */ + void Process(const RadioProcessContext &aContext); + + /** + * This method 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. + * + */ + void OnRcpReset(void); + + /** + * This method is called when RCP is reset to recreate the connection with it. + * + * @retval OT_ERROR_NONE Reset the connection successfully. + * @retval OT_ERROR_FAILED Failed to reset the connection. + * + */ + otError ResetConnection(void); + + /** + * This method returns the RCP interface metrics. + * + * @returns The RCP interface metrics. + * + */ + const otRcpInterfaceMetrics *GetRcpInterfaceMetrics(void); +}; + +} // namespace Posix +} // namespace ot + +#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR +#endif // POSIX_APP_VENDOR_INTERFACE_HPP_ diff --git a/src/posix/platform/vendor_interface_example.cpp b/src/posix/platform/vendor_interface_example.cpp new file mode 100644 index 000000000..12121d398 --- /dev/null +++ b/src/posix/platform/vendor_interface_example.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file provides an example on how to implement an OpenThread vendor interface to RCP. + */ + +#include "openthread-posix-config.h" + +#if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR + +#include "vendor_interface.hpp" +#include "common/new.hpp" + +namespace ot { +namespace Posix { +using ot::Spinel::SpinelInterface; + +/** + * This class defines the vendor implementation object. + * + */ +class VendorInterfaceImpl +{ +public: + explicit VendorInterfaceImpl(SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + SpinelInterface::RxFrameBuffer & aFrameBuffer) + : mReceiveFrameCallback(aCallback) + , mReceiveFrameContext(aCallbackContext) + , mRxFrameBuffer(aFrameBuffer) + { + OT_UNUSED_VARIABLE(mReceiveFrameCallback); + OT_UNUSED_VARIABLE(mReceiveFrameContext); + OT_UNUSED_VARIABLE(mRxFrameBuffer); + } + + // TODO: Add vendor code (add methods and/or member variables). + +private: + SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback; + void * mReceiveFrameContext; + SpinelInterface::RxFrameBuffer & mRxFrameBuffer; +}; + +// ---------------------------------------------------------------------------- +// `VendorInterface` API +// ---------------------------------------------------------------------------- + +static OT_DEFINE_ALIGNED_VAR(sVendorInterfaceImplRaw, sizeof(VendorInterfaceImpl), uint64_t); + +VendorInterface::VendorInterface(SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + SpinelInterface::RxFrameBuffer & aFrameBuffer) +{ + new (&sVendorInterfaceImplRaw) VendorInterfaceImpl(aCallback, aCallbackContext, aFrameBuffer); + OT_UNUSED_VARIABLE(sVendorInterfaceImplRaw); +} + +VendorInterface::~VendorInterface(void) +{ + Deinit(); +} + +otError VendorInterface::Init(const Url::Url &aRadioUrl) +{ + OT_UNUSED_VARIABLE(aRadioUrl); + + // TODO: Implement vendor code here. + + return OT_ERROR_NONE; +} + +void VendorInterface::Deinit(void) +{ + // TODO: Implement vendor code here. +} + +uint32_t VendorInterface::GetBusSpeed(void) const +{ + return 1000000; +} + +void VendorInterface::OnRcpReset(void) +{ + // TODO: Implement vendor code here. +} + +void VendorInterface::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout) +{ + OT_UNUSED_VARIABLE(aReadFdSet); + OT_UNUSED_VARIABLE(aWriteFdSet); + OT_UNUSED_VARIABLE(aMaxFd); + OT_UNUSED_VARIABLE(aTimeout); + + // TODO: Implement vendor code here. +} + +void VendorInterface::Process(const RadioProcessContext &aContext) +{ + OT_UNUSED_VARIABLE(aContext); + + // TODO: Implement vendor code here. +} + +otError VendorInterface::WaitForFrame(uint64_t aTimeoutUs) +{ + OT_UNUSED_VARIABLE(aTimeoutUs); + + // TODO: Implement vendor code here. + + return OT_ERROR_NONE; +} + +otError VendorInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength) +{ + OT_UNUSED_VARIABLE(aFrame); + OT_UNUSED_VARIABLE(aLength); + + // TODO: Implement vendor code here. + + return OT_ERROR_NONE; +} + +otError VendorInterface::ResetConnection(void) +{ + // TODO: Implement vendor code here. + + return OT_ERROR_NONE; +} + +const otRcpInterfaceMetrics *VendorInterface::GetRcpInterfaceMetrics(void) +{ + // TODO: Implement vendor code here. + + return nullptr; +} +} // namespace Posix +} // namespace ot + +#endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR