1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2016, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker * All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker *
5*cfb92d14SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker * 3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker * names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker *
16*cfb92d14SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*cfb92d14SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*cfb92d14SAndroid Build Coastguard Worker * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*cfb92d14SAndroid Build Coastguard Worker * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20*cfb92d14SAndroid Build Coastguard Worker * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*cfb92d14SAndroid Build Coastguard Worker * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*cfb92d14SAndroid Build Coastguard Worker * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*cfb92d14SAndroid Build Coastguard Worker * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*cfb92d14SAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*cfb92d14SAndroid Build Coastguard Worker * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*cfb92d14SAndroid Build Coastguard Worker */
27*cfb92d14SAndroid Build Coastguard Worker
28*cfb92d14SAndroid Build Coastguard Worker /**
29*cfb92d14SAndroid Build Coastguard Worker * @file
30*cfb92d14SAndroid Build Coastguard Worker * This file implements NCP frame buffer class.
31*cfb92d14SAndroid Build Coastguard Worker */
32*cfb92d14SAndroid Build Coastguard Worker
33*cfb92d14SAndroid Build Coastguard Worker #include "spinel_buffer.hpp"
34*cfb92d14SAndroid Build Coastguard Worker
35*cfb92d14SAndroid Build Coastguard Worker #include <assert.h>
36*cfb92d14SAndroid Build Coastguard Worker
37*cfb92d14SAndroid Build Coastguard Worker #include "lib/utils/utils.hpp"
38*cfb92d14SAndroid Build Coastguard Worker
39*cfb92d14SAndroid Build Coastguard Worker namespace ot {
40*cfb92d14SAndroid Build Coastguard Worker namespace Spinel {
41*cfb92d14SAndroid Build Coastguard Worker
42*cfb92d14SAndroid Build Coastguard Worker const Buffer::FrameTag Buffer::kInvalidTag = nullptr;
43*cfb92d14SAndroid Build Coastguard Worker
Buffer(uint8_t * aBuffer,uint16_t aBufferLength)44*cfb92d14SAndroid Build Coastguard Worker Buffer::Buffer(uint8_t *aBuffer, uint16_t aBufferLength)
45*cfb92d14SAndroid Build Coastguard Worker : mBuffer(aBuffer)
46*cfb92d14SAndroid Build Coastguard Worker , mBufferEnd(aBuffer + aBufferLength)
47*cfb92d14SAndroid Build Coastguard Worker , mBufferLength(aBufferLength)
48*cfb92d14SAndroid Build Coastguard Worker {
49*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
50*cfb92d14SAndroid Build Coastguard Worker for (otMessageQueue &queue : mMessageQueue)
51*cfb92d14SAndroid Build Coastguard Worker {
52*cfb92d14SAndroid Build Coastguard Worker otMessageQueueInit(&queue);
53*cfb92d14SAndroid Build Coastguard Worker }
54*cfb92d14SAndroid Build Coastguard Worker
55*cfb92d14SAndroid Build Coastguard Worker otMessageQueueInit(&mWriteFrameMessageQueue);
56*cfb92d14SAndroid Build Coastguard Worker #endif
57*cfb92d14SAndroid Build Coastguard Worker
58*cfb92d14SAndroid Build Coastguard Worker SetFrameAddedCallback(nullptr, nullptr);
59*cfb92d14SAndroid Build Coastguard Worker SetFrameRemovedCallback(nullptr, nullptr);
60*cfb92d14SAndroid Build Coastguard Worker Clear();
61*cfb92d14SAndroid Build Coastguard Worker }
62*cfb92d14SAndroid Build Coastguard Worker
Clear(void)63*cfb92d14SAndroid Build Coastguard Worker void Buffer::Clear(void)
64*cfb92d14SAndroid Build Coastguard Worker {
65*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
66*cfb92d14SAndroid Build Coastguard Worker otMessage *message;
67*cfb92d14SAndroid Build Coastguard Worker #endif
68*cfb92d14SAndroid Build Coastguard Worker
69*cfb92d14SAndroid Build Coastguard Worker // Write (InFrame) related variables
70*cfb92d14SAndroid Build Coastguard Worker mWriteFrameStart[kPriorityLow] = mBuffer;
71*cfb92d14SAndroid Build Coastguard Worker mWriteFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mBuffer, 1, kBackward);
72*cfb92d14SAndroid Build Coastguard Worker mWriteDirection = kUnknown;
73*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentHead = mBuffer;
74*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentTail = mBuffer;
75*cfb92d14SAndroid Build Coastguard Worker mWriteFrameTag = kInvalidTag;
76*cfb92d14SAndroid Build Coastguard Worker
77*cfb92d14SAndroid Build Coastguard Worker // Read (OutFrame) related variables
78*cfb92d14SAndroid Build Coastguard Worker mReadDirection = kForward;
79*cfb92d14SAndroid Build Coastguard Worker mReadState = kReadStateNotActive;
80*cfb92d14SAndroid Build Coastguard Worker mReadFrameLength = kUnknownFrameLength;
81*cfb92d14SAndroid Build Coastguard Worker
82*cfb92d14SAndroid Build Coastguard Worker mReadFrameStart[kPriorityLow] = mBuffer;
83*cfb92d14SAndroid Build Coastguard Worker mReadFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mBuffer, 1, kBackward);
84*cfb92d14SAndroid Build Coastguard Worker mReadSegmentHead = mBuffer;
85*cfb92d14SAndroid Build Coastguard Worker mReadSegmentTail = mBuffer;
86*cfb92d14SAndroid Build Coastguard Worker mReadPointer = mBuffer;
87*cfb92d14SAndroid Build Coastguard Worker
88*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
89*cfb92d14SAndroid Build Coastguard Worker mReadMessage = nullptr;
90*cfb92d14SAndroid Build Coastguard Worker mReadMessageOffset = 0;
91*cfb92d14SAndroid Build Coastguard Worker mReadMessageTail = mMessageBuffer;
92*cfb92d14SAndroid Build Coastguard Worker
93*cfb92d14SAndroid Build Coastguard Worker // Free all messages in the queues.
94*cfb92d14SAndroid Build Coastguard Worker
95*cfb92d14SAndroid Build Coastguard Worker while ((message = otMessageQueueGetHead(&mWriteFrameMessageQueue)) != nullptr)
96*cfb92d14SAndroid Build Coastguard Worker {
97*cfb92d14SAndroid Build Coastguard Worker otMessageQueueDequeue(&mWriteFrameMessageQueue, message);
98*cfb92d14SAndroid Build Coastguard Worker
99*cfb92d14SAndroid Build Coastguard Worker // Note that messages associated with current (unfinished) input frame
100*cfb92d14SAndroid Build Coastguard Worker // are not yet owned by the `Buffer` and therefore should not
101*cfb92d14SAndroid Build Coastguard Worker // be freed.
102*cfb92d14SAndroid Build Coastguard Worker }
103*cfb92d14SAndroid Build Coastguard Worker
104*cfb92d14SAndroid Build Coastguard Worker for (otMessageQueue &queue : mMessageQueue)
105*cfb92d14SAndroid Build Coastguard Worker {
106*cfb92d14SAndroid Build Coastguard Worker while ((message = otMessageQueueGetHead(&queue)) != nullptr)
107*cfb92d14SAndroid Build Coastguard Worker {
108*cfb92d14SAndroid Build Coastguard Worker otMessageQueueDequeue(&queue, message);
109*cfb92d14SAndroid Build Coastguard Worker otMessageFree(message);
110*cfb92d14SAndroid Build Coastguard Worker }
111*cfb92d14SAndroid Build Coastguard Worker }
112*cfb92d14SAndroid Build Coastguard Worker #endif
113*cfb92d14SAndroid Build Coastguard Worker }
114*cfb92d14SAndroid Build Coastguard Worker
SetFrameAddedCallback(BufferCallback aFrameAddedCallback,void * aFrameAddedContext)115*cfb92d14SAndroid Build Coastguard Worker void Buffer::SetFrameAddedCallback(BufferCallback aFrameAddedCallback, void *aFrameAddedContext)
116*cfb92d14SAndroid Build Coastguard Worker {
117*cfb92d14SAndroid Build Coastguard Worker mFrameAddedCallback = aFrameAddedCallback;
118*cfb92d14SAndroid Build Coastguard Worker mFrameAddedContext = aFrameAddedContext;
119*cfb92d14SAndroid Build Coastguard Worker }
120*cfb92d14SAndroid Build Coastguard Worker
SetFrameRemovedCallback(BufferCallback aFrameRemovedCallback,void * aFrameRemovedContext)121*cfb92d14SAndroid Build Coastguard Worker void Buffer::SetFrameRemovedCallback(BufferCallback aFrameRemovedCallback, void *aFrameRemovedContext)
122*cfb92d14SAndroid Build Coastguard Worker {
123*cfb92d14SAndroid Build Coastguard Worker mFrameRemovedCallback = aFrameRemovedCallback;
124*cfb92d14SAndroid Build Coastguard Worker mFrameRemovedContext = aFrameRemovedContext;
125*cfb92d14SAndroid Build Coastguard Worker }
126*cfb92d14SAndroid Build Coastguard Worker
127*cfb92d14SAndroid Build Coastguard Worker // Returns an updated buffer pointer by moving forward/backward (based on `aDirection`) from `aBufPtr` by a given
128*cfb92d14SAndroid Build Coastguard Worker // offset. The resulting buffer pointer is ensured to stay within the `mBuffer` boundaries.
GetUpdatedBufPtr(uint8_t * aBufPtr,uint16_t aOffset,Direction aDirection) const129*cfb92d14SAndroid Build Coastguard Worker uint8_t *Buffer::GetUpdatedBufPtr(uint8_t *aBufPtr, uint16_t aOffset, Direction aDirection) const
130*cfb92d14SAndroid Build Coastguard Worker {
131*cfb92d14SAndroid Build Coastguard Worker uint8_t *ptr = aBufPtr;
132*cfb92d14SAndroid Build Coastguard Worker
133*cfb92d14SAndroid Build Coastguard Worker switch (aDirection)
134*cfb92d14SAndroid Build Coastguard Worker {
135*cfb92d14SAndroid Build Coastguard Worker case kForward:
136*cfb92d14SAndroid Build Coastguard Worker ptr += aOffset;
137*cfb92d14SAndroid Build Coastguard Worker
138*cfb92d14SAndroid Build Coastguard Worker while (ptr >= mBufferEnd)
139*cfb92d14SAndroid Build Coastguard Worker {
140*cfb92d14SAndroid Build Coastguard Worker ptr -= mBufferLength;
141*cfb92d14SAndroid Build Coastguard Worker }
142*cfb92d14SAndroid Build Coastguard Worker
143*cfb92d14SAndroid Build Coastguard Worker break;
144*cfb92d14SAndroid Build Coastguard Worker
145*cfb92d14SAndroid Build Coastguard Worker case kBackward:
146*cfb92d14SAndroid Build Coastguard Worker ptr -= aOffset;
147*cfb92d14SAndroid Build Coastguard Worker
148*cfb92d14SAndroid Build Coastguard Worker while (ptr < mBuffer)
149*cfb92d14SAndroid Build Coastguard Worker {
150*cfb92d14SAndroid Build Coastguard Worker ptr += mBufferLength;
151*cfb92d14SAndroid Build Coastguard Worker }
152*cfb92d14SAndroid Build Coastguard Worker
153*cfb92d14SAndroid Build Coastguard Worker break;
154*cfb92d14SAndroid Build Coastguard Worker
155*cfb92d14SAndroid Build Coastguard Worker case kUnknown:
156*cfb92d14SAndroid Build Coastguard Worker assert(false);
157*cfb92d14SAndroid Build Coastguard Worker OT_UNREACHABLE_CODE(break);
158*cfb92d14SAndroid Build Coastguard Worker }
159*cfb92d14SAndroid Build Coastguard Worker
160*cfb92d14SAndroid Build Coastguard Worker return ptr;
161*cfb92d14SAndroid Build Coastguard Worker }
162*cfb92d14SAndroid Build Coastguard Worker
163*cfb92d14SAndroid Build Coastguard Worker // Gets the distance between two buffer pointers (adjusts for the wrap-around) given a direction (forward or backward).
GetDistance(const uint8_t * aStartPtr,const uint8_t * aEndPtr,Direction aDirection) const164*cfb92d14SAndroid Build Coastguard Worker uint16_t Buffer::GetDistance(const uint8_t *aStartPtr, const uint8_t *aEndPtr, Direction aDirection) const
165*cfb92d14SAndroid Build Coastguard Worker {
166*cfb92d14SAndroid Build Coastguard Worker size_t distance = 0;
167*cfb92d14SAndroid Build Coastguard Worker
168*cfb92d14SAndroid Build Coastguard Worker switch (aDirection)
169*cfb92d14SAndroid Build Coastguard Worker {
170*cfb92d14SAndroid Build Coastguard Worker case kForward:
171*cfb92d14SAndroid Build Coastguard Worker
172*cfb92d14SAndroid Build Coastguard Worker if (aEndPtr >= aStartPtr)
173*cfb92d14SAndroid Build Coastguard Worker {
174*cfb92d14SAndroid Build Coastguard Worker distance = static_cast<size_t>(aEndPtr - aStartPtr);
175*cfb92d14SAndroid Build Coastguard Worker }
176*cfb92d14SAndroid Build Coastguard Worker else
177*cfb92d14SAndroid Build Coastguard Worker {
178*cfb92d14SAndroid Build Coastguard Worker distance = static_cast<size_t>(mBufferEnd - aStartPtr);
179*cfb92d14SAndroid Build Coastguard Worker distance += static_cast<size_t>(aEndPtr - mBuffer);
180*cfb92d14SAndroid Build Coastguard Worker }
181*cfb92d14SAndroid Build Coastguard Worker
182*cfb92d14SAndroid Build Coastguard Worker break;
183*cfb92d14SAndroid Build Coastguard Worker
184*cfb92d14SAndroid Build Coastguard Worker case kBackward:
185*cfb92d14SAndroid Build Coastguard Worker
186*cfb92d14SAndroid Build Coastguard Worker if (aEndPtr <= aStartPtr)
187*cfb92d14SAndroid Build Coastguard Worker {
188*cfb92d14SAndroid Build Coastguard Worker distance = static_cast<size_t>(aStartPtr - aEndPtr);
189*cfb92d14SAndroid Build Coastguard Worker }
190*cfb92d14SAndroid Build Coastguard Worker else
191*cfb92d14SAndroid Build Coastguard Worker {
192*cfb92d14SAndroid Build Coastguard Worker distance = static_cast<size_t>(mBufferEnd - aEndPtr);
193*cfb92d14SAndroid Build Coastguard Worker distance += static_cast<size_t>(aStartPtr - mBuffer);
194*cfb92d14SAndroid Build Coastguard Worker }
195*cfb92d14SAndroid Build Coastguard Worker
196*cfb92d14SAndroid Build Coastguard Worker break;
197*cfb92d14SAndroid Build Coastguard Worker
198*cfb92d14SAndroid Build Coastguard Worker case kUnknown:
199*cfb92d14SAndroid Build Coastguard Worker assert(false);
200*cfb92d14SAndroid Build Coastguard Worker OT_UNREACHABLE_CODE(break);
201*cfb92d14SAndroid Build Coastguard Worker }
202*cfb92d14SAndroid Build Coastguard Worker
203*cfb92d14SAndroid Build Coastguard Worker return static_cast<uint16_t>(distance);
204*cfb92d14SAndroid Build Coastguard Worker }
205*cfb92d14SAndroid Build Coastguard Worker
206*cfb92d14SAndroid Build Coastguard Worker // Writes a uint16 value at the given buffer pointer (big-endian style).
WriteUint16At(uint8_t * aBufPtr,uint16_t aValue,Direction aDirection)207*cfb92d14SAndroid Build Coastguard Worker void Buffer::WriteUint16At(uint8_t *aBufPtr, uint16_t aValue, Direction aDirection)
208*cfb92d14SAndroid Build Coastguard Worker {
209*cfb92d14SAndroid Build Coastguard Worker *aBufPtr = (aValue >> 8);
210*cfb92d14SAndroid Build Coastguard Worker *GetUpdatedBufPtr(aBufPtr, 1, aDirection) = (aValue & 0xff);
211*cfb92d14SAndroid Build Coastguard Worker }
212*cfb92d14SAndroid Build Coastguard Worker
213*cfb92d14SAndroid Build Coastguard Worker // Reads a uint16 value at the given buffer pointer (big-endian style).
ReadUint16At(uint8_t * aBufPtr,Direction aDirection)214*cfb92d14SAndroid Build Coastguard Worker uint16_t Buffer::ReadUint16At(uint8_t *aBufPtr, Direction aDirection)
215*cfb92d14SAndroid Build Coastguard Worker {
216*cfb92d14SAndroid Build Coastguard Worker uint16_t value;
217*cfb92d14SAndroid Build Coastguard Worker
218*cfb92d14SAndroid Build Coastguard Worker value = static_cast<uint16_t>((*aBufPtr) << 8);
219*cfb92d14SAndroid Build Coastguard Worker value += *GetUpdatedBufPtr(aBufPtr, 1, aDirection);
220*cfb92d14SAndroid Build Coastguard Worker
221*cfb92d14SAndroid Build Coastguard Worker return value;
222*cfb92d14SAndroid Build Coastguard Worker }
223*cfb92d14SAndroid Build Coastguard Worker
224*cfb92d14SAndroid Build Coastguard Worker // Appends a byte at the write tail and updates the tail, discards the frame if buffer gets full.
InFrameAppend(uint8_t aByte)225*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameAppend(uint8_t aByte)
226*cfb92d14SAndroid Build Coastguard Worker {
227*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
228*cfb92d14SAndroid Build Coastguard Worker uint8_t *newTail;
229*cfb92d14SAndroid Build Coastguard Worker
230*cfb92d14SAndroid Build Coastguard Worker assert(mWriteDirection != kUnknown);
231*cfb92d14SAndroid Build Coastguard Worker
232*cfb92d14SAndroid Build Coastguard Worker newTail = GetUpdatedBufPtr(mWriteSegmentTail, 1, mWriteDirection);
233*cfb92d14SAndroid Build Coastguard Worker
234*cfb92d14SAndroid Build Coastguard Worker // Ensure the `newTail` has not reached the `mWriteFrameStart` for other direction (other priority level).
235*cfb92d14SAndroid Build Coastguard Worker if (newTail != mWriteFrameStart[(mWriteDirection == kForward) ? kBackward : kForward])
236*cfb92d14SAndroid Build Coastguard Worker {
237*cfb92d14SAndroid Build Coastguard Worker *mWriteSegmentTail = aByte;
238*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentTail = newTail;
239*cfb92d14SAndroid Build Coastguard Worker }
240*cfb92d14SAndroid Build Coastguard Worker else
241*cfb92d14SAndroid Build Coastguard Worker {
242*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_NO_BUFS;
243*cfb92d14SAndroid Build Coastguard Worker InFrameDiscard();
244*cfb92d14SAndroid Build Coastguard Worker }
245*cfb92d14SAndroid Build Coastguard Worker
246*cfb92d14SAndroid Build Coastguard Worker return error;
247*cfb92d14SAndroid Build Coastguard Worker }
248*cfb92d14SAndroid Build Coastguard Worker
249*cfb92d14SAndroid Build Coastguard Worker // This method begins a new segment (if one is not already open).
InFrameBeginSegment(void)250*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameBeginSegment(void)
251*cfb92d14SAndroid Build Coastguard Worker {
252*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
253*cfb92d14SAndroid Build Coastguard Worker uint16_t headerFlags = kSegmentHeaderNoFlag;
254*cfb92d14SAndroid Build Coastguard Worker
255*cfb92d14SAndroid Build Coastguard Worker // Verify that segment is not yet started (i.e., head and tail are the same).
256*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteSegmentHead == mWriteSegmentTail, NO_ACTION);
257*cfb92d14SAndroid Build Coastguard Worker
258*cfb92d14SAndroid Build Coastguard Worker // Check if this is the start of a new frame (i.e., frame start is same as segment head).
259*cfb92d14SAndroid Build Coastguard Worker if (mWriteFrameStart[mWriteDirection] == mWriteSegmentHead)
260*cfb92d14SAndroid Build Coastguard Worker {
261*cfb92d14SAndroid Build Coastguard Worker headerFlags |= kSegmentHeaderNewFrameFlag;
262*cfb92d14SAndroid Build Coastguard Worker }
263*cfb92d14SAndroid Build Coastguard Worker
264*cfb92d14SAndroid Build Coastguard Worker // Reserve space for the segment header.
265*cfb92d14SAndroid Build Coastguard Worker for (uint16_t i = kSegmentHeaderSize; i; i--)
266*cfb92d14SAndroid Build Coastguard Worker {
267*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameAppend(0));
268*cfb92d14SAndroid Build Coastguard Worker }
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker // Write the flags at the segment head.
271*cfb92d14SAndroid Build Coastguard Worker WriteUint16At(mWriteSegmentHead, headerFlags, mWriteDirection);
272*cfb92d14SAndroid Build Coastguard Worker
273*cfb92d14SAndroid Build Coastguard Worker exit:
274*cfb92d14SAndroid Build Coastguard Worker return error;
275*cfb92d14SAndroid Build Coastguard Worker }
276*cfb92d14SAndroid Build Coastguard Worker
277*cfb92d14SAndroid Build Coastguard Worker // This function closes/ends the current segment.
InFrameEndSegment(uint16_t aSegmentHeaderFlags)278*cfb92d14SAndroid Build Coastguard Worker void Buffer::InFrameEndSegment(uint16_t aSegmentHeaderFlags)
279*cfb92d14SAndroid Build Coastguard Worker {
280*cfb92d14SAndroid Build Coastguard Worker uint16_t segmentLength;
281*cfb92d14SAndroid Build Coastguard Worker uint16_t header;
282*cfb92d14SAndroid Build Coastguard Worker
283*cfb92d14SAndroid Build Coastguard Worker segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection);
284*cfb92d14SAndroid Build Coastguard Worker
285*cfb92d14SAndroid Build Coastguard Worker if (segmentLength >= kSegmentHeaderSize)
286*cfb92d14SAndroid Build Coastguard Worker {
287*cfb92d14SAndroid Build Coastguard Worker // Reduce the header size.
288*cfb92d14SAndroid Build Coastguard Worker segmentLength -= kSegmentHeaderSize;
289*cfb92d14SAndroid Build Coastguard Worker
290*cfb92d14SAndroid Build Coastguard Worker // Update the length and the flags in segment header (at segment head pointer).
291*cfb92d14SAndroid Build Coastguard Worker header = ReadUint16At(mWriteSegmentHead, mWriteDirection);
292*cfb92d14SAndroid Build Coastguard Worker header |= (segmentLength & kSegmentHeaderLengthMask);
293*cfb92d14SAndroid Build Coastguard Worker header |= aSegmentHeaderFlags;
294*cfb92d14SAndroid Build Coastguard Worker WriteUint16At(mWriteSegmentHead, header, mWriteDirection);
295*cfb92d14SAndroid Build Coastguard Worker
296*cfb92d14SAndroid Build Coastguard Worker // Move the segment head to current tail (to be ready for a possible next segment).
297*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentHead = mWriteSegmentTail;
298*cfb92d14SAndroid Build Coastguard Worker }
299*cfb92d14SAndroid Build Coastguard Worker else
300*cfb92d14SAndroid Build Coastguard Worker {
301*cfb92d14SAndroid Build Coastguard Worker // Remove the current segment (move the tail back to head).
302*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentTail = mWriteSegmentHead;
303*cfb92d14SAndroid Build Coastguard Worker }
304*cfb92d14SAndroid Build Coastguard Worker }
305*cfb92d14SAndroid Build Coastguard Worker
306*cfb92d14SAndroid Build Coastguard Worker // This method discards the current frame being written.
InFrameDiscard(void)307*cfb92d14SAndroid Build Coastguard Worker void Buffer::InFrameDiscard(void)
308*cfb92d14SAndroid Build Coastguard Worker {
309*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
310*cfb92d14SAndroid Build Coastguard Worker otMessage *message;
311*cfb92d14SAndroid Build Coastguard Worker #endif
312*cfb92d14SAndroid Build Coastguard Worker
313*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, NO_ACTION);
314*cfb92d14SAndroid Build Coastguard Worker
315*cfb92d14SAndroid Build Coastguard Worker // Move the write segment head and tail pointers back to frame start.
316*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentHead = mWriteSegmentTail = mWriteFrameStart[mWriteDirection];
317*cfb92d14SAndroid Build Coastguard Worker
318*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
319*cfb92d14SAndroid Build Coastguard Worker while ((message = otMessageQueueGetHead(&mWriteFrameMessageQueue)) != nullptr)
320*cfb92d14SAndroid Build Coastguard Worker {
321*cfb92d14SAndroid Build Coastguard Worker otMessageQueueDequeue(&mWriteFrameMessageQueue, message);
322*cfb92d14SAndroid Build Coastguard Worker
323*cfb92d14SAndroid Build Coastguard Worker // Note that messages associated with current (unfinished) input frame
324*cfb92d14SAndroid Build Coastguard Worker // being discarded, are not yet owned by the `Buffer` and
325*cfb92d14SAndroid Build Coastguard Worker // therefore should not be freed.
326*cfb92d14SAndroid Build Coastguard Worker }
327*cfb92d14SAndroid Build Coastguard Worker #endif
328*cfb92d14SAndroid Build Coastguard Worker
329*cfb92d14SAndroid Build Coastguard Worker mWriteDirection = kUnknown;
330*cfb92d14SAndroid Build Coastguard Worker
331*cfb92d14SAndroid Build Coastguard Worker exit:
332*cfb92d14SAndroid Build Coastguard Worker UpdateReadWriteStartPointers();
333*cfb92d14SAndroid Build Coastguard Worker }
334*cfb92d14SAndroid Build Coastguard Worker
335*cfb92d14SAndroid Build Coastguard Worker // Returns `true` if in middle of writing a frame with given priority.
InFrameIsWriting(Priority aPriority) const336*cfb92d14SAndroid Build Coastguard Worker bool Buffer::InFrameIsWriting(Priority aPriority) const
337*cfb92d14SAndroid Build Coastguard Worker {
338*cfb92d14SAndroid Build Coastguard Worker return (mWriteDirection == static_cast<Direction>(aPriority));
339*cfb92d14SAndroid Build Coastguard Worker }
340*cfb92d14SAndroid Build Coastguard Worker
InFrameBegin(Priority aPriority)341*cfb92d14SAndroid Build Coastguard Worker void Buffer::InFrameBegin(Priority aPriority)
342*cfb92d14SAndroid Build Coastguard Worker {
343*cfb92d14SAndroid Build Coastguard Worker // Discard any previous unfinished frame.
344*cfb92d14SAndroid Build Coastguard Worker InFrameDiscard();
345*cfb92d14SAndroid Build Coastguard Worker
346*cfb92d14SAndroid Build Coastguard Worker switch (aPriority)
347*cfb92d14SAndroid Build Coastguard Worker {
348*cfb92d14SAndroid Build Coastguard Worker case kPriorityHigh:
349*cfb92d14SAndroid Build Coastguard Worker mWriteDirection = kBackward;
350*cfb92d14SAndroid Build Coastguard Worker break;
351*cfb92d14SAndroid Build Coastguard Worker
352*cfb92d14SAndroid Build Coastguard Worker case kPriorityLow:
353*cfb92d14SAndroid Build Coastguard Worker mWriteDirection = kForward;
354*cfb92d14SAndroid Build Coastguard Worker break;
355*cfb92d14SAndroid Build Coastguard Worker }
356*cfb92d14SAndroid Build Coastguard Worker
357*cfb92d14SAndroid Build Coastguard Worker // Set up the segment head and tail
358*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentHead = mWriteSegmentTail = mWriteFrameStart[mWriteDirection];
359*cfb92d14SAndroid Build Coastguard Worker }
360*cfb92d14SAndroid Build Coastguard Worker
InFrameFeedByte(uint8_t aByte)361*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameFeedByte(uint8_t aByte)
362*cfb92d14SAndroid Build Coastguard Worker {
363*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
364*cfb92d14SAndroid Build Coastguard Worker
365*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
366*cfb92d14SAndroid Build Coastguard Worker
367*cfb92d14SAndroid Build Coastguard Worker // Begin a new segment (if we are not in middle of segment already).
368*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameBeginSegment());
369*cfb92d14SAndroid Build Coastguard Worker
370*cfb92d14SAndroid Build Coastguard Worker error = InFrameAppend(aByte);
371*cfb92d14SAndroid Build Coastguard Worker
372*cfb92d14SAndroid Build Coastguard Worker exit:
373*cfb92d14SAndroid Build Coastguard Worker return error;
374*cfb92d14SAndroid Build Coastguard Worker }
375*cfb92d14SAndroid Build Coastguard Worker
InFrameFeedData(const uint8_t * aDataBuffer,uint16_t aDataBufferLength)376*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength)
377*cfb92d14SAndroid Build Coastguard Worker {
378*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
379*cfb92d14SAndroid Build Coastguard Worker
380*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
381*cfb92d14SAndroid Build Coastguard Worker
382*cfb92d14SAndroid Build Coastguard Worker // Begin a new segment (if we are not in middle of segment already).
383*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameBeginSegment());
384*cfb92d14SAndroid Build Coastguard Worker
385*cfb92d14SAndroid Build Coastguard Worker // Write the data buffer
386*cfb92d14SAndroid Build Coastguard Worker while (aDataBufferLength--)
387*cfb92d14SAndroid Build Coastguard Worker {
388*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameAppend(*aDataBuffer++));
389*cfb92d14SAndroid Build Coastguard Worker }
390*cfb92d14SAndroid Build Coastguard Worker
391*cfb92d14SAndroid Build Coastguard Worker exit:
392*cfb92d14SAndroid Build Coastguard Worker return error;
393*cfb92d14SAndroid Build Coastguard Worker }
394*cfb92d14SAndroid Build Coastguard Worker
395*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
InFrameFeedMessage(otMessage * aMessage)396*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameFeedMessage(otMessage *aMessage)
397*cfb92d14SAndroid Build Coastguard Worker {
398*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
399*cfb92d14SAndroid Build Coastguard Worker
400*cfb92d14SAndroid Build Coastguard Worker EXPECT(aMessage != nullptr, error = OT_ERROR_INVALID_ARGS);
401*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
402*cfb92d14SAndroid Build Coastguard Worker
403*cfb92d14SAndroid Build Coastguard Worker // Begin a new segment (if we are not in middle of segment already).
404*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameBeginSegment());
405*cfb92d14SAndroid Build Coastguard Worker
406*cfb92d14SAndroid Build Coastguard Worker // Enqueue the message in the current write frame queue.
407*cfb92d14SAndroid Build Coastguard Worker otMessageQueueEnqueue(&mWriteFrameMessageQueue, aMessage);
408*cfb92d14SAndroid Build Coastguard Worker
409*cfb92d14SAndroid Build Coastguard Worker // End/Close the current segment marking the flag that it contains an associated message.
410*cfb92d14SAndroid Build Coastguard Worker InFrameEndSegment(kSegmentHeaderMessageIndicatorFlag);
411*cfb92d14SAndroid Build Coastguard Worker
412*cfb92d14SAndroid Build Coastguard Worker exit:
413*cfb92d14SAndroid Build Coastguard Worker return error;
414*cfb92d14SAndroid Build Coastguard Worker }
415*cfb92d14SAndroid Build Coastguard Worker #endif
416*cfb92d14SAndroid Build Coastguard Worker
InFrameGetPosition(WritePosition & aPosition)417*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameGetPosition(WritePosition &aPosition)
418*cfb92d14SAndroid Build Coastguard Worker {
419*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
420*cfb92d14SAndroid Build Coastguard Worker
421*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
422*cfb92d14SAndroid Build Coastguard Worker
423*cfb92d14SAndroid Build Coastguard Worker // Begin a new segment (if we are not in middle of segment already).
424*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = InFrameBeginSegment());
425*cfb92d14SAndroid Build Coastguard Worker
426*cfb92d14SAndroid Build Coastguard Worker aPosition.mPosition = mWriteSegmentTail;
427*cfb92d14SAndroid Build Coastguard Worker aPosition.mSegmentHead = mWriteSegmentHead;
428*cfb92d14SAndroid Build Coastguard Worker
429*cfb92d14SAndroid Build Coastguard Worker exit:
430*cfb92d14SAndroid Build Coastguard Worker return error;
431*cfb92d14SAndroid Build Coastguard Worker }
432*cfb92d14SAndroid Build Coastguard Worker
InFrameOverwrite(const WritePosition & aPosition,const uint8_t * aDataBuffer,uint16_t aDataBufferLength)433*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameOverwrite(const WritePosition &aPosition, const uint8_t *aDataBuffer, uint16_t aDataBufferLength)
434*cfb92d14SAndroid Build Coastguard Worker {
435*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
436*cfb92d14SAndroid Build Coastguard Worker uint8_t *bufPtr;
437*cfb92d14SAndroid Build Coastguard Worker uint16_t segmentLength;
438*cfb92d14SAndroid Build Coastguard Worker uint16_t distance;
439*cfb92d14SAndroid Build Coastguard Worker
440*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
441*cfb92d14SAndroid Build Coastguard Worker
442*cfb92d14SAndroid Build Coastguard Worker EXPECT(aPosition.mSegmentHead == mWriteSegmentHead, error = OT_ERROR_INVALID_ARGS);
443*cfb92d14SAndroid Build Coastguard Worker
444*cfb92d14SAndroid Build Coastguard Worker // Ensure the overwrite does not go beyond current segment tail.
445*cfb92d14SAndroid Build Coastguard Worker segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection);
446*cfb92d14SAndroid Build Coastguard Worker distance = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection);
447*cfb92d14SAndroid Build Coastguard Worker EXPECT(distance + aDataBufferLength <= segmentLength, error = OT_ERROR_INVALID_ARGS);
448*cfb92d14SAndroid Build Coastguard Worker
449*cfb92d14SAndroid Build Coastguard Worker bufPtr = aPosition.mPosition;
450*cfb92d14SAndroid Build Coastguard Worker while (aDataBufferLength > 0)
451*cfb92d14SAndroid Build Coastguard Worker {
452*cfb92d14SAndroid Build Coastguard Worker *bufPtr = *aDataBuffer;
453*cfb92d14SAndroid Build Coastguard Worker
454*cfb92d14SAndroid Build Coastguard Worker aDataBuffer++;
455*cfb92d14SAndroid Build Coastguard Worker aDataBufferLength--;
456*cfb92d14SAndroid Build Coastguard Worker
457*cfb92d14SAndroid Build Coastguard Worker bufPtr = GetUpdatedBufPtr(bufPtr, 1, mWriteDirection);
458*cfb92d14SAndroid Build Coastguard Worker }
459*cfb92d14SAndroid Build Coastguard Worker
460*cfb92d14SAndroid Build Coastguard Worker exit:
461*cfb92d14SAndroid Build Coastguard Worker return error;
462*cfb92d14SAndroid Build Coastguard Worker }
463*cfb92d14SAndroid Build Coastguard Worker
InFrameGetDistance(const WritePosition & aPosition) const464*cfb92d14SAndroid Build Coastguard Worker uint16_t Buffer::InFrameGetDistance(const WritePosition &aPosition) const
465*cfb92d14SAndroid Build Coastguard Worker {
466*cfb92d14SAndroid Build Coastguard Worker uint16_t distance = 0;
467*cfb92d14SAndroid Build Coastguard Worker uint16_t segmentLength;
468*cfb92d14SAndroid Build Coastguard Worker uint16_t offset;
469*cfb92d14SAndroid Build Coastguard Worker
470*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, NO_ACTION);
471*cfb92d14SAndroid Build Coastguard Worker EXPECT(aPosition.mSegmentHead == mWriteSegmentHead, NO_ACTION);
472*cfb92d14SAndroid Build Coastguard Worker
473*cfb92d14SAndroid Build Coastguard Worker segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection);
474*cfb92d14SAndroid Build Coastguard Worker offset = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection);
475*cfb92d14SAndroid Build Coastguard Worker EXPECT(offset < segmentLength, NO_ACTION);
476*cfb92d14SAndroid Build Coastguard Worker
477*cfb92d14SAndroid Build Coastguard Worker distance = GetDistance(aPosition.mPosition, mWriteSegmentTail, mWriteDirection);
478*cfb92d14SAndroid Build Coastguard Worker
479*cfb92d14SAndroid Build Coastguard Worker exit:
480*cfb92d14SAndroid Build Coastguard Worker return distance;
481*cfb92d14SAndroid Build Coastguard Worker }
482*cfb92d14SAndroid Build Coastguard Worker
InFrameReset(const WritePosition & aPosition)483*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameReset(const WritePosition &aPosition)
484*cfb92d14SAndroid Build Coastguard Worker {
485*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
486*cfb92d14SAndroid Build Coastguard Worker uint16_t segmentLength;
487*cfb92d14SAndroid Build Coastguard Worker uint16_t offset;
488*cfb92d14SAndroid Build Coastguard Worker
489*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
490*cfb92d14SAndroid Build Coastguard Worker EXPECT(aPosition.mSegmentHead == mWriteSegmentHead, error = OT_ERROR_INVALID_ARGS);
491*cfb92d14SAndroid Build Coastguard Worker
492*cfb92d14SAndroid Build Coastguard Worker segmentLength = GetDistance(mWriteSegmentHead, mWriteSegmentTail, mWriteDirection);
493*cfb92d14SAndroid Build Coastguard Worker offset = GetDistance(mWriteSegmentHead, aPosition.mPosition, mWriteDirection);
494*cfb92d14SAndroid Build Coastguard Worker EXPECT(offset < segmentLength, error = OT_ERROR_INVALID_ARGS);
495*cfb92d14SAndroid Build Coastguard Worker
496*cfb92d14SAndroid Build Coastguard Worker mWriteSegmentTail = aPosition.mPosition;
497*cfb92d14SAndroid Build Coastguard Worker
498*cfb92d14SAndroid Build Coastguard Worker exit:
499*cfb92d14SAndroid Build Coastguard Worker return error;
500*cfb92d14SAndroid Build Coastguard Worker }
501*cfb92d14SAndroid Build Coastguard Worker
InFrameEnd(void)502*cfb92d14SAndroid Build Coastguard Worker otError Buffer::InFrameEnd(void)
503*cfb92d14SAndroid Build Coastguard Worker {
504*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
505*cfb92d14SAndroid Build Coastguard Worker otMessage *message;
506*cfb92d14SAndroid Build Coastguard Worker #endif
507*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
508*cfb92d14SAndroid Build Coastguard Worker
509*cfb92d14SAndroid Build Coastguard Worker EXPECT(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE);
510*cfb92d14SAndroid Build Coastguard Worker
511*cfb92d14SAndroid Build Coastguard Worker // End/Close the current segment (if any).
512*cfb92d14SAndroid Build Coastguard Worker InFrameEndSegment(kSegmentHeaderNoFlag);
513*cfb92d14SAndroid Build Coastguard Worker
514*cfb92d14SAndroid Build Coastguard Worker // Save and use the frame start pointer as the tag associated with the frame.
515*cfb92d14SAndroid Build Coastguard Worker mWriteFrameTag = mWriteFrameStart[mWriteDirection];
516*cfb92d14SAndroid Build Coastguard Worker
517*cfb92d14SAndroid Build Coastguard Worker // Update the frame start pointer to current segment head to be ready for next frame.
518*cfb92d14SAndroid Build Coastguard Worker mWriteFrameStart[mWriteDirection] = mWriteSegmentHead;
519*cfb92d14SAndroid Build Coastguard Worker
520*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
521*cfb92d14SAndroid Build Coastguard Worker // Move all the messages from the frame queue to the main queue.
522*cfb92d14SAndroid Build Coastguard Worker while ((message = otMessageQueueGetHead(&mWriteFrameMessageQueue)) != nullptr)
523*cfb92d14SAndroid Build Coastguard Worker {
524*cfb92d14SAndroid Build Coastguard Worker otMessageQueueDequeue(&mWriteFrameMessageQueue, message);
525*cfb92d14SAndroid Build Coastguard Worker otMessageQueueEnqueue(&mMessageQueue[mWriteDirection], message);
526*cfb92d14SAndroid Build Coastguard Worker }
527*cfb92d14SAndroid Build Coastguard Worker #endif
528*cfb92d14SAndroid Build Coastguard Worker
529*cfb92d14SAndroid Build Coastguard Worker if (mFrameAddedCallback != nullptr)
530*cfb92d14SAndroid Build Coastguard Worker {
531*cfb92d14SAndroid Build Coastguard Worker mFrameAddedCallback(mFrameAddedContext, mWriteFrameTag, static_cast<Priority>(mWriteDirection), this);
532*cfb92d14SAndroid Build Coastguard Worker }
533*cfb92d14SAndroid Build Coastguard Worker
534*cfb92d14SAndroid Build Coastguard Worker mWriteDirection = kUnknown;
535*cfb92d14SAndroid Build Coastguard Worker
536*cfb92d14SAndroid Build Coastguard Worker exit:
537*cfb92d14SAndroid Build Coastguard Worker return error;
538*cfb92d14SAndroid Build Coastguard Worker }
539*cfb92d14SAndroid Build Coastguard Worker
InFrameGetLastTag(void) const540*cfb92d14SAndroid Build Coastguard Worker Buffer::FrameTag Buffer::InFrameGetLastTag(void) const { return mWriteFrameTag; }
541*cfb92d14SAndroid Build Coastguard Worker
HasFrame(Priority aPriority) const542*cfb92d14SAndroid Build Coastguard Worker bool Buffer::HasFrame(Priority aPriority) const { return mReadFrameStart[aPriority] != mWriteFrameStart[aPriority]; }
543*cfb92d14SAndroid Build Coastguard Worker
IsEmpty(void) const544*cfb92d14SAndroid Build Coastguard Worker bool Buffer::IsEmpty(void) const { return !HasFrame(kPriorityHigh) && !HasFrame(kPriorityLow); }
545*cfb92d14SAndroid Build Coastguard Worker
OutFrameSelectReadDirection(void)546*cfb92d14SAndroid Build Coastguard Worker void Buffer::OutFrameSelectReadDirection(void)
547*cfb92d14SAndroid Build Coastguard Worker {
548*cfb92d14SAndroid Build Coastguard Worker if (mReadState == kReadStateNotActive)
549*cfb92d14SAndroid Build Coastguard Worker {
550*cfb92d14SAndroid Build Coastguard Worker mReadDirection = HasFrame(kPriorityHigh) ? kBackward : kForward;
551*cfb92d14SAndroid Build Coastguard Worker }
552*cfb92d14SAndroid Build Coastguard Worker }
553*cfb92d14SAndroid Build Coastguard Worker
554*cfb92d14SAndroid Build Coastguard Worker // Start/Prepare a new segment for reading.
OutFramePrepareSegment(void)555*cfb92d14SAndroid Build Coastguard Worker otError Buffer::OutFramePrepareSegment(void)
556*cfb92d14SAndroid Build Coastguard Worker {
557*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
558*cfb92d14SAndroid Build Coastguard Worker uint16_t header;
559*cfb92d14SAndroid Build Coastguard Worker
560*cfb92d14SAndroid Build Coastguard Worker while (true)
561*cfb92d14SAndroid Build Coastguard Worker {
562*cfb92d14SAndroid Build Coastguard Worker // Go to the next segment (set the segment head to current segment's end/tail).
563*cfb92d14SAndroid Build Coastguard Worker mReadSegmentHead = mReadSegmentTail;
564*cfb92d14SAndroid Build Coastguard Worker
565*cfb92d14SAndroid Build Coastguard Worker // Ensure there is something to read (i.e. segment head is not at start of frame being written).
566*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadSegmentHead != mWriteFrameStart[mReadDirection], error = OT_ERROR_NOT_FOUND);
567*cfb92d14SAndroid Build Coastguard Worker
568*cfb92d14SAndroid Build Coastguard Worker // Read the segment header.
569*cfb92d14SAndroid Build Coastguard Worker header = ReadUint16At(mReadSegmentHead, mReadDirection);
570*cfb92d14SAndroid Build Coastguard Worker
571*cfb92d14SAndroid Build Coastguard Worker // Check if this segment is the start of a frame.
572*cfb92d14SAndroid Build Coastguard Worker if (header & kSegmentHeaderNewFrameFlag)
573*cfb92d14SAndroid Build Coastguard Worker {
574*cfb92d14SAndroid Build Coastguard Worker // Ensure that this segment is start of current frame, otherwise the current frame is finished.
575*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadSegmentHead == mReadFrameStart[mReadDirection], error = OT_ERROR_NOT_FOUND);
576*cfb92d14SAndroid Build Coastguard Worker }
577*cfb92d14SAndroid Build Coastguard Worker
578*cfb92d14SAndroid Build Coastguard Worker // Find tail/end of current segment.
579*cfb92d14SAndroid Build Coastguard Worker mReadSegmentTail = GetUpdatedBufPtr(mReadSegmentHead, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask),
580*cfb92d14SAndroid Build Coastguard Worker mReadDirection);
581*cfb92d14SAndroid Build Coastguard Worker
582*cfb92d14SAndroid Build Coastguard Worker // Update the current read pointer to skip the segment header.
583*cfb92d14SAndroid Build Coastguard Worker mReadPointer = GetUpdatedBufPtr(mReadSegmentHead, kSegmentHeaderSize, mReadDirection);
584*cfb92d14SAndroid Build Coastguard Worker
585*cfb92d14SAndroid Build Coastguard Worker // Check if there are data bytes to be read in this segment (i.e. read pointer not at the tail).
586*cfb92d14SAndroid Build Coastguard Worker if (mReadPointer != mReadSegmentTail)
587*cfb92d14SAndroid Build Coastguard Worker {
588*cfb92d14SAndroid Build Coastguard Worker // Update the state to `InSegment` and return.
589*cfb92d14SAndroid Build Coastguard Worker mReadState = kReadStateInSegment;
590*cfb92d14SAndroid Build Coastguard Worker
591*cfb92d14SAndroid Build Coastguard Worker EXIT_NOW();
592*cfb92d14SAndroid Build Coastguard Worker }
593*cfb92d14SAndroid Build Coastguard Worker
594*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
595*cfb92d14SAndroid Build Coastguard Worker // No data in this segment, prepare any appended/associated message of this segment.
596*cfb92d14SAndroid Build Coastguard Worker if (OutFramePrepareMessage() == OT_ERROR_NONE)
597*cfb92d14SAndroid Build Coastguard Worker {
598*cfb92d14SAndroid Build Coastguard Worker EXIT_NOW();
599*cfb92d14SAndroid Build Coastguard Worker }
600*cfb92d14SAndroid Build Coastguard Worker
601*cfb92d14SAndroid Build Coastguard Worker // If there is no message (`PrepareMessage()` returned an error), loop back to prepare the next segment.
602*cfb92d14SAndroid Build Coastguard Worker #endif
603*cfb92d14SAndroid Build Coastguard Worker }
604*cfb92d14SAndroid Build Coastguard Worker
605*cfb92d14SAndroid Build Coastguard Worker exit:
606*cfb92d14SAndroid Build Coastguard Worker
607*cfb92d14SAndroid Build Coastguard Worker if (error != OT_ERROR_NONE)
608*cfb92d14SAndroid Build Coastguard Worker {
609*cfb92d14SAndroid Build Coastguard Worker mReadState = kReadStateDone;
610*cfb92d14SAndroid Build Coastguard Worker }
611*cfb92d14SAndroid Build Coastguard Worker
612*cfb92d14SAndroid Build Coastguard Worker return error;
613*cfb92d14SAndroid Build Coastguard Worker }
614*cfb92d14SAndroid Build Coastguard Worker
615*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
616*cfb92d14SAndroid Build Coastguard Worker // This method prepares an associated message in current segment and fills the message buffer. It returns
617*cfb92d14SAndroid Build Coastguard Worker // ThreadError_NotFound if there is no message or if the message has no content.
OutFramePrepareMessage(void)618*cfb92d14SAndroid Build Coastguard Worker otError Buffer::OutFramePrepareMessage(void)
619*cfb92d14SAndroid Build Coastguard Worker {
620*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
621*cfb92d14SAndroid Build Coastguard Worker uint16_t header;
622*cfb92d14SAndroid Build Coastguard Worker
623*cfb92d14SAndroid Build Coastguard Worker // Read the segment header
624*cfb92d14SAndroid Build Coastguard Worker header = ReadUint16At(mReadSegmentHead, mReadDirection);
625*cfb92d14SAndroid Build Coastguard Worker
626*cfb92d14SAndroid Build Coastguard Worker // Ensure that the segment header indicates that there is an associated message or return `NotFound` error.
627*cfb92d14SAndroid Build Coastguard Worker EXPECT((header & kSegmentHeaderMessageIndicatorFlag) != 0, error = OT_ERROR_NOT_FOUND);
628*cfb92d14SAndroid Build Coastguard Worker
629*cfb92d14SAndroid Build Coastguard Worker // Update the current message from the queue.
630*cfb92d14SAndroid Build Coastguard Worker mReadMessage = (mReadMessage == nullptr) ? otMessageQueueGetHead(&mMessageQueue[mReadDirection])
631*cfb92d14SAndroid Build Coastguard Worker : otMessageQueueGetNext(&mMessageQueue[mReadDirection], mReadMessage);
632*cfb92d14SAndroid Build Coastguard Worker
633*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadMessage != nullptr, error = OT_ERROR_NOT_FOUND);
634*cfb92d14SAndroid Build Coastguard Worker
635*cfb92d14SAndroid Build Coastguard Worker // Reset the offset for reading the message.
636*cfb92d14SAndroid Build Coastguard Worker mReadMessageOffset = 0;
637*cfb92d14SAndroid Build Coastguard Worker
638*cfb92d14SAndroid Build Coastguard Worker // Fill the content from current message into the message buffer.
639*cfb92d14SAndroid Build Coastguard Worker EXPECT_NO_ERROR(error = OutFrameFillMessageBuffer());
640*cfb92d14SAndroid Build Coastguard Worker
641*cfb92d14SAndroid Build Coastguard Worker // If all successful, set the state to `InMessage`.
642*cfb92d14SAndroid Build Coastguard Worker mReadState = kReadStateInMessage;
643*cfb92d14SAndroid Build Coastguard Worker
644*cfb92d14SAndroid Build Coastguard Worker exit:
645*cfb92d14SAndroid Build Coastguard Worker return error;
646*cfb92d14SAndroid Build Coastguard Worker }
647*cfb92d14SAndroid Build Coastguard Worker
648*cfb92d14SAndroid Build Coastguard Worker // This method fills content from current message into the message buffer. It returns OT_ERROR_NOT_FOUND if no more
649*cfb92d14SAndroid Build Coastguard Worker // content in the current message.
OutFrameFillMessageBuffer(void)650*cfb92d14SAndroid Build Coastguard Worker otError Buffer::OutFrameFillMessageBuffer(void)
651*cfb92d14SAndroid Build Coastguard Worker {
652*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
653*cfb92d14SAndroid Build Coastguard Worker int readLength;
654*cfb92d14SAndroid Build Coastguard Worker
655*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadMessage != nullptr, error = OT_ERROR_NOT_FOUND);
656*cfb92d14SAndroid Build Coastguard Worker
657*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadMessageOffset < otMessageGetLength(mReadMessage), error = OT_ERROR_NOT_FOUND);
658*cfb92d14SAndroid Build Coastguard Worker
659*cfb92d14SAndroid Build Coastguard Worker // Read portion of current message from the offset into message buffer.
660*cfb92d14SAndroid Build Coastguard Worker readLength = otMessageRead(mReadMessage, mReadMessageOffset, mMessageBuffer, sizeof(mMessageBuffer));
661*cfb92d14SAndroid Build Coastguard Worker
662*cfb92d14SAndroid Build Coastguard Worker EXPECT(readLength > 0, error = OT_ERROR_NOT_FOUND);
663*cfb92d14SAndroid Build Coastguard Worker
664*cfb92d14SAndroid Build Coastguard Worker // Update the message offset, set up the message tail, and set read pointer to start of message buffer.
665*cfb92d14SAndroid Build Coastguard Worker
666*cfb92d14SAndroid Build Coastguard Worker mReadMessageOffset += readLength;
667*cfb92d14SAndroid Build Coastguard Worker
668*cfb92d14SAndroid Build Coastguard Worker mReadMessageTail = mMessageBuffer + readLength;
669*cfb92d14SAndroid Build Coastguard Worker
670*cfb92d14SAndroid Build Coastguard Worker mReadPointer = mMessageBuffer;
671*cfb92d14SAndroid Build Coastguard Worker
672*cfb92d14SAndroid Build Coastguard Worker exit:
673*cfb92d14SAndroid Build Coastguard Worker return error;
674*cfb92d14SAndroid Build Coastguard Worker }
675*cfb92d14SAndroid Build Coastguard Worker #endif // #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
676*cfb92d14SAndroid Build Coastguard Worker
OutFrameBegin(void)677*cfb92d14SAndroid Build Coastguard Worker otError Buffer::OutFrameBegin(void)
678*cfb92d14SAndroid Build Coastguard Worker {
679*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
680*cfb92d14SAndroid Build Coastguard Worker
681*cfb92d14SAndroid Build Coastguard Worker EXPECT(!IsEmpty(), error = OT_ERROR_NOT_FOUND);
682*cfb92d14SAndroid Build Coastguard Worker
683*cfb92d14SAndroid Build Coastguard Worker OutFrameSelectReadDirection();
684*cfb92d14SAndroid Build Coastguard Worker
685*cfb92d14SAndroid Build Coastguard Worker // Move the segment head and tail to start of frame.
686*cfb92d14SAndroid Build Coastguard Worker mReadSegmentHead = mReadSegmentTail = mReadFrameStart[mReadDirection];
687*cfb92d14SAndroid Build Coastguard Worker
688*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
689*cfb92d14SAndroid Build Coastguard Worker mReadMessage = nullptr;
690*cfb92d14SAndroid Build Coastguard Worker #endif
691*cfb92d14SAndroid Build Coastguard Worker
692*cfb92d14SAndroid Build Coastguard Worker // Prepare the current segment for reading.
693*cfb92d14SAndroid Build Coastguard Worker error = OutFramePrepareSegment();
694*cfb92d14SAndroid Build Coastguard Worker
695*cfb92d14SAndroid Build Coastguard Worker exit:
696*cfb92d14SAndroid Build Coastguard Worker return error;
697*cfb92d14SAndroid Build Coastguard Worker }
698*cfb92d14SAndroid Build Coastguard Worker
OutFrameHasEnded(void)699*cfb92d14SAndroid Build Coastguard Worker bool Buffer::OutFrameHasEnded(void) { return (mReadState == kReadStateDone) || (mReadState == kReadStateNotActive); }
700*cfb92d14SAndroid Build Coastguard Worker
OutFrameReadByte(void)701*cfb92d14SAndroid Build Coastguard Worker uint8_t Buffer::OutFrameReadByte(void)
702*cfb92d14SAndroid Build Coastguard Worker {
703*cfb92d14SAndroid Build Coastguard Worker otError error;
704*cfb92d14SAndroid Build Coastguard Worker uint8_t retval = kReadByteAfterFrameHasEnded;
705*cfb92d14SAndroid Build Coastguard Worker
706*cfb92d14SAndroid Build Coastguard Worker switch (mReadState)
707*cfb92d14SAndroid Build Coastguard Worker {
708*cfb92d14SAndroid Build Coastguard Worker case kReadStateNotActive:
709*cfb92d14SAndroid Build Coastguard Worker OT_FALL_THROUGH;
710*cfb92d14SAndroid Build Coastguard Worker
711*cfb92d14SAndroid Build Coastguard Worker case kReadStateDone:
712*cfb92d14SAndroid Build Coastguard Worker
713*cfb92d14SAndroid Build Coastguard Worker retval = kReadByteAfterFrameHasEnded;
714*cfb92d14SAndroid Build Coastguard Worker
715*cfb92d14SAndroid Build Coastguard Worker break;
716*cfb92d14SAndroid Build Coastguard Worker
717*cfb92d14SAndroid Build Coastguard Worker case kReadStateInSegment:
718*cfb92d14SAndroid Build Coastguard Worker
719*cfb92d14SAndroid Build Coastguard Worker // Read a byte from current read pointer and move the read pointer by 1 byte in the read direction.
720*cfb92d14SAndroid Build Coastguard Worker retval = *mReadPointer;
721*cfb92d14SAndroid Build Coastguard Worker mReadPointer = GetUpdatedBufPtr(mReadPointer, 1, mReadDirection);
722*cfb92d14SAndroid Build Coastguard Worker
723*cfb92d14SAndroid Build Coastguard Worker // Check if at end of current segment.
724*cfb92d14SAndroid Build Coastguard Worker if (mReadPointer == mReadSegmentTail)
725*cfb92d14SAndroid Build Coastguard Worker {
726*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
727*cfb92d14SAndroid Build Coastguard Worker // Prepare any message associated with this segment.
728*cfb92d14SAndroid Build Coastguard Worker error = OutFramePrepareMessage();
729*cfb92d14SAndroid Build Coastguard Worker #else
730*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_NOT_FOUND;
731*cfb92d14SAndroid Build Coastguard Worker #endif
732*cfb92d14SAndroid Build Coastguard Worker
733*cfb92d14SAndroid Build Coastguard Worker // If there is no message, move to next segment (if any).
734*cfb92d14SAndroid Build Coastguard Worker if (error != OT_ERROR_NONE)
735*cfb92d14SAndroid Build Coastguard Worker {
736*cfb92d14SAndroid Build Coastguard Worker IGNORE_RETURN(OutFramePrepareSegment());
737*cfb92d14SAndroid Build Coastguard Worker }
738*cfb92d14SAndroid Build Coastguard Worker }
739*cfb92d14SAndroid Build Coastguard Worker
740*cfb92d14SAndroid Build Coastguard Worker break;
741*cfb92d14SAndroid Build Coastguard Worker
742*cfb92d14SAndroid Build Coastguard Worker case kReadStateInMessage:
743*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
744*cfb92d14SAndroid Build Coastguard Worker // Read a byte from current read pointer and move the read pointer by 1 byte.
745*cfb92d14SAndroid Build Coastguard Worker retval = *mReadPointer;
746*cfb92d14SAndroid Build Coastguard Worker mReadPointer++;
747*cfb92d14SAndroid Build Coastguard Worker
748*cfb92d14SAndroid Build Coastguard Worker // Check if at the end of content in message buffer.
749*cfb92d14SAndroid Build Coastguard Worker if (mReadPointer == mReadMessageTail)
750*cfb92d14SAndroid Build Coastguard Worker {
751*cfb92d14SAndroid Build Coastguard Worker // Fill more bytes from current message into message buffer.
752*cfb92d14SAndroid Build Coastguard Worker error = OutFrameFillMessageBuffer();
753*cfb92d14SAndroid Build Coastguard Worker
754*cfb92d14SAndroid Build Coastguard Worker // If no more bytes in the message, move to next segment (if any).
755*cfb92d14SAndroid Build Coastguard Worker if (error != OT_ERROR_NONE)
756*cfb92d14SAndroid Build Coastguard Worker {
757*cfb92d14SAndroid Build Coastguard Worker IGNORE_RETURN(OutFramePrepareSegment());
758*cfb92d14SAndroid Build Coastguard Worker }
759*cfb92d14SAndroid Build Coastguard Worker }
760*cfb92d14SAndroid Build Coastguard Worker #endif
761*cfb92d14SAndroid Build Coastguard Worker break;
762*cfb92d14SAndroid Build Coastguard Worker }
763*cfb92d14SAndroid Build Coastguard Worker
764*cfb92d14SAndroid Build Coastguard Worker return retval;
765*cfb92d14SAndroid Build Coastguard Worker }
766*cfb92d14SAndroid Build Coastguard Worker
OutFrameRead(uint16_t aReadLength,uint8_t * aDataBuffer)767*cfb92d14SAndroid Build Coastguard Worker uint16_t Buffer::OutFrameRead(uint16_t aReadLength, uint8_t *aDataBuffer)
768*cfb92d14SAndroid Build Coastguard Worker {
769*cfb92d14SAndroid Build Coastguard Worker uint16_t bytesRead = 0;
770*cfb92d14SAndroid Build Coastguard Worker
771*cfb92d14SAndroid Build Coastguard Worker for (bytesRead = 0; (bytesRead < aReadLength) && !OutFrameHasEnded(); bytesRead++)
772*cfb92d14SAndroid Build Coastguard Worker {
773*cfb92d14SAndroid Build Coastguard Worker *aDataBuffer++ = OutFrameReadByte();
774*cfb92d14SAndroid Build Coastguard Worker }
775*cfb92d14SAndroid Build Coastguard Worker
776*cfb92d14SAndroid Build Coastguard Worker return bytesRead;
777*cfb92d14SAndroid Build Coastguard Worker }
778*cfb92d14SAndroid Build Coastguard Worker
OutFrameRemove(void)779*cfb92d14SAndroid Build Coastguard Worker otError Buffer::OutFrameRemove(void)
780*cfb92d14SAndroid Build Coastguard Worker {
781*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
782*cfb92d14SAndroid Build Coastguard Worker uint8_t *bufPtr;
783*cfb92d14SAndroid Build Coastguard Worker uint16_t header;
784*cfb92d14SAndroid Build Coastguard Worker uint8_t numSegments;
785*cfb92d14SAndroid Build Coastguard Worker FrameTag tag;
786*cfb92d14SAndroid Build Coastguard Worker
787*cfb92d14SAndroid Build Coastguard Worker EXPECT(!IsEmpty(), error = OT_ERROR_NOT_FOUND);
788*cfb92d14SAndroid Build Coastguard Worker
789*cfb92d14SAndroid Build Coastguard Worker OutFrameSelectReadDirection();
790*cfb92d14SAndroid Build Coastguard Worker
791*cfb92d14SAndroid Build Coastguard Worker // Save the frame start pointer as the tag associated with the frame being removed.
792*cfb92d14SAndroid Build Coastguard Worker tag = mReadFrameStart[mReadDirection];
793*cfb92d14SAndroid Build Coastguard Worker
794*cfb92d14SAndroid Build Coastguard Worker // Begin at the start of current frame and move through all segments.
795*cfb92d14SAndroid Build Coastguard Worker
796*cfb92d14SAndroid Build Coastguard Worker bufPtr = mReadFrameStart[mReadDirection];
797*cfb92d14SAndroid Build Coastguard Worker numSegments = 0;
798*cfb92d14SAndroid Build Coastguard Worker
799*cfb92d14SAndroid Build Coastguard Worker while (bufPtr != mWriteFrameStart[mReadDirection])
800*cfb92d14SAndroid Build Coastguard Worker {
801*cfb92d14SAndroid Build Coastguard Worker // Read the segment header
802*cfb92d14SAndroid Build Coastguard Worker header = ReadUint16At(bufPtr, mReadDirection);
803*cfb92d14SAndroid Build Coastguard Worker
804*cfb92d14SAndroid Build Coastguard Worker // If the current segment defines a new frame, and it is not the start of current frame, then we have reached
805*cfb92d14SAndroid Build Coastguard Worker // end of current frame.
806*cfb92d14SAndroid Build Coastguard Worker if (header & kSegmentHeaderNewFrameFlag)
807*cfb92d14SAndroid Build Coastguard Worker {
808*cfb92d14SAndroid Build Coastguard Worker if (bufPtr != mReadFrameStart[mReadDirection])
809*cfb92d14SAndroid Build Coastguard Worker {
810*cfb92d14SAndroid Build Coastguard Worker break;
811*cfb92d14SAndroid Build Coastguard Worker }
812*cfb92d14SAndroid Build Coastguard Worker }
813*cfb92d14SAndroid Build Coastguard Worker
814*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
815*cfb92d14SAndroid Build Coastguard Worker // If current segment has an appended message, remove it from message queue and free it.
816*cfb92d14SAndroid Build Coastguard Worker if (header & kSegmentHeaderMessageIndicatorFlag)
817*cfb92d14SAndroid Build Coastguard Worker {
818*cfb92d14SAndroid Build Coastguard Worker otMessage *message;
819*cfb92d14SAndroid Build Coastguard Worker
820*cfb92d14SAndroid Build Coastguard Worker if ((message = otMessageQueueGetHead(&mMessageQueue[mReadDirection])) != nullptr)
821*cfb92d14SAndroid Build Coastguard Worker {
822*cfb92d14SAndroid Build Coastguard Worker otMessageQueueDequeue(&mMessageQueue[mReadDirection], message);
823*cfb92d14SAndroid Build Coastguard Worker otMessageFree(message);
824*cfb92d14SAndroid Build Coastguard Worker }
825*cfb92d14SAndroid Build Coastguard Worker }
826*cfb92d14SAndroid Build Coastguard Worker #endif
827*cfb92d14SAndroid Build Coastguard Worker
828*cfb92d14SAndroid Build Coastguard Worker // Move the pointer to next segment.
829*cfb92d14SAndroid Build Coastguard Worker bufPtr = GetUpdatedBufPtr(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask), mReadDirection);
830*cfb92d14SAndroid Build Coastguard Worker
831*cfb92d14SAndroid Build Coastguard Worker numSegments++;
832*cfb92d14SAndroid Build Coastguard Worker
833*cfb92d14SAndroid Build Coastguard Worker // If this assert fails, it is a likely indicator that the internal structure of the NCP buffer has been
834*cfb92d14SAndroid Build Coastguard Worker // corrupted.
835*cfb92d14SAndroid Build Coastguard Worker assert(numSegments <= kMaxSegments);
836*cfb92d14SAndroid Build Coastguard Worker }
837*cfb92d14SAndroid Build Coastguard Worker
838*cfb92d14SAndroid Build Coastguard Worker mReadFrameStart[mReadDirection] = bufPtr;
839*cfb92d14SAndroid Build Coastguard Worker
840*cfb92d14SAndroid Build Coastguard Worker UpdateReadWriteStartPointers();
841*cfb92d14SAndroid Build Coastguard Worker
842*cfb92d14SAndroid Build Coastguard Worker mReadState = kReadStateNotActive;
843*cfb92d14SAndroid Build Coastguard Worker mReadFrameLength = kUnknownFrameLength;
844*cfb92d14SAndroid Build Coastguard Worker
845*cfb92d14SAndroid Build Coastguard Worker if (mFrameRemovedCallback != nullptr)
846*cfb92d14SAndroid Build Coastguard Worker {
847*cfb92d14SAndroid Build Coastguard Worker mFrameRemovedCallback(mFrameRemovedContext, tag, static_cast<Priority>(mReadDirection), this);
848*cfb92d14SAndroid Build Coastguard Worker }
849*cfb92d14SAndroid Build Coastguard Worker
850*cfb92d14SAndroid Build Coastguard Worker exit:
851*cfb92d14SAndroid Build Coastguard Worker return error;
852*cfb92d14SAndroid Build Coastguard Worker }
853*cfb92d14SAndroid Build Coastguard Worker
UpdateReadWriteStartPointers(void)854*cfb92d14SAndroid Build Coastguard Worker void Buffer::UpdateReadWriteStartPointers(void)
855*cfb92d14SAndroid Build Coastguard Worker {
856*cfb92d14SAndroid Build Coastguard Worker // If there is no fully written high priority frame, and not in middle of writing a new frame either.
857*cfb92d14SAndroid Build Coastguard Worker if (!HasFrame(kPriorityHigh) && !InFrameIsWriting(kPriorityHigh))
858*cfb92d14SAndroid Build Coastguard Worker {
859*cfb92d14SAndroid Build Coastguard Worker // Move the high priority pointers to be right behind the low priority start.
860*cfb92d14SAndroid Build Coastguard Worker mWriteFrameStart[kPriorityHigh] = GetUpdatedBufPtr(mReadFrameStart[kPriorityLow], 1, kBackward);
861*cfb92d14SAndroid Build Coastguard Worker mReadFrameStart[kPriorityHigh] = mWriteFrameStart[kPriorityHigh];
862*cfb92d14SAndroid Build Coastguard Worker EXIT_NOW();
863*cfb92d14SAndroid Build Coastguard Worker }
864*cfb92d14SAndroid Build Coastguard Worker
865*cfb92d14SAndroid Build Coastguard Worker // If there is no fully written low priority frame, and not in middle of writing a new frame either.
866*cfb92d14SAndroid Build Coastguard Worker if (!HasFrame(kPriorityLow) && !InFrameIsWriting(kPriorityLow))
867*cfb92d14SAndroid Build Coastguard Worker {
868*cfb92d14SAndroid Build Coastguard Worker // Move the low priority pointers to be 1 byte after the high priority start.
869*cfb92d14SAndroid Build Coastguard Worker mWriteFrameStart[kPriorityLow] = GetUpdatedBufPtr(mReadFrameStart[kPriorityHigh], 1, kForward);
870*cfb92d14SAndroid Build Coastguard Worker mReadFrameStart[kPriorityLow] = mWriteFrameStart[kPriorityLow];
871*cfb92d14SAndroid Build Coastguard Worker }
872*cfb92d14SAndroid Build Coastguard Worker
873*cfb92d14SAndroid Build Coastguard Worker exit:
874*cfb92d14SAndroid Build Coastguard Worker return;
875*cfb92d14SAndroid Build Coastguard Worker }
876*cfb92d14SAndroid Build Coastguard Worker
OutFrameGetLength(void)877*cfb92d14SAndroid Build Coastguard Worker uint16_t Buffer::OutFrameGetLength(void)
878*cfb92d14SAndroid Build Coastguard Worker {
879*cfb92d14SAndroid Build Coastguard Worker uint16_t frameLength = 0;
880*cfb92d14SAndroid Build Coastguard Worker uint16_t header;
881*cfb92d14SAndroid Build Coastguard Worker uint8_t *bufPtr;
882*cfb92d14SAndroid Build Coastguard Worker uint8_t numSegments;
883*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
884*cfb92d14SAndroid Build Coastguard Worker otMessage *message = nullptr;
885*cfb92d14SAndroid Build Coastguard Worker #endif
886*cfb92d14SAndroid Build Coastguard Worker
887*cfb92d14SAndroid Build Coastguard Worker // If the frame length was calculated before, return the previously calculated length.
888*cfb92d14SAndroid Build Coastguard Worker EXPECT(mReadFrameLength == kUnknownFrameLength, frameLength = mReadFrameLength);
889*cfb92d14SAndroid Build Coastguard Worker
890*cfb92d14SAndroid Build Coastguard Worker EXPECT(!IsEmpty(), frameLength = 0);
891*cfb92d14SAndroid Build Coastguard Worker
892*cfb92d14SAndroid Build Coastguard Worker OutFrameSelectReadDirection();
893*cfb92d14SAndroid Build Coastguard Worker
894*cfb92d14SAndroid Build Coastguard Worker // Calculate frame length by adding length of all segments and messages within the current frame.
895*cfb92d14SAndroid Build Coastguard Worker
896*cfb92d14SAndroid Build Coastguard Worker bufPtr = mReadFrameStart[mReadDirection];
897*cfb92d14SAndroid Build Coastguard Worker numSegments = 0;
898*cfb92d14SAndroid Build Coastguard Worker
899*cfb92d14SAndroid Build Coastguard Worker while (bufPtr != mWriteFrameStart[mReadDirection])
900*cfb92d14SAndroid Build Coastguard Worker {
901*cfb92d14SAndroid Build Coastguard Worker // Read the segment header
902*cfb92d14SAndroid Build Coastguard Worker header = ReadUint16At(bufPtr, mReadDirection);
903*cfb92d14SAndroid Build Coastguard Worker
904*cfb92d14SAndroid Build Coastguard Worker // If the current segment defines a new frame, and it is not the start of current frame, then we have reached
905*cfb92d14SAndroid Build Coastguard Worker // end of current frame.
906*cfb92d14SAndroid Build Coastguard Worker if (header & kSegmentHeaderNewFrameFlag)
907*cfb92d14SAndroid Build Coastguard Worker {
908*cfb92d14SAndroid Build Coastguard Worker if (bufPtr != mReadFrameStart[mReadDirection])
909*cfb92d14SAndroid Build Coastguard Worker {
910*cfb92d14SAndroid Build Coastguard Worker break;
911*cfb92d14SAndroid Build Coastguard Worker }
912*cfb92d14SAndroid Build Coastguard Worker }
913*cfb92d14SAndroid Build Coastguard Worker
914*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE
915*cfb92d14SAndroid Build Coastguard Worker // If current segment has an associated message, add its length to frame length.
916*cfb92d14SAndroid Build Coastguard Worker if (header & kSegmentHeaderMessageIndicatorFlag)
917*cfb92d14SAndroid Build Coastguard Worker {
918*cfb92d14SAndroid Build Coastguard Worker message = (message == nullptr) ? otMessageQueueGetHead(&mMessageQueue[mReadDirection])
919*cfb92d14SAndroid Build Coastguard Worker : otMessageQueueGetNext(&mMessageQueue[mReadDirection], message);
920*cfb92d14SAndroid Build Coastguard Worker
921*cfb92d14SAndroid Build Coastguard Worker if (message != nullptr)
922*cfb92d14SAndroid Build Coastguard Worker {
923*cfb92d14SAndroid Build Coastguard Worker frameLength += otMessageGetLength(message);
924*cfb92d14SAndroid Build Coastguard Worker }
925*cfb92d14SAndroid Build Coastguard Worker }
926*cfb92d14SAndroid Build Coastguard Worker #endif
927*cfb92d14SAndroid Build Coastguard Worker
928*cfb92d14SAndroid Build Coastguard Worker // Add the length of current segment to the frame length.
929*cfb92d14SAndroid Build Coastguard Worker frameLength += (header & kSegmentHeaderLengthMask);
930*cfb92d14SAndroid Build Coastguard Worker
931*cfb92d14SAndroid Build Coastguard Worker // Move the pointer to next segment.
932*cfb92d14SAndroid Build Coastguard Worker bufPtr = GetUpdatedBufPtr(bufPtr, kSegmentHeaderSize + (header & kSegmentHeaderLengthMask), mReadDirection);
933*cfb92d14SAndroid Build Coastguard Worker
934*cfb92d14SAndroid Build Coastguard Worker numSegments++;
935*cfb92d14SAndroid Build Coastguard Worker
936*cfb92d14SAndroid Build Coastguard Worker // If this assert fails, it is a likely indicator that the internal structure of the NCP buffer has been
937*cfb92d14SAndroid Build Coastguard Worker // corrupted.
938*cfb92d14SAndroid Build Coastguard Worker assert(numSegments <= kMaxSegments);
939*cfb92d14SAndroid Build Coastguard Worker }
940*cfb92d14SAndroid Build Coastguard Worker
941*cfb92d14SAndroid Build Coastguard Worker // Remember the calculated frame length for current active frame.
942*cfb92d14SAndroid Build Coastguard Worker if (mReadState != kReadStateNotActive)
943*cfb92d14SAndroid Build Coastguard Worker {
944*cfb92d14SAndroid Build Coastguard Worker mReadFrameLength = frameLength;
945*cfb92d14SAndroid Build Coastguard Worker }
946*cfb92d14SAndroid Build Coastguard Worker
947*cfb92d14SAndroid Build Coastguard Worker exit:
948*cfb92d14SAndroid Build Coastguard Worker return frameLength;
949*cfb92d14SAndroid Build Coastguard Worker }
950*cfb92d14SAndroid Build Coastguard Worker
OutFrameGetTag(void)951*cfb92d14SAndroid Build Coastguard Worker Buffer::FrameTag Buffer::OutFrameGetTag(void)
952*cfb92d14SAndroid Build Coastguard Worker {
953*cfb92d14SAndroid Build Coastguard Worker OutFrameSelectReadDirection();
954*cfb92d14SAndroid Build Coastguard Worker
955*cfb92d14SAndroid Build Coastguard Worker // If buffer is empty use `kInvalidTag`, otherwise use the frame start pointer as the tag associated with
956*cfb92d14SAndroid Build Coastguard Worker // current out frame being read
957*cfb92d14SAndroid Build Coastguard Worker
958*cfb92d14SAndroid Build Coastguard Worker return IsEmpty() ? kInvalidTag : mReadFrameStart[mReadDirection];
959*cfb92d14SAndroid Build Coastguard Worker }
960*cfb92d14SAndroid Build Coastguard Worker
961*cfb92d14SAndroid Build Coastguard Worker } // namespace Spinel
962*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
963