1 /* 2 * Copyright (c) 2016, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /** 29 * @file 30 * This file contains definitions for the NCP frame buffer class. 31 */ 32 33 #ifndef NCP_FRAME_BUFFER_HPP_ 34 #define NCP_FRAME_BUFFER_HPP_ 35 36 #include "openthread-spinel-config.h" 37 38 #include <openthread/message.h> 39 40 namespace ot { 41 namespace Spinel { 42 43 /** 44 * Implements a buffer/queue for storing Ncp frames. 45 * 46 * A frame can consist of a sequence of data bytes and/or the content of an `otMessage` or a combination of the two. 47 * `Buffer` implements priority FIFO logic for storing and reading frames. Two priority levels of high and low 48 * are supported. Within same priority level first-in-first-out order is preserved. High priority frames are read 49 * ahead of any low priority ones. 50 */ 51 class Buffer 52 { 53 friend class Encoder; 54 55 public: 56 /** 57 * Defines the priority of a frame. High priority frames are read before low priority frames. Within same priority 58 * level FIFO order is preserved. 59 */ 60 enum Priority 61 { 62 kPriorityLow = 0, ///< Indicates low/normal priority for a frame. 63 kPriorityHigh = 1, ///< Indicates high priority for a frame. 64 }; 65 66 /** 67 * Defines the (abstract) frame tag type. The tag is a unique value (within currently queued frames) associated 68 * with a frame in the `Buffer`. Frame tags can be compared with one another using operator `==`. 69 */ 70 typedef const void *FrameTag; 71 72 /** 73 * Defines the tag value indicating an invalid tag (e.g., when there is no frame). 74 */ 75 static const FrameTag kInvalidTag; 76 77 /** 78 * Defines the structure to hold a write position for an input frame (frame being written). 79 * 80 * It should be considered as an opaque data structure to users of `Buffer`. 81 */ 82 struct WritePosition 83 { 84 public: 85 /** 86 * The constructor for a `WritePosition` object. 87 */ WritePositionot::Spinel::Buffer::WritePosition88 WritePosition(void) 89 : mPosition(nullptr) 90 , mSegmentHead(nullptr) 91 { 92 } 93 94 private: 95 uint8_t *mPosition; // Pointer into buffer corresponding to saved write position. 96 uint8_t *mSegmentHead; // Pointer to segment head. 97 98 friend class Buffer; 99 }; 100 101 /** 102 * Defines a function pointer callback which is invoked to inform a change in `Buffer` either when a new 103 * frame is added/written to `Buffer` or when a frame is removed from `Buffer`. 104 * 105 * @param[in] aContext A pointer to arbitrary context information. 106 * @param[in] aTag The tag associated with the frame which is added or removed. 107 * @param[in] aPriority The priority of frame. 108 * @param[in] aBuffer A pointer to the `Buffer`. 109 */ 110 typedef void (*BufferCallback)(void *aContext, FrameTag aTag, Priority aPriority, Buffer *aBuffer); 111 112 /** 113 * Initializes an NCP frame buffer. 114 * 115 * @param[in] aBuffer A pointer to a buffer which will be used by NCP frame buffer. 116 * @param[in] aBufferLength The buffer size (in bytes). 117 */ 118 Buffer(uint8_t *aBuffer, uint16_t aBufferLength); 119 120 /** 121 * Clears the NCP frame buffer. All the frames are cleared/removed. 122 */ 123 void Clear(void); 124 125 /** 126 * Sets the FrameAdded callback and its context. 127 * 128 * Subsequent calls to this method will overwrite the previous callback and its context. 129 * 130 * @param[in] aFrameAddedCallback Callback invoked when a new frame is successfully added to buffer. 131 * @param[in] aFrameAddedContext A pointer to arbitrary context used with frame added callback. 132 */ 133 void SetFrameAddedCallback(BufferCallback aFrameAddedCallback, void *aFrameAddedContext); 134 135 /** 136 * Sets the FrameRemoved callback and its context. 137 * 138 * Subsequent calls to this method will overwrite the previous callback and its context. 139 * 140 * @param[in] aFrameRemovedCallback Callback invoked when a frame is removed from buffer. 141 * @param[in] aFrameRemovedContext A pointer to arbitrary context used with frame removed callback. 142 */ 143 void SetFrameRemovedCallback(BufferCallback aFrameRemovedCallback, void *aFrameRemovedContext); 144 145 /** 146 * Begins a new input frame (InFrame) to be added/written to the frame buffer. 147 148 * If there is a previous frame being written (for which `InFrameEnd()` has not yet been called), calling 149 * `InFrameBegin()` will discard and clear the previous unfinished frame. 150 * 151 * @param[in] aPriority Priority level of the new input frame. 152 */ 153 void InFrameBegin(Priority aPriority); 154 155 /** 156 * Adds a single byte to current input frame. 157 * 158 * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this 159 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 160 * 161 * If no buffer space is available, this method will discard and clear the current input frame and return the 162 * error status `OT_ERROR_NO_BUFS`. 163 * 164 * @param[in] aByte The byte value to add to input frame. 165 * 166 * @retval OT_ERROR_NONE Successfully added given byte to the frame. 167 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. 168 * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. 169 */ 170 otError InFrameFeedByte(uint8_t aByte); 171 172 /** 173 * Adds data to the current input frame. 174 * 175 * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this 176 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 177 * 178 * If no buffer space is available, this method will discard and clear the current input frame and return the 179 * error status `OT_ERROR_NO_BUFS`. 180 * 181 * @param[in] aDataBuffer A pointer to data buffer. 182 * @param[in] aDataBufferLength The length of the data buffer. 183 * 184 * @retval OT_ERROR_NONE Successfully added new data to the frame. 185 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data. 186 * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. 187 */ 188 otError InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength); 189 190 #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE 191 /** 192 * Adds a message to the current input frame. 193 * 194 * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this 195 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 196 * 197 * If no buffer space is available, this method will discard and clear the frame and return error status 198 * `OT_ERROR_NO_BUFS`. 199 * 200 * The ownership of the passed-in message @p aMessage changes to `Buffer` ONLY when the entire frame is 201 * successfully finished (i.e., with a successful call to `InFrameEnd()` for the current input frame), and in this 202 * case the `otMessage` instance will be freed once the frame is removed (using `OutFrameRemove()`) from NCP buffer. 203 * However, if the input frame gets discarded before it is finished (e.g., running out of buffer space), the 204 * `otMessage` instance remains unchanged. 205 * 206 * @param[in] aMessage A message to be added to current frame. 207 * 208 * @retval OT_ERROR_NONE Successfully added the message to the frame. 209 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message. 210 * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. 211 * @retval OT_ERROR_INVALID_ARGS If @p aMessage is nullptr. 212 */ 213 otError InFrameFeedMessage(otMessage *aMessage); 214 #endif 215 216 /** 217 * Gets the current write position in the input frame. 218 * 219 * The write position is returned in @p aPosition. The saved position can later be used to overwrite the frame 220 * content (using `InFrameOverwrite()`) or discard a portion of written frame and move the write pointer back to 221 * the saved position (using `InFrameReset()`). 222 * 223 * @param[out] aPosition A reference to a `WritePosition` to save the current write position. 224 * 225 * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. 226 * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. 227 */ 228 otError InFrameGetPosition(WritePosition &aPosition); 229 230 /** 231 * Overwrites the previously written content in the current input frame at a given write position. 232 * 233 * The write position @p aPostion must belong to the same input frame saved earlier with `InFrameGetPosition()`. 234 * Does not allow writing beyond the current end of the input frame (i.e., it can only write over 235 * previously added content). If writing @p aDataBufferLength bytes from write position @p aPosition goes beyond 236 * the end, this method does not change the input frame and returns error status `OT_ERROR_INVALID_ARGS`. 237 * Cannot be used if the input frame has an added `otMessage` (i.e., a previous call to 238 * `InFrameFeedMessage()`). 239 * 240 * @param[in] aPosition A reference to the write position. 241 * @param[in] aDataBuffer A pointer to data buffer. 242 * @param[in] aDataBufferLength The length of the data buffer. 243 * 244 * @retval OT_ERROR_NONE Successfully overwrote the data at the given write position. 245 * @retval OT_ERROR_INVALID_STATE No input frame (`InFrameBegin()` has not been called). 246 * @retval OT_ERROR_INVALID_ARGS The given write position is not valid (i.e., if it does not belong to same 247 * input frame), or the input frame has an added `otMessage`, or the write 248 * operation will go beyond the current end of the input frame. 249 */ 250 otError InFrameOverwrite(const WritePosition &aPosition, const uint8_t *aDataBuffer, uint16_t aDataBufferLength); 251 252 /** 253 * Resets the write position of input frame back to a previously saved position. Any previously 254 * added content after the write position is discarded. 255 * 256 * The write position @p aPosition must belong to the same input frame saved earlier with `InFrameGetPosition()`. 257 * Cannot be used if the input frame has an added `otMessage` (i.e., a previous call to 258 * `InFrameFeedMessage()`). 259 * 260 * @param[in] aPosition A reference to write position 261 * 262 * @retval OT_ERROR_NONE Successfully reset the write position of current input frame.. 263 * @retval OT_ERROR_INVALID_STATE No input frame (`InFrameBegin()` has not been called). 264 * @retval OT_ERROR_INVALID_ARGS The given write position is not valid (does not belong to same input frame), or 265 * the input frame has an added `otMessage`. 266 */ 267 otError InFrameReset(const WritePosition &aPosition); 268 269 /** 270 * Gets the distance (number of bytes) from a given saved position to current end of frame. 271 * 272 * The write position @p aPosition must belong to the same input frame saved earlier with `InFrameGetPosition()`. 273 * Cannot be used if the input frame has an added `otMessage` (i.e., a previous call to 274 * `InFrameFeedMessage()`). In case of invalid argument, this method returns zero. 275 * 276 * @param[in] aPosition A reference to write position 277 * 278 * @returns The distance (number of bytes) from a write position to current end of frame, or zero for invalid 279 * arguments. 280 */ 281 uint16_t InFrameGetDistance(const WritePosition &aPosition) const; 282 283 /** 284 * Finalizes/ends the current input frame being written to the buffer. 285 * 286 * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this 287 * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. 288 * 289 * If no buffer space is available, this method will discard and clear the frame and return error status 290 * `OT_ERROR_NO_BUFS`. 291 * 292 * @retval OT_ERROR_NONE Successfully ended the input frame. 293 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. 294 * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. 295 */ 296 otError InFrameEnd(void); 297 298 /** 299 * Returns the tag assigned to last successfully written/added frame to NcpBuffer (i.e., last input 300 * frame for which `InFrameEnd()` was called and returned success status). The tag is a unique value (within 301 * currently queued frames) associated with a frame in the `Buffer`. The tag can be used to identify the 302 * same frame when it is read and removed from the NcpBuffer. Tags can be compared using operator `==`. 303 * 304 * @returns The tag of the last successfully written frame, or `kInvalidTag` if no frame is written so far. 305 */ 306 FrameTag InFrameGetLastTag(void) const; 307 308 /** 309 * Checks if the buffer is empty. A non-empty buffer contains at least one full frame for reading. 310 * 311 * @retval TRUE Buffer is not empty and contains at least one full frame for reading. 312 * @retval FALSE Buffer is empty and contains no frame for reading. 313 */ 314 bool IsEmpty(void) const; 315 316 /** 317 * Begins/prepares an output frame to be read from the frame buffer if there is no current active output 318 * frame, or resets the read offset if there is a current active output frame. 319 * 320 * The NCP buffer maintains a read offset for the current frame being read. Before reading any bytes from the frame 321 * this method should be called to prepare the frame and set the read offset. 322 * 323 * If part or even all of current frame has been read, a sub-sequent call to this method will reset the read 324 * offset back to beginning of current output frame (note that the current output frame will remain unchanged even 325 * in case where a higher priority frame was written to buffer while reading current output frame). A prepared 326 * output frame will stay active as current output frame until it is explicitly removed using `OutFrameRemove()`. 327 * 328 * @retval OT_ERROR_NONE Successfully started/prepared a new output frame for reading. 329 * @retval OT_ERROR_NOT_FOUND No frame available in buffer for reading. 330 */ 331 otError OutFrameBegin(void); 332 333 /** 334 * Checks if the current output frame (being read) has ended. 335 * 336 * The NCP buffer maintains a read offset for the current output frame being read. This method returns `true` if 337 * the read offset has reached the end of the frame and there are no more bytes available to read, or if there is 338 * no currently active output frame. 339 * 340 * @retval TRUE Frame has ended (no more bytes available to read from current output frame), or 341 * there is currently no prepared/active output frame. 342 * @retval FALSE Frame still has more data to read. 343 */ 344 bool OutFrameHasEnded(void); 345 346 /** 347 * Reads and returns the next byte from the current output frame. 348 * 349 * The NCP buffer maintains a read offset for the current output frame being read. This method reads and returns 350 * the next byte from the current frame and moves the read offset forward. If read offset is already at the end 351 * current output frame, this method returns zero. 352 * 353 * @returns The next byte from the current output frame or zero if current output frame has ended or there is 354 * prepared/active output from. 355 */ 356 uint8_t OutFrameReadByte(void); 357 358 /** 359 * Reads and copies bytes from the current output frame into a given buffer. 360 * 361 * The NCP buffer maintains a read offset for the current output frame being read. This method attempts to read 362 * the given number of bytes (@p aReadLength) from the current frame and copies the bytes into the given 363 * data buffer (@p aDataBuffer). It also moves the read offset forward accordingly. If there are fewer bytes 364 * remaining in current frame than the requested @p aReadLength, the available bytes are read/copied. This methods 365 * returns the number of bytes read from frame and copied into @p aDataBuffer. 366 * 367 * @param[in] aReadLength Number of bytes to read. 368 * @param[out] aDataBuffer A pointer to a data buffer. 369 * 370 * @returns The number of bytes read and copied into data buffer. 371 */ 372 uint16_t OutFrameRead(uint16_t aReadLength, uint8_t *aDataBuffer); 373 374 /** 375 * Removes the current or front output frame from the buffer. 376 * 377 * If there is an active output from being read (an output frame was prepared earlier with a successful call to 378 * `OutFrameBegin()`), this method removes the current active output frame. If there is no current active frame, 379 * the front frame in the queue (the next frame which would have been read) will be removed. 380 * 381 * When a frame is removed all its associated messages will be freed. 382 * 383 * If the remove operation is successful, this method will invoke the `FrameRemovedCallback` (if not nullptr) before 384 * returning the success state. 385 * 386 * @retval OT_ERROR_NONE Successfully removed the front frame. 387 * @retval OT_ERROR_NOT_FOUND No frame available in NCP frame buffer to remove. 388 */ 389 otError OutFrameRemove(void); 390 391 /** 392 * Returns the number of bytes (length) of current or front frame in the NCP frame buffer. 393 * 394 * If there is an active output from being read (an output frame was prepared earlier with successful call to 395 * `OutFrameBegin()`), this method returns the length of the current output frame. If there is no current active 396 * frame, the length of the front frame in the queue (the next frame which would have been read) will be returned. 397 * 398 * If there is no frame in buffer, this method returns zero. 399 * 400 * @returns The number of bytes (length) of current/front frame, or zero if no frame in buffer. 401 */ 402 uint16_t OutFrameGetLength(void); 403 404 /** 405 * Returns the tag value associated to current or front frame in the NCP frame buffer. 406 * 407 * If there is an active output from being read (an output frame was prepared earlier with successful call to 408 * `OutFrameBegin()`), this method returns the tag associated with current output frame. If there is no current 409 * active frame, the tag associated with the front frame in the queue (the next frame which would have been read) 410 * will be returned. 411 * 412 * If there is no frame in buffer, this method returns `kInvalidTag`. 413 * 414 * @returns The tag assigned to the current/from output frame, or `kInvalidTag` if no frame in buffer. 415 */ 416 FrameTag OutFrameGetTag(void); 417 418 private: 419 /* 420 * `Buffer` Implementation 421 * ------------------------------- 422 * 423 * `Buffer` internally stores a frame as a sequence of data segments. Each segment stores a portion of 424 * frame. The data segments are stored in the main buffer `mBuffer`. `mBuffer` is utilized as a circular buffer. 425 426 * The content of messages (which are added using `InFrameFeedMessage()`) are not directly copied in the `mBuffer` 427 * but instead they are enqueued in a message queue `mMessageQueue`. 428 * 429 * Every data segments starts with a header before the data portion. The header is 2 bytes long with the following 430 * format: 431 * 432 * Bit 0-13: Give the length of the data segment (max segment len is 2^14 = 16,384 bytes). 433 * Bit 14: Flag bit set to indicate that this segment has an associated `Message` (appended to its end). 434 * Bit 15: Flag bit set to indicate that this segment defines the start of a new frame. 435 * 436 * Bit 15 Bit 14 Bits: 0 - 13 437 * +--------------+--------------+--------------------------------------------------------+ 438 * | New Frame | Has Message | Length of segment (excluding the header) | 439 * +--------------+--------------+--------------------------------------------------------+ 440 * 441 * The header is encoded in big-endian (msb first) style. 442 443 * Consider the following calls to create a frame: 444 * 445 * ncpBuffer.InFrameBegin(); 446 * ncpBuffer.InFrameFeedData("Hello", 5); 447 * ncpBuffer.InFrameFeedData("There", 5); 448 * ncpBuffer.InFrameFeedMessage(*someMessage); 449 * ncpBuffer.InFrameFeedData("Bye", 3); 450 * ncpBuffer.InFrameEnd(); 451 * 452 * This frame is stored as two segments: 453 * 454 * - Segment #1 contains "HelloThere" with a header value `0xC00A` which shows that this segment contains 10 455 * data bytes, and it starts a new frame, and also includes an appended message from the message queue. 456 * 457 * - Segment #2 contains "Bye" with a header value of `0x0003` showing length of 3 and no appended message. 458 * 459 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ 460 * | C0 | 0A | 'H' | 'e' | 'l' | 'l' | 'o' | 'T' | 'h' | 'e' | 'r' | 'e' | 00 | 03 | 'B' | 'y' | 'e' | 461 * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ 462 * \ / \ / 463 * Segment #1 Header Segment #2 Header 464 * 465 * 466 * `Buffer` uses the `mBuffer` as a circular/ring buffer. To support two frame priorities the buffer is 467 * divided into two high-priority and low-priority regions. The high priority frames are stored in buffer in 468 * backward direction while the low-priority frames use the buffer in forward direction. This model ensures the 469 * available buffer space is utilized efficiently between all frame types. 470 * 471 * mReadFrameStart[kPriorityLow] 472 * | 473 * | mWriteFrameStart[kPriorityLow] 474 * | | 475 * V Low Priority Frames V 476 * --------------+------------------------------+------------------------------+------------------ 477 * ... | <-------- | --------> | ... 478 * --------------+------------------------------+------------------------------+------------------ 479 * ^ High Priority Frames ^ 480 * | | 481 * | mReadFrameStart[kPriorityHigh] 482 * | 483 * mWriteFrameStart[kPriorityHigh] 484 * 485 * 486 * 487 * When frames are removed, if possible, the `mReadFrameStart` and `mWriteFrameStart` pointers of the two priority 488 * levels are moved closer to avoid gaps. 489 * 490 * For an output frame (frame being read), Buffer maintains a `ReadState` along with a set of pointers 491 * into the buffer: 492 * 493 * mReadFrameStart[priority]: Start of the current/front frame. 494 * | 495 * | mReadSegmentHead: Start of the current segment. 496 * | | 497 * | | mReadPointer: Pointer to the next byte to read. 498 * | | | 499 * | | | mReadSegmentTail: End of the current segment. 500 * | | | | 501 * V V V V 502 * ---------+------------+--------------------------+------+----------------+----------------------------------- 503 * ... | Segment 1 | Segment 2 | ... | Last Segment | ... (possible) next frame 504 * ---------+------------+--------------------------+------+----------------+----------------------------------- 505 * \ | | / 506 * | \------------v-----------/ | 507 * | Current Segment | 508 * | | 509 * \---------------------------V-----------------------------/ 510 * Current OutFrame (being read) 511 * 512 * Note that the diagram above shows the pointers for a low-priority frame (with pointers increasing in forward 513 * direction). 514 * 515 * The `ReadState` indicates the state of current output frame and its read offset (e.g., if read offset is in 516 * middle of a segment or if it is is middle of an appended message, or if we are done with entire frame). 517 * 518 * For an input frame (frame being written), the following pointers are maintained: 519 * 520 * mWriteFrameWrite[priority]: Start of the current/next frame being written. 521 * | 522 * | mWriteSegmentHead: Start of the current segment of the active input frame. 523 * | | 524 * | | mWriteSegmentTail: Pointer to the next byte to write. 525 * | | | 526 * | | | 527 * | | | 528 * V V V 529 * ------------------+------------------+------------------------------------------------------------------- 530 * Previous Frames | Segment 1 | Segment 2 : . . . 531 * ------------------+------------------+------------------------------------------------------------------- 532 * \ / 533 * | | 534 * \------------------V-----------------/ 535 * Current InFrame (being written) 536 */ 537 538 enum 539 { 540 kReadByteAfterFrameHasEnded = 0, // Value returned by ReadByte() when frame has ended. 541 kMessageReadBufferSize = 16, // Size of message buffer array `mMessageBuffer`. 542 kUnknownFrameLength = 0xffff, // Value used when frame length is unknown. 543 kSegmentHeaderSize = 2, // Length of the segment header. 544 kSegmentHeaderLengthMask = 0x3fff, // Bit mask to get the length from the segment header 545 kMaxSegments = 10, // Max number of segments allowed in a frame 546 547 kSegmentHeaderNoFlag = 0, // No flags are set. 548 kSegmentHeaderNewFrameFlag = (1 << 15), // Indicates that this segment starts a new frame. 549 kSegmentHeaderMessageIndicatorFlag = (1 << 14), // Indicates this segment ends with a Message. 550 551 kNumPrios = (kPriorityHigh + 1), // Number of priorities. 552 }; 553 554 enum ReadState 555 { 556 kReadStateNotActive, // No current prepared output frame. 557 kReadStateInSegment, // In middle of a data segment while reading current frame. 558 kReadStateInMessage, // In middle of a message while reading current frame. 559 kReadStateDone, // Current output frame is read fully. 560 }; 561 562 enum Direction 563 { 564 kForward = kPriorityLow, 565 kBackward = kPriorityHigh, 566 kUnknown, 567 }; 568 569 uint8_t *GetUpdatedBufPtr(uint8_t *aBufPtr, uint16_t aOffset, Direction aDirection) const; 570 uint16_t GetDistance(const uint8_t *aStartPtr, const uint8_t *aEndPtr, Direction aDirection) const; 571 572 uint16_t ReadUint16At(uint8_t *aBufPtr, Direction aDirection); 573 void WriteUint16At(uint8_t *aBufPtr, uint16_t aValue, Direction aDirection); 574 575 bool HasFrame(Priority aPriority) const; 576 void UpdateReadWriteStartPointers(void); 577 578 otError InFrameAppend(uint8_t aByte); 579 otError InFrameBeginSegment(void); 580 void InFrameEndSegment(uint16_t aSegmentHeaderFlags); 581 void InFrameDiscard(void); 582 bool InFrameIsWriting(Priority aPriority) const; 583 584 void OutFrameSelectReadDirection(void); 585 otError OutFramePrepareSegment(void); 586 void OutFrameMoveToNextSegment(void); 587 588 #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE 589 otError OutFramePrepareMessage(void); 590 otError OutFrameFillMessageBuffer(void); 591 #endif 592 593 uint8_t *const mBuffer; // Pointer to the buffer used to store the data. 594 uint8_t *const mBufferEnd; // Points to after the end of buffer. 595 const uint16_t mBufferLength; // Length of the buffer. 596 597 BufferCallback mFrameAddedCallback; // Callback to signal when a new frame is added 598 void *mFrameAddedContext; // Context passed to `mFrameAddedCallback`. 599 BufferCallback mFrameRemovedCallback; // Callback to signal when a frame is removed. 600 void *mFrameRemovedContext; // Context passed to `mFrameRemovedCallback`. 601 602 Direction mWriteDirection; // Direction (priority) for current frame being read. 603 uint8_t *mWriteFrameStart[kNumPrios]; // Pointer to start of current frame being written. 604 uint8_t *mWriteSegmentHead; // Pointer to start of current segment in the frame being written. 605 uint8_t *mWriteSegmentTail; // Pointer to end of current segment in the frame being written. 606 FrameTag mWriteFrameTag; // Tag associated with last successfully written frame. 607 608 Direction mReadDirection; // Direction (priority) for current frame being read. 609 ReadState mReadState; // Read state. 610 uint16_t mReadFrameLength; // Length of current frame being read. 611 612 uint8_t *mReadFrameStart[kNumPrios]; // Pointer to start of current frame being read. 613 uint8_t *mReadSegmentHead; // Pointer to start of current segment in the frame being read. 614 uint8_t *mReadSegmentTail; // Pointer to end of current segment in the frame being read. 615 uint8_t *mReadPointer; // Pointer to next byte to read (either in segment or in msg buffer). 616 617 #if OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE 618 otMessageQueue mWriteFrameMessageQueue; // Message queue for the current frame being written. 619 otMessageQueue mMessageQueue[kNumPrios]; // Main message queues. 620 otMessage *mReadMessage; // Current Message in the frame being read. 621 uint16_t mReadMessageOffset; // Offset within current message being read. 622 uint8_t mMessageBuffer[kMessageReadBufferSize]; // Buffer to hold part of current message being read. 623 uint8_t *mReadMessageTail; // Pointer to end of current part in mMessageBuffer. 624 #endif 625 }; 626 627 } // namespace Spinel 628 } // namespace ot 629 630 #endif // NCP_FRAME_BUFFER_HPP_ 631