1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#ifndef DFX_RING_BUFFER_H
17800b99b8Sopenharmony_ci#define DFX_RING_BUFFER_H
18800b99b8Sopenharmony_ci
19800b99b8Sopenharmony_ci#include "dfx_ring_buffer_block.h"
20800b99b8Sopenharmony_ci
21800b99b8Sopenharmony_ci/**
22800b99b8Sopenharmony_ci * @brief            A ring buffer is a FIFO structure that can be used to
23800b99b8Sopenharmony_ci *                     spool data between devices.
24800b99b8Sopenharmony_ci *
25800b99b8Sopenharmony_ci *                     There is a Skip() function that allows the client to
26800b99b8Sopenharmony_ci *                     control when the read cursor is changed. This is so the
27800b99b8Sopenharmony_ci *                     client can perform an action after Read() without the
28800b99b8Sopenharmony_ci *                     write cursor overwriting data while the read block is used.
29800b99b8Sopenharmony_ci *
30800b99b8Sopenharmony_ci *                     For e.g with the sequence of events:
31800b99b8Sopenharmony_ci *                         1.    Read(1000, false)
32800b99b8Sopenharmony_ci *                         2.    Busy writing to sd card for 5 seconds
33800b99b8Sopenharmony_ci *                         3.    Skip()
34800b99b8Sopenharmony_ci *
35800b99b8Sopenharmony_ci *                     Because the skip isn't called until the writing
36800b99b8Sopenharmony_ci *                     has finished, another thread can .Append() without
37800b99b8Sopenharmony_ci *                     corrupting the data being written.
38800b99b8Sopenharmony_ci *
39800b99b8Sopenharmony_ci *
40800b99b8Sopenharmony_ci * @attention        The ring buffer can only contain Length-1 number of entries,
41800b99b8Sopenharmony_ci *                   because the last index is reserved for overrun checks.
42800b99b8Sopenharmony_ci *
43800b99b8Sopenharmony_ci * @tparam Length    The length of the backing store array.
44800b99b8Sopenharmony_ci * @tparam T         The type of data stored.
45800b99b8Sopenharmony_ci */
46800b99b8Sopenharmony_citemplate<unsigned int LENGTH, class T>
47800b99b8Sopenharmony_ciclass DfxRingBuffer {
48800b99b8Sopenharmony_cipublic:
49800b99b8Sopenharmony_ci    DfxRingBuffer() : readPosition(0), writePosition(0), data{{T()}}, overrunFlag(false)
50800b99b8Sopenharmony_ci    {
51800b99b8Sopenharmony_ci    }
52800b99b8Sopenharmony_ci
53800b99b8Sopenharmony_ci    ~DfxRingBuffer()
54800b99b8Sopenharmony_ci    {
55800b99b8Sopenharmony_ci    }
56800b99b8Sopenharmony_ci
57800b99b8Sopenharmony_ci    /**
58800b99b8Sopenharmony_ci     * @brief     Appends a value the end of the
59800b99b8Sopenharmony_ci     *            buffer.
60800b99b8Sopenharmony_ci     */
61800b99b8Sopenharmony_ci    void Append(T& value)
62800b99b8Sopenharmony_ci    {
63800b99b8Sopenharmony_ci        /*
64800b99b8Sopenharmony_ci         * If the next position is where the read cursor
65800b99b8Sopenharmony_ci         * is then we have a full buffer.
66800b99b8Sopenharmony_ci         */
67800b99b8Sopenharmony_ci        bool bufferFull;
68800b99b8Sopenharmony_ci
69800b99b8Sopenharmony_ci        bufferFull = ((writePosition + 1U) % LENGTH) == readPosition;
70800b99b8Sopenharmony_ci
71800b99b8Sopenharmony_ci        if (bufferFull) {
72800b99b8Sopenharmony_ci            /*
73800b99b8Sopenharmony_ci             * Tried to append a value while the buffer is full.
74800b99b8Sopenharmony_ci             */
75800b99b8Sopenharmony_ci            overrunFlag = true;
76800b99b8Sopenharmony_ci        } else {
77800b99b8Sopenharmony_ci            /*
78800b99b8Sopenharmony_ci             * Buffer isn't full yet, write to the curr write position
79800b99b8Sopenharmony_ci             * and increment it by 1.
80800b99b8Sopenharmony_ci             */
81800b99b8Sopenharmony_ci            overrunFlag         = false;
82800b99b8Sopenharmony_ci            data[writePosition] = value;
83800b99b8Sopenharmony_ci            writePosition       = (writePosition + 1U) % LENGTH;
84800b99b8Sopenharmony_ci        }
85800b99b8Sopenharmony_ci    }
86800b99b8Sopenharmony_ci
87800b99b8Sopenharmony_ci    /**
88800b99b8Sopenharmony_ci     * @brief                        Retrieve a continuous block of
89800b99b8Sopenharmony_ci     *                               valid buffered data.
90800b99b8Sopenharmony_ci     * @param numReadsRequested    How many reads are required.
91800b99b8Sopenharmony_ci     * @return                       A block of items containing the maximum
92800b99b8Sopenharmony_ci     *                               number the buffer can provide at this time.
93800b99b8Sopenharmony_ci     */
94800b99b8Sopenharmony_ci    DfxRingBufferBlock<T> Read(unsigned int numReadsRequested)
95800b99b8Sopenharmony_ci    {
96800b99b8Sopenharmony_ci        bool bridgesZero;
97800b99b8Sopenharmony_ci        DfxRingBufferBlock<T> block;
98800b99b8Sopenharmony_ci
99800b99b8Sopenharmony_ci        /*
100800b99b8Sopenharmony_ci          * Make sure the number of reads does not bridge the 0 index.
101800b99b8Sopenharmony_ci          * This is because we can only provide 1 contiguous block at
102800b99b8Sopenharmony_ci          * a time.
103800b99b8Sopenharmony_ci          */
104800b99b8Sopenharmony_ci        bridgesZero = (readPosition > writePosition);
105800b99b8Sopenharmony_ci
106800b99b8Sopenharmony_ci        if (bridgesZero) {
107800b99b8Sopenharmony_ci            unsigned int readsToEnd;
108800b99b8Sopenharmony_ci            bool reqSurpassesBufferEnd;
109800b99b8Sopenharmony_ci
110800b99b8Sopenharmony_ci            readsToEnd = LENGTH - readPosition;
111800b99b8Sopenharmony_ci            reqSurpassesBufferEnd = numReadsRequested > readsToEnd;
112800b99b8Sopenharmony_ci
113800b99b8Sopenharmony_ci            if (reqSurpassesBufferEnd) {
114800b99b8Sopenharmony_ci                /*
115800b99b8Sopenharmony_ci                 * If the block requested exceeds the buffer end. Then
116800b99b8Sopenharmony_ci                 * return a block that reaches the end and no more.
117800b99b8Sopenharmony_ci                 */
118800b99b8Sopenharmony_ci                block.SetStart(&(data[readPosition]));
119800b99b8Sopenharmony_ci                block.SetLength(readsToEnd);
120800b99b8Sopenharmony_ci            } else {
121800b99b8Sopenharmony_ci                /*
122800b99b8Sopenharmony_ci                 * If the block requested does not exceed 0
123800b99b8Sopenharmony_ci                 * then return a block that reaches the number of reads required.
124800b99b8Sopenharmony_ci                 */
125800b99b8Sopenharmony_ci                block.SetStart(&(data[readPosition]));
126800b99b8Sopenharmony_ci                block.SetLength(numReadsRequested);
127800b99b8Sopenharmony_ci            }
128800b99b8Sopenharmony_ci        } else {
129800b99b8Sopenharmony_ci            /*
130800b99b8Sopenharmony_ci             * If the block doesn't bridge the zero then
131800b99b8Sopenharmony_ci             * return the maximum number of reads to the write
132800b99b8Sopenharmony_ci             * cursor.
133800b99b8Sopenharmony_ci             */
134800b99b8Sopenharmony_ci            unsigned int maxNumReads;
135800b99b8Sopenharmony_ci            unsigned int numReadsToWritePosition;
136800b99b8Sopenharmony_ci
137800b99b8Sopenharmony_ci            numReadsToWritePosition = (writePosition - readPosition);
138800b99b8Sopenharmony_ci
139800b99b8Sopenharmony_ci            if (numReadsRequested > numReadsToWritePosition) {
140800b99b8Sopenharmony_ci                /*
141800b99b8Sopenharmony_ci                 * If the block length requested exceeds the
142800b99b8Sopenharmony_ci                 * number of items available, then restrict
143800b99b8Sopenharmony_ci                 * the block length to the distance to the write position.
144800b99b8Sopenharmony_ci                 */
145800b99b8Sopenharmony_ci                maxNumReads = numReadsToWritePosition;
146800b99b8Sopenharmony_ci            } else {
147800b99b8Sopenharmony_ci                /*
148800b99b8Sopenharmony_ci                 * If the block length requested does not exceed the
149800b99b8Sopenharmony_ci                 * number of items available then the entire
150800b99b8Sopenharmony_ci                 * block is valid.
151800b99b8Sopenharmony_ci                 */
152800b99b8Sopenharmony_ci                maxNumReads = numReadsRequested;
153800b99b8Sopenharmony_ci            }
154800b99b8Sopenharmony_ci
155800b99b8Sopenharmony_ci            block.SetStart(&(data[readPosition]));
156800b99b8Sopenharmony_ci            block.SetLength(maxNumReads);
157800b99b8Sopenharmony_ci        }
158800b99b8Sopenharmony_ci
159800b99b8Sopenharmony_ci        return block;
160800b99b8Sopenharmony_ci    }
161800b99b8Sopenharmony_ci
162800b99b8Sopenharmony_ci    /**
163800b99b8Sopenharmony_ci     * @brief    Advances the read position.
164800b99b8Sopenharmony_ci     *
165800b99b8Sopenharmony_ci     */
166800b99b8Sopenharmony_ci    void Skip(unsigned int numReads)
167800b99b8Sopenharmony_ci    {
168800b99b8Sopenharmony_ci        readPosition = (readPosition + numReads) % LENGTH;
169800b99b8Sopenharmony_ci    }
170800b99b8Sopenharmony_ci
171800b99b8Sopenharmony_ci    bool Overrun() const
172800b99b8Sopenharmony_ci    {
173800b99b8Sopenharmony_ci        return overrunFlag;
174800b99b8Sopenharmony_ci    }
175800b99b8Sopenharmony_ci
176800b99b8Sopenharmony_ci    /**
177800b99b8Sopenharmony_ci     * @brief    The total size of the ring buffer including the full position.
178800b99b8Sopenharmony_ci     *
179800b99b8Sopenharmony_ci     */
180800b99b8Sopenharmony_ci    unsigned int Length() const
181800b99b8Sopenharmony_ci    {
182800b99b8Sopenharmony_ci        return LENGTH;
183800b99b8Sopenharmony_ci    }
184800b99b8Sopenharmony_ci
185800b99b8Sopenharmony_ci    /**
186800b99b8Sopenharmony_ci     * @brief    Returns the number of reads available.
187800b99b8Sopenharmony_ci     *
188800b99b8Sopenharmony_ci     */
189800b99b8Sopenharmony_ci    unsigned int Available()
190800b99b8Sopenharmony_ci    {
191800b99b8Sopenharmony_ci        bool bridgesZero;
192800b99b8Sopenharmony_ci        unsigned availableReads;
193800b99b8Sopenharmony_ci
194800b99b8Sopenharmony_ci        bridgesZero = readPosition > writePosition;
195800b99b8Sopenharmony_ci        availableReads = 0;
196800b99b8Sopenharmony_ci
197800b99b8Sopenharmony_ci        if (bridgesZero) {
198800b99b8Sopenharmony_ci            /* Add the number of reads to zero, and number of reads from 0 to the write cursor */
199800b99b8Sopenharmony_ci            unsigned int numReadsToZero;
200800b99b8Sopenharmony_ci            unsigned int numReadsToWritePosition;
201800b99b8Sopenharmony_ci
202800b99b8Sopenharmony_ci            numReadsToZero = LENGTH - readPosition;
203800b99b8Sopenharmony_ci            numReadsToWritePosition = writePosition;
204800b99b8Sopenharmony_ci
205800b99b8Sopenharmony_ci            availableReads = numReadsToZero + numReadsToWritePosition;
206800b99b8Sopenharmony_ci        } else {
207800b99b8Sopenharmony_ci            /* The number of available reads is between the write position and the read position. */
208800b99b8Sopenharmony_ci            availableReads = writePosition - readPosition;
209800b99b8Sopenharmony_ci        }
210800b99b8Sopenharmony_ci
211800b99b8Sopenharmony_ci        return availableReads;
212800b99b8Sopenharmony_ci    }
213800b99b8Sopenharmony_ci
214800b99b8Sopenharmony_ciprivate:
215800b99b8Sopenharmony_ci    volatile unsigned int readPosition;
216800b99b8Sopenharmony_ci    volatile unsigned int writePosition;
217800b99b8Sopenharmony_ci
218800b99b8Sopenharmony_ci    T data[LENGTH] = {T()};
219800b99b8Sopenharmony_ci
220800b99b8Sopenharmony_ci    bool overrunFlag = false;
221800b99b8Sopenharmony_ci};
222800b99b8Sopenharmony_ci
223800b99b8Sopenharmony_ci#endif
224