[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.
This commit is contained in:
Jiacheng Guo
2020-04-20 20:50:58 -07:00
committed by GitHub
parent f37d72e5ca
commit 8de4ab4740
27 changed files with 1278 additions and 848 deletions
+3 -1
View File
@@ -269,6 +269,7 @@ LOCAL_SRC_FILES := \
src/core/utils/parse_cmdline.cpp \ src/core/utils/parse_cmdline.cpp \
src/core/utils/slaac_address.cpp \ src/core/utils/slaac_address.cpp \
src/lib/hdlc/hdlc.cpp \ src/lib/hdlc/hdlc.cpp \
src/lib/platform/exit_code.c \
src/lib/spinel/spinel.c \ src/lib/spinel/spinel.c \
src/lib/spinel/spinel_decoder.cpp \ src/lib/spinel/spinel_decoder.cpp \
src/lib/spinel/spinel_encoder.cpp \ src/lib/spinel/spinel_encoder.cpp \
@@ -278,7 +279,7 @@ LOCAL_SRC_FILES := \
src/posix/platform/logging.cpp \ src/posix/platform/logging.cpp \
src/posix/platform/misc.cpp \ src/posix/platform/misc.cpp \
src/posix/platform/netif.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/settings.cpp \
src/posix/platform/spi_interface.cpp \ src/posix/platform/spi_interface.cpp \
src/posix/platform/system.cpp \ src/posix/platform/system.cpp \
@@ -486,6 +487,7 @@ LOCAL_CFLAGS := \
LOCAL_C_INCLUDES := \ LOCAL_C_INCLUDES := \
$(OPENTHREAD_PROJECT_INCLUDES) \ $(OPENTHREAD_PROJECT_INCLUDES) \
$(LOCAL_PATH)/include \ $(LOCAL_PATH)/include \
$(LOCAL_PATH)/src/ \
$(LOCAL_PATH)/src/core \ $(LOCAL_PATH)/src/core \
$(LOCAL_PATH)/src/posix/platform \ $(LOCAL_PATH)/src/posix/platform \
$(LOCAL_PATH)/src/posix/platform/include \ $(LOCAL_PATH)/src/posix/platform/include \
+1
View File
@@ -1027,6 +1027,7 @@ src/posix/Makefile
src/posix/platform/Makefile src/posix/platform/Makefile
src/lib/Makefile src/lib/Makefile
src/lib/hdlc/Makefile src/lib/hdlc/Makefile
src/lib/platform/Makefile
src/lib/spinel/Makefile src/lib/spinel/Makefile
third_party/Makefile third_party/Makefile
third_party/jlink/Makefile third_party/jlink/Makefile
+1
View File
@@ -27,4 +27,5 @@
# #
add_subdirectory(hdlc) add_subdirectory(hdlc)
add_subdirectory(platform)
add_subdirectory(spinel) add_subdirectory(spinel)
+1
View File
@@ -30,6 +30,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
SUBDIRS = \ SUBDIRS = \
hdlc \ hdlc \
platform \
spinel \ spinel \
$(NULL) $(NULL)
+48
View File
@@ -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}
)
+43
View File
@@ -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
+81
View File
@@ -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 <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
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;
}
+152
View File
@@ -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 <stdint.h>
#include <stdlib.h>
#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_
+2
View File
@@ -70,6 +70,8 @@ include_HEADERS = \
$(NULL) $(NULL)
noinst_HEADERS = \ noinst_HEADERS = \
radio_spinel.hpp \
radio_spinel_impl.hpp \
spinel_buffer.hpp \ spinel_buffer.hpp \
spinel_decoder.hpp \ spinel_decoder.hpp \
spinel_encoder.hpp \ spinel_encoder.hpp \
@@ -34,30 +34,72 @@
#ifndef RADIO_SPINEL_HPP_ #ifndef RADIO_SPINEL_HPP_
#define RADIO_SPINEL_HPP_ #define RADIO_SPINEL_HPP_
#include "openthread-posix-config.h"
#include <openthread/platform/radio.h> #include <openthread/platform/radio.h>
#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE #include "spinel.h"
#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_interface.hpp" #include "spinel_interface.hpp"
#include "lib/spinel/spinel.h"
#include "ncp/ncp_config.h" #include "ncp/ncp_config.h"
namespace ot { 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 <typename InterfaceType, typename ProcessContextType> class RadioSpinel
{ {
public: public:
/** /**
@@ -69,10 +111,13 @@ public:
/** /**
* Initialize this radio transceiver. * 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. * Deinitialize this radio transceiver.
@@ -451,42 +496,46 @@ public:
bool IsEnabled(void) const { return mState != kStateDisabled; } 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. * @retval TRUE There is a pending transmission.
* @param[inout] aWriteFdSet A reference to the write file descriptors. * @retval FALSE There is no pending transmission.
* @param[inout] aMaxFd A reference to the max file descriptor.
* @param[inout] aTimeout A reference to the timeout.
* *
*/ */
void UpdateFdSet(fd_set &aReadFdSet, fd_set &aWriteFdSet, int &aMaxFd, struct timeval &aTimeout); 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. * @retval TRUE The trasmission is done.
* @param[in] aWriteFdSet A reference to the write file descriptors. * @retval FALSE The trasmission is not done.
* *
*/ */
void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); bool IsTransmitDone(void) const { return mState == kStateTransmitDone; }
#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);
/** /**
* 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); uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; }
#endif
/**
* 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 #if OPENTHREAD_CONFIG_DIAG_ENABLE
/** /**
@@ -540,6 +589,34 @@ public:
*/ */
void HandleReceivedFrame(void); 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: private:
enum enum
{ {
@@ -561,10 +638,22 @@ private:
typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
static void HandleReceivedFrame(void *aContext);
otError CheckSpinelVersion(void); otError CheckSpinelVersion(void);
otError CheckCapabilities(bool &aIsRcp);
otError CheckRadioCapabilities(void); 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. * This method tries to retrieve a spinel property from OpenThread transceiver.
@@ -665,28 +754,11 @@ private:
void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError); 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; otInstance *mInstance;
SpinelInterface::RxFrameBuffer mRxFrameBuffer; SpinelInterface::RxFrameBuffer mRxFrameBuffer;
#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE InterfaceType mSpinelInterface;
HdlcInterface mSpinelInterface;
#endif
#if OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE
SpiInterface mSpinelInterface;
#endif
uint16_t mCmdTidsInUse; ///< Used transaction ids. uint16_t mCmdTidsInUse; ///< Used transaction ids.
spinel_tid_t mCmdNextTid; ///< Next available transaction id. spinel_tid_t mCmdNextTid; ///< Next available transaction id.
@@ -714,6 +786,7 @@ private:
int8_t mRxSensitivity; int8_t mRxSensitivity;
otError mTxError; otError mTxError;
char mVersion[kVersionStringSize]; char mVersion[kVersionStringSize];
otExtAddress mIeeeEui64;
State mState; State mState;
bool mIsPromiscuous : 1; ///< Promiscuous mode. bool mIsPromiscuous : 1; ///< Promiscuous mode.
@@ -729,7 +802,9 @@ private:
uint64_t mTxRadioEndUs; uint64_t mTxRadioEndUs;
}; };
} // namespace Posix } // namespace Spinel
} // namespace ot } // namespace ot
#include "radio_spinel_impl.hpp"
#endif // RADIO_SPINEL_HPP_ #endif // RADIO_SPINEL_HPP_
File diff suppressed because it is too large Load Diff
@@ -35,12 +35,10 @@
#ifndef POSIX_APP_SPINEL_INTERFACE_HPP_ #ifndef POSIX_APP_SPINEL_INTERFACE_HPP_
#define POSIX_APP_SPINEL_INTERFACE_HPP_ #define POSIX_APP_SPINEL_INTERFACE_HPP_
#include "openthread-posix-config.h"
#include "lib/hdlc/hdlc.hpp" #include "lib/hdlc/hdlc.hpp"
namespace ot { namespace ot {
namespace Posix { namespace Spinel {
class SpinelInterface class SpinelInterface
{ {
@@ -59,26 +57,9 @@ public:
*/ */
typedef Hdlc::MultiFrameBuffer<kMaxFrameSize> RxFrameBuffer; typedef Hdlc::MultiFrameBuffer<kMaxFrameSize> RxFrameBuffer;
/** typedef void (*ReceiveFrameCallback)(void *aContext);
* 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);
};
}; };
} // namespace Posix } // namespace Spinel
} // namespace ot } // namespace ot
#endif // POSIX_APP_SPINEL_INTERFACE_HPP_ #endif // POSIX_APP_SPINEL_INTERFACE_HPP_
+2
View File
@@ -42,6 +42,7 @@ SUBDIRS = \
CPPFLAGS_COMMON = \ CPPFLAGS_COMMON = \
-I$(top_srcdir)/include \ -I$(top_srcdir)/include \
-I$(top_srcdir)/src/ \
-I$(top_srcdir)/src/core \ -I$(top_srcdir)/src/core \
-I$(top_srcdir)/src/posix/platform \ -I$(top_srcdir)/src/posix/platform \
-I$(top_srcdir)/src/posix/platform/include \ -I$(top_srcdir)/src/posix/platform/include \
@@ -54,6 +55,7 @@ CPPFLAGS_COMMON = \
LIBTOOLFLAGS_COMMON = --preserve-dup-deps LIBTOOLFLAGS_COMMON = --preserve-dup-deps
LDADD_COMMON = \ LDADD_COMMON = \
$(top_builddir)/src/lib/platform/libopenthread-platform.a \
$(top_builddir)/src/posix/platform/libopenthread-posix.a \ $(top_builddir)/src/posix/platform/libopenthread-posix.a \
-lutil \ -lutil \
$(NULL) $(NULL)
+1
View File
@@ -76,6 +76,7 @@ target_compile_options(ot-ctl PRIVATE
) )
target_link_libraries(ot-ctl target_link_libraries(ot-ctl
openthread-platform
$<$<BOOL:${READLINE}>:${OT_READLINE}> $<$<BOOL:${READLINE}>:${OT_READLINE}>
) )
+1
View File
@@ -74,6 +74,7 @@
#else #else
#error "Unknown posix app type!" #error "Unknown posix app type!"
#endif #endif
#include <lib/platform/exit_code.h>
#include <openthread/openthread-system.h> #include <openthread/openthread-system.h>
#ifndef OPENTHREAD_ENABLE_COVERAGE #ifndef OPENTHREAD_ENABLE_COVERAGE
+2 -1
View File
@@ -59,7 +59,7 @@ add_library(openthread-posix
logging.cpp logging.cpp
misc.cpp misc.cpp
netif.cpp netif.cpp
radio_spinel.cpp radio.cpp
settings.cpp settings.cpp
spi_interface.cpp spi_interface.cpp
system.cpp system.cpp
@@ -76,6 +76,7 @@ set_target_properties(
) )
target_link_libraries(openthread-posix PUBLIC target_link_libraries(openthread-posix PUBLIC
openthread-platform
util util
) )
+2 -3
View File
@@ -49,7 +49,7 @@ libopenthread_posix_a_SOURCES = \
logging.cpp \ logging.cpp \
misc.cpp \ misc.cpp \
netif.cpp \ netif.cpp \
radio_spinel.cpp \ radio.cpp \
settings.cpp \ settings.cpp \
spi_interface.cpp \ spi_interface.cpp \
system.cpp \ system.cpp \
@@ -62,8 +62,6 @@ noinst_HEADERS = \
hdlc_interface.hpp \ hdlc_interface.hpp \
openthread-posix-config.h \ openthread-posix-config.h \
platform-posix.h \ platform-posix.h \
radio_spinel.hpp \
spinel_interface.hpp \
$(NULL) $(NULL)
openthread_HEADERS = \ openthread_HEADERS = \
@@ -81,6 +79,7 @@ check_PROGRAMS = test-settings
test_settings_CPPFLAGS = \ test_settings_CPPFLAGS = \
-I$(top_srcdir)/include \ -I$(top_srcdir)/include \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/core \ -I$(top_srcdir)/src/core \
-I$(top_srcdir)/src/posix/platform/include \ -I$(top_srcdir)/src/posix/platform/include \
-DOPENTHREAD_CONFIG_LOG_PLATFORM=0 \ -DOPENTHREAD_CONFIG_LOG_PLATFORM=0 \
+3 -3
View File
@@ -51,7 +51,7 @@ static uint32_t sUsAlarm = 0;
static uint32_t sSpeedUpFactor = 1; static uint32_t sSpeedUpFactor = 1;
#if !OPENTHREAD_POSIX_VIRTUAL_TIME #if !OPENTHREAD_POSIX_VIRTUAL_TIME
uint64_t platformGetTime(void) uint64_t otPlatTimeGet(void)
{ {
struct timespec now; struct timespec now;
@@ -67,7 +67,7 @@ uint64_t platformGetTime(void)
static uint64_t platformAlarmGetNow(void) static uint64_t platformAlarmGetNow(void)
{ {
return platformGetTime() * sSpeedUpFactor; return otPlatTimeGet() * sSpeedUpFactor;
} }
void platformAlarmInit(uint32_t aSpeedUpFactor) void platformAlarmInit(uint32_t aSpeedUpFactor)
@@ -98,7 +98,7 @@ void otPlatAlarmMilliStop(otInstance *aInstance)
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
uint32_t otPlatAlarmMicroGetNow(void) uint32_t otPlatAlarmMicroGetNow(void)
{ {
return (uint32_t)(platformGetTime()); return (uint32_t)(otPlatTimeGet());
} }
void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
+24 -17
View File
@@ -120,12 +120,17 @@
#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE #if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE
using ot::Spinel::SpinelInterface;
namespace ot { namespace ot {
namespace Posix { namespace Posix {
HdlcInterface::HdlcInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer) HdlcInterface::HdlcInterface(SpinelInterface::ReceiveFrameCallback aCallback,
: mCallbacks(aCallback) void * aCallbackContext,
, mRxFrameBuffer(aFrameBuffer) SpinelInterface::RxFrameBuffer & aFrameBuffer)
: mReceiveFrameCallback(aCallback)
, mReceiveFrameContext(aCallbackContext)
, mReceiveFrameBuffer(aFrameBuffer)
, mSockFd(-1) , mSockFd(-1)
, mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this) , mHdlcDecoder(aFrameBuffer, HandleHdlcFrame, this)
{ {
@@ -248,14 +253,17 @@ exit:
return error; 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 #if OPENTHREAD_POSIX_VIRTUAL_TIME
struct Event event; struct Event event;
uint64_t delay = static_cast<uint64_t>(aTimeout.tv_sec) * US_PER_S + static_cast<uint64_t>(aTimeout.tv_usec);
virtualTimeSendSleepEvent(&aTimeout); timeout.tv_sec = aTimeoutUs / US_PER_S;
timeout.tv_usec = aTimeoutUs % US_PER_S;
virtualTimeSendSleepEvent(&timeout);
virtualTimeReceiveEvent(&event); virtualTimeReceiveEvent(&event);
switch (event.mEvent) switch (event.mEvent)
@@ -265,7 +273,7 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout)
break; break;
case OT_SIM_EVENT_ALARM_FIRED: 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; break;
default: default:
@@ -273,7 +281,8 @@ otError HdlcInterface::WaitForFrame(const struct timeval &aTimeout)
break; break;
} }
#else // OPENTHREAD_POSIX_VIRTUAL_TIME #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 read_fds;
fd_set error_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, aContext.mReadFdSet))
if (FD_ISSET(mSockFd, &aReadFdSet))
{ {
Read(); Read();
} }
@@ -342,7 +349,7 @@ otError HdlcInterface::WaitForWritable(void)
{ {
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
struct timeval timeout = {kMaxWaitTime / 1000, (kMaxWaitTime % 1000) * 1000}; struct timeval timeout = {kMaxWaitTime / 1000, (kMaxWaitTime % 1000) * 1000};
uint64_t now = platformGetTime(); uint64_t now = otPlatTimeGet();
uint64_t end = now + kMaxWaitTime * US_PER_MS; uint64_t end = now + kMaxWaitTime * US_PER_MS;
fd_set writeFds; fd_set writeFds;
fd_set errorFds; fd_set errorFds;
@@ -377,7 +384,7 @@ otError HdlcInterface::WaitForWritable(void)
DieNow(OT_EXIT_ERROR_ERRNO); DieNow(OT_EXIT_ERROR_ERRNO);
} }
now = platformGetTime(); now = otPlatTimeGet();
if (end > now) if (end > now)
{ {
@@ -626,11 +633,11 @@ void HdlcInterface::HandleHdlcFrame(otError aError)
{ {
if (aError == OT_ERROR_NONE) if (aError == OT_ERROR_NONE)
{ {
mCallbacks.HandleReceivedFrame(); mReceiveFrameCallback(mReceiveFrameContext);
} }
else else
{ {
mRxFrameBuffer.DiscardFrame(); mReceiveFrameBuffer.DiscardFrame();
otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError)); otLogWarnPlat("Error decoding hdlc frame: %s", otThreadErrorToString(aError));
} }
} }
+22 -16
View File
@@ -36,8 +36,8 @@
#include "openthread-posix-config.h" #include "openthread-posix-config.h"
#include "platform-posix.h" #include "platform-posix.h"
#include "spinel_interface.hpp"
#include "lib/hdlc/hdlc.hpp" #include "lib/hdlc/hdlc.hpp"
#include "lib/spinel/spinel_interface.hpp"
#if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE #if OPENTHREAD_POSIX_CONFIG_RCP_UART_ENABLE
@@ -54,11 +54,14 @@ public:
/** /**
* This constructor initializes the object. * This constructor initializes the object.
* *
* @param[in] aCallback A reference to a `Callback` object. * @param[in] aCallback Callback on frame received
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object. * @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. * This destructor deinitializes the object.
@@ -105,13 +108,13 @@ public:
/** /**
* This method waits for receiving part or all of spinel frame within specified interval. * 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_NONE Part or all of spinel frame is received.
* @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p 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. * 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. * This method performs radio driver processing.
* *
* @param[in] aReadFdSet A reference to the read file descriptors. * @param[in] aContext The context containing fd_sets.
* @param[in] aWriteFdSet A reference to the write file descriptors.
* *
*/ */
void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); void Process(const RadioProcessContext &aContext);
#if OPENTHREAD_POSIX_VIRTUAL_TIME #if OPENTHREAD_POSIX_VIRTUAL_TIME
/** /**
* This method process read data (decode the data). * 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 * 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] aEvent The data event.
* @param[in] aLength The length (number of bytes) in the buffer.
* *
*/ */
void ProcessReadData(const uint8_t *aBuffer, uint16_t aLength) { Decode(aBuffer, aLength); } void Process(const Event &aEvent) { Decode(aEvent.mData, aEvent.mDataLength); }
#endif #endif
private: private:
@@ -204,15 +205,20 @@ private:
enum enum
{ {
kMaxFrameSize = SpinelInterface::kMaxFrameSize, kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize,
kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`). kMaxWaitTime = 2000, ///< Maximum wait time in Milliseconds for socket to become writable (see `SendFrame`).
}; };
SpinelInterface::Callbacks & mCallbacks; Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback;
SpinelInterface::RxFrameBuffer &mRxFrameBuffer; void * mReceiveFrameContext;
Spinel::SpinelInterface::RxFrameBuffer & mReceiveFrameBuffer;
int mSockFd; int mSockFd;
Hdlc::Decoder mHdlcDecoder; Hdlc::Decoder mHdlcDecoder;
// Non-copyable, intentionally not implemented.
HdlcInterface(const HdlcInterface &);
HdlcInterface &operator=(const HdlcInterface &);
}; };
} // namespace Posix } // namespace Posix
@@ -47,48 +47,6 @@
extern "C" { extern "C" {
#endif #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. * This enumeration represents default parameters for the SPI interface.
* *
+17 -72
View File
@@ -46,9 +46,12 @@
#include <openthread/error.h> #include <openthread/error.h>
#include <openthread/instance.h> #include <openthread/instance.h>
#include <openthread/openthread-system.h> #include <openthread/openthread-system.h>
#include <openthread/platform/time.h>
#include "common/logging.hpp" #include "common/logging.hpp"
#include "lib/platform/exit_code.h"
/** /**
* @def OPENTHREAD_POSIX_VIRTUAL_TIME * @def OPENTHREAD_POSIX_VIRTUAL_TIME
* *
@@ -87,69 +90,11 @@ struct Event
uint8_t mData[OT_EVENT_DATA_MAX_SIZE]; uint8_t mData[OT_EVENT_DATA_MAX_SIZE];
} OT_TOOL_PACKED_END; } OT_TOOL_PACKED_END;
/** struct RadioProcessContext
* This function converts an exit code into a string. {
* const fd_set *mReadFdSet;
* @param[in] aExitCode An exit code. const fd_set *mWriteFdSet;
* };
* @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)
/** /**
* Unique node ID. * Unique node ID.
@@ -187,10 +132,18 @@ void platformAlarmProcess(otInstance *aInstance);
*/ */
int32_t platformAlarmGetNext(void); int32_t platformAlarmGetNext(void);
#ifndef MS_PER_S
#define MS_PER_S 1000 #define MS_PER_S 1000
#endif
#ifndef US_PER_MS
#define US_PER_MS 1000 #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 #define NS_PER_US 1000
#endif
/** /**
* This function advances the alarm time by @p aDelta. * 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); 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. * This function initializes platform UDP driver.
* *
+421
View File
@@ -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<ot::Posix::HdlcInterface, Event> sRadioSpinel;
#else
static ot::Spinel::RadioSpinel<ot::Posix::HdlcInterface, RadioProcessContext> sRadioSpinel;
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME
#elif OPENTHREAD_POSIX_CONFIG_RCP_SPI_ENABLE
static ot::Spinel::RadioSpinel<ot::Posix::SpiInterface, RadioProcessContext> 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<uint64_t>(aTimeout->tv_sec * US_PER_S + aTimeout->tv_usec))
{
aTimeout->tv_sec = static_cast<time_t>(remain / US_PER_S);
aTimeout->tv_usec = static_cast<suseconds_t>(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<size_t>(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();
}
+33 -23
View File
@@ -45,9 +45,11 @@
#include <unistd.h> #include <unistd.h>
#include <openthread/platform/misc.h> #include <openthread/platform/misc.h>
#include <openthread/platform/radio.h>
#include <openthread/platform/settings.h> #include <openthread/platform/settings.h>
#include "common/code_utils.hpp" #include "common/code_utils.hpp"
#include "common/encoding.hpp"
static const size_t kMaxFileNameSize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32; 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 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"); const char *offset = getenv("PORT_OFFSET");
uint64_t nodeId;
otPlatRadioGetIeeeEui64(aInstance, reinterpret_cast<uint8_t *>(&nodeId));
nodeId = ot::Encoding::BigEndian::HostSwap64(nodeId);
snprintf(aFileName, kMaxFileNameSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s_%" PRIx64 ".%s", 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]; char fileName[kMaxFileNameSize];
int fd; int fd;
getSettingsFileName(fileName, true); getSettingsFileName(aInstance, fileName, true);
fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO); VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO);
@@ -83,8 +88,10 @@ static int swapOpen(void)
* @param[in] aLength Number of bytes to copy. * @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; const size_t kBlockSize = 512;
uint8_t buffer[kBlockSize]; 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 swapFile[kMaxFileNameSize];
char dataFile[kMaxFileNameSize]; char dataFile[kMaxFileNameSize];
getSettingsFileName(swapFile, true); getSettingsFileName(aInstance, swapFile, true);
getSettingsFileName(dataFile, false); getSettingsFileName(aInstance, dataFile, false);
VerifyOrDie(0 == close(sSettingsFd), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == close(sSettingsFd), OT_EXIT_ERROR_ERRNO);
VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO);
@@ -117,19 +124,17 @@ static void swapPersist(int aFd)
sSettingsFd = aFd; sSettingsFd = aFd;
} }
static void swapDiscard(int aFd) static void swapDiscard(otInstance *aInstance, int aFd)
{ {
char swapFileName[kMaxFileNameSize]; char swapFileName[kMaxFileNameSize];
VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO);
getSettingsFileName(swapFileName, true); getSettingsFileName(aInstance, swapFileName, true);
VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO);
} }
void otPlatSettingsInit(otInstance *aInstance) void otPlatSettingsInit(otInstance *aInstance)
{ {
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
{ {
@@ -144,7 +149,7 @@ void otPlatSettingsInit(otInstance *aInstance)
{ {
char fileName[kMaxFileNameSize]; char fileName[kMaxFileNameSize];
getSettingsFileName(fileName, false); getSettingsFileName(aInstance, fileName, false);
sSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600); 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, write(swapFd, aValue, aValueLength) == aValueLength,
OT_EXIT_FAILURE); OT_EXIT_FAILURE);
swapPersist(swapFd); swapPersist(aInstance, swapFd);
return OT_ERROR_NONE; return OT_ERROR_NONE;
} }
@@ -268,12 +273,12 @@ otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *a
OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aInstance);
off_t size = lseek(sSettingsFd, 0, SEEK_END); off_t size = lseek(sSettingsFd, 0, SEEK_END);
int swapFd = swapOpen(); int swapFd = swapOpen(aInstance);
if (size > 0) if (size > 0)
{ {
VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO); VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO);
swapWrite(swapFd, static_cast<uint16_t>(size)); swapWrite(aInstance, swapFd, static_cast<uint16_t>(size));
} }
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) && 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, write(swapFd, aValue, aValueLength) == aValueLength,
OT_EXIT_FAILURE); OT_EXIT_FAILURE);
swapPersist(swapFd); swapPersist(aInstance, swapFd);
return OT_ERROR_NONE; return OT_ERROR_NONE;
} }
@@ -314,7 +319,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int
otError error = OT_ERROR_NOT_FOUND; otError error = OT_ERROR_NOT_FOUND;
off_t size = lseek(sSettingsFd, 0, SEEK_END); off_t size = lseek(sSettingsFd, 0, SEEK_END);
off_t offset = lseek(sSettingsFd, 0, SEEK_SET); off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
int swapFd = swapOpen(); int swapFd = swapOpen(aInstance);
assert(swapFd != -1); assert(swapFd != -1);
assert(offset == 0); assert(offset == 0);
@@ -339,7 +344,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int
if (aIndex == 0) if (aIndex == 0)
{ {
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE); VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
swapWrite(swapFd, static_cast<uint16_t>(size - offset)); swapWrite(aInstance, swapFd, static_cast<uint16_t>(size - offset));
error = OT_ERROR_NONE; error = OT_ERROR_NONE;
break; break;
} }
@@ -363,7 +368,7 @@ static otError platformSettingsDelete(otInstance *aInstance, uint16_t aKey, int
assert(rval == sizeof(length)); assert(rval == sizeof(length));
VerifyOrDie(rval == sizeof(length), OT_EXIT_FAILURE); VerifyOrDie(rval == sizeof(length), OT_EXIT_FAILURE);
swapWrite(swapFd, length); swapWrite(aInstance, swapFd, length);
} }
exit: exit:
@@ -375,11 +380,11 @@ exit:
} }
else if (error == OT_ERROR_NONE) else if (error == OT_ERROR_NONE)
{ {
swapPersist(swapFd); swapPersist(aInstance, swapFd);
} }
else if (error == OT_ERROR_NOT_FOUND) else if (error == OT_ERROR_NOT_FOUND)
{ {
swapDiscard(swapFd); swapDiscard(aInstance, swapFd);
} }
return error; return error;
@@ -397,7 +402,12 @@ void otPlatSettingsWipe(otInstance *aInstance)
#if SELF_TEST #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() int main()
{ {
+23 -16
View File
@@ -59,11 +59,16 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/spi/spidev.h> #include <linux/spi/spidev.h>
using ot::Spinel::SpinelInterface;
namespace ot { namespace ot {
namespace Posix { namespace Posix {
SpiInterface::SpiInterface(SpinelInterface::Callbacks &aCallback, SpinelInterface::RxFrameBuffer &aFrameBuffer) SpiInterface::SpiInterface(SpinelInterface::ReceiveFrameCallback aCallback,
: mCallbacks(aCallback) void * aCallbackContext,
SpinelInterface::RxFrameBuffer & aFrameBuffer)
: mReceiveFrameCallback(aCallback)
, mReceiveFrameContext(aCallbackContext)
, mRxFrameBuffer(aFrameBuffer) , mRxFrameBuffer(aFrameBuffer)
, mSpiDevFd(-1) , mSpiDevFd(-1)
, mResetGpioValueFd(-1) , mResetGpioValueFd(-1)
@@ -508,7 +513,7 @@ otError SpiInterface::PushPullSpi(void)
// Upper layer will free the frame buffer. // Upper layer will free the frame buffer.
discardRxFrame = false; 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, aContext.mReadFdSet))
if (FD_ISSET(mIntGpioValueFd, &aReadFdSet))
{ {
struct gpioevent_data event; 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; otError error = OT_ERROR_NONE;
struct timeval timeout = {kSecPerDay, 0}; struct timeval spiTimeout = {kSecPerDay, 0};
struct timeval timeout;
fd_set readFdSet; fd_set readFdSet;
int ret; int ret;
bool isDataReady = false; bool isDataReady = false;
timeout.tv_sec = aTimeoutUs / US_PER_S;
timeout.tv_usec = aTimeoutUs % US_PER_S;
FD_ZERO(&readFdSet); FD_ZERO(&readFdSet);
if (mIntGpioValueFd >= 0) if (mIntGpioValueFd >= 0)
@@ -695,8 +702,8 @@ otError SpiInterface::WaitForFrame(const struct timeval &aTimeout)
if ((isDataReady = CheckInterrupt())) if ((isDataReady = CheckInterrupt()))
{ {
// Interrupt pin is asserted, set the timeout to be 0. // Interrupt pin is asserted, set the timeout to be 0.
timeout.tv_sec = 0; spiTimeout.tv_sec = 0;
timeout.tv_usec = 0; spiTimeout.tv_usec = 0;
} }
else else
{ {
@@ -708,13 +715,13 @@ otError SpiInterface::WaitForFrame(const struct timeval &aTimeout)
else else
{ {
// In this case we don't have an interrupt, so we revert to SPI polling. // In this case we don't have an interrupt, so we revert to SPI polling.
timeout.tv_sec = 0; spiTimeout.tv_sec = 0;
timeout.tv_usec = kSpiPollPeriodUs; spiTimeout.tv_usec = kSpiPollPeriodUs;
} }
if (timercmp(&aTimeout, &timeout, <)) if (timercmp(&spiTimeout, &timeout, <))
{ {
timeout = aTimeout; timeout = spiTimeout;
} }
ret = select(mIntGpioValueFd + 1, &readFdSet, NULL, NULL, &timeout); ret = select(mIntGpioValueFd + 1, &readFdSet, NULL, NULL, &timeout);
+20 -12
View File
@@ -36,8 +36,9 @@
#include "openthread-posix-config.h" #include "openthread-posix-config.h"
#include "spinel_interface.hpp" #include "platform-posix.h"
#include "lib/hdlc/hdlc.hpp" #include "lib/hdlc/hdlc.hpp"
#include "lib/spinel/spinel_interface.hpp"
#include <openthread/openthread-system.h> #include <openthread/openthread-system.h>
@@ -58,11 +59,14 @@ public:
/** /**
* This constructor initializes the object. * This constructor initializes the object.
* *
* @param[in] aCallback A reference to a `Callback` object. * @param[in] aCallback A reference to a `Callback` object.
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` 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. * This destructor deinitializes the object.
@@ -107,13 +111,13 @@ public:
/** /**
* This method waits for receiving part or all of spinel frame within specified interval. * 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_NONE Part or all of spinel frame is received.
* @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout. * @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p 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. * 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. * This method performs radio driver processing.
* *
* @param[in] aReadFdSet A reference to the read file descriptors. * @param[in] aContext The context containing fd_sets.
* @param[in] aWriteFdSet A reference to the write file descriptors.
* *
*/ */
void Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet); void Process(const RadioProcessContext &aContext);
private: private:
int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel); int SetupGpioHandle(int aFd, uint8_t aLine, uint32_t aHandleFlags, const char *aLabel);
@@ -184,11 +187,12 @@ private:
enum enum
{ {
kMaxFrameSize = SpinelInterface::kMaxFrameSize, kMaxFrameSize = Spinel::SpinelInterface::kMaxFrameSize,
}; };
SpinelInterface::Callbacks & mCallbacks; Spinel::SpinelInterface::ReceiveFrameCallback mReceiveFrameCallback;
SpinelInterface::RxFrameBuffer &mRxFrameBuffer; void * mReceiveFrameContext;
Spinel::SpinelInterface::RxFrameBuffer & mRxFrameBuffer;
int mSpiDevFd; int mSpiDevFd;
int mResetGpioValueFd; int mResetGpioValueFd;
@@ -218,6 +222,10 @@ private:
bool mDidPrintRateLimitLog; bool mDidPrintRateLimitLog;
uint16_t mSpiSlaveDataLen; uint16_t mSpiSlaveDataLen;
// Non-copyable, intentionally not implemented.
SpiInterface(const SpiInterface &);
SpiInterface &operator=(const SpiInterface &);
}; };
} // namespace Posix } // namespace Posix
+1 -1
View File
@@ -201,7 +201,7 @@ void virtualTimeProcess(otInstance * aInstance,
virtualTimeRadioSpinelProcess(aInstance, &event); virtualTimeRadioSpinelProcess(aInstance, &event);
} }
uint64_t platformGetTime(void) uint64_t otPlatTimeGet(void)
{ {
return sNow; return sNow;
} }