blob: fc77dc8345a23342a757850c91ac05a4673ab551 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2016-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines the circular buffer for TLV
* elements. When used as the backing store for the TLVReader and
* TLVWriter, those classes will work with the wraparound of data
* within the buffer. Additionally, the TLVWriter will be able
* to continually add top-level TLV elements by evicting
* pre-existing elements.
*/
#pragma once
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPTLV.h>
#include <lib/core/CHIPTLVTags.h>
#include <lib/core/CHIPTLVTypes.h>
#include <lib/support/DLLUtil.h>
#include <stdlib.h>
namespace chip {
namespace TLV {
/**
* @class CHIPCircularTLVBuffer
*
* @brief
* CHIPCircularTLVBuffer provides circular storage for the
* chip::TLV::TLVWriter and chip::TLVTLVReader. chip::TLV::TLVWriter is able to write an
* unbounded number of TLV entries to the CHIPCircularTLVBuffer
* as long as each individual TLV entry fits entirely within the
* provided storage. The chip::TLV::TLVReader will read at most the size of
* the buffer, but will accommodate the wraparound within the
* buffer.
*
*/
class DLL_EXPORT CHIPCircularTLVBuffer : public chip::TLV::TLVBackingStore
{
public:
CHIPCircularTLVBuffer(uint8_t * inBuffer, uint32_t inBufferLength);
CHIPCircularTLVBuffer(uint8_t * inBuffer, uint32_t inBufferLength, uint8_t * inHead);
void Init(uint8_t * inBuffer, uint32_t inBufferLength);
inline uint8_t * QueueHead() const { return mQueueHead; }
inline uint8_t * QueueTail() const { return mQueue + ((static_cast<size_t>(mQueueHead - mQueue) + mQueueLength) % mQueueSize); }
inline uint32_t DataLength() const { return mQueueLength; }
inline uint32_t AvailableDataLength() const { return mQueueSize - mQueueLength; }
inline uint32_t GetTotalDataLength() const { return mQueueSize; }
inline uint8_t * GetQueue() const { return mQueue; }
CHIP_ERROR EvictHead();
// chip::TLV::TLVBackingStore overrides:
CHIP_ERROR OnInit(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen) override;
CHIP_ERROR GetNextBuffer(TLVReader & ioReader, const uint8_t *& outBufStart, uint32_t & outBufLen) override;
CHIP_ERROR OnInit(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen) override;
CHIP_ERROR GetNewBuffer(TLVWriter & ioWriter, uint8_t *& outBufStart, uint32_t & outBufLen) override;
CHIP_ERROR FinalizeBuffer(TLVWriter & ioWriter, uint8_t * inBufStart, uint32_t inBufLen) override;
/**
* @typedef CHIP_ERROR (*ProcessEvictedElementFunct)(CHIPCircularTLVBuffer &inBuffer, void * inAppData, TLVReader &inReader)
*
* A function that is called to process a TLV element prior to it
* being evicted from the chip::TLV::CHIPCircularTLVBuffer
*
* Functions of this type are used to process a TLV element about
* to be evicted from the buffer. The function will be given a
* chip::TLV::TLVReader positioned on the element about to be deleted, as
* well as void * context where the user may have provided
* additional environment for the callback. If the function
* processed the element successfully, it must return
* #CHIP_NO_ERROR ; this signifies to the CHIPCircularTLVBuffer
* that the element may be safely evicted. Any other return
* value is treated as an error and will prevent the
* #CHIPCircularTLVBuffer from evicting the element under
* consideration.
*
* Note: This callback may be used to force
* CHIPCircularTLVBuffer to not evict the element. This may be
* useful in a number of circumstances, when it is desired to
* have an underlying circular buffer, but not to override any
* elements within it.
*
* @param[in] inBuffer A reference to the buffer from which the
* eviction takes place
*
* @param[in] inAppData A pointer to the user-provided structure
* containing additional context for this
* callback
*
* @param[in] inReader A TLVReader positioned at the element to
* be evicted.
*
* @retval #CHIP_NO_ERROR On success. Element will be evicted.
*
* @retval other An error has occurred during the event
* processing. The element stays in the
* buffer. The write function that
* triggered this element eviction will
* fail.
*/
typedef CHIP_ERROR (*ProcessEvictedElementFunct)(CHIPCircularTLVBuffer & inBuffer, void * inAppData, TLVReader & inReader);
uint32_t mImplicitProfileId;
void * mAppData; /**< An optional, user supplied context to be used with the callback processing the evicted element. */
ProcessEvictedElementFunct
mProcessEvictedElement; /**< An optional, user-supplied callback that processes the element prior to evicting it from the
circular buffer. See the ProcessEvictedElementFunct type definition on additional information on
implementing the mProcessEvictedElement function. */
private:
uint8_t * mQueue;
uint32_t mQueueSize;
uint8_t * mQueueHead;
uint32_t mQueueLength;
};
class DLL_EXPORT CircularTLVReader : public TLVReader
{
public:
/**
* @brief
* Initializes a TLVReader object to read from a single CHIPCircularTLVBuffer
*
* Parsing begins at the start of the buffer (obtained by the
* buffer->Start() position) and continues until the end of the buffer
* Parsing may wraparound within the buffer (on any element). At most
* buffer->GetQueueSize() bytes are read out.
*
* @param[in] buf A pointer to a fully initialized CHIPCircularTLVBuffer
*
*/
void Init(CHIPCircularTLVBuffer & buf) { TLVReader::Init(buf, buf.DataLength()); }
};
class DLL_EXPORT CircularTLVWriter : public TLVWriter
{
public:
/**
* @brief
* Initializes a TLVWriter object to write from a single CHIPCircularTLVBuffer
*
* Writing begins at the last byte of the buffer. The number of bytes
* to be written is not constrained by the underlying circular buffer:
* writing new elements to the buffer will kick out previous elements
* as long as an individual top-level TLV structure fits within the
* buffer. For example, writing a 7-byte top-level boolean TLV into a
* 7 byte buffer will work indefinitely, but writing an 8-byte TLV
* structure will result in an error.
*
* @param[in] buf A pointer to a fully initialized CHIPCircularTLVBuffer
*
*/
void Init(CHIPCircularTLVBuffer & buf) { TLVWriter::Init(buf, UINT32_MAX); }
};
} // namespace TLV
} // namespace chip