mirror of
https://github.com/espressif/openthread.git
synced 2026-09-22 00:47:42 +00:00
[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:
+3
-1
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,4 +27,5 @@
|
||||
#
|
||||
|
||||
add_subdirectory(hdlc)
|
||||
add_subdirectory(platform)
|
||||
add_subdirectory(spinel)
|
||||
|
||||
@@ -30,6 +30,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
|
||||
|
||||
SUBDIRS = \
|
||||
hdlc \
|
||||
platform \
|
||||
spinel \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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 \
|
||||
|
||||
@@ -34,30 +34,72 @@
|
||||
#ifndef RADIO_SPINEL_HPP_
|
||||
#define RADIO_SPINEL_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#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 <typename InterfaceType, typename ProcessContextType> 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_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<kMaxFrameSize> 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_
|
||||
@@ -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)
|
||||
|
||||
@@ -76,6 +76,7 @@ target_compile_options(ot-ctl PRIVATE
|
||||
)
|
||||
|
||||
target_link_libraries(ot-ctl
|
||||
openthread-platform
|
||||
$<$<BOOL:${READLINE}>:${OT_READLINE}>
|
||||
)
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#else
|
||||
#error "Unknown posix app type!"
|
||||
#endif
|
||||
#include <lib/platform/exit_code.h>
|
||||
#include <openthread/openthread-system.h>
|
||||
|
||||
#ifndef OPENTHREAD_ENABLE_COVERAGE
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<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);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -46,9 +46,12 @@
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/openthread-system.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#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.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -45,9 +45,11 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openthread/platform/misc.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#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<uint8_t *>(&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<uint16_t>(size));
|
||||
swapWrite(aInstance, swapFd, static_cast<uint16_t>(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<uint16_t>(size - offset));
|
||||
swapWrite(aInstance, swapFd, static_cast<uint16_t>(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()
|
||||
{
|
||||
|
||||
@@ -59,11 +59,16 @@
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -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 <openthread/openthread-system.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -201,7 +201,7 @@ void virtualTimeProcess(otInstance * aInstance,
|
||||
virtualTimeRadioSpinelProcess(aInstance, &event);
|
||||
}
|
||||
|
||||
uint64_t platformGetTime(void)
|
||||
uint64_t otPlatTimeGet(void)
|
||||
{
|
||||
return sNow;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user