[posix-host] add posix parameter to get dataset from NCP and save to file (#4446)

There are cases when NCP platform was used at first. Then need to
change to use RCP platform later. The PAN active and pending dataset
needs to be retrieved from NCP firmware to avoid repairing again.

This change,
1. Add one parameter to posix host (--ncp-dataset).
2. Avoid some radio spinel command and check so that posix app can start
otInstance and talk to NCP firmware.
3. Utilize spinel property SPINEL_PROP_THREAD_ACTIVE_DATASET and
SPINEL_PROP_THREAD_PENDING_DATASET to retrieve dataset from NCP.
This commit is contained in:
Jintao Lin
2020-01-09 18:15:23 -08:00
committed by Jonathan Hui
parent f520ea9a76
commit 8788cf5a97
12 changed files with 404 additions and 27 deletions
+4
View File
@@ -65,6 +65,10 @@ jobs:
os: linux
compiler: gcc
script: .travis/script.sh
- env: BUILD_TARGET="posix-app-migrate" VERBOSE=1 COVERAGE=1
os: linux
compiler: clang
script: .travis/script.sh
- env: BUILD_TARGET="android-build" VERBOSE=1
os: linux
dist: trusty
+4
View File
@@ -104,6 +104,10 @@ cd /tmp || die
) || die
}
[ $BUILD_TARGET != posix-app-migrate ] || {
sudo apt-get install expect || die
}
[ $BUILD_TARGET != arm-gcc-4 ] || {
sudo apt-get install lib32z1 || die
wget https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q3-update/+download/gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2 || die
+142
View File
@@ -0,0 +1,142 @@
#!/bin/bash
#
# 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.
#
set -e
set -x
at_exit() {
EXIT_CODE=$?
killall expect || true
killall ot-cli-ftd || true
killall ot-cli || true
killall ot-rcp || true
exit $EXIT_CODE
}
build() {
make -f examples/Makefile-posix
make -f src/posix/Makefile-posix
}
check() {
trap at_exit INT TERM EXIT
rm -rf tmp/
PANID="0xc001"
EXT_PANID="0123456789abcdef"
NETWORK_NAME="OT_NCP_TO_RCP"
CHANNEL="20"
MASTER_KEY="0123456789abcdef0123456789abcdef"
echo "Step 1. Start NCP platform and form a PAN..."
RADIO_NCP_CMD="$(pwd)/$(ls output/*linux*/bin/ot-cli-ftd)"
expect <<EOF
spawn ${RADIO_NCP_CMD} 1
set timeout 2
expect_after {
timeout { exit 1 }
}
send "panid ${PANID}\r\n"
expect "Done"
send "extpanid ${EXT_PANID}\r\n"
expect "Done"
send "networkname ${NETWORK_NAME}\r\n"
expect "Done"
send "channel ${CHANNEL}\r\n"
expect "Done"
send "masterkey ${MASTER_KEY}\r\n"
expect "Done"
send "ifconfig up\r\n"
expect "Done"
send "thread start\r\n"
expect "Done"
sleep 5
send "state\r\n"
expect "leader"
expect "Done"
send "exit\r\n"
expect eof
EOF
echo "Step 2. Start retrieving dataset from Radio..."
RADIO_NCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-ncp-ftd)"
"$(pwd)/$(ls output/posix/*linux*/bin/ot-ncp)" -n --radio-version --ncp-dataset -- ${RADIO_NCP_PATH} 1
echo "Step 3. Start posix app and check whether PAN dataset is the same..."
RADIO_RCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-rcp)"
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) ${RADIO_RCP_PATH} 1"
expect <<EOF
spawn ${OT_CLI_CMD}
set timeout 2
expect_after {
timeout { exit 1 }
}
send "panid\r\n"
expect ${PANID}
expect "Done"
send "extpanid\r\n"
expect ${EXT_PANID}
expect "Done"
send "networkname\r\n"
expect ${NETWORK_NAME}
expect "Done"
send "channel\r\n"
expect ${CHANNEL}
expect "Done"
send "masterkey\r\n"
expect ${MASTER_KEY}
expect "Done"
send "exit\r\n"
expect eof
EOF
echo "Step 4. Start posix app and check whether it can get radio firmware version..."
RADIO_VERSION="$("$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)" -n --radio-version --ncp-dataset -- ${RADIO_RCP_PATH} 1)" || true
test -n "{RADIO_VERSION}"
}
main() {
case "$1" in
check)
check
;;
*)
build
check
;;
esac
}
main "$@"
+5
View File
@@ -601,6 +601,11 @@ build_samr21() {
.travis/check-posix-app-pty || die
}
[ $BUILD_TARGET != posix-app-migrate ] || {
./bootstrap
.travis/check-ncp-rcp-migrate || die
}
[ $BUILD_TARGET != posix-mtd ] || {
./bootstrap || die
REFERENCE_DEVICE=1 COVERAGE=1 CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 USE_MTD=1 make -f examples/Makefile-posix check || die
+4 -3
View File
@@ -52,9 +52,10 @@ extern "C" {
*
*/
#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes)
#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes)
#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes)
#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes)
#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits)
#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes)
#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes)
/**
* @struct otIp6Address
+1 -2
View File
@@ -38,7 +38,6 @@
#include "common/locator.hpp"
#include "mac/mac_types.hpp"
#include "thread/mle.hpp"
#if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
#include "utils/slaac_address.hpp"
#endif
@@ -136,7 +135,6 @@ public:
uint8_t mMode; ///< The MLE device mode
};
protected:
/**
* This enumeration defines the keys of settings.
*
@@ -152,6 +150,7 @@ protected:
kKeySlaacIidSecretKey = 0x0007, ///< Secret key used by SLAAC module for generating semantically opaque IID
};
protected:
explicit SettingsBase(Instance &aInstance)
: InstanceLocator(aInstance)
{
+6 -6
View File
@@ -1034,8 +1034,8 @@ otError NcpBase::EncodeOperationalDataset(const otOperationalDataset &aDataset)
SuccessOrExit(mEncoder.OpenStruct());
SuccessOrExit(mEncoder.WriteUintPacked(SPINEL_PROP_IPV6_ML_PREFIX));
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
SuccessOrExit(error = mEncoder.WriteUint8(64)); // Prefix length (in bits)
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
SuccessOrExit(mEncoder.CloseStruct());
}
@@ -1223,7 +1223,7 @@ otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset,
SuccessOrExit(error = mDecoder.ReadIp6Address(addr));
SuccessOrExit(error = mDecoder.ReadUint8(prefixLen));
VerifyOrExit(prefixLen == 64, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
memcpy(aDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE);
}
@@ -1557,8 +1557,8 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
// Zero out the last 8 bytes.
memset(addr.mFields.m8 + 8, 0, 8);
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
SuccessOrExit(error = mEncoder.WriteUint8(64)); // Prefix length (in bits)
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
exit:
return error;
@@ -1572,7 +1572,7 @@ template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
SuccessOrExit(error = mDecoder.ReadIp6Address(meshLocalPrefix));
SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
VerifyOrExit(prefixLength == 64, error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(prefixLength == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
error = otThreadSetMeshLocalPrefix(mInstance, reinterpret_cast<const otMeshLocalPrefix *>(meshLocalPrefix));
+6
View File
@@ -98,6 +98,7 @@ static const struct option kOptions[] = {{"debug-level", required_argument, NULL
{"radio-version", no_argument, NULL, 0},
{"time-speed", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
{"ncp-dataset", no_argument, NULL, 0},
{0, 0, 0, 0}};
static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
@@ -111,6 +112,7 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
" -n --dry-run Just verify if arguments is valid and radio spinel is compatible.\n"
" --no-reset Do not reset RCP on initialization\n"
" --radio-version Print radio firmware version\n"
" --ncp-dataset Retrieve and save NCP dataset to file\n"
" -s --time-speed factor Time speed up factor.\n"
" -v --verbose Also log to stderr.\n"
" -h --help Display this usage information.\n",
@@ -178,6 +180,10 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
{
aConfig->mPlatformConfig.mResetRadio = false;
}
else if (!strcmp(kOptions[index].name, "ncp-dataset"))
{
aConfig->mPlatformConfig.mRestoreDatasetFromNcp = true;
}
break;
case '?':
PrintUsage(aArgVector[0], stderr, OT_EXIT_INVALID_ARGUMENTS);
+1
View File
@@ -68,4 +68,5 @@ target_include_directories(openthread-posix PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/src/core
${PROJECT_SOURCE_DIR}/src/posix/platform
${PROJECT_SOURCE_DIR}/third_party/mbedtls/repo/include
)
+7 -6
View File
@@ -90,12 +90,13 @@ enum
*/
typedef struct otPlatformConfig
{
uint64_t mNodeId; ///< Unique node ID.
uint32_t mSpeedUpFactor; ///< Speed up factor.
const char *mInterfaceName; ///< Thread network interface name.
const char *mRadioFile; ///< Radio file path.
const char *mRadioConfig; ///< Radio configurations.
bool mResetRadio; ///< Whether to reset RCP when initializing.
uint64_t mNodeId; ///< Unique node ID.
uint32_t mSpeedUpFactor; ///< Speed up factor.
const char *mInterfaceName; ///< Thread network interface name.
const char *mRadioFile; ///< Radio file path.
const char *mRadioConfig; ///< Radio configurations.
bool mResetRadio; ///< Whether to reset RCP when initializing.
bool mRestoreDatasetFromNcp; ///< Whether to retrieve dataset from NCP and save to file.
} otPlatformConfig;
/**
+209 -9
View File
@@ -33,6 +33,7 @@
#include "openthread-core-config.h"
#include "platform-posix.h"
#include "ncp/spinel_decoder.hpp"
#include "radio_spinel.hpp"
@@ -52,9 +53,14 @@
#include <common/encoding.hpp>
#include <common/logging.hpp>
#include <common/new.hpp>
#include <common/settings.hpp>
#include <meshcop/dataset.hpp>
#include <meshcop/meshcop_tlvs.hpp>
#include <openthread/dataset.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/radio.h>
#include <openthread/platform/settings.h>
#ifndef TX_WAIT_US
#define TX_WAIT_US (5 * US_PER_S)
@@ -184,6 +190,7 @@ RadioSpinel::RadioSpinel(void)
void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig)
{
otError error = OT_ERROR_NONE;
bool isRcp;
SuccessOrExit(error = mHdlcInterface.Init(aPlatformConfig));
@@ -196,14 +203,19 @@ void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig)
VerifyOrExit(mIsReady, error = OT_ERROR_FAILED);
SuccessOrExit(error = CheckSpinelVersion());
SuccessOrExit(error = CheckCapabilities());
SuccessOrExit(error = CheckRadioCapabilities());
SuccessOrExit(error = CheckCapabilities(isRcp));
SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion)));
SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_UINT64_S, &gNodeId));
gNodeId = ot::Encoding::BigEndian::HostSwap64(gNodeId);
if (aPlatformConfig.mRestoreDatasetFromNcp && !isRcp)
{
DieNow((RestoreDatasetFromNcp() == OT_ERROR_NONE) ? OT_EXIT_SUCCESS : OT_EXIT_FAILURE);
}
SuccessOrExit(error = CheckRadioCapabilities());
mRxRadioFrame.mPsdu = mRxPsdu;
mTxRadioFrame.mPsdu = mTxPsdu;
mAckRadioFrame.mPsdu = mAckPsdu;
@@ -234,7 +246,7 @@ exit:
return error;
}
otError RadioSpinel::CheckCapabilities(void)
otError RadioSpinel::CheckCapabilities(bool &aIsRcp)
{
otError error = OT_ERROR_NONE;
uint8_t capsBuffer[kCapsBufferSize];
@@ -244,6 +256,8 @@ otError RadioSpinel::CheckCapabilities(void)
SuccessOrExit(error = Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength));
aIsRcp = false;
while (capsLength > 0)
{
unsigned int capability;
@@ -262,11 +276,16 @@ otError RadioSpinel::CheckCapabilities(void)
supportsRawRadio = true;
}
if (capability == SPINEL_CAP_CONFIG_RADIO)
{
aIsRcp = true;
}
capsData += unpacked;
capsLength -= static_cast<spinel_size_t>(unpacked);
}
if (!supportsRawRadio)
if (!supportsRawRadio && aIsRcp)
{
otLogCritPlat("RCP capability list does not include support for radio/raw mode");
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
@@ -301,6 +320,23 @@ exit:
return error;
}
otError RadioSpinel::RestoreDatasetFromNcp(void)
{
otError error = OT_ERROR_NONE;
otPlatSettingsInit(mInstance);
otLogInfoPlat("Trying to get saved dataset from NCP");
SuccessOrExit(
error = Get(SPINEL_PROP_THREAD_ACTIVE_DATASET, SPINEL_DATATYPE_VOID_S, &RadioSpinel::ThreadDatasetHandler));
SuccessOrExit(
error = Get(SPINEL_PROP_THREAD_PENDING_DATASET, SPINEL_DATATYPE_VOID_S, &RadioSpinel::ThreadDatasetHandler));
exit:
otPlatSettingsDeinit(mInstance);
return error;
}
void RadioSpinel::Deinit(void)
{
mHdlcInterface.Deinit();
@@ -452,6 +488,159 @@ exit:
LogIfFail("Error processing response", error);
}
otError RadioSpinel::ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength)
{
otError error = OT_ERROR_NONE;
otOperationalDataset opDataset;
bool isActive = ((mWaitingKey == SPINEL_PROP_THREAD_ACTIVE_DATASET) ? true : false);
Ncp::SpinelDecoder decoder;
MeshCoP::Dataset dataset(isActive ? MeshCoP::Tlv::kActiveTimestamp : MeshCoP::Tlv::kPendingTimestamp);
memset(&opDataset, 0, sizeof(otOperationalDataset));
decoder.Init(aBuffer, aLength);
while (!decoder.IsAllReadInStruct())
{
unsigned int propKey;
SuccessOrExit(error = decoder.OpenStruct());
SuccessOrExit(error = decoder.ReadUintPacked(propKey));
switch (static_cast<spinel_prop_key_t>(propKey))
{
case SPINEL_PROP_NET_MASTER_KEY:
{
const uint8_t *key;
uint16_t len;
SuccessOrExit(error = decoder.ReadData(key, len));
VerifyOrExit(len == OT_MASTER_KEY_SIZE, error = OT_ERROR_INVALID_ARGS);
memcpy(opDataset.mMasterKey.m8, key, len);
opDataset.mComponents.mIsMasterKeyPresent = true;
break;
}
case SPINEL_PROP_NET_NETWORK_NAME:
{
const char *name;
size_t len;
SuccessOrExit(error = decoder.ReadUtf8(name));
len = strnlen(name, OT_NETWORK_NAME_MAX_SIZE);
memcpy(opDataset.mNetworkName.m8, name, len);
opDataset.mNetworkName.m8[len] = '\0';
opDataset.mComponents.mIsNetworkNamePresent = true;
break;
}
case SPINEL_PROP_NET_XPANID:
{
const uint8_t *xpanid;
uint16_t len;
SuccessOrExit(error = decoder.ReadData(xpanid, len));
VerifyOrExit(len == OT_EXT_PAN_ID_SIZE, error = OT_ERROR_INVALID_ARGS);
memcpy(opDataset.mExtendedPanId.m8, xpanid, len);
opDataset.mComponents.mIsExtendedPanIdPresent = true;
break;
}
case SPINEL_PROP_IPV6_ML_PREFIX:
{
const otIp6Address *addr;
uint8_t prefixLen;
SuccessOrExit(error = decoder.ReadIp6Address(addr));
SuccessOrExit(error = decoder.ReadUint8(prefixLen));
VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
memcpy(opDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE);
opDataset.mComponents.mIsMeshLocalPrefixPresent = true;
break;
}
case SPINEL_PROP_DATASET_DELAY_TIMER:
{
SuccessOrExit(error = decoder.ReadUint32(opDataset.mDelay));
opDataset.mComponents.mIsDelayPresent = true;
break;
}
case SPINEL_PROP_MAC_15_4_PANID:
{
SuccessOrExit(error = decoder.ReadUint16(opDataset.mPanId));
opDataset.mComponents.mIsPanIdPresent = true;
break;
}
case SPINEL_PROP_PHY_CHAN:
{
uint8_t channel;
SuccessOrExit(error = decoder.ReadUint8(channel));
opDataset.mChannel = channel;
opDataset.mComponents.mIsChannelPresent = true;
break;
}
case SPINEL_PROP_NET_PSKC:
{
const uint8_t *psk;
uint16_t len;
SuccessOrExit(error = decoder.ReadData(psk, len));
VerifyOrExit(len == OT_PSKC_MAX_SIZE, error = OT_ERROR_INVALID_ARGS);
memcpy(opDataset.mPskc.m8, psk, OT_PSKC_MAX_SIZE);
opDataset.mComponents.mIsPskcPresent = true;
break;
}
case SPINEL_PROP_DATASET_SECURITY_POLICY:
{
SuccessOrExit(error = decoder.ReadUint16(opDataset.mSecurityPolicy.mRotationTime));
SuccessOrExit(error = decoder.ReadUint8(opDataset.mSecurityPolicy.mFlags));
opDataset.mComponents.mIsSecurityPolicyPresent = true;
break;
}
case SPINEL_PROP_PHY_CHAN_SUPPORTED:
{
uint8_t channel;
opDataset.mChannelMask = 0;
while (!decoder.IsAllReadInStruct())
{
SuccessOrExit(error = decoder.ReadUint8(channel));
VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS);
opDataset.mChannelMask |= (1UL << channel);
}
opDataset.mComponents.mIsChannelMaskPresent = true;
break;
}
default:
break;
}
SuccessOrExit(error = decoder.CloseStruct());
}
/*
* Initially set Active Timestamp to 0. This is to allow the node to join the network
* yet retrieve the full Active Dataset from a neighboring device if one exists.
*/
opDataset.mActiveTimestamp = 0;
opDataset.mComponents.mIsActiveTimestampPresent = true;
SuccessOrExit(error = dataset.Set(opDataset));
SuccessOrExit(error = otPlatSettingsSet(
mInstance, isActive ? SettingsBase::kKeyActiveDataset : SettingsBase::kKeyPendingDataset,
dataset.GetBytes(), dataset.GetSize()));
exit:
return error;
}
void RadioSpinel::HandleWaitingResponse(uint32_t aCommand,
spinel_prop_key_t aKey,
const uint8_t * aBuffer,
@@ -480,11 +669,22 @@ void RadioSpinel::HandleWaitingResponse(uint32_t aCommand,
{
if (mPropertyFormat)
{
spinel_ssize_t unpacked =
spinel_datatype_vunpack_in_place(aBuffer, aLength, mPropertyFormat, mPropertyArgs);
if (static_cast<spinel_datatype_t>(mPropertyFormat[0]) == SPINEL_DATATYPE_VOID_C)
{
// reserved SPINEL_DATATYPE_VOID_C indicate caller want to parse the spinel response itself
ResponseHandler handler = va_arg(mPropertyArgs, ResponseHandler);
VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE);
mError = OT_ERROR_NONE;
assert(handler != NULL);
mError = (this->*handler)(aBuffer, aLength);
}
else
{
spinel_ssize_t unpacked =
spinel_datatype_vunpack_in_place(aBuffer, aLength, mPropertyFormat, mPropertyArgs);
VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE);
mError = OT_ERROR_NONE;
}
}
else
{
+15 -1
View File
@@ -538,8 +538,10 @@ private:
kStateTransmitDone, ///< Radio indicated frame transmission is done.
};
typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
otError CheckSpinelVersion(void);
otError CheckCapabilities(void);
otError CheckCapabilities(bool &aIsRcp);
otError CheckRadioCapabilities(void);
void ProcessFrameQueue(void);
@@ -612,6 +614,7 @@ private:
const char * pack_format,
va_list args);
otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength);
otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength);
/**
* This method returns if the property changed event is safe to be handled now.
@@ -641,6 +644,17 @@ 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;
HdlcInterface mHdlcInterface;