-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
RingBuffer.c
executable file
·236 lines (221 loc) · 6.82 KB
/
RingBuffer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**
*******************************************
* @file RingBuffer.c
* @author Dmitriy Semenov / Crazy_Geeks
* @version 1.2
* @date 05-March-2022
* @brief Source file for RingBuffer lib
* @note https://crazygeeks.ru/c-ringbuffer/
*******************************************
*/
#include "RingBuffer.h"
/**
* @addtogroup RING_BUF
* @{
*/
/**
* @brief Init ring buffer
*
* @param[in] buf Pointer to the allocated buffer
* @param[in] size Size of buffer
* @param[in] cellsize Size of 1 cell [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Init(void *buf, u16_t size, size_t cellsize, RINGBUF_t *rb) {
rb->size = size; // size of array
rb->cell_size = cellsize; // size of 1 cell of array
rb->buf = buf; // set pointer to buffer
RingBuf_Clear(rb); // clear all
return rb->buf ? RINGBUF_OK : RINGBUF_PARAM_ERR;
}
/**
* @brief Clear ring buffer
* @note Disable interrupts while clearing
*
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Clear(RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
rb->head = rb->tail = 0;
return RINGBUF_OK;
}
/**
* @brief Check available size to read
*
* @param[out] len Size to read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_Available(u16_t *len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
if (rb->head < rb->tail)
*len = rb->size - rb->tail + rb->head;
else
*len = rb->head - rb->tail;
return RINGBUF_OK;
}
/**
* @brief Put byte to the buffer
*
* @param[in] data Data byte to be put [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_BytePut(const u8_t data, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
rb->buf[rb->head++] = data; // put byte in cell and increment data
if (rb->head >= rb->size) // if overflow
rb->head = 0; // set to start
return RINGBUF_OK;
}
/**
* @brief Put 1 cell to the buffer
* @param[in] data Pointer to data
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellPut(const void *data, RINGBUF_t *rb) {
return RingBuf_DataPut(data, 1, rb);
}
/**
* @brief Put some data to the buffer
*
* @param[in] data Data to be put
* @param[in] len Length of data to be written [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataPut(const void *data, u16_t len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
if (len > rb->size)
return RINGBUF_OVERFLOW;
const char *input = data; // recast pointer
// INPUT data index start address
size_t s_addr = 0;
// available space in the end of buffer
size_t space = rb->size - rb->head;
if (len > space) { // if len > available space
// copy data to available space
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], space * rb->cell_size);
// next writing will start from 0
rb->head = 0;
// new start address = space length
s_addr = space;
// new length = len-space
len -= space;
}
// copy all the data to the buf storage
memcpy(&rb->buf[rb->head*rb->cell_size], &input[s_addr * rb->cell_size], len * rb->cell_size);
// shift to the next head
rb->head += len;
if (rb->head >= rb->size)
rb->head = 0;
return RINGBUF_OK;
}
/**
* @brief Read next byte from the buffer
*
* @param[out] data Data byte from the buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_ByteRead(u8_t *data, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
RINGBUF_STATUS st = RingBuf_ByteWatch(data, rb);
if (st != RINGBUF_OK)
return st;
rb->tail++;
if (rb->tail >= rb->size)
rb->tail = 0;
return st;
}
/**
* @brief Read 1 cell from buf
* @param[out] data Data cell from the buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellRead(void *data, RINGBUF_t *rb) {
return RingBuf_DataRead(data, 1, rb);
}
/**
* @brief Read some next data from the buffer
*
* @param[out] data Data from the buffer
* @param[in] len Length of data to be read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataRead(void *data, u16_t len, RINGBUF_t *rb) {
if (rb->buf == NULL) return RINGBUF_PARAM_ERR;
// read data
RINGBUF_STATUS st = RingBuf_DataWatch(data, len, rb);
if (st != RINGBUF_OK)
return st;
// shift to the next head
rb->tail += len;
if (rb->tail >= rb->size)
rb->tail = 0;
return st;
}
/**
* @brief Watch current byte in buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Pointer to data byte got from buffer
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_ByteWatch(u8_t *data, RINGBUF_t *rb) {
if (data == NULL) return RINGBUF_PARAM_ERR;
*data = rb->buf[rb->tail];
return RINGBUF_OK;
}
/**
* @brief Watch 1 cell from buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Pointer to data cell got from buffer
* @param[in] #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_CellWatch(void *data, RINGBUF_t *rb) {
return RingBuf_DataWatch(data, 1, rb);
}
/**
* @brief Watch current data in the buf
* @note Reads data without shifting in the buffer
*
* @param[out] data Data from buffer
* @param[in] len Length of data to be read [bytes]
* @param[in] rb #RINGBUF_t structure instance
* @return #RINGBUF_STATUS enum
*/
RINGBUF_STATUS RingBuf_DataWatch(void *data, u16_t len, RINGBUF_t *rb) {
if (data == NULL)
return RINGBUF_PARAM_ERR;
if (len > rb->size)
return RINGBUF_OVERFLOW;
// OUTPUT data index start address
u16_t s_addr = 0;
// available space in the end of buffer
u16_t space = rb->size - rb->tail;
u16_t loc_tail = rb->tail;
if (len > space) { // if len > available space
// recast pointer to u8_t
// copy data from available space
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], space * rb->cell_size);
// next reading will start from 0
loc_tail = 0;
// new start address - space length
s_addr = space;
// new length - len-space
len -= space;
}
// copy all the data from the buf storage
memcpy(&data[s_addr * rb->cell_size], &rb->buf[loc_tail * rb->cell_size], len * rb->cell_size);
return RINGBUF_OK;
}
/// @} RING_BUF Group