ASCII Serial Com
Serial communication library between computers, microcontrollers, FPGAs, etc. Uses only ASCII. Not the most efficient protocol, but meant to be easy to read
Loading...
Searching...
No Matches
circular_buffer.c
Go to the documentation of this file.
1#include "circular_buffer.h"
2#include "asc_exception.h"
3#include <stdlib.h>
4
5#ifdef linux
6#include <errno.h>
7#include <stdio.h>
8#include <unistd.h>
9#endif
10
11/** \file */
12
13// Private helper functions
14
15inline void inc_iStart_uint8(circular_buffer_uint8 *buf);
16inline void inc_iStop_uint8(circular_buffer_uint8 *buf);
17inline void dec_iStart_uint8(circular_buffer_uint8 *buf);
18inline void dec_iStop_uint8(circular_buffer_uint8 *buf);
19#define isPowerOfTwo(x) ((x != 0) && ((x & (~x + 1)) == x))
20
21void inc_iStart_uint8(circular_buffer_uint8 *buf) {
22 buf->iStart = (buf->iStart + 1) & (buf->capacity - 1);
23}
24
25void inc_iStop_uint8(circular_buffer_uint8 *buf) {
26 buf->iStop = (buf->iStop + 1) & (buf->capacity - 1);
27}
28
29void dec_iStart_uint8(circular_buffer_uint8 *buf) {
30 if (buf->iStart == 0) {
31 buf->iStart = buf->capacity - 1;
32 } else {
33 buf->iStart = (buf->iStart - 1) & (buf->capacity - 1);
34 }
35}
36
37void dec_iStop_uint8(circular_buffer_uint8 *buf) {
38 if (buf->iStop == 0) {
39 buf->iStop = buf->capacity - 1;
40 } else {
41 buf->iStop = (buf->iStop - 1) & (buf->capacity - 1);
42 }
43}
44
46 const size_t capacity, uint8_t *buffer) {
47 if (!isPowerOfTwo(capacity)) {
48 Throw(ASC_ERROR_CB_BAD_CAPACITY);
49 }
50 circ_buf->capacity = capacity;
51 circ_buf->size = 0;
52 circ_buf->iStart = 0;
53 circ_buf->iStop = 0;
54 circ_buf->buffer = buffer;
55 for (size_t i = 0; i < capacity; i++) {
56 buffer[i] = 0x40; // '@'
57 }
58}
59
61 return circ_buf->size;
62}
63
65 return circular_buffer_get_size_uint8(circ_buf) == circ_buf->capacity;
66}
67
69 return circular_buffer_get_size_uint8(circ_buf) == 0;
70}
71
72#ifdef linux
74 FILE *outfile, uint8_t verbosity) {
75 fprintf(outfile, "circular_buffer_uint8, capacity: %zu size: %zu",
76 circ_buf->capacity, circ_buf->size);
77 if (verbosity >= 2) {
78 fprintf(outfile, " iStart: %zu iStop %zu buffer: %p\n", circ_buf->iStart,
79 circ_buf->iStop, (void *)circ_buf->buffer);
80 }
81 if (verbosity >= 3) {
82 fprintf(outfile, " Content: [ ");
83 for (size_t i = 0; i < circ_buf->size; i++) {
84 fprintf(outfile, "%" PRIu8 " ",
86 }
87 fprintf(outfile, "]\n");
88 }
89 if (verbosity >= 4) {
90 fprintf(outfile, " Raw Memory: [ ");
91 for (size_t i = 0; i < circ_buf->capacity; i++) {
92 fprintf(outfile, "%" PRIu8 " ", *(circ_buf->buffer + i));
93 }
94 fprintf(outfile, "]\n");
95 }
96 fprintf(outfile, " Content as string: ");
97 for (size_t i = 0; i < circ_buf->size; i++) {
98 uint8_t thisChar = circular_buffer_get_element_uint8(circ_buf, i);
99 if (thisChar == 0x0A) {
100 fprintf(outfile, "\\n");
101 } else if (thisChar < 0x20 || thisChar >= 0x7F) { // is control char
102 fprintf(outfile, "\\x%02" PRIX8, thisChar);
103 } else { // is printable
104 fprintf(outfile, "%c", thisChar);
105 }
106 }
107 fprintf(outfile, "\n");
108 if (verbosity >= 1) {
109 fprintf(outfile, " Raw memory as string: ");
110 for (size_t i = 0; i < circ_buf->capacity; i++) {
111 uint8_t thisChar = *(circ_buf->buffer + i);
112 if (thisChar == 0x0A) {
113 fprintf(outfile, "\\n");
114 } else if (thisChar < 0x20 || thisChar >= 0x7F) { // is control char
115 fprintf(outfile, "\\x%02" PRIX8, thisChar);
116 } else { // is printable
117 fprintf(outfile, "%c", thisChar);
118 }
119 }
120 fprintf(outfile, "\n");
121 fflush(outfile);
122 }
123}
124#endif
125
127 const size_t iElement) {
128
129 if (iElement >= circular_buffer_get_size_uint8(circ_buf)) {
130 Throw(ASC_ERROR_CB_OOB);
131 }
132 size_t iResult = (circ_buf->iStart + iElement) & (circ_buf->capacity - 1);
133 uint8_t result = *(circ_buf->buffer + iResult);
134 return result;
135}
136
138 const uint8_t element) {
139 dec_iStart_uint8(circ_buf);
140 *(circ_buf->buffer + circ_buf->iStart) = element;
141 if (circ_buf->size == circ_buf->capacity) {
142 dec_iStop_uint8(circ_buf);
143 } else {
144 circ_buf->size++;
145 }
146}
147
149 const uint8_t element) {
150 *(circ_buf->buffer + circ_buf->iStop) = element;
151 inc_iStop_uint8(circ_buf);
152 if (circ_buf->size == circ_buf->capacity) {
153 inc_iStart_uint8(circ_buf);
154 } else {
155 circ_buf->size++;
156 }
157}
158
160 if (circ_buf->size == 0) {
161 Throw(ASC_ERROR_CB_POP_EMPTY);
162 }
163 const uint8_t result = *(circ_buf->buffer + circ_buf->iStart);
164 inc_iStart_uint8(circ_buf);
165 circ_buf->size--;
166 return result;
167}
168
170 if (circ_buf->size == 0) {
171 Throw(ASC_ERROR_CB_POP_EMPTY);
172 }
173 dec_iStop_uint8(circ_buf);
174 circ_buf->size--;
175 const uint8_t result = *(circ_buf->buffer + circ_buf->iStop);
176 return result;
177}
178
180 const uint8_t value,
181 const bool inclusive) {
182 while (circ_buf->size > 0) {
183 uint8_t iValue = circular_buffer_get_element_uint8(circ_buf, 0);
184 if (iValue == value) {
185 if (inclusive) {
187 }
188 return;
189 } else {
191 }
192 }
193}
194
196 const uint8_t value,
197 const bool inclusive) {
198 while (circ_buf->size > 0) {
199 uint8_t iValue =
200 circular_buffer_get_element_uint8(circ_buf, circ_buf->size - 1);
201 if (iValue == value) {
202 if (inclusive) {
204 }
205 return;
206 } else {
208 }
209 }
210}
211
213 const uint8_t value) {
214 size_t iElement = 0;
215 for (iElement = 0; iElement < circ_buf->size; iElement++) {
216 uint8_t iValue = circular_buffer_get_element_uint8(circ_buf, iElement);
217 if (iValue == value) {
218 return iElement;
219 }
220 }
221 return circ_buf->size;
222}
223
225 const uint8_t value) {
226 size_t iElement = circ_buf->size;
227 while (iElement > 0) {
228 iElement--;
229 uint8_t iValue = circular_buffer_get_element_uint8(circ_buf, iElement);
230 if (iValue == value) {
231 return iElement;
232 }
233 }
234 return circ_buf->size;
235}
236
238 const uint8_t value) {
239 size_t result = 0;
240 for (size_t iElement = 0; iElement < circ_buf->size; iElement++) {
241 uint8_t iValue = circular_buffer_get_element_uint8(circ_buf, iElement);
242 if (iValue == value) {
243 result++;
244 }
245 }
246 return result;
247}
248
249size_t
251 const uint8_t **outBlock) {
252 *outBlock = circ_buf->buffer + circ_buf->iStart;
253 if (circ_buf->iStart + circ_buf->size > circ_buf->capacity) { // wraps
254 return circ_buf->capacity - circ_buf->iStart;
255 } else { // doesn't wrap
256 return circ_buf->size;
257 }
258}
259
260size_t
262 if (circ_buf->iStart + circ_buf->size > circ_buf->capacity) { // wraps
263 const size_t toPop = circ_buf->capacity - circ_buf->iStart;
264 for (size_t i = 0; i < toPop; i++) {
266 }
267 return toPop;
268 } else { // doesn't wrap
269 const size_t origSize = circ_buf->size;
270 circ_buf->size = 0;
271 circ_buf->iStart = 0;
272 circ_buf->iStop = 0;
273 return origSize;
274 }
275}
276
278 const uint8_t *source,
279 size_t source_size) {
280 for (size_t iElement = 0; iElement < source_size; iElement++) {
281 circular_buffer_push_back_uint8(circ_buf, source[iElement]);
282 }
283}
284
286 uint8_t *destination,
287 size_t dest_size) {
288 uint8_t *outBlock = circ_buf->buffer + circ_buf->iStart;
289 size_t nBlock;
290 if (circ_buf->iStart + circ_buf->size > circ_buf->capacity) { // wraps
291 nBlock = circ_buf->capacity - circ_buf->iStart;
292 } else { // doesn't wrap
293 nBlock = circ_buf->size;
294 }
295 const size_t nWritten = dest_size < nBlock ? dest_size : nBlock;
296 for (size_t iByte = 0; iByte < nWritten; iByte++) {
297 destination[iByte] = outBlock[iByte];
298 }
299 circ_buf->size -= nWritten;
300 if (circ_buf->size == 0) {
301 circ_buf->iStart = 0;
302 circ_buf->iStop = 0;
303 } else {
304 circ_buf->iStart = (circ_buf->iStart + nWritten) & (circ_buf->capacity - 1);
305 }
306 return nWritten;
307}
308
309#ifdef linux
311 int fd) {
312 size_t block_size_available;
313 uint8_t *block_start = circ_buf->buffer + circ_buf->iStop;
314 if (circ_buf->iStop >= circ_buf->iStart) {
315 block_size_available = circ_buf->capacity - circ_buf->iStop;
316 } else {
317 block_size_available = circ_buf->iStart - circ_buf->iStop;
318 }
319 ssize_t nRead = read(fd, block_start, block_size_available);
320 if (nRead < 0) {
321 perror("circular_buffer_push_back_from_fd_uint8 error while reading from "
322 "file");
323 Throw(ASC_ERROR_FILE_READ);
324 }
325 circ_buf->iStop = (circ_buf->iStop + nRead) & (circ_buf->capacity - 1);
326 circ_buf->size += nRead;
327 if (circ_buf->size >= circ_buf->capacity) {
328 circ_buf->iStart =
329 (circ_buf->iStart + circ_buf->size - circ_buf->capacity) &
330 (circ_buf->capacity - 1);
331 circ_buf->size = circ_buf->capacity;
332 }
333 // fprintf(stderr,"circular_buffer_push_back_from_fd_uint8:
334 // block_size_available: %zu nRead: %zd\n",block_size_available,nRead);
335 return nRead;
336}
337
339 const int fd) {
340 uint8_t *outBlock = circ_buf->buffer + circ_buf->iStart;
341 size_t nBlock;
342 if (circ_buf->iStart + circ_buf->size > circ_buf->capacity) { // wraps
343 nBlock = circ_buf->capacity - circ_buf->iStart;
344 } else { // doesn't wrap
345 nBlock = circ_buf->size;
346 }
347 ssize_t nWritten = write(fd, outBlock, nBlock);
348 if (nWritten < 0) {
349 perror("circular_buffer_pop_front_to_fd_uint8 error while writing to "
350 "file");
351 Throw(ASC_ERROR_FILE_WRITE);
352 }
353 circ_buf->size -= nWritten;
354 if (circ_buf->size == 0) {
355 circ_buf->iStart = 0;
356 circ_buf->iStop = 0;
357 } else {
358 circ_buf->iStart = (circ_buf->iStart + nWritten) & (circ_buf->capacity - 1);
359 }
360 return nWritten;
361}
362#endif
363
365 circ_buf->size = 0;
366 circ_buf->iStart = 0;
367 circ_buf->iStop = 0;
368}
369
371 const char *string) {
372 size_t nPushed = 0;
373 size_t iChar = 0;
374 while (true) {
375 const char *pChar = string + iChar;
376 if ((*pChar) == '\0') {
377 break;
378 }
379 circular_buffer_push_back_uint8(circ_buf, *pChar);
380 iChar++;
381 }
382 return nPushed;
383}
384
386 circular_buffer_uint8 *circ_buf, const char startChar, const char endChar) {
387 const size_t iEnd = circular_buffer_find_first_uint8(circ_buf, endChar);
388 if (iEnd >= circ_buf->size) { // no end found
389 const size_t iLastStart =
390 circular_buffer_find_last_uint8(circ_buf, startChar);
391 if (iLastStart >= circ_buf->size) { // no start found
392 const size_t bufSize = circ_buf->size;
394 return bufSize;
395 }
396 for (size_t i = 0; i < iLastStart; i++) {
398 }
399 return iLastStart;
400 }
401 if (iEnd == 0) { // end of frame first element, can't be start of frame
404 circ_buf, startChar, endChar);
405 }
406 size_t iElement = iEnd - 1;
407 while (true) {
408 if (circular_buffer_get_element_uint8(circ_buf, iElement) == startChar) {
409 break;
410 }
411 if (iElement == 0) { // No startChar found, this frame is bad
412 for (size_t i = 0; i <= iEnd; i++) { // delete up to including endChar
414 }
415 return iEnd + 1 +
417 circ_buf, startChar, endChar);
418 }
419 iElement--;
420 }
421 // iElement is the iStart we want, so pop all before that
422 for (size_t i = 0; i < iElement; i++) {
424 }
425 return iElement;
426}
427
429 size_t iStart, size_t nElem,
430 uint8_t **blocks,
431 size_t *blocks_sizes) {
432 if (iStart + nElem > circular_buffer_get_size_uint8(circ_buf)) {
433 Throw(ASC_ERROR_CB_OOB);
434 }
435 bool wraps = circ_buf->iStart + iStart + nElem > circ_buf->capacity;
436 blocks[0] = circ_buf->buffer + circ_buf->iStart + iStart;
437 if (wraps) {
438 blocks[1] = circ_buf->buffer;
439 blocks_sizes[0] = circ_buf->capacity - circ_buf->iStart - iStart;
440 blocks_sizes[1] = nElem - blocks_sizes[0];
441 return 2;
442 } else {
443 blocks[1] = NULL;
444 blocks_sizes[0] = nElem;
445 blocks_sizes[1] = 0;
446 return 1;
447 }
448}
size_t circular_buffer_pop_front_to_fd_uint8(circular_buffer_uint8 *circ_buf, const int fd)
circular buffer pop front writing to file descriptor
uint8_t circular_buffer_pop_back_uint8(circular_buffer_uint8 *circ_buf)
circular buffer pop back
void circular_buffer_remove_front_to_uint8(circular_buffer_uint8 *circ_buf, const uint8_t value, const bool inclusive)
circular buffer remove elements from front until you find the given value
size_t circular_buffer_count_uint8(const circular_buffer_uint8 *circ_buf, const uint8_t value)
circular buffer count the number of a given value
size_t circular_buffer_get_size_uint8(const circular_buffer_uint8 *circ_buf)
circular buffer get number of elements
size_t circular_buffer_pop_front_block_uint8(circular_buffer_uint8 *circ_buf, uint8_t *destination, size_t dest_size)
circular buffer pop from front into a block of memory
void circular_buffer_init_uint8(circular_buffer_uint8 *circ_buf, const size_t capacity, uint8_t *buffer)
circular buffer init method
size_t circular_buffer_remove_front_unfinished_frames_uint8(circular_buffer_uint8 *circ_buf, const char startChar, const char endChar)
circular buffer remove unfinished frames from front of buffer
size_t circular_buffer_get_blocks_uint8(circular_buffer_uint8 *circ_buf, size_t iStart, size_t nElem, uint8_t **blocks, size_t *blocks_sizes)
circular buffer access raw blocks of data for a given range of elements
size_t circular_buffer_push_back_from_fd_uint8(circular_buffer_uint8 *circ_buf, int fd)
circular buffer push back reading from file descriptor
uint8_t circular_buffer_get_element_uint8(const circular_buffer_uint8 *circ_buf, const size_t iElement)
circular buffer get element
size_t circular_buffer_find_first_uint8(const circular_buffer_uint8 *circ_buf, const uint8_t value)
circular buffer find index of first occurance of value
uint8_t circular_buffer_pop_front_uint8(circular_buffer_uint8 *circ_buf)
circular buffer pop front
bool circular_buffer_is_full_uint8(const circular_buffer_uint8 *circ_buf)
circular buffer get if full
size_t circular_buffer_get_first_block_uint8(const circular_buffer_uint8 *circ_buf, const uint8_t **outBlock)
circular buffer get first block
void circular_buffer_remove_back_to_uint8(circular_buffer_uint8 *circ_buf, const uint8_t value, const bool inclusive)
circular buffer remove elements from back until you find the given value
size_t circular_buffer_delete_first_block_uint8(circular_buffer_uint8 *circ_buf)
circular buffer delete first block
size_t circular_buffer_push_back_string_uint8(circular_buffer_uint8 *circ_buf, const char *string)
circular buffer push back string (null terminated)
void circular_buffer_clear_uint8(circular_buffer_uint8 *circ_buf)
circular buffer clear
size_t circular_buffer_find_last_uint8(const circular_buffer_uint8 *circ_buf, const uint8_t value)
circular buffer find index of last occurance of value
bool circular_buffer_is_empty_uint8(const circular_buffer_uint8 *circ_buf)
circular buffer get if empty
void circular_buffer_push_front_uint8(circular_buffer_uint8 *circ_buf, const uint8_t element)
circular buffer push front
void circular_buffer_push_back_block_uint8(circular_buffer_uint8 *circ_buf, const uint8_t *source, size_t source_size)
circular buffer push a block of memory on back
void circular_buffer_push_back_uint8(circular_buffer_uint8 *circ_buf, const uint8_t element)
circular buffer push back
void circular_buffer_print_uint8(const circular_buffer_uint8 *circ_buf, FILE *outfile, uint8_t verbosity)
circular buffer print contents
circular buffer struct