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