kopia lustrzana https://gitlab.com/markol/Teathimble_Firmware
116 wiersze
3.0 KiB
C
116 wiersze
3.0 KiB
C
/** \file
|
|
\brief Header for implementing a ringbuffer.
|
|
|
|
This header implements a macro-level ringbuffer. It's meant to be included
|
|
only in source files and only where needed. Such a sequence implements a
|
|
ringbuffer:
|
|
|
|
#define BUFSIZE 64
|
|
volatile uint8_t rxhead = 0;
|
|
volatile uint8_t rxtail = 0;
|
|
volatile uint8_t rxbuf[BUFSIZE];
|
|
#include "ringbuffer.h"
|
|
|
|
Requirements:
|
|
|
|
- The name 'BUFSIZE' has to be kept exactly. One can use two or more
|
|
ringbuffers in the same source file, but they all have to be the same
|
|
size.
|
|
|
|
- BUFSIZE has to be a power of two: 2, 4, 8, 16, 32, 64, 128 or 256.
|
|
|
|
- In the example above, 'rx' is the name of the buffer. <name>head,
|
|
<name>tail and <name>buf have to be named exactly.
|
|
|
|
Ringbuffer logic:
|
|
|
|
head = written data pointer.
|
|
tail = read data pointer.
|
|
|
|
When head == tail, buffer is empty.
|
|
When head + 1 == tail, buffer is full.
|
|
Thus, number of available spaces in buffer is (tail - head) & bufsize.
|
|
|
|
Can write:
|
|
(tail - head - 1) & (BUFSIZE - 1)
|
|
|
|
Write to buffer:
|
|
buf[head++] = data; head &= (BUFSIZE - 1);
|
|
|
|
Can read:
|
|
(head - tail) & (BUFSIZE - 1)
|
|
|
|
Read from buffer:
|
|
data = buf[tail++]; tail &= (BUFSIZE - 1);
|
|
*/
|
|
|
|
/** \def buf_canread()
|
|
|
|
Check if we can read from this buffer. Buffer pointers are left unchanged.
|
|
|
|
Example:
|
|
|
|
if (buf_canread(rx)) {
|
|
...
|
|
}
|
|
|
|
*/
|
|
#define buf_canread(buffer) ((buffer ## head - buffer ## tail ) & \
|
|
(BUFSIZE - 1))
|
|
|
|
/** \def buf_pop()
|
|
|
|
Actually read a byte from this buffer. This also forwards the buffer pointer.
|
|
It's imperative to check for availabilty of a byte before. Pop'ing an
|
|
empty buffer means to go through the whle buffer again.
|
|
|
|
Example:
|
|
|
|
uint8_t next_byte;
|
|
|
|
if (buf_canread(rx)) {
|
|
buf_pop(rx, next_byte);
|
|
}
|
|
|
|
*/
|
|
#define buf_pop(buffer, data) do { \
|
|
data = buffer ## buf[buffer ## tail]; \
|
|
buffer ## tail = (buffer ## tail + 1) & \
|
|
(BUFSIZE - 1); \
|
|
} while (0)
|
|
|
|
/** \def buf_canwrite()
|
|
|
|
Check if we can write to this buffer. Buffer pointers are left unchanged.
|
|
|
|
Example:
|
|
|
|
uint8_t data;
|
|
|
|
if (buf_canwrite(tx)) {
|
|
printf("There's room in the buffer, please send data.\n");
|
|
}
|
|
|
|
*/
|
|
#define buf_canwrite(buffer) ((buffer ## tail - buffer ## head - 1) & \
|
|
(BUFSIZE - 1))
|
|
|
|
/** \def buf_push()
|
|
|
|
Actually write to this buffer. This also forwards the buffer pointers. Like
|
|
with buf_pop() it's mandatory to test for available room before actually
|
|
writing, else valid data is overwritten.
|
|
|
|
Example:
|
|
|
|
void write_char_to_buffer(uint8_t data) {
|
|
if (buf_canwrite(tx))
|
|
buf_push(tx, data);
|
|
}
|
|
*/
|
|
#define buf_push(buffer, data) do { \
|
|
buffer ## buf[buffer ## head] = data; \
|
|
buffer ## head = (buffer ## head + 1) & \
|
|
(BUFSIZE - 1); \
|
|
} while (0)
|