mirror of
https://github.com/espressif/openthread.git
synced 2026-07-29 15:17:47 +00:00
[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:
committed by
Jonathan Hui
parent
c7b02326b5
commit
92ba27a1fa
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -237,7 +237,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otThreadSetSteeringData(otInstance *aInstance, otExtAddress *aExtAddress)
|
||||
otError otThreadSetSteeringData(otInstance *aInstance, const otExtAddress *aExtAddress)
|
||||
{
|
||||
otError error;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+91
-108
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+55
-184
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user