From fa1041f70564b2a94845051d49c8e920196a14cd Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 19 Jul 2017 09:06:14 -0700 Subject: [PATCH] [ncp-buffer] support for saving write position and overwriting content (#2010) This commit adds new `InFrame` related methods to `NcpFrameBuffer` to allow user to get/save current write position in an input frame being written to the buffer. The saved position can later be used to overwrite the previously added content (using `InFrameOverwrite()`) or discard a portion of written data and move the write pointer back to the saved position (using `InFrameReset()`). The unit test for NCP buffer is also updated to add new test-cases specific for the newly added methods. --- src/ncp/ncp_buffer.cpp | 83 ++++++++++++++ src/ncp/ncp_buffer.hpp | 193 ++++++++++++++++++++++++--------- tests/unit/test_ncp_buffer.cpp | 93 ++++++++++++++++ 3 files changed, 319 insertions(+), 50 deletions(-) diff --git a/src/ncp/ncp_buffer.cpp b/src/ncp/ncp_buffer.cpp index d88561232..8cf79d167 100644 --- a/src/ncp/ncp_buffer.cpp +++ b/src/ncp/ncp_buffer.cpp @@ -382,6 +382,89 @@ exit: return error; } +otError NcpFrameBuffer::InFrameGetPosition(WritePosition &aPosition) const +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE); + + aPosition.mPosition = mWriteSegmentTail; + aPosition.mSegmentHead = mWriteSegmentHead; + +exit: + return error; +} + +otError NcpFrameBuffer::InFrameOverwrite(const WritePosition &aPosition, const uint8_t *aDataBuffer, + uint16_t aDataBufferLength) +{ + otError error = OT_ERROR_NONE; + uint8_t *bufPtr; + uint16_t segmentLength; + uint16_t distance; + + VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE); + + VerifyOrExit(aPosition.mSegmentHead == mWriteSegmentHead, error = OT_ERROR_INVALID_ARGS); + + // Ensure the overwrite does not go beyond current sgement tail. + segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection); + distance = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection); + VerifyOrExit(distance + aDataBufferLength <= segmentLength, error = OT_ERROR_INVALID_ARGS); + + bufPtr = aPosition.mPosition; + while (aDataBufferLength > 0) + { + *bufPtr = *aDataBuffer; + + aDataBuffer++; + aDataBufferLength--; + + bufPtr = GetUpdatedBufPtr(bufPtr, 1, mWriteDirection); + } + +exit: + return error; +} + +uint16_t NcpFrameBuffer::InFrameGetDistance(const WritePosition &aPosition) const +{ + uint16_t distance = 0; + uint16_t segmentLength; + uint16_t offset; + + VerifyOrExit(mWriteDirection != kUnknown); + VerifyOrExit(aPosition.mSegmentHead == mWriteSegmentHead); + + segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection); + offset = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection); + VerifyOrExit(offset < segmentLength); + + distance = GetDistance(aPosition.mPosition, mWriteSegmentTail, mWriteDirection); + +exit: + return distance; +} + +otError NcpFrameBuffer::InFrameReset(const WritePosition &aPosition) +{ + otError error = OT_ERROR_NONE; + uint16_t segmentLength; + uint16_t offset; + + VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE); + VerifyOrExit(aPosition.mSegmentHead == mWriteSegmentHead, error = OT_ERROR_INVALID_ARGS); + + segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection); + offset = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection); + VerifyOrExit(offset < segmentLength, error = OT_ERROR_INVALID_ARGS); + + mWriteSegmentTail = aPosition.mPosition; + +exit: + return error; +} + otError NcpFrameBuffer::InFrameEnd(void) { otMessage *message; diff --git a/src/ncp/ncp_buffer.hpp b/src/ncp/ncp_buffer.hpp index d185992ce..6d6c39c0e 100644 --- a/src/ncp/ncp_buffer.hpp +++ b/src/ncp/ncp_buffer.hpp @@ -44,9 +44,9 @@ 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 + * `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. + * ahead of any low priority ones. * */ class NcpFrameBuffer @@ -54,7 +54,7 @@ class NcpFrameBuffer public: /** - * Defines the priority of frame. High priority frames are read before low priority frames. Within same priority + * Defines the priority of a frame. High priority frames are read before low priority frames. Within same priority * level FIFO order is preserved. * */ @@ -65,17 +65,40 @@ public: }; /** - * Defines the (abstract) frame tag type. Frame tags can be compared with one another using operator `==`. + * Defines the (abstract) frame tag type. The tag is a unique value (within currently queued frames) associated + * with a frame in the `NcpFrameBuffer`. Frame tags can be compared with one another using operator `==`. * */ typedef const void *FrameTag; /** - * Defines the tag to indicate an invalid tag (e.g., when there is no frame). + * Defines the tag value indicating an invalid tag (e.g., when there is no frame). * */ static const FrameTag kInvalidTag; + /** + * Defines the structure to hold a write position for an input frame (frame being written). + * + * It should be considered as an opaque data structure to users of `NcpFrameBuffer`. + * + */ + struct WritePosition + { + public: + /** + * The constructor for a `WritePosition` object. + * + */ + WritePosition(void): mPosition(0), mSegmentHead(0) { } + + private: + uint8_t *mPosition; //< Pointer into buffer corresponding to saved write position. + uint8_t *mSegmentHead; //< Pointer to segment head. + + friend class NcpFrameBuffer; + }; + /** * 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`. @@ -89,7 +112,7 @@ public: typedef void (*BufferCallback)(void *aContext, FrameTag aTag, Priority aPriority, NcpFrameBuffer *aNcpFrameBuffer); /** - * This constructor creates an NCP frame buffer. + * This constructor initializes 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). @@ -104,7 +127,7 @@ public: void Clear(void); /** - * This method sets the `FrameAdded` callback and its context. + * This method sets the FrameAdded callback and its context. * * Subsequent calls to this method will overwrite the previous callback and its context. * @@ -115,7 +138,7 @@ public: void SetFrameAddedCallback(BufferCallback aFrameAddedCallback, void *aFrameAddedContext); /** - * This method sets the `FrameRemoved` callback and its context. + * This method sets the FrameRemoved callback and its context. * * Subsequent calls to this method will overwrite the previous callback and its context. * @@ -126,12 +149,12 @@ public: void SetFrameRemovedCallback(BufferCallback aFrameRemovedCallback, void *aFrameRemovedContext); /** - * This method begins a new input frame to be added/written to the frame buffer. + * This method begins a new input frame (InFrame) to be added/written to the frame buffer. * 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. * - * @param[in] aPriority Priority level of new input frame. + * @param[in] aPriority Priority level of the new input frame. * * @retval OT_ERROR_NONE Successfully started a new frame. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. @@ -140,13 +163,13 @@ public: otError InFrameBegin(Priority aPriority); /** - * This method adds data to the current input frame being written. + * This method adds data to the current input frame. * * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. * - * If no buffer space is available, this method will discard and clear the current input frame being written before - * returning the error status `OT_ERROR_NO_BUFS`. + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. * * @param[in] aDataBuffer A pointer to data buffer. * @param[in] aDataBufferLength The length of the data buffer. @@ -159,12 +182,12 @@ public: otError InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength); /** - * This method adds a message to the current input frame being written. + * This method adds a message to the current input frame. * * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. * - * If no buffer space is available, this method will discard and clear the frame before returning error status + * If no buffer space is available, this method will discard and clear the frame and return error status * `OT_ERROR_NO_BUFS`. * * In case of success, the passed-in message @p aMessage will be owned by the frame buffer instance and will be @@ -173,23 +196,94 @@ public: * @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_NO_BUFS Insufficient buffer space available to add the message. * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. * @retval OT_ERROR_INVALID_ARGS If @p aMessage is NULL. * */ otError InFrameFeedMessage(otMessage *aMessage); + /** + * This method gets the current write position in the input frame. + * + * The write position is returned in @p aPosition. The saved position can later be used to overwrite the frame + * content (using `InFrameOverwrite()`) or discard a portion of written frame and move the write pointer back to + * the saved position (using `InFrameReset()`). + * + * @param[out] aPosition A reference to a `WritePosition` to save the current write position. + * + * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. + * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. + * + */ + otError InFrameGetPosition(WritePosition &aPosition) const; + + /** + * This method overwrites the previously written content in the current input frame at a given write position. + * + * The write position @p aPostion must belong to the same input frame saved earlier with `InFrameGetPosition()`. + * This method does not allow writing beyond the current end of the input frame (i.e., it can only write over + * previously added content). If writing @p aDataBufferLength bytes from write position @p aPosition goes beyond + * the end, this method does not change the input frame and returns error status `OT_ERROR_INVALID_ARGS`. + * This method cannot be used if the input frame has an added `otMessage` (i.e., a previous call to + * `InFrameFeedMessage()`). + * + * @param[in] aPosition A reference to the write position. + * @param[in] aDataBuffer A pointer to data buffer. + * @param[in] aDataBufferLength The length of the data buffer. + * + * @retval OT_ERROR_NONE Successfully overwrote the data at the given write position. + * @retval OT_ERROR_INVALID_STATE No input frame (`InFrameBegin()` has not been called). + * @retval OT_ERROR_INVALID_ARGS The given write position is not valid (i.e., if it does not belong to same + * input frame), or the input frame has an added `otMessage`, or the write + * operation will go beyond the current end of the input frame. + * + */ + otError InFrameOverwrite(const WritePosition &aPosition, const uint8_t *aDataBuffer, uint16_t aDataBufferLength); + + /** + * This method resets the write position of input frame back to a previously saved position. Any previously + * added content after the write position is discarded. + * + * The write position @p aPosition must belong to the same input frame saved earlier with `InFrameGetPosition()`. + * This method cannot be used if the input frame has an added `otMessage` (i.e., a previous call to + * `InFrameFeedMessage()`). + * + * @param[in] aPosition A reference to write position + * + * @retval OT_ERROR_NONE Successfully reset the write position of current input frame.. + * @retval OT_ERROR_INVALID_STATE No input frame (`InFrameBegin()` has not been called). + * @retval OT_ERROR_INVALID_ARGS The given write position is not valid (does not belong to same input frame), or + * the input frame has an added `otMessage`. + * + */ + otError InFrameReset(const WritePosition &aPosition); + + /** + * This method gets the distance (number of bytes) from a given saved position to current end of frame. + * + * The write position @p aPosition must belong to the same input frame saved earlier with `InFrameGetPosition()`. + * This method cannot be used if the input frame has an added `otMessage` (i.e., a previous call to + * `InFrameFeedMessage()`). In case of invalid argument, this method returns zero. + * + * @param[in] aPosition A reference to write position + * + * @returns The distance (number of bytes) from a write position to current end of frame, or zero for invalid + * arguments. + * + */ + uint16_t InFrameGetDistance(const WritePosition &aPosition) const; + /** * This method finalizes/ends the current input frame being written to the buffer. * * 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 + * + * If no buffer space is available, this method will discard and clear the frame and return error status * `OT_ERROR_NO_BUFS`. * - * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NONE Successfully ended the input frame. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. * @@ -202,7 +296,7 @@ public: * 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. + * @returns The tag of the last successfully written frame, or `kInvalidTag` if no frame is written so far. */ FrameTag InFrameGetLastTag(void) const; @@ -266,8 +360,8 @@ public: * 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 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. + * remaining in current frame than the requested @p aReadLength, the available bytes are read/copied. This methods + * returns the number of bytes read from frame and copied into @p aDataBuffer. * * @param[in] aDataBuffer A pointer to a data buffer. * @param[in] aReadLength Number of bytes to read. @@ -286,7 +380,8 @@ public: * * 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). + * If the remove operation is successful, this method will invoke the `FrameRemovedCallback` (if not NULL) before + * returning the success state. * * @retval OT_ERROR_NONE Successfully removed the front frame. * @retval OT_ERROR_NOT_FOUND No frame available in NCP frame buffer to remove. @@ -326,11 +421,11 @@ public: private: /* - * NcpFrameBuffer Implementation - * ----------------------------- + * `NcpFrameBuffer` Implementation + * ------------------------------- * - * 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. + * `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. * 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`. @@ -360,22 +455,22 @@ 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 includes an appended message from the message queue. + * - Segment #1 contains "HelloThere" with a header value `0xC00A` which shows that this segment contains 10 + * data bytes, and it starts a new frame, and also 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. * * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ - * | C0 | 0A | `H` | 'e' | 'l' | 'l' | 'o' | 'T' | 'h' | 'e' | 'r' | 'e' | 00 | 03 | 'B' | 'y' | 'e' | + * | C0 | 0A | 'H' | 'e' | 'l' | 'l' | 'o' | 'T' | 'h' | 'e' | 'r' | 'e' | 00 | 03 | 'B' | 'y' | 'e' | * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ * \ / \ / * Segment #1 Header Segment #2 Header * * - * 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. + * `NcpFrameBuffer` uses the `mBuffer` as a circular/ring buffer. To support two frame priorities the buffer is + * divided into 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] * | @@ -393,19 +488,19 @@ private: * * * - * When frames are removed, if possible, the `mReadFrameStart` and `mWriteFrameStart` pointers of two priority + * When frames are removed, if possible, the `mReadFrameStart` and `mWriteFrameStart` pointers of the 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. + * mReadFrameStart[priority]: Start of the current/front frame. * | - * | mReadSegmentHead: Start of current segment of active output frame. + * | mReadSegmentHead: Start of the current segment. * | | - * | | mReadPointer: Pointer to next byte to read in current segment. + * | | mReadPointer: Pointer to the next byte to read. * | | | - * | | | mReadSegmentTail: End of current segment. + * | | | mReadSegmentTail: End of the current segment. * | | | | * V V V V * ---------+------------+--------------------------+------+----------------+----------------------------------- @@ -421,16 +516,16 @@ private: * 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). + * The `ReadState` indicates the state of current output frame and its read offset (e.g., if read offset is in + * middle of a segment or if it is is middle of an appended message, or if we are done with entire frame). * - * For a input frame (frame being written), the following pointers are maintained: + * For an input frame (frame being written), the following pointers are maintained: * - * mWriteFrameWrite[priority]: Start of current/next frame being written. + * mWriteFrameWrite[priority]: Start of the current/next frame being written. * | - * | mWriteSegmentHead: Start of current segment of active input frame. + * | mWriteSegmentHead: Start of the current segment of the active input frame. * | | - * | | mWriteSegmentTail: Pointer to next byte to write in current segment. + * | | mWriteSegmentTail: Pointer to the next byte to write. * | | | * | | | * | | | @@ -449,7 +544,7 @@ private: enum { kReadByteAfterFrameHasEnded = 0, // Value returned by ReadByte() when frame has ended. - kMessageReadBufferSize = 16, // Size of message buffer array. + kMessageReadBufferSize = 16, // Size of message buffer array `mMessageBuffer`. kUnknownFrameLength = 0xffff, // Value used when frame length is unknown. kSegmentHeaderSize = 2, // Length of the segment header. kSegmentHeaderLengthMask = 0x3fff, // Bit mask to get the length from the segment header @@ -463,10 +558,10 @@ private: enum ReadState { - kReadStateNotActive, // No current prepared out frame. + kReadStateNotActive, // No current prepared output 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. + kReadStateDone, // Current output frame is read fully. }; enum Direction @@ -476,8 +571,6 @@ private: kUnknown, }; - // Private methods - uint8_t * GetUpdatedBufPtr(uint8_t *aBufPtr, uint16_t aOffset, Direction aDirection) const; uint16_t GetDistance(uint8_t *aStartPtr, uint8_t *aEndPtr, Direction aDirection) const; diff --git a/tests/unit/test_ncp_buffer.cpp b/tests/unit/test_ncp_buffer.cpp index 1d08b581c..a2596254d 100644 --- a/tests/unit/test_ncp_buffer.cpp +++ b/tests/unit/test_ncp_buffer.cpp @@ -55,6 +55,7 @@ static const uint8_t sOpenThreadText[] = "OpenThread Rocks"; static const uint8_t sHelloText[] = "Hello there!"; static const uint8_t sMottoText[] = "Think good thoughts, say good words, do good deeds!"; static const uint8_t sMysteryText[] = "4871(\\):|(3$}{4|/4/2%14(\\)"; +static const uint8_t sHexText[] = "0123456789abcdef"; static otInstance *sInstance; static MessagePool *sMessagePool; @@ -373,6 +374,7 @@ void TestNcpFrameBuffer(void) Message *message; uint8_t readBuffer[16]; uint16_t readLen, readOffset; + NcpFrameBuffer::WritePosition pos1, pos2; sInstance = testInitInstance(); sMessagePool = &sInstance->mIp6.mMessagePool; @@ -798,6 +800,97 @@ void TestNcpFrameBuffer(void) SuccessOrQuit(ncpBuffer.OutFrameRemove(), "OutFrameRemove() failed."); printf(" -- PASS\n"); + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\n Test 14: Test InFrameOverwrite "); + printf("\nIterations: "); + + for (j = 0; j < kTestIterationAttemps; j++) + { + uint16_t index; + bool addExtra = ((j % 7) != 0); + NcpFrameBuffer::Priority priority; + + printf("*"); + priority = ((j % 3) == 0) ? NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow; + index = static_cast(j % sizeof(sHexText)); + SuccessOrQuit(ncpBuffer.InFrameBegin(priority), "InFrameBegin() failed"); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText, index), "InFrameFeedData() failed."); + SuccessOrQuit(ncpBuffer.InFrameGetPosition(pos1), "InFrameGetPosition() failed"); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sMysteryText, sizeof(sHexText) - index), "InFrameFeedData() failed."); + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index , "InFrameGetDistance() failed"); + + if (addExtra) + { + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHelloText, sizeof(sHelloText)), "InFrameFeedData() failed."); + } + + SuccessOrQuit(ncpBuffer.InFrameOverwrite(pos1, sHexText + index, sizeof(sHexText) - index), + "InFrameOverwrite() failed."); + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index + (addExtra ? sizeof(sHelloText) : 0), + "InFrameGetDistance() failed"); + SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed."); + VerifyOrQuit(ncpBuffer.InFrameGetPosition(pos2) == OT_ERROR_INVALID_STATE, "GetPosition failed."); + VerifyOrQuit(ncpBuffer.InFrameOverwrite(pos1, sHexText, 0) != OT_ERROR_NONE, "Failed to give error."); + SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed"); + ReadAndVerifyContent(ncpBuffer, sHexText, sizeof(sHexText)); + + if (addExtra) + { + ReadAndVerifyContent(ncpBuffer, sHelloText, sizeof(sHelloText)); + } + + SuccessOrQuit(ncpBuffer.OutFrameRemove(), "OutFrameRemove() failed"); + VerifyOrQuit(ncpBuffer.InFrameGetPosition(pos2) == OT_ERROR_INVALID_STATE, "GetPosition failed"); + } + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\n Test 15: Test InFrameReset()"); + printf("\nIterations: "); + + for (j = 0; j < kTestIterationAttemps; j++) + { + uint16_t index; + bool addExtra = ((j % 7) != 0); + NcpFrameBuffer::Priority priority; + + printf("*"); + priority = ((j % 3) == 0) ? NcpFrameBuffer::kPriorityHigh : NcpFrameBuffer::kPriorityLow; + index = static_cast(j % sizeof(sHexText)); + SuccessOrQuit(ncpBuffer.InFrameBegin(priority), "InFrameBegin() failed"); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText, index), "InFrameFeedData() failed."); + SuccessOrQuit(ncpBuffer.InFrameGetPosition(pos1), "InFrameGetPosition() failed"); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sMysteryText, sizeof(sHexText) - index), "InFrameFeedData() failed."); + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index , "InFrameGetDistance() failed"); + + if (addExtra) + { + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHelloText, sizeof(sHelloText)), "InFrameFeedData() failed."); + } + + SuccessOrQuit(ncpBuffer.InFrameReset(pos1), "InFrameReset() failed."); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText + index, sizeof(sHexText) - index), + "InFrameOverwrite() failed."); + + if (addExtra) + { + SuccessOrQuit(ncpBuffer.InFrameReset(pos1), "InFrameReset() failed."); + SuccessOrQuit(ncpBuffer.InFrameFeedData(sHexText + index, sizeof(sHexText) - index), + "InFrameOverwrite() failed."); + + } + + VerifyOrQuit(ncpBuffer.InFrameGetDistance(pos1) == sizeof(sHexText) - index, + "InFrameGetDistance() failed"); + SuccessOrQuit(ncpBuffer.InFrameEnd(), "InFrameEnd() failed."); + SuccessOrQuit(ncpBuffer.OutFrameBegin(), "OutFrameBegin() failed"); + ReadAndVerifyContent(ncpBuffer, sHexText, sizeof(sHexText)); + SuccessOrQuit(ncpBuffer.OutFrameRemove(), "OutFrameRemove() failed"); + } + + printf(" -- PASS\n"); + testFreeInstance(sInstance); }