[ncp] adding SpinelDecoder class and updating NCP implementation (#2258)

This commit adds a new class `SpinelDecoder` which provides a set of
methods/APIs to help in decoding/reading content using Spinel formating
(it is practically a C++ wrapper over Spinel C APIs). A unit test
`test_spinel_decoder` is also added in this commit.

This commit also updates the `NcpBase` implementation to adopt the new
`SpinelDecoder` class mainly in set, insert, and remove handlers
for different Spinel properties. The new class provides similar advantage
as `SpinelEncoder` by simplifying the handler implementations and adding
type-check safety when parsing/reading the spinel frame.
This commit is contained in:
Abtin Keshavarzian
2017-10-13 09:18:37 -07:00
committed by Jonathan Hui
parent c7b02326b5
commit 92ba27a1fa
22 changed files with 2565 additions and 1982 deletions
@@ -66,6 +66,7 @@
<ClCompile Include="..\..\src\ncp\ncp_buffer.cpp" />
<ClCompile Include="..\..\src\ncp\ncp_spi.cpp" />
<ClCompile Include="..\..\src\ncp\spinel.c" />
<ClCompile Include="..\..\src\ncp\spinel_decoder.cpp" />
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp" />
</ItemGroup>
<ItemGroup>
@@ -74,6 +75,7 @@
<ClInclude Include="..\..\src\ncp\ncp_buffer.hpp" />
<ClInclude Include="..\..\src\ncp\ncp_spi.hpp" />
<ClInclude Include="..\..\src\ncp\spinel.h" />
<ClInclude Include="..\..\src\ncp\spinel_decoder.hpp" />
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
@@ -36,6 +36,9 @@
<ClCompile Include="..\..\src\ncp\spinel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_decoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -59,6 +62,9 @@
<ClInclude Include="..\..\src\ncp\spinel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_decoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -67,6 +67,7 @@
<ClCompile Include="..\..\src\ncp\ncp_buffer.cpp" />
<ClCompile Include="..\..\src\ncp\ncp_uart.cpp" />
<ClCompile Include="..\..\src\ncp\spinel.c" />
<ClCompile Include="..\..\src\ncp\spinel_decoder.cpp" />
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp" />
</ItemGroup>
<ItemGroup>
@@ -76,6 +77,7 @@
<ClInclude Include="..\..\src\ncp\ncp_buffer.hpp" />
<ClInclude Include="..\..\src\ncp\ncp_uart.hpp" />
<ClInclude Include="..\..\src\ncp\spinel.h" />
<ClInclude Include="..\..\src\ncp\spinel_decoder.hpp" />
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
@@ -42,6 +42,9 @@
<ClCompile Include="..\..\src\ncp\spinel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_decoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -65,6 +68,9 @@
<ClInclude Include="..\..\src\ncp\spinel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_decoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -237,7 +237,7 @@ exit:
return error;
}
otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress)
otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress)
{
otError error;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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];
+1 -1
View File
@@ -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];
+1 -1
View File
@@ -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
/**
+1 -1
View File
@@ -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; }
+2
View File
@@ -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 \
+375 -546
View File
File diff suppressed because it is too large Load Diff
+91 -108
View File
@@ -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;
+71 -278
View File
@@ -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<uint16_t>(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)
+241 -855
View File
File diff suppressed because it is too large Load Diff
+55 -184
View File
@@ -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<uint8_t>(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;
}
+369
View File
@@ -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 <openthread/config.h>
#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<int8_t>(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<uint16_t>(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<int16_t>(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<uint32_t>(mFrame[mIndex + 0]) << 0) |
(static_cast<uint32_t>(mFrame[mIndex + 1]) << 8) |
(static_cast<uint32_t>(mFrame[mIndex + 2]) << 16) |
(static_cast<uint32_t>(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<int32_t>(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<const char *>(&mFrame[mIndex]), mEnd - mIndex);
VerifyOrExit(len < static_cast<uint16_t>(mEnd - mIndex), error = OT_ERROR_PARSE);
aUtf8 = reinterpret_cast<const char *>(&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
+565
View File
@@ -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 <openthread/config.h>
#include <openthread/ncp.h>
#include <openthread/types.h>
#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<const uint8_t **>(&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<const uint8_t **>(&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<const uint8_t **>(&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<const uint8_t **>(&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<const uint8_t **>(&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<SomeType>()` 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_
+4 -4
View File
@@ -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<SomeType>()` 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`.
+4
View File
@@ -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
+765
View File
@@ -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 <ctype.h>
#include <openthread/openthread.h>
#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<char>(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<uint16_t>(frameLen));
decoder.Init(buffer, static_cast<uint16_t>(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<uint16_t>(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<uint16_t>(frameLen));
decoder.Init(buffer, static_cast<uint16_t>(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<uint16_t>(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<uint16_t>(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<uint16_t>(frameLen));
decoder.Init(buffer, static_cast<uint16_t>(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<uint16_t>(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<uint16_t>(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<uint16_t>(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<uint16_t>(frameLen));
decoder.Init(buffer, static_cast<uint16_t>(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