mirror of
https://github.com/espressif/openthread.git
synced 2026-09-08 02:00:12 +00:00
[ncp-buffer] Frame Priority Support (#1948)
This commit adds support for setting two levels of priority (high or low) to frames stored in `NcpFrameBuffer`. High-priority frames are read before any queued low-priority frames. Within the same priority level FIFO order is preserved. The `NcpBase` is updated to send/queue the spinel response frames (with non- zero `tid`) as higher-priority frames. This ensures faster response time for spinel commands. This commit also adds/updates test cases for unit testing the NCP buffer and its new priority feature.
This commit is contained in:
committed by
Jonathan Hui
parent
529b188609
commit
529c291f7a
+57
-35
@@ -732,9 +732,21 @@ NcpBase *NcpBase::GetNcpInstance(void)
|
||||
// MARK: Outbound Frame methods
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
otError NcpBase::OutboundFrameBegin(void)
|
||||
otError NcpBase::OutboundFrameBegin(uint8_t aHeader)
|
||||
{
|
||||
return mTxFrameBuffer.InFrameBegin();
|
||||
NcpFrameBuffer::Priority priority;
|
||||
|
||||
// Non-zero tid indicates this is a response to a spinel command.
|
||||
if (SPINEL_HEADER_GET_TID(aHeader) != 0)
|
||||
{
|
||||
priority = NcpFrameBuffer::kPriorityHigh;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = NcpFrameBuffer::kPriorityLow;
|
||||
}
|
||||
|
||||
return mTxFrameBuffer.InFrameBegin(priority);
|
||||
}
|
||||
|
||||
otError NcpBase::OutboundFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength)
|
||||
@@ -767,13 +779,14 @@ void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint1
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t length = otMessageGetLength(aMessage);
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(header));
|
||||
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
SPINEL_PROP_THREAD_TMF_PROXY_STREAM,
|
||||
length
|
||||
@@ -823,15 +836,16 @@ void NcpBase::HandleDatagramFromStack(otMessage *aMessage, void *aContext)
|
||||
void NcpBase::HandleDatagramFromStack(otMessage *aMessage)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
bool isSecure = otMessageIsLinkSecurityEnabled(aMessage);
|
||||
uint16_t length = otMessageGetLength(aMessage);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(header));
|
||||
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE,
|
||||
length
|
||||
@@ -859,7 +873,7 @@ exit:
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_STATUS_DROPPED);
|
||||
SendLastStatus(header, SPINEL_STATUS_DROPPED);
|
||||
mDroppedOutboundIpFrameCounter++;
|
||||
}
|
||||
else
|
||||
@@ -887,13 +901,14 @@ void NcpBase::HandleRawFrame(const otRadioFrame *aFrame, void *aContext)
|
||||
void NcpBase::HandleRawFrame(const otRadioFrame *aFrame)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
|
||||
if (!mIsRawStreamEnabled)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
SuccessOrExit(OutboundFrameBegin());
|
||||
SuccessOrExit(OutboundFrameBegin(header));
|
||||
|
||||
if (aFrame->mDidTX)
|
||||
{
|
||||
@@ -904,7 +919,7 @@ void NcpBase::HandleRawFrame(const otRadioFrame *aFrame)
|
||||
SuccessOrExit(
|
||||
OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
SPINEL_PROP_STREAM_RAW,
|
||||
aFrame->mLength
|
||||
@@ -1070,8 +1085,9 @@ void NcpBase::LinkRawReceiveDone(otInstance *, otRadioFrame *aFrame, otError aEr
|
||||
void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
|
||||
SuccessOrExit(OutboundFrameBegin());
|
||||
SuccessOrExit(OutboundFrameBegin(header));
|
||||
|
||||
if (aFrame->mDidTX)
|
||||
{
|
||||
@@ -1082,7 +1098,7 @@ void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
|
||||
SuccessOrExit(
|
||||
OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
SPINEL_PROP_STREAM_RAW,
|
||||
(aError == OT_ERROR_NONE) ? aFrame->mLength : 0
|
||||
@@ -1467,9 +1483,11 @@ void NcpBase::HandleReceive(const uint8_t *aBuf, uint16_t aBufLength)
|
||||
}
|
||||
|
||||
void NcpBase::HandleFrameRemovedFromNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
|
||||
NcpFrameBuffer *aNcpBuffer)
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpBuffer)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aNcpBuffer);
|
||||
OT_UNUSED_VARIABLE(aPriority);
|
||||
|
||||
static_cast<NcpBase *>(aContext)->HandleFrameRemovedFromNcpBuffer(aFrameTag);
|
||||
}
|
||||
|
||||
@@ -1750,7 +1768,7 @@ otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_pr
|
||||
va_list args;
|
||||
|
||||
va_start(args, aPackFormat);
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey));
|
||||
SuccessOrExit(error = OutboundFrameFeedVPacked(aPackFormat, args));
|
||||
SuccessOrExit(error = OutboundFrameSend());
|
||||
@@ -1765,7 +1783,7 @@ otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_pr
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey));
|
||||
SuccessOrExit(error = OutboundFrameFeedData(aValuePtr, aValueLen));
|
||||
SuccessOrExit(error = OutboundFrameSend());
|
||||
@@ -1778,7 +1796,7 @@ otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_pr
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey));
|
||||
SuccessOrExit(error = OutboundFrameFeedMessage(aMessage));
|
||||
|
||||
@@ -2069,7 +2087,7 @@ otError NcpBase::CommandHandler_PEEK(uint8_t aHeader, unsigned int aCommand, con
|
||||
VerifyOrExit(mAllowPeekDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
(
|
||||
@@ -2193,7 +2211,7 @@ otError NcpBase::GetPropertyHandler_CAPS(uint8_t aHeader, spinel_prop_key_t aKey
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2493,7 +2511,7 @@ otError NcpBase::GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_pr
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2770,7 +2788,7 @@ otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(uint8_t aHeader, spinel_
|
||||
&networkDataLen
|
||||
);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2798,7 +2816,7 @@ otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(uint8_t aHeader,
|
||||
&networkDataLen
|
||||
);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2827,7 +2845,7 @@ otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(uint8_t aHeader,
|
||||
&networkDataLen
|
||||
);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2855,7 +2873,7 @@ otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(uint8_t aH
|
||||
&networkDataLen
|
||||
);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -2969,7 +2987,7 @@ otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_p
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -3036,7 +3054,7 @@ otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t aHeader, spine
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, SPINEL_CMD_PROP_VALUE_IS,
|
||||
aKey));
|
||||
|
||||
@@ -3087,7 +3105,7 @@ otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spin
|
||||
uint8_t numEntries = 0;
|
||||
const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, SPINEL_CMD_PROP_VALUE_IS,
|
||||
aKey));
|
||||
|
||||
@@ -3134,7 +3152,7 @@ otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -3342,7 +3360,7 @@ otError NcpBase::GetPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_p
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -3415,7 +3433,7 @@ otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spin
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -3839,7 +3857,7 @@ otError NcpBase::GetPropertyHandler_MSG_BUFFER_COUNTERS(uint8_t aHeader, spinel_
|
||||
|
||||
otMessageGetBufferInfo(mInstance, &bufferInfo);
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -3957,7 +3975,7 @@ otError NcpBase::GetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_k
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -4019,7 +4037,7 @@ otError NcpBase::GetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_k
|
||||
|
||||
mDisableStreamWrite = true;
|
||||
|
||||
SuccessOrExit(error = OutboundFrameBegin());
|
||||
SuccessOrExit(error = OutboundFrameBegin(aHeader));
|
||||
SuccessOrExit(
|
||||
error = OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S,
|
||||
@@ -7415,14 +7433,16 @@ exit:
|
||||
|
||||
void NcpBase::HandleDidReceiveNewLegacyUlaPrefix(const uint8_t *aUlaPrefix)
|
||||
{
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
|
||||
memcpy(mLegacyUlaPrefix, aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH);
|
||||
|
||||
SuccessOrExit(OutboundFrameBegin());
|
||||
SuccessOrExit(OutboundFrameBegin(header));
|
||||
|
||||
SuccessOrExit(
|
||||
OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_DATA_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
SPINEL_PROP_NEST_LEGACY_ULA_PREFIX,
|
||||
aUlaPrefix, OT_NCP_LEGACY_ULA_PREFIX_LENGTH
|
||||
@@ -7436,14 +7456,16 @@ exit:
|
||||
|
||||
void NcpBase::HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr)
|
||||
{
|
||||
uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0;
|
||||
|
||||
mLegacyNodeDidJoin = true;
|
||||
|
||||
SuccessOrExit(OutboundFrameBegin());
|
||||
SuccessOrExit(OutboundFrameBegin(header));
|
||||
|
||||
SuccessOrExit(
|
||||
OutboundFrameFeedPacked(
|
||||
SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_EUI64_S,
|
||||
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0,
|
||||
header,
|
||||
SPINEL_CMD_PROP_VALUE_IS,
|
||||
SPINEL_PROP_NEST_LEGACY_JOINED_NODE,
|
||||
aExtAddr->m8
|
||||
|
||||
@@ -111,11 +111,13 @@ 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(void);
|
||||
otError OutboundFrameBegin(uint8_t aHeader);
|
||||
|
||||
/**
|
||||
* This method adds data to the current outbound frame being written.
|
||||
@@ -192,7 +194,7 @@ private:
|
||||
#endif // OPENTHREAD_ENABLE_TMF_PROXY && OPENTHREAD_FTD
|
||||
|
||||
static void HandleFrameRemovedFromNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
|
||||
NcpFrameBuffer *aNcpBuffer);
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpBuffer);
|
||||
void HandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag);
|
||||
|
||||
static void HandleDatagramFromStack(otMessage *aMessage, void *aContext);
|
||||
|
||||
+246
-97
@@ -35,6 +35,7 @@
|
||||
#include "ncp_buffer.hpp"
|
||||
#include "utils/wrap_string.h"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -45,7 +46,11 @@ NcpFrameBuffer::NcpFrameBuffer(uint8_t *aBuffer, uint16_t aBufferLen) :
|
||||
mBufferEnd(aBuffer + aBufferLen),
|
||||
mBufferLength(aBufferLen)
|
||||
{
|
||||
otMessageQueueInit(&mMessageQueue);
|
||||
for (uint8_t priority = 0; priority < kNumPrios; priority++)
|
||||
{
|
||||
otMessageQueueInit(&mMessageQueue[priority]);
|
||||
}
|
||||
|
||||
otMessageQueueInit(&mWriteFrameMessageQueue);
|
||||
SetFrameAddedCallback(NULL, NULL);
|
||||
SetFrameRemovedCallback(NULL, NULL);
|
||||
@@ -57,16 +62,19 @@ void NcpFrameBuffer::Clear(void)
|
||||
otMessage *message;
|
||||
|
||||
// Write (InFrame) related variables
|
||||
mWriteFrameStart = mBuffer;
|
||||
mWriteFrameStart[kPriorityLow] = mBuffer;
|
||||
mWriteFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mBuffer, 1, kBackward);
|
||||
mWriteDirection = kUnknown;
|
||||
mWriteSegmentHead = mBuffer;
|
||||
mWriteSegmentTail = mBuffer;
|
||||
mWriteFrameTag = kInvalidTag;
|
||||
|
||||
// Read (OutFrame) related variables
|
||||
mReadState = kReadStateDone;
|
||||
mReadState = kReadStateNotActive;
|
||||
mReadFrameLength = kUnknownFrameLength;
|
||||
|
||||
mReadFrameStart = mBuffer;
|
||||
mReadFrameStart[kPriorityLow] = mBuffer;
|
||||
mReadFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mBuffer, 1, kBackward);
|
||||
mReadSegmentHead = mBuffer;
|
||||
mReadSegmentTail = mBuffer;
|
||||
mReadPointer = mBuffer;
|
||||
@@ -83,10 +91,13 @@ void NcpFrameBuffer::Clear(void)
|
||||
otMessageFree(message);
|
||||
}
|
||||
|
||||
while ((message = otMessageQueueGetHead(&mMessageQueue)) != NULL)
|
||||
for (uint8_t priority = 0; priority < kNumPrios; priority++)
|
||||
{
|
||||
otMessageQueueDequeue(&mMessageQueue, message);
|
||||
otMessageFree(message);
|
||||
while ((message = otMessageQueueGetHead(&mMessageQueue[priority])) != NULL)
|
||||
{
|
||||
otMessageQueueDequeue(&mMessageQueue[priority], message);
|
||||
otMessageFree(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,84 +113,129 @@ void NcpFrameBuffer::SetFrameRemovedCallback(BufferCallback aFrameRemovedCallbac
|
||||
mFrameRemovedContext = aFrameRemovedContext;
|
||||
}
|
||||
|
||||
// Increments the buffer pointer by one byte while handling the the wrap-around at the end of buffer.
|
||||
uint8_t *NcpFrameBuffer::Next(uint8_t *aBufPtr) const
|
||||
// Returns an updated buffer pointer by moving forward/backward (based on `aDirection`) from `aBufPtr` by a given
|
||||
// offset. The resulting buffer pointer is ensured to stay within the `mBuffer` boundaries.
|
||||
uint8_t *NcpFrameBuffer::GetUpdatedBufPtr(uint8_t *aBufPtr, uint16_t aOffset, Direction aDirection) const
|
||||
{
|
||||
aBufPtr++;
|
||||
return (aBufPtr == mBufferEnd) ? mBuffer : aBufPtr;
|
||||
}
|
||||
uint8_t *ptr = aBufPtr;
|
||||
|
||||
// Returns an advanced (moved forward) version of the given buffer pointer by the given offset.
|
||||
uint8_t *NcpFrameBuffer::Advance(uint8_t *aBufPtr, uint16_t aOffset) const
|
||||
{
|
||||
aBufPtr += aOffset;
|
||||
|
||||
while (aBufPtr >= mBufferEnd)
|
||||
switch (aDirection)
|
||||
{
|
||||
aBufPtr -= mBufferLength;
|
||||
case kForward:
|
||||
ptr += aOffset;
|
||||
|
||||
while (ptr >= mBufferEnd)
|
||||
{
|
||||
ptr -= mBufferLength;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kBackward:
|
||||
ptr -= aOffset;
|
||||
|
||||
while (ptr < mBuffer)
|
||||
{
|
||||
ptr += mBufferLength;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kUnknown:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return aBufPtr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Gets the distance between two buffer pointers (adjusts for the wrap-around).
|
||||
uint16_t NcpFrameBuffer::GetDistance(uint8_t *aStartPtr, uint8_t *aEndPtr) const
|
||||
// Gets the distance between two buffer pointers (adjusts for the wrap-around) given a direction (forward or backward).
|
||||
uint16_t NcpFrameBuffer::GetDistance(uint8_t *aStartPtr, uint8_t *aEndPtr, Direction aDirection) const
|
||||
{
|
||||
size_t distance;
|
||||
size_t distance = 0;
|
||||
|
||||
if (aEndPtr >= aStartPtr)
|
||||
switch (aDirection)
|
||||
{
|
||||
distance = static_cast<size_t>(aEndPtr - aStartPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = static_cast<size_t>(mBufferEnd - aStartPtr);
|
||||
distance += static_cast<size_t>(aEndPtr - mBuffer);
|
||||
case kForward:
|
||||
|
||||
if (aEndPtr >= aStartPtr)
|
||||
{
|
||||
distance = static_cast<size_t>(aEndPtr - aStartPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = static_cast<size_t>(mBufferEnd - aStartPtr);
|
||||
distance += static_cast<size_t>(aEndPtr - mBuffer);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kBackward:
|
||||
|
||||
if (aEndPtr <= aStartPtr)
|
||||
{
|
||||
distance = static_cast<size_t>(aStartPtr - aEndPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = static_cast<size_t>(mBufferEnd - aEndPtr);
|
||||
distance += static_cast<size_t>(aStartPtr - mBuffer);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kUnknown:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return static_cast<uint16_t>(distance);
|
||||
}
|
||||
|
||||
// Writes a uint16 value at the given buffer pointer (big-endian style).
|
||||
void NcpFrameBuffer::WriteUint16At(uint8_t *aBufPtr, uint16_t aValue)
|
||||
void NcpFrameBuffer::WriteUint16At(uint8_t *aBufPtr, uint16_t aValue, Direction aDirection)
|
||||
{
|
||||
*aBufPtr = (aValue >> 8);
|
||||
*Next(aBufPtr) = (aValue & 0xff);
|
||||
*GetUpdatedBufPtr(aBufPtr, 1, aDirection) = (aValue & 0xff);
|
||||
}
|
||||
|
||||
// Reads a uint16 value at the given buffer pointer (big-endian style).
|
||||
uint16_t NcpFrameBuffer::ReadUint16At(uint8_t *aBufPtr)
|
||||
uint16_t NcpFrameBuffer::ReadUint16At(uint8_t *aBufPtr, Direction aDirection)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
value = static_cast<uint16_t>((*aBufPtr) << 8);
|
||||
value += *Next(aBufPtr);
|
||||
value += *GetUpdatedBufPtr(aBufPtr, 1, aDirection);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Writes a bytes at the write tail, discards the frame if buffer gets full.
|
||||
// Writes a byte at the write tail, discards the frame if buffer gets full.
|
||||
otError NcpFrameBuffer::InFrameFeedByte(uint8_t aByte)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t *newTail = Next(mWriteSegmentTail);
|
||||
uint8_t *newTail;
|
||||
|
||||
VerifyOrExit(newTail != mReadFrameStart, error = OT_ERROR_NO_BUFS);
|
||||
assert(mWriteDirection != kUnknown);
|
||||
|
||||
*mWriteSegmentTail = aByte;
|
||||
mWriteSegmentTail = newTail;
|
||||
newTail = GetUpdatedBufPtr(mWriteSegmentTail, 1, mWriteDirection);
|
||||
|
||||
exit:
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
// Ensure the `newTail` has not reached the `mWriteFrameStart` for other direction (other priority level).
|
||||
if (newTail != mWriteFrameStart[(mWriteDirection == kForward) ? kBackward : kForward])
|
||||
{
|
||||
*mWriteSegmentTail = aByte;
|
||||
mWriteSegmentTail = newTail;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_NO_BUFS;
|
||||
InFrameDiscard();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// This method begins a new segment (if one is not already open)
|
||||
// This method begins a new segment (if one is not already open).
|
||||
otError NcpFrameBuffer::InFrameBeginSegment(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -188,8 +244,8 @@ otError NcpFrameBuffer::InFrameBeginSegment(void)
|
||||
// Verify that segment is not yet started (i.e., head and tail are the same).
|
||||
VerifyOrExit(mWriteSegmentHead == mWriteSegmentTail);
|
||||
|
||||
// If this is the start of a new frame (i.e., frame start is same as segment head)
|
||||
if (mWriteFrameStart == mWriteSegmentHead)
|
||||
// Check if this is the start of a new frame (i.e., frame start is same as segment head).
|
||||
if (mWriteFrameStart[mWriteDirection] == mWriteSegmentHead)
|
||||
{
|
||||
headerFlags |= kSegmentHeaderNewFrameFlag;
|
||||
}
|
||||
@@ -200,8 +256,8 @@ otError NcpFrameBuffer::InFrameBeginSegment(void)
|
||||
SuccessOrExit(error = InFrameFeedByte(0));
|
||||
}
|
||||
|
||||
// Write the flags at the segment head
|
||||
WriteUint16At(mWriteSegmentHead, headerFlags);
|
||||
// Write the flags at the segment head.
|
||||
WriteUint16At(mWriteSegmentHead, headerFlags, mWriteDirection);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -213,7 +269,7 @@ void NcpFrameBuffer::InFrameEndSegment(uint16_t aHeaderFlags)
|
||||
uint16_t segmentLength;
|
||||
uint16_t header;
|
||||
|
||||
segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail);
|
||||
segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection);
|
||||
|
||||
if (segmentLength >= kSegmentHeaderSize)
|
||||
{
|
||||
@@ -221,10 +277,10 @@ void NcpFrameBuffer::InFrameEndSegment(uint16_t aHeaderFlags)
|
||||
segmentLength -= kSegmentHeaderSize;
|
||||
|
||||
// Update the length and the flags in segment header (at segment head pointer).
|
||||
header = ReadUint16At(mWriteSegmentHead);
|
||||
header = ReadUint16At(mWriteSegmentHead, mWriteDirection);
|
||||
header |= (segmentLength & kSegmentHeaderLengthMask);
|
||||
header |= aHeaderFlags;
|
||||
WriteUint16At(mWriteSegmentHead, header);
|
||||
WriteUint16At(mWriteSegmentHead, header, mWriteDirection);
|
||||
|
||||
// Move the segment head to current tail (to be ready for a possible next segment).
|
||||
mWriteSegmentHead = mWriteSegmentTail;
|
||||
@@ -236,13 +292,15 @@ void NcpFrameBuffer::InFrameEndSegment(uint16_t aHeaderFlags)
|
||||
}
|
||||
}
|
||||
|
||||
// This method discards the current frame.
|
||||
// This method discards the current frame being written.
|
||||
void NcpFrameBuffer::InFrameDiscard(void)
|
||||
{
|
||||
otMessage *message;
|
||||
|
||||
VerifyOrExit(mWriteDirection != kUnknown);
|
||||
|
||||
// Move the write segment head and tail pointers back to frame start.
|
||||
mWriteSegmentHead = mWriteSegmentTail = mWriteFrameStart;
|
||||
mWriteSegmentHead = mWriteSegmentTail = mWriteFrameStart[mWriteDirection];
|
||||
|
||||
// Free any messages associated with current frame.
|
||||
while ((message = otMessageQueueGetHead(&mWriteFrameMessageQueue)) != NULL)
|
||||
@@ -250,13 +308,38 @@ void NcpFrameBuffer::InFrameDiscard(void)
|
||||
otMessageQueueDequeue(&mWriteFrameMessageQueue, message);
|
||||
otMessageFree(message);
|
||||
}
|
||||
|
||||
mWriteDirection = kUnknown;
|
||||
|
||||
exit:
|
||||
UpdateReadWriteStartPointers();
|
||||
}
|
||||
|
||||
otError NcpFrameBuffer::InFrameBegin(void)
|
||||
// Returns `true` if in middle of writing a frame with given priority.
|
||||
bool NcpFrameBuffer::InFrameIsWriting(Priority aPriority) const
|
||||
{
|
||||
// Discard any previous frame.
|
||||
return (mWriteDirection == static_cast<Direction>(aPriority));
|
||||
}
|
||||
|
||||
otError NcpFrameBuffer::InFrameBegin(Priority aPriority)
|
||||
{
|
||||
// Discard any previous unfinished frame.
|
||||
InFrameDiscard();
|
||||
|
||||
switch (aPriority)
|
||||
{
|
||||
case kPriorityHigh:
|
||||
mWriteDirection = kBackward;
|
||||
break;
|
||||
|
||||
case kPriorityLow:
|
||||
mWriteDirection = kForward;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set up the segment head and tail
|
||||
mWriteSegmentHead = mWriteSegmentTail = mWriteFrameStart[mWriteDirection];
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -264,6 +347,8 @@ otError NcpFrameBuffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDa
|
||||
{
|
||||
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());
|
||||
|
||||
@@ -281,6 +366,9 @@ otError NcpFrameBuffer::InFrameFeedMessage(otMessage *aMessage)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aMessage != NULL, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
// Begin a new segment (if we are not in middle of segment already).
|
||||
SuccessOrExit(error = InFrameBeginSegment());
|
||||
|
||||
@@ -297,29 +385,35 @@ exit:
|
||||
otError NcpFrameBuffer::InFrameEnd(void)
|
||||
{
|
||||
otMessage *message;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
// End/Close the current segment (if any).
|
||||
InFrameEndSegment(kSegmentHeaderNoFlag);
|
||||
|
||||
// Save and use the frame start pointer as the tag associated with the frame.
|
||||
mWriteFrameTag = mWriteFrameStart;
|
||||
mWriteFrameTag = mWriteFrameStart[mWriteDirection];
|
||||
|
||||
// Update the frame start pointer to current segment head to be ready for next frame.
|
||||
mWriteFrameStart = mWriteSegmentHead;
|
||||
mWriteFrameStart[mWriteDirection] = mWriteSegmentHead;
|
||||
|
||||
// Move all the messages from the frame queue to the main queue.
|
||||
while ((message = otMessageQueueGetHead(&mWriteFrameMessageQueue)) != NULL)
|
||||
{
|
||||
otMessageQueueDequeue(&mWriteFrameMessageQueue, message);
|
||||
otMessageQueueEnqueue(&mMessageQueue, message);
|
||||
otMessageQueueEnqueue(&mMessageQueue[mWriteDirection], message);
|
||||
}
|
||||
|
||||
if (mFrameAddedCallback != NULL)
|
||||
{
|
||||
mFrameAddedCallback(mFrameAddedContext, mWriteFrameTag, this);
|
||||
mFrameAddedCallback(mFrameAddedContext, mWriteFrameTag, static_cast<Priority>(mWriteDirection), this);
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
mWriteDirection = kUnknown;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
NcpFrameBuffer::FrameTag NcpFrameBuffer::InFrameGetLastTag(void) const
|
||||
@@ -327,9 +421,22 @@ NcpFrameBuffer::FrameTag NcpFrameBuffer::InFrameGetLastTag(void) const
|
||||
return mWriteFrameTag;
|
||||
}
|
||||
|
||||
bool NcpFrameBuffer::HasFrame(Priority aPriority) const
|
||||
{
|
||||
return mReadFrameStart[aPriority] != mWriteFrameStart[aPriority];
|
||||
}
|
||||
|
||||
bool NcpFrameBuffer::IsEmpty(void) const
|
||||
{
|
||||
return (mReadFrameStart == mWriteFrameStart);
|
||||
return !HasFrame(kPriorityHigh) && !HasFrame(kPriorityLow);
|
||||
}
|
||||
|
||||
void NcpFrameBuffer::OutFrameSelectReadDirection(void)
|
||||
{
|
||||
if (mReadState == kReadStateNotActive)
|
||||
{
|
||||
mReadDirection = HasFrame(kPriorityHigh) ? kBackward : kForward;
|
||||
}
|
||||
}
|
||||
|
||||
// Start/Prepare a new segment for reading.
|
||||
@@ -344,24 +451,24 @@ otError NcpFrameBuffer::OutFramePrepareSegment(void)
|
||||
mReadSegmentHead = mReadSegmentTail;
|
||||
|
||||
// Ensure there is something to read (i.e. segment head is not at start of frame being written).
|
||||
VerifyOrExit(mReadSegmentHead != mWriteFrameStart, error = OT_ERROR_NOT_FOUND);
|
||||
VerifyOrExit(mReadSegmentHead != mWriteFrameStart[mReadDirection], error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
// Read the segment header.
|
||||
header = ReadUint16At(mReadSegmentHead);
|
||||
header = ReadUint16At(mReadSegmentHead, mReadDirection);
|
||||
|
||||
// Check if this segment is the start of a frame.
|
||||
if (header & kSegmentHeaderNewFrameFlag)
|
||||
{
|
||||
// Ensure that this segment is start of current frame, otherwise the current frame is finished.
|
||||
VerifyOrExit(mReadSegmentHead == mReadFrameStart, error = OT_ERROR_NOT_FOUND);
|
||||
VerifyOrExit(mReadSegmentHead == mReadFrameStart[mReadDirection], error = OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Find tail/end of current segment.
|
||||
mReadSegmentTail = Advance(mReadSegmentHead,
|
||||
kSegmentHeaderSize + (header & kSegmentHeaderLengthMask));
|
||||
mReadSegmentTail = GetUpdatedBufPtr(mReadSegmentHead, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask),
|
||||
mReadDirection);
|
||||
|
||||
// Update the current read pointer to skip the segment header.
|
||||
mReadPointer = Advance(mReadSegmentHead, kSegmentHeaderSize);
|
||||
mReadPointer = GetUpdatedBufPtr(mReadSegmentHead, kSegmentHeaderSize, mReadDirection);
|
||||
|
||||
// Check if there are data bytes to be read in this segment (i.e. read pointer not at the tail).
|
||||
if (mReadPointer != mReadSegmentTail)
|
||||
@@ -399,15 +506,15 @@ otError NcpFrameBuffer::OutFramePrepareMessage(void)
|
||||
uint16_t header;
|
||||
|
||||
// Read the segment header
|
||||
header = ReadUint16At(mReadSegmentHead);
|
||||
header = ReadUint16At(mReadSegmentHead, mReadDirection);
|
||||
|
||||
// Ensure that the segment header indicates that there is an associated message or return `NotFound` error.
|
||||
VerifyOrExit((header & kSegmentHeaderMessageIndicatorFlag) != 0, error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
// Update the current message from the queue.
|
||||
mReadMessage = (mReadMessage == NULL) ?
|
||||
otMessageQueueGetHead(&mMessageQueue) :
|
||||
otMessageQueueGetNext(&mMessageQueue, mReadMessage);
|
||||
otMessageQueueGetHead(&mMessageQueue[mReadDirection]) :
|
||||
otMessageQueueGetNext(&mMessageQueue[mReadDirection], mReadMessage);
|
||||
|
||||
VerifyOrExit(mReadMessage != NULL, error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
@@ -456,20 +563,25 @@ otError NcpFrameBuffer::OutFrameBegin(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
mReadMessage = NULL;
|
||||
VerifyOrExit(!IsEmpty(), error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
OutFrameSelectReadDirection();
|
||||
|
||||
// Move the segment head and tail to start of frame.
|
||||
mReadSegmentHead = mReadSegmentTail = mReadFrameStart;
|
||||
mReadSegmentHead = mReadSegmentTail = mReadFrameStart[mReadDirection];
|
||||
|
||||
mReadMessage = NULL;
|
||||
|
||||
// Prepare the current segment for reading.
|
||||
error = OutFramePrepareSegment();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool NcpFrameBuffer::OutFrameHasEnded(void)
|
||||
{
|
||||
return (mReadState == kReadStateDone);
|
||||
return (mReadState == kReadStateDone) || (mReadState == kReadStateNotActive);
|
||||
}
|
||||
|
||||
uint8_t NcpFrameBuffer::OutFrameReadByte(void)
|
||||
@@ -479,6 +591,10 @@ uint8_t NcpFrameBuffer::OutFrameReadByte(void)
|
||||
|
||||
switch (mReadState)
|
||||
{
|
||||
case kReadStateNotActive:
|
||||
|
||||
// Fall through
|
||||
|
||||
case kReadStateDone:
|
||||
|
||||
retval = kReadByteAfterFrameHasEnded;
|
||||
@@ -487,9 +603,9 @@ uint8_t NcpFrameBuffer::OutFrameReadByte(void)
|
||||
|
||||
case kReadStateInSegment:
|
||||
|
||||
// Read a byte from current read pointer and move the read pointer forward.
|
||||
// Read a byte from current read pointer and move the read pointer by 1 byte in the read direction.
|
||||
retval = *mReadPointer;
|
||||
mReadPointer = Next(mReadPointer);
|
||||
mReadPointer = GetUpdatedBufPtr(mReadPointer, 1, mReadDirection);
|
||||
|
||||
// Check if at end of current segment.
|
||||
if (mReadPointer == mReadSegmentTail)
|
||||
@@ -508,7 +624,7 @@ uint8_t NcpFrameBuffer::OutFrameReadByte(void)
|
||||
|
||||
case kReadStateInMessage:
|
||||
|
||||
// Read a byte from current read pointer and move the read pointer forward.
|
||||
// Read a byte from current read pointer and move the read pointer by 1 byte.
|
||||
retval = *mReadPointer;
|
||||
mReadPointer++;
|
||||
|
||||
@@ -553,23 +669,25 @@ otError NcpFrameBuffer::OutFrameRemove(void)
|
||||
|
||||
VerifyOrExit(!IsEmpty(), error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
OutFrameSelectReadDirection();
|
||||
|
||||
// Save the frame start pointer as the tag associated with the frame being removed.
|
||||
tag = mReadFrameStart;
|
||||
tag = mReadFrameStart[mReadDirection];
|
||||
|
||||
// Begin at the start of current frame and move through all segments.
|
||||
|
||||
bufPtr = mReadFrameStart;
|
||||
bufPtr = mReadFrameStart[mReadDirection];
|
||||
|
||||
while (bufPtr != mWriteFrameStart)
|
||||
while (bufPtr != mWriteFrameStart[mReadDirection])
|
||||
{
|
||||
// Read the segment header
|
||||
header = ReadUint16At(bufPtr);
|
||||
header = ReadUint16At(bufPtr, mReadDirection);
|
||||
|
||||
// If the current segment defines a new frame, and it is not the start of current frame, then we have reached
|
||||
// end of current frame.
|
||||
if (header & kSegmentHeaderNewFrameFlag)
|
||||
{
|
||||
if (bufPtr != mReadFrameStart)
|
||||
if (bufPtr != mReadFrameStart[mReadDirection])
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -578,31 +696,55 @@ otError NcpFrameBuffer::OutFrameRemove(void)
|
||||
// If current segment has an appended message, remove it from message queue and free it.
|
||||
if (header & kSegmentHeaderMessageIndicatorFlag)
|
||||
{
|
||||
if ((message = otMessageQueueGetHead(&mMessageQueue)) != NULL)
|
||||
if ((message = otMessageQueueGetHead(&mMessageQueue[mReadDirection])) != NULL)
|
||||
{
|
||||
otMessageQueueDequeue(&mMessageQueue, message);
|
||||
otMessageQueueDequeue(&mMessageQueue[mReadDirection], message);
|
||||
otMessageFree(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the pointer to next segment.
|
||||
bufPtr = Advance(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask));
|
||||
bufPtr = GetUpdatedBufPtr(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask), mReadDirection);
|
||||
}
|
||||
|
||||
mReadFrameStart = bufPtr;
|
||||
mReadFrameStart[mReadDirection] = bufPtr;
|
||||
|
||||
mReadState = kReadStateDone;
|
||||
UpdateReadWriteStartPointers();
|
||||
|
||||
mReadState = kReadStateNotActive;
|
||||
mReadFrameLength = kUnknownFrameLength;
|
||||
|
||||
if (mFrameRemovedCallback != NULL)
|
||||
{
|
||||
mFrameRemovedCallback(mFrameRemovedContext, tag, this);
|
||||
mFrameRemovedCallback(mFrameRemovedContext, tag, static_cast<Priority>(mReadDirection), this);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void NcpFrameBuffer::UpdateReadWriteStartPointers(void)
|
||||
{
|
||||
// If there is no fully written high priority frame, and not in middle of writing a new frame either.
|
||||
if (!HasFrame(kPriorityHigh) && !InFrameIsWriting(kPriorityHigh))
|
||||
{
|
||||
// Move the high priority pointers to be right behind the low priority start.
|
||||
mWriteFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mReadFrameStart[kPriorityLow], 1, kBackward);
|
||||
mReadFrameStart[kPriorityHigh] = mWriteFrameStart[kPriorityHigh];
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// If there is no fully written low priority frame, and not in middle of writing a new frame either.
|
||||
if (!HasFrame(kPriorityLow) && !InFrameIsWriting(kPriorityLow))
|
||||
{
|
||||
// Move the low priority pointers to be 1 byte after the high priority start.
|
||||
mWriteFrameStart[kPriorityLow] = GetUpdatedBufPtr(mReadFrameStart[kPriorityHigh], 1, kForward);
|
||||
mReadFrameStart[kPriorityLow] = mWriteFrameStart[kPriorityLow];
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t NcpFrameBuffer::OutFrameGetLength(void)
|
||||
{
|
||||
@@ -616,20 +758,22 @@ uint16_t NcpFrameBuffer::OutFrameGetLength(void)
|
||||
|
||||
VerifyOrExit(!IsEmpty(), frameLength = 0);
|
||||
|
||||
OutFrameSelectReadDirection();
|
||||
|
||||
// Calculate frame length by adding length of all segments and messages within the current frame.
|
||||
|
||||
bufPtr = mReadFrameStart;
|
||||
bufPtr = mReadFrameStart[mReadDirection];
|
||||
|
||||
while (bufPtr != mWriteFrameStart)
|
||||
while (bufPtr != mWriteFrameStart[mReadDirection])
|
||||
{
|
||||
// Read the segment header
|
||||
header = ReadUint16At(bufPtr);
|
||||
header = ReadUint16At(bufPtr, mReadDirection);
|
||||
|
||||
// If the current segment defines a new frame, and it is not the start of current frame, then we have reached
|
||||
// end of current frame.
|
||||
if (header & kSegmentHeaderNewFrameFlag)
|
||||
{
|
||||
if (bufPtr != mReadFrameStart)
|
||||
if (bufPtr != mReadFrameStart[mReadDirection])
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -639,8 +783,8 @@ uint16_t NcpFrameBuffer::OutFrameGetLength(void)
|
||||
if (header & kSegmentHeaderMessageIndicatorFlag)
|
||||
{
|
||||
message = (message == NULL) ?
|
||||
otMessageQueueGetHead(&mMessageQueue) :
|
||||
otMessageQueueGetNext(&mMessageQueue, message);
|
||||
otMessageQueueGetHead(&mMessageQueue[mReadDirection]) :
|
||||
otMessageQueueGetNext(&mMessageQueue[mReadDirection], message);
|
||||
|
||||
if (message != NULL)
|
||||
{
|
||||
@@ -652,22 +796,27 @@ uint16_t NcpFrameBuffer::OutFrameGetLength(void)
|
||||
frameLength += (header & kSegmentHeaderLengthMask);
|
||||
|
||||
// Move the pointer to next segment.
|
||||
bufPtr = Advance(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask));
|
||||
bufPtr = GetUpdatedBufPtr(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask), mReadDirection);
|
||||
}
|
||||
|
||||
// Remember the calculated frame length for current frame.
|
||||
mReadFrameLength = frameLength;
|
||||
// Remember the calculated frame length for current active frame.
|
||||
if (mReadState != kReadStateNotActive)
|
||||
{
|
||||
mReadFrameLength = frameLength;
|
||||
}
|
||||
|
||||
exit:
|
||||
return frameLength;
|
||||
}
|
||||
|
||||
NcpFrameBuffer::FrameTag NcpFrameBuffer::OutFrameGetTag(void) const
|
||||
NcpFrameBuffer::FrameTag NcpFrameBuffer::OutFrameGetTag(void)
|
||||
{
|
||||
OutFrameSelectReadDirection();
|
||||
|
||||
// If buffer is empty use `kInvalidTag`, otherwise use the frame start pointer as the tag associated with
|
||||
// current out frame being read
|
||||
|
||||
return IsEmpty() ? kInvalidTag : mReadFrameStart;
|
||||
return IsEmpty() ? kInvalidTag : mReadFrameStart[mReadDirection];
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
+223
-104
@@ -39,11 +39,33 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
|
||||
/**
|
||||
* This class implements a buffer/queue for storing NCP frames.
|
||||
*
|
||||
* A frame can consist of a sequence of data bytes and/or the content of an `otMessage` or a combination of the two.
|
||||
* NcpFrameBuffer implements priority FIFO logic for storing and reading frames. Two priority levels of high and low
|
||||
* are supported. Within same priority level first-in-first-out order is preserved. High priority frames are read
|
||||
* ahead of the low priority ones.
|
||||
*
|
||||
*/
|
||||
class NcpFrameBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Defines the frame tag type. Frame tags can be compared with one another using operator `==`.
|
||||
* Defines the priority of frame. High priority frames are read before low priority frames. Within same priority
|
||||
* level FIFO order is preserved.
|
||||
*
|
||||
*/
|
||||
enum Priority
|
||||
{
|
||||
kPriorityLow = 0, //< Indicates low/normal priority for a frame.
|
||||
kPriorityHigh = 1, //< Indicates high priority for a frame.
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines the (abstract) frame tag type. Frame tags can be compared with one another using operator `==`.
|
||||
*
|
||||
*/
|
||||
typedef const void *FrameTag;
|
||||
@@ -58,18 +80,19 @@ public:
|
||||
* Defines a function pointer callback which is invoked to inform a change in `NcpFrameBuffer` either when a new
|
||||
* frame is added/written to `NcpFrameBuffer` or when a frame is removed from `NcpFrameBuffer`.
|
||||
*
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTag The tag associated with the frame which is added or removed.
|
||||
* @param[in] aNcpFrameBuffer A pointer to the `NcpFrameBuffer`.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
* @param[in] aTag The tag associated with the frame which is added or removed.
|
||||
* @param[in] aPriority The priority of frame.
|
||||
* @param[in] aNcpFrameBuffer A pointer to the `NcpFrameBuffer`.
|
||||
*
|
||||
*/
|
||||
typedef void (*BufferCallback)(void *aContext, FrameTag aTag, NcpFrameBuffer *aNcpFrameBuffer);
|
||||
typedef void (*BufferCallback)(void *aContext, FrameTag aTag, Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer);
|
||||
|
||||
/**
|
||||
* This constructor creates an NCP frame buffer.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to a buffer which will be used by NCP frame buffer.
|
||||
* @param[in] aBufferLength The buffer size (in bytes).
|
||||
* @param[in] aBuffer A pointer to a buffer which will be used by NCP frame buffer.
|
||||
* @param[in] aBufferLength The buffer size (in bytes).
|
||||
*
|
||||
*/
|
||||
NcpFrameBuffer(uint8_t *aBuffer, uint16_t aBufferLength);
|
||||
@@ -85,8 +108,8 @@ public:
|
||||
*
|
||||
* Subsequent calls to this method will overwrite the previous callback and its context.
|
||||
*
|
||||
* @param[in] aFrameAddedCallback Callback invoked when a new frame is successfully added to buffer.
|
||||
* @param[in] aFrameAddedContext A pointer to arbitrary context used with frame added callback.
|
||||
* @param[in] aFrameAddedCallback Callback invoked when a new frame is successfully added to buffer.
|
||||
* @param[in] aFrameAddedContext A pointer to arbitrary context used with frame added callback.
|
||||
*
|
||||
*/
|
||||
void SetFrameAddedCallback(BufferCallback aFrameAddedCallback, void *aFrameAddedContext);
|
||||
@@ -96,8 +119,8 @@ public:
|
||||
*
|
||||
* Subsequent calls to this method will overwrite the previous callback and its context.
|
||||
*
|
||||
* @param[in] aFrameRemovedCallback Callback invoked when a frame is removed from buffer.
|
||||
* @param[in] aFrameRemovedContext A pointer to arbitrary context used with frame removed callback.
|
||||
* @param[in] aFrameRemovedCallback Callback invoked when a frame is removed from buffer.
|
||||
* @param[in] aFrameRemovedContext A pointer to arbitrary context used with frame removed callback.
|
||||
*
|
||||
*/
|
||||
void SetFrameRemovedCallback(BufferCallback aFrameRemovedCallback, void *aFrameRemovedContext);
|
||||
@@ -105,40 +128,54 @@ public:
|
||||
/**
|
||||
* This method begins a new input frame to be added/written to the frame buffer.
|
||||
|
||||
* If there is a previous frame being written (`InFrameEnd()` has not yet been called on the frame), this method
|
||||
* will discard and clear the previous unfinished frame.
|
||||
* If there is a previous frame being written (for which `InFrameEnd()` has not yet been called), calling
|
||||
* `InFrameBegin()` will discard and clear the previous unfinished frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started a new frame.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame.
|
||||
* @param[in] aPriority Priority level of 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 InFrameBegin(void);
|
||||
otError InFrameBegin(Priority aPriority);
|
||||
|
||||
/**
|
||||
* This method adds data to the current input frame being written to the buffer.
|
||||
* This method adds data to the current input frame being written.
|
||||
*
|
||||
* If no buffer space is available, this method will discard and clear the frame before returning an error status.
|
||||
* 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`.
|
||||
*
|
||||
* @param[in] aDataBuffer A pointer to data buffer.
|
||||
* @param[in] aDataBufferLength The length of the data buffer.
|
||||
* If no buffer space is available, this method will discard and clear the current input frame being written before
|
||||
* returning the error status `OT_ERROR_NO_BUFS`.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added new data to the frame.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data.
|
||||
* @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.
|
||||
* @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame.
|
||||
*
|
||||
*/
|
||||
otError InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength);
|
||||
|
||||
/**
|
||||
* This method adds a message to the current input frame being written to the buffer.
|
||||
* This method adds a message to the current input frame being written.
|
||||
*
|
||||
* 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 frame before returning error status
|
||||
* `OT_ERROR_NO_BUFS`.
|
||||
*
|
||||
* If no buffer space is available, this method will discard and clear the frame before returning an error status.
|
||||
* 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.
|
||||
* 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.
|
||||
* @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 message.
|
||||
* @retval OT_ERROR_NONE Successfully added the message to the 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_ARGS If @p aMessage is NULL.
|
||||
*
|
||||
*/
|
||||
otError InFrameFeedMessage(otMessage *aMessage);
|
||||
@@ -146,10 +183,15 @@ public:
|
||||
/**
|
||||
* This method finalizes/ends the current input frame being written to the buffer.
|
||||
*
|
||||
* If no buffer space is available, this method will discard and clear the frame before returning an error status.
|
||||
* 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 frame before returning 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 add message.
|
||||
* @retval OT_ERROR_NONE Successfully added the message to the 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.
|
||||
*
|
||||
*/
|
||||
otError InFrameEnd(void);
|
||||
@@ -157,7 +199,7 @@ public:
|
||||
/**
|
||||
* This method returns the tag assigned to last successfully written/added frame to NcpBuffer (i.e., last input
|
||||
* frame for which `InFrameEnd()` was called and returned success status). The tag is a unique value (within
|
||||
* currently queued frames) associated with each frame in the `NcpFrameBuffer`. The tag can be used to identify the
|
||||
* currently queued frames) associated with a frame in the `NcpFrameBuffer`. The tag can be used to identify the
|
||||
* same frame when it is read and removed from the NcpBuffer. Tags can be compared using operator `==`.
|
||||
*
|
||||
* @returns The tag of last successfully written frame, or `kInvalidTag` if no frame is written so far.
|
||||
@@ -165,25 +207,28 @@ public:
|
||||
FrameTag InFrameGetLastTag(void) const;
|
||||
|
||||
/**
|
||||
* This method checks if the buffer is empty. An non-empty buffer contains at least one full frame for reading.
|
||||
* This method checks if the buffer is empty. A non-empty buffer contains at least one full frame for reading.
|
||||
*
|
||||
* @retval true Buffer is not empty and contains at least one full frame for reading.
|
||||
* @retval false Buffer is empty and contains no frame for reading.
|
||||
* @retval TRUE Buffer is not empty and contains at least one full frame for reading.
|
||||
* @retval FALSE Buffer is empty and contains no frame for reading.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const;
|
||||
|
||||
/**
|
||||
* This method begins/prepares a new output frame to be read from the frame buffer.
|
||||
* This method begins/prepares an output frame to be read from the frame buffer if there is no current active output
|
||||
* frame, or resets the read offset if there is a current active output frame.
|
||||
*
|
||||
* The NCP buffer maintains a read offset for the current frame being read. Before reading any bytes from the frame
|
||||
* this method should be called to prepare the frame and set the read offset.
|
||||
*
|
||||
* If part of current frame has already been read, a sub-sequent call to this method will reset the read offset
|
||||
* back to beginning of current output frame.
|
||||
* If part or even all of current frame has been read, a sub-sequent call to this method will reset the read
|
||||
* offset back to beginning of current output frame (note that the current output frame will remain unchanged even
|
||||
* in case where a higher priority frame was written to buffer while reading current output frame). A prepared
|
||||
* output frame will stay active as current output frame until it is explicitly removed using `OutFrameRemove()`.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started/prepared a new output frame for reading.
|
||||
* @retval OT_ERROR_NOT_FOUND No frame available in buffer for reading.
|
||||
* @retval OT_ERROR_NONE Successfully started/prepared a new output frame for reading.
|
||||
* @retval OT_ERROR_NOT_FOUND No frame available in buffer for reading.
|
||||
*
|
||||
*/
|
||||
otError OutFrameBegin(void);
|
||||
@@ -191,11 +236,13 @@ public:
|
||||
/**
|
||||
* This method checks if the current output frame (being read) has ended.
|
||||
*
|
||||
* The NCP buffer maintains a read offset for the current output frame being read. This method returns true if the
|
||||
* read offset is at the end of the frame and there are no more bytes available to read from current frame.
|
||||
* The NCP buffer maintains a read offset for the current output frame being read. This method returns `true` if
|
||||
* the read offset has reached the end of the frame and there are no more bytes available to read, or if there is
|
||||
* no currently active output frame.
|
||||
*
|
||||
* @retval true Frame has ended (no more bytes available to read from current output frame).
|
||||
* @retval false Frame has data (can read more bytes from current output frame).
|
||||
* @retval TRUE Frame has ended (no more bytes available to read from current output frame), or
|
||||
* there is currently no prepared/active output frame.
|
||||
* @retval FALSE Frame still has more data to read.
|
||||
*
|
||||
*/
|
||||
bool OutFrameHasEnded(void);
|
||||
@@ -207,72 +254,74 @@ public:
|
||||
* the next byte from the current frame and moves the read offset forward. If read offset is already at the end
|
||||
* current output frame, this method returns zero.
|
||||
*
|
||||
* @returns The next byte from the current output frame or zero if frame has ended.
|
||||
* @returns The next byte from the current output frame or zero if current output frame has ended or there is
|
||||
* prepared/active output from.
|
||||
*
|
||||
*/
|
||||
uint8_t OutFrameReadByte(void);
|
||||
|
||||
/**
|
||||
* This method reads bytes from the current output frame.
|
||||
* This method reads and copies bytes from the current output frame into a given buffer.
|
||||
*
|
||||
* The NCP buffer maintains a read offset for the current output frame being read. This method attempts to read
|
||||
* the given number of bytes (@p aDataBufferLength) from the current frame and copies the bytes into the given
|
||||
* data buffer (@p aDataBuffer). It also moves the read offset forward accordingly. If there are less bytes
|
||||
* remaining in current frame, the available bytes are read/copied. This methods returns the actual number of bytes
|
||||
* read.
|
||||
* data buffer (@p aDataBuffer). It also moves the read offset forward accordingly. If there are fewer bytes
|
||||
* remaining in current frame than the request @p aReadLength, the available bytes are read/copied. This methods
|
||||
* returns the actual number of bytes read.
|
||||
*
|
||||
* @param[in] aDataBuffer A pointer to a data buffer.
|
||||
* @param[in] aReadLength Number of bytes to read.
|
||||
* @param[in] aDataBuffer A pointer to a data buffer.
|
||||
* @param[in] aReadLength Number of bytes to read.
|
||||
*
|
||||
* @returns The number of bytes read and copied into data buffer.
|
||||
* @returns The number of bytes read and copied into data buffer.
|
||||
*
|
||||
*/
|
||||
uint16_t OutFrameRead(uint16_t aReadLength, uint8_t *aDataBuffer);
|
||||
|
||||
/**
|
||||
* This method removes the current/front output frame from the buffer.
|
||||
* This method removes the current or front output frame from the buffer.
|
||||
*
|
||||
* The NCP buffer stores the frames in FIFO order. This method removes the front frame (which may be the current
|
||||
* output frame being read) from the buffer. There is no need to prepare/begin reading the current frame before
|
||||
* removing it, so the front frame can be removed without a previous call to `OutFrameBegin()`.
|
||||
* If there is an active output from being read (an output frame was prepared earlier with a successful call to
|
||||
* `OutFrameBegin()`), this method removes the current active output frame. If there is no current active frame,
|
||||
* the front frame in the queue (the next frame which would have been read) will be removed.
|
||||
*
|
||||
* When a frame is removed all its associated messages will be freed.
|
||||
*
|
||||
* If the remove operation is successful, this method will invoke the `FrameRemovedCallback` (if provided).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully removed the front frame.
|
||||
* @retval OT_ERROR_NOT_FOUND No frame available in NCP frame buffer to remove.
|
||||
* @retval OT_ERROR_NONE Successfully removed the front frame.
|
||||
* @retval OT_ERROR_NOT_FOUND No frame available in NCP frame buffer to remove.
|
||||
*
|
||||
*/
|
||||
otError OutFrameRemove(void);
|
||||
|
||||
/**
|
||||
* This method returns the number of bytes (length) of current/front frame in the NCP frame buffer.
|
||||
* This method returns the number of bytes (length) of current or front frame in the NCP frame buffer.
|
||||
*
|
||||
* The NCP buffer stores the frames in FIFO order. This method returns the length of the front frame (which may
|
||||
* be the current output frame being read) from the buffer. There is no need to prepare/begin reading the current
|
||||
* frame before calling this method so this method can be used without a previous call to `OutFrameBegin()`.
|
||||
* If there is an active output from being read (an output frame was prepared earlier with successful call to
|
||||
* `OutFrameBegin()`), this method returns the length of the current output frame. If there is no current active
|
||||
* frame, the length of the front frame in the queue (the next frame which would have been read) will be returned.
|
||||
*
|
||||
* If there is no frame in buffer, this method returns zero.
|
||||
*
|
||||
* @returns The number of bytes (length) of current/front frame, or zero if no frame in buffer.
|
||||
* @returns The number of bytes (length) of current/front frame, or zero if no frame in buffer.
|
||||
*
|
||||
*/
|
||||
uint16_t OutFrameGetLength(void);
|
||||
|
||||
/**
|
||||
* This method returns the tag value associated to current/front frame in the NCP frame buffer.
|
||||
* This method returns the tag value associated to current or front frame in the NCP frame buffer.
|
||||
*
|
||||
* The NCP buffer stores the frames in FIFO order. This method returns the tag of the front frame (which may
|
||||
* be the current output frame being read) from the buffer. There is no need to prepare/begin reading the current
|
||||
* frame before calling this method so this method can be used without a previous call to `OutFrameBegin()`.
|
||||
* If there is an active output from being read (an output frame was prepared earlier with successful call to
|
||||
* `OutFrameBegin()`), this method returns the tag associated with current output frame. If there is no current
|
||||
* active frame, the tag associated with the front frame in the queue (the next frame which would have been read)
|
||||
* will be returned.
|
||||
*
|
||||
* If there is no frame in buffer, this method returns `kInvalidTag`.
|
||||
*
|
||||
* @returns The tag assigned to the current/from output frame, or `kInvalidTag` if no frame in buffer.
|
||||
* @returns The tag assigned to the current/from output frame, or `kInvalidTag` if no frame in buffer.
|
||||
*
|
||||
*/
|
||||
FrameTag OutFrameGetTag(void) const;
|
||||
FrameTag OutFrameGetTag(void);
|
||||
|
||||
private:
|
||||
|
||||
@@ -280,19 +329,20 @@ private:
|
||||
* NcpFrameBuffer Implementation
|
||||
* -----------------------------
|
||||
*
|
||||
* NcpFrameBuffer internally stores a frame as a sequence of data segments. The data segments are stored in the
|
||||
* the main buffer `mBuffer`. mBuffer is utilized as a circular buffer.
|
||||
* NcpFrameBuffer internally stores a frame as a sequence of data segments. Each segment stores a portion of frame.
|
||||
* The data segments are stored in the the main buffer `mBuffer`. mBuffer is utilized as a circular buffer.
|
||||
|
||||
* Messages (which are added using `InFrameFeedMessaged()`) are not copied in the `mBuffer` but instead are
|
||||
* enqueued in a message queue `mMessageQueue`.
|
||||
* The content of messages (which are added using `InFrameFeedMessage()`) are not directly copied in the `mBuffer`
|
||||
* but instead they are enqueued in a message queue `mMessageQueue`.
|
||||
*
|
||||
* The data segments include a header before the data portion. The header is 2 bytes long is formated as follows
|
||||
* Every data segments starts with a header before the data portion. The header is 2 bytes long with the following
|
||||
* format:
|
||||
*
|
||||
* Bit 0-13: Give the length of the data segment (max segment len is 2^14 = 16,384 bytes).
|
||||
* Bit 14: Flag bit set to indicate that this segment has an associated `Message` (appended to its end).
|
||||
* Bit 15: Flag bit set to indicate that this segment defines the start of a new frame.
|
||||
*
|
||||
* Bit 15 Bit 14 Bits: 0 - 13
|
||||
* Bit 15 Bit 14 Bits: 0 - 13
|
||||
* +--------------+--------------+--------------------------------------------------------+
|
||||
* | New Frame | Has Message | Length of segment (excluding the header) |
|
||||
* +--------------+--------------+--------------------------------------------------------+
|
||||
@@ -311,7 +361,7 @@ private:
|
||||
* This frame is stored as two segments:
|
||||
*
|
||||
* - Segment #1 contains "HelloThere" with a header of `0xC00A` which shows that this segment contains 10 data
|
||||
* bytes, and it starts a new frame, and also must include a message from the message queue.
|
||||
* bytes, and it starts a new frame, and also must includes an appended message from the message queue.
|
||||
*
|
||||
* - Segment #2 contains "Bye" with a header value of `0x0003` showing length of 3 and no appended message.
|
||||
*
|
||||
@@ -322,24 +372,77 @@ private:
|
||||
* Segment #1 Header Segment #2 Header
|
||||
*
|
||||
*
|
||||
* Buffer pointers:
|
||||
* NcpFrameBuffer uses the `mBuffer` as a circular/ring buffer. To support two frame priorities the buffer is
|
||||
* divided in two high-priority and low-priority regions. The high priority frames are stored in buffer in backward
|
||||
* direction while the low-priority frames use the buffer in forward direction. This model ensures the available
|
||||
* buffer space is utilized efficiently between all frame types.
|
||||
*
|
||||
* mReadFrameStart[kPriorityLow]
|
||||
* |
|
||||
* | mWriteFrameStart[kPriorityLow]
|
||||
* | |
|
||||
* V Low Priority Frames V
|
||||
* --------------+------------------------------+------------------------------+------------------
|
||||
* ... | <-------- | --------> | ...
|
||||
* --------------+------------------------------+------------------------------+------------------
|
||||
* ^ High Priority Frames ^
|
||||
* | |
|
||||
* | mReadFrameStart[kPriorityHigh]
|
||||
* |
|
||||
* mWriteFrameStart[kPriorityHigh]
|
||||
*
|
||||
*
|
||||
*
|
||||
* When frames are removed, if possible, the `mReadFrameStart` and `mWriteFrameStart` pointers of two priority
|
||||
* levels are moved closer to avoid gaps.
|
||||
*
|
||||
* For an output frame (frame being read), NcpFrameBuffer maintains a `ReadState` along with a set of pointers
|
||||
* into the buffer:
|
||||
*
|
||||
* mReadFrameStart[priority]: Start of current/front frame.
|
||||
* |
|
||||
* | mReadSegmentHead: Start of current segment of active output frame.
|
||||
* | |
|
||||
* | | mReadPointer: Pointer to next byte to read in current segment.
|
||||
* | | |
|
||||
* | | | mReadSegmentTail: End of current segment.
|
||||
* | | | |
|
||||
* V V V V
|
||||
* ---------+------------+--------------------------+------+----------------+-----------------------------------
|
||||
* ... | Segment 1 | Segment 2 | ... | Last Segment | ... (possible) next frame
|
||||
* ---------+------------+--------------------------+------+----------------+-----------------------------------
|
||||
* \ | | /
|
||||
* | \------------v-----------/ |
|
||||
* | Current Segment |
|
||||
* | |
|
||||
* \---------------------------V-----------------------------/
|
||||
* Current OutFrame (being read)
|
||||
*
|
||||
* Note that the diagram above shows the pointers for a low-priority frame (with pointers increasing in forward
|
||||
* direction).
|
||||
*
|
||||
* The `ReadState` indicates the state of current output frame and its read offset (e.g., read offset is in middle
|
||||
* of a segment or it is in an appended message, or we are done with entire frame).
|
||||
*
|
||||
* For a input frame (frame being written), the following pointers are maintained:
|
||||
*
|
||||
* mWriteFrameWrite[priority]: Start of current/next frame being written.
|
||||
* |
|
||||
* | mWriteSegmentHead: Start of current segment of active input frame.
|
||||
* | |
|
||||
* | | mWriteSegmentTail: Pointer to next byte to write in current segment.
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* V V V
|
||||
* ------------------+------------------+-------------------------------------------------------------------
|
||||
* Previous Frames | Segment 1 | Segment 2 : . . .
|
||||
* ------------------+------------------+-------------------------------------------------------------------
|
||||
* \ /
|
||||
* | |
|
||||
* \------------------V-----------------/
|
||||
* Current InFrame (being written)
|
||||
*
|
||||
* mReadFrameStart
|
||||
* |
|
||||
* | mReadSegmentHead mWriteFrameStart
|
||||
* | | |
|
||||
* | | mReadPointer | mWriteSegmentHead
|
||||
* | | | | |
|
||||
* mBuffer | | | mReadSegmentTail | | mWriteSegmentTail mBufferEnd
|
||||
* | | | | | | | | |
|
||||
* V V V V V V V V V
|
||||
* +-------+---------+---------+-------+--------------------------+---------+---------+----------------------+-
|
||||
* | ... | Seg 1 | Seg 2 | Seg 3 | . . . | Seg 1 | Seg 2 : . . . |
|
||||
* +-------+---------+---------+-------+---------------------------+---------+--------+----------------------+-
|
||||
* \ \ / / \ /
|
||||
* | Cur segment | | |
|
||||
* | | | |
|
||||
* Current OutFrame (being read) Current InFrame (being written)
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -354,29 +457,43 @@ private:
|
||||
kSegmentHeaderNoFlag = 0, // No flags are set.
|
||||
kSegmentHeaderNewFrameFlag = (1 << 15), // Indicates that this segment starts a new frame.
|
||||
kSegmentHeaderMessageIndicatorFlag = (1 << 14), // Indicates this segment ends with a Message.
|
||||
|
||||
kNumPrios = (kPriorityHigh + 1), // Number of priorities.
|
||||
};
|
||||
|
||||
enum ReadState
|
||||
{
|
||||
kReadStateInSegment, // In middle of a data segment while reading current (out) frame.
|
||||
kReadStateInMessage, // In middle of a message while reading current (out) frame.
|
||||
kReadStateDone, // Current (out) frame is read fully.
|
||||
kReadStateNotActive, // No current prepared out frame.
|
||||
kReadStateInSegment, // In middle of a data segment while reading current frame.
|
||||
kReadStateInMessage, // In middle of a message while reading current frame.
|
||||
kReadStateDone, // Current (out) frame is read fully.
|
||||
};
|
||||
|
||||
enum Direction
|
||||
{
|
||||
kForward = kPriorityLow,
|
||||
kBackward = kPriorityHigh,
|
||||
kUnknown,
|
||||
};
|
||||
|
||||
// Private methods
|
||||
|
||||
uint8_t * Next(uint8_t *aBufferPtr) const;
|
||||
uint8_t * Advance(uint8_t *aBufPtr, uint16_t aOffset) const;
|
||||
uint16_t GetDistance(uint8_t *aStartPtr, uint8_t *aEndPtr) const;
|
||||
uint8_t * GetUpdatedBufPtr(uint8_t *aBufPtr, uint16_t aOffset, Direction aDirection) const;
|
||||
uint16_t GetDistance(uint8_t *aStartPtr, uint8_t *aEndPtr, Direction aDirection) const;
|
||||
|
||||
uint16_t ReadUint16At(uint8_t *aBufPtr);
|
||||
void WriteUint16At(uint8_t *aBufPtr, uint16_t aValue);
|
||||
uint16_t ReadUint16At(uint8_t *aBufPtr, Direction aDirection);
|
||||
void WriteUint16At(uint8_t *aBufPtr, uint16_t aValue, Direction aDirection);
|
||||
|
||||
bool HasFrame(Priority aPriority) const;
|
||||
void UpdateReadWriteStartPointers(void);
|
||||
|
||||
otError InFrameFeedByte(uint8_t aByte);
|
||||
otError InFrameBeginSegment(void);
|
||||
void InFrameEndSegment(uint16_t aSegmentHeaderFlags);
|
||||
void InFrameDiscard(void);
|
||||
bool InFrameIsWriting(Priority aPriority) const;
|
||||
|
||||
void OutFrameSelectReadDirection(void);
|
||||
otError OutFramePrepareSegment(void);
|
||||
void OutFrameMoveToNextSegment(void);
|
||||
otError OutFramePrepareMessage(void);
|
||||
@@ -391,18 +508,20 @@ private:
|
||||
BufferCallback mFrameRemovedCallback; // Callback to signal when a frame is removed.
|
||||
void * mFrameRemovedContext; // Context passed to `mFrameRemovedCallback`.
|
||||
|
||||
otMessageQueue mMessageQueue; // Main message queue.
|
||||
otMessageQueue mMessageQueue[kNumPrios]; // Main message queues.
|
||||
|
||||
Direction mWriteDirection; // Direction (priority) for current frame being read.
|
||||
otMessageQueue mWriteFrameMessageQueue; // Message queue for the current frame being written.
|
||||
uint8_t * mWriteFrameStart; // Pointer to start of current frame being written.
|
||||
uint8_t * mWriteFrameStart[kNumPrios]; // Pointer to start of current frame being written.
|
||||
uint8_t * mWriteSegmentHead; // Pointer to start of current segment in the frame being written.
|
||||
uint8_t * mWriteSegmentTail; // Pointer to end of current segment in the frame being written.
|
||||
FrameTag mWriteFrameTag; // Tag associated with last successfully written frame.
|
||||
|
||||
Direction mReadDirection; // Direction (priority) for current frame being read.
|
||||
ReadState mReadState; // Read state.
|
||||
uint16_t mReadFrameLength; // Length of current frame being read.
|
||||
|
||||
uint8_t * mReadFrameStart; // Pointer to start of current frame being read.
|
||||
uint8_t * mReadFrameStart[kNumPrios]; // Pointer to start of current frame being read.
|
||||
uint8_t * mReadSegmentHead; // Pointer to start of current segment in the frame being read.
|
||||
uint8_t * mReadSegmentTail; // Pointer to end of current segment in the frame being read.
|
||||
uint8_t * mReadPointer; // Pointer to next byte to read (either in segment or in msg buffer).
|
||||
|
||||
+3
-1
@@ -246,10 +246,12 @@ void NcpSpi::SpiTransactionProcess(void)
|
||||
}
|
||||
}
|
||||
|
||||
void NcpSpi::HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer *aNcpFrameBuffer)
|
||||
void NcpSpi::HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag aTag,
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aNcpFrameBuffer);
|
||||
OT_UNUSED_VARIABLE(aTag);
|
||||
OT_UNUSED_VARIABLE(aPriority);
|
||||
|
||||
static_cast<NcpSpi *>(aContext)->mPrepareTxFrameTask.Post();
|
||||
}
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ private:
|
||||
void SpiTransactionProcess(void);
|
||||
|
||||
static void HandleFrameAddedToTxBuffer(void *aContext, NcpFrameBuffer::FrameTag aFrameTag,
|
||||
NcpFrameBuffer *aNcpFrameBuffer);
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer);
|
||||
|
||||
static void PrepareTxFrame(Tasklet &aTasklet);
|
||||
void PrepareTxFrame(void);
|
||||
|
||||
@@ -106,10 +106,11 @@ NcpUart::NcpUart(otInstance *aInstance):
|
||||
}
|
||||
|
||||
void NcpUart::HandleFrameAddedToNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aTag,
|
||||
NcpFrameBuffer *aNcpFrameBuffer)
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aNcpFrameBuffer);
|
||||
OT_UNUSED_VARIABLE(aTag);
|
||||
OT_UNUSED_VARIABLE(aPriority);
|
||||
|
||||
static_cast<NcpUart *>(aContext)->HandleFrameAddedToNcpBuffer();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ private:
|
||||
static void HandleFrame(void *context, uint8_t *aBuf, uint16_t aBufLength);
|
||||
static void HandleError(void *context, otError aError, uint8_t *aBuf, uint16_t aBufLength);
|
||||
static void HandleFrameAddedToNcpBuffer(void *aContext, NcpFrameBuffer::FrameTag aTag,
|
||||
NcpFrameBuffer *aNcpFrameBuffer);
|
||||
NcpFrameBuffer::Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer);
|
||||
|
||||
Hdlc::Encoder mFrameEncoder;
|
||||
Hdlc::Decoder mFrameDecoder;
|
||||
|
||||
+409
-108
@@ -42,9 +42,10 @@ namespace ot {
|
||||
|
||||
// This module implements unit-test for NcpFrameBuffer class.
|
||||
|
||||
// Test related constants:
|
||||
enum
|
||||
{
|
||||
kTestBufferSize = 2500,
|
||||
kTestBufferSize = 800,
|
||||
kTestIterationAttemps = 10000,
|
||||
kTagArraySize = 1000,
|
||||
};
|
||||
@@ -66,36 +67,54 @@ struct CallbackContext
|
||||
|
||||
CallbackContext sContext;
|
||||
|
||||
NcpFrameBuffer::FrameTag sTagHistoryArray[kTagArraySize];
|
||||
uint32_t sTagHistoryHead = 0;
|
||||
uint32_t sTagHistoryTail = 0;
|
||||
enum
|
||||
{
|
||||
kNumPrios = 2, // Number of priority levels.
|
||||
|
||||
kTestFrame1Size = sizeof(sMottoText) + sizeof(sMysteryText) + sizeof(sMottoText) + sizeof(sHelloText),
|
||||
kTestFrame2Size = sizeof(sMysteryText) + sizeof(sHelloText) + sizeof(sOpenThreadText),
|
||||
kTestFrame3Size = sizeof(sMysteryText),
|
||||
kTestFrame4Size = sizeof(sOpenThreadText),
|
||||
};
|
||||
|
||||
NcpFrameBuffer::FrameTag sTagHistoryArray[kNumPrios][kTagArraySize];
|
||||
uint32_t sTagHistoryHead[kNumPrios] = {0};
|
||||
uint32_t sTagHistoryTail[kNumPrios] = {0};
|
||||
NcpFrameBuffer::FrameTag sExpectedRemovedTag = NcpFrameBuffer::kInvalidTag;
|
||||
|
||||
void ClearTagHistory(void)
|
||||
{
|
||||
sTagHistoryHead = sTagHistoryTail;
|
||||
for (uint8_t priority = 0; priority < kNumPrios; priority++)
|
||||
{
|
||||
sTagHistoryHead[priority] = sTagHistoryTail[priority];
|
||||
}
|
||||
}
|
||||
|
||||
void AddTagToHistory(NcpFrameBuffer::FrameTag aTag)
|
||||
void AddTagToHistory(NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
sTagHistoryArray[sTagHistoryTail] = aTag;
|
||||
uint8_t priority = static_cast<uint8_t>(aPriority);
|
||||
|
||||
if (++sTagHistoryTail == kTagArraySize)
|
||||
sTagHistoryArray[priority][sTagHistoryTail[priority]] = aTag;
|
||||
|
||||
if (++sTagHistoryTail[priority] == kTagArraySize)
|
||||
{
|
||||
sTagHistoryTail = 0;
|
||||
sTagHistoryTail[priority] = 0;
|
||||
}
|
||||
|
||||
VerifyOrQuit(sTagHistoryTail != sTagHistoryHead, "Ran out of space in `TagHistoryArray`, increase its size.");
|
||||
VerifyOrQuit(sTagHistoryTail[priority] != sTagHistoryHead[priority],
|
||||
"Ran out of space in `TagHistoryArray`, increase its size.");
|
||||
}
|
||||
|
||||
void VerifyAndRemoveTagFromHistory(NcpFrameBuffer::FrameTag aTag)
|
||||
void VerifyAndRemoveTagFromHistory(NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
VerifyOrQuit(sTagHistoryHead != sTagHistoryTail, "Tag history is empty,");
|
||||
VerifyOrQuit(aTag == sTagHistoryArray[sTagHistoryHead], "Removed tag does not match the added one");
|
||||
uint8_t priority = static_cast<uint8_t>(aPriority);
|
||||
|
||||
if (++sTagHistoryHead == kTagArraySize)
|
||||
VerifyOrQuit(sTagHistoryHead[priority] != sTagHistoryTail[priority], "Tag history is empty,");
|
||||
VerifyOrQuit(aTag == sTagHistoryArray[priority][sTagHistoryHead[priority]], "Removed tag does not match the added one");
|
||||
|
||||
if (++sTagHistoryHead[priority] == kTagArraySize)
|
||||
{
|
||||
sTagHistoryHead = 0;
|
||||
sTagHistoryHead[priority] = 0;
|
||||
}
|
||||
|
||||
if (sExpectedRemovedTag != NcpFrameBuffer::kInvalidTag)
|
||||
@@ -105,7 +124,8 @@ void VerifyAndRemoveTagFromHistory(NcpFrameBuffer::FrameTag aTag)
|
||||
}
|
||||
}
|
||||
|
||||
void FrameAddedCallback(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer *aNcpBuffer)
|
||||
void FrameAddedCallback(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer::Priority aPriority,
|
||||
NcpFrameBuffer *aNcpBuffer)
|
||||
{
|
||||
CallbackContext *callbackContext = reinterpret_cast<CallbackContext *>(aContext);
|
||||
|
||||
@@ -113,19 +133,22 @@ void FrameAddedCallback(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameB
|
||||
VerifyOrQuit(callbackContext != NULL, "Null context in the callback");
|
||||
VerifyOrQuit(aTag != NcpFrameBuffer::kInvalidTag, "Invalid tag in the callback");
|
||||
VerifyOrQuit(aTag == aNcpBuffer->InFrameGetLastTag(), "InFrameGetLastTag() does not match the tag from callback");
|
||||
AddTagToHistory(aTag);
|
||||
|
||||
AddTagToHistory(aTag, aPriority);
|
||||
|
||||
callbackContext->mFrameAddedCount++;
|
||||
}
|
||||
|
||||
void FrameRemovedCallback(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer *aNcpBuffer)
|
||||
void FrameRemovedCallback(void *aContext, NcpFrameBuffer::FrameTag aTag, NcpFrameBuffer::Priority aPriority,
|
||||
NcpFrameBuffer *aNcpBuffer)
|
||||
{
|
||||
CallbackContext *callbackContext = reinterpret_cast<CallbackContext *>(aContext);
|
||||
|
||||
VerifyOrQuit(aNcpBuffer != NULL, "Null NcpFrameBuffer in the callback");
|
||||
VerifyOrQuit(callbackContext != NULL, "Null context in the callback");
|
||||
VerifyOrQuit(aTag != NcpFrameBuffer::kInvalidTag, "Invalid tag in the callback");
|
||||
VerifyAndRemoveTagFromHistory(aTag);
|
||||
|
||||
VerifyAndRemoveTagFromHistory(aTag, aPriority);
|
||||
|
||||
callbackContext->mFrameRemovedCount++;
|
||||
}
|
||||
@@ -183,7 +206,7 @@ void ReadAndVerifyContent(NcpFrameBuffer &aNcpBuffer, const uint8_t *aContentBuf
|
||||
}
|
||||
}
|
||||
|
||||
void WriteTestFrame1(NcpFrameBuffer &aNcpBuffer)
|
||||
void WriteTestFrame1(NcpFrameBuffer &aNcpBuffer, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
Message *message;
|
||||
CallbackContext oldContext;
|
||||
@@ -194,13 +217,12 @@ void WriteTestFrame1(NcpFrameBuffer &aNcpBuffer)
|
||||
message->Write(0, sizeof(sMottoText), sMottoText);
|
||||
|
||||
oldContext = sContext;
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(), "InFrameBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(aPriority), "InFrameBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sMottoText, sizeof(sMottoText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sMysteryText, sizeof(sMysteryText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedMessage(message), "InFrameFeedMessage() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sHelloText, sizeof(sHelloText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount + 1 == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
VerifyOrQuit(oldContext.mFrameRemovedCount == sContext.mFrameRemovedCount, "FrameRemovedCallback failed.");
|
||||
}
|
||||
@@ -210,27 +232,24 @@ void VerifyAndRemoveFrame1(NcpFrameBuffer &aNcpBuffer)
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
sExpectedRemovedTag = aNcpBuffer.OutFrameGetTag();
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(sExpectedRemovedTag == aNcpBuffer.OutFrameGetTag(), "OutFrameGetTag() value changed unexpectedly.");
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sMottoText) + sizeof(sMysteryText) + sizeof(sMottoText)
|
||||
+ sizeof(sHelloText), "GetLength() is incorrect.");
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(aNcpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(aNcpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
ReadAndVerifyContent(aNcpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(aNcpBuffer, sHelloText, sizeof(sHelloText));
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameReadByte() == 0, "ReadByte() returned non-zero after end of frame.");
|
||||
VerifyOrQuit(sExpectedRemovedTag == aNcpBuffer.OutFrameGetTag(), "OutFrameGetTag() value changed unexpectedly.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameRemove(), "Remove() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
VerifyOrQuit(oldContext.mFrameRemovedCount + 1 == sContext.mFrameRemovedCount, "FrameRemovedCallback failed.");
|
||||
}
|
||||
|
||||
void WriteTestFrame2(NcpFrameBuffer &aNcpBuffer)
|
||||
void WriteTestFrame2(NcpFrameBuffer &aNcpBuffer, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
Message *message1;
|
||||
Message *message2;
|
||||
@@ -246,7 +265,7 @@ void WriteTestFrame2(NcpFrameBuffer &aNcpBuffer)
|
||||
SuccessOrQuit(message2->SetLength(sizeof(sHelloText)), "Could not set the length of message.");
|
||||
message2->Write(0, sizeof(sHelloText), sHelloText);
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(aPriority), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedMessage(message1), "InFrameFeedMessage() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sOpenThreadText, sizeof(sOpenThreadText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedMessage(message2), "InFrameFeedMessage() failed.");
|
||||
@@ -260,25 +279,23 @@ void VerifyAndRemoveFrame2(NcpFrameBuffer &aNcpBuffer)
|
||||
{
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame2Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sMysteryText) + sizeof(sHelloText) + sizeof(sOpenThreadText),
|
||||
"GetLength() is incorrect.");
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame2Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(aNcpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
ReadAndVerifyContent(aNcpBuffer, sOpenThreadText, sizeof(sOpenThreadText));
|
||||
ReadAndVerifyContent(aNcpBuffer, sHelloText, sizeof(sHelloText));
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameReadByte() == 0, "ReadByte() returned non-zero after end of frame.");
|
||||
sExpectedRemovedTag = aNcpBuffer.OutFrameGetTag();
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == kTestFrame2Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameRemove(), "Remove() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
VerifyOrQuit(oldContext.mFrameRemovedCount + 1 == sContext.mFrameRemovedCount, "FrameRemovedCallback failed.");
|
||||
}
|
||||
|
||||
void WriteTestFrame3(NcpFrameBuffer &aNcpBuffer)
|
||||
void WriteTestFrame3(NcpFrameBuffer &aNcpBuffer, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
Message *message1;
|
||||
CallbackContext oldContext = sContext;
|
||||
@@ -289,7 +306,7 @@ void WriteTestFrame3(NcpFrameBuffer &aNcpBuffer)
|
||||
// An empty message with no content.
|
||||
SuccessOrQuit(message1->SetLength(0), "Could not set the length of message.");
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(aPriority), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedMessage(message1), "InFrameFeedMessage() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sMysteryText, sizeof(sMysteryText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
@@ -302,15 +319,44 @@ void VerifyAndRemoveFrame3(NcpFrameBuffer &aNcpBuffer)
|
||||
{
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sMysteryText), "GetLength() is incorrect.");
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sMysteryText), "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(aNcpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameReadByte() == 0, "ReadByte() returned non-zero after end of frame.");
|
||||
sExpectedRemovedTag = aNcpBuffer.OutFrameGetTag();
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sMysteryText), "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameRemove(), "Remove() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
VerifyOrQuit(oldContext.mFrameRemovedCount + 1 == sContext.mFrameRemovedCount, "FrameRemovedCallback failed.");
|
||||
}
|
||||
|
||||
void WriteTestFrame4(NcpFrameBuffer &aNcpBuffer, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.InFrameBegin(aPriority), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameFeedData(sOpenThreadText, sizeof(sOpenThreadText)), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(aNcpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount + 1 == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
VerifyOrQuit(oldContext.mFrameRemovedCount == sContext.mFrameRemovedCount, "FrameRemovedCallback failed.");
|
||||
}
|
||||
|
||||
void VerifyAndRemoveFrame4(NcpFrameBuffer &aNcpBuffer)
|
||||
{
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sOpenThreadText), "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sOpenThreadText), "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(aNcpBuffer, sOpenThreadText, sizeof(sOpenThreadText));
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameReadByte() == 0, "ReadByte() returned non-zero after end of frame.");
|
||||
sExpectedRemovedTag = aNcpBuffer.OutFrameGetTag();
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == sizeof(sOpenThreadText), "GetLength() is incorrect.");
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameRemove(), "Remove() failed.");
|
||||
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
@@ -352,21 +398,47 @@ void TestNcpFrameBuffer(void)
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetTag() == NcpFrameBuffer::kInvalidTag, "Incorrect OutFrameTag after init.");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 2: Write a frame 1 ");
|
||||
printf("\nTest 2: Write and read a single frame");
|
||||
|
||||
WriteTestFrame1(ncpBuffer);
|
||||
DumpBuffer("\nBuffer after frame1", buffer, kTestBufferSize);
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
DumpBuffer("\nBuffer after frame1 (low priority)", buffer, kTestBufferSize);
|
||||
printf("\nFrameLen is %u", ncpBuffer.OutFrameGetLength());
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
DumpBuffer("\nBuffer after frame1 (high priority)", buffer, kTestBufferSize);
|
||||
printf("\nFrameLen is %u", ncpBuffer.OutFrameGetLength());
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
|
||||
printf("\nIterations: ");
|
||||
|
||||
// Repeat this multiple times.
|
||||
// Always add as low priority.
|
||||
for (j = 0; j < kTestIterationAttemps; j++)
|
||||
{
|
||||
printf("*");
|
||||
WriteTestFrame1(ncpBuffer);
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == false, "IsEmpty() is incorrect when buffer is non-empty");
|
||||
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() is incorrect when buffer is empty.");
|
||||
}
|
||||
|
||||
// Always add as high priority.
|
||||
for (j = 0; j < kTestIterationAttemps; j++)
|
||||
{
|
||||
printf("*");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == false, "IsEmpty() is incorrect when buffer is non-empty");
|
||||
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() is incorrect when buffer is empty.");
|
||||
}
|
||||
|
||||
// Every 5th add as high priority.
|
||||
for (j = 0; j < kTestIterationAttemps; j++)
|
||||
{
|
||||
printf("*");
|
||||
WriteTestFrame1(ncpBuffer, ((j % 5) == 0) ? NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == false, "IsEmpty() is incorrect when buffer is non-empty");
|
||||
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
@@ -376,12 +448,12 @@ void TestNcpFrameBuffer(void)
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 3: Multiple frames write and read ");
|
||||
printf("\nTest 3: Multiple frames write and read (same priority)");
|
||||
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame3(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
|
||||
DumpBuffer("\nBuffer after multiple frames", buffer, kTestBufferSize);
|
||||
|
||||
@@ -397,15 +469,15 @@ void TestNcpFrameBuffer(void)
|
||||
{
|
||||
printf("*");
|
||||
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame3(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame3(ncpBuffer);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
@@ -417,14 +489,75 @@ void TestNcpFrameBuffer(void)
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 4: Frame discard when buffer full and partial read restart");
|
||||
printf("\nTest 4: Multiple frames write and read (mixed priority)");
|
||||
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 5: Frame discard when buffer full and partial read restart");
|
||||
|
||||
printf("\nIterations: ");
|
||||
|
||||
for (j = 0; j < kTestIterationAttemps; j++)
|
||||
{
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
WriteTestFrame3(ncpBuffer);
|
||||
bool frame1IsHighPriority = ((j % 3) == 0);
|
||||
|
||||
ncpBuffer.InFrameBegin();
|
||||
printf("*");
|
||||
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
|
||||
ncpBuffer.InFrameBegin((j % 2) == 0 ? NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow);
|
||||
ncpBuffer.InFrameFeedData(sHelloText, sizeof(sHelloText));
|
||||
|
||||
message = sMessagePool->New(Message::kTypeIp6, 0);
|
||||
@@ -434,20 +567,11 @@ void TestNcpFrameBuffer(void)
|
||||
|
||||
ncpBuffer.InFrameFeedMessage(message);
|
||||
|
||||
// Now cause a restart the current frame and test if it's discarded ok.
|
||||
WriteTestFrame2(ncpBuffer);
|
||||
// Start writing a new frame in middle of an unfinished frame. Ensure the first one is discarded.
|
||||
WriteTestFrame1(ncpBuffer,
|
||||
frame1IsHighPriority ? NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow);
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
DumpBuffer("\nAfter frame gets discarded", buffer, kTestBufferSize);
|
||||
printf("\nIterations: ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("*");
|
||||
}
|
||||
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
|
||||
// Start reading few bytes from the frame
|
||||
ncpBuffer.OutFrameBegin();
|
||||
@@ -456,8 +580,17 @@ void TestNcpFrameBuffer(void)
|
||||
ncpBuffer.OutFrameReadByte();
|
||||
|
||||
// Now reset the read pointer and read/verify the frame from start.
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
if (frame1IsHighPriority)
|
||||
{
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
}
|
||||
|
||||
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() is incorrect when buffer is empty.");
|
||||
}
|
||||
@@ -465,9 +598,9 @@ void TestNcpFrameBuffer(void)
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 5: Clear() and empty buffer method tests");
|
||||
printf("\nTest 6: Clear() and empty buffer method tests");
|
||||
|
||||
WriteTestFrame1(ncpBuffer);
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
|
||||
ncpBuffer.Clear();
|
||||
ClearTagHistory();
|
||||
@@ -480,7 +613,7 @@ void TestNcpFrameBuffer(void)
|
||||
"Remove() returned incorrect error status when buffer is empty.");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == 0, "OutFrameGetLength() returned non-zero length when buffer is empty.");
|
||||
|
||||
WriteTestFrame1(ncpBuffer);
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() is incorrect when buffer is empty.");
|
||||
@@ -492,9 +625,9 @@ void TestNcpFrameBuffer(void)
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 6: OutFrameRead() in parts\n");
|
||||
printf("\nTest 7: OutFrameRead() in parts\n");
|
||||
|
||||
ncpBuffer.InFrameBegin();
|
||||
ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityLow);
|
||||
ncpBuffer.InFrameFeedData(sMottoText, sizeof(sMottoText));
|
||||
ncpBuffer.InFrameEnd();
|
||||
|
||||
@@ -512,8 +645,159 @@ void TestNcpFrameBuffer(void)
|
||||
}
|
||||
|
||||
VerifyOrQuit(readOffset == sizeof(sMottoText), "Read len does not match expected length.");
|
||||
|
||||
ncpBuffer.OutFrameRemove();
|
||||
|
||||
printf("\n -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 8: Remove a frame without reading it first");
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(ncpBuffer.OutFrameRemove(), "Remove() failed.");
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 9: Check length when front frame gets changed (a higher priority frame is added)");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame3Size, "GetLength() is incorrect.");
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\nTest 10: Active out frame remaining unchanged when a higher priority frame is written while reading it");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(ncpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(ncpBuffer, sHelloText, sizeof(sHelloText));
|
||||
VerifyOrQuit(ncpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
// Repeat test reversing frame priority orders.
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed unexpectedly.");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(ncpBuffer, sMysteryText, sizeof(sMysteryText));
|
||||
ReadAndVerifyContent(ncpBuffer, sMottoText, sizeof(sMottoText));
|
||||
ReadAndVerifyContent(ncpBuffer, sHelloText, sizeof(sHelloText));
|
||||
VerifyOrQuit(ncpBuffer.OutFrameHasEnded() == true, "Frame longer than expected.");
|
||||
WriteTestFrame3(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame4(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
VerifyOrQuit(ncpBuffer.OutFrameGetLength() == kTestFrame1Size, "GetLength() is incorrect.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame3(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\n Test 11: Read and remove in middle of an active input frame write");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityHigh), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, sizeof(sOpenThreadText)), "InFrameFeedData() failed.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
// Repeat the test reversing priorities
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityLow), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, sizeof(sOpenThreadText)), "InFrameFeedData() failed.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
// Repeat the test with same priorities
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityHigh), "InFrameFeedBegin() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, sizeof(sOpenThreadText)), "InFrameFeedData() failed.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
VerifyAndRemoveFrame4(ncpBuffer);
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\n Test 12: Check returned error status");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityHigh), "InFrameFeedBegin() failed.");
|
||||
VerifyOrQuit(ncpBuffer.InFrameFeedData(buffer, sizeof(buffer)) == OT_ERROR_NO_BUFS, "Incorrect error status");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty() failed.");
|
||||
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
// Ensure writes with starting `InFrameBegin()` fail
|
||||
VerifyOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, 1) == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
VerifyOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, 0) == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
VerifyOrQuit(ncpBuffer.InFrameFeedData(sOpenThreadText, 0) == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
VerifyOrQuit(ncpBuffer.InFrameEnd() == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
message = sMessagePool->New(Message::kTypeIp6, 0);
|
||||
VerifyOrQuit(message != NULL, "Null Message");
|
||||
SuccessOrQuit(message->SetLength(sizeof(sMysteryText)), "Could not set the length of message.");
|
||||
message->Write(0, sizeof(sMysteryText), sMysteryText);
|
||||
VerifyOrQuit(ncpBuffer.InFrameFeedMessage(message) == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
SuccessOrQuit(message->Free(), "Failed to free allocated message");
|
||||
VerifyOrQuit(ncpBuffer.InFrameEnd() == OT_ERROR_INVALID_STATE, "Incorrect error status");
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty(), "IsEmpty() failed");
|
||||
VerifyOrQuit(ncpBuffer.OutFrameBegin() == OT_ERROR_NOT_FOUND, "OutFrameBegin() failed on empty queue");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty(), "IsEmpty() failed");
|
||||
printf(" -- PASS\n");
|
||||
|
||||
printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
printf("\n Test 13: Ensure we can utilize the full buffer size when frames removed during write");
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityHigh), "InFrameBegin() failed.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
SuccessOrQuit(ncpBuffer.InFrameFeedData(buffer, sizeof(buffer) - 4), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
SuccessOrQuit(ncpBuffer.OutFrameRemove(), "OutFrameRemove() failed.");
|
||||
// Repeat the test with a low priority buffer write
|
||||
WriteTestFrame1(ncpBuffer, NcpFrameBuffer::kPriorityHigh);
|
||||
WriteTestFrame2(ncpBuffer, NcpFrameBuffer::kPriorityLow);
|
||||
SuccessOrQuit(ncpBuffer.InFrameBegin(NcpFrameBuffer::kPriorityLow), "InFrameBegin() failed.");
|
||||
VerifyAndRemoveFrame1(ncpBuffer);
|
||||
VerifyAndRemoveFrame2(ncpBuffer);
|
||||
SuccessOrQuit(ncpBuffer.InFrameFeedData(buffer, sizeof(buffer) - 4), "InFrameFeedData() failed.");
|
||||
SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed.");
|
||||
SuccessOrQuit(ncpBuffer.OutFrameRemove(), "OutFrameRemove() failed.");
|
||||
printf(" -- PASS\n");
|
||||
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
@@ -536,11 +820,12 @@ enum
|
||||
kLensArraySize = 500, // Size of "Lengths" array.
|
||||
kMaxFrameLen = 400, // Maximum frame length
|
||||
kReadProbability = 50, // Probability (in percent) to randomly choose to read vs write frame
|
||||
kHighPriorityProbablity = 20, // Probability (in percent) to write a high priority frame
|
||||
kUseTrueRandomNumberGenerator = 1, // To use true random number generator or not.
|
||||
};
|
||||
|
||||
uint8_t sFrameBuffer[kFuzTestBufferSize];
|
||||
uint32_t sFrameBufferTailIndex = 0;
|
||||
uint8_t sFrameBuffer[kNumPrios][kFuzTestBufferSize];
|
||||
uint32_t sFrameBufferTailIndex[kNumPrios] = {0};
|
||||
|
||||
uint32_t GetRandom(uint32_t max)
|
||||
{
|
||||
@@ -558,25 +843,26 @@ uint32_t GetRandom(uint32_t max)
|
||||
return value % max;
|
||||
}
|
||||
|
||||
otError WriteRandomFrame(uint32_t aLength, NcpFrameBuffer &aNcpBuffer)
|
||||
otError WriteRandomFrame(uint32_t aLength, NcpFrameBuffer &aNcpBuffer, NcpFrameBuffer::Priority aPriority)
|
||||
{
|
||||
otError error;
|
||||
uint8_t byte;
|
||||
uint8_t priority = static_cast<uint8_t>(aPriority);
|
||||
CallbackContext oldContext = sContext;
|
||||
uint32_t tail = sFrameBufferTailIndex;
|
||||
uint32_t tail = sFrameBufferTailIndex[priority];
|
||||
|
||||
SuccessOrExit(error = aNcpBuffer.InFrameBegin());
|
||||
SuccessOrExit(error = aNcpBuffer.InFrameBegin(aPriority));
|
||||
|
||||
while (aLength--)
|
||||
{
|
||||
byte = static_cast<uint8_t>(GetRandom(256));
|
||||
SuccessOrExit(error = aNcpBuffer.InFrameFeedData(&byte, sizeof(byte)));
|
||||
sFrameBuffer[tail++] = byte;
|
||||
sFrameBuffer[priority][tail++] = byte;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = aNcpBuffer.InFrameEnd());
|
||||
|
||||
sFrameBufferTailIndex = tail;
|
||||
sFrameBufferTailIndex[priority] = tail;
|
||||
|
||||
// check the callbacks
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount + 1 == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
@@ -586,7 +872,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError ReadRandomFrame(uint32_t aLength, NcpFrameBuffer &aNcpBuffer)
|
||||
otError ReadRandomFrame(uint32_t aLength, NcpFrameBuffer &aNcpBuffer, uint8_t priority)
|
||||
{
|
||||
CallbackContext oldContext = sContext;
|
||||
|
||||
@@ -594,13 +880,13 @@ otError ReadRandomFrame(uint32_t aLength, NcpFrameBuffer &aNcpBuffer)
|
||||
VerifyOrQuit(aNcpBuffer.OutFrameGetLength() == aLength, "OutFrameGetLength() does not match");
|
||||
|
||||
// Read and verify that the content is same as sFrameBuffer values...
|
||||
ReadAndVerifyContent(aNcpBuffer, sFrameBuffer, static_cast<uint16_t>(aLength));
|
||||
ReadAndVerifyContent(aNcpBuffer, sFrameBuffer[priority], static_cast<uint16_t>(aLength));
|
||||
sExpectedRemovedTag = aNcpBuffer.OutFrameGetTag();
|
||||
|
||||
SuccessOrQuit(aNcpBuffer.OutFrameRemove(), "OutFrameRemove failed");
|
||||
|
||||
sFrameBufferTailIndex -= aLength;
|
||||
memmove(sFrameBuffer, sFrameBuffer + aLength, sFrameBufferTailIndex);
|
||||
sFrameBufferTailIndex[priority] -= aLength;
|
||||
memmove(sFrameBuffer[priority], sFrameBuffer[priority] + aLength, sFrameBufferTailIndex[priority]);
|
||||
|
||||
// If successful check the callbacks
|
||||
VerifyOrQuit(oldContext.mFrameAddedCount == sContext.mFrameAddedCount, "FrameAddedCallback failed.");
|
||||
@@ -616,9 +902,9 @@ void TestFuzzNcpFrameBuffer(void)
|
||||
uint8_t buffer[kFuzTestBufferSize];
|
||||
NcpFrameBuffer ncpBuffer(buffer, kFuzTestBufferSize);
|
||||
|
||||
uint32_t lensArray[kLensArraySize]; // Keeps track of length of written frames so far
|
||||
uint32_t lensArrayStart;
|
||||
uint32_t lensArrayCount;
|
||||
uint32_t lensArray[kNumPrios][kLensArraySize]; // Keeps track of length of written frames so far
|
||||
uint32_t lensArrayStart[kNumPrios];
|
||||
uint32_t lensArrayCount[kNumPrios];
|
||||
|
||||
sInstance = testInitInstance();
|
||||
sMessagePool = &sInstance->mIp6.mMessagePool;
|
||||
@@ -626,8 +912,8 @@ void TestFuzzNcpFrameBuffer(void)
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
memset(lensArray, 0, sizeof(lensArray));
|
||||
lensArrayStart = 0;
|
||||
lensArrayCount = 0;
|
||||
memset(lensArrayStart, 0, sizeof(lensArrayStart));
|
||||
memset(lensArrayCount, 0, sizeof(lensArrayCount));
|
||||
|
||||
sContext.mFrameAddedCount = 0;
|
||||
sContext.mFrameRemovedCount = 0;
|
||||
@@ -640,11 +926,11 @@ void TestFuzzNcpFrameBuffer(void)
|
||||
{
|
||||
bool shouldRead;
|
||||
|
||||
if (lensArrayCount == 0)
|
||||
if (lensArrayCount[0] == 0 && lensArrayCount[1] == 0)
|
||||
{
|
||||
shouldRead = false;
|
||||
}
|
||||
else if (lensArrayCount == kLensArraySize - 1)
|
||||
else if (lensArrayCount[0] == kLensArraySize - 1 || lensArrayCount[1] == kLensArraySize - 1)
|
||||
{
|
||||
shouldRead = true;
|
||||
}
|
||||
@@ -656,25 +942,40 @@ void TestFuzzNcpFrameBuffer(void)
|
||||
|
||||
if (shouldRead)
|
||||
{
|
||||
uint32_t len = lensArray[lensArrayStart];
|
||||
uint32_t len;
|
||||
uint8_t priority;
|
||||
|
||||
lensArrayStart = (lensArrayStart + 1) % kLensArraySize;
|
||||
lensArrayCount--;
|
||||
priority = (lensArrayCount[NcpFrameBuffer::kPriorityHigh] != 0) ?
|
||||
NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow;
|
||||
|
||||
printf("R%d ", len);
|
||||
len = lensArray[priority][lensArrayStart[priority]];
|
||||
lensArrayStart[priority] = (lensArrayStart[priority] + 1) % kLensArraySize;
|
||||
lensArrayCount[priority]--;
|
||||
|
||||
SuccessOrQuit(ReadRandomFrame(len, ncpBuffer), "Failed to read random frame.");
|
||||
printf("R%c%d ", priority == NcpFrameBuffer::kPriorityHigh ? 'H' : 'L', len);
|
||||
|
||||
SuccessOrQuit(ReadRandomFrame(len, ncpBuffer, priority), "Failed to read random frame.");
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t len = GetRandom(kMaxFrameLen) + 1;
|
||||
NcpFrameBuffer::Priority priority;
|
||||
|
||||
if (WriteRandomFrame(len, ncpBuffer) == OT_ERROR_NONE)
|
||||
if (GetRandom(100) < kHighPriorityProbablity)
|
||||
{
|
||||
lensArray[(lensArrayStart + lensArrayCount) % kLensArraySize] = len;
|
||||
lensArrayCount++;
|
||||
priority = NcpFrameBuffer::kPriorityHigh;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = NcpFrameBuffer::kPriorityLow;
|
||||
}
|
||||
|
||||
printf("W%d ", len);
|
||||
if (WriteRandomFrame(len, ncpBuffer, priority) == OT_ERROR_NONE)
|
||||
{
|
||||
lensArray[priority][(lensArrayStart[priority] + lensArrayCount[priority]) % kLensArraySize] = len;
|
||||
lensArrayCount[priority]++;
|
||||
|
||||
printf("W%c%d ", priority == NcpFrameBuffer::kPriorityHigh ? 'H' : 'L', len);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -682,7 +983,7 @@ void TestFuzzNcpFrameBuffer(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (lensArrayCount == 0)
|
||||
if (lensArrayCount[0] == 0 && lensArrayCount[1] == 0)
|
||||
{
|
||||
VerifyOrQuit(ncpBuffer.IsEmpty() == true, "IsEmpty failed.");
|
||||
printf("EMPTY ");
|
||||
|
||||
+16
-18
@@ -43,25 +43,23 @@ extern "C" {
|
||||
// Enable main functions
|
||||
#define ENABLE_TEST_MAIN
|
||||
|
||||
#define SuccessOrQuit(ERR, MSG) \
|
||||
do { \
|
||||
if ((ERR) != OT_ERROR_NONE) \
|
||||
{ \
|
||||
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
|
||||
fputs(MSG, stderr); \
|
||||
exit(-1); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SuccessOrQuit(ERR, MSG) \
|
||||
do { \
|
||||
if ((ERR) != OT_ERROR_NONE) \
|
||||
{ \
|
||||
fprintf(stderr, "\nFAILED %s:%d - %s\n", __FUNCTION__, __LINE__, MSG); \
|
||||
exit(-1); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define VerifyOrQuit(TST, MSG) \
|
||||
do { \
|
||||
if (!(TST)) \
|
||||
{ \
|
||||
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
|
||||
fputs(MSG, stderr); \
|
||||
exit(-1); \
|
||||
} \
|
||||
} while (0)
|
||||
#define VerifyOrQuit(TST, MSG) \
|
||||
do { \
|
||||
if (!(TST)) \
|
||||
{ \
|
||||
fprintf(stderr, "\nFAILED %s:%d - %s\n", __FUNCTION__, __LINE__, MSG); \
|
||||
exit(-1); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
//#define CompileTimeAssert(COND, MSG) typedef char __C_ASSERT__[(COND)?1:-1]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user