Pico-Arduino
RingBuffer.h
1 /*
2  Copyright (c) 2014 Arduino. All right reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  See the GNU Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #ifdef __cplusplus
20 
21 #ifndef _RING_BUFFER_
22 #define _RING_BUFFER_
23 
24 #include <stdint.h>
25 #include <string.h>
26 
27 namespace arduino {
28 
29 // Define constants and variables for buffering incoming serial data. We're
30 // using a ring buffer (I think), in which head is the index of the location
31 // to which to write the next incoming character and tail is the index of the
32 // location from which to read.
33 #define SERIAL_BUFFER_SIZE 64
34 
35 template <int N>
36 class RingBufferN
37 {
38  public:
39  uint8_t _aucBuffer[N] ;
40  volatile int _iHead ;
41  volatile int _iTail ;
42  volatile int _numElems;
43 
44  public:
45  RingBufferN( void ) ;
46  void store_char( uint8_t c ) ;
47  void clear();
48  int read_char();
49  int available();
50  int availableForStore();
51  int peek();
52  bool isFull();
53 
54  private:
55  int nextIndex(int index);
56  inline bool isEmpty() const { return (_numElems == 0); }
57 };
58 
59 typedef RingBufferN<SERIAL_BUFFER_SIZE> RingBuffer;
60 
61 
62 template <int N>
63 RingBufferN<N>::RingBufferN( void )
64 {
65  memset( _aucBuffer, 0, N ) ;
66  clear();
67 }
68 
69 template <int N>
70 void RingBufferN<N>::store_char( uint8_t c )
71 {
72  // if we should be storing the received character into the location
73  // just before the tail (meaning that the head would advance to the
74  // current location of the tail), we're about to overflow the buffer
75  // and so we don't write the character or advance the head.
76  if (!isFull())
77  {
78  _aucBuffer[_iHead] = c ;
79  _iHead = nextIndex(_iHead);
80  _numElems++;
81  }
82 }
83 
84 template <int N>
85 void RingBufferN<N>::clear()
86 {
87  _iHead = 0;
88  _iTail = 0;
89  _numElems = 0;
90 }
91 
92 template <int N>
93 int RingBufferN<N>::read_char()
94 {
95  if (isEmpty())
96  return -1;
97 
98  uint8_t value = _aucBuffer[_iTail];
99  _iTail = nextIndex(_iTail);
100  _numElems--;
101 
102  return value;
103 }
104 
105 template <int N>
106 int RingBufferN<N>::available()
107 {
108  return _numElems;
109 }
110 
111 template <int N>
112 int RingBufferN<N>::availableForStore()
113 {
114  return (N - _numElems);
115 }
116 
117 template <int N>
118 int RingBufferN<N>::peek()
119 {
120  if (isEmpty())
121  return -1;
122 
123  return _aucBuffer[_iTail];
124 }
125 
126 template <int N>
127 int RingBufferN<N>::nextIndex(int index)
128 {
129  return (uint32_t)(index + 1) % N;
130 }
131 
132 template <int N>
133 bool RingBufferN<N>::isFull()
134 {
135  return (_numElems == N);
136 }
137 
138 }
139 
140 #endif /* _RING_BUFFER_ */
141 #endif /* __cplusplus */