mirror of
https://github.com/espressif/openthread.git
synced 2026-09-14 05:00:11 +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/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 \
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -27,4 +27,5 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
add_subdirectory(hdlc)
|
add_subdirectory(hdlc)
|
||||||
|
add_subdirectory(platform)
|
||||||
add_subdirectory(spinel)
|
add_subdirectory(spinel)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
|
|||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
hdlc \
|
hdlc \
|
||||||
|
platform \
|
||||||
spinel \
|
spinel \
|
||||||
$(NULL)
|
$(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)
|
$(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_
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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 <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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user