diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj b/etc/visual-studio/libopenthread-ncp-spi.vcxproj
index d7adc3a5e..ae0b5f21d 100644
--- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj
+++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj
@@ -66,6 +66,7 @@
+
@@ -74,6 +75,7 @@
+
diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
index ad6f0f90b..5b94a7cdb 100644
--- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
+++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters
@@ -36,6 +36,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -59,6 +62,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj b/etc/visual-studio/libopenthread-ncp-uart.vcxproj
index 3e996c4cb..cfa765854 100644
--- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj
+++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj
@@ -67,6 +67,7 @@
+
@@ -76,6 +77,7 @@
+
diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
index 16df2e80e..544d4c8ea 100644
--- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
+++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters
@@ -42,6 +42,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -65,6 +68,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h
index 4ed933b90..7aecdee6e 100644
--- a/include/openthread/thread_ftd.h
+++ b/include/openthread/thread_ftd.h
@@ -195,7 +195,7 @@ OTAPI otError OTCALL otThreadSetJoinerUdpPort(otInstance *aInstance, uint16_t aJ
* @retval OT_ERROR_DISABLED_FEATURE Feature is disabled, not capable of setting steering data out of band.
*
*/
-otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress);
+otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress);
/**
* Get the CONTEXT_ID_REUSE_DELAY parameter used in the Leader role.
diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp
index 967304f3e..7e75026b3 100644
--- a/src/core/api/thread_ftd_api.cpp
+++ b/src/core/api/thread_ftd_api.cpp
@@ -237,7 +237,7 @@ exit:
return error;
}
-otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress)
+otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress)
{
otError error;
diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp
index bd5d15ecc..dcec31fe3 100644
--- a/src/core/meshcop/meshcop_tlvs.cpp
+++ b/src/core/meshcop/meshcop_tlvs.cpp
@@ -52,7 +52,7 @@ bool SteeringDataTlv::IsCleared(void) const
return rval;
}
-void SteeringDataTlv::ComputeBloomFilter(otExtAddress *aExtAddress)
+void SteeringDataTlv::ComputeBloomFilter(const otExtAddress *aExtAddress)
{
Crc16 ccitt(Crc16::kCcitt);
Crc16 ansi(Crc16::kAnsi);
diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp
index 663d76867..79f042148 100644
--- a/src/core/meshcop/meshcop_tlvs.hpp
+++ b/src/core/meshcop/meshcop_tlvs.hpp
@@ -646,7 +646,7 @@ public:
* @param[in] aExtAddress Extended address
*
*/
- void ComputeBloomFilter(otExtAddress *aExtAddress);
+ void ComputeBloomFilter(const otExtAddress *aExtAddress);
private:
uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH];
diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp
index 6472e276e..e3ff118b7 100644
--- a/src/core/thread/mle_router.cpp
+++ b/src/core/thread/mle_router.cpp
@@ -2636,7 +2636,7 @@ exit:
}
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-otError MleRouter::SetSteeringData(otExtAddress *aExtAddress)
+otError MleRouter::SetSteeringData(const otExtAddress *aExtAddress)
{
otError error = OT_ERROR_NONE;
uint8_t nullExtAddr[OT_EXT_ADDRESS_SIZE];
diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp
index a120e9b58..c58bd937b 100644
--- a/src/core/thread/mle_router_ftd.hpp
+++ b/src/core/thread/mle_router_ftd.hpp
@@ -670,7 +670,7 @@ public:
* @retval OT_ERROR_NONE Steering data was set
*
*/
- otError SetSteeringData(otExtAddress *aExtAddress);
+ otError SetSteeringData(const otExtAddress *aExtAddress);
#endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
/**
diff --git a/src/core/thread/mle_router_mtd.hpp b/src/core/thread/mle_router_mtd.hpp
index 2dd9a1cb8..7952717e3 100644
--- a/src/core/thread/mle_router_mtd.hpp
+++ b/src/core/thread/mle_router_mtd.hpp
@@ -127,7 +127,7 @@ public:
otError SendChildUpdateRequest(void) { return Mle::SendChildUpdateRequest(); }
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
- otError SetSteeringData(otExtAddress *) { return OT_ERROR_NOT_IMPLEMENTED; }
+ otError SetSteeringData(const otExtAddress *) { return OT_ERROR_NOT_IMPLEMENTED; }
#endif // OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
otError GetMaxChildTimeout(uint32_t &) { return OT_ERROR_NOT_IMPLEMENTED; }
diff --git a/src/ncp/Makefile.am b/src/ncp/Makefile.am
index c9e2e6c78..cc77f1e2c 100644
--- a/src/ncp/Makefile.am
+++ b/src/ncp/Makefile.am
@@ -71,6 +71,8 @@ COMMON_SOURCES = \
ncp_buffer.hpp \
spinel.c \
spinel.h \
+ spinel_decoder.hpp \
+ spinel_decoder.cpp \
spinel_encoder.hpp \
spinel_encoder.cpp \
spinel_platform.h \
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 531e29340..768dc82c8 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -55,36 +55,13 @@
namespace ot {
namespace Ncp {
-
// ----------------------------------------------------------------------------
-// MARK: Command/Property Jump Tables
+// MARK: Property Handler Jump Tables and Methods
// ----------------------------------------------------------------------------
-#define NCP_CMD_HANDLER_ENTRY(name) { SPINEL_CMD_##name, &NcpBase::CommandHandler_##name }
-
-const NcpBase::CommandHandlerEntry NcpBase::mCommandHandlerTable[] =
-{
- NCP_CMD_HANDLER_ENTRY(NOOP),
- NCP_CMD_HANDLER_ENTRY(RESET),
- NCP_CMD_HANDLER_ENTRY(PROP_VALUE_GET),
- NCP_CMD_HANDLER_ENTRY(PROP_VALUE_SET),
- NCP_CMD_HANDLER_ENTRY(PROP_VALUE_INSERT),
- NCP_CMD_HANDLER_ENTRY(PROP_VALUE_REMOVE),
-#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
- NCP_CMD_HANDLER_ENTRY(PEEK),
- NCP_CMD_HANDLER_ENTRY(POKE),
-#endif
-#if OPENTHREAD_MTD || OPENTHREAD_FTD
- NCP_CMD_HANDLER_ENTRY(NET_SAVE),
- NCP_CMD_HANDLER_ENTRY(NET_CLEAR),
- NCP_CMD_HANDLER_ENTRY(NET_RECALL),
-#endif
-};
-
#define NCP_GET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::GetPropertyHandler_##name }
-#define NCP_GET_PROP_HANDLER_ENTRY_METHOD(name, method) { SPINEL_PROP_##name, &NcpBase::GetPropertyHandler_##method }
-const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
+const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
{
NCP_GET_PROP_HANDLER_ENTRY(CAPS),
NCP_GET_PROP_HANDLER_ENTRY(DEBUG_TEST_ASSERT),
@@ -180,7 +157,6 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
NCP_GET_PROP_HANDLER_ENTRY(NEST_LEGACY_LAST_NODE_JOINED),
#endif
- NCP_GET_PROP_HANDLER_ENTRY(STREAM_NET),
// MAC counters
NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_TOTAL),
NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_ACK_REQ),
@@ -253,10 +229,9 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
#define NCP_SET_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::SetPropertyHandler_##name }
-const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
+const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
{
NCP_SET_PROP_HANDLER_ENTRY(POWER_STATE),
- NCP_SET_PROP_HANDLER_ENTRY(HOST_POWER_STATE),
NCP_SET_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
NCP_SET_PROP_HANDLER_ENTRY(PHY_TX_POWER),
NCP_SET_PROP_HANDLER_ENTRY(PHY_CHAN),
@@ -270,7 +245,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_SHORT_ADDRESSES),
NCP_SET_PROP_HANDLER_ENTRY(MAC_SRC_MATCH_EXTENDED_ADDRESSES),
NCP_SET_PROP_HANDLER_ENTRY(PHY_ENABLED),
- NCP_SET_PROP_HANDLER_ENTRY(STREAM_RAW),
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
#if OPENTHREAD_MTD || OPENTHREAD_FTD
NCP_SET_PROP_HANDLER_ENTRY(MAC_DATA_POLL_PERIOD),
@@ -313,9 +287,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_WINDOW),
NCP_SET_PROP_HANDLER_ENTRY(JAM_DETECT_BUSY),
#endif
-#if OPENTHREAD_ENABLE_DIAG
- NCP_SET_PROP_HANDLER_ENTRY(NEST_STREAM_MFG),
-#endif
#if OPENTHREAD_ENABLE_LEGACY
NCP_SET_PROP_HANDLER_ENTRY(NEST_LEGACY_ULA_PREFIX),
#endif
@@ -336,9 +307,6 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
NCP_SET_PROP_HANDLER_ENTRY(THREAD_STEERING_DATA),
#endif
-#if OPENTHREAD_ENABLE_COMMISSIONER
- NCP_SET_PROP_HANDLER_ENTRY(THREAD_COMMISSIONER_ENABLED),
-#endif
#if OPENTHREAD_ENABLE_TMF_PROXY
NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_ENABLED),
NCP_SET_PROP_HANDLER_ENTRY(THREAD_TMF_PROXY_STREAM),
@@ -348,7 +316,7 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] =
#define NCP_INSERT_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::InsertPropertyHandler_##name }
-const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] =
+const NcpBase::PropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[] =
{
NCP_INSERT_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
#if OPENTHREAD_ENABLE_RAW_LINK_API
@@ -378,7 +346,7 @@ const NcpBase::InsertPropertyHandlerEntry NcpBase::mInsertPropertyHandlerTable[]
#define NCP_REMOVE_PROP_HANDLER_ENTRY(name) { SPINEL_PROP_##name, &NcpBase::RemovePropertyHandler_##name }
-const NcpBase::RemovePropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[] =
+const NcpBase::PropertyHandlerEntry NcpBase::mRemovePropertyHandlerTable[] =
{
NCP_REMOVE_PROP_HANDLER_ENTRY(UNSOL_UPDATE_FILTER),
#if OPENTHREAD_ENABLE_RAW_LINK_API
@@ -535,6 +503,7 @@ NcpBase::NcpBase(otInstance *aInstance):
mInstance(aInstance),
mTxFrameBuffer(mTxBuffer, sizeof(mTxBuffer)),
mEncoder(mTxFrameBuffer),
+ mDecoder(),
mHostPowerStateInProgress(false),
mLastStatus(SPINEL_STATUS_OK),
mSupportedChannelMask(OT_RADIO_SUPPORTED_CHANNELS),
@@ -617,48 +586,42 @@ NcpFrameBuffer::FrameTag NcpBase::GetLastOutboundFrameTag(void)
void NcpBase::HandleReceive(const uint8_t *aBuf, uint16_t aBufLength)
{
+ otError parseError = OT_ERROR_NONE;
+ otError responseError = OT_ERROR_NONE;
uint8_t header = 0;
unsigned int command = 0;
- spinel_ssize_t parsedLength;
- const uint8_t *argPtr = NULL;
- unsigned int argLen = 0;
- otError error = OT_ERROR_NONE;
spinel_tid_t tid = 0;
- parsedLength = spinel_datatype_unpack(
- aBuf,
- aBufLength,
- SPINEL_DATATYPE_COMMAND_S SPINEL_DATATYPE_DATA_S,
- &header,
- &command,
- &argPtr,
- &argLen
- );
-
- tid = SPINEL_HEADER_GET_TID(header);
+ // Initialize the decoder with the newly received spinel frame.
+ mDecoder.Init(aBuf, aBufLength);
// Receiving any message from the host has the side effect of transitioning the host power state to online.
mHostPowerState = SPINEL_HOST_POWER_STATE_ONLINE;
mHostPowerStateInProgress = false;
- if (parsedLength == aBufLength)
- {
- error = HandleCommand(header, command, argPtr, static_cast(argLen));
+ SuccessOrExit(parseError = mDecoder.ReadUint8(header));
+ SuccessOrExit(parseError = mDecoder.ReadUintPacked(command));
- // Check if we may have missed a `tid` in the sequence.
- if ((mNextExpectedTid != 0) && (tid != mNextExpectedTid))
- {
- mRxSpinelOutOfOrderTidCounter++;
- }
+ responseError = HandleCommand(header, command);
- mNextExpectedTid = SPINEL_GET_NEXT_TID(tid);
- }
- else
+ tid = SPINEL_HEADER_GET_TID(header);
+
+ // Check if we may have missed a `tid` in the sequence.
+ if ((mNextExpectedTid != 0) && (tid != mNextExpectedTid))
{
- error = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR);
+ mRxSpinelOutOfOrderTidCounter++;
}
- if (error == OT_ERROR_NO_BUFS)
+ mNextExpectedTid = SPINEL_GET_NEXT_TID(tid);
+
+exit:
+
+ if (parseError != OT_ERROR_NONE)
+ {
+ responseError = SendLastStatus(header, SPINEL_STATUS_PARSE_ERROR);
+ }
+
+ if (responseError == OT_ERROR_NO_BUFS)
{
// If we cannot send a response due to buffer space not being
// available, we remember the TID of command so to send an
@@ -921,179 +884,310 @@ exit:
}
// ----------------------------------------------------------------------------
-// MARK: Inbound Command Handlers
+// MARK: Inbound Command Handler
// ----------------------------------------------------------------------------
-otError NcpBase::HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen)
+otError NcpBase::HandleCommand(uint8_t aHeader, unsigned int aCommand)
{
- unsigned i;
otError error = OT_ERROR_NONE;
// Skip if this isn't a spinel frame
VerifyOrExit((SPINEL_HEADER_FLAG & aHeader) == SPINEL_HEADER_FLAG, error = OT_ERROR_INVALID_ARGS);
+ mDisableStreamWrite = true;
+
// We only support IID zero for now.
- VerifyOrExit(
- SPINEL_HEADER_GET_IID(aHeader) == 0,
- error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_INTERFACE)
- );
+ VerifyOrExit(SPINEL_HEADER_GET_IID(aHeader) == 0, error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_INTERFACE));
+
+ switch (aCommand)
+ {
+ case SPINEL_CMD_NOOP:
+ error = CommandHandler_NOOP(aHeader);
+ break;
+
+ case SPINEL_CMD_RESET:
+ error = CommandHandler_RESET(aHeader);
+ break;
+
+ case SPINEL_CMD_PROP_VALUE_GET:
+ case SPINEL_CMD_PROP_VALUE_SET:
+ case SPINEL_CMD_PROP_VALUE_INSERT:
+ case SPINEL_CMD_PROP_VALUE_REMOVE:
+ error = CommandHandler_PROP_VALUE_update(aHeader, aCommand);
+ break;
+
+#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
+ case SPINEL_CMD_PEEK:
+ error = CommandHandler_PEEK(aHeader);
+ break;
+
+ case SPINEL_CMD_POKE:
+ error = CommandHandler_POKE(aHeader);
+ break;
+#endif
+
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ case SPINEL_CMD_NET_SAVE:
+ error = CommandHandler_NET_SAVE(aHeader);
+ break;
+
+ case SPINEL_CMD_NET_CLEAR:
+ error = CommandHandler_NET_CLEAR(aHeader);
+ break;
+
+ case SPINEL_CMD_NET_RECALL:
+ error = CommandHandler_NET_RECALL(aHeader);
+ break;
+#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
+
+ default:
+
#if OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT
- if (aCommand >= SPINEL_CMD_VENDOR__BEGIN && aCommand < SPINEL_CMD_VENDOR__END)
- {
- error = VendorCommandHandler(aHeader, aCommand, aArgPtr, aArgLen);
- }
- else
-#endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT
- {
- for (i = 0; i < sizeof(mCommandHandlerTable) / sizeof(mCommandHandlerTable[0]); i++)
+ if (aCommand >= SPINEL_CMD_VENDOR__BEGIN && aCommand < SPINEL_CMD_VENDOR__END)
{
- if (mCommandHandlerTable[i].mCommand == aCommand)
- {
- break;
- }
- }
-
- if (i < sizeof(mCommandHandlerTable) / sizeof(mCommandHandlerTable[0]))
- {
- error = (this->*mCommandHandlerTable[i].mHandler)(aHeader, aCommand, aArgPtr, aArgLen);
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_COMMAND);
- }
- }
-
-exit:
- return error;
-}
-
-otError NcpBase::HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey)
-{
- unsigned i;
- bool found = false;
- otError error = OT_ERROR_NONE;
-
- for (i = 0; i < sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0]); i++)
- {
- if (mGetPropertyHandlerTable[i].mPropKey == aKey)
- {
- found = true;
+ error = VendorCommandHandler(aHeader, aCommand);
break;
}
- }
+#endif
- mDisableStreamWrite = true;
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
-
- if (found)
- {
- SuccessOrExit(error = (this->*mGetPropertyHandlerTable[i].mHandler)());
+ error = SendLastStatus(aHeader, SPINEL_STATUS_INVALID_COMMAND);
+ break;
}
- else
- {
- SuccessOrExit(error = mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_PROP_NOT_FOUND));
- }
-
- SuccessOrExit(error = mEncoder.EndFrame());
exit:
mDisableStreamWrite = false;
return error;
}
-otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
-{
- unsigned i;
- otError error = OT_ERROR_NONE;
+// ----------------------------------------------------------------------------
+// MARK: Property Get/Set/Insert/Remove Commands
+// ----------------------------------------------------------------------------
- for (i = 0; i < sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0]); i++)
+NcpBase::PropertyHandler NcpBase::FindPropertyHandler(spinel_prop_key_t aKey, const PropertyHandlerEntry *aTableEntry,
+ size_t aTableLen)
+{
+ PropertyHandler handler = NULL;
+
+ while (aTableLen--)
{
- if (mSetPropertyHandlerTable[i].mPropKey == aKey)
+ if (aTableEntry->mPropKey == aKey)
{
+ handler = aTableEntry->mHandler;
break;
}
+
+ aTableEntry++;
}
- if (i < sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0]))
- {
- error = (this->*mSetPropertyHandlerTable[i].mHandler)(aHeader, aKey, aValuePtr, aValueLen);
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND);
- }
+ return handler;
+}
+NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey)
+{
+ return FindPropertyHandler(
+ aKey,
+ mGetPropertyHandlerTable,
+ sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0])
+ );
+
+}
+
+NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
+{
+ return FindPropertyHandler(
+ aKey,
+ mSetPropertyHandlerTable,
+ sizeof(mSetPropertyHandlerTable) / sizeof(mSetPropertyHandlerTable[0])
+ );
+}
+
+NcpBase::PropertyHandler NcpBase::FindInsertPropertyHandler(spinel_prop_key_t aKey)
+{
+ return FindPropertyHandler(
+ aKey,
+ mInsertPropertyHandlerTable,
+ sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0])
+ );
+}
+
+NcpBase::PropertyHandler NcpBase::FindRemovePropertyHandler(spinel_prop_key_t aKey)
+{
+ return FindPropertyHandler(
+ aKey,
+ mRemovePropertyHandlerTable,
+ sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0])
+ );
+}
+
+otError NcpBase::HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey)
+{
+ otError error = OT_ERROR_NONE;
+ PropertyHandler handler = FindGetPropertyHandler(aKey);
+
+ VerifyOrExit(handler != NULL, error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
+
+ SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
+ SuccessOrExit(error = (this->*handler)());
+ SuccessOrExit(error = mEncoder.EndFrame());
+
+exit:
return error;
}
-otError NcpBase::HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+// Returns `true` and updates the `aError` on success.
+bool NcpBase::HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError)
+{
+ bool didHandle = true;
+
+ // Here the properties that require special treatment are handled.
+ // These properties are expected to form the response from their
+ // set handler directly.
+
+ switch (aKey)
+ {
+ case SPINEL_PROP_HOST_POWER_STATE:
+ ExitNow(aError = SetPropertyHandler_HOST_POWER_STATE(aHeader));
+
+#if OPENTHREAD_ENABLE_DIAG
+ case SPINEL_PROP_NEST_STREAM_MFG:
+ ExitNow(aError = SetPropertyHandler_NEST_STREAM_MFG(aHeader));
+#endif
+
+#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
+ case SPINEL_PROP_THREAD_COMMISSIONER_ENABLED:
+ ExitNow(aError = SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(aHeader));
+#endif
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ case SPINEL_PROP_STREAM_RAW:
+ ExitNow(aError = SetPropertyHandler_STREAM_RAW(aHeader));
+#endif
+
+ default:
+ didHandle = false;
+ break;
+ }
+
+exit:
+ return didHandle;
+}
+
+otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey)
{
- unsigned i;
otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND;
+ PropertyHandler handler = FindSetPropertyHandler(aKey);
+ const uint8_t *valuePtr;
+ uint16_t valueLen;
- for (i = 0; i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0]); i++)
+ if (handler == NULL)
{
- if (mInsertPropertyHandlerTable[i].mPropKey == aKey)
- {
- break;
- }
+ // If there is no "set" handler, check if this property is one of the
+ // ones that require different treatment.
+
+ bool didHandle = HandlePropertySetForSpecialProperties(aHeader, aKey, error);
+
+ VerifyOrExit(!didHandle);
+
+ ExitNow(error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
}
- if (i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0]))
- {
- spinelError = ThreadErrorToSpinelStatus(
- (this->*mInsertPropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen));
- }
+ // Save current read position in the decoder. Read the entire
+ // content as a data blob (which can be used in forming the response
+ // if there is no associated get handler), then reset the read
+ // position back so that the handler method can parse the
+ // content.
- if (spinelError == SPINEL_STATUS_OK)
+ mDecoder.SavePosition();
+ mDecoder.ReadData(valuePtr, valueLen);
+ mDecoder.ResetToSaved();
+
+ error = (this->*handler)();
+
+ VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)));
+
+ // Prepare the response.
+
+ if ((handler = FindGetPropertyHandler(aKey)) != NULL)
{
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_INSERTED, aKey));
- SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
+ SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
+ SuccessOrExit(error = (this->*handler)());
SuccessOrExit(error = mEncoder.EndFrame());
}
else
{
- SuccessOrExit(error = SendLastStatus(aHeader, spinelError));
+ if ((aKey == SPINEL_PROP_STREAM_NET) || (aKey == SPINEL_PROP_STREAM_NET_INSECURE)
+#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
+ || (aKey == SPINEL_PROP_THREAD_TMF_PROXY_STREAM)
+#endif
+ )
+ {
+ // Only send a successful status for `STREAM` properties
+ // if the transaction id (TID) is non-zero.
+
+ if (SPINEL_HEADER_GET_TID(aHeader) != 0)
+ {
+ error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
+ }
+
+ ExitNow();
+ }
+
+ // If there is no get handler for this property, echo the same
+ // value from input frame in the response.
+
+ SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
+ SuccessOrExit(error = mEncoder.WriteData(valuePtr, valueLen));
+ SuccessOrExit(error = mEncoder.EndFrame());
}
exit:
return error;
}
-otError NcpBase::HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand)
{
- unsigned i;
otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND;
+ PropertyHandler handler = NULL;
+ unsigned int responseCommand = 0;
+ const uint8_t *valuePtr;
+ uint16_t valueLen;
- for (i = 0; i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0]); i++)
+ switch (aCommand)
{
- if (mRemovePropertyHandlerTable[i].mPropKey == aKey)
- {
- break;
- }
+ case SPINEL_CMD_PROP_VALUE_INSERT:
+ handler = FindInsertPropertyHandler(aKey);
+ responseCommand = SPINEL_CMD_PROP_VALUE_INSERTED;
+ break;
+
+ case SPINEL_CMD_PROP_VALUE_REMOVE:
+ handler = FindRemovePropertyHandler(aKey);
+ responseCommand = SPINEL_CMD_PROP_VALUE_REMOVED;
+ break;
+
+ default:
+ assert(false);
+ break;
}
- if (i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0]))
- {
- spinelError = ThreadErrorToSpinelStatus(
- (this->*mRemovePropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen));
- }
+ VerifyOrExit(handler != NULL, error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
- if (spinelError == SPINEL_STATUS_OK)
- {
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_REMOVED, aKey));
- SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
- SuccessOrExit(error = mEncoder.EndFrame());
- }
- else
- {
- SuccessOrExit(error = SendLastStatus(aHeader, spinelError));
- }
+ // Save current read position in the decoder. Read the entire
+ // content as a data blob (which is used in forming the response
+ // in case of success), then reset the read position back so
+ // that the `PropertyHandler` method can parse the content.
+
+ mDecoder.SavePosition();
+ mDecoder.ReadData(valuePtr, valueLen);
+ mDecoder.ResetToSaved();
+
+ error = (this->*handler)();
+
+ VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)));
+
+ // Prepare the response
+ SuccessOrExit(error = mEncoder.BeginFrame(aHeader, responseCommand, aKey));
+ SuccessOrExit(error = mEncoder.WriteData(valuePtr, valueLen));
+ SuccessOrExit(error = mEncoder.EndFrame());
exit:
return error;
@@ -1120,43 +1214,20 @@ exit:
return error;
}
-otError NcpBase::SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError)
-{
- if (aError == OT_ERROR_NONE)
- {
- aError = HandleCommandPropertyGet(aHeader, aKey);
- }
- else
- {
- aError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(aError));
- }
-
- return aError;
-}
-
// ----------------------------------------------------------------------------
// MARK: Individual Command Handlers
// ----------------------------------------------------------------------------
-otError NcpBase::CommandHandler_NOOP(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen)
+otError NcpBase::CommandHandler_NOOP(uint8_t aHeader)
{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
return SendLastStatus(aHeader, SPINEL_STATUS_OK);
}
-otError NcpBase::CommandHandler_RESET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
+otError NcpBase::CommandHandler_RESET(uint8_t aHeader)
{
otError error = OT_ERROR_NONE;
- // We aren't using any of the arguments to this function.
OT_UNUSED_VARIABLE(aHeader);
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
// Signal a platform reset. If implemented, this function
// shouldn't return.
@@ -1182,229 +1253,96 @@ otError NcpBase::CommandHandler_RESET(uint8_t aHeader, unsigned int aCommand, co
return error;
}
-otError NcpBase::CommandHandler_PROP_VALUE_GET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
+otError NcpBase::CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand)
{
- unsigned int propKey = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
+ unsigned int propKey = 0;
- parsedLength = spinel_datatype_unpack(aArgPtr, aArgLen, SPINEL_DATATYPE_UINT_PACKED_S, &propKey);
+ error = mDecoder.ReadUintPacked(propKey);
- if (parsedLength > 0)
+ VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)));
+
+ switch (aCommand)
{
+ case SPINEL_CMD_PROP_VALUE_GET:
error = HandleCommandPropertyGet(aHeader, static_cast(propKey));
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
+ break;
+
+ case SPINEL_CMD_PROP_VALUE_SET:
+ error = HandleCommandPropertySet(aHeader, static_cast(propKey));
+ break;
+
+ case SPINEL_CMD_PROP_VALUE_INSERT:
+ case SPINEL_CMD_PROP_VALUE_REMOVE:
+ error = HandleCommandPropertyInsertRemove(aHeader, static_cast(propKey), aCommand);
+ break;
+
+ default:
+ break;
}
- OT_UNUSED_VARIABLE(aCommand);
-
- return error;
-}
-
-otError NcpBase::CommandHandler_PROP_VALUE_SET(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- unsigned int propKey = 0;
- spinel_ssize_t parsedLength;
- const uint8_t *valuePtr;
- unsigned int valueLen;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aArgPtr,
- aArgLen,
- SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S,
- &propKey,
- &valuePtr,
- &valueLen
- );
-
- if (parsedLength == aArgLen)
- {
- error = HandleCommandPropertySet(
- aHeader,
- static_cast(propKey),
- valuePtr,
- static_cast(valueLen)
- );
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
- }
-
- OT_UNUSED_VARIABLE(aCommand);
-
- return error;
-}
-
-otError NcpBase::CommandHandler_PROP_VALUE_INSERT(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- unsigned int propKey = 0;
- spinel_ssize_t parsedLength;
- const uint8_t *valuePtr;
- unsigned int valueLen;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aArgPtr,
- aArgLen,
- SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S,
- &propKey,
- &valuePtr,
- &valueLen
- );
-
- if (parsedLength == aArgLen)
- {
- error = HandleCommandPropertyInsert(
- aHeader,
- static_cast(propKey),
- valuePtr,
- static_cast(valueLen)
- );
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
- }
-
- OT_UNUSED_VARIABLE(aCommand);
-
- return error;
-}
-
-otError NcpBase::CommandHandler_PROP_VALUE_REMOVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
-{
- unsigned int propKey = 0;
- spinel_ssize_t parsedLength;
- const uint8_t *valuePtr;
- unsigned int valueLen;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aArgPtr,
- aArgLen,
- SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_DATA_S,
- &propKey,
- &valuePtr,
- &valueLen
- );
-
- if (parsedLength == aArgLen)
- {
- error = HandleCommandPropertyRemove(
- aHeader,
- static_cast(propKey),
- valuePtr,
- static_cast(valueLen)
- );
- }
- else
- {
- error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR);
- }
-
- OT_UNUSED_VARIABLE(aCommand);
-
+exit:
return error;
}
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
-otError NcpBase::CommandHandler_PEEK(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen)
+otError NcpBase::CommandHandler_PEEK(uint8_t aHeader)
{
- spinel_ssize_t parsedLength;
+ otError parseError = OT_ERROR_NONE;
+ otError responseError = OT_ERROR_NONE;
uint32_t address;
uint16_t count;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aArgPtr,
- aArgLen,
- (
- SPINEL_DATATYPE_UINT32_S // Address
- SPINEL_DATATYPE_UINT16_S // Count
- ),
- &address,
- &count
- );
+ SuccessOrExit(parseError = mDecoder.ReadUint32(address));
+ SuccessOrExit(parseError = mDecoder.ReadUint16(count));
- VerifyOrExit(parsedLength == aArgLen, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- VerifyOrExit(count != 0, spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
+ VerifyOrExit(count != 0, parseError = OT_ERROR_INVALID_ARGS);
if (mAllowPeekDelegate != NULL)
{
- VerifyOrExit(mAllowPeekDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
+ VerifyOrExit(mAllowPeekDelegate(address, count), parseError = OT_ERROR_INVALID_ARGS);
}
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PEEK_RET));
- SuccessOrExit(error = mEncoder.WriteUint32(address));
- SuccessOrExit(error = mEncoder.WriteUint16(count));
- SuccessOrExit(error = mEncoder.WriteData(reinterpret_cast(address), count));
- SuccessOrExit(error = mEncoder.EndFrame());
+ SuccessOrExit(responseError = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PEEK_RET));
+ SuccessOrExit(responseError = mEncoder.WriteUint32(address));
+ SuccessOrExit(responseError = mEncoder.WriteUint16(count));
+ SuccessOrExit(responseError = mEncoder.WriteData(reinterpret_cast(address), count));
+ SuccessOrExit(responseError = mEncoder.EndFrame());
exit:
- if (spinelError != SPINEL_STATUS_OK)
+ if (parseError != OT_ERROR_NONE)
{
- error = SendLastStatus(aHeader, spinelError);
+ responseError = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(parseError));
}
- OT_UNUSED_VARIABLE(aCommand);
-
- return error;
+ return responseError;
}
-otError NcpBase::CommandHandler_POKE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen)
+otError NcpBase::CommandHandler_POKE(uint8_t aHeader)
{
- spinel_ssize_t parsedLength;
+ otError parseError = OT_ERROR_NONE;
uint32_t address;
uint16_t count;
const uint8_t *dataPtr = NULL;
- spinel_size_t dataLen;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- otError error = OT_ERROR_NONE;
+ uint16_t dataLen;
- parsedLength = spinel_datatype_unpack(
- aArgPtr,
- aArgLen,
- (
- SPINEL_DATATYPE_UINT32_S // Address
- SPINEL_DATATYPE_UINT16_S // Count
- SPINEL_DATATYPE_DATA_S // Bytes
- ),
- &address,
- &count,
- &dataPtr,
- &dataLen
- );
+ SuccessOrExit(error = mDecoder.ReadUint32(address));
+ SuccessOrExit(error = mDecoder.ReadUint16(count));
+ SuccessOrExit(error = mDecoder.ReadData(dataPtr, dataLen));
- VerifyOrExit(parsedLength == aArgLen, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- VerifyOrExit(count != 0, spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
- VerifyOrExit(count <= dataLen, spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
+ VerifyOrExit(count != 0, parseError = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit(count <= dataLen, parseError = OT_ERROR_INVALID_ARGS);
if (mAllowPokeDelegate != NULL)
{
- VerifyOrExit(mAllowPokeDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
+ VerifyOrExit(mAllowPokeDelegate(address, count), parseError = OT_ERROR_INVALID_ARGS);
}
memcpy(reinterpret_cast(address), dataPtr, count);
exit:
- error = SendLastStatus(aHeader, spinelError);
-
- OT_UNUSED_VARIABLE(aCommand);
-
- return error;
+ return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(parseError));
}
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
@@ -1428,21 +1366,12 @@ otError NcpBase::GetPropertyHandler_PHY_CHAN(void)
return mEncoder.WriteUint8(otLinkGetChannel(mInstance));
}
-otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_PHY_CHAN(void)
{
unsigned int channel = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &channel
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUintPacked(channel));
#if OPENTHREAD_MTD || OPENTHREAD_FTD
error = otLinkSetChannel(mInstance, static_cast(channel));
@@ -1467,7 +1396,7 @@ otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(void)
@@ -1478,21 +1407,12 @@ otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(void)
);
}
-otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(void)
{
uint8_t mode = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &mode
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(mode));
switch (mode)
{
@@ -1511,7 +1431,7 @@ otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(void)
@@ -1519,26 +1439,17 @@ otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(void)
return mEncoder.WriteUint16(otLinkGetPanId(mInstance));
}
-otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(void)
{
uint16_t panid;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &panid
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint16(panid));
error = otLinkSetPanId(mInstance, panid);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(void)
@@ -1546,26 +1457,17 @@ otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(void)
return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance));
}
-otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(void)
{
- otExtAddress *extAddress;
- spinel_ssize_t parsedLength;
+ const otExtAddress *extAddress;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
error = otLinkSetExtendedAddress(mInstance, extAddress);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(void)
@@ -1578,27 +1480,18 @@ otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(void)
return mEncoder.WriteBool(mIsRawStreamEnabled);
}
-otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(void)
{
- bool value = false;
- spinel_ssize_t parsedLength;
+ bool enabled = false;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
#if OPENTHREAD_ENABLE_RAW_LINK_API
if (otLinkRawIsEnabled(mInstance))
{
- if (value)
+ if (enabled)
{
error = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
}
@@ -1610,10 +1503,10 @@ otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spin
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
- mIsRawStreamEnabled = value;
+ mIsRawStreamEnabled = enabled;
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(void)
@@ -1636,65 +1529,41 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_UNSOL_UPDATE_FILTER(void)
{
- spinel_ssize_t parsedLength;
unsigned int propKey;
otError error = OT_ERROR_NONE;
- bool reportAsync;
// First clear the current filter.
mChangedPropsSet.ClearFilter();
- while (aValueLen > 0)
+ while (mDecoder.GetRemainingLengthInStruct() > 0)
{
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(mDecoder.ReadUintPacked(propKey));
IgnoreReturnValue(mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
}
exit:
// If we had an error, we may have actually changed
- // the state of the filter---so we need to report
+ // the state of the filter, So we need to report
// those incomplete changes via an asynchronous
// change event.
- reportAsync = (error != OT_ERROR_NONE);
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
+ if (error != OT_ERROR_NONE)
{
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_UNSOL_UPDATE_FILTER);
}
return error;
}
-otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
unsigned int propKey;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUintPacked(propKey));
error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true);
@@ -1702,20 +1571,12 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
unsigned int propKey;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &propKey
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUintPacked(propKey));
error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), false);
@@ -1817,15 +1678,9 @@ otError NcpBase::GetPropertyHandler_POWER_STATE(void)
return mEncoder.WriteUint8(SPINEL_POWER_STATE_ONLINE); // Always online at the moment
}
-otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_POWER_STATE(void)
{
- // TODO: Implement POWER_STATE
- OT_UNUSED_VARIABLE(aKey);
- OT_UNUSED_VARIABLE(aValuePtr);
- OT_UNUSED_VARIABLE(aValueLen);
-
- return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
+ return OT_ERROR_NOT_IMPLEMENTED;
}
otError NcpBase::GetPropertyHandler_HWADDR(void)
@@ -1847,30 +1702,29 @@ otError NcpBase::GetPropertyHandler_HOST_POWER_STATE(void)
return mEncoder.WriteUint8(mHostPowerState);
}
-otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+// Setting `HOST_POWER_STATE` is treated and implemented differently from other
+// handlers as it requires two special behaviors (a) the response frame for the
+// set operation should be tracked and only when it is delivered we can assume
+// that host is sleep (b) the response is critical so if there is no spinel
+// buffer to prepare the response, the current spinel header is saved to
+// prepare and send the response as soon as buffer space becomes available.
+otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader)
{
- uint8_t value;
- spinel_ssize_t parsedLength;
+ uint8_t powerState;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &value
- );
+ error = mDecoder.ReadUint8(powerState);
- if (parsedLength > 0)
+ if (error == OT_ERROR_NONE)
{
- switch (value)
+ switch (powerState)
{
case SPINEL_HOST_POWER_STATE_OFFLINE:
case SPINEL_HOST_POWER_STATE_DEEP_SLEEP:
case SPINEL_HOST_POWER_STATE_LOW_POWER:
case SPINEL_HOST_POWER_STATE_ONLINE:
// Adopt the requested power state.
- mHostPowerState = static_cast(value);
+ mHostPowerState = static_cast(powerState);
break;
case SPINEL_HOST_POWER_STATE_RESERVED:
@@ -1883,17 +1737,10 @@ otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_pro
mHostPowerState = SPINEL_HOST_POWER_STATE_LOW_POWER;
break;
}
- }
- else
- {
- error = OT_ERROR_PARSE;
- }
- if (error == OT_ERROR_NONE)
- {
mHostPowerStateHeader = 0;
- error = HandleCommandPropertyGet(aHeader, aKey);
+ error = HandleCommandPropertyGet(aHeader, SPINEL_PROP_HOST_POWER_STATE);
if (mHostPowerState != SPINEL_HOST_POWER_STATE_ONLINE)
{
@@ -1958,26 +1805,17 @@ otError NcpBase::GetPropertyHandler_PHY_TX_POWER(void)
return mEncoder.WriteInt8(otLinkGetMaxTransmitPower(mInstance));
}
-otError NcpBase::SetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_PHY_TX_POWER(void)
{
- int8_t value = 0;
- spinel_ssize_t parsedLength;
+ int8_t txPower = 0;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_INT8_S,
- &value
- );
+ SuccessOrExit(error = mDecoder.ReadInt8(txPower));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- otLinkSetMaxTransmitPower(mInstance, value);
+ otLinkSetMaxTransmitPower(mInstance, txPower);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(void)
@@ -2024,22 +1862,13 @@ otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(void)
return mEncoder.WriteUint8(logLevel);
}
-otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(void)
{
uint8_t spinelNcpLogLevel = 0;
otLogLevel logLevel;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &spinelNcpLogLevel
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(spinelNcpLogLevel));
switch (spinelNcpLogLevel)
{
@@ -2074,7 +1903,7 @@ otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_
error = otSetDynamicLogLevel(mInstance, logLevel);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
} // namespace Ncp
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index 266ffde77..4c55b7935 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -47,6 +47,7 @@
#include "changed_props_set.hpp"
#include "common/tasklet.hpp"
#include "ncp/ncp_buffer.hpp"
+#include "ncp/spinel_decoder.hpp"
#include "ncp/spinel_encoder.hpp"
#include "spinel.h"
@@ -54,37 +55,10 @@
namespace ot {
namespace Ncp {
-#define NCP_COMMAND_HANDLER(name) \
- otError CommandHandler_##name( \
- uint8_t aHeader, \
- unsigned int aCommand, \
- const uint8_t *aArgPtr, \
- uint16_t aArgLen \
- )
-
-
-#define NCP_GET_PROP_HANDLER(name) \
- otError GetPropertyHandler_##name(void)
-
-#define NCP_SET_PROP_HANDLER(name) \
- otError SetPropertyHandler_##name( \
- uint8_t aHeader, \
- spinel_prop_key_t aKey, \
- const uint8_t *aValuePtr, \
- uint16_t aValueLen \
- )
-
-#define NCP_INSERT_PROP_HANDLER(name) \
- otError InsertPropertyHandler_##name( \
- const uint8_t *aValuePtr, \
- uint16_t aValueLen \
- )
-
-#define NCP_REMOVE_PROP_HANDLER(name) \
- otError RemovePropertyHandler_##name( \
- const uint8_t *aValuePtr, \
- uint16_t aValueLen \
- )
+#define NCP_GET_PROP_HANDLER(name) otError GetPropertyHandler_##name(void)
+#define NCP_SET_PROP_HANDLER(name) otError SetPropertyHandler_##name(void)
+#define NCP_INSERT_PROP_HANDLER(name) otError InsertPropertyHandler_##name(void)
+#define NCP_REMOVE_PROP_HANDLER(name) otError RemovePropertyHandler_##name(void)
class NcpBase
{
@@ -107,7 +81,7 @@ public:
static NcpBase *GetNcpInstance(void);
/**
- * This method sends data to host via specifiec stream.
+ * This method sends data to host via specific stream.
*
*
* @param[in] aStreamId A numeric identifier for the stream to write to.
@@ -190,64 +164,30 @@ public:
bool ShouldDeferHostSend(void);
private:
- typedef otError(NcpBase::*CommandHandlerType)(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen);
+ typedef otError (NcpBase::*PropertyHandler)(void);
- typedef otError(NcpBase::*GetPropertyHandlerType)(void);
-
- typedef otError(NcpBase::*InsertRemovePropertyHandlerType)(const uint8_t *aValuePtr, uint16_t aValueLen);
-
- typedef otError(NcpBase::*SetPropertyHandlerType)(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen);
-
- struct CommandHandlerEntry
- {
- spinel_cid_t mCommand;
- CommandHandlerType mHandler;
- };
-
- struct GetPropertyHandlerEntry
+ struct PropertyHandlerEntry
{
spinel_prop_key_t mPropKey;
- GetPropertyHandlerType mHandler;
- };
-
- struct SetPropertyHandlerEntry
- {
- spinel_prop_key_t mPropKey;
- SetPropertyHandlerType mHandler;
- };
-
- struct InsertPropertyHandlerEntry
- {
- spinel_prop_key_t mPropKey;
- InsertRemovePropertyHandlerType mHandler;
- };
-
- struct RemovePropertyHandlerEntry
- {
- spinel_prop_key_t mPropKey;
- InsertRemovePropertyHandlerType mHandler;
+ PropertyHandler mHandler;
};
NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void);
- otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen);
+ otError HandleCommand(uint8_t aHeader, unsigned int aCommand);
+
+ PropertyHandler FindPropertyHandler(spinel_prop_key_t aKey, const PropertyHandlerEntry *aTable, size_t aTableLen);
+ PropertyHandler FindGetPropertyHandler(spinel_prop_key_t aKey);
+ PropertyHandler FindSetPropertyHandler(spinel_prop_key_t aKey);
+ PropertyHandler FindInsertPropertyHandler(spinel_prop_key_t aKey);
+ PropertyHandler FindRemovePropertyHandler(spinel_prop_key_t aKey);
otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey);
-
- otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
- otError HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen);
-
+ bool HandlePropertySetForSpecialProperties(uint8_t aHeader, spinel_prop_key_t aKey, otError &aError);
+ otError HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKey);
+ otError HandleCommandPropertyInsertRemove(uint8_t aHeader, spinel_prop_key_t aKey, unsigned int aCommand);
otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus);
- otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError);
static void UpdateChangedProps(Tasklet &aTasklet);
void UpdateChangedProps(void);
@@ -300,19 +240,58 @@ private:
#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
#if OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT
- otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen);
+ otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand);
#endif // OPENTHREAD_ENABLE_SPINEL_VENDOR_SUPPORT
- NCP_COMMAND_HANDLER(NOOP);
- NCP_COMMAND_HANDLER(RESET);
- NCP_COMMAND_HANDLER(PROP_VALUE_GET);
- NCP_COMMAND_HANDLER(PROP_VALUE_SET);
- NCP_COMMAND_HANDLER(PROP_VALUE_INSERT);
- NCP_COMMAND_HANDLER(PROP_VALUE_REMOVE);
+ otError CommandHandler_NOOP(uint8_t aHeader);
+ otError CommandHandler_RESET(uint8_t aHeader);
+ // Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`.
+ otError CommandHandler_PROP_VALUE_update(uint8_t aHeader, unsigned int aCommand);
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
- NCP_COMMAND_HANDLER(PEEK);
- NCP_COMMAND_HANDLER(POKE);
+ otError CommandHandler_PEEK(uint8_t aHeader);
+ otError CommandHandler_POKE(uint8_t aHeader);
#endif
+#if OPENTHREAD_MTD || OPENTHREAD_FTD
+ otError CommandHandler_NET_SAVE(uint8_t aHeader);
+ otError CommandHandler_NET_CLEAR(uint8_t aHeader);
+ otError CommandHandler_NET_RECALL(uint8_t aHeader);
+#endif
+
+ // ----------------------------------------------------------------------------
+ // Property Handlers
+ // ----------------------------------------------------------------------------
+ //
+ // There are 4 types of property handlers for "get", "set", "insert", and
+ // "remove" commands.
+ //
+ // "Get" handlers should get/retrieve the property value and then encode and
+ // write the value into the NCP buffer. If the "get" operation itself fails,
+ // "get" handler should write a `LAST_STATUS` with the error status into the NCP
+ // buffer. The `otError` returned from a "get" handler is the error of writing
+ // into the NCP buffer (e.g., running out buffer), and not of the "get" operation
+ // itself.
+ //
+ // "Set/Insert/Remove" handlers should first decode/parse the value from the
+ // input Spinel frame and then perform the corresponding set/insert/remove
+ // operation. They are not responsible for preparing the Spinel response and
+ // therefore should not write anything to the NCP buffer. The `otError` returned
+ // from a "set/insert/remove" handler indicates the error in either parsing of
+ // the input or the error of set/insert/remove operation.
+ //
+ // The corresponding command handler (e.g., `HandleCommandPropertySet()` for
+ // `VALUE_SET` command) will take care of preparing the Spinel response after
+ // invoking the "set/insert/remove" handler for a given property. For example,
+ // for a `VALUE_SET` command, if the "set" handler returns an error, then a
+ // `LAST_STATUS` update response is prepared, otherwise on success the "get"
+ // handler for the property is used to prepare a `VALUE_IS` Spinel response (in
+ // cases where there is no "get" handler for the property, the input value is
+ // echoed in the response).
+ //
+ // Few properties require special treatment where the response needs to be
+ // prepared directly in the "set" handler (e.g., `HOST_POWER_STATE` or
+ // `NEST_STREAM_MFG`). These properties have a different handler method format
+ // (they expect `aHeader` as an input argument) and are processed separately in
+ // `HandleCommandPropertySet()`.
NCP_GET_PROP_HANDLER(LAST_STATUS);
NCP_GET_PROP_HANDLER(PROTOCOL_VERSION);
@@ -329,7 +308,6 @@ private:
NCP_GET_PROP_HANDLER(HWADDR);
NCP_GET_PROP_HANDLER(LOCK);
NCP_GET_PROP_HANDLER(HOST_POWER_STATE);
- NCP_SET_PROP_HANDLER(HOST_POWER_STATE);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_FILTER);
NCP_GET_PROP_HANDLER(UNSOL_UPDATE_LIST);
@@ -372,14 +350,10 @@ private:
NCP_REMOVE_PROP_HANDLER(MAC_SRC_MATCH_EXTENDED_ADDRESSES);
NCP_SET_PROP_HANDLER(PHY_ENABLED);
- NCP_SET_PROP_HANDLER(STREAM_RAW);
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
// FTD or MTD handlers.
#if OPENTHREAD_MTD || OPENTHREAD_FTD
- NCP_COMMAND_HANDLER(NET_SAVE);
- NCP_COMMAND_HANDLER(NET_CLEAR);
- NCP_COMMAND_HANDLER(NET_RECALL);
NCP_GET_PROP_HANDLER(MAC_EXTENDED_ADDR);
NCP_GET_PROP_HANDLER(MAC_SCAN_MASK);
@@ -462,7 +436,6 @@ private:
#if OPENTHREAD_ENABLE_BORDER_ROUTER
NCP_SET_PROP_HANDLER(THREAD_ALLOW_LOCAL_NET_DATA_CHANGE);
#endif
- NCP_GET_PROP_HANDLER(STREAM_NET);
NCP_SET_PROP_HANDLER(STREAM_NET);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_TOTAL);
@@ -541,11 +514,7 @@ private:
NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_ENABLE_FILTERING);
NCP_GET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID);
NCP_SET_PROP_HANDLER(THREAD_DISCOVERY_SCAN_PANID);
-#if OPENTHREAD_ENABLE_COMMISSIONER
- NCP_GET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
- NCP_SET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
- NCP_INSERT_PROP_HANDLER(THREAD_JOINERS);
-#endif
+
#if OPENTHREAD_ENABLE_JAM_DETECTION
NCP_GET_PROP_HANDLER(JAM_DETECTED);
NCP_GET_PROP_HANDLER(JAM_DETECT_ENABLE);
@@ -565,10 +534,6 @@ private:
#endif
NCP_SET_PROP_HANDLER(STREAM_NET_INSECURE);
NCP_SET_PROP_HANDLER(CNTR_RESET);
-#if OPENTHREAD_ENABLE_DIAG
- NCP_SET_PROP_HANDLER(NEST_STREAM_MFG);
-#endif
-
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_FTD
@@ -596,6 +561,10 @@ private:
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
NCP_SET_PROP_HANDLER(THREAD_STEERING_DATA);
#endif
+#if OPENTHREAD_ENABLE_COMMISSIONER
+ NCP_GET_PROP_HANDLER(THREAD_COMMISSIONER_ENABLED);
+ NCP_INSERT_PROP_HANDLER(THREAD_JOINERS);
+#endif
#if OPENTHREAD_ENABLE_TMF_PROXY
NCP_GET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
NCP_SET_PROP_HANDLER(THREAD_TMF_PROXY_ENABLED);
@@ -604,6 +573,20 @@ private:
NCP_REMOVE_PROP_HANDLER(THREAD_ACTIVE_ROUTER_IDS);
#endif // OPENTHREAD_FTD
+ otError SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader);
+
+#if OPENTHREAD_ENABLE_DIAG
+ otError SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader);
+#endif
+
+#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_COMMISSIONER
+ otError SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader);
+#endif // OPENTHREAD_FTD
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ otError SetPropertyHandler_STREAM_RAW(uint8_t aHeader);
+#endif
+
protected:
static NcpBase *sNcpInstance;
static spinel_status_t ThreadErrorToSpinelStatus(otError aError);
@@ -611,6 +594,7 @@ protected:
otInstance *mInstance;
NcpFrameBuffer mTxFrameBuffer;
SpinelEncoder mEncoder;
+ SpinelDecoder mDecoder;
bool mHostPowerStateInProgress;
private:
@@ -621,11 +605,10 @@ private:
};
// Command Handlers
- static const CommandHandlerEntry mCommandHandlerTable[];
- static const GetPropertyHandlerEntry mGetPropertyHandlerTable[];
- static const SetPropertyHandlerEntry mSetPropertyHandlerTable[];
- static const InsertPropertyHandlerEntry mInsertPropertyHandlerTable[];
- static const RemovePropertyHandlerEntry mRemovePropertyHandlerTable[];
+ static const PropertyHandlerEntry mGetPropertyHandlerTable[];
+ static const PropertyHandlerEntry mSetPropertyHandlerTable[];
+ static const PropertyHandlerEntry mInsertPropertyHandlerTable[];
+ static const PropertyHandlerEntry mRemovePropertyHandlerTable[];
spinel_status_t mLastStatus;
uint32_t mSupportedChannelMask;
diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp
index 193a6f0e5..83c7efe0a 100644
--- a/src/ncp/ncp_base_ftd.cpp
+++ b/src/ncp/ncp_base_ftd.cpp
@@ -113,26 +113,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void)
return mEncoder.WriteBool(otThreadIsRouterRoleEnabled(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
otThreadSetRouterRoleEnabled(mInstance, enabled);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_PSKC(void)
@@ -140,28 +131,20 @@ otError NcpBase::GetPropertyHandler_NET_PSKC(void)
return mEncoder.WriteData(otThreadGetPSKc(mInstance), sizeof(spinel_net_pskc_t));
}
-otError NcpBase::SetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_PSKC(void)
{
const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
+ uint16_t len;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
+ SuccessOrExit(error = mDecoder.ReadData(ptr, len));
- VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_pskc_t)), error = OT_ERROR_PARSE);
+ VerifyOrExit(len == sizeof(spinel_net_pskc_t), error = OT_ERROR_PARSE);
error = otThreadSetPSKc(mInstance, ptr);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void)
@@ -169,26 +152,17 @@ otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void)
return mEncoder.WriteUint8(otThreadGetMaxAllowedChildren(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(void)
{
uint8_t maxChildren = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &maxChildren
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(maxChildren));
error = otThreadSetMaxAllowedChildren(mInstance, maxChildren);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void)
@@ -196,26 +170,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void)
return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void)
{
uint8_t threshold = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(threshold));
otThreadSetRouterUpgradeThreshold(mInstance, threshold);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void)
@@ -223,26 +188,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void)
return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void)
{
uint8_t threshold = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(threshold));
otThreadSetRouterDowngradeThreshold(mInstance, threshold);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void)
@@ -250,26 +206,17 @@ otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void)
return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void)
{
uint8_t jitter = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &jitter
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(jitter));
otThreadSetRouterSelectionJitter(mInstance, jitter);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void)
@@ -277,26 +224,17 @@ otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void)
return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void)
{
uint32_t delay = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &delay
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint32(delay));
otThreadSetContextIdReuseDelay(mInstance, delay);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void)
@@ -304,26 +242,17 @@ otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void)
return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void)
{
uint8_t timeout = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &timeout
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(timeout));
otThreadSetNetworkIdTimeout(mInstance, timeout);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
#if OPENTHREAD_ENABLE_COMMISSIONER
@@ -332,22 +261,12 @@ otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(void)
return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE);
}
-otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader)
{
bool enabled = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
if (enabled == false)
{
@@ -359,50 +278,26 @@ otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader,
}
exit:
- OT_UNUSED_VARIABLE(aKey);
-
return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
-otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
const char *aPSKd = NULL;
uint32_t joinerTimeout = 0;
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_UTF8_S // PSK
- SPINEL_DATATYPE_UINT32_S // Timeout
- SPINEL_DATATYPE_EUI64_S // Extended address
- ),
- &aPSKd,
- &joinerTimeout,
- &extAddress
- );
+ SuccessOrExit(error = mDecoder.ReadUtf8(aPSKd));
+ SuccessOrExit(error = mDecoder.ReadUint32(joinerTimeout));
- if (parsedLength <= 0)
+ if (mDecoder.ReadEui64(extAddress) != OT_ERROR_NONE)
{
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_UTF8_S // PSK
- SPINEL_DATATYPE_UINT32_S // Timeout
- ),
- &aPSKd,
- &joinerTimeout
- );
extAddress = NULL;
}
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout);
@@ -412,136 +307,74 @@ exit:
#endif // OPENTHREAD_ENABLE_COMMISSIONER
-otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(void)
{
uint8_t weight;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &weight
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(weight));
otThreadSetLocalLeaderWeight(mInstance, weight);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
#if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(void)
{
- otExtAddress *extAddress;
- spinel_ssize_t parsedLength;
+ const otExtAddress *extAddress;
otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otThreadSetSteeringData(mInstance, extAddress);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ SuccessOrExit(error = otThreadSetSteeringData(mInstance, extAddress));
// Note that there is no get handler for this property
-
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
- SuccessOrExit(error = mEncoder.WriteEui64(*extAddress));
- SuccessOrExit(error = mEncoder.EndFrame());
+ // so the response becomes `VALUE_IS` echo of the
+ // received content.
exit:
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
return error;
}
#endif // #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
-otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_CHILD_TIMEOUT(void)
{
uint32_t timeout = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &timeout
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint32(timeout));
otThreadSetChildTimeout(mInstance, timeout);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- uint8_t routerId = 0;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &routerId
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- error = otThreadSetPreferredRouterId(mInstance, routerId);
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- // Note that there is no get handler for this property.
-
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
- SuccessOrExit(error = mEncoder.WriteUint8(routerId));
- SuccessOrExit(error = mEncoder.EndFrame());
-
-exit:
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
return error;
}
-otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(void)
+{
+ uint8_t routerId = 0;
+ otError error = OT_ERROR_NONE;
+
+ SuccessOrExit(error = mDecoder.ReadUint8(routerId));
+
+ SuccessOrExit(error = otThreadSetPreferredRouterId(mInstance, routerId));
+
+ // Note that there is no get handler for this property
+ // so the response becomes `VALUE_IS` echo of the
+ // received content.
+
+exit:
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
uint8_t routerId;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &routerId
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(routerId));
error = otThreadReleaseRouterId(mInstance, routerId);
@@ -563,37 +396,22 @@ otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(void)
return mEncoder.WriteBool(otTmfProxyIsEnabled(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(void)
{
const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
+ uint16_t frameLen = 0;
uint16_t locator;
uint16_t port;
otMessage *message;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
// THREAD_TMF_PROXY_STREAM requires layer 2 security.
message = otIp6NewMessage(mInstance, true);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_UINT16_S // Locator
- SPINEL_DATATYPE_UINT16_S // Port
- ),
- &framePtr,
- &frameLen,
- &locator,
- &port
- );
-
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen));
+ SuccessOrExit(error = mDecoder.ReadUint16(locator));
+ SuccessOrExit(error = mDecoder.ReadUint16(port));
SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
@@ -610,40 +428,15 @@ exit:
otMessageFree(message);
}
- if (error == OT_ERROR_NONE)
- {
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
- }
- else
- {
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
- }
-
- OT_UNUSED_VARIABLE(aKey);
-
return error;
}
-otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
if (enabled)
{
@@ -655,7 +448,7 @@ otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, sp
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort, void *aContext)
diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp
index c240a27df..1fef0240b 100644
--- a/src/ncp/ncp_base_mtd.cpp
+++ b/src/ncp/ncp_base_mtd.cpp
@@ -177,26 +177,17 @@ otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(void)
return mEncoder.WriteUint32(otLinkGetPollPeriod(mInstance));
}
-otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(void)
{
uint32_t pollPeriod;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &pollPeriod
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint32(pollPeriod));
otLinkSetPollPeriod(mInstance, pollPeriod);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(void)
@@ -235,33 +226,18 @@ otError NcpBase::GetPropertyHandler_PHY_RSSI(void)
return mEncoder.WriteInt8(otPlatRadioGetRssi(mInstance));
}
-otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
+otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader)
{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
}
-otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
+otError NcpBase::CommandHandler_NET_CLEAR(uint8_t aHeader)
{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(otInstanceErasePersistentInfo(mInstance)));
}
-otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
- uint16_t aArgLen)
+otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader)
{
- OT_UNUSED_VARIABLE(aCommand);
- OT_UNUSED_VARIABLE(aArgPtr);
- OT_UNUSED_VARIABLE(aArgLen);
-
return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED);
}
@@ -275,26 +251,17 @@ otError NcpBase::GetPropertyHandler_NET_IF_UP(void)
return mEncoder.WriteBool(otIp6IsEnabled(mInstance));
}
-otError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_IF_UP(void)
{
bool enabled = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
error = otIp6SetEnabled(mInstance, enabled);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_STACK_UP(void)
@@ -302,21 +269,12 @@ otError NcpBase::GetPropertyHandler_NET_STACK_UP(void)
return mEncoder.WriteBool(otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED);
}
-otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_STACK_UP(void)
{
bool enabled = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
// If the value has changed...
if ((enabled != false) != (otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED))
@@ -350,7 +308,7 @@ otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_ke
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_ROLE(void)
@@ -380,22 +338,12 @@ otError NcpBase::GetPropertyHandler_NET_ROLE(void)
return mEncoder.WriteUint8(role);
}
-otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_ROLE(void)
{
unsigned int role = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT_PACKED_S,
- &role
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
+ SuccessOrExit(error = mDecoder.ReadUintPacked(role));
switch (role)
{
@@ -419,7 +367,7 @@ otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(void)
@@ -427,26 +375,17 @@ otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(void)
return mEncoder.WriteUtf8(otThreadGetNetworkName(mInstance));
}
-otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(void)
{
const char *string = NULL;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UTF8_S,
- &string
- );
-
- VerifyOrExit((parsedLength > 0) && (string != NULL), error = OT_ERROR_PARSE);
+ SuccessOrExit(mDecoder.ReadUtf8(string));
error = otThreadSetNetworkName(mInstance, string);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_XPANID(void)
@@ -454,28 +393,20 @@ otError NcpBase::GetPropertyHandler_NET_XPANID(void)
return mEncoder.WriteData(otThreadGetExtendedPanId(mInstance), sizeof(spinel_net_xpanid_t));
}
-otError NcpBase::SetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_XPANID(void)
{
const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
+ uint16_t len;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
+ SuccessOrExit(error = mDecoder.ReadData(ptr, len));
- VerifyOrExit((parsedLength > 0) && (len == sizeof(spinel_net_xpanid_t)), error = OT_ERROR_PARSE);
+ VerifyOrExit(len == sizeof(spinel_net_xpanid_t), error = OT_ERROR_PARSE);
error = otThreadSetExtendedPanId(mInstance, ptr);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(void)
@@ -483,28 +414,20 @@ otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(void)
return mEncoder.WriteData(otThreadGetMasterKey(mInstance)->m8, OT_MASTER_KEY_SIZE);
}
-otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(void)
{
const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
+ uint16_t len;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
+ SuccessOrExit(error = mDecoder.ReadData(ptr, len));
- VerifyOrExit((parsedLength > 0) && (len == OT_MASTER_KEY_SIZE), error = OT_ERROR_PARSE);
+ VerifyOrExit(len == OT_MASTER_KEY_SIZE, error = OT_ERROR_PARSE);
error = otThreadSetMasterKey(mInstance, reinterpret_cast(ptr));
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void)
@@ -512,26 +435,17 @@ otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void)
return mEncoder.WriteUint32(otThreadGetKeySequenceCounter(mInstance));
}
-otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void)
{
- unsigned int keySeqCounter;
- spinel_ssize_t parsedLength;
+ uint32_t keySeqCounter;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &keySeqCounter
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint32(keySeqCounter));
otThreadSetKeySequenceCounter(mInstance, keySeqCounter);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(void)
@@ -544,26 +458,17 @@ otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(void)
return mEncoder.WriteUint32(otThreadGetKeySwitchGuardTime(mInstance));
}
-otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(void)
{
- unsigned int keyGuardTime;
- spinel_ssize_t parsedLength;
+ uint32_t keyGuardTime;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT32_S,
- &keyGuardTime
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint32(keyGuardTime));
otThreadSetKeySwitchGuardTime(mInstance, keyGuardTime);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(void)
@@ -735,57 +640,36 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ASSISTING_PORTS(void)
{
uint8_t numEntries = 0;
const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
- spinel_ssize_t parsedLength;
- bool portsChanged = false;
otError error = OT_ERROR_NONE;
// First, we need to remove all of the current assisting ports.
for (; numEntries != 0; ports++, numEntries--)
{
SuccessOrExit(error = otIp6RemoveUnsecurePort(mInstance, *ports));
- portsChanged = true;
}
- while (aValueLen >= 2)
+ while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t))
{
uint16_t port;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(mDecoder.ReadUint16(port));
SuccessOrExit(error = otIp6AddUnsecurePort(mInstance, port));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
-
- portsChanged = true;
}
- // No error happened so the new state of ports will
- // be reported in the response.
- portsChanged = false;
-
exit:
- error = SendSetPropertyResponse(aHeader, aKey, error);
- if (portsChanged)
+ if (error != OT_ERROR_NONE)
{
// We had an error, but we've actually changed
- // the state of these ports---so we need to report
+ // the state of these ports, so we need to report
// those incomplete changes via an asynchronous
// change event.
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_THREAD_ASSISTING_PORTS);
}
return error;
@@ -797,22 +681,13 @@ otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(void)
}
#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(void)
{
bool value = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
bool shouldRegisterWithLeader = false;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(value));
// Register any net data changes on transition from `true` to `false`.
shouldRegisterWithLeader = (mAllowLocalNetworkDataChange == true) && (value == false);
@@ -820,7 +695,6 @@ otError NcpBase::SetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t a
mAllowLocalNetworkDataChange = value;
exit:
- error = SendSetPropertyResponse(aHeader, aKey, error);
if (shouldRegisterWithLeader)
{
@@ -877,12 +751,10 @@ exit:
}
#if OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otBorderRouterConfig borderRouterConfig;
- otIp6Address *addrPtr;
bool stable = false;
uint8_t flags = 0;
@@ -890,24 +762,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValue
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_BOOL_S // Stable
- SPINEL_DATATYPE_UINT8_S // Flags
- ),
- &addrPtr,
- &borderRouterConfig.mPrefix.mLength,
- &stable,
- &flags
- );
+ SuccessOrExit(error = mDecoder.ReadIp6Address(borderRouterConfig.mPrefix.mPrefix));
+ SuccessOrExit(error = mDecoder.ReadUint8(borderRouterConfig.mPrefix.mLength));
+ SuccessOrExit(error = mDecoder.ReadBool(stable));
+ SuccessOrExit(error = mDecoder.ReadUint8(flags));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- borderRouterConfig.mPrefix.mPrefix = *addrPtr;
borderRouterConfig.mStable = stable;
borderRouterConfig.mPreference =
((flags & SPINEL_NET_FLAG_PREFERENCE_MASK) >> SPINEL_NET_FLAG_PREFERENCE_OFFSET);
@@ -924,31 +783,17 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otIp6Prefix ip6Prefix;
- otIp6Address *addrPtr;
memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // On-mesh prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- ),
- &addrPtr,
- &ip6Prefix.mLength
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- ip6Prefix.mPrefix = *addrPtr;
+ SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix));
+ SuccessOrExit(error = mDecoder.ReadUint8(ip6Prefix.mLength));
error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix);
@@ -970,26 +815,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(void)
return mEncoder.WriteBool(mDiscoveryScanJoinerFlag);
}
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(void)
{
- bool joinerFlag = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &joinerFlag
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanJoinerFlag = joinerFlag;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return mDecoder.ReadBool(mDiscoveryScanJoinerFlag);
}
otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void)
@@ -997,27 +825,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void)
return mEncoder.WriteBool(mDiscoveryScanEnableFiltering);
}
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void)
{
- bool enabled = false;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanEnableFiltering = enabled;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return mDecoder.ReadBool(mDiscoveryScanEnableFiltering);
}
otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void)
@@ -1025,26 +835,9 @@ otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void)
return mEncoder.WriteUint16(mDiscoveryScanPanId);
}
-otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void)
{
- uint16_t panid;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &panid
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mDiscoveryScanPanId = panid;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return mDecoder.ReadUint16(mDiscoveryScanPanId);
}
otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(void)
@@ -1067,17 +860,20 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_IPV6_ML_PREFIX(void)
{
otError error = OT_ERROR_NONE;
+ const uint8_t *meshLocalPrefix;
+ uint16_t prefixLength;
- VerifyOrExit(aValueLen >= 8, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadData(meshLocalPrefix, prefixLength));
- error = otThreadSetMeshLocalPrefix(mInstance, aValuePtr);
+ VerifyOrExit(prefixLength >= 8, error = OT_ERROR_PARSE);
+
+ error = otThreadSetMeshLocalPrefix(mInstance, meshLocalPrefix);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(void)
@@ -1124,37 +920,20 @@ exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otNetifAddress netifAddr;
- otIp6Address *addrPtr;
uint32_t preferredLifetime;
uint32_t validLifetime;
- uint8_t prefixLen;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_UINT32_S // Preferred lifetime
- SPINEL_DATATYPE_UINT32_S // Valid lifetime
- ),
- &addrPtr,
- &prefixLen,
- &preferredLifetime,
- &validLifetime
- );
+ SuccessOrExit(error = mDecoder.ReadIp6Address(netifAddr.mAddress));
+ SuccessOrExit(error = mDecoder.ReadUint8(netifAddr.mPrefixLength));
+ SuccessOrExit(error = mDecoder.ReadUint32(preferredLifetime));
+ SuccessOrExit(error = mDecoder.ReadUint32(validLifetime));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- netifAddr.mAddress = *addrPtr;
- netifAddr.mPrefixLength = prefixLen;
- netifAddr.mPreferred = preferredLifetime != 0;
- netifAddr.mValid = validLifetime != 0;
+ netifAddr.mPreferred = (preferredLifetime != 0);
+ netifAddr.mValid = (validLifetime != 0);
error = otIp6AddUnicastAddress(mInstance, &netifAddr);
@@ -1162,20 +941,12 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otIp6Address *addrPtr;
+ const otIp6Address *addrPtr;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S,
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
error = otIp6RemoveUnicastAddress(mInstance, addrPtr);
@@ -1200,26 +971,17 @@ otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void)
return mEncoder.WriteBool(otIcmp6IsEchoEnabled(mInstance));
}
-otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void)
{
bool enabled = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
otIcmp6SetEchoEnabled(mInstance, enabled);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void)
@@ -1238,20 +1000,12 @@ exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otIp6Address *addrPtr;
+ const otIp6Address *addrPtr;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S, // IPv6 address
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
error = otIp6SubscribeMulticastAddress(mInstance, addrPtr);
@@ -1264,20 +1018,12 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otIp6Address *addrPtr;
+ const otIp6Address *addrPtr;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_IPv6ADDR_S,
- &addrPtr
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadIp6Address(addrPtr));
error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr);
@@ -1298,27 +1044,18 @@ otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void)
return mEncoder.WriteBool(!otIp6IsReceiveFilterEnabled(mInstance));
}
-otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void)
{
bool enabled = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
// Note reverse logic: passthru enabled = filter disabled
otIp6SetReceiveFilterEnabled(mInstance, !enabled);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(void)
@@ -1389,12 +1126,10 @@ static int FlagByteToExternalRoutePreference(uint8_t aFlags)
return route_preference;
}
-otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otExternalRouteConfig routeConfig;
- otIp6Address *addrPtr;
bool stable = false;
uint8_t flags = 0;
@@ -1402,24 +1137,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aVa
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- SPINEL_DATATYPE_BOOL_S // Stable
- SPINEL_DATATYPE_UINT8_S // Flags (Route Preference)
- ),
- &addrPtr,
- &routeConfig.mPrefix.mLength,
- &stable,
- &flags
- );
+ SuccessOrExit(error = mDecoder.ReadIp6Address(routeConfig.mPrefix.mPrefix));
+ SuccessOrExit(error = mDecoder.ReadUint8(routeConfig.mPrefix.mLength));
+ SuccessOrExit(error = mDecoder.ReadBool(stable));
+ SuccessOrExit(error = mDecoder.ReadUint8(flags));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- routeConfig.mPrefix.mPrefix = *addrPtr;
routeConfig.mStable = stable;
routeConfig.mPreference = FlagByteToExternalRoutePreference(flags);
@@ -1429,31 +1151,17 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otIp6Prefix ip6Prefix;
- otIp6Address *addrPtr;
memset(&ip6Prefix, 0, sizeof(otIp6Prefix));
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_IPv6ADDR_S // Route prefix
- SPINEL_DATATYPE_UINT8_S // Prefix length (in bits)
- ),
- &addrPtr,
- &ip6Prefix.mLength
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- ip6Prefix.mPrefix = *addrPtr;
+ SuccessOrExit(error = mDecoder.ReadIp6Address(ip6Prefix.mPrefix));
+ SuccessOrExit(error = mDecoder.ReadUint8(ip6Prefix.mLength));
error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix);
@@ -1468,45 +1176,26 @@ exit:
}
#endif // OPENTHREAD_ENABLE_BORDER_ROUTER
-otError NcpBase::GetPropertyHandler_STREAM_NET(void)
-{
- // TODO: Implement explicit data poll.
- return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED);
-}
-
-otError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_STREAM_NET(void)
{
const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
+ uint16_t frameLen = 0;
const uint8_t *metaPtr = NULL;
- unsigned int metaLen = 0;
- otMessage *message;
- spinel_ssize_t parsedLength;
+ uint16_t metaLen = 0;
+ otMessage *message = NULL;
otError error = OT_ERROR_NONE;
// STREAM_NET requires layer 2 security.
message = otIp6NewMessage(mInstance, true);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_DATA_S // Meta data
- ),
- &framePtr,
- &frameLen,
- &metaPtr,
- &metaLen
- );
+ SuccessOrExit(error = mDecoder.ReadDataWithLen(framePtr, frameLen));
+ SuccessOrExit(error = mDecoder.ReadData(metaPtr, metaLen));
// We ignore metadata for now.
// May later include TX power, allow retransmits, etc...
OT_UNUSED_VARIABLE(metaPtr);
OT_UNUSED_VARIABLE(metaLen);
- OT_UNUSED_VARIABLE(parsedLength);
SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
@@ -1527,23 +1216,12 @@ exit:
if (error == OT_ERROR_NONE)
{
mInboundSecureIpFrameCounter++;
-
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
}
else
{
mDroppedInboundIpFrameCounter++;
-
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
- OT_UNUSED_VARIABLE(aKey);
-
return error;
}
@@ -1589,21 +1267,12 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
if (enabled)
{
@@ -1615,73 +1284,46 @@ otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_pr
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(void)
{
int8_t threshold = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_INT8_S,
- &threshold
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadInt8(threshold));
error = otJamDetectionSetRssiThreshold(mInstance, threshold);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_JAM_DETECT_WINDOW(void)
{
uint8_t window = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &window
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(window));
error = otJamDetectionSetWindow(mInstance, window);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_JAM_DETECT_BUSY(void)
{
uint8_t busy = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &busy
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(busy));
error = otJamDetectionSetBusyPeriod(mInstance, busy);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
void NcpBase::HandleJamStateChange_Jump(bool aJamState, void *aContext)
@@ -2021,93 +1663,68 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_WHITELIST(void)
{
- bool reportAsync;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
// First, clear the address filter entries.
otLinkFilterClearAddresses(mInstance);
- while (aValueLen > 0)
+ while (mDecoder.GetRemainingLengthInStruct() > 0)
{
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
int8_t rss;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- SPINEL_DATATYPE_INT8_S
- ),
- &extAddress,
- &rss
- );
+ SuccessOrExit(error = mDecoder.OpenStruct());
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
- if (parsedLength <= 0)
+ if (!mDecoder.IsAllReadInStruct())
+ {
+ SuccessOrExit(error = mDecoder.ReadInt8(rss));
+ }
+ else
{
rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- ),
- &extAddress
- );
}
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.CloseStruct());
error = otLinkFilterAddAddress(mInstance, extAddress);
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
+ if (error == OT_ERROR_ALREADY)
+ {
+ error = OT_ERROR_NONE;
+ }
+
+ SuccessOrExit(error);
if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED)
{
SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
}
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
}
exit:
// If we had an error, we may have actually changed
- // the state of the whitelist---so we need to report
+ // the state of the whitelist, so we need to report
// those incomplete changes via an asynchronous
// change event.
- reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
+ if (error != OT_ERROR_NONE)
{
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_WHITELIST);
}
return error;
}
-otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
if (enabled)
{
@@ -2117,75 +1734,55 @@ otError NcpBase::SetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spine
error = otLinkFilterSetAddressMode(mInstance, mode);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_BLACKLIST(void)
{
- bool reportAsync;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
// First, clear the address filter entries.
otLinkFilterClearAddresses(mInstance);
- while (aValueLen > 0)
+ while (mDecoder.GetRemainingLengthInStruct() > 0)
{
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- ),
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.OpenStruct());
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
+ SuccessOrExit(error = mDecoder.CloseStruct());
error = otLinkFilterRemoveAddress(mInstance, extAddress);
- VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
+ if (error == OT_ERROR_ALREADY)
+ {
+ error = OT_ERROR_NONE;
+ }
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
+ SuccessOrExit(error);
}
exit:
// If we had an error, we may have actually changed
- // the state of the blacklist---so we need to report
+ // the state of the blacklist, so we need to report
// those incomplete changes via an asynchronous
// change event.
- reportAsync = (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY);
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
+ if (error != OT_ERROR_NONE)
{
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_BLACKLIST);
}
return error;
}
-otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
otMacFilterAddressMode mode = OT_MAC_FILTER_ADDRESS_MODE_DISABLED;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
if (enabled)
{
@@ -2195,68 +1792,48 @@ otError NcpBase::SetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spine
error = otLinkFilterSetAddressMode(mInstance, mode);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_FIXED_RSS(void)
{
- bool reportAsync;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
// First, clear the address filter entries.
otLinkFilterClearRssIn(mInstance);
- while (aValueLen > 0)
+ while (mDecoder.GetRemainingLengthInStruct() > 0)
{
- otExtAddress *extAddress;
+ const otExtAddress *extAddress;
int8_t rss;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_EUI64_S
- SPINEL_DATATYPE_INT8_S
- ),
- &extAddress,
- &rss
- );
+ SuccessOrExit(error = mDecoder.OpenStruct());
- if (parsedLength < 0)
+ if (mDecoder.GetRemainingLengthInStruct() > sizeof(otExtAddress))
+ {
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
+ }
+ else
{
extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_STRUCT_S(
- SPINEL_DATATYPE_INT8_S
- ),
- &rss
- );
}
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadInt8(rss));
+
+ SuccessOrExit(error = mDecoder.CloseStruct());
SuccessOrExit(error = otLinkFilterAddRssIn(mInstance, extAddress, rss));
-
- aValuePtr += parsedLength;
- aValueLen -= parsedLength;
}
exit:
// If we had an error, we may have actually changed
- // the state of the RssIn filter---so we need to report
+ // the state of the RssIn filter, so we need to report
// those incomplete changes via an asynchronous
// change event.
- reportAsync = (error != OT_ERROR_NONE);
- error = SendSetPropertyResponse(aHeader, aKey, error);
-
- if (reportAsync)
+ if (error != OT_ERROR_NONE)
{
- HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, aKey);
+ HandleCommandPropertyGet(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_PROP_MAC_FIXED_RSS);
}
return error;
@@ -2278,22 +1855,13 @@ otError NcpBase::GetPropertyHandler_THREAD_MODE(void)
return mEncoder.WriteUint8(numericMode);
}
-otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_THREAD_MODE(void)
{
uint8_t numericMode = 0;
otLinkModeConfig modeConfig;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &numericMode
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(mDecoder.ReadUint8(numericMode));
modeConfig.mRxOnWhenIdle = ((numericMode & SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE) == SPINEL_THREAD_MODE_RX_ON_WHEN_IDLE);
modeConfig.mSecureDataRequests =
@@ -2304,7 +1872,7 @@ otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key
error = otThreadSetLinkMode(mInstance, modeConfig);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(void)
@@ -2322,61 +1890,31 @@ otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(void)
return mEncoder.WriteBool(mRequireJoinExistingNetwork);
}
-otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(void)
{
- bool value = mRequireJoinExistingNetwork;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mRequireJoinExistingNetwork = value;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return mDecoder.ReadBool(mRequireJoinExistingNetwork);
}
-otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_STREAM_NET_INSECURE(void)
{
const uint8_t *framePtr = NULL;
- unsigned int frameLen = 0;
+ uint16_t frameLen = 0;
const uint8_t *metaPtr = NULL;
- unsigned int metaLen = 0;
- otMessage *message;
- spinel_ssize_t parsedLength;
+ uint16_t metaLen = 0;
+ otMessage *message = NULL;
otError error = OT_ERROR_NONE;
// STREAM_NET_INSECURE packets are not secured at layer 2.
message = otIp6NewMessage(mInstance, false);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- (
- SPINEL_DATATYPE_DATA_WLEN_S // Frame data
- SPINEL_DATATYPE_DATA_S // Meta data
- ),
- &framePtr,
- &frameLen,
- &metaPtr,
- &metaLen
- );
+ SuccessOrExit(mDecoder.ReadDataWithLen(framePtr, frameLen));
+ SuccessOrExit(mDecoder.ReadData(metaPtr, metaLen));
// We ignore metadata for now.
// May later include TX power, allow retransmits, etc...
OT_UNUSED_VARIABLE(metaPtr);
OT_UNUSED_VARIABLE(metaLen);
- OT_UNUSED_VARIABLE(parsedLength);
SuccessOrExit(error = otMessageAppend(message, framePtr, static_cast(frameLen)));
@@ -2400,41 +1938,21 @@ exit:
{
mInboundInsecureIpFrameCounter++;
- if (SPINEL_HEADER_GET_TID(aHeader) != 0)
- {
- // Only send a successful status update if
- // there was a transaction id in the aHeader.
- error = SendLastStatus(aHeader, SPINEL_STATUS_OK);
- }
}
else
{
mDroppedInboundIpFrameCounter++;
-
- error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
- OT_UNUSED_VARIABLE(aKey);
-
return error;
}
-
-otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_CNTR_RESET(void)
{
uint8_t value = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(value));
VerifyOrExit(value == 1, error = OT_ERROR_INVALID_ARGS);
@@ -2442,70 +1960,41 @@ otError NcpBase::SetPropertyHandler_CNTR_RESET(uint8_t aHeader, spinel_prop_key_
error = OT_ERROR_NOT_IMPLEMENTED;
exit:
- OT_UNUSED_VARIABLE(aKey);
-
- // There is currently no getter for PROP_CNTR_RESET, so we just
- // return SPINEL_STATUS_OK for success when the counters are reset.
-
- return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
+ return error;
}
-
#if OPENTHREAD_ENABLE_DIAG
-otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader)
{
- char *string = NULL;
+ const char *string = NULL;
char *output = NULL;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UTF8_S,
- &string
- );
+ error = mDecoder.ReadUtf8(string);
-
-
- VerifyOrExit((parsedLength > 0) && (string != NULL), spinelError = SPINEL_STATUS_PARSE_ERROR);
+ VerifyOrExit(error == OT_ERROR_NONE, error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)));
// All diagnostics related features are processed within diagnostics module
- output = otDiagProcessCmdLine(string);
+ output = otDiagProcessCmdLine(const_cast(string));
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
+ // Prepare the response
+ SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_NEST_STREAM_MFG));
SuccessOrExit(error = mEncoder.WriteUtf8(output));
SuccessOrExit(error = mEncoder.EndFrame());
exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
return error;
}
#endif // OPENTHREAD_ENABLE_DIAG
-otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
uint16_t port;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint16(port));
error = otIp6AddUnsecurePort(mInstance, port);
exit:
@@ -2514,34 +2003,18 @@ exit:
#if OPENTHREAD_ENABLE_MAC_FILTER
-otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
- if (aValueLen > static_cast(sizeof(otExtAddress)))
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
- &extAddress,
- &rss
- );
- }
- else
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
- }
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ if (!mDecoder.IsAllRead())
+ {
+ SuccessOrExit(error = mDecoder.ReadInt8(rss));
+ }
error = otLinkFilterAddAddress(mInstance, extAddress);
@@ -2561,20 +2034,12 @@ exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
error = otLinkFilterAddAddress(mInstance, extAddress);
@@ -2587,34 +2052,18 @@ exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED;
- if (aValueLen > sizeof(int8_t))
+ if (mDecoder.GetRemainingLength() > sizeof(int8_t))
{
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_INT8_S,
- &extAddress,
- &rss
- );
- }
- else
- {
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_INT8_S,
- &rss
- );
+ SuccessOrExit(mDecoder.ReadEui64(extAddress));
}
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(mDecoder.ReadInt8(rss));
error = otLinkFilterAddRssIn(mInstance, extAddress, rss);
@@ -2624,20 +2073,12 @@ exit:
#endif // OPENTHREAD_ENABLE_MAC_FILTER
-otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
uint16_t port;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &port
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint16(port));
error = otIp6RemoveUnsecurePort(mInstance, port);
@@ -2653,20 +2094,12 @@ exit:
#if OPENTHREAD_ENABLE_MAC_FILTER
-otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
error = otLinkFilterRemoveAddress(mInstance, extAddress);
@@ -2679,20 +2112,12 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
error = otLinkFilterRemoveAddress(mInstance, extAddress);
@@ -2705,22 +2130,14 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- if (aValueLen > 0)
+ if (mDecoder.GetRemainingLength() > 0)
{
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
}
error = otLinkFilterRemoveRssIn(mInstance, extAddress);
@@ -2794,23 +2211,15 @@ otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(void)
return mEncoder.WriteData(mLegacyUlaPrefix, sizeof(mLegacyUlaPrefix));
}
-otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(void)
{
const uint8_t *ptr = NULL;
- spinel_size_t len;
- spinel_ssize_t parsedLength;
+ uint16_t len;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_S,
- &ptr,
- &len
- );
+ SuccessOrExit(error = mDecoder.ReadData(ptr, len));
- VerifyOrExit((parsedLength > 0) && (len <= sizeof(mLegacyUlaPrefix)), error = OT_ERROR_PARSE);
+ VerifyOrExit(len <= sizeof(mLegacyUlaPrefix), error = OT_ERROR_PARSE);
memset(mLegacyUlaPrefix, 0, sizeof(mLegacyUlaPrefix));
memcpy(mLegacyUlaPrefix, ptr, len);
@@ -2821,7 +2230,7 @@ otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spin
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(void)
@@ -2858,24 +2267,27 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(void)
return GetPropertyHandler_ChannelMaskHelper(mChannelMask);
}
-otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(void)
{
uint32_t newMask = 0;
otError error = OT_ERROR_NONE;
+ const uint8_t *valuePtr;
+ uint16_t valueLen;
- for (; aValueLen != 0; aValueLen--, aValuePtr++)
+ SuccessOrExit(error = mDecoder.ReadData(valuePtr, valueLen));
+
+ for (; valueLen != 0; valueLen--, valuePtr++)
{
- VerifyOrExit(aValuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS);
- VerifyOrExit((mSupportedChannelMask & (1 << aValuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit(valuePtr[0] <= 31, error = OT_ERROR_INVALID_ARGS);
+ VerifyOrExit((mSupportedChannelMask & (1 << valuePtr[0])) != 0, error = OT_ERROR_INVALID_ARGS);
- newMask |= (1 << aValuePtr[0]);
+ newMask |= (1 << valuePtr[0]);
}
mChannelMask = newMask;
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(void)
@@ -2883,26 +2295,9 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(void)
return mEncoder.WriteUint16(mScanPeriod);
}
-otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(void)
{
- uint16_t period = mScanPeriod;
- spinel_ssize_t parsedLength;
- otError error = OT_ERROR_NONE;
-
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &period
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- mScanPeriod = period;
-
-exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return mDecoder.ReadUint16(mScanPeriod);
}
otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(void)
@@ -2942,21 +2337,12 @@ otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(void)
return mEncoder.WriteUint8(scanState);
}
-otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(void)
{
uint8_t state = 0;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT8_S,
- &state
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint8(state));
switch (state)
{
@@ -3041,7 +2427,7 @@ otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aContext)
@@ -3098,7 +2484,7 @@ void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult)
}
else
{
- // We are finished with the scan, send an unsolicated
+ // We are finished with the scan, send an unsolicited
// scan state update.
mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
mUpdateChangedPropsTask.Post();
@@ -3138,7 +2524,7 @@ void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult)
}
else
{
- // We are finished with the scan, send an unsolicated
+ // We are finished with the scan, send an unsolicited
// scan state update.
mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE);
mUpdateChangedPropsTask.Post();
diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp
index ace98cade..4ada00ecb 100644
--- a/src/ncp/ncp_base_radio.cpp
+++ b/src/ncp/ncp_base_radio.cpp
@@ -193,142 +193,67 @@ exit:
return;
}
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(void)
{
bool enabled;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &enabled
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(enabled));
error = otLinkRawSrcMatchEnable(mInstance, enabled);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
-}
-
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
-{
- otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- const uint8_t *data = aValuePtr;
- uint16_t dataLen = aValueLen;
-
- // Clear the list first
- error = otLinkRawSrcMatchClearShortEntries(mInstance);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
-
- // Loop through the addresses and add them
- while (dataLen >= sizeof(uint16_t))
- {
- spinel_ssize_t parsedLength;
- uint16_t short_address;
-
- parsedLength = spinel_datatype_unpack(
- data,
- dataLen,
- SPINEL_DATATYPE_UINT16_S,
- &short_address
- );
-
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- data += parsedLength;
- dataLen -= (uint16_t)parsedLength;
-
- error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
- }
-
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
- SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
- SuccessOrExit(error = mEncoder.EndFrame());
-
-exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
return error;
}
-otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
- const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void)
{
otError error = OT_ERROR_NONE;
- spinel_status_t spinelError = SPINEL_STATUS_OK;
- const uint8_t *data = aValuePtr;
- uint16_t dataLen = aValueLen;
// Clear the list first
- error = otLinkRawSrcMatchClearExtEntries(mInstance);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ SuccessOrExit(error = otLinkRawSrcMatchClearShortEntries(mInstance));
// Loop through the addresses and add them
- while (dataLen >= sizeof(otExtAddress))
+ while (mDecoder.GetRemainingLengthInStruct() >= sizeof(uint16_t))
{
- spinel_ssize_t parsedLength;
- otExtAddress *extAddress;
+ uint16_t shortAddress;
- parsedLength = spinel_datatype_unpack(
- data,
- dataLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
+ SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
- VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
-
- data += parsedLength;
- dataLen -= (uint16_t)parsedLength;
-
- error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
-
- VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
+ SuccessOrExit(error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress));
}
- SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
- SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
- SuccessOrExit(error = mEncoder.EndFrame());
-
exit:
-
- if (spinelError != SPINEL_STATUS_OK)
- {
- error = SendLastStatus(aHeader, spinelError);
- }
-
return error;
}
-otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void)
+{
+ otError error = OT_ERROR_NONE;
+
+ // Clear the list first
+ SuccessOrExit(error = otLinkRawSrcMatchClearExtEntries(mInstance));
+
+ // Loop through the addresses and add them
+ while (mDecoder.GetRemainingLengthInStruct() >= sizeof(otExtAddress))
+ {
+ const otExtAddress *extAddress;
+
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
+
+ SuccessOrExit(error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress));
+ }
+
+exit:
+ return error;
+}
+
+otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
uint16_t shortAddress;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &shortAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress);
@@ -336,20 +261,12 @@ exit:
return error;
}
-otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress;
+ const otExtAddress *extAddress;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));;
error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress);
@@ -357,41 +274,25 @@ exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- uint16_t short_address;
+ uint16_t shortAddress;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &short_address
- );
+ SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
-
- error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
+ error = otLinkRawSrcMatchAddShortEntry(mInstance, shortAddress);
exit:
return error;
}
-otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
+otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(void)
{
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- otExtAddress *extAddress = NULL;
+ const otExtAddress *extAddress = NULL;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_EUI64_S,
- &extAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadEui64(extAddress));
error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
@@ -399,21 +300,12 @@ exit:
return error;
}
-otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_PHY_ENABLED(void)
{
bool value = false;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_BOOL_S,
- &value
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadBool(value));
if (value == false)
{
@@ -437,64 +329,45 @@ otError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key
}
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_MAC_15_4_SADDR(void)
{
uint16_t shortAddress;
- spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_UINT16_S,
- &shortAddress
- );
-
- VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
+ SuccessOrExit(error = mDecoder.ReadUint16(shortAddress));
error = otLinkRawSetShortAddress(mInstance, shortAddress);
exit:
- return SendSetPropertyResponse(aHeader, aKey, error);
+ return error;
}
-otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
- uint16_t aValueLen)
+otError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t aHeader)
{
- uint8_t *frame_buffer = NULL;
+ const uint8_t *frameBuffer = NULL;
otRadioFrame *frame;
- unsigned int frameLen = 0;
- spinel_ssize_t parsedLength;
+ uint16_t frameLen = 0;
otError error = OT_ERROR_NONE;
VerifyOrExit(otLinkRawIsEnabled(mInstance), error = OT_ERROR_INVALID_STATE);
frame = otLinkRawGetTransmitBuffer(mInstance);
- parsedLength = spinel_datatype_unpack(
- aValuePtr,
- aValueLen,
- SPINEL_DATATYPE_DATA_WLEN_S
- SPINEL_DATATYPE_UINT8_S
- SPINEL_DATATYPE_INT8_S,
- &frame_buffer,
- &frameLen,
- &frame->mChannel,
- &frame->mPower
- );
+ SuccessOrExit(error = mDecoder.ReadDataWithLen(frameBuffer, frameLen));
+ SuccessOrExit(error = mDecoder.ReadUint8(frame->mChannel));
+ SuccessOrExit(error = mDecoder.ReadInt8(frame->mPower));
- VerifyOrExit(parsedLength > 0 && frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE);
+ VerifyOrExit(frameLen <= OT_RADIO_FRAME_MAX_SIZE, error = OT_ERROR_PARSE);
// Cache the transaction ID for async response
mCurTransmitTID = SPINEL_HEADER_GET_TID(aHeader);
// Update frame buffer and length
frame->mLength = static_cast(frameLen);
- memcpy(frame->mPsdu, frame_buffer, frame->mLength);
+ memcpy(frame->mPsdu, frameBuffer, frame->mLength);
// TODO: This should be later added in the STREAM_RAW argument to allow user to directly specify it.
frame->mMaxTxAttempts = OPENTHREAD_CONFIG_MAX_TX_ATTEMPTS_DIRECT;
@@ -514,8 +387,6 @@ exit:
error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
- OT_UNUSED_VARIABLE(aKey);
-
return error;
}
diff --git a/src/ncp/spinel_decoder.cpp b/src/ncp/spinel_decoder.cpp
new file mode 100644
index 000000000..08d0472e9
--- /dev/null
+++ b/src/ncp/spinel_decoder.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2017, 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 a spinel decoder.
+ */
+
+#include
+
+#include "spinel_decoder.hpp"
+
+#include "common/code_utils.hpp"
+
+namespace ot {
+namespace Ncp {
+
+SpinelDecoder::SpinelDecoder(void) :
+ mFrame(NULL),
+ mLength(0),
+ mIndex(0),
+ mEnd(0),
+ mNumOpenStructs(0),
+ mSavedNumOpenStructs(0),
+ mSavedIndex(0),
+ mSavedEnd(0)
+{
+}
+
+void SpinelDecoder::Init(const uint8_t *aFrame, uint16_t aLength)
+{
+ mFrame = aFrame;
+ mLength = (mFrame != NULL) ? aLength : 0;
+
+ Reset();
+ ClearSavedPosition();
+}
+
+void SpinelDecoder::Reset(void)
+{
+ mIndex = 0;
+ mEnd = mLength;
+ mNumOpenStructs = 0;
+ ClearSavedPosition();
+}
+
+otError SpinelDecoder::ReadBool(bool &aBool)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t byte;
+
+ SuccessOrExit(error = ReadUint8(byte));
+
+ // Boolean value are encoded in 8-bits as either 0x00 or 0x01. All other values are illegal.
+ if (byte == 0x00)
+ {
+ aBool = false;
+ }
+ else if (byte == 0x01)
+ {
+ aBool = true;
+ }
+ else
+ {
+ error = OT_ERROR_PARSE;
+ }
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadUint8(uint8_t &aUint8)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(mIndex + sizeof(uint8_t) <= mEnd, error = OT_ERROR_PARSE);
+ aUint8 = mFrame[mIndex];
+ mIndex += sizeof(uint8_t);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadInt8(int8_t &aInt8)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t byte;
+
+ SuccessOrExit(error = ReadUint8(byte));
+ aInt8 = static_cast(byte);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadUint16(uint16_t &aUint16)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(mIndex + sizeof(uint16_t) <= mEnd, error = OT_ERROR_PARSE);
+
+ aUint16 = static_cast(mFrame[mIndex] | (mFrame[mIndex + 1] << 8));
+
+ mIndex += sizeof(uint16_t);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadInt16(int16_t &aInt16)
+{
+ otError error = OT_ERROR_NONE;
+ uint16_t u16;
+
+ SuccessOrExit(error = ReadUint16(u16));
+ aInt16 = static_cast(u16);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadUint32(uint32_t &aUint32)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(mIndex + sizeof(uint32_t) <= mEnd, error = OT_ERROR_PARSE);
+
+ aUint32 = ((static_cast(mFrame[mIndex + 0]) << 0) |
+ (static_cast(mFrame[mIndex + 1]) << 8) |
+ (static_cast(mFrame[mIndex + 2]) << 16) |
+ (static_cast(mFrame[mIndex + 3]) << 24));
+
+ mIndex += sizeof(uint32_t);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadInt32(int32_t &aInt32)
+{
+ otError error = OT_ERROR_NONE;
+ uint32_t u32;
+
+ SuccessOrExit(error = ReadUint32(u32));
+ aInt32 = static_cast(u32);
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadUintPacked(unsigned int &aUint)
+{
+ otError error = OT_ERROR_NONE;
+ spinel_ssize_t parsedLen;
+ unsigned int uint;
+
+ parsedLen = spinel_packed_uint_decode(&mFrame[mIndex], mEnd - mIndex, &uint);
+ VerifyOrExit(parsedLen > 0, error = OT_ERROR_PARSE);
+
+ mIndex += parsedLen;
+ aUint = uint;
+
+exit:
+ return error;
+}
+
+// Reads an item of given size and updates the pointer `aPtr`.
+otError SpinelDecoder::ReadItem(const uint8_t **aPtr, size_t aSize)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(mIndex + aSize <= mEnd, error = OT_ERROR_PARSE);
+
+ *aPtr = &mFrame[mIndex];
+
+ mIndex += aSize;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadIp6Address(spinel_ipv6addr_t &aIp6Addr)
+{
+ otError error = OT_ERROR_NONE;
+ const spinel_ipv6addr_t *ipv6AddrPtr;
+
+ SuccessOrExit(error = ReadIp6Address(ipv6AddrPtr));
+ aIp6Addr = *ipv6AddrPtr;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadIp6Address(otIp6Address &aIp6Addr)
+{
+ otError error = OT_ERROR_NONE;
+ const otIp6Address *ipv6AddrPtr;
+
+ SuccessOrExit(error = ReadIp6Address(ipv6AddrPtr));
+ aIp6Addr = *ipv6AddrPtr;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadEui64(spinel_eui64_t &aEui64)
+{
+ otError error = OT_ERROR_NONE;
+ const spinel_eui64_t *eui64Ptr;
+
+ SuccessOrExit(error = ReadEui64(eui64Ptr));
+ aEui64 = *eui64Ptr;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadEui64(otExtAddress &aEui64)
+{
+ otError error = OT_ERROR_NONE;
+ const otExtAddress *eui64Ptr;
+
+ SuccessOrExit(error = ReadEui64(eui64Ptr));
+ aEui64 = *eui64Ptr;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadEui48(spinel_eui48_t &aEui48)
+{
+ otError error = OT_ERROR_NONE;
+ const spinel_eui48_t *eui48Ptr;
+
+ SuccessOrExit(error = ReadEui48(eui48Ptr));
+ aEui48 = *eui48Ptr;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadUtf8(const char *&aUtf8)
+{
+ otError error = OT_ERROR_NONE;
+ size_t len;
+
+ // Ensure there is at least one byte (for null character).
+ VerifyOrExit(mIndex + sizeof(uint8_t) <= mEnd, error = OT_ERROR_PARSE);
+
+ len = strnlen(reinterpret_cast(&mFrame[mIndex]), mEnd - mIndex);
+ VerifyOrExit(len < static_cast(mEnd - mIndex), error = OT_ERROR_PARSE);
+
+ aUtf8 = reinterpret_cast(&mFrame[mIndex]);
+
+ mIndex += (len + sizeof(uint8_t)); // `sizeof(uint8_t)` is added for the terminating null character.
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::ReadData(const uint8_t *&aData, uint16_t &aDataLen)
+{
+ aDataLen = mEnd - mIndex;
+
+ return ReadItem(&aData, aDataLen);
+}
+
+otError SpinelDecoder::ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen)
+{
+ otError error = OT_ERROR_NONE;
+ uint16_t len;
+
+ SuccessOrExit(error = ReadUint16(len));
+ SuccessOrExit(error = ReadItem(&aData, len));
+ aDataLen = len;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::OpenStruct(void)
+{
+ otError error = OT_ERROR_NONE;
+ uint16_t structLen;
+
+ VerifyOrExit(mNumOpenStructs < kMaxNestedStructs, error = OT_ERROR_INVALID_STATE);
+
+ SuccessOrExit(error = ReadUint16(structLen));
+ VerifyOrExit(structLen <= mEnd - mIndex, error = OT_ERROR_PARSE);
+
+ mPrevEnd[mNumOpenStructs] = mEnd;
+ mEnd = (mIndex + structLen);
+ mNumOpenStructs++;
+
+exit:
+ return error;
+}
+
+otError SpinelDecoder::CloseStruct(void)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(mNumOpenStructs > 0, error = OT_ERROR_INVALID_STATE);
+
+ // If there is a saved position and it is contained
+ // within the current struct being closed, the saved
+ // position is cleared to ensure user cannot go back
+ // to middle of an already closed struct.
+
+ if (IsSavedPositionValid() && (mNumOpenStructs == mSavedNumOpenStructs))
+ {
+ ClearSavedPosition();
+ }
+
+ mNumOpenStructs--;
+ mIndex = mEnd;
+ mEnd = mPrevEnd[mNumOpenStructs];
+
+exit:
+ return error;
+}
+
+void SpinelDecoder::SavePosition(void)
+{
+ mSavedIndex = mIndex;
+ mSavedEnd = mEnd;
+ mSavedNumOpenStructs = mNumOpenStructs;
+}
+
+otError SpinelDecoder::ResetToSaved(void)
+{
+ otError error = OT_ERROR_NONE;
+
+ VerifyOrExit(IsSavedPositionValid(), error = OT_ERROR_INVALID_STATE);
+
+ mIndex = mSavedIndex;
+ mEnd = mSavedEnd;
+ mNumOpenStructs = mSavedNumOpenStructs;
+
+exit:
+ return error;
+}
+
+} // namespace Ncp
+} // namespace ot
diff --git a/src/ncp/spinel_decoder.hpp b/src/ncp/spinel_decoder.hpp
new file mode 100644
index 000000000..e7a55fedc
--- /dev/null
+++ b/src/ncp/spinel_decoder.hpp
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2017, 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 the definitions of a spinel decoder.
+ */
+
+#ifndef SPINEL_DECODER_HPP_
+#define SPINEL_DECODER_HPP_
+
+#include
+
+#include
+#include
+
+#include "openthread-core-config.h"
+#include "ncp/spinel.h"
+
+namespace ot {
+namespace Ncp {
+
+/**
+ * This class defines a spinel decoder.
+ *
+ */
+class SpinelDecoder
+{
+public:
+
+ /**
+ * This constructor initializes a `SpinelDecoder` object
+ *
+ */
+ SpinelDecoder(void);
+
+ /**
+ * This method initializes the decoder to start decoding a new given spinel encoded frame.
+ *
+ * It sets the read position to beginning of the frame and also erases/voids any saved positions (see
+ * `SavePosition()` and `ResetToSaved()` methods).
+ *
+ * @param[in] aFrame Pointer to the buffer containing the frame to be decoded.
+ * @param[in] aLength Length (number of bytes) of the frame.
+ *
+ */
+ void Init(const uint8_t *aFrame, uint16_t aLength);
+
+ /**
+ * This method returns a pointer to the frame.
+ *
+ * @returns A pointer to buffer containing current frame being decoded.
+ *
+ */
+ const uint8_t *GetFrame(void) const { return mFrame; }
+
+ /**
+ * This method returns the total length of current frame being decoded.
+ *
+ * @returns The length of current frame being decoded.
+ *
+ */
+ uint16_t GetLength(void) const { return mLength; }
+
+ /**
+ * This method returns the number of bytes that are already read/decoded from the frame.
+ *
+ * @returns The number of bytes already read from frame.
+ *
+ */
+ uint16_t GetReadLength(void) const { return mIndex; }
+
+ /**
+ * This method returns the number of remaining (not yet read/decoded) bytes in the frame.
+ *
+ * @returns The number of remaining unread bytes in the frame.
+ *
+ */
+ uint16_t GetRemainingLength(void) const { return mLength - mIndex; }
+
+ /**
+ * This method indicates whether or not all the bytes in the frame are read.
+ *
+ * @returns TRUE if all the bytes in the buffer are read, FALSE otherwise.
+ *
+ */
+ bool IsAllRead(void) const { return (mIndex == mLength); }
+
+ /**
+ * This method resets the read position to beginning of frame. It will also void/erase any previously saved
+ * position using `SavePosition()` method.
+ *
+ */
+ void Reset(void);
+
+ /**
+ * This method decodes and reads a boolean value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aBool Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadBool(bool &aBool);
+
+ /**
+ * This method decodes and reads an `int8_t` value form the frame.
+ *
+ * On success, the read position get updated.
+ *
+ * @param[out] aInt8 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadInt8(int8_t &aInt8);
+
+ /**
+ * This method decodes and reads an `uint8_t` value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aUint8 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadUint8(uint8_t &aUint8);
+
+ /**
+ * This method decodes and reads an `int16_t` value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aInt16 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadInt16(int16_t &aInt16);
+
+ /**
+ * This method decodes and reads an `uint16_t` value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aUint16 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadUint16(uint16_t &aUint16);
+
+ /**
+ * This method decodes and reads an `int32_t` value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aInt32 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadInt32(int32_t &aInt32);
+
+ /**
+ * This method decodes and reads an `uint32_t` value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aUint32 Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadUint32(uint32_t &aUint32);
+
+ /**
+ * This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aUint Reference to variable to output the read value.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadUintPacked(unsigned int &aUint);
+
+ /**
+ * This method decodes and reads an IPv6 address form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`).
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr) {
+ return ReadItem(reinterpret_cast(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
+ }
+
+ /**
+ * This method decodes and reads an IPv6 address form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `otIp6Address`).
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr) {
+ return ReadItem(reinterpret_cast(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
+ }
+
+ /**
+ * This method decodes and reads an IPv6 address form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aIp6AddrBufPtr Reference to a buffer pointer to output the value.
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr) {
+ return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t));
+ }
+
+ /**
+ * This method decodes and reads an IPv6 address form the frame.
+ *
+ * On success, the read position gets updated and the IP address is copied into the given output variable.
+ *
+ * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as spinel_ipv6addr_t).
+ * On success, the address is copied into the output variable.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr);
+
+ /**
+ * This method decodes and reads an IPv6 address form the frame.
+ *
+ * On success, the read position gets updated and the IP address is copied into the given output variable.
+ *
+ * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as otIp6Address).
+ * On success, the address is copied into the output variable.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadIp6Address(otIp6Address &aIp6Addr);
+
+ /**
+ * This method decodes and reads an EUI64 value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`).
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui64(const spinel_eui64_t *&aEui64Ptr) {
+ return ReadItem(reinterpret_cast(&aEui64Ptr), sizeof(spinel_eui64_t));
+ }
+
+ /**
+ * This method decodes and reads an EUI64 value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `otExtAddress`).
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui64(const otExtAddress *&aEui64Ptr) {
+ return ReadItem(reinterpret_cast(&aEui64Ptr), sizeof(spinel_eui64_t));
+ }
+
+ /**
+ * This method decodes and reads an EUI64 value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aEui64BufPtr Reference to a buffer pointer to output the value.
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui64(const uint8_t *&aEui64BufPtr) {
+ return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t));
+ }
+
+ /**
+ * This method decodes and reads an EUI64 value form the frame.
+ *
+ * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
+ *
+ * @param[out] aEui64 Reference to EUI64 variable to output the value (as spinel_eui64_t).
+ * On success, the address is copied into the output variable.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui64(spinel_eui64_t &aEui64);
+
+ /**
+ * This method decodes and reads an EUI64 value form the frame.
+ *
+ * On success, the read position gets updated and the EUI64 value is copied into the given output variable.
+ *
+ * @param[out] aEui64 Reference to EUI64 variable to output the value (as otExtAddress).
+ * On success, the address is copied into the output variable.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui64(otExtAddress &aEui64);
+
+ /**
+ * This method decodes and reads an EUI48 value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aEui48Ptr Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`).
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui48(const spinel_eui48_t *&aEui48Ptr) {
+ return ReadItem(reinterpret_cast(&aEui48Ptr), sizeof(spinel_eui48_t));
+ }
+
+ /**
+ * This method decodes and reads an EUI48 value form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aEui48BufPtr Reference to a buffer pointer to output the value.
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui48(const uint8_t *&aEui48BufPtr) {
+ return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t));
+ }
+
+ /**
+ * This method decodes and reads an EUI48 value form the frame.
+ *
+ * On success, the read position gets updated and the EUI48 value is copied into the given output variable.
+ *
+ * @param[out] aEui48 Reference to EUI48 variable to output the value (as spinel_eui48_t).
+ * On success, value is copied into the output variable.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadEui48(spinel_eui48_t &aEui48);
+
+ /**
+ * This method decodes and reads a UTF8 string form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aUt8 Reference to a `char` pointer to output the string.
+ * On success, the pointer variable is updated.
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadUtf8(const char *&aUt8);
+
+ /**
+ * This method decodes and reads a data blob (sequence of bytes) form the frame.
+ *
+ * On success, the read position gets updated.
+ *
+ * @param[out] aData Reference to pointer variable to output the data.
+ * On success, the pointer variable is updated.
+ * @param[out] aDataLength Reference to variable to out the data length (number of bytes).
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadData(const uint8_t *&aData, uint16_t &aDataLen);
+
+ /**
+ * This method decodes and reads a data blob (sequence of bytes) with data length.
+ *
+ * The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the
+ * length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN`
+ * type.
+ *
+ * @param[out] aData Reference to pointer variable to output the data.
+ * On success, the pointer variable is updated.
+ * @param[out] aDataLength Reference to variable to out the data length (number of bytes).
+ *
+ * @retval OT_ERROR_NONE Successfully read the value.
+ * @retval OT_ERROR_PARSE Failed to parse/decode the value.
+ *
+ */
+ otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen);
+
+ /**
+ * This method opens a struct in the frame.
+ *
+ * After a successful call to this method, all the subsequent `Read()` methods decode and read the
+ * field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can
+ * be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time.
+ *
+ * @retval OT_ERROR_NONE Successfully opened a struct.
+ * @retval OT_ERROR_PARSE Failed to parse/open a struct.
+ * @retval OT_ERROR_INVALID_STATE Already at the maximum number of nested open structures.
+ *
+ */
+ otError OpenStruct(void);
+
+ /**
+ * This method closes the most recently opened struct (using `OpenStruct()`) in the frame.
+ *
+ * On success, the read position is moved to end of the struct skipping any unread bytes within the struct.
+ *
+ * @retval OT_ERROR_NONE Successfully closed the struct.
+ * @retval OT_ERROR_INVALID_STATE There is no current open struct to close.
+ *
+ */
+ otError CloseStruct(void);
+
+ /**
+ * This method returns the number of remaining/unread bytes in the current inner-most open structure.
+ *
+ * If there is no currently open structure the number of remaining bytes in whole frame is returned instead.
+ *
+ * @returns The number of remaining unread bytes in the inner-most open structure.
+ *
+ */
+ uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; }
+
+ /**
+ * This method indicates whether or not all the bytes in inner-most open structure are read.
+ *
+ * If there is no currently open structure, the whole frame is considered instead.
+ *
+ * @returns TRUE if all the bytes are read, FALSE otherwise.
+ *
+ */
+ bool IsAllReadInStruct(void) const { return (mIndex == mEnd); }
+
+ /**
+ * This method saves the current read position in the frame.
+
+ * A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be
+ * used to to move the read position back (using `ResetToSaved()`) and re-read the same content.
+ *
+ * Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is
+ * closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to
+ * middle an already fully decoded/read and closed struct.
+ *
+ */
+ void SavePosition(void);
+
+ /**
+ * This method resets/moves the read position to a previously saved position.
+ *
+ * The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open
+ * structure will be the same as when position was saved.
+ *
+ * @retval OT_ERROR_NONE Successfully reset the read position.
+ * @retval OT_ERROR_INVALID_STATE The saved position is not valid (there is no saved position or the saved
+ * position was voided since its enclosing struct was closed).
+ *
+ */
+ otError ResetToSaved(void);
+
+private:
+ otError ReadItem(const uint8_t **aPtr, size_t aSize);
+ void ClearSavedPosition(void) { mSavedIndex = mLength; }
+ bool IsSavedPositionValid(void) const { return (mSavedIndex < mLength); }
+
+ enum
+ {
+ kMaxNestedStructs = 4, ///< Maximum number of nested structs.
+ };
+
+ const uint8_t *mFrame; // Frame buffer
+ uint16_t mLength; // Total length of the buffer.
+ uint16_t mIndex; // Current read index.
+ uint16_t mEnd; // Current end index (end of struct if in a struct, or end of buffer otherwise).
+ uint8_t mNumOpenStructs; // Number of open structs.
+
+ uint8_t mSavedNumOpenStructs; // Number of open structs when read position was saved.
+ uint16_t mSavedIndex; // Read index when position was saved.
+ uint16_t mSavedEnd; // End index when position was saved.
+
+ uint16_t mPrevEnd[kMaxNestedStructs];
+};
+
+} // namespace Ncp
+} // namespace ot
+
+#endif // SPINEL_DECODER_HPP_
diff --git a/src/ncp/spinel_encoder.hpp b/src/ncp/spinel_encoder.hpp
index c197e0532..fe40f80e1 100644
--- a/src/ncp/spinel_encoder.hpp
+++ b/src/ncp/spinel_encoder.hpp
@@ -571,7 +571,7 @@ public:
* This method opens a struct in the current input frame.
*
* After a successful call to this method, all the subsequent `Write()` methods add the field/value to
- * the current open struct until the struct is closed using `CloseStruct()` method. Structs can be nested. Up to
+ * the current open struct until the struct is closed using `CloseStruct()` method. Structures can be nested. Up to
* `kMaxNestedStructs` nested structs can be opened at the same time.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
@@ -580,7 +580,7 @@ public:
* If no buffer space is available, this method will discard and clear the frame and return error status
* `OT_ERROR_NO_BUFS`.
*
- * @retval OT_ERROR_NONE Successfully added the message to the frame.
+ * @retval OT_ERROR_NONE Successfully opened the struct.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if we reached
* the maximum number of nested open structures.
@@ -597,7 +597,7 @@ public:
* If no buffer space is available, this method will discard and clear the frame and return error status
* `OT_ERROR_NO_BUFS`.
*
- * @retval OT_ERROR_NONE Successfully added the message to the frame.
+ * @retval OT_ERROR_NONE Successfully closed the most recently opened struct.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if there is no
* open struct to close
@@ -623,7 +623,7 @@ public:
* The saved position must belong to the same input frame saved earlier with `SavePosition()`. This method cannot
* be used if the input frame has an added `otMessage`.
*
- * @retval OT_ERROR_NONE Successfully reset the write position of current input frame..
+ * @retval OT_ERROR_NONE Successfully reset the write position of current input frame.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_ARGS The saved position is not valid (does not belong to same input frame), or
* the input frame has an added `otMessage`.
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index bc17680c5..43c804f23 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -97,6 +97,7 @@ check_PROGRAMS = \
test-strlcat \
test-strlcpy \
test-strnlen \
+ test-spinel-decoder \
test-spinel-encoder \
test-timer \
test-toolchain \
@@ -187,6 +188,9 @@ test_strlcpy_SOURCES = test_strlcpy.c
test_strnlen_LDADD = $(COMMON_LDADD)
test_strnlen_SOURCES = test_strnlen.c
+test_spinel_decoder_LDADD = $(COMMON_LDADD)
+test_spinel_decoder_SOURCES = test_platform.cpp test_spinel_decoder.cpp
+
test_spinel_encoder_LDADD = $(COMMON_LDADD)
test_spinel_encoder_SOURCES = test_platform.cpp test_spinel_encoder.cpp
diff --git a/tests/unit/test_spinel_decoder.cpp b/tests/unit/test_spinel_decoder.cpp
new file mode 100644
index 000000000..056e85269
--- /dev/null
+++ b/tests/unit/test_spinel_decoder.cpp
@@ -0,0 +1,765 @@
+/*
+ * Copyright (c) 2017, 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
+
+#include
+
+#include "openthread-instance.h"
+#include "common/code_utils.hpp"
+#include "ncp/spinel_decoder.hpp"
+
+#include "test_util.h"
+
+namespace ot {
+namespace Ncp {
+
+enum
+{
+ kTestBufferSize = 800,
+};
+
+
+// Dump the buffer content to screen.
+void DumpBuffer(const char *aTextMessage, uint8_t *aBuffer, uint16_t aBufferLength)
+{
+ enum
+ {
+ kBytesPerLine = 32, // Number of bytes per line.
+ };
+
+ char charBuff[kBytesPerLine + 1];
+ uint16_t counter;
+ uint8_t byte;
+
+ printf("\n%s - len = %u\n ", aTextMessage, aBufferLength);
+
+ counter = 0;
+
+ while (aBufferLength--)
+ {
+ byte = *aBuffer++;
+ printf("%02X ", byte);
+ charBuff[counter] = isprint(byte) ? static_cast(byte) : '.';
+ counter++;
+
+ if (counter == kBytesPerLine)
+ {
+ charBuff[counter] = 0;
+ printf(" %s\n ", charBuff);
+ counter = 0;
+ }
+ }
+
+ charBuff[counter] = 0;
+
+ while (counter++ < kBytesPerLine)
+ {
+ printf(" ");
+ }
+
+ printf(" %s\n", charBuff);
+}
+
+void TestSpinelDecoder(void)
+{
+ uint8_t buffer[kTestBufferSize];
+ SpinelDecoder decoder;
+
+ spinel_ssize_t frameLen;
+
+ const bool kBool_1 = true;
+ const bool kBool_2 = false;
+ const uint8_t kUint8 = 0x42;
+ const int8_t kInt8 = -73;
+ const uint16_t kUint16 = 0xabcd;
+ const int16_t kInt16 = -567;
+ const uint32_t kUint32 = 0xdeadbeef;
+ const int32_t kInt32 = -123455678L;
+
+
+ const unsigned int kUint_1 = 9;
+ const unsigned int kUint_2 = 0xa3;
+ const unsigned int kUint_3 = 0x8765;
+ const unsigned int kUint_4 = SPINEL_MAX_UINT_PACKED - 1;
+
+
+ const spinel_ipv6addr_t kIp6Addr =
+ {
+ { 0x6B, 0x41, 0x65, 0x73, 0x42, 0x68, 0x61, 0x76, 0x54, 0x61, 0x72, 0x7A, 0x49, 0x69, 0x61, 0x4E }
+ };
+
+ const spinel_eui48_t kEui48 =
+ {
+ { 4, 8, 15, 16, 23, 42 } // "Lost" EUI48!
+ };
+
+ const spinel_eui64_t kEui64 =
+ {
+ { 2, 3, 5, 7, 11, 13, 17, 19 }, // "Prime" EUI64!
+ };
+
+ const char kString_1[] = "OpenThread";
+ const char kString_2[] = "";
+
+ const uint16_t kData[] = { 10, 20, 3, 15, 1000, 60, 16 }; // ... then comes 17,18,19,20 :)
+
+ bool b_1, b_2;
+ uint8_t u8;
+ int8_t i8;
+ uint16_t u16;
+ int16_t i16;
+ uint32_t u32;
+ int32_t i32;
+ unsigned int u_1, u_2, u_3, u_4;
+ const spinel_ipv6addr_t *ip6Addr;
+ const spinel_eui48_t *eui48;
+ const spinel_eui64_t *eui64;
+ const char *utf_1;
+ const char *utf_2;
+ const uint8_t *dataPtr_1;
+ const uint8_t *dataPtr_2;
+ uint16_t dataLen_1;
+ uint16_t dataLen_2;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 1: Decoding simple types");
+
+ frameLen = spinel_datatype_pack(
+ buffer,
+ sizeof(buffer),
+ (
+ SPINEL_DATATYPE_BOOL_S
+ SPINEL_DATATYPE_BOOL_S
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_UINT16_S
+ SPINEL_DATATYPE_INT16_S
+ SPINEL_DATATYPE_UINT32_S
+ SPINEL_DATATYPE_INT32_S
+ SPINEL_DATATYPE_UINT_PACKED_S
+ SPINEL_DATATYPE_UINT_PACKED_S
+ SPINEL_DATATYPE_UINT_PACKED_S
+ SPINEL_DATATYPE_UINT_PACKED_S
+ SPINEL_DATATYPE_IPv6ADDR_S
+ SPINEL_DATATYPE_EUI48_S
+ SPINEL_DATATYPE_EUI64_S
+ SPINEL_DATATYPE_UTF8_S
+ SPINEL_DATATYPE_UTF8_S
+ SPINEL_DATATYPE_DATA_WLEN_S
+ SPINEL_DATATYPE_DATA_S
+ ),
+ kBool_1,
+ kBool_2,
+ kUint8,
+ kInt8,
+ kUint16,
+ kInt16,
+ kUint32,
+ kInt32,
+ kUint_1,
+ kUint_2,
+ kUint_3,
+ kUint_4,
+ &kIp6Addr,
+ &kEui48,
+ &kEui64,
+ kString_1,
+ kString_2,
+ kData, sizeof(kData),
+ kData, sizeof(kData)
+ );
+
+ DumpBuffer("Packed Spinel Frame", buffer, static_cast(frameLen));
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed.");
+ VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed.");
+
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadBool(b_2), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadInt8(i8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ SuccessOrQuit(decoder.ReadInt32(i32), "ReadUint32() failed.");
+
+ // Check the state
+ VerifyOrQuit(decoder.GetReadLength() != 0, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == frameLen - decoder.GetReadLength(),
+ "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed.");
+
+ SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.ReadEui64(eui64), "ReadEui64() failed.");
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.ReadUtf8(utf_2), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1), "ReadDataWithLen() failed.");
+ SuccessOrQuit(decoder.ReadData(dataPtr_2, dataLen_2), "ReadData() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(b_2 == kBool_2, "ReadBool() parse failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(i8 == kInt8, "ReadUint8() parse failed.");
+ VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
+ VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
+ VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+ VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "ReadEui64() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+ VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0, "ReadUtf8() parse failed.");
+ VerifyOrQuit(dataLen_1 == sizeof(kData), "ReadData() parse failed.");
+ VerifyOrQuit(memcmp(dataPtr_1, &kData, sizeof(kData)) == 0, "ReadData() parse failed.");
+ VerifyOrQuit(dataLen_2 == sizeof(kData), "ReadData() parse failed.");
+ VerifyOrQuit(memcmp(dataPtr_2, &kData, sizeof(kData)) == 0, "ReadData() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 2: Test Reset(), SavePosition(), ResetToSaved()");
+
+ // `ResetToSaved()` should fail if there is no saved position
+ VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail");
+
+ decoder.Reset();
+
+ VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed.");
+ VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed.");
+ VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed.");
+
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadBool(b_2), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadInt8(i8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ SuccessOrQuit(decoder.ReadInt32(i32), "ReadUint32() failed.");
+
+ // `ResetToSaved()` should fail if there is no saved position
+ VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail");
+
+ // Save position
+ decoder.SavePosition();
+
+ SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(b_2 == kBool_2, "ReadBool() parse failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(i8 == kInt8, "ReadUint8() parse failed.");
+ VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
+ VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
+ VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+
+ SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed");
+
+ SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+
+ // Go back to save position again.
+ SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed");
+
+ SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(u_4 == kUint_4, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+
+ // Ensure saved position is cleared when decoder is reset or re-initialized.
+
+ decoder.Reset();
+
+ // `ResetToSaved()` should fail if there is no saved position
+ VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail");
+
+ decoder.SavePosition();
+ SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed");
+
+ decoder.Init(buffer, static_cast(frameLen));
+ VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 3: Test decoding a single simple struct.");
+
+ frameLen = spinel_datatype_pack(
+ buffer,
+ sizeof(buffer),
+ (
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_UINT32_S
+ SPINEL_DATATYPE_EUI48_S
+ SPINEL_DATATYPE_UINT_PACKED_S
+ )
+ SPINEL_DATATYPE_INT16_S
+
+ ),
+ kUint8,
+ kUint32,
+ &kEui48,
+ kUint_3,
+ kInt16
+ );
+
+ DumpBuffer("Packed Spinel Frame (single struct)", buffer, static_cast(frameLen));
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 4: Test partial struct read");
+
+ // Re-use same frame as the previous test.
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ // Skip the remaining fields in the struct
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
+
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
+
+ printf(" -- PASS\n");
+
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 5: Test `GetRemainingLengthInStruct()` and `IsAllReadInStruct`() in and out of an struct");
+
+ // Re-use same frame as the previous test.
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ VerifyOrQuit(decoder.GetFrame() == &buffer[0], "GetFrame() failed.");
+ VerifyOrQuit(decoder.GetLength() == frameLen, "GetLength() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == 0, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == frameLen, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed.");
+
+ // When not in an struct, `etRemainingLengthInStruct()` should consider the whole frame.
+ VerifyOrQuit(decoder.GetRemainingLengthInStruct() == frameLen, "GetRemLengthInStruct() failed.");
+ VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed.");
+
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed.");
+
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
+
+ VerifyOrQuit(decoder.IsAllReadInStruct() == true, "IsAllReadInStruct() failed.");
+ VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0, "GetRemLengthInStruct() failed.");
+
+ // Try reading beyond end of the struct and ensure it fails.
+ VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE, "ReadUint8() did not fail.");
+
+ // `ReadData()` at end of struct should still succeed but return zero as the data length.
+ SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1), "ReadData() failed.");
+ VerifyOrQuit(dataLen_1 == 0, "ReadData() parse value failed.");
+
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+
+ VerifyOrQuit(decoder.IsAllReadInStruct() == false, "IsAllReadInStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0, "GetRemLengthInStruct() failed.");
+ VerifyOrQuit(decoder.IsAllReadInStruct() == true, "IsAllReadInStruct() failed.");
+
+ // `ReadData()` at end of frame should still succeed but return zero as the data length.
+ SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1), "ReadData() failed.");
+ VerifyOrQuit(dataLen_1 == 0, "ReadData() parse value failed.");
+
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 6: Test multiple nested structs");
+
+ frameLen = spinel_datatype_pack(
+ buffer,
+ sizeof(buffer),
+ (
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_UTF8_S
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_BOOL_S
+ SPINEL_DATATYPE_IPv6ADDR_S
+ )
+ SPINEL_DATATYPE_UINT16_S
+ )
+ SPINEL_DATATYPE_EUI48_S
+ SPINEL_DATATYPE_STRUCT_S(
+ SPINEL_DATATYPE_UINT32_S
+ )
+ SPINEL_DATATYPE_INT32_S
+ ),
+ kUint8,
+ kString_1,
+ kBool_1,
+ &kIp6Addr,
+ kUint16,
+ &kEui48,
+ kUint32,
+ kInt32
+ );
+
+ DumpBuffer("Packed Spinel Frame (multiple struct)", buffer, static_cast(frameLen));
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 7: Test `SavePosition()`, `ResetToSaved()` for nested structs");
+
+ // Re-use same frame as the previous test.
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+
+ decoder.SavePosition();
+
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ }
+
+ // Verify the read content so far.
+
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+
+ // Do not close the inner struct and jump to previously saved position and re-read the content.
+
+ SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed.");
+
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 8: Test saving position at start of an open struct");
+
+ // Re-use same frame as the previous test.
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ // Save position at start of the struct
+ decoder.SavePosition();
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+
+ // Verify the read content so far.
+
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+
+ // Do not close the struct and jump to the previously saved position and re-read the content.
+
+ SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed.");
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadEui48(eui48), "ReadEui48() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadInt32(i32), "WriteUint32() failed.");
+
+ VerifyOrQuit(decoder.GetReadLength() == frameLen, "GetReadLength() failed.");
+ VerifyOrQuit(decoder.GetRemainingLength() == 0, "GetRemainingLength() failed.");
+ VerifyOrQuit(decoder.IsAllRead() == true, "IsAllRead() failed.");
+
+ VerifyOrQuit(b_1 == kBool_1, "ReadBool() parse failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
+ VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
+ VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
+ VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "ReadIp6Address() parse failed.");
+ VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "ReadEui48() parse failed.");
+ VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "ReadUtf8() parse failed.");
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 9: Test `ResetToSaved()` failure case (jumping back to a saved position closed struct).");
+
+ // Re-use same frame as the previous test.
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUtf8(utf_1), "ReadUtf8() failed.");
+ SuccessOrQuit(decoder.OpenStruct(), "OpenStruct() failed.");
+ {
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadBool() failed.");
+
+ decoder.SavePosition();
+
+ SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
+
+ }
+ SuccessOrQuit(decoder.CloseStruct(), "CloseStruct() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+
+ // `ResetToSaved()` should fail sicne the enclosing struct for the saved position is closed.
+ VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE, "ResetToSaved() did not fail.");
+ }
+
+ printf(" -- PASS\n");
+
+ printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
+ printf("\nTest 10: Testing error cases and failures. (e.g., wrong struct length).");
+
+ frameLen = spinel_datatype_pack(
+ buffer,
+ sizeof(buffer),
+ (
+ SPINEL_DATATYPE_UINT8_S
+ SPINEL_DATATYPE_UINT16_S // Treat this as struct length
+ SPINEL_DATATYPE_BOOL_S
+ ),
+ kUint8,
+ 10,
+ kBool_1
+ );
+
+ DumpBuffer("Packed Spinel Frame (incorrect format)", buffer, static_cast(frameLen));
+
+ decoder.Init(buffer, static_cast(frameLen));
+
+ decoder.SavePosition();
+
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+
+ // `OpenStruct()` should fail, since it expects a length 10 but there are not enough
+ // bytes in the frame.
+ VerifyOrQuit(decoder.OpenStruct() == OT_ERROR_PARSE, "OpenStruct() did not fail.");
+
+ decoder.ResetToSaved();
+
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ VerifyOrQuit(u8 == kUint8, "ReadUint8() parse failed.");
+ VerifyOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1) == OT_ERROR_PARSE,
+ "ReadDataWithLen() did not fail.");
+
+ decoder.ResetToSaved();
+ SuccessOrQuit(decoder.ReadUint8(u8), "ReadUint8() failed.");
+ SuccessOrQuit(decoder.ReadUint16(u16), "ReadUint16() failed.");
+ SuccessOrQuit(decoder.ReadBool(b_1), "ReadUint16() failed.");
+
+ // Try reading beyond end of frame.
+ VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE, "ReadUint8() did not fail");
+
+ printf(" -- PASS\n");
+}
+
+} // namespace Ncp
+} // namespace ot
+
+#ifdef ENABLE_TEST_MAIN
+int main(void)
+{
+ ot::Ncp::TestSpinelDecoder();
+ printf("\nAll tests passed.\n");
+ return 0;
+}
+#endif