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 defines 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 :
30 : #pragma once
31 :
32 : #include <lib/core/CHIPError.h>
33 : #include <lib/core/TLVBackingStore.h>
34 : #include <lib/core/TLVReader.h>
35 : #include <lib/core/TLVWriter.h>
36 : #include <lib/support/DLLUtil.h>
37 :
38 : #include <stdint.h>
39 : #include <stdlib.h>
40 :
41 : namespace chip {
42 : namespace TLV {
43 :
44 : /**
45 : * @class TLVCircularBuffer
46 : *
47 : * @brief
48 : * TLVCircularBuffer provides circular storage for the
49 : * chip::TLV::TLVWriter and chip::TLVTLVReader. chip::TLV::TLVWriter is able to write an
50 : * unbounded number of TLV entries to the TLVCircularBuffer
51 : * as long as each individual TLV entry fits entirely within the
52 : * provided storage. The chip::TLV::TLVReader will read at most the size of
53 : * the buffer, but will accommodate the wraparound within the
54 : * buffer.
55 : *
56 : */
57 : class DLL_EXPORT TLVCircularBuffer : public chip::TLV::TLVBackingStore
58 : {
59 : public:
60 : TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength);
61 : TLVCircularBuffer(uint8_t * inBuffer, uint32_t inBufferLength, uint8_t * inHead);
62 :
63 : void Init(uint8_t * inBuffer, uint32_t inBufferLength);
64 : inline uint8_t * QueueHead() const { return mQueueHead; }
65 7732 : inline uint8_t * QueueTail() const { return mQueue + ((static_cast<size_t>(mQueueHead - mQueue) + mQueueLength) % mQueueSize); }
66 4978 : inline uint32_t DataLength() const { return mQueueLength; }
67 3281 : inline uint32_t AvailableDataLength() const { return mQueueSize - mQueueLength; }
68 1366 : inline uint32_t GetTotalDataLength() const { return mQueueSize; }
69 12 : inline uint8_t * GetQueue() const { return mQueue; }
70 :
71 : CHIP_ERROR EvictHead();
72 :
73 : // chip::TLV::TLVBackingStore overrides:
74 : CHIP_ERROR OnInit(TLVReader & reader, const uint8_t *& bufStart, uint32_t & bufLen) override;
75 : CHIP_ERROR GetNextBuffer(TLVReader & ioReader, const uint8_t *& outBufStart, uint32_t & outBufLen) override;
76 : CHIP_ERROR OnInit(TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen) override;
77 : CHIP_ERROR GetNewBuffer(TLVWriter & ioWriter, uint8_t *& outBufStart, uint32_t & outBufLen) override;
78 : CHIP_ERROR FinalizeBuffer(TLVWriter & ioWriter, uint8_t * inBufStart, uint32_t inBufLen) override;
79 :
80 : /**
81 : * @typedef CHIP_ERROR (*ProcessEvictedElementFunct)(TLVCircularBuffer &inBuffer, void * inAppData, TLVReader &inReader)
82 : *
83 : * A function that is called to process a TLV element prior to it
84 : * being evicted from the chip::TLV::TLVCircularBuffer
85 : *
86 : * Functions of this type are used to process a TLV element about
87 : * to be evicted from the buffer. The function will be given a
88 : * chip::TLV::TLVReader positioned on the element about to be deleted, as
89 : * well as void * context where the user may have provided
90 : * additional environment for the callback. If the function
91 : * processed the element successfully, it must return
92 : * #CHIP_NO_ERROR ; this signifies to the TLVCircularBuffer
93 : * that the element may be safely evicted. Any other return
94 : * value is treated as an error and will prevent the
95 : * #TLVCircularBuffer from evicting the element under
96 : * consideration.
97 : *
98 : * Note: This callback may be used to force
99 : * TLVCircularBuffer to not evict the element. This may be
100 : * useful in a number of circumstances, when it is desired to
101 : * have an underlying circular buffer, but not to override any
102 : * elements within it.
103 : *
104 : * @param[in] inBuffer A reference to the buffer from which the
105 : * eviction takes place
106 : *
107 : * @param[in] inAppData A pointer to the user-provided structure
108 : * containing additional context for this
109 : * callback
110 : *
111 : * @param[in] inReader A TLVReader positioned at the element to
112 : * be evicted.
113 : *
114 : * @retval #CHIP_NO_ERROR On success. Element will be evicted.
115 : *
116 : * @retval other An error has occurred during the event
117 : * processing. The element stays in the
118 : * buffer. The write function that
119 : * triggered this element eviction will
120 : * fail.
121 : */
122 : typedef CHIP_ERROR (*ProcessEvictedElementFunct)(TLVCircularBuffer & inBuffer, void * inAppData, TLVReader & inReader);
123 :
124 : uint32_t mImplicitProfileId;
125 : void * mAppData; /**< An optional, user supplied context to be used with the callback processing the evicted element. */
126 : ProcessEvictedElementFunct
127 : mProcessEvictedElement; /**< An optional, user-supplied callback that processes the element prior to evicting it from the
128 : circular buffer. See the ProcessEvictedElementFunct type definition on additional information on
129 : implementing the mProcessEvictedElement function. */
130 :
131 : protected:
132 : /**
133 : * @brief
134 : * returns the actual state of what our current available buffer space is
135 : *
136 : * @param[out] outBufStart The pointer to the current buffer
137 : *
138 : * @param[out] outBufLen The available length for writing
139 : */
140 : void GetCurrentWritableBuffer(uint8_t *& outBufStart, uint32_t & outBufLen) const;
141 :
142 : private:
143 : uint8_t * mQueue;
144 : uint32_t mQueueSize;
145 : uint8_t * mQueueHead;
146 : uint32_t mQueueLength;
147 : };
148 :
149 : class DLL_EXPORT CircularTLVReader : public TLVReader
150 : {
151 : public:
152 : /**
153 : * @brief
154 : * Initializes a TLVReader object to read from a single TLVCircularBuffer
155 : *
156 : * Parsing begins at the start of the buffer (obtained by the
157 : * buffer->Start() position) and continues until the end of the buffer
158 : * Parsing may wraparound within the buffer (on any element). At most
159 : * buffer->GetQueueSize() bytes are read out.
160 : *
161 : * @param[in] buf A pointer to a fully initialized TLVCircularBuffer
162 : *
163 : */
164 3044 : void Init(TLVCircularBuffer & buf) { TLVReader::Init(buf, buf.DataLength()); }
165 : };
166 :
167 : class DLL_EXPORT CircularTLVWriter : public TLVWriter
168 : {
169 : public:
170 : /**
171 : * @brief
172 : * Initializes a TLVWriter object to write from a single TLVCircularBuffer
173 : *
174 : * Writing begins at the last byte of the buffer. The number of bytes
175 : * to be written is not constrained by the underlying circular buffer:
176 : * writing new elements to the buffer will kick out previous elements
177 : * as long as an individual top-level TLV structure fits within the
178 : * buffer. For example, writing a 7-byte top-level boolean TLV into a
179 : * 7 byte buffer will work indefinitely, but writing an 8-byte TLV
180 : * structure will result in an error.
181 : *
182 : * @param[in] buf A pointer to a fully initialized TLVCircularBuffer
183 : *
184 : */
185 1084 : void Init(TLVCircularBuffer & buf) { TLVWriter::Init(buf, UINT32_MAX); }
186 : };
187 :
188 : } // namespace TLV
189 : } // namespace chip
|