[ncp] adding SpinelEncoder class and updating NCP implementation (#2221)

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

This commit also updates the `NcpBase` implementation to adopt the new
`SpinelEncoder` class mainly in implementation of get, insert, and
remove  handlers for different Spinel properties. The new class
provides the following advantages: (a) it simplifies the
implementation of handers, particularly get-handlers for properties
with a single type output; (b) it adds type-checking and type-safety
when frames are being created, e.g., if the Spinel format expects a
`SPINEL_DATATYPE_UINT8` but a `uint16_t` value is provided, the new
model will cause a compile-time error (few instances in code where the
types did not match are fixed in this commit).
This commit is contained in:
Abtin Keshavarzian
2017-09-27 23:04:53 -07:00
committed by Jonathan Hui
parent 7dbc20d2dd
commit 192df6cf00
16 changed files with 2576 additions and 2604 deletions
@@ -66,6 +66,7 @@
<ClCompile Include="..\..\src\ncp\ncp_buffer.cpp" />
<ClCompile Include="..\..\src\ncp\ncp_spi.cpp" />
<ClCompile Include="..\..\src\ncp\spinel.c" />
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ncp\changed_props_set.hpp" />
@@ -73,6 +74,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_encoder.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -36,6 +36,9 @@
<ClCompile Include="..\..\src\ncp\spinel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\ncp_spi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -56,5 +59,8 @@
<ClInclude Include="..\..\src\ncp\spinel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -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_encoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ncp\changed_props_set.hpp" />
@@ -75,6 +76,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_encoder.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -42,6 +42,9 @@
<ClCompile Include="..\..\src\ncp\spinel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ncp\spinel_encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ncp\changed_props_set.hpp">
@@ -62,5 +65,8 @@
<ClInclude Include="..\..\src\ncp\spinel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ncp\spinel_encoder.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+2
View File
@@ -71,6 +71,8 @@ COMMON_SOURCES = \
ncp_buffer.hpp \
spinel.c \
spinel.h \
spinel_encoder.hpp \
spinel_encoder.cpp \
spinel_platform.h \
ncp_spi.cpp \
ncp_spi.hpp \
+199 -512
View File
File diff suppressed because it is too large Load Diff
+55 -83
View File
@@ -47,6 +47,7 @@
#include "changed_props_set.hpp"
#include "common/tasklet.hpp"
#include "ncp/ncp_buffer.hpp"
#include "ncp/spinel_encoder.hpp"
#include "spinel.h"
@@ -63,10 +64,7 @@ namespace Ncp {
#define NCP_GET_PROP_HANDLER(name) \
otError GetPropertyHandler_##name( \
uint8_t aHeader, \
spinel_prop_key_t aKey \
)
otError GetPropertyHandler_##name(void)
#define NCP_SET_PROP_HANDLER(name) \
otError SetPropertyHandler_##name( \
@@ -78,16 +76,12 @@ namespace Ncp {
#define NCP_INSERT_PROP_HANDLER(name) \
otError InsertPropertyHandler_##name( \
uint8_t aHeader, \
spinel_prop_key_t aKey, \
const uint8_t *aValuePtr, \
uint16_t aValueLen \
)
#define NCP_REMOVE_PROP_HANDLER(name) \
otError RemovePropertyHandler_##name( \
uint8_t aHeader, \
spinel_prop_key_t aKey, \
const uint8_t *aValuePtr, \
uint16_t aValueLen \
)
@@ -175,59 +169,6 @@ public:
#endif
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
protected:
/**
* This method is called to start a new outbound frame.
*
* param[in] aHeader The spinel header byte
*
* @retval OT_ERROR_NONE Successfully started a new frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame.
*
*/
otError OutboundFrameBegin(uint8_t aHeader);
/**
* This method adds data to the current outbound frame being written.
*
* If no buffer space is available, this method should discard and clear the frame before returning an error status.
*
* @param[in] aDataBuffer A pointer to data buffer.
* @param[in] aDataBufferLength The length of the data buffer.
*
* @retval OT_ERROR_NONE Successfully added new data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data.
*
*/
otError OutboundFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength);
/**
* This method adds a message to the current outbound frame being written.
*
* If no buffer space is available, this method should discard and clear the frame before returning an error status.
* In case of success, the passed-in message @aMessage should be owned by outbound buffer and should be freed
* when either the frame is successfully sent and removed or if the frame is discarded.
*
* @param[in] aMessage A reference to the message to be added to current frame.
*
* @retval OT_ERROR_NONE Successfully added the message to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message.
*
*/
otError OutboundFrameFeedMessage(otMessage *aMessage);
/**
* This method finalizes and sends the current outbound frame
*
* If no buffer space is available, this method should discard and clear the frame
* before returning an error status.
*
* @retval OT_ERROR_NONE Successfully added the message to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message.
*
*/
otError OutboundFrameEnd(void);
/**
* This method is called by the framer whenever a framing error is detected.
*/
@@ -252,7 +193,9 @@ private:
typedef otError(NcpBase::*CommandHandlerType)(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr,
uint16_t aArgLen);
typedef otError(NcpBase::*GetPropertyHandlerType)(uint8_t aHeader, spinel_prop_key_t aKey);
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);
@@ -278,24 +221,17 @@ private:
struct InsertPropertyHandlerEntry
{
spinel_prop_key_t mPropKey;
SetPropertyHandlerType mHandler;
InsertRemovePropertyHandlerType mHandler;
};
struct RemovePropertyHandlerEntry
{
spinel_prop_key_t mPropKey;
SetPropertyHandlerType mHandler;
InsertRemovePropertyHandlerType mHandler;
};
otError OutboundFrameSend(void);
NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void);
otError OutboundFrameFeedPacked(const char *aPackFormat, ...);
otError OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs);
otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen);
otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey);
@@ -311,14 +247,6 @@ private:
otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus);
otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const uint8_t *aValuePtr,
uint16_t aValueLen);
otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, otMessage *message);
otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const char *format, ...);
otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError);
static void UpdateChangedProps(Tasklet &aTasklet);
@@ -363,7 +291,7 @@ private:
static void SendDoneTask(void *aContext);
void SendDoneTask(void);
otError GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t channel_mask);
otError GetPropertyHandler_ChannelMaskHelper(uint32_t channel_mask);
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
@@ -536,9 +464,52 @@ private:
#endif
NCP_GET_PROP_HANDLER(STREAM_NET);
NCP_SET_PROP_HANDLER(STREAM_NET);
NCP_GET_PROP_HANDLER(MAC_CNTR);
NCP_GET_PROP_HANDLER(NCP_CNTR);
NCP_GET_PROP_HANDLER(IP_CNTR);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_ACK_REQ);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_ACKED);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_NO_ACK_REQ);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_DATA);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_DATA_POLL);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BEACON);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BEACON_REQ);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_OTHER);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_RETRY);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_UNICAST);
NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BROADCAST);
NCP_GET_PROP_HANDLER(CNTR_TX_ERR_CCA);
NCP_GET_PROP_HANDLER(CNTR_TX_ERR_ABORT);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DATA);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DATA_POLL);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BEACON);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BEACON_REQ);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_OTHER);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_FILT_WL);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_FILT_DA);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_UNICAST);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BROADCAST);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_EMPTY);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_UKWN_NBR);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_NVLD_SADDR);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_SECURITY);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_BAD_FCS);
NCP_GET_PROP_HANDLER(CNTR_RX_ERR_OTHER);
NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DUP);
NCP_GET_PROP_HANDLER(CNTR_TX_IP_SEC_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_TX_IP_INSEC_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_TX_IP_DROPPED);
NCP_GET_PROP_HANDLER(CNTR_RX_IP_SEC_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_RX_IP_INSEC_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_RX_IP_DROPPED);
NCP_GET_PROP_HANDLER(CNTR_TX_SPINEL_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_TOTAL);
NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_OUT_OF_ORDER_TID);
NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_ERR);
NCP_GET_PROP_HANDLER(CNTR_IP_TX_SUCCESS);
NCP_GET_PROP_HANDLER(CNTR_IP_RX_SUCCESS);
NCP_GET_PROP_HANDLER(CNTR_IP_TX_FAILURE);
NCP_GET_PROP_HANDLER(CNTR_IP_RX_FAILURE);
NCP_GET_PROP_HANDLER(MSG_BUFFER_COUNTERS);
#if OPENTHREAD_ENABLE_MAC_FILTER
NCP_GET_PROP_HANDLER(MAC_WHITELIST_ENABLED);
@@ -639,6 +610,7 @@ protected:
static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData);
otInstance *mInstance;
NcpFrameBuffer mTxFrameBuffer;
SpinelEncoder mEncoder;
bool mHostPowerStateInProgress;
private:
+100 -253
View File
@@ -56,53 +56,28 @@
namespace ot {
namespace Ncp {
otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetLocalLeaderWeight(mInstance)
);
return mEncoder.WriteUint8(otThreadGetLocalLeaderWeight(mInstance));
}
otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetLeaderWeight(mInstance)
);
return mEncoder.WriteUint8(otThreadGetLeaderWeight(mInstance));
}
otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(void)
{
otError error = OT_ERROR_NONE;
otChildInfo childInfo;
uint8_t maxChildren;
uint8_t modeFlags;
mDisableStreamWrite = true;
SuccessOrExit(error = OutboundFrameBegin(aHeader));
SuccessOrExit(
error = OutboundFrameFeedPacked(
SPINEL_DATATYPE_COMMAND_PROP_S,
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey
));
maxChildren = otThreadGetMaxAllowedChildren(mInstance);
for (uint8_t index = 0; index < maxChildren; index++)
{
error = otThreadGetChildInfoByIndex(mInstance, index, &childInfo);
if (error != OT_ERROR_NONE)
if (otThreadGetChildInfoByIndex(mInstance, index, &childInfo) != OT_ERROR_NONE)
{
continue;
}
@@ -114,47 +89,28 @@ otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_p
childInfo.mFullNetworkData
);
SuccessOrExit(
error = OutboundFrameFeedPacked(
SPINEL_DATATYPE_STRUCT_S(
SPINEL_DATATYPE_EUI64_S // EUI64 Address
SPINEL_DATATYPE_UINT16_S // Rloc16
SPINEL_DATATYPE_UINT32_S // Timeout
SPINEL_DATATYPE_UINT32_S // Age
SPINEL_DATATYPE_UINT8_S // Network Data Version
SPINEL_DATATYPE_UINT8_S // Link Quality In
SPINEL_DATATYPE_INT8_S // Average RSS
SPINEL_DATATYPE_UINT8_S // Mode (flags)
SPINEL_DATATYPE_INT8_S // Most recent RSS
),
childInfo.mExtAddress.m8,
childInfo.mRloc16,
childInfo.mTimeout,
childInfo.mAge,
childInfo.mNetworkDataVersion,
childInfo.mLinkQualityIn,
childInfo.mAverageRssi,
modeFlags,
childInfo.mLastRssi
));
SuccessOrExit(error = mEncoder.OpenStruct());
SuccessOrExit(error = mEncoder.WriteEui64(childInfo.mExtAddress));
SuccessOrExit(error = mEncoder.WriteUint16(childInfo.mRloc16));
SuccessOrExit(error = mEncoder.WriteUint32(childInfo.mTimeout));
SuccessOrExit(error = mEncoder.WriteUint32(childInfo.mAge));
SuccessOrExit(error = mEncoder.WriteUint8(childInfo.mNetworkDataVersion));
SuccessOrExit(error = mEncoder.WriteUint8(childInfo.mLinkQualityIn));
SuccessOrExit(error = mEncoder.WriteInt8(childInfo.mAverageRssi));
SuccessOrExit(error = mEncoder.WriteUint8(modeFlags));
SuccessOrExit(error = mEncoder.WriteInt8(childInfo.mLastRssi));
SuccessOrExit(error = mEncoder.CloseStruct());
}
SuccessOrExit(error = OutboundFrameSend());
exit:
mDisableStreamWrite = false;
return error;
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_BOOL_S,
otThreadIsRouterRoleEnabled(mInstance)
);
return mEncoder.WriteBool(otThreadIsRouterRoleEnabled(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -179,16 +135,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_NET_PSKC(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_DATA_S,
otThreadGetPSKc(mInstance),
sizeof(spinel_net_pskc_t)
);
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,
@@ -215,15 +164,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetMaxAllowedChildren(mInstance)
);
return mEncoder.WriteUint8(otThreadGetMaxAllowedChildren(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -248,15 +191,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetRouterUpgradeThreshold(mInstance)
);
return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -281,15 +218,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetRouterDowngradeThreshold(mInstance)
);
return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -314,15 +245,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetRouterSelectionJitter(mInstance)
);
return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -347,15 +272,9 @@ exit:
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT32_S,
otThreadGetContextIdReuseDelay(mInstance)
);
return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -380,15 +299,9 @@ otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader,
return SendSetPropertyResponse(aHeader, aKey, error);
}
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
otThreadGetNetworkIdTimeout(mInstance)
);
return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance));
}
otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -414,22 +327,9 @@ otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, s
}
#if OPENTHREAD_ENABLE_COMMISSIONER
otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(void)
{
bool enabled = false;
if (otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE)
{
enabled = true;
}
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_BOOL_S,
enabled
);
return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE);
}
otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
@@ -464,17 +364,15 @@ exit:
return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
otExtAddress *extAddress = NULL;
const char *aPSKd = NULL;
uint32_t joinerTimeout = 0;
VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE);
VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE);
parsedLength = spinel_datatype_unpack(
aValuePtr,
@@ -504,26 +402,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_pr
extAddress = NULL;
}
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_INSERTED,
aKey,
aValuePtr,
aValueLen
);
exit:
if (spinelError != SPINEL_STATUS_OK)
{
error = SendLastStatus(aHeader, spinelError);
}
return error;
}
@@ -558,6 +441,7 @@ otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel
otExtAddress *extAddress;
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
parsedLength = spinel_datatype_unpack(
aValuePtr,
@@ -566,26 +450,21 @@ otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel
&extAddress
);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
error = otThreadSetSteeringData(mInstance, extAddress);
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.WriteEui64(*extAddress));
SuccessOrExit(error = mEncoder.EndFrame());
exit:
if (error == OT_ERROR_NONE)
if (spinelError != SPINEL_STATUS_OK)
{
// Note that there is no get handler for this property.
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_EUI64_S,
extAddress->m8
);
}
else
{
error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
error = SendLastStatus(aHeader, spinelError);
}
return error;
@@ -620,44 +499,7 @@ otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader,
uint8_t routerId = 0;
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
parsedLength = spinel_datatype_unpack(
aValuePtr,
aValueLen,
SPINEL_DATATYPE_UINT8_S,
&routerId
);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otThreadSetPreferredRouterId(mInstance, routerId);
exit:
if (error == OT_ERROR_NONE)
{
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_UINT8_S,
routerId
);
}
else
{
error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error));
}
return error;
}
otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
uint8_t routerId;
parsedLength = spinel_datatype_unpack(
aValuePtr,
@@ -668,24 +510,16 @@ otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader,
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
error = otThreadReleaseRouterId(mInstance, routerId);
// `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list)
// in such a case, the "remove" operation can be considered successful.
VerifyOrExit(error != OT_ERROR_INVALID_STATE, error = SendLastStatus(aHeader, SPINEL_STATUS_OK));
error = otThreadSetPreferredRouterId(mInstance, routerId);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_REMOVED,
aKey,
aValuePtr,
aValueLen
);
// 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);
@@ -694,16 +528,39 @@ exit:
return error;
}
#if OPENTHREAD_ENABLE_TMF_PROXY
otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey)
otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(const uint8_t *aValuePtr, uint16_t aValueLen)
{
return SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
SPINEL_DATATYPE_BOOL_S,
otTmfProxyIsEnabled(mInstance)
);
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);
error = otThreadReleaseRouterId(mInstance, routerId);
// `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list)
// in such a case, the "remove" operation can be considered successful.
if (error == OT_ERROR_INVALID_STATE)
{
error = OT_ERROR_NONE;
}
exit:
return error;
}
#if OPENTHREAD_ENABLE_TMF_PROXY
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,
@@ -812,34 +669,24 @@ void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint1
uint16_t length = otMessageGetLength(aMessage);
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
SuccessOrExit(error = OutboundFrameBegin(header));
SuccessOrExit(
error = OutboundFrameFeedPacked(
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
header,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_THREAD_TMF_PROXY_STREAM,
length
));
SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
SuccessOrExit(
error = OutboundFrameFeedPacked(
SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_UINT16_S,
aLocator,
aPort
));
SuccessOrExit(error = mEncoder.BeginFrame(
header,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_THREAD_TMF_PROXY_STREAM
));
SuccessOrExit(error = mEncoder.WriteUint16(length));
SuccessOrExit(error = mEncoder.WriteMessage(aMessage));
// Set the `aMessage` pointer to NULL to indicate that it does
// not need to be freed at the exit. The `aMessage` is now owned
// by the OutboundFrame and will be freed when the frame is either
// by the outbound frame and will be freed when the frame is either
// successfully sent and then removed, or if the frame gets
// discarded.
aMessage = NULL;
SuccessOrExit(error = OutboundFrameSend());
SuccessOrExit(error = mEncoder.WriteUint16(aLocator));
SuccessOrExit(error = mEncoder.WriteUint16(aPort));
SuccessOrExit(error = mEncoder.EndFrame());
exit:
+635 -1569
View File
File diff suppressed because it is too large Load Diff
+73 -175
View File
@@ -68,55 +68,38 @@ void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
uint16_t flags = 0;
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
SuccessOrExit(OutboundFrameBegin(header));
if (aFrame->mDidTX)
{
flags |= SPINEL_MD_FLAG_TX;
}
// Append frame header and frame length
SuccessOrExit(
OutboundFrameFeedPacked(
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
header,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_STREAM_RAW,
(aError == OT_ERROR_NONE) ? aFrame->mLength : 0
));
SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
SuccessOrExit(mEncoder.WriteUint16((aError == OT_ERROR_NONE) ? aFrame->mLength : 0));
if (aError == OT_ERROR_NONE)
{
// Append the frame contents
SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength));
SuccessOrExit(mEncoder.WriteData(aFrame->mPsdu, aFrame->mLength));
}
// Append metadata (rssi, etc)
SuccessOrExit(
OutboundFrameFeedPacked(
SPINEL_DATATYPE_INT8_S
SPINEL_DATATYPE_INT8_S
SPINEL_DATATYPE_UINT16_S
SPINEL_DATATYPE_STRUCT_S( // PHY-data
SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
SPINEL_DATATYPE_UINT32_S // The timestamp milliseconds
SPINEL_DATATYPE_UINT16_S // The timestamp microseconds
)
SPINEL_DATATYPE_STRUCT_S( // Vendor-data
SPINEL_DATATYPE_UINT_PACKED_S
),
aFrame->mPower, // TX Power
-128, // Noise Floor (Currently unused)
flags, // Flags
aFrame->mChannel, // Receive channel
aFrame->mLqi, // Link quality indicator
aFrame->mMsec, // The timestamp milliseconds
aFrame->mUsec, // The timestamp microseconds, offset to mMsec
aError // Receive error
));
SuccessOrExit(mEncoder.WriteInt8(aFrame->mPower)); // TX Power
SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused)
SuccessOrExit(mEncoder.WriteUint16(flags)); // Flags
SuccessOrExit(OutboundFrameSend());
SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
SuccessOrExit(mEncoder.WriteUint8(aFrame->mChannel)); // 802.15.4 channel (Receive channel)
SuccessOrExit(mEncoder.WriteUint8(aFrame->mLqi)); // 802.15.4 LQI
SuccessOrExit(mEncoder.WriteUint32(aFrame->mMsec)); // The timestamp milliseconds
SuccessOrExit(mEncoder.WriteUint16(aFrame->mUsec)); // The timestamp microseconds, offset to mMsec
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data
SuccessOrExit(mEncoder.WriteUintPacked(aError)); // Receive error
SuccessOrExit(mEncoder.CloseStruct());
SuccessOrExit(mEncoder.EndFrame());
exit:
return;
@@ -138,40 +121,28 @@ void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame,
// Clear cached transmit TID
mCurTransmitTID = 0;
SuccessOrExit(OutboundFrameBegin(header));
SuccessOrExit(OutboundFrameFeedPacked(
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_BOOL_S,
header,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_LAST_STATUS,
ThreadErrorToSpinelStatus(aError),
framePending
));
SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_LAST_STATUS));
SuccessOrExit(mEncoder.WriteUintPacked(ThreadErrorToSpinelStatus(aError)));
SuccessOrExit(mEncoder.WriteBool(framePending));
if (aAckFrame && aError == OT_ERROR_NONE)
{
SuccessOrExit(OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, aAckFrame->mLength));
SuccessOrExit(OutboundFrameFeedData(aAckFrame->mPsdu, aAckFrame->mLength));
SuccessOrExit(OutboundFrameFeedPacked(
SPINEL_DATATYPE_INT8_S
SPINEL_DATATYPE_INT8_S
SPINEL_DATATYPE_UINT16_S
SPINEL_DATATYPE_STRUCT_S( // PHY-data
SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
),
aAckFrame->mPower, // RSSI
-128, // Noise Floor (Currently unused)
0, // Flags
aAckFrame->mChannel, // Receive channel
aAckFrame->mLqi, // Link quality indicator
aFrame->mMsec, // The timestamp milliseconds
aFrame->mUsec // The timestamp microseconds, offset to mMsec
));
SuccessOrExit(mEncoder.WriteUint16(aAckFrame->mLength));
SuccessOrExit(mEncoder.WriteData(aAckFrame->mPsdu, aAckFrame->mLength));
SuccessOrExit(mEncoder.WriteInt8(aAckFrame->mPower)); // RSSI
SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused)
SuccessOrExit(mEncoder.WriteUint16(0)); // Flags
SuccessOrExit(mEncoder.OpenStruct()); // PHY-data
SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mChannel)); // Receive channel
SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mLqi)); // Link Quality Indicator
SuccessOrExit(mEncoder.CloseStruct());
}
SuccessOrExit(OutboundFrameSend());
SuccessOrExit(mEncoder.EndFrame());
}
exit:
@@ -186,15 +157,7 @@ void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi)
void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi)
{
SendPropertyUpdate(
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_MAC_ENERGY_SCAN_RESULT,
SPINEL_DATATYPE_UINT8_S
SPINEL_DATATYPE_INT8_S,
mCurScanChannel,
aEnergyScanMaxRssi
);
int8_t scanChannel = mCurScanChannel;
// Clear current scan channel
mCurScanChannel = kInvalidScanChannel;
@@ -203,17 +166,32 @@ void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi)
// since the energy scan could have been on a different channel.
otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone);
SuccessOrExit(
mEncoder.BeginFrame(
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_MAC_ENERGY_SCAN_RESULT
));
SuccessOrExit(mEncoder.WriteUint8(static_cast<uint8_t>(scanChannel)));
SuccessOrExit(mEncoder.WriteInt8(aEnergyScanMaxRssi));
SuccessOrExit(mEncoder.EndFrame());
// We are finished with the scan, so send out
// a property update indicating such.
SendPropertyUpdate(
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_MAC_SCAN_STATE,
SPINEL_DATATYPE_UINT8_S,
SPINEL_SCAN_STATE_IDLE
);
}
SuccessOrExit(
mEncoder.BeginFrame(
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_MAC_SCAN_STATE
));
SuccessOrExit(mEncoder.WriteUint8(SPINEL_SCAN_STATE_IDLE));
SuccessOrExit(mEncoder.EndFrame());
exit:
return;
}
otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
@@ -273,14 +251,9 @@ otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeade
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
}
error =
SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
aValuePtr,
aValueLen
);
SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
SuccessOrExit(error = mEncoder.EndFrame());
exit:
@@ -328,14 +301,9 @@ otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHe
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
}
error =
SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_IS,
aKey,
aValuePtr,
aValueLen
);
SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey));
SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen));
SuccessOrExit(error = mEncoder.EndFrame());
exit:
@@ -347,12 +315,10 @@ exit:
return error;
}
otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
uint16_t shortAddress;
parsedLength = spinel_datatype_unpack(
@@ -362,35 +328,18 @@ otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHe
&shortAddress
);
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_REMOVED,
aKey,
aValuePtr,
aValueLen
);
exit:
if (spinelError != SPINEL_STATUS_OK)
{
error = SendLastStatus(aHeader, spinelError);
}
return error;
}
otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
otExtAddress *extAddress;
parsedLength = spinel_datatype_unpack(
@@ -400,35 +349,18 @@ otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t
&extAddress
);
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_REMOVED,
aKey,
aValuePtr,
aValueLen
);
exit:
if (spinelError != SPINEL_STATUS_OK)
{
error = SendLastStatus(aHeader, spinelError);
}
return error;
}
otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
uint16_t short_address;
parsedLength = spinel_datatype_unpack(
@@ -438,36 +370,18 @@ otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHe
&short_address
);
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_INSERTED,
aKey,
aValuePtr,
aValueLen
);
exit:
if (spinelError != SPINEL_STATUS_OK)
{
error = SendLastStatus(aHeader, spinelError);
}
return error;
}
otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey,
const uint8_t *aValuePtr, uint16_t aValueLen)
otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen)
{
spinel_ssize_t parsedLength;
otError error = OT_ERROR_NONE;
spinel_status_t spinelError = SPINEL_STATUS_OK;
otExtAddress *extAddress = NULL;
parsedLength = spinel_datatype_unpack(
@@ -477,27 +391,11 @@ otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t
&extAddress
);
VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR);
VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE);
error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress);
VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error));
error = SendPropertyUpdate(
aHeader,
SPINEL_CMD_PROP_VALUE_INSERTED,
aKey,
aValuePtr,
aValueLen
);
exit:
if (spinelError != SPINEL_STATUS_OK)
{
error = SendLastStatus(aHeader, spinelError);
}
return error;
}
+23 -5
View File
@@ -211,8 +211,8 @@ uint16_t NcpFrameBuffer::ReadUint16At(uint8_t *aBufPtr, Direction aDirection)
return value;
}
// Writes a byte at the write tail, discards the frame if buffer gets full.
otError NcpFrameBuffer::InFrameFeedByte(uint8_t aByte)
// Appends a byte at the write tail and updates the tail, discards the frame if buffer gets full.
otError NcpFrameBuffer::InFrameAppend(uint8_t aByte)
{
otError error = OT_ERROR_NONE;
uint8_t *newTail;
@@ -254,7 +254,7 @@ otError NcpFrameBuffer::InFrameBeginSegment(void)
// Reserve space for the segment header.
for (uint16_t i = kSegmentHeaderSize; i; i--)
{
SuccessOrExit(error = InFrameFeedByte(0));
SuccessOrExit(error = InFrameAppend(0));
}
// Write the flags at the segment head.
@@ -344,6 +344,21 @@ otError NcpFrameBuffer::InFrameBegin(Priority aPriority)
return OT_ERROR_NONE;
}
otError NcpFrameBuffer::InFrameFeedByte(uint8_t aByte)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
// Begin a new segment (if we are not in middle of segment already).
SuccessOrExit(error = InFrameBeginSegment());
error = InFrameAppend(aByte);
exit:
return error;
}
otError NcpFrameBuffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength)
{
otError error = OT_ERROR_NONE;
@@ -356,7 +371,7 @@ otError NcpFrameBuffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDa
// Write the data buffer
while (aDataBufferLength--)
{
SuccessOrExit(error = InFrameFeedByte(*aDataBuffer++));
SuccessOrExit(error = InFrameAppend(*aDataBuffer++));
}
exit:
@@ -383,12 +398,15 @@ exit:
return error;
}
otError NcpFrameBuffer::InFrameGetPosition(WritePosition &aPosition) const
otError NcpFrameBuffer::InFrameGetPosition(WritePosition &aPosition)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
// Begin a new segment (if we are not in middle of segment already).
SuccessOrExit(error = InFrameBeginSegment());
aPosition.mPosition = mWriteSegmentTail;
aPosition.mSegmentHead = mWriteSegmentHead;
+25 -7
View File
@@ -40,7 +40,6 @@
namespace ot {
namespace Ncp {
/**
* This class implements a buffer/queue for storing NCP frames.
*
@@ -52,6 +51,7 @@ namespace Ncp {
*/
class NcpFrameBuffer
{
friend class SpinelEncoder;
public:
/**
@@ -163,6 +163,24 @@ public:
*/
otError InFrameBegin(Priority aPriority);
/**
* This method adds a single byte to current input frame.
*
* Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aByte The byte value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given byte to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte.
* @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame.
*
*/
otError InFrameFeedByte(uint8_t aByte);
/**
* This method adds data to the current input frame.
*
@@ -177,7 +195,7 @@ public:
*
* @retval OT_ERROR_NONE Successfully added new data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data.
* @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame.
*
*/
otError InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength);
@@ -198,7 +216,7 @@ public:
*
* @retval OT_ERROR_NONE Successfully added the message to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message.
* @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_ARGS If @p aMessage is NULL.
*
*/
@@ -214,10 +232,10 @@ public:
* @param[out] aPosition A reference to a `WritePosition` to save the current write position.
*
* @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition.
* @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame.
*
*/
otError InFrameGetPosition(WritePosition &aPosition) const;
otError InFrameGetPosition(WritePosition &aPosition);
/**
* This method overwrites the previously written content in the current input frame at a given write position.
@@ -286,7 +304,7 @@ public:
*
* @retval OT_ERROR_NONE Successfully ended the input frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message.
* @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame.
*
*/
otError InFrameEnd(void);
@@ -581,7 +599,7 @@ private:
bool HasFrame(Priority aPriority) const;
void UpdateReadWriteStartPointers(void);
otError InFrameFeedByte(uint8_t aByte);
otError InFrameAppend(uint8_t aByte);
otError InFrameBeginSegment(void);
void InFrameEndSegment(uint16_t aSegmentHeaderFlags);
void InFrameDiscard(void);
+277
View File
@@ -0,0 +1,277 @@
/*
* 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 encoder.
*/
#include <openthread/config.h>
#include "spinel_encoder.hpp"
#include "common/code_utils.hpp"
namespace ot {
namespace Ncp {
otError SpinelEncoder::BeginFrame(NcpFrameBuffer::Priority aPriority)
{
mNumOpenStructs = 0;
return mNcpBuffer.InFrameBegin(aPriority);
}
otError SpinelEncoder::BeginFrame(uint8_t aHeader, unsigned int aCommand)
{
otError error = OT_ERROR_NONE;
// Non-zero TID indicates this is a response to a spinel command.
if (SPINEL_HEADER_GET_TID(aHeader) != 0)
{
SuccessOrExit(error = BeginFrame(NcpFrameBuffer::kPriorityHigh));
}
else
{
SuccessOrExit(error = BeginFrame(NcpFrameBuffer::kPriorityLow));
}
SuccessOrExit(error = WriteUint8(aHeader));
SuccessOrExit(error = WriteUintPacked(aCommand));
exit:
return error;
}
otError SpinelEncoder::BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = BeginFrame(aHeader, aCommand));
// The write position is saved before writing the property key,
// so that if fetching the property fails and we need to
// reply with a `LAST_STATUS` error we can get back to
// this saved write position and update the property key.
// (Also see `OverwriteWithLastStatusError()`).
SuccessOrExit(error = SavePosition());
SuccessOrExit(error = WriteUintPacked(aKey));
exit:
return error;
}
otError SpinelEncoder::OverwriteWithLastStatusError(spinel_status_t aStatus)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = ResetToSaved());
SuccessOrExit(error = WriteUintPacked(SPINEL_PROP_LAST_STATUS));
SuccessOrExit(error = WriteUintPacked(aStatus));
exit:
return error;
}
otError SpinelEncoder::EndFrame(void)
{
otError error = OT_ERROR_NONE;
while (mNumOpenStructs > 0)
{
SuccessOrExit(error = CloseStruct());
}
error = mNcpBuffer.InFrameEnd();
exit:
return error;
}
otError SpinelEncoder::WriteUint16(uint16_t aUint16)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 0) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 8) & 0xff));
exit:
return error;
}
otError SpinelEncoder::WriteUint32(uint32_t aUint32)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 0) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 8) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 16) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 24) & 0xff));
exit:
return error;
}
otError SpinelEncoder::WriteUintPacked(unsigned int aUint)
{
uint8_t buffer[6];
spinel_ssize_t len;
len = spinel_packed_uint_encode(buffer, sizeof(buffer), aUint);
return WriteData(buffer, static_cast<uint16_t>(len));
}
otError SpinelEncoder::WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = WriteUint16(aDataLen));
SuccessOrExit(error = WriteData(aData, aDataLen));
exit:
return error;
}
otError SpinelEncoder::WriteUtf8(const char *aUtf8)
{
otError error;
size_t len = strlen(aUtf8);
if (len >= 0xffff)
{
len = 0xffff;
}
SuccessOrExit(error = WriteData(reinterpret_cast<const uint8_t *>(aUtf8), static_cast<uint16_t>(len)));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0));
exit:
return error;
}
otError SpinelEncoder::OpenStruct(void)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(mNumOpenStructs < kMaxNestedStructs, error = OT_ERROR_INVALID_STATE);
SuccessOrExit(error = mNcpBuffer.InFrameGetPosition(mStructPosition[mNumOpenStructs]));
// Reserve bytes for the length to be filled when the struct gets closed.
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0));
mNumOpenStructs++;
exit:
return error;
}
otError SpinelEncoder::CloseStruct(void)
{
otError error = OT_ERROR_NONE;
uint16_t len;
uint8_t buffer[sizeof(uint16_t)];
VerifyOrExit(mNumOpenStructs > 0, error = OT_ERROR_INVALID_STATE);
mNumOpenStructs--;
len = mNcpBuffer.InFrameGetDistance(mStructPosition[mNumOpenStructs]);
VerifyOrExit(len >= sizeof(uint16_t), error = OT_ERROR_INVALID_STATE);
len -= sizeof(uint16_t);
buffer[0] = (len >> 0 & 0xff);
buffer[1] = (len >> 8 & 0xff);
SuccessOrExit(error = mNcpBuffer.InFrameOverwrite(mStructPosition[mNumOpenStructs], buffer, sizeof(buffer)));
exit:
return error;
}
otError SpinelEncoder::SavePosition(void)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mNcpBuffer.InFrameGetPosition(mSavedPosition));
mSavedNumOpenStructs = mNumOpenStructs;
exit:
return error;
}
otError SpinelEncoder::ResetToSaved(void)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mNcpBuffer.InFrameReset(mSavedPosition));
mNumOpenStructs = mSavedNumOpenStructs;
exit:
return error;
}
otError SpinelEncoder::WritePacked(const char *aPackFormat, ...)
{
uint8_t buf[kPackFormatBufferSize];
otError error = OT_ERROR_NONE;
spinel_ssize_t packedLen;
va_list args;
va_start(args, aPackFormat);
packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, args);
VerifyOrExit((packedLen > 0) && (packedLen <= static_cast<spinel_ssize_t>(sizeof(buf))), error = OT_ERROR_NO_BUFS);
error = mNcpBuffer.InFrameFeedData(buf, static_cast<uint16_t>(packedLen));
va_end(args);
exit:
return error;
}
otError SpinelEncoder::WriteVPacked(const char *aPackFormat, va_list aArgs)
{
uint8_t buf[kPackFormatBufferSize];
otError error = OT_ERROR_NONE;
spinel_ssize_t packedLen;
packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, aArgs);
VerifyOrExit((packedLen > 0) && (packedLen <= static_cast<spinel_ssize_t>(sizeof(buf))), error = OT_ERROR_NO_BUFS);
error = mNcpBuffer.InFrameFeedData(buf, static_cast<uint16_t>(packedLen));
exit:
return error;
}
} // namespace Ncp
} // namespace ot
+652
View File
@@ -0,0 +1,652 @@
/*
* 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 encoder.
*/
#ifndef SPINEL_ENCODER_HPP_
#define SPINEL_ENCODER_HPP_
#include <openthread/config.h>
#include <openthread/message.h>
#include <openthread/ncp.h>
#include <openthread/types.h>
#include "openthread-core-config.h"
#include "ncp/spinel.h"
#include "ncp/ncp_buffer.hpp"
namespace ot {
namespace Ncp {
/**
* This class defines a spinel encoder.
*
*/
class SpinelEncoder
{
public:
/**
* This constructor initializes a `SpinelEncoder` object.
*
* @param[in] aNcpBuffer A reference to a `NcpFrameBuffer` where the frames are written.
*
*/
SpinelEncoder(NcpFrameBuffer &aNcpBuffer): mNcpBuffer(aNcpBuffer), mNumOpenStructs(0) { }
/**
* This method begins a new frame to be added/written to the frame buffer.
*
* If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling
* `BeginFrame()` will discard and clear the previous unfinished frame.
*
* @param[in] aPriority Priority level of the new input frame.
*
* @retval OT_ERROR_NONE Successfully started a new frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame.
*
*/
otError BeginFrame(NcpFrameBuffer::Priority aPriority);
/**
* This method begins a new spinel command frame to be added/written to the frame buffer.
*
* If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling
* `BeginFrame()` will discard and clear the previous unfinished frame.
*
* The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new
* frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level.
*
* @param[in] aHeader Spinel header for new the command frame.
* @param[in] aCommand Spinel command.
*
* @retval OT_ERROR_NONE Successfully started a new frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame.
*
*/
otError BeginFrame(uint8_t aHeader, unsigned int aCommand);
/**
* This method begins a new spinel property update command frame to be added/written to the frame buffer.
*
* If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling
* `BeginFrame()` will discard and clear the previous unfinished frame.
*
* The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new
* frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level.
*
* This method saves the write position before the property key (see also `SavePosition()`) so that if fetching the
* property fails and the property key should be switched to `LAST_STATUS` with an error status, the saved
* position can be used to update the property key in the frame (see also `OverwriteWithLastStatusError()`)
*
* @param[in] aHeader Spinel header for new the command frame.
* @param[in] aCommand Spinel command.
* @param[in] aKey Spinel property key
*
* @retval OT_ERROR_NONE Successfully started a new frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame.
*
*/
otError BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey);
/**
* This method overwrites the property key with `LAST_STATUS` in a property update command frame.
*
* This method should be only used after a successful `BeginFrame(aHeader, aCommand, aPropertKey)`, otherwise, its
* behavior is undefined.
*
* This method moves the write position back to saved position by `BeginFrame()` and replaces the property key
* `SPINEL_PORP_LAST_STATUS` and writes the given spinel status error.
*
* @param[in] aStatus Spinel error status
*
* @retval OT_ERROR_NONE Successfully updated the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to update the frame.
*
*/
otError OverwriteWithLastStatusError(spinel_status_t aStatus);
/**
* This method finalizes/ends the current frame being written to the buffer.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new frame. Otherwise, this method
* does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the frame and return error status
* `OT_ERROR_NO_BUFS`.
*
* This method ensures to close any open structure (previously opened using `OpenStruct()` but not closed using
* `CloseStruct()`).
*
* @retval OT_ERROR_NONE Successfully ended the input frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError EndFrame(void);
/**
* This method encodes and writes a boolean value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aBool The boolean value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given byte to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteBool(bool aBool) { return mNcpBuffer.InFrameFeedByte( aBool ? 0x01: 0x00); }
/**
* This method encodes and writes a `uint8_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUint8 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUint8(uint8_t aUint8) { return mNcpBuffer.InFrameFeedByte(aUint8); }
/**
* This method encodes and writes an `int8_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aInt8 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteInt8(int8_t aInt8) { return WriteUint8(static_cast<uint8_t>(aInt8)); }
/**
* This method encodes and writes a `uint16_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUint16 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUint16(uint16_t aUint16);
/**
* This method encodes and writes an `int16_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aInt16 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteInt16(int16_t aInt16) { return WriteUint16(static_cast<uint16_t>(aInt16)); }
/**
* This method encodes and writes a `uint32_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUint32 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUint32(uint32_t aUint32);
/**
* This method encodes and writes an `int32_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aInt32 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteInt32(int32_t aInt32) { return WriteUint32(static_cast<uint32_t>(aInt32)); }
/**
* This method encodes (using spinel packed integer format) and writes a value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUint The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUintPacked(unsigned int aUint);
/**
* This method encodes and writes an IPv6 address to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aIp6Addr A reference to the IPv6 address to be added (as `spinel_ipv6addr_t`)
*
* @retval OT_ERROR_NONE Successfully added given address to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteIp6Address(const spinel_ipv6addr_t &aIp6Addr) { return WriteIp6Address(aIp6Addr.bytes); }
/**
* This method encodes and writes an IPv6 address to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aIp6Addr A reference to the IPv6 address to be added (as `otIp6Address`)
*
* @retval OT_ERROR_NONE Successfully added given address to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteIp6Address(const otIp6Address &aIp6Addr) { return WriteIp6Address(aIp6Addr.mFields.m8); }
/**
* This method encodes and writes an IPv6 address to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aIp6AddrBuf A pointer to a buffer containing the IPv6 address.
*
* @retval OT_ERROR_NONE Successfully added given address to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteIp6Address(const uint8_t *aIp6AddrBuf) { return WriteData(aIp6AddrBuf, sizeof(spinel_ipv6addr_t)); }
/**
* This method encodes and writes an EUI64 value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aEui64 A reference to the EUI64 value as a `spinel_eui64_t` type.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteEui64(const spinel_eui64_t &aEui64) { return WriteEui64(aEui64.bytes); }
/**
* This method encodes and writes an EUI64 value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aExtAddress A reference to an `otExtAddress`
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteEui64(const otExtAddress &aExtAddress) { return WriteEui64(aExtAddress.m8); }
/**
* This method encodes and writes an EUI64 value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aExtAddress A pointer to a buffer containing the EUI64 value.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteEui64(const uint8_t *aEui64) { return WriteData(aEui64, sizeof(spinel_eui64_t)); }
/**
* This method encodes and writes an EUI48 value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aEui48 A reference to the EUI48 value.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteEui48(const spinel_eui48_t &aEui48) { return WriteEui48(aEui48.bytes); }
/**
* This method encodes and writes an EUI48 value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aEui48 A pointer to a buffer containing the EUI64 value.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteEui48(const uint8_t *aEui48) { return WriteData(aEui48, sizeof(spinel_eui48_t)); }
/**
* This method encodes and writes a UTF8 string to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUtf8 A const character pointer (C string).
*
* @retval OT_ERROR_NONE Successfully added given string to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the string.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUtf8(const char *aUtf8);
/**
* This method encodes and writes a sequence of bytes to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aData A pointer to data buffer.
* @param[in] aDataLen The length (number of bytes) in the data buffer.
*
* @retval OT_ERROR_NONE Successfully added given data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteData(const uint8_t *aData, uint16_t aDataLen) { return mNcpBuffer.InFrameFeedData(aData, aDataLen); }
/**
* This method encodes and writes a data blob (sequence of bytes) with its length prepended before the data.
*
* The length of the data (in bytes) is prepended (with the length encoded as a `uint16`). The size of the length
* field is not included in the length. This is similar to `SPINEL_DATATYPE_DATA_WLEN` type.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aData A pointer to data buffer.
* @param[in] aDataLen The length (number of bytes) in the data buffer.
*
* @retval OT_ERROR_NONE Successfully added given data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen);
/**
* This method adds a message to the current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the frame and return error status
* `OT_ERROR_NO_BUFS`.
*
* In case of success, the passed-in message @p aMessage will be owned by the frame buffer instance and will be
* freed when either the the frame is removed or discarded. In case of failure @p aMessage remains unchanged.
*
* @param[in] aMessage A message to be added to current frame.
*
* @retval OT_ERROR_NONE Successfully added the message to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
* @retval OT_ERROR_INVALID_ARGS If @p aMessage is NULL.
*
*/
otError WriteMessage(otMessage *aMessage) { return mNcpBuffer.InFrameFeedMessage(aMessage); }
/**
* This method encodes and writes a set of variables to the current input frame using a given spinel packing format
* string.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes.
*
* @param[in] aPackFormat A string giving the spinel packing format.
* @param[in] ... Variable arguments corresponding to the types given in @p aPackFormat (see
* `spinel_datatype_pack()`).
*
* @retval OT_ERROR_NONE Successfully added given data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WritePacked(const char *aPackFormat, ...);
/**
* This method encodes and writes a set of variables to the current input frame using a given spinel packing format
* string.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes.
*
* @param[in] aPackFormat A string giving the spinel packing format.
* @param[in] aArgs Variable arguments corresponding to the types given in @p aPackFormat (see
* `spinel_datatype_pack()`).
*
* @retval OT_ERROR_NONE Successfully added given data to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteVPacked(const char *aPackFormat, va_list aArgs);
/**
* 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
* `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
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* 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_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.
*
*/
otError OpenStruct(void);
/**
* This method closes the most recently opened struct (using `OpenStruct()`) in the current input frame.
*
* Each call to `CloseStruct()` must correspond to an earlier successfully opened struct. If a frame is ended using
* `EndFrame()` with remaining open structs, the `EndFrame()` method will close all the remaining structs.
*
* 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_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
*/
otError CloseStruct(void);
/**
* This method saves the current write position in the input frame.
*
* The saved position can later be used to discard a portion of written/encoded frame and move the write pointer
* back to the saved position (using `ResetToSaved()`).
*
* @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError SavePosition(void);
/**
* This method resets the write position of input frame back to a previously saved position. Any added content
* after the write position is discarded.
*
* 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_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`.
*
*/
otError ResetToSaved(void);
private:
enum
{
kPackFormatBufferSize = 96, ///< Size of buffer used when encoding using `WritePacked()` or `WriteVPacked()`.
kMaxNestedStructs = 4, ///< Maximum number of nested structs.
};
NcpFrameBuffer &mNcpBuffer;
NcpFrameBuffer::WritePosition mStructPosition[kMaxNestedStructs];
uint8_t mNumOpenStructs;
uint8_t mSavedNumOpenStructs;
NcpFrameBuffer::WritePosition mSavedPosition;
};
} // namespace Ncp
} // namespace ot
#endif // SPINEL_ENCODER_HPP_
+4
View File
@@ -97,6 +97,7 @@ check_PROGRAMS = \
test-strlcat \
test-strlcpy \
test-strnlen \
test-spinel-encoder \
test-timer \
test-toolchain \
$(NULL)
@@ -186,6 +187,9 @@ test_strlcpy_SOURCES = test_strlcpy.c
test_strnlen_LDADD = $(COMMON_LDADD)
test_strnlen_SOURCES = test_strnlen.c
test_spinel_encoder_LDADD = $(COMMON_LDADD)
test_spinel_encoder_SOURCES = test_platform.cpp test_spinel_encoder.cpp
test_timer_LDADD = $(COMMON_LDADD)
test_timer_SOURCES = test_platform.cpp test_timer.cpp
+515
View File
@@ -0,0 +1,515 @@
/*
* 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_encoder.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);
}
otError ReadFrame(NcpFrameBuffer &aNcpBuffer, uint8_t *aFrame, uint16_t &aFrameLen)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = aNcpBuffer.OutFrameBegin());
aFrameLen = aNcpBuffer.OutFrameGetLength();
VerifyOrExit(aNcpBuffer.OutFrameRead(aFrameLen, aFrame) == aFrameLen, error = OT_ERROR_FAILED);
SuccessOrExit(error = aNcpBuffer.OutFrameRemove());
exit:
return error;
}
void TestSpinelEncoder(void)
{
uint8_t buffer[kTestBufferSize];
NcpFrameBuffer ncpBuffer(buffer, kTestBufferSize);
SpinelEncoder encoder(ncpBuffer);
uint8_t frame[kTestBufferSize];
uint16_t frameLen;
spinel_ssize_t parsedLen;
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;
spinel_ipv6addr_t *ip6Addr;
spinel_eui48_t *eui48;
spinel_eui64_t *eui64;
const char *utf_1;
const char *utf_2;
const uint8_t *dataPtr;
spinel_size_t dataLen;
memset(buffer, 0, sizeof(buffer));
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
printf("\nTest 1: Encoding of simple types");
SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed.");
SuccessOrQuit(encoder.WriteBool(kBool_1), "WriteBool() failed.");
SuccessOrQuit(encoder.WriteBool(kBool_2), "WriteBool() failed.");
SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed.");
SuccessOrQuit(encoder.WriteInt8(kInt8), "WriteUint8() failed.");
SuccessOrQuit(encoder.WriteUint16(kUint16), "WriteUint16() failed.");
SuccessOrQuit(encoder.WriteInt16(kInt16), "WriteInt16() failed.");
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
SuccessOrQuit(encoder.WriteInt32(kInt32), "WriteUint32() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_1), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_2), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_4), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed.");
SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed.");
SuccessOrQuit(encoder.WriteEui64(kEui64), "WriteEui64() failed.");
SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed.");
SuccessOrQuit(encoder.WriteUtf8(kString_2), "WriteUtf8() failed.");
SuccessOrQuit(encoder.WriteData((const uint8_t *)kData, sizeof(kData)), "WriteData() failed.");
SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed.");
DumpBuffer("Buffer", buffer, 256);
SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed.");
DumpBuffer("Frame", frame, frameLen);
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
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_S
),
&b_1,
&b_2,
&u8,
&i8,
&u16,
&i16,
&u32,
&i32,
&u_1,
&u_2,
&u_3,
&u_4,
&ip6Addr,
&eui48,
&eui64,
&utf_1,
&utf_2,
&dataPtr,
&dataLen
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(b_1 == kBool_1, "WriteBool() parse failed.");
VerifyOrQuit(b_2 == kBool_2, "WriteBool() parse failed.");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(i8 == kInt8, "WriteUint8() parse failed.");
VerifyOrQuit(u16 == kUint16, "WriteUint16() parse failed.");
VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "WriteUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "WriteUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed.");
VerifyOrQuit(u_4 == kUint_4, "WriteUintPacked() parse failed.");
VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed.");
VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed.");
VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "WriteEui64() parse failed.");
VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed.");
VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0, "WriteUtf8() parse failed.");
VerifyOrQuit(dataLen == sizeof(kData), "WriteData() parse failed.");
VerifyOrQuit(memcmp(dataPtr, &kData, sizeof(kData)) == 0, "WriteData() parse failed.");
printf(" -- PASS\n");
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
printf("\nTest 2: Test a single simple struct.");
SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed.");
SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed.");
}
SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed.");
SuccessOrQuit(encoder.WriteInt16(kInt16), "WriteInt16() failed.");
SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed.");
DumpBuffer("Buffer", buffer, 256);
SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed.");
DumpBuffer("Frame", frame, frameLen);
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
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
),
&u8,
&u32,
&eui48,
&u_3,
&i16
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed.");
VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed.");
// Parse the struct as a "data with len".
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
SPINEL_DATATYPE_UINT8_S
SPINEL_DATATYPE_DATA_WLEN_S
SPINEL_DATATYPE_INT16_S
),
&u8,
&dataPtr,
&dataLen,
&i16
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed.");
printf(" -- PASS\n");
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
printf("\nTest 3: Test multiple structs and struct within struct.");
SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed.");
SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteBool(kBool_1), "WriteBool() failed.");
SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed.");
}
SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed.");
SuccessOrQuit(encoder.WriteUint16(kUint16), "WriteUint16() failed.");
}
SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed.");
SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
}
SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed.");
SuccessOrQuit(encoder.WriteInt32(kInt32), "WriteUint32() failed.");
SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed.");
DumpBuffer("Buffer", buffer, 256 + 100);
SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed.");
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
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
),
&u8,
&utf_1,
&b_1,
&ip6Addr,
&u16,
&eui48,
&u32,
&i32
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(b_1 == kBool_1, "WriteBool() parse failed.");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(u16 == kUint16, "WriteUint16() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed.");
VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed.");
VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed.");
VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed.");
printf(" -- PASS\n");
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
printf("\nTest 4: Test unclosed struct.");
SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed.");
SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed.");
// Do not close the structs expecting `EndFrame()` to close them.
}
}
SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed.");
SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed.");
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
SPINEL_DATATYPE_UINT8_S
SPINEL_DATATYPE_STRUCT_S(
SPINEL_DATATYPE_UINT32_S
SPINEL_DATATYPE_STRUCT_S(
SPINEL_DATATYPE_EUI48_S
SPINEL_DATATYPE_UINT_PACKED_S
)
)
),
&u8,
&u32,
&eui48,
&u_3
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed.");
VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed.");
printf(" -- PASS\n");
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
printf("\nTest 5: Test saving position and reseting back to a saved position");
SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed.");
SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
// Save position in middle a first open struct.
SuccessOrQuit(encoder.SavePosition(), "SavePosition failed.");
SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed.");
{
SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed.");
}
// Reset to saved position in middle of the second open struct which should be discarded.
SuccessOrQuit(encoder.ResetToSaved(), "ResetToSaved() failed.");
SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed.");
SuccessOrQuit(encoder.WriteEui64(kEui64), "WriteEui64() failed.");
}
SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed.");
SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed.");
SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed.");
SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed.");
parsedLen = spinel_datatype_unpack(
frame,
(spinel_size_t)frameLen,
(
SPINEL_DATATYPE_UINT8_S
SPINEL_DATATYPE_STRUCT_S(
SPINEL_DATATYPE_UINT32_S
SPINEL_DATATYPE_IPv6ADDR_S
SPINEL_DATATYPE_EUI64_S
)
SPINEL_DATATYPE_UTF8_S
),
&u8,
&u32,
&ip6Addr,
&eui64,
&utf_1
);
VerifyOrQuit(parsedLen == frameLen, "spinel parse failed");
VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed.");
VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed.");
VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "WriteEui64() parse failed.");
VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed.");
printf(" -- PASS\n");
}
} // namespace Ncp
} // namespace ot
#ifdef ENABLE_TEST_MAIN
int main(void)
{
ot::Ncp::TestSpinelEncoder();
printf("\nAll tests passed.\n");
return 0;
}
#endif