mirror of
https://github.com/espressif/openthread.git
synced 2026-09-06 09:10:04 +00:00
[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.
This commit is contained in:
committed by
Jonathan Hui
parent
4603e9907f
commit
fa1041f705
@@ -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;
|
||||
|
||||
+143
-50
@@ -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;
|
||||
|
||||
|
||||
@@ -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<uint16_t>(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<uint16_t>(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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user