Matter SDK Coverage Report
Current view: top level - lib/core - TLVCircularBuffer.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 98.7 % 78 77
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    Copyright (c) 2016-2017 Nest Labs, Inc.
       5              :  *    All rights reserved.
       6              :  *
       7              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8              :  *    you may not use this file except in compliance with the License.
       9              :  *    You may obtain a copy of the License at
      10              :  *
      11              :  *        http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  *    Unless required by applicable law or agreed to in writing, software
      14              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  *    See the License for the specific language governing permissions and
      17              :  *    limitations under the License.
      18              :  */
      19              : 
      20              : /**
      21              :  *    @file
      22              :  *      This file implements the circular buffer for TLV
      23              :  *      elements. When used as the backing store for the TLVReader and
      24              :  *      TLVWriter, those classes will work with the wraparound of data
      25              :  *      within the buffer.  Additionally, the TLVWriter will be able
      26              :  *      to continually add top-level TLV elements by evicting
      27              :  *      pre-existing elements.
      28              :  */
      29              : #include <lib/core/TLVCircularBuffer.h>
      30              : 
      31              : #include <lib/core/CHIPError.h>
      32              : #include <lib/core/TLVReader.h>
      33              : #include <lib/core/TLVTags.h>
      34              : #include <lib/core/TLVWriter.h>
      35              : #include <lib/support/BufferWriter.h>
      36              : #include <lib/support/CodeUtils.h>
      37              : 
      38              : #include <stdint.h>
      39              : 
      40              : namespace chip {
      41              : namespace TLV {
      42              : 
      43              : using namespace chip::Encoding;
      44              : 
      45              : /**
      46              :  * @brief
      47              :  *   TLVCircularBuffer constructor
      48              :  *
      49              :  * @param[in] inBuffer       A pointer to the backing store for the queue
      50              :  *
      51              :  * @param[in] inBufferLength Length, in bytes, of the backing store
      52              :  *
      53              :  * @param[in] inHead         Initial point for the head.  The @a inHead pointer is must fall within the backing store for the
      54              :  * circular buffer, i.e. within @a inBuffer and &(@a inBuffer[@a inBufferLength])
      55              :  */
      56            1 : TLVCircularBuffer::TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength, uint8_t * inHead)
      57              : {
      58            1 :     mQueue       = inBuffer;
      59            1 :     mQueueSize   = inBufferLength;
      60            1 :     mQueueLength = 0;
      61            1 :     mQueueHead   = inHead;
      62              : 
      63            1 :     mProcessEvictedElement = nullptr;
      64            1 :     mAppData               = nullptr;
      65              : 
      66              :     // use common as opposed to unspecified, s.t. the reader that
      67              :     // skips over the elements does not complain about implicit
      68              :     // profile tags.
      69            1 :     mImplicitProfileId = kCommonProfileId;
      70            1 : }
      71              : 
      72              : /**
      73              :  * @brief
      74              :  *   TLVCircularBuffer constructor
      75              :  *
      76              :  * @param[in] inBuffer       A pointer to the backing store for the queue
      77              :  *
      78              :  * @param[in] inBufferLength Length, in bytes, of the backing store
      79              :  */
      80         1027 : TLVCircularBuffer::TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength)
      81              : {
      82         1027 :     Init(inBuffer, inBufferLength);
      83         1027 : }
      84              : 
      85              : /**
      86              :  * @brief
      87              :  *   TLVCircularBuffer Init function
      88              :  *
      89              :  * @param[in] inBuffer       A pointer to the backing store for the queue
      90              :  *
      91              :  * @param[in] inBufferLength Length, in bytes, of the backing store
      92              :  */
      93         1402 : void TLVCircularBuffer::Init(uint8_t * inBuffer, uint32_t inBufferLength)
      94              : {
      95         1402 :     mQueue       = inBuffer;
      96         1402 :     mQueueSize   = inBufferLength;
      97         1402 :     mQueueLength = 0;
      98         1402 :     mQueueHead   = mQueue;
      99              : 
     100         1402 :     mProcessEvictedElement = nullptr;
     101         1402 :     mAppData               = nullptr;
     102              : 
     103              :     // use common as opposed to unspecified, s.t. the reader that
     104              :     // skips over the elements does not complain about implicit
     105              :     // profile tags.
     106         1402 :     mImplicitProfileId = kCommonProfileId;
     107         1402 : }
     108              : 
     109              : /**
     110              :  * @brief
     111              :  *   Evicts the oldest top-level TLV element in the TLVCircularBuffer
     112              :  *
     113              :  * This function removes the oldest top level TLV element in the
     114              :  * buffer.  The function will call the callback registered at
     115              :  * #mProcessEvictedElement to process the element prior to removal.
     116              :  * If the callback returns anything but #CHIP_NO_ERROR, the element
     117              :  * is not removed.  Similarly, if any other error occurs -- no
     118              :  * elements within the buffer, etc -- the underlying
     119              :  * #TLVCircularBuffer remains unchanged.
     120              :  *
     121              :  *  @retval #CHIP_NO_ERROR On success.
     122              :  *
     123              :  *  @retval other          On any other error returned either by the callback
     124              :  *                         or by the TLVReader.
     125              :  *
     126              :  */
     127         1545 : CHIP_ERROR TLVCircularBuffer::EvictHead()
     128              : {
     129         1545 :     CircularTLVReader reader;
     130              :     uint8_t * newHead;
     131              :     uint32_t newLen;
     132              : 
     133              :     // find the boundaries of an event to throw away
     134         1545 :     reader.Init(*this);
     135         1545 :     reader.ImplicitProfileId = mImplicitProfileId;
     136              : 
     137              :     // position the reader on the first element
     138         1545 :     ReturnErrorOnFailure(reader.Next());
     139              : 
     140              :     // skip to the next element
     141         1545 :     ReturnErrorOnFailure(reader.Skip());
     142              : 
     143              :     // record the state of the queue post-call
     144         1544 :     newLen  = mQueueLength - (reader.GetLengthRead());
     145         1544 :     newHead = const_cast<uint8_t *>(reader.GetReadPoint());
     146              : 
     147              :     // if a custom handler is installed, give it a chance to
     148              :     // process the element before we evict it from the buffer.
     149         1544 :     if (mProcessEvictedElement != nullptr)
     150              :     {
     151              :         // Reinitialize the reader
     152         1116 :         reader.Init(*this);
     153         1116 :         reader.ImplicitProfileId = mImplicitProfileId;
     154              : 
     155         1116 :         ReturnErrorOnFailure(mProcessEvictedElement(*this, mAppData, reader));
     156              :     }
     157              : 
     158              :     // update queue state
     159          809 :     mQueueLength = newLen;
     160          809 :     mQueueHead   = newHead;
     161              : 
     162          809 :     return CHIP_NO_ERROR;
     163              : }
     164              : 
     165              : /**
     166              :  * @brief
     167              :  *  Implements TLVBackingStore::OnInit(TLVWriter) for circular buffers.
     168              :  */
     169           10 : CHIP_ERROR TLVCircularBuffer::OnInit(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen)
     170              : {
     171           10 :     return GetNewBuffer(writer, bufStart, bufLen);
     172              : }
     173              : 
     174              : /**
     175              :  * @brief
     176              :  *   Get additional space for the TLVWriter.  In actuality, the
     177              :  *   function evicts an element from the circular buffer, and adjusts
     178              :  *   the head of this buffer queue
     179              :  *
     180              :  * @param[in,out] ioWriter  TLVWriter calling this function
     181              :  *
     182              :  * @param[out] outBufStart The pointer to the new buffer
     183              :  *
     184              :  * @param[out] outBufLen   The available length for writing
     185              :  *
     186              :  * @retval #CHIP_NO_ERROR On success.
     187              :  *
     188              :  * @retval other           If the function was unable to elide a complete
     189              :  *                         top-level TLV element.
     190              :  */
     191              : 
     192          508 : CHIP_ERROR TLVCircularBuffer::GetNewBuffer(TLVWriter & ioWriter, uint8_t *& outBufStart, uint32_t & outBufLen)
     193              : {
     194          508 :     if (mQueueLength >= mQueueSize)
     195              :     {
     196              :         // Queue is out of space, need to evict an element
     197           18 :         ReturnErrorOnFailure(EvictHead());
     198              :     }
     199              : 
     200          507 :     GetCurrentWritableBuffer(outBufStart, outBufLen);
     201          507 :     return CHIP_NO_ERROR;
     202              : }
     203              : 
     204         1591 : void TLVCircularBuffer::GetCurrentWritableBuffer(uint8_t *& outBufStart, uint32_t & outBufLen) const
     205              : {
     206         1591 :     uint8_t * tail = QueueTail();
     207              : 
     208              :     // set the output values, returned buffer must be contiguous
     209         1591 :     outBufStart = tail;
     210              : 
     211         1591 :     if (tail >= mQueueHead)
     212              :     {
     213          351 :         outBufLen = mQueueSize - static_cast<uint32_t>(tail - mQueue);
     214              :     }
     215              :     else
     216              :     {
     217         1240 :         outBufLen = static_cast<uint32_t>(mQueueHead - tail);
     218              :     }
     219         1591 : }
     220              : 
     221              : /**
     222              :  * @brief
     223              :  *   FinalizeBuffer adjust the `TLVCircularBuffer` state on
     224              :  *   completion of output from the TLVWriter.  This function affects
     225              :  *   the position of the queue tail.
     226              :  *
     227              :  * @param[in,out] ioWriter TLVWriter calling this function
     228              :  *
     229              :  * @param[in] inBufStart pointer to the start of data (from `TLVWriter`
     230              :  *                       perspective)
     231              :  *
     232              :  * @param[in] inBufLen   length of data in the buffer pointed to by
     233              :  *                       `inbufStart`
     234              :  *
     235              :  * @retval #CHIP_NO_ERROR Unconditionally.
     236              :  */
     237              : 
     238         1605 : CHIP_ERROR TLVCircularBuffer::FinalizeBuffer(TLVWriter & ioWriter, uint8_t * inBufStart, uint32_t inBufLen)
     239              : {
     240         1605 :     CHIP_ERROR err = CHIP_NO_ERROR;
     241         1605 :     uint8_t * tail = inBufStart + inBufLen;
     242         1605 :     if (inBufLen)
     243              :     {
     244         1605 :         if (tail <= mQueueHead)
     245              :         {
     246         1242 :             mQueueLength = mQueueSize - static_cast<uint32_t>(mQueueHead - tail);
     247              :         }
     248              :         else
     249              :         {
     250          363 :             mQueueLength = static_cast<uint32_t>(tail - mQueueHead);
     251              :         }
     252              :     }
     253         1605 :     return err;
     254              : }
     255              : 
     256              : /**
     257              :  * @brief
     258              :  *  Implements TLVBackingStore::OnInit(TVLReader) for circular buffers.
     259              :  */
     260         4041 : CHIP_ERROR TLVCircularBuffer::OnInit(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen)
     261              : {
     262         4041 :     return GetNextBuffer(reader, bufStart, bufLen);
     263              : }
     264              : 
     265              : /**
     266              :  * @brief
     267              :  *   Get additional space for the TLVReader.
     268              :  *
     269              :  *  The storage provided by the TLVCircularBuffer may be
     270              :  *  wraparound within the buffer.  This function provides us with an
     271              :  *  ability to match the buffering of the circular buffer to the
     272              :  *  TLVReader constraints.  The reader will read at most `mQueueSize`
     273              :  *  bytes from the buffer.
     274              :  *
     275              :  * @param[in] ioReader         TLVReader calling this function.
     276              :  *
     277              :  * @param[in,out] outBufStart  The reference to the data buffer.  On
     278              :  *                             return, it is set to a value within this
     279              :  *                             buffer.
     280              :  *
     281              :  * @param[out] outBufLen       On return, set to the number of continuous
     282              :  *                             bytes that could be read out of the buffer.
     283              :  *
     284              :  * @retval #CHIP_NO_ERROR      Succeeds unconditionally.
     285              :  */
     286         6141 : CHIP_ERROR TLVCircularBuffer::GetNextBuffer(TLVReader & ioReader, const uint8_t *& outBufStart, uint32_t & outBufLen)
     287              : {
     288         6141 :     CHIP_ERROR err              = CHIP_NO_ERROR;
     289         6141 :     uint8_t * tail              = QueueTail();
     290         6141 :     const uint8_t * readerStart = outBufStart;
     291              : 
     292         6141 :     if (readerStart == nullptr)
     293              :     {
     294         5855 :         outBufStart = mQueueHead;
     295              : 
     296         5855 :         if (outBufStart == mQueue + mQueueSize)
     297              :         {
     298           10 :             outBufStart = mQueue;
     299              :         }
     300              :     }
     301          286 :     else if (readerStart >= (mQueue + mQueueSize))
     302              :     {
     303          238 :         outBufStart = mQueue;
     304              :     }
     305              :     else
     306              :     {
     307           48 :         outBufLen = 0;
     308           48 :         return err;
     309              :     }
     310              : 
     311         6093 :     if ((mQueueLength != 0) && (tail <= outBufStart))
     312              :     {
     313              :         // the buffer is non-empty and data wraps around the end
     314              :         // point.  The returned buffer conceptually spans from
     315              :         // outBufStart until the end of the underlying storage buffer
     316              :         // (i.e. mQueue+mQueueSize).  This case tail == outBufStart
     317              :         // indicates that the buffer is completely full
     318         3077 :         outBufLen = mQueueSize - static_cast<uint32_t>(outBufStart - mQueue);
     319         3077 :         if ((tail == outBufStart) && (readerStart != nullptr))
     320            0 :             outBufLen = 0;
     321              :     }
     322              :     else
     323              :     {
     324              :         // the buffer length is the distance between head and tail;
     325              :         // tail is either strictly larger or the buffer is empty
     326         3016 :         outBufLen = static_cast<uint32_t>(tail - outBufStart);
     327              :     }
     328         6093 :     return err;
     329              : }
     330              : 
     331              : } // namespace TLV
     332              : } // namespace chip
        

Generated by: LCOV version 2.0-1