From 8de4ab4740ddd16f6c12af51c8a6ab2e6c083b61 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Tue, 21 Apr 2020 11:50:58 +0800 Subject: [PATCH] [spinel] platform independent spinel radio (#4705) This change refactors radio-spinel into a platform independent header-only library so that other platforms (baremetal/RTOS) can enable Thread with RCP mode as well. --- Android.mk | 4 +- configure.ac | 1 + src/lib/CMakeLists.txt | 1 + src/lib/Makefile.am | 1 + src/lib/platform/CMakeLists.txt | 48 ++ src/lib/platform/Makefile.am | 43 + src/lib/platform/exit_code.c | 81 ++ src/lib/platform/exit_code.h | 152 ++++ src/lib/spinel/Makefile.am | 2 + .../platform => lib/spinel}/radio_spinel.hpp | 201 +++-- .../spinel/radio_spinel_impl.hpp} | 789 ++++++------------ .../spinel}/spinel_interface.hpp | 25 +- src/posix/Makefile.am | 2 + src/posix/daemon.cmake | 1 + src/posix/main.c | 1 + src/posix/platform/CMakeLists.txt | 3 +- src/posix/platform/Makefile.am | 5 +- src/posix/platform/alarm.cpp | 6 +- src/posix/platform/hdlc_interface.cpp | 41 +- src/posix/platform/hdlc_interface.hpp | 38 +- .../include/openthread/openthread-system.h | 42 - src/posix/platform/platform-posix.h | 89 +- src/posix/platform/radio.cpp | 421 ++++++++++ src/posix/platform/settings.cpp | 56 +- src/posix/platform/spi_interface.cpp | 39 +- src/posix/platform/spi_interface.hpp | 32 +- src/posix/platform/virtual_time.cpp | 2 +- 27 files changed, 1278 insertions(+), 848 deletions(-) create mode 100644 src/lib/platform/CMakeLists.txt create mode 100644 src/lib/platform/Makefile.am create mode 100644 src/lib/platform/exit_code.c create mode 100644 src/lib/platform/exit_code.h rename src/{posix/platform => lib/spinel}/radio_spinel.hpp (84%) rename src/{posix/platform/radio_spinel.cpp => lib/spinel/radio_spinel_impl.hpp} (71%) rename src/{posix/platform => lib/spinel}/spinel_interface.hpp (75%) create mode 100644 src/posix/platform/radio.cpp diff --git a/Android.mk b/Android.mk index fec4ed1a0..9989ad1b4 100644 --- a/Android.mk +++ b/Android.mk @@ -269,6 +269,7 @@ LOCAL_SRC_FILES := \ src/core/utils/parse_cmdline.cpp \ src/core/utils/slaac_address.cpp \ src/lib/hdlc/hdlc.cpp \ + src/lib/platform/exit_code.c \ src/lib/spinel/spinel.c \ src/lib/spinel/spinel_decoder.cpp \ src/lib/spinel/spinel_encoder.cpp \ @@ -278,7 +279,7 @@ LOCAL_SRC_FILES := \ src/posix/platform/logging.cpp \ src/posix/platform/misc.cpp \ src/posix/platform/netif.cpp \ - src/posix/platform/radio_spinel.cpp \ + src/posix/platform/radio.cpp \ src/posix/platform/settings.cpp \ src/posix/platform/spi_interface.cpp \ src/posix/platform/system.cpp \ @@ -486,6 +487,7 @@ LOCAL_CFLAGS := \ LOCAL_C_INCLUDES := \ $(OPENTHREAD_PROJECT_INCLUDES) \ $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/src/ \ $(LOCAL_PATH)/src/core \ $(LOCAL_PATH)/src/posix/platform \ $(LOCAL_PATH)/src/posix/platform/include \ diff --git a/configure.ac b/configure.ac index 711202451..f2cec23fe 100644 --- a/configure.ac +++ b/configure.ac @@ -1027,6 +1027,7 @@ src/posix/Makefile src/posix/platform/Makefile src/lib/Makefile src/lib/hdlc/Makefile +src/lib/platform/Makefile src/lib/spinel/Makefile third_party/Makefile third_party/jlink/Makefile diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 5e68e9450..e3b522ba8 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -27,4 +27,5 @@ # add_subdirectory(hdlc) +add_subdirectory(platform) add_subdirectory(spinel) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index f9a4f7b04..8cef70448 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -30,6 +30,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am SUBDIRS = \ hdlc \ + platform \ spinel \ $(NULL) diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt new file mode 100644 index 000000000..e1fd0d6ba --- /dev/null +++ b/src/lib/platform/CMakeLists.txt @@ -0,0 +1,48 @@ +# +# Copyright (c) 2020, 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. +# + +add_library(openthread-platform + exit_code.c + exit_code.h +) + +target_include_directories(openthread-platform + PUBLIC + ${OT_PUBLIC_INCLUDES} + ${PROJECT_SOURCE_DIR}/src/ + PRIVATE + ${OT_PRIVATE_INCLUDES} +) + +target_compile_definitions(openthread-platform PRIVATE + ${OT_PRIVATE_DEFINES} +) + +target_compile_options(openthread-platform PRIVATE + ${OT_CFLAGS} +) diff --git a/src/lib/platform/Makefile.am b/src/lib/platform/Makefile.am new file mode 100644 index 000000000..70f861148 --- /dev/null +++ b/src/lib/platform/Makefile.am @@ -0,0 +1,43 @@ +# +# Copyright (c) 2020, 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. +# + +include $(abs_top_nlbuild_autotools_dir)/automake/pre.am + +noinst_LIBRARIES = libopenthread-platform.a + +libopenthread_platform_a_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/core \ + $(NULL) + +libopenthread_platform_a_SOURCES = \ + exit_code.c \ + exit_code.h \ + $(NULL) + +include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/src/lib/platform/exit_code.c b/src/lib/platform/exit_code.c new file mode 100644 index 000000000..acac14e2d --- /dev/null +++ b/src/lib/platform/exit_code.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020, 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 implements exit code utilities. + */ + +#include "exit_code.h" + +#include +#include +#include +#include + +const char *otExitCodeToString(uint8_t aExitCode) +{ + const char *retval = NULL; + + switch (aExitCode) + { + case OT_EXIT_SUCCESS: + retval = "Success"; + break; + + case OT_EXIT_FAILURE: + retval = "Failure"; + break; + + case OT_EXIT_INVALID_ARGUMENTS: + retval = "InvalidArgument"; + break; + + case OT_EXIT_RADIO_SPINEL_INCOMPATIBLE: + retval = "RadioSpinelIncompatible"; + break; + + case OT_EXIT_RADIO_SPINEL_RESET: + retval = "RadioSpinelReset"; + break; + + case OT_EXIT_RADIO_SPINEL_NO_RESPONSE: + retval = "RadioSpinelNoResponse"; + break; + + case OT_EXIT_ERROR_ERRNO: + retval = strerror(errno); + break; + + default: + assert(false); + retval = "UnknownExitCode"; + break; + } + + return retval; +} diff --git a/src/lib/platform/exit_code.h b/src/lib/platform/exit_code.h new file mode 100644 index 000000000..81a332128 --- /dev/null +++ b/src/lib/platform/exit_code.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2020, 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 contains header for exit code utilities. + */ + +#ifndef PLATFORM_EXIT_CODE_H_ +#define PLATFORM_EXIT_CODE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This enumeration represents exit codes used when OpenThread exits. + * + */ +enum +{ + /** + * Success. + */ + OT_EXIT_SUCCESS = 0, + + /** + * Generic failure. + */ + OT_EXIT_FAILURE = 1, + + /** + * Invalid arguments. + */ + OT_EXIT_INVALID_ARGUMENTS = 2, + + /** + * Incompatible radio spinel. + */ + OT_EXIT_RADIO_SPINEL_INCOMPATIBLE = 3, + + /** + * Unexpected radio spinel reset. + */ + OT_EXIT_RADIO_SPINEL_RESET = 4, + + /** + * System call or library function error. + */ + OT_EXIT_ERROR_ERRNO = 5, + + /** + * No response from radio spinel. + */ + OT_EXIT_RADIO_SPINEL_NO_RESPONSE = 6, +}; + +/** + * This function converts an exit code into a string. + * + * @param[in] aExitCode An exit code. + * + * @returns A string representation of an exit code. + * + */ +const char *otExitCodeToString(uint8_t aExitCode); + +/** + * This macro checks for the specified condition, which is expected to commonly be true, + * and both records exit status and terminates the program if the condition is false. + * + * @param[in] aCondition The condition to verify + * @param[in] aExitCode The exit code. + * + */ +#define VerifyOrDie(aCondition, aExitCode) \ + do \ + { \ + if (!(aCondition)) \ + { \ + otLogCritPlat("%s() at %s:%d: %s", __func__, __FILE__, __LINE__, otExitCodeToString(aExitCode)); \ + exit(aExitCode); \ + } \ + } while (false) + +/** + * This macro checks for the specified error code, which is expected to commonly be successful, + * and both records exit status and terminates the program if the error code is unsuccessful. + * + * @param[in] aError An error code to be evaluated against OT_ERROR_NONE. + * + */ +#define SuccessOrDie(aError) \ + VerifyOrDie(aError == OT_ERROR_NONE, \ + (aError == OT_ERROR_INVALID_ARGS ? OT_EXIT_INVALID_ARGUMENTS : OT_EXIT_FAILURE)) + +/** + * This macro unconditionally both records exit status and terminates the program. + * + * @param[in] aExitCode The exit code. + * + */ +#define DieNow(aExitCode) VerifyOrDie(false, aExitCode) + +/** + * This macro unconditionally both records exit status and exit message and terminates the program. + * + * @param[in] aMessage The exit message. + * @param[in] aExitCode The exit code. + * + */ +#define DieNowWithMessage(aMessage, aExitCode) \ + do \ + { \ + otLogCritPlat("exit(%d): %s line %d, %s, %s", aExitCode, __func__, __LINE__, aMessage, \ + otExitCodeToString(aExitCode)); \ + exit(aExitCode); \ + } while (false) + +#ifdef __cplusplus +} +#endif + +#endif // PLATFORM_EXIT_CODE_H_ diff --git a/src/lib/spinel/Makefile.am b/src/lib/spinel/Makefile.am index 2dfc49eed..af1fa20e6 100644 --- a/src/lib/spinel/Makefile.am +++ b/src/lib/spinel/Makefile.am @@ -70,6 +70,8 @@ include_HEADERS = \ $(NULL) noinst_HEADERS = \ + radio_spinel.hpp \ + radio_spinel_impl.hpp \ spinel_buffer.hpp \ spinel_decoder.hpp \ spinel_encoder.hpp \ diff --git a/src/posix/platform/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp similarity index 84% rename from src/posix/platform/radio_spinel.hpp rename to src/lib/spinel/radio_spinel.hpp index e754d7b37..9fe0c0156 100644 --- a/src/posix/platform/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -34,30 +34,72 @@ #ifndef RADIO_SPINEL_HPP_ #define RADIO_SPINEL_HPP_ -#include "openthread-posix-config.h" - #include -#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE -#include "hdlc_interface.hpp" -#endif - -#if OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE -#include "spi_interface.hpp" -#endif - -#if !OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE && !OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE -#error "Please enable either OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE or OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE." -#endif - +#include "spinel.h" #include "spinel_interface.hpp" -#include "lib/spinel/spinel.h" #include "ncp/ncp_config.h" namespace ot { -namespace Posix { +namespace Spinel { -class RadioSpinel : public SpinelInterface::Callbacks +/** + * The class for providing a OpenThread radio interface by talking with a radio-only + * co-procesor(RCP). The InterfaceType template parameter should provide the following + * methods: + * + * class InterfaceType { + * + * // This constructor initializes the object. + * + * // @param[in] aCallback Callback on frame received + * // @param[in] aCallbackContext Callback context + * // @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. + * + * InterFaceType(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, + * void * aCallbackContext, + * Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); + * + * + * // This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket. + * + * // 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. + * + * // @retval OT_ERROR_NONE Successfully encoded and sent the spinel frame. + * // @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode the frame. + * // @retval OT_ERROR_FAILED Failed to send due to socket not becoming writable within `kMaxWaitTime`. + * + * 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] aTimeout The timeout value in micrsoseconds. + * + * // @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 performs radio driver processing. + * + * // @param[in] aContext The context containing fd_sets. + * // The type is specified by the user in template parameters. + * + * void Process(const ProcessContextType &aContext); + * + * + * // This method deinitializes the interface to the RCP. + * + * void Deinit(void); + * }; + */ +template class RadioSpinel { public: /** @@ -69,10 +111,13 @@ public: /** * Initialize this radio transceiver. * - * @param[in] aPlatformConfig Platform configuration structure. + * @param[in] aResetRadio TRUE to reset on init, FALSE to not reset on init. + * @param[in] aRestoreDatasetFromNcp TRUE to restore dataset to host from non-volatile memory + * (only used when attempts to upgrade from NCP to RCP mode), + * FALSE otherwise. * */ - void Init(const otPlatformConfig &aPlatformConfig); + void Init(bool aResetRadio, bool aRestoreDataSetFromNcp); /** * Deinitialize this radio transceiver. @@ -451,42 +496,46 @@ public: bool IsEnabled(void) const { return mState != kStateDisabled; } /** - * This method updates the file descriptor sets with file descriptors used by the radio driver. + * This method indicates whether there is a pending transmission. * - * @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. + * @retval TRUE There is a pending transmission. + * @retval FALSE There is no pending transmission. * */ - void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout); + bool IsTransmitting(void) const { return mState == kStateTransmitting; } /** - * This method performs radio driver processing. + * This method indicates whether a transmit has just finished. * - * @param[in] aReadFdSet A reference to the read file descriptors. - * @param[in] aWriteFdSet A reference to the write file descriptors. + * @retval TRUE The trasmission is done. + * @retval FALSE The trasmission is not done. * */ - void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); - -#if OPENTHREAD_POSIX_VIRTUAL_TIME - /** - * This method performs radio spinel processing in simulation mode. - * - * @param[in] aEvent A reference to the current received simulation event. - * - */ - void Process(const struct Event &aEvent); + bool IsTransmitDone(void) const { return mState == kStateTransmitDone; } /** - * This method updates the @p aTimeout for processing radio spinel in simulation mode. + * This method returns the timeout timepoint for the pending transmission. * - * @param[out] aTimeout A reference to the current timeout. + * @returns The timeout timepoint for the pending transmission. * */ - void Update(struct timeval &aTimeout); -#endif + uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; } + + /** + * This method processes any pending the I/O data. + * + * @param[in] aContext The process context. + * + */ + void Process(const ProcessContextType &aContext); + + /** + * This method returns the underlying spinel interface. + * + * @returns The underlying spinel interface. + * + */ + InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; } #if OPENTHREAD_CONFIG_DIAG_ENABLE /** @@ -540,6 +589,34 @@ public: */ void HandleReceivedFrame(void); + /** + * This method checks whether the spinel interface is radio-only + * + * @retval TRUE The radio chip is in radio-only mode. + * @retval FALSE Otherwise. + * + */ + bool IsRcp(void); + + /** + * This method checks whether there is pending frame in the buffer. + * + * @returns Whether there is pending frame in the buffer. + * + */ + bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); } + + /** + * This method gets dataset from NCP radio and saves it. + * + * @retval OT_ERROR_NONE Successfully restore dataset. + * @retval OT_ERROR_BUSY Failed due to another operation is on going. + * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the radio. + * @retval OT_ERROR_NOT_FOUND Failed due to spinel property not supported in radio. + * @retval OT_ERROR_FAILED Failed due to other reasons. + */ + otError RestoreDatasetFromNcp(void); + private: enum { @@ -561,10 +638,22 @@ private: typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); + static void HandleReceivedFrame(void *aContext); + otError CheckSpinelVersion(void); - otError CheckCapabilities(bool &aIsRcp); otError CheckRadioCapabilities(void); - void ProcessFrameQueue(void); + + /** + * This method triggers a state transfer of the state machine. + * + */ + void ProcessRadioStateMachine(void); + + /** + * This method processes the frame queue. + * + */ + void ProcessFrameQueue(void); /** * This method tries to retrieve a spinel property from OpenThread transceiver. @@ -665,28 +754,11 @@ private: void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); - /** - * This method gets dataset from NCP radio and saves it. - * - * @retval OT_ERROR_NONE Successfully restore dataset. - * @retval OT_ERROR_BUSY Failed due to another operation is on going. - * @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver. - * @retval OT_ERROR_NOT_FOUND Failed due to spinel property not supported in radio. - * @retval OT_ERROR_FAILED Failed due to other reasons. - */ - otError RestoreDatasetFromNcp(void); - otInstance *mInstance; SpinelInterface::RxFrameBuffer mRxFrameBuffer; -#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE - HdlcInterface mSpinelInterface; -#endif - -#if OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE - SpiInterface mSpinelInterface; -#endif + InterfaceType mSpinelInterface; uint16_t mCmdTidsInUse; ///< Used transaction ids. spinel_tid_t mCmdNextTid; ///< Next available transaction id. @@ -714,6 +786,7 @@ private: int8_t mRxSensitivity; otError mTxError; char mVersion[kVersionStringSize]; + otExtAddress mIeeeEui64; State mState; bool mIsPromiscuous : 1; ///< Promiscuous mode. @@ -729,7 +802,9 @@ private: uint64_t mTxRadioEndUs; }; -} // namespace Posix +} // namespace Spinel } // namespace ot +#include "radio_spinel_impl.hpp" + #endif // RADIO_SPINEL_HPP_ diff --git a/src/posix/platform/radio_spinel.cpp b/src/lib/spinel/radio_spinel_impl.hpp similarity index 71% rename from src/posix/platform/radio_spinel.cpp rename to src/lib/spinel/radio_spinel_impl.hpp index 3673d4422..f32a07f56 100644 --- a/src/posix/platform/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The OpenThread Authors. + * Copyright (c) 2020, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,47 +31,47 @@ * This file implements the spinel based radio transceiver. */ -#include "radio_spinel.hpp" - -#include "platform-posix.h" -#include "lib/spinel/spinel_decoder.hpp" - #include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include #include +#include #include "common/code_utils.hpp" #include "common/encoding.hpp" #include "common/logging.hpp" #include "common/new.hpp" #include "common/settings.hpp" +#include "lib/platform/exit_code.h" +#include "lib/spinel/spinel_decoder.hpp" #include "meshcop/dataset.hpp" #include "meshcop/meshcop_tlvs.hpp" +#ifndef MS_PER_S +#define MS_PER_S 1000 +#endif +#ifndef US_PER_MS +#define US_PER_MS 1000 +#endif +#ifndef US_PER_S +#define US_PER_S (MS_PER_S * US_PER_MS) +#endif +#ifndef NS_PER_US +#define NS_PER_US 1000 +#endif + #ifndef TX_WAIT_US #define TX_WAIT_US (5 * US_PER_S) #endif using ot::Spinel::Decoder; -static ot::Posix::RadioSpinel sRadioSpinel; - namespace ot { -namespace Posix { +namespace Spinel { static otError SpinelStatusToOtError(spinel_status_t aError) { @@ -158,15 +158,17 @@ static void LogIfFail(const char *aText, otError aError) } } -void SpinelInterface::Callbacks::HandleReceivedFrame(void) +template +void RadioSpinel::HandleReceivedFrame(void *aContext) { - static_cast(this)->HandleReceivedFrame(); + static_cast(aContext)->HandleReceivedFrame(); } -RadioSpinel::RadioSpinel(void) +template +RadioSpinel::RadioSpinel(void) : mInstance(NULL) , mRxFrameBuffer() - , mSpinelInterface(*this, mRxFrameBuffer) + , mSpinelInterface(HandleReceivedFrame, this, mRxFrameBuffer) , mCmdTidsInUse(0) , mCmdNextTid(1) , mTxRadioTid(0) @@ -195,14 +197,12 @@ RadioSpinel::RadioSpinel(void) mVersion[0] = '\0'; } -void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig) +template +void RadioSpinel::Init(bool aResetRadio, bool aRestoreDatasetFromNcp) { otError error = OT_ERROR_NONE; - bool isRcp; - SuccessOrExit(error = mSpinelInterface.Init(aPlatformConfig)); - - if (aPlatformConfig.mResetRadio) + if (aResetRadio) { SuccessOrExit(error = SendReset()); } @@ -211,18 +211,14 @@ void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig) VerifyOrExit(mIsReady, error = OT_ERROR_FAILED); SuccessOrExit(error = CheckSpinelVersion()); - SuccessOrExit(error = CheckCapabilities(isRcp)); SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion))); - SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_UINT64_S, &gNodeId)); + SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, mIeeeEui64.m8)); - gNodeId = ot::Encoding::BigEndian::HostSwap64(gNodeId); - - if (aPlatformConfig.mRestoreDatasetFromNcp && !isRcp) + if (!IsRcp() && aRestoreDatasetFromNcp) { DieNow((RestoreDatasetFromNcp() == OT_ERROR_NONE) ? OT_EXIT_SUCCESS : OT_EXIT_FAILURE); } - - SuccessOrExit(error = CheckRadioCapabilities()); + SuccessOrDie(CheckRadioCapabilities()); mRxRadioFrame.mPsdu = mRxPsdu; mTxRadioFrame.mPsdu = mTxPsdu; @@ -232,7 +228,8 @@ exit: SuccessOrDie(error); } -otError RadioSpinel::CheckSpinelVersion(void) +template +otError RadioSpinel::CheckSpinelVersion(void) { otError error = OT_ERROR_NONE; unsigned int versionMajor; @@ -254,17 +251,16 @@ exit: return error; } -otError RadioSpinel::CheckCapabilities(bool &aIsRcp) +template +bool RadioSpinel::IsRcp(void) { - otError error = OT_ERROR_NONE; uint8_t capsBuffer[kCapsBufferSize]; const uint8_t *capsData = capsBuffer; spinel_size_t capsLength = sizeof(capsBuffer); bool supportsRawRadio = false; + bool isRcp = false; - SuccessOrExit(error = Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength)); - - aIsRcp = false; + SuccessOrDie(Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength)); while (capsLength > 0) { @@ -272,12 +268,7 @@ otError RadioSpinel::CheckCapabilities(bool &aIsRcp) spinel_ssize_t unpacked; unpacked = spinel_datatype_unpack(capsData, capsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability); - VerifyOrExit(unpacked > 0, error = OT_ERROR_FAILED); - - if (capability == SPINEL_CAP_OPENTHREAD_LOG_METADATA) - { - mSupportsLogStream = true; - } + VerifyOrDie(unpacked > 0, OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); if (capability == SPINEL_CAP_MAC_RAW) { @@ -286,33 +277,36 @@ otError RadioSpinel::CheckCapabilities(bool &aIsRcp) if (capability == SPINEL_CAP_CONFIG_RADIO) { - aIsRcp = true; + isRcp = true; } capsData += unpacked; capsLength -= static_cast(unpacked); } - if (!supportsRawRadio && aIsRcp) + if (!supportsRawRadio && isRcp) { otLogCritPlat("RCP capability list does not include support for radio/raw mode"); DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); } -exit: - return error; + return isRcp; } -otError RadioSpinel::CheckRadioCapabilities(void) +template +otError RadioSpinel::CheckRadioCapabilities(void) { const otRadioCaps kRequiredRadioCaps = OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_TRANSMIT_RETRIES | OT_RADIO_CAPS_CSMA_BACKOFF; - otError error = OT_ERROR_NONE; - unsigned int caps; + otError error = OT_ERROR_NONE; + unsigned int radioCaps; + uint8_t capsBuffer[kCapsBufferSize]; + const uint8_t *capsData = capsBuffer; + spinel_size_t capsLength = sizeof(capsBuffer); - SuccessOrExit(error = Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &caps)); - mRadioCaps = static_cast(caps); + SuccessOrExit(error = Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &radioCaps)); + mRadioCaps = static_cast(radioCaps); if ((mRadioCaps & kRequiredRadioCaps) != kRequiredRadioCaps) { @@ -324,11 +318,30 @@ otError RadioSpinel::CheckRadioCapabilities(void) DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); } + SuccessOrExit(error = Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength)); + while (capsLength > 0) + { + unsigned int capability; + spinel_ssize_t unpacked = + spinel_datatype_unpack(capsData, capsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability); + + VerifyOrDie(unpacked > 0, OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + + if (capability == SPINEL_CAP_OPENTHREAD_LOG_METADATA) + { + mSupportsLogStream = true; + } + + capsData += unpacked; + capsLength -= static_cast(unpacked); + } + exit: return error; } -otError RadioSpinel::RestoreDatasetFromNcp(void) +template +otError RadioSpinel::RestoreDatasetFromNcp(void) { otError error = OT_ERROR_NONE; @@ -345,14 +358,16 @@ exit: return error; } -void RadioSpinel::Deinit(void) +template +void RadioSpinel::Deinit(void) { mSpinelInterface.Deinit(); // This allows implementing pseudo reset. new (this) RadioSpinel(); } -void RadioSpinel::HandleReceivedFrame(void) +template +void RadioSpinel::HandleReceivedFrame(void) { otError error = OT_ERROR_NONE; uint8_t header; @@ -382,7 +397,8 @@ exit: } } -void RadioSpinel::HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer) +template +void RadioSpinel::HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer) { spinel_prop_key_t key; spinel_size_t len = 0; @@ -435,7 +451,8 @@ exit: LogIfFail("Error processing notification", error); } -void RadioSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength) +template +void RadioSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength) { spinel_prop_key_t key; spinel_size_t len = 0; @@ -455,7 +472,8 @@ exit: LogIfFail("Error processing saved notification", error); } -void RadioSpinel::HandleResponse(const uint8_t *aBuffer, uint16_t aLength) +template +void RadioSpinel::HandleResponse(const uint8_t *aBuffer, uint16_t aLength) { spinel_prop_key_t key; uint8_t * data = NULL; @@ -495,7 +513,8 @@ exit: LogIfFail("Error processing response", error); } -otError RadioSpinel::ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength) +template +otError RadioSpinel::ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength) { otError error = OT_ERROR_NONE; otOperationalDataset opDataset; @@ -648,10 +667,11 @@ exit: return error; } -void RadioSpinel::HandleWaitingResponse(uint32_t aCommand, - spinel_prop_key_t aKey, - const uint8_t * aBuffer, - uint16_t aLength) +template +void RadioSpinel::HandleWaitingResponse(uint32_t aCommand, + spinel_prop_key_t aKey, + const uint8_t * aBuffer, + uint16_t aLength) { if (aKey == SPINEL_PROP_LAST_STATUS) { @@ -714,7 +734,10 @@ exit: LogIfFail("Error processing result", mError); } -void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength) +template +void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, + const uint8_t * aBuffer, + uint16_t aLength) { otError error = OT_ERROR_NONE; @@ -813,7 +836,10 @@ exit: LogIfFail("Failed to handle ValueIs", error); } -otError RadioSpinel::ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength) +template +otError RadioSpinel::ParseRadioFrame(otRadioFrame & aFrame, + const uint8_t *aBuffer, + uint16_t aLength) { otError error = OT_ERROR_NONE; uint16_t flags = 0; @@ -860,7 +886,8 @@ exit: return error; } -void RadioSpinel::ProcessFrameQueue(void) +template +void RadioSpinel::ProcessFrameQueue(void) { uint8_t *frame = NULL; uint16_t length; @@ -873,7 +900,8 @@ void RadioSpinel::ProcessFrameQueue(void) mRxFrameBuffer.ClearSavedFrames(); } -void RadioSpinel::RadioReceive(void) +template +void RadioSpinel::RadioReceive(void) { if (!mIsPromiscuous) { @@ -905,7 +933,10 @@ exit: return; } -void RadioSpinel::TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError) +template +void RadioSpinel::TransmitDone(otRadioFrame *aFrame, + otRadioFrame *aAckFrame, + otError aError) { #if OPENTHREAD_CONFIG_DIAG_ENABLE if (otPlatDiagModeGet()) @@ -919,53 +950,9 @@ void RadioSpinel::TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, ot } } -void RadioSpinel::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout) +template +void RadioSpinel::ProcessRadioStateMachine(void) { - mSpinelInterface.UpdateFdSet(aReadFdSet, aWriteFdSet, aMaxFd, aTimeout); - - if (mState == kStateTransmitting) - { - uint64_t now = platformGetTime(); - - if (now < mTxRadioEndUs) - { - uint64_t remain = mTxRadioEndUs - now; - - if (remain < static_cast(aTimeout.tv_sec * US_PER_S + aTimeout.tv_usec)) - { - aTimeout.tv_sec = static_cast(remain / US_PER_S); - aTimeout.tv_usec = static_cast(remain % US_PER_S); - } - } - else - { - aTimeout.tv_sec = 0; - aTimeout.tv_usec = 0; - } - } - - if (mRxFrameBuffer.HasSavedFrame() || (mState == kStateTransmitDone)) - { - aTimeout.tv_sec = 0; - aTimeout.tv_usec = 0; - } -} - -void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet) -{ - if (mRxFrameBuffer.HasSavedFrame()) - { - // Handle frames received and saved during `WaitResponse()` - ProcessFrameQueue(); - } - - mSpinelInterface.Process(aReadFdSet, aWriteFdSet); - - if (mRxFrameBuffer.HasSavedFrame()) - { - ProcessFrameQueue(); - } - if (mState == kStateTransmitDone) { mState = kStateReceive; @@ -973,14 +960,33 @@ void RadioSpinel::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet) TransmitDone(mTransmitFrame, (mAckRadioFrame.mLength != 0) ? &mAckRadioFrame : NULL, mTxError); } - else if (mState == kStateTransmitting && platformGetTime() >= mTxRadioEndUs) + else if (mState == kStateTransmitting && otPlatTimeGet() >= mTxRadioEndUs) { // Frame has been successfully passed to radio, but no `TransmitDone` event received within TX_WAIT_US. DieNowWithMessage("radio tx timeout", OT_EXIT_FAILURE); } } -otError RadioSpinel::SetPromiscuous(bool aEnable) +template +void RadioSpinel::Process(const ProcessContextType &aContext) +{ + if (mRxFrameBuffer.HasSavedFrame()) + { + ProcessFrameQueue(); + } + + GetSpinelInterface().Process(aContext); + + if (mRxFrameBuffer.HasSavedFrame()) + { + ProcessFrameQueue(); + } + + ProcessRadioStateMachine(); +} + +template +otError RadioSpinel::SetPromiscuous(bool aEnable) { otError error; @@ -992,24 +998,29 @@ exit: return error; } -otError RadioSpinel::SetShortAddress(uint16_t aAddress) +template +otError RadioSpinel::SetShortAddress(uint16_t aAddress) { otError error = OT_ERROR_NONE; VerifyOrExit(mShortAddress != aAddress, OT_NOOP); - SuccessOrExit(error = sRadioSpinel.Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, aAddress)); + SuccessOrExit(error = Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, aAddress)); mShortAddress = aAddress; exit: return error; } -otError RadioSpinel::GetIeeeEui64(uint8_t *aIeeeEui64) +template +otError RadioSpinel::GetIeeeEui64(uint8_t *aIeeeEui64) { - return Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, aIeeeEui64); + memcpy(aIeeeEui64, mIeeeEui64.m8, sizeof(mIeeeEui64.m8)); + + return OT_ERROR_NONE; } -otError RadioSpinel::SetExtendedAddress(const otExtAddress &aExtAddress) +template +otError RadioSpinel::SetExtendedAddress(const otExtAddress &aExtAddress) { otError error; @@ -1020,7 +1031,8 @@ exit: return error; } -otError RadioSpinel::SetPanId(uint16_t aPanId) +template +otError RadioSpinel::SetPanId(uint16_t aPanId) { otError error = OT_ERROR_NONE; @@ -1032,42 +1044,50 @@ exit: return error; } -otError RadioSpinel::EnableSrcMatch(bool aEnable) +template +otError RadioSpinel::EnableSrcMatch(bool aEnable) { return Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, aEnable); } -otError RadioSpinel::AddSrcMatchShortEntry(const uint16_t aShortAddress) +template +otError RadioSpinel::AddSrcMatchShortEntry(const uint16_t aShortAddress) { return Insert(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, aShortAddress); } -otError RadioSpinel::AddSrcMatchExtEntry(const otExtAddress &aExtAddress) +template +otError RadioSpinel::AddSrcMatchExtEntry(const otExtAddress &aExtAddress) { return Insert(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, aExtAddress.m8); } -otError RadioSpinel::ClearSrcMatchShortEntry(const uint16_t aShortAddress) +template +otError RadioSpinel::ClearSrcMatchShortEntry(const uint16_t aShortAddress) { return Remove(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, aShortAddress); } -otError RadioSpinel::ClearSrcMatchExtEntry(const otExtAddress &aExtAddress) +template +otError RadioSpinel::ClearSrcMatchExtEntry(const otExtAddress &aExtAddress) { return Remove(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, aExtAddress.m8); } -otError RadioSpinel::ClearSrcMatchShortEntries(void) +template +otError RadioSpinel::ClearSrcMatchShortEntries(void) { return Set(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, NULL); } -otError RadioSpinel::ClearSrcMatchExtEntries(void) +template +otError RadioSpinel::ClearSrcMatchExtEntries(void) { return Set(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, NULL); } -otError RadioSpinel::GetTransmitPower(int8_t &aPower) +template +otError RadioSpinel::GetTransmitPower(int8_t &aPower) { otError error = Get(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, &aPower); @@ -1075,7 +1095,8 @@ otError RadioSpinel::GetTransmitPower(int8_t &aPower) return error; } -otError RadioSpinel::GetCcaEnergyDetectThreshold(int8_t &aThreshold) +template +otError RadioSpinel::GetCcaEnergyDetectThreshold(int8_t &aThreshold) { otError error = Get(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, &aThreshold); @@ -1083,7 +1104,8 @@ otError RadioSpinel::GetCcaEnergyDetectThreshold(int8_t &aThreshold) return error; } -int8_t RadioSpinel::GetRssi(void) +template +int8_t RadioSpinel::GetRssi(void) { int8_t rssi = OT_RADIO_RSSI_INVALID; otError error = Get(SPINEL_PROP_PHY_RSSI, SPINEL_DATATYPE_INT8_S, &rssi); @@ -1093,12 +1115,14 @@ int8_t RadioSpinel::GetRssi(void) } #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE -otError RadioSpinel::SetCoexEnabled(bool aEnabled) +template +otError RadioSpinel::SetCoexEnabled(bool aEnabled) { return Set(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, aEnabled); } -bool RadioSpinel::IsCoexEnabled(void) +template +bool RadioSpinel::IsCoexEnabled(void) { bool enabled; otError error = Get(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, &enabled); @@ -1107,7 +1131,8 @@ bool RadioSpinel::IsCoexEnabled(void) return enabled; } -otError RadioSpinel::GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics) +template +otError RadioSpinel::GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics) { otError error; @@ -1147,21 +1172,24 @@ otError RadioSpinel::GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics) } #endif -otError RadioSpinel::SetTransmitPower(int8_t aPower) +template +otError RadioSpinel::SetTransmitPower(int8_t aPower) { otError error = Set(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, aPower); LogIfFail("Set transmit power failed", error); return error; } -otError RadioSpinel::SetCcaEnergyDetectThreshold(int8_t aThreshold) +template +otError RadioSpinel::SetCcaEnergyDetectThreshold(int8_t aThreshold) { otError error = Set(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, aThreshold); LogIfFail("Set CCA ED threshold failed", error); return error; } -otError RadioSpinel::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration) +template +otError RadioSpinel::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration) { otError error; @@ -1175,7 +1203,8 @@ exit: return error; } -otError RadioSpinel::Get(spinel_prop_key_t aKey, const char *aFormat, ...) +template +otError RadioSpinel::Get(spinel_prop_key_t aKey, const char *aFormat, ...) { otError error; @@ -1190,7 +1219,8 @@ otError RadioSpinel::Get(spinel_prop_key_t aKey, const char *aFormat, ...) return error; } -otError RadioSpinel::Set(spinel_prop_key_t aKey, const char *aFormat, ...) +template +otError RadioSpinel::Set(spinel_prop_key_t aKey, const char *aFormat, ...) { otError error; @@ -1205,7 +1235,8 @@ otError RadioSpinel::Set(spinel_prop_key_t aKey, const char *aFormat, ...) return error; } -otError RadioSpinel::Insert(spinel_prop_key_t aKey, const char *aFormat, ...) +template +otError RadioSpinel::Insert(spinel_prop_key_t aKey, const char *aFormat, ...) { otError error; @@ -1220,7 +1251,8 @@ otError RadioSpinel::Insert(spinel_prop_key_t aKey, const char *aFormat, ...) return error; } -otError RadioSpinel::Remove(spinel_prop_key_t aKey, const char *aFormat, ...) +template +otError RadioSpinel::Remove(spinel_prop_key_t aKey, const char *aFormat, ...) { otError error; @@ -1235,26 +1267,23 @@ otError RadioSpinel::Remove(spinel_prop_key_t aKey, const char *aFormat, ...) return error; } -otError RadioSpinel::WaitResponse(void) +template +otError RadioSpinel::WaitResponse(void) { - uint64_t end = platformGetTime() + kMaxWaitTime * US_PER_MS; + uint64_t end = otPlatTimeGet() + kMaxWaitTime * US_PER_MS; otLogDebgPlat("Wait response: tid=%u key=%u", mWaitingTid, mWaitingKey); do { - uint64_t now; - uint64_t remain; - struct timeval timeout; + uint64_t now; + uint64_t remain; - now = platformGetTime(); + now = otPlatTimeGet(); VerifyOrDie(end > now, OT_EXIT_RADIO_SPINEL_NO_RESPONSE); remain = end - now; - timeout.tv_sec = static_cast(remain / US_PER_S); - timeout.tv_usec = static_cast(remain % US_PER_S); - - VerifyOrDie(mSpinelInterface.WaitForFrame(timeout) == OT_ERROR_NONE, OT_EXIT_RADIO_SPINEL_NO_RESPONSE); + VerifyOrDie(mSpinelInterface.WaitForFrame(remain) == OT_ERROR_NONE, OT_EXIT_RADIO_SPINEL_NO_RESPONSE); } while (mWaitingTid || !mIsReady); LogIfFail("Error waiting response", mError); @@ -1263,7 +1292,8 @@ otError RadioSpinel::WaitResponse(void) return mError; } -spinel_tid_t RadioSpinel::GetNextTid(void) +template +spinel_tid_t RadioSpinel::GetNextTid(void) { spinel_tid_t tid = 0; @@ -1277,7 +1307,8 @@ spinel_tid_t RadioSpinel::GetNextTid(void) return tid; } -otError RadioSpinel::SendReset(void) +template +otError RadioSpinel::SendReset(void) { otError error = OT_ERROR_NONE; uint8_t buffer[kMaxSpinelFrame]; @@ -1291,17 +1322,16 @@ otError RadioSpinel::SendReset(void) SuccessOrExit(error = mSpinelInterface.SendFrame(buffer, static_cast(packed))); - sleep(0); - exit: return error; } -otError RadioSpinel::SendCommand(uint32_t aCommand, - spinel_prop_key_t aKey, - spinel_tid_t tid, - const char * aFormat, - va_list args) +template +otError RadioSpinel::SendCommand(uint32_t aCommand, + spinel_prop_key_t aKey, + spinel_tid_t tid, + const char * aFormat, + va_list args) { otError error = OT_ERROR_NONE; uint8_t buffer[kMaxSpinelFrame]; @@ -1331,7 +1361,12 @@ exit: return error; } -otError RadioSpinel::RequestV(bool aWait, uint32_t command, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs) +template +otError RadioSpinel::RequestV(bool aWait, + uint32_t command, + spinel_prop_key_t aKey, + const char * aFormat, + va_list aArgs) { otError error = OT_ERROR_NONE; spinel_tid_t tid = (aWait ? GetNextTid() : 0); @@ -1359,7 +1394,12 @@ exit: return error; } -otError RadioSpinel::Request(bool aWait, uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...) +template +otError RadioSpinel::Request(bool aWait, + uint32_t aCommand, + spinel_prop_key_t aKey, + const char * aFormat, + ...) { va_list args; va_start(args, aFormat); @@ -1368,10 +1408,11 @@ otError RadioSpinel::Request(bool aWait, uint32_t aCommand, spinel_prop_key_t aK return status; } -void RadioSpinel::HandleTransmitDone(uint32_t aCommand, - spinel_prop_key_t aKey, - const uint8_t * aBuffer, - uint16_t aLength) +template +void RadioSpinel::HandleTransmitDone(uint32_t aCommand, + spinel_prop_key_t aKey, + const uint8_t * aBuffer, + uint16_t aLength) { otError error = OT_ERROR_NONE; spinel_status_t status = SPINEL_STATUS_OK; @@ -1415,7 +1456,8 @@ exit: LogIfFail("Handle transmit done failed", error); } -otError RadioSpinel::Transmit(otRadioFrame &aFrame) +template +otError RadioSpinel::Transmit(otRadioFrame &aFrame) { otError error = OT_ERROR_INVALID_STATE; @@ -1440,14 +1482,15 @@ otError RadioSpinel::Transmit(otRadioFrame &aFrame) { // Waiting for `TransmitDone` event. mState = kStateTransmitting; - mTxRadioEndUs = platformGetTime() + TX_WAIT_US; + mTxRadioEndUs = otPlatTimeGet() + TX_WAIT_US; } exit: return error; } -otError RadioSpinel::Receive(uint8_t aChannel) +template +otError RadioSpinel::Receive(uint8_t aChannel) { otError error = OT_ERROR_NONE; @@ -1478,14 +1521,15 @@ exit: return error; } -otError RadioSpinel::Sleep(void) +template +otError RadioSpinel::Sleep(void) { otError error = OT_ERROR_NONE; switch (mState) { case kStateReceive: - error = sRadioSpinel.Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, false); + error = Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, false); SuccessOrExit(error); mState = kStateSleep; @@ -1503,7 +1547,8 @@ exit: return error; } -otError RadioSpinel::Enable(otInstance *aInstance) +template +otError RadioSpinel::Enable(otInstance *aInstance) { otError error = OT_ERROR_NONE; @@ -1528,14 +1573,15 @@ exit: return error; } -otError RadioSpinel::Disable(void) +template +otError RadioSpinel::Disable(void) { otError error = OT_ERROR_NONE; VerifyOrExit(IsEnabled(), OT_NOOP); VerifyOrExit(mState == kStateSleep, error = OT_ERROR_INVALID_STATE); - SuccessOrDie(sRadioSpinel.Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, false)); + SuccessOrDie(Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, false)); mState = kStateDisabled; mInstance = NULL; @@ -1544,7 +1590,10 @@ exit: } #if OPENTHREAD_CONFIG_DIAG_ENABLE -otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen) +template +otError RadioSpinel::PlatDiagProcess(const char *aString, + char * aOutput, + size_t aOutputMaxLen) { otError error; @@ -1560,7 +1609,8 @@ otError RadioSpinel::PlatDiagProcess(const char *aString, char *aOutput, size_t } #endif -uint32_t RadioSpinel::GetRadioChannelMask(bool aPreferred) +template +uint32_t RadioSpinel::GetRadioChannelMask(bool aPreferred) { uint8_t maskBuffer[kChannelMaskBufferSize]; otError error = OT_ERROR_NONE; @@ -1590,7 +1640,8 @@ exit: return channelMask; } -otRadioState RadioSpinel::GetState(void) const +template +otRadioState RadioSpinel::GetState(void) const { static const otRadioState sOtRadioStateMap[] = { OT_RADIO_STATE_DISABLED, OT_RADIO_STATE_SLEEP, OT_RADIO_STATE_RECEIVE, @@ -1600,379 +1651,5 @@ otRadioState RadioSpinel::GetState(void) const return sOtRadioStateMap[mState]; } -} // namespace Posix +} // namespace Spinel } // namespace ot - -void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) -{ - SuccessOrDie(sRadioSpinel.GetIeeeEui64(aIeeeEui64)); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid) -{ - SuccessOrDie(sRadioSpinel.SetPanId(panid)); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) -{ - otExtAddress addr; - - for (size_t i = 0; i < sizeof(addr); i++) - { - addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i]; - } - - SuccessOrDie(sRadioSpinel.SetExtendedAddress(addr)); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) -{ - SuccessOrDie(sRadioSpinel.SetShortAddress(aAddress)); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) -{ - SuccessOrDie(sRadioSpinel.SetPromiscuous(aEnable)); - OT_UNUSED_VARIABLE(aInstance); -} - -void platformRadioInit(const otPlatformConfig *aPlatformConfig) -{ - sRadioSpinel.Init(*aPlatformConfig); -} - -void platformRadioDeinit(void) -{ - sRadioSpinel.Deinit(); -} - -bool otPlatRadioIsEnabled(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.IsEnabled(); -} - -otError otPlatRadioEnable(otInstance *aInstance) -{ - return sRadioSpinel.Enable(aInstance); -} - -otError otPlatRadioDisable(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.Disable(); -} - -otError otPlatRadioSleep(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.Sleep(); -} - -otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.Receive(aChannel); -} - -otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.Transmit(*aFrame); -} - -otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return &sRadioSpinel.GetTransmitFrame(); -} - -int8_t otPlatRadioGetRssi(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetRssi(); -} - -otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetRadioCaps(); -} - -const char *otPlatRadioGetVersionString(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetVersion(); -} - -bool otPlatRadioGetPromiscuous(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.IsPromiscuous(); -} - -void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd, struct timeval *aTimeout) -{ - sRadioSpinel.UpdateFdSet(*aReadFdSet, *aWriteFdSet, *aMaxFd, *aTimeout); -} - -void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet) -{ - sRadioSpinel.Process(*aReadFdSet, *aWriteFdSet); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) -{ - SuccessOrDie(sRadioSpinel.EnableSrcMatch(aEnable)); - OT_UNUSED_VARIABLE(aInstance); -} - -otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.AddSrcMatchShortEntry(aShortAddress); -} - -otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) -{ - otExtAddress addr; - - for (size_t i = 0; i < sizeof(addr); i++) - { - addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i]; - } - - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.AddSrcMatchExtEntry(addr); -} - -otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.ClearSrcMatchShortEntry(aShortAddress); -} - -otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) -{ - otExtAddress addr; - - for (size_t i = 0; i < sizeof(addr); i++) - { - addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i]; - } - - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.ClearSrcMatchExtEntry(addr); -} - -void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) -{ - SuccessOrDie(sRadioSpinel.ClearSrcMatchShortEntries()); - OT_UNUSED_VARIABLE(aInstance); -} - -void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) -{ - SuccessOrDie(sRadioSpinel.ClearSrcMatchExtEntries()); - OT_UNUSED_VARIABLE(aInstance); -} - -otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.EnergyScan(aScanChannel, aScanDuration); -} - -otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) -{ - assert(aPower != NULL); - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetTransmitPower(*aPower); -} - -otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.SetTransmitPower(aPower); -} - -otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) -{ - assert(aThreshold != NULL); - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetCcaEnergyDetectThreshold(*aThreshold); -} - -otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.SetCcaEnergyDetectThreshold(aThreshold); -} - -int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetReceiveSensitivity(); -} - -#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE -otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.SetCoexEnabled(aEnabled); -} - -bool otPlatRadioIsCoexEnabled(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.IsCoexEnabled(); -} - -otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics) -{ - OT_UNUSED_VARIABLE(aInstance); - - otError error = OT_ERROR_NONE; - - VerifyOrExit(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS); - - error = sRadioSpinel.GetCoexMetrics(*aCoexMetrics); - -exit: - return error; -} -#endif - -#if OPENTHREAD_POSIX_VIRTUAL_TIME -void ot::Posix::RadioSpinel::Process(const Event &aEvent) -{ - if (mRxFrameBuffer.HasSavedFrame()) - { - ProcessFrameQueue(); - } - - // The current event can be other event types - if (aEvent.mEvent == OT_SIM_EVENT_RADIO_SPINEL_WRITE) - { - mSpinelInterface.ProcessReadData(aEvent.mData, aEvent.mDataLength); - } - - if (mRxFrameBuffer.HasSavedFrame()) - { - ProcessFrameQueue(); - } - - if (mState == kStateTransmitDone) - { - mState = kStateReceive; - mTxRadioEndUs = UINT64_MAX; - - TransmitDone(mTransmitFrame, (mAckRadioFrame.mLength != 0) ? &mAckRadioFrame : NULL, mTxError); - } - else if (mState == kStateTransmitting && platformGetTime() >= mTxRadioEndUs) - { - // Frame has been successfully passed to radio, but no `TransmitDone` event received within TX_WAIT_US. - DieNowWithMessage("radio tx timeout", OT_EXIT_FAILURE); - } -} - -void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct Event *aEvent) -{ - sRadioSpinel.Process(*aEvent); - OT_UNUSED_VARIABLE(aInstance); -} -#endif // OPENTHREAD_POSIX_VIRTUAL_TIME - -#if OPENTHREAD_CONFIG_DIAG_ENABLE -otError otPlatDiagProcess(otInstance *aInstance, - uint8_t aArgsLength, - char * aArgs[], - char * aOutput, - size_t aOutputMaxLen) -{ - // deliver the platform specific diags commands to radio only ncp. - OT_UNUSED_VARIABLE(aInstance); - - char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'}; - char *cur = cmd; - char *end = cmd + sizeof(cmd); - - for (uint8_t index = 0; index < aArgsLength; index++) - { - cur += snprintf(cur, static_cast(end - cur), "%s ", aArgs[index]); - } - - return sRadioSpinel.PlatDiagProcess(cmd, aOutput, aOutputMaxLen); -} - -void otPlatDiagModeSet(bool aMode) -{ - SuccessOrExit(sRadioSpinel.PlatDiagProcess(aMode ? "start" : "stop", NULL, 0)); - sRadioSpinel.SetDiagEnabled(aMode); - -exit: - return; -} - -bool otPlatDiagModeGet(void) -{ - return sRadioSpinel.IsDiagEnabled(); -} - -void otPlatDiagTxPowerSet(int8_t aTxPower) -{ - char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; - - snprintf(cmd, sizeof(cmd), "power %d", aTxPower); - SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); - -exit: - return; -} - -void otPlatDiagChannelSet(uint8_t aChannel) -{ - char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; - - snprintf(cmd, sizeof(cmd), "channel %d", aChannel); - SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); - -exit: - return; -} - -void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) -{ - OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aFrame); - OT_UNUSED_VARIABLE(aError); -} - -void otPlatDiagAlarmCallback(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); -} -#endif // OPENTHREAD_CONFIG_DIAG_ENABLE - -uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetRadioChannelMask(false); -} - -uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetRadioChannelMask(true); -} - -otRadioState otPlatRadioGetState(otInstance *aInstance) -{ - OT_UNUSED_VARIABLE(aInstance); - return sRadioSpinel.GetState(); -} diff --git a/src/posix/platform/spinel_interface.hpp b/src/lib/spinel/spinel_interface.hpp similarity index 75% rename from src/posix/platform/spinel_interface.hpp rename to src/lib/spinel/spinel_interface.hpp index 5e203139a..950f09ffa 100644 --- a/src/posix/platform/spinel_interface.hpp +++ b/src/lib/spinel/spinel_interface.hpp @@ -35,12 +35,10 @@ #ifndef POSIX_APP_SPINEL_INTERFACE_HPP_ #define POSIX_APP_SPINEL_INTERFACE_HPP_ -#include "openthread-posix-config.h" - #include "lib/hdlc/hdlc.hpp" namespace ot { -namespace Posix { +namespace Spinel { class SpinelInterface { @@ -59,26 +57,9 @@ public: */ typedef Hdlc::MultiFrameBuffer RxFrameBuffer; - /** - * This class defines the callbacks provided by `SpinelInterface` to its owner/user. - * - */ - class Callbacks - { - public: - /** - * This callback is invoked to notify owner/user of `SpinelInterface` of a received spinel frame. - * - * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`. - * User can read and process the frame. The callback is expected to either discard the new frame using - * `RxFrameBuffer::DiscardFrame()` or save the frame using `RxFrameBuffer::SaveFrame()` to be read and - * processed later. - * - */ - void HandleReceivedFrame(void); - }; + typedef void (*ReceiveFrameCallback)(void *aContext); }; -} // namespace Posix +} // namespace Spinel } // namespace ot #endif // POSIX_APP_SPINEL_INTERFACE_HPP_ diff --git a/src/posix/Makefile.am b/src/posix/Makefile.am index 92741934f..fd2bfbb1f 100644 --- a/src/posix/Makefile.am +++ b/src/posix/Makefile.am @@ -42,6 +42,7 @@ SUBDIRS = \ CPPFLAGS_COMMON = \ -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/core \ -I$(top_srcdir)/src/posix/platform \ -I$(top_srcdir)/src/posix/platform/include \ @@ -54,6 +55,7 @@ CPPFLAGS_COMMON = \ LIBTOOLFLAGS_COMMON = --preserve-dup-deps LDADD_COMMON = \ + $(top_builddir)/src/lib/platform/libopenthread-platform.a \ $(top_builddir)/src/posix/platform/libopenthread-posix.a \ -lutil \ $(NULL) diff --git a/src/posix/daemon.cmake b/src/posix/daemon.cmake index 1b3ff8a54..3c8d77420 100644 --- a/src/posix/daemon.cmake +++ b/src/posix/daemon.cmake @@ -76,6 +76,7 @@ target_compile_options(ot-ctl PRIVATE ) target_link_libraries(ot-ctl + openthread-platform $<$:${OT_READLINE}> ) diff --git a/src/posix/main.c b/src/posix/main.c index 3f2b06630..3f3e4b927 100644 --- a/src/posix/main.c +++ b/src/posix/main.c @@ -74,6 +74,7 @@ #else #error "Unknown posix app type!" #endif +#include #include #ifndef OPENTHREAD_ENABLE_COVERAGE diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index f07b5d199..d6458f80c 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -59,7 +59,7 @@ add_library(openthread-posix logging.cpp misc.cpp netif.cpp - radio_spinel.cpp + radio.cpp settings.cpp spi_interface.cpp system.cpp @@ -76,6 +76,7 @@ set_target_properties( ) target_link_libraries(openthread-posix PUBLIC + openthread-platform util ) diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index 7b1fa37e5..6d4855ef6 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -49,7 +49,7 @@ libopenthread_posix_a_SOURCES = \ logging.cpp \ misc.cpp \ netif.cpp \ - radio_spinel.cpp \ + radio.cpp \ settings.cpp \ spi_interface.cpp \ system.cpp \ @@ -62,8 +62,6 @@ noinst_HEADERS = \ hdlc_interface.hpp \ openthread-posix-config.h \ platform-posix.h \ - radio_spinel.hpp \ - spinel_interface.hpp \ $(NULL) openthread_HEADERS = \ @@ -81,6 +79,7 @@ check_PROGRAMS = test-settings test_settings_CPPFLAGS = \ -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ -I$(top_srcdir)/src/core \ -I$(top_srcdir)/src/posix/platform/include \ -DOPENTHREAD_CONFIG_LOG_PLATFORM=0 \ diff --git a/src/posix/platform/alarm.cpp b/src/posix/platform/alarm.cpp index 14f74ab3b..f74f1367c 100644 --- a/src/posix/platform/alarm.cpp +++ b/src/posix/platform/alarm.cpp @@ -51,7 +51,7 @@ static uint32_t sUsAlarm = 0; static uint32_t sSpeedUpFactor = 1; #if !OPENTHREAD_POSIX_VIRTUAL_TIME -uint64_t platformGetTime(void) +uint64_t otPlatTimeGet(void) { struct timespec now; @@ -67,7 +67,7 @@ uint64_t platformGetTime(void) static uint64_t platformAlarmGetNow(void) { - return platformGetTime() * sSpeedUpFactor; + return otPlatTimeGet() * sSpeedUpFactor; } void platformAlarmInit(uint32_t aSpeedUpFactor) @@ -98,7 +98,7 @@ void otPlatAlarmMilliStop(otInstance *aInstance) #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE uint32_t otPlatAlarmMicroGetNow(void) { - return (uint32_t)(platformGetTime()); + return (uint32_t)(otPlatTimeGet()); } void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) diff --git a/src/posix/platform/hdlc_interface.cpp b/src/posix/platform/hdlc_interface.cpp index 1d0492ffa..aaa450f4f 100644 --- a/src/posix/platform/hdlc_interface.cpp +++ b/src/posix/platform/hdlc_interface.cpp @@ -120,12 +120,17 @@ #if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE +using ot::Spinel::SpinelInterface; + namespace ot { namespace Posix { -HdlcInterface::HdlcInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer) - : mCallbacks(aCallback) - , mRxFrameBuffer(aFrameBuffer) +HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + SpinelInterface::RxFrameBuffer & aFrameBuffer) + : mReceiveFrameCallback(aCallback) + , mReceiveFrameContext(aCallbackContext) + , mReceiveFrameBuffer(aFrameBuffer) , mSockFd(-1) , mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this) { @@ -248,14 +253,17 @@ exit: return error; } -otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) +otError HdlcInterface::WaitForFrame(uint64_t aTimeoutUs) { - otError error = OT_ERROR_NONE; + otError error = OT_ERROR_NONE; + struct timeval timeout; #if OPENTHREAD_POSIX_VIRTUAL_TIME struct Event event; - uint64_t delay = static_cast(aTimeout.tv_sec) * US_PER_S + static_cast(aTimeout.tv_usec); - virtualTimeSendSleepEvent(&aTimeout); + timeout.tv_sec = aTimeoutUs / US_PER_S; + timeout.tv_usec = aTimeoutUs % US_PER_S; + + virtualTimeSendSleepEvent(&timeout); virtualTimeReceiveEvent(&event); switch (event.mEvent) @@ -265,7 +273,7 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) break; case OT_SIM_EVENT_ALARM_FIRED: - VerifyOrExit(event.mDelay <= delay, error = OT_ERROR_RESPONSE_TIMEOUT); + VerifyOrExit(event.mDelay <= aTimeoutUs, error = OT_ERROR_RESPONSE_TIMEOUT); break; default: @@ -273,7 +281,8 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout) break; } #else // OPENTHREAD_POSIX_VIRTUAL_TIME - struct timeval timeout = aTimeout; + timeout.tv_sec = aTimeoutUs / US_PER_S; + timeout.tv_usec = aTimeoutUs % US_PER_S; fd_set read_fds; fd_set error_fds; @@ -328,11 +337,9 @@ void HdlcInterface::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aM } } -void HdlcInterface::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet) +void HdlcInterface::Process(const RadioProcessContext &aContext) { - OT_UNUSED_VARIABLE(aWriteFdSet); - - if (FD_ISSET(mSockFd, &aReadFdSet)) + if (FD_ISSET(mSockFd, aContext.mReadFdSet)) { Read(); } @@ -342,7 +349,7 @@ otError HdlcInterface::WaitForWritable(void) { otError error = OT_ERROR_NONE; struct timeval timeout = {kMaxWaitTime / 1000, (kMaxWaitTime % 1000) * 1000}; - uint64_t now = platformGetTime(); + uint64_t now = otPlatTimeGet(); uint64_t end = now + kMaxWaitTime * US_PER_MS; fd_set writeFds; fd_set errorFds; @@ -377,7 +384,7 @@ otError HdlcInterface::WaitForWritable(void) DieNow(OT_EXIT_ERROR_ERRNO); } - now = platformGetTime(); + now = otPlatTimeGet(); if (end > now) { @@ -626,11 +633,11 @@ void HdlcInterface::HandleHdlcFrame(otError aError) { if (aError == OT_ERROR_NONE) { - mCallbacks.HandleReceivedFrame(); + mReceiveFrameCallback(mReceiveFrameContext); } else { - mRxFrameBuffer.DiscardFrame(); + mReceiveFrameBuffer.DiscardFrame(); otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError)); } } diff --git a/src/posix/platform/hdlc_interface.hpp b/src/posix/platform/hdlc_interface.hpp index 621ad26c8..915fa7263 100644 --- a/src/posix/platform/hdlc_interface.hpp +++ b/src/posix/platform/hdlc_interface.hpp @@ -36,8 +36,8 @@ #include "openthread-posix-config.h" #include "platform-posix.h" -#include "spinel_interface.hpp" #include "lib/hdlc/hdlc.hpp" +#include "lib/spinel/spinel_interface.hpp" #if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE @@ -54,11 +54,14 @@ public: /** * This constructor initializes the object. * - * @param[in] aCallback A reference to a `Callback` object. - * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. + * @param[in] aCallback Callback on frame received + * @param[in] aCallbackContext Callback context + * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. * */ - HdlcInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer); + HdlcInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); /** * This destructor deinitializes the object. @@ -105,13 +108,13 @@ public: /** * This method waits for receiving part or all of spinel frame within specified interval. * - * @param[in] aTimeout A reference to the timeout. + * @param[in] aTimeout The timeout value in microseconds. * * @retval OT_ERROR_NONE Part or all of spinel frame is received. * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. * */ - otError WaitForFrame(const struct timeval &aTimeout); + otError WaitForFrame(uint64_t aTimeoutUs); /** * This method updates the file descriptor sets with file descriptors used by the radio driver. @@ -127,24 +130,22 @@ public: /** * This method performs radio driver processing. * - * @param[in] aReadFdSet A reference to the read file descriptors. - * @param[in] aWriteFdSet A reference to the write file descriptors. + * @param[in] aContext The context containing fd_sets. * */ - void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); + void Process(const RadioProcessContext &aContext); #if OPENTHREAD_POSIX_VIRTUAL_TIME /** * This method process read data (decode the data). * * This method is intended only for virtual time simulation. Its behavior is similar to `Read()` but instead of - * reading the data from the radio socket, it uses the given data in the buffer `aBuffer`. + * reading the data from the radio socket, it uses the given data in @p `aEvent`. * - * @param[in] aBuffer A pointer to buffer containing data. - * @param[in] aLength The length (number of bytes) in the buffer. + * @param[in] aEvent The data event. * */ - void ProcessReadData(const uint8_t *aBuffer, uint16_t aLength) { Decode(aBuffer, aLength); } + void Process(const Event &aEvent) { Decode(aEvent.mData, aEvent.mDataLength); } #endif private: @@ -204,15 +205,20 @@ private: enum { - kMaxFrameSize = SpinelInterface::kMaxFrameSize, + kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize, kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`). }; - SpinelInterface::Callbacks & mCallbacks; - SpinelInterface::RxFrameBuffer &mRxFrameBuffer; + Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback; + void * mReceiveFrameContext; + Spinel::SpinelInterface::RxFrameBuffer & mReceiveFrameBuffer; int mSockFd; Hdlc::Decoder mHdlcDecoder; + + // Non-copyable, intentionally not implemented. + HdlcInterface(const HdlcInterface &); + HdlcInterface &operator=(const HdlcInterface &); }; } // namespace Posix diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index 476940563..7d2628be3 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -47,48 +47,6 @@ extern "C" { #endif -/** - * This enumeration represents exit codes used when OpenThread exits. - * - */ -enum -{ - /** - * Success. - */ - OT_EXIT_SUCCESS = 0, - - /** - * Generic failure. - */ - OT_EXIT_FAILURE = 1, - - /** - * Invalid arguments. - */ - OT_EXIT_INVALID_ARGUMENTS = 2, - - /** - * Incompatible radio spinel. - */ - OT_EXIT_RADIO_SPINEL_INCOMPATIBLE = 3, - - /** - * Unexpected radio spinel reset. - */ - OT_EXIT_RADIO_SPINEL_RESET = 4, - - /** - * System call or library function error. - */ - OT_EXIT_ERROR_ERRNO = 5, - - /** - * No response from radio spinel. - */ - OT_EXIT_RADIO_SPINEL_NO_RESPONSE = 6, -}; - /** * This enumeration represents default parameters for the SPI interface. * diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index 397e7a164..2f077d46f 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -46,9 +46,12 @@ #include #include #include +#include #include "common/logging.hpp" +#include "lib/platform/exit_code.h" + /** * @def OPENTHREAD_POSIX_VIRTUAL_TIME * @@ -87,69 +90,11 @@ struct Event uint8_t mData[OT_EVENT_DATA_MAX_SIZE]; } OT_TOOL_PACKED_END; -/** - * This function converts an exit code into a string. - * - * @param[in] aExitCode An exit code. - * - * @returns A string representation of an exit code. - * - */ -const char *otExitCodeToString(uint8_t aExitCode); - -/** - * This macro checks for the specified condition, which is expected to commonly be true, - * and both records exit status and terminates the program if the condition is false. - * - * @param[in] aCondition The condition to verify - * @param[in] aExitCode The exit code. - * - */ -#define VerifyOrDie(aCondition, aExitCode) \ - do \ - { \ - if (!(aCondition)) \ - { \ - otLogCritPlat("%s() at %s:%d: %s", __func__, __FILE__, __LINE__, otExitCodeToString(aExitCode)); \ - exit(aExitCode); \ - } \ - } while (false) - -/** - * This macro checks for the specified error code, which is expected to commonly be successful, - * and both records exit status and terminates the program if the error code is unsuccessful. - * - * @param[in] aError An error code to be evaluated against OT_ERROR_NONE. - * - */ -#define SuccessOrDie(aError) \ - VerifyOrDie(aError == OT_ERROR_NONE, \ - (aError == OT_ERROR_INVALID_ARGS ? OT_EXIT_INVALID_ARGUMENTS : OT_EXIT_FAILURE)) - -/** - * This macro unconditionally both records exit status and terminates the program. - * - * @param[in] aExitCode The exit code. - * - */ -#define DieNow(aExitCode) VerifyOrDie(false, aExitCode) - -/** - * This macro unconditionally both records exit status and exit message and terminates the program. - * - * @param[in] aMessage The exit message. - * @param[in] aExitCode The exit code. - * - */ -#define DieNowWithMessage(aMessage, aExitCode) \ - do \ - { \ - fprintf(stderr, "exit(%d): %s line %d, %s, %s\r\n", aExitCode, __func__, __LINE__, aMessage, \ - otExitCodeToString(aExitCode)); \ - otLogCritPlat("exit(%d): %s line %d, %s, %s", aExitCode, __func__, __LINE__, aMessage, \ - otExitCodeToString(aExitCode)); \ - exit(aExitCode); \ - } while (false) +struct RadioProcessContext +{ + const fd_set *mReadFdSet; + const fd_set *mWriteFdSet; +}; /** * Unique node ID. @@ -187,10 +132,18 @@ void platformAlarmProcess(otInstance *aInstance); */ int32_t platformAlarmGetNext(void); +#ifndef MS_PER_S #define MS_PER_S 1000 +#endif +#ifndef US_PER_MS #define US_PER_MS 1000 -#define US_PER_S 1000000 +#endif +#ifndef US_PER_S +#define US_PER_S (MS_PER_S * US_PER_MS) +#endif +#ifndef NS_PER_US #define NS_PER_US 1000 +#endif /** * This function advances the alarm time by @p aDelta. @@ -394,14 +347,6 @@ void virtualTimeSendSleepEvent(const struct timeval *aTimeout); */ void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct Event *aEvent); -/** - * This function gets system time in microseconds without applying speed up factor. - * - * @returns System time in microseconds. - * - */ -uint64_t platformGetTime(void); - /** * This function initializes platform UDP driver. * diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp new file mode 100644 index 000000000..c7b0562a0 --- /dev/null +++ b/src/posix/platform/radio.cpp @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2020, 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 implements the radio apis on posix platform. + */ + +#include "platform-posix.h" +#include "lib/spinel/radio_spinel.hpp" + +#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE +#include "hdlc_interface.hpp" +#elif OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE +#include "spi_interface.hpp" +#else +#error "Please enable either OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE or OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE." +#endif + +#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE +#if OPENTHREAD_POSIX_VIRTUAL_TIME +static ot::Spinel::RadioSpinel sRadioSpinel; +#else +static ot::Spinel::RadioSpinel sRadioSpinel; +#endif // OPENTHREAD_POSIX_VIRTUAL_TIME +#elif OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE +static ot::Spinel::RadioSpinel sRadioSpinel; +#endif // OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE + +void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.GetIeeeEui64(aIeeeEui64)); +} + +void otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.SetPanId(panid)); +} + +void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + otExtAddress addr; + + for (size_t i = 0; i < sizeof(addr); i++) + { + addr.m8[i] = aAddress->m8[sizeof(addr) - 1 - i]; + } + + SuccessOrDie(sRadioSpinel.SetExtendedAddress(addr)); +} + +void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.SetShortAddress(aAddress)); +} + +void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.SetPromiscuous(aEnable)); +} + +void platformRadioInit(const otPlatformConfig *aPlatformConfig) +{ + SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(*aPlatformConfig)); + sRadioSpinel.Init(aPlatformConfig->mResetRadio, aPlatformConfig->mRestoreDatasetFromNcp); +} + +void platformRadioDeinit(void) +{ + sRadioSpinel.Deinit(); +} + +bool otPlatRadioIsEnabled(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.IsEnabled(); +} + +otError otPlatRadioEnable(otInstance *aInstance) +{ + return sRadioSpinel.Enable(aInstance); +} + +otError otPlatRadioDisable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.Disable(); +} + +otError otPlatRadioSleep(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.Sleep(); +} + +otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.Receive(aChannel); +} + +otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.Transmit(*aFrame); +} + +otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return &sRadioSpinel.GetTransmitFrame(); +} + +int8_t otPlatRadioGetRssi(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRssi(); +} + +otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRadioCaps(); +} + +const char *otPlatRadioGetVersionString(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetVersion(); +} + +bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.IsPromiscuous(); +} + +void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd, struct timeval *aTimeout) +{ + sRadioSpinel.GetSpinelInterface().UpdateFdSet(*aReadFdSet, *aWriteFdSet, *aMaxFd, *aTimeout); + + if (sRadioSpinel.IsTransmitting()) + { + uint64_t now = otPlatTimeGet(); + uint64_t txRadioEndUs = sRadioSpinel.GetTxRadioEndUs(); + + if (now < txRadioEndUs) + { + uint64_t remain = txRadioEndUs - now; + + if (remain < static_cast(aTimeout->tv_sec * US_PER_S + aTimeout->tv_usec)) + { + aTimeout->tv_sec = static_cast(remain / US_PER_S); + aTimeout->tv_usec = static_cast(remain % US_PER_S); + } + } + else + { + aTimeout->tv_sec = 0; + aTimeout->tv_usec = 0; + } + } + + if (sRadioSpinel.HasPendingFrame() || sRadioSpinel.IsTransmitDone()) + { + aTimeout->tv_sec = 0; + aTimeout->tv_usec = 0; + } +} + +#if OPENTHREAD_POSIX_VIRTUAL_TIME +void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct Event *aEvent) +{ + OT_UNUSED_VARIABLE(aInstance); + sRadioSpinel.Process(*aEvent); +} +#else +void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet) +{ + OT_UNUSED_VARIABLE(aInstance); + RadioProcessContext context = {aReadFdSet, aWriteFdSet}; + + sRadioSpinel.Process(context); +} +#endif // OPENTHREAD_POSIX_VIRTUAL_TIME + +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.EnableSrcMatch(aEnable)); +} + +otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.AddSrcMatchShortEntry(aShortAddress); +} + +otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + otExtAddress addr; + + for (size_t i = 0; i < sizeof(addr); i++) + { + addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i]; + } + + return sRadioSpinel.AddSrcMatchExtEntry(addr); +} + +otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.ClearSrcMatchShortEntry(aShortAddress); +} + +otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) +{ + OT_UNUSED_VARIABLE(aInstance); + otExtAddress addr; + + for (size_t i = 0; i < sizeof(addr); i++) + { + addr.m8[i] = aExtAddress->m8[sizeof(addr) - 1 - i]; + } + + return sRadioSpinel.ClearSrcMatchExtEntry(addr); +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.ClearSrcMatchShortEntries()); +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + SuccessOrDie(sRadioSpinel.ClearSrcMatchExtEntries()); +} + +otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.EnergyScan(aScanChannel, aScanDuration); +} + +otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) +{ + OT_UNUSED_VARIABLE(aInstance); + assert(aPower != NULL); + return sRadioSpinel.GetTransmitPower(*aPower); +} + +otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.SetTransmitPower(aPower); +} + +otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) +{ + OT_UNUSED_VARIABLE(aInstance); + assert(aThreshold != NULL); + return sRadioSpinel.GetCcaEnergyDetectThreshold(*aThreshold); +} + +otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.SetCcaEnergyDetectThreshold(aThreshold); +} + +int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetReceiveSensitivity(); +} + +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE +otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.SetCoexEnabled(aEnabled); +} + +bool otPlatRadioIsCoexEnabled(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.IsCoexEnabled(); +} + +otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + + VerifyOrExit(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS); + + error = sRadioSpinel.GetCoexMetrics(*aCoexMetrics); + +exit: + return error; +} +#endif + +#if OPENTHREAD_CONFIG_DIAG_ENABLE +otError otPlatDiagProcess(otInstance *aInstance, int argc, char *argv[], char *aOutput, size_t aOutputMaxLen) +{ + // deliver the platform specific diags commands to radio only ncp. + OT_UNUSED_VARIABLE(aInstance); + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'}; + char *cur = cmd; + char *end = cmd + sizeof(cmd); + + for (int index = 0; index < argc; index++) + { + cur += snprintf(cur, static_cast(end - cur), "%s ", argv[index]); + } + + return sRadioSpinel.PlatDiagProcess(cmd, aOutput, aOutputMaxLen); +} + +void otPlatDiagModeSet(bool aMode) +{ + SuccessOrExit(sRadioSpinel.PlatDiagProcess(aMode ? "start" : "stop", NULL, 0)); + sRadioSpinel.SetDiagEnabled(aMode); + +exit: + return; +} + +bool otPlatDiagModeGet(void) +{ + return sRadioSpinel.IsDiagEnabled(); +} + +void otPlatDiagTxPowerSet(int8_t aTxPower) +{ + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; + + snprintf(cmd, sizeof(cmd), "power %d", aTxPower); + SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); + +exit: + return; +} + +void otPlatDiagChannelSet(uint8_t aChannel) +{ + char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; + + snprintf(cmd, sizeof(cmd), "channel %d", aChannel); + SuccessOrExit(sRadioSpinel.PlatDiagProcess(cmd, NULL, 0)); + +exit: + return; +} + +void otPlatDiagRadioReceived(otInstance *aInstance, otRadioFrame *aFrame, otError aError) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aFrame); + OT_UNUSED_VARIABLE(aError); +} + +void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); +} +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE + +uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRadioChannelMask(false); +} + +uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetRadioChannelMask(true); +} + +otRadioState otPlatRadioGetState(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return sRadioSpinel.GetState(); +} diff --git a/src/posix/platform/settings.cpp b/src/posix/platform/settings.cpp index e408cea93..b316a666d 100644 --- a/src/posix/platform/settings.cpp +++ b/src/posix/platform/settings.cpp @@ -45,9 +45,11 @@ #include #include +#include #include #include "common/code_utils.hpp" +#include "common/encoding.hpp" static const size_t kMaxFileNameSize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32; @@ -55,20 +57,23 @@ static int sSettingsFd = -1; static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex, int *aSwapFd); -static void getSettingsFileName(char aFileName[kMaxFileNameSize], bool aSwap) +static void getSettingsFileName(otInstance *aInstance, char aFileName[kMaxFileNameSize], bool aSwap) { const char *offset = getenv("PORT_OFFSET"); + uint64_t nodeId; + otPlatRadioGetIeeeEui64(aInstance, reinterpret_cast(&nodeId)); + nodeId = ot::Encoding::BigEndian::HostSwap64(nodeId); snprintf(aFileName, kMaxFileNameSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s_%" PRIx64 ".%s", - offset == NULL ? "0" : offset, gNodeId, (aSwap ? "swap" : "data")); + offset == NULL ? "0" : offset, nodeId, (aSwap ? "swap" : "data")); } -static int swapOpen(void) +static int swapOpen(otInstance *aInstance) { char fileName[kMaxFileNameSize]; int fd; - getSettingsFileName(fileName, true); + getSettingsFileName(aInstance, fileName, true); fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO); @@ -83,8 +88,10 @@ static int swapOpen(void) * @param[in] aLength Number of bytes to copy. * */ -static void swapWrite(int aFd, uint16_t aLength) +static void swapWrite(otInstance *aInstance, int aFd, uint16_t aLength) { + OT_UNUSED_VARIABLE(aInstance); + const size_t kBlockSize = 512; uint8_t buffer[kBlockSize]; @@ -102,13 +109,13 @@ static void swapWrite(int aFd, uint16_t aLength) } } -static void swapPersist(int aFd) +static void swapPersist(otInstance *aInstance, int aFd) { char swapFile[kMaxFileNameSize]; char dataFile[kMaxFileNameSize]; - getSettingsFileName(swapFile, true); - getSettingsFileName(dataFile, false); + getSettingsFileName(aInstance, swapFile, true); + getSettingsFileName(aInstance, dataFile, false); VerifyOrDie(0 == close(sSettingsFd), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO); @@ -117,19 +124,17 @@ static void swapPersist(int aFd) sSettingsFd = aFd; } -static void swapDiscard(int aFd) +static void swapDiscard(otInstance *aInstance, int aFd) { char swapFileName[kMaxFileNameSize]; VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO); - getSettingsFileName(swapFileName, true); + getSettingsFileName(aInstance, swapFileName, true); VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO); } void otPlatSettingsInit(otInstance *aInstance) { - OT_UNUSED_VARIABLE(aInstance); - otError error = OT_ERROR_NONE; { @@ -144,7 +149,7 @@ void otPlatSettingsInit(otInstance *aInstance) { char fileName[kMaxFileNameSize]; - getSettingsFileName(fileName, false); + getSettingsFileName(aInstance, fileName, false); sSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600); } @@ -258,7 +263,7 @@ otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *a write(swapFd, aValue, aValueLength) == aValueLength, OT_EXIT_FAILURE); - swapPersist(swapFd); + swapPersist(aInstance, swapFd); return OT_ERROR_NONE; } @@ -268,12 +273,12 @@ otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *a OT_UNUSED_VARIABLE(aInstance); off_t size = lseek(sSettingsFd, 0, SEEK_END); - int swapFd = swapOpen(); + int swapFd = swapOpen(aInstance); if (size > 0) { VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO); - swapWrite(swapFd, static_cast(size)); + swapWrite(aInstance, swapFd, static_cast(size)); } VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) && @@ -281,7 +286,7 @@ otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *a write(swapFd, aValue, aValueLength) == aValueLength, OT_EXIT_FAILURE); - swapPersist(swapFd); + swapPersist(aInstance, swapFd); return OT_ERROR_NONE; } @@ -314,7 +319,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int otError error = OT_ERROR_NOT_FOUND; off_t size = lseek(sSettingsFd, 0, SEEK_END); off_t offset = lseek(sSettingsFd, 0, SEEK_SET); - int swapFd = swapOpen(); + int swapFd = swapOpen(aInstance); assert(swapFd != -1); assert(offset == 0); @@ -339,7 +344,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int if (aIndex == 0) { VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE); - swapWrite(swapFd, static_cast(size - offset)); + swapWrite(aInstance, swapFd, static_cast(size - offset)); error = OT_ERROR_NONE; break; } @@ -363,7 +368,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int assert(rval == sizeof(length)); VerifyOrDie(rval == sizeof(length), OT_EXIT_FAILURE); - swapWrite(swapFd, length); + swapWrite(aInstance, swapFd, length); } exit: @@ -375,11 +380,11 @@ exit: } else if (error == OT_ERROR_NONE) { - swapPersist(swapFd); + swapPersist(aInstance, swapFd); } else if (error == OT_ERROR_NOT_FOUND) { - swapDiscard(swapFd); + swapDiscard(aInstance, swapFd); } return error; @@ -397,7 +402,12 @@ void otPlatSettingsWipe(otInstance *aInstance) #if SELF_TEST -uint64_t gNodeId = 1; +void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + OT_UNUSED_VARIABLE(aInstance); + + memset(aIeeeEui64, 0, sizeof(uint64_t)); +} int main() { diff --git a/src/posix/platform/spi_interface.cpp b/src/posix/platform/spi_interface.cpp index 96172266d..0440f7271 100644 --- a/src/posix/platform/spi_interface.cpp +++ b/src/posix/platform/spi_interface.cpp @@ -59,11 +59,16 @@ #include #include +using ot::Spinel::SpinelInterface; + namespace ot { namespace Posix { -SpiInterface::SpiInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer) - : mCallbacks(aCallback) +SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + SpinelInterface::RxFrameBuffer & aFrameBuffer) + : mReceiveFrameCallback(aCallback) + , mReceiveFrameContext(aCallbackContext) , mRxFrameBuffer(aFrameBuffer) , mSpiDevFd(-1) , mResetGpioValueFd(-1) @@ -508,7 +513,7 @@ otError SpiInterface::PushPullSpi(void) // Upper layer will free the frame buffer. discardRxFrame = false; - mCallbacks.HandleReceivedFrame(); + mReceiveFrameCallback(mReceiveFrameContext); } } @@ -658,11 +663,9 @@ void SpiInterface::UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMa } } -void SpiInterface::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet) +void SpiInterface::Process(const RadioProcessContext &aContext) { - OT_UNUSED_VARIABLE(aWriteFdSet); - - if (FD_ISSET(mIntGpioValueFd, &aReadFdSet)) + if (FD_ISSET(mIntGpioValueFd, aContext.mReadFdSet)) { struct gpioevent_data event; @@ -680,14 +683,18 @@ void SpiInterface::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet) } } -otError SpiInterface::WaitForFrame(const struct timeval &aTimeout) +otError SpiInterface::WaitForFrame(uint64_t aTimeoutUs) { - otError error = OT_ERROR_NONE; - struct timeval timeout = {kSecPerDay, 0}; + otError error = OT_ERROR_NONE; + struct timeval spiTimeout = {kSecPerDay, 0}; + struct timeval timeout; fd_set readFdSet; int ret; bool isDataReady = false; + timeout.tv_sec = aTimeoutUs / US_PER_S; + timeout.tv_usec = aTimeoutUs % US_PER_S; + FD_ZERO(&readFdSet); if (mIntGpioValueFd >= 0) @@ -695,8 +702,8 @@ otError SpiInterface::WaitForFrame(const struct timeval &aTimeout) if ((isDataReady = CheckInterrupt())) { // Interrupt pin is asserted, set the timeout to be 0. - timeout.tv_sec = 0; - timeout.tv_usec = 0; + spiTimeout.tv_sec = 0; + spiTimeout.tv_usec = 0; } else { @@ -708,13 +715,13 @@ otError SpiInterface::WaitForFrame(const struct timeval &aTimeout) else { // In this case we don't have an interrupt, so we revert to SPI polling. - timeout.tv_sec = 0; - timeout.tv_usec = kSpiPollPeriodUs; + spiTimeout.tv_sec = 0; + spiTimeout.tv_usec = kSpiPollPeriodUs; } - if (timercmp(&aTimeout, &timeout, <)) + if (timercmp(&spiTimeout, &timeout, <)) { - timeout = aTimeout; + timeout = spiTimeout; } ret = select(mIntGpioValueFd + 1, &readFdSet, NULL, NULL, &timeout); diff --git a/src/posix/platform/spi_interface.hpp b/src/posix/platform/spi_interface.hpp index 05649dc09..07c25331a 100644 --- a/src/posix/platform/spi_interface.hpp +++ b/src/posix/platform/spi_interface.hpp @@ -36,8 +36,9 @@ #include "openthread-posix-config.h" -#include "spinel_interface.hpp" +#include "platform-posix.h" #include "lib/hdlc/hdlc.hpp" +#include "lib/spinel/spinel_interface.hpp" #include @@ -58,11 +59,14 @@ public: /** * This constructor initializes the object. * - * @param[in] aCallback A reference to a `Callback` object. - * @param[in] aFrameBuffer A reference to a `RxFrameBuffer` 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. * */ - SpiInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer); + SpiInterface(Spinel::SpinelInterface::ReceiveFrameCallback aCallback, + void * aCallbackContext, + Spinel::SpinelInterface::RxFrameBuffer & aFrameBuffer); /** * This destructor deinitializes the object. @@ -107,13 +111,13 @@ public: /** * This method waits for receiving part or all of spinel frame within specified interval. * - * @param[in] aTimeout A reference to the timeout. + * @param[in] aTimeout The timeout value in microseconds. * * @retval OT_ERROR_NONE Part or all of spinel frame is received. * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. * */ - otError WaitForFrame(const struct timeval &aTimeout); + otError WaitForFrame(uint64_t aTimeoutUs); /** * This method updates the file descriptor sets with file descriptors used by the radio driver. @@ -129,11 +133,10 @@ public: /** * This method performs radio driver processing. * - * @param[in] aReadFdSet A reference to the read file descriptors. - * @param[in] aWriteFdSet A reference to the write file descriptors. + * @param[in] aContext The context containing fd_sets. * */ - void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); + void Process(const RadioProcessContext &aContext); private: int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel); @@ -184,11 +187,12 @@ private: enum { - kMaxFrameSize = SpinelInterface::kMaxFrameSize, + kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize, }; - SpinelInterface::Callbacks & mCallbacks; - SpinelInterface::RxFrameBuffer &mRxFrameBuffer; + Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback; + void * mReceiveFrameContext; + Spinel::SpinelInterface::RxFrameBuffer & mRxFrameBuffer; int mSpiDevFd; int mResetGpioValueFd; @@ -218,6 +222,10 @@ private: bool mDidPrintRateLimitLog; uint16_t mSpiSlaveDataLen; + + // Non-copyable, intentionally not implemented. + SpiInterface(const SpiInterface &); + SpiInterface &operator=(const SpiInterface &); }; } // namespace Posix diff --git a/src/posix/platform/virtual_time.cpp b/src/posix/platform/virtual_time.cpp index bc6b2ec46..f369ef59c 100644 --- a/src/posix/platform/virtual_time.cpp +++ b/src/posix/platform/virtual_time.cpp @@ -201,7 +201,7 @@ void virtualTimeProcess(otInstance * aInstance, virtualTimeRadioSpinelProcess(aInstance, &event); } -uint64_t platformGetTime(void) +uint64_t otPlatTimeGet(void) { return sNow; }