Skip to content

Instantly share code, notes, and snippets.

@lukicdarkoo
Last active September 10, 2019 09:00
Show Gist options
  • Save lukicdarkoo/4c7db5a5bdd99f60b659616a3284ca06 to your computer and use it in GitHub Desktop.
Save lukicdarkoo/4c7db5a5bdd99f60b659616a3284ca06 to your computer and use it in GitHub Desktop.
Bit-aware circular buffer
#include "circbuff.h"
void circbuff_init(circbuff_t *circbuff) {
circbuff->end_bit = 0;
circbuff->end_byte = 0;
circbuff->start_bit = 0;
circbuff->start_byte = 0;
}
uint8_t circbuff_size(circbuff_t *circbuff) {
if (circbuff->end_byte >= circbuff->start_byte) {
return (circbuff->end_byte - circbuff->start_byte);
} else {
return CIRCBUFF_LENGTH -
(circbuff->start_byte - circbuff->end_byte);
}
}
bool circbuff_is_full(circbuff_t *circbuff) {
return (circbuff_size(circbuff) >= CIRCBUFF_LENGTH - 1);
}
bool circbuff_add_byte(circbuff_t *circbuff, uint8_t data) {
bool status = false;
if (circbuff_is_full(circbuff) == true) {
circbuff->start_byte =
(circbuff->start_byte + 1) % CIRCBUFF_LENGTH;
circbuff->start_bit = 0;
status = true;
}
circbuff->data[circbuff->end_byte] = data;
circbuff->end_byte = (circbuff->end_byte + 1) % CIRCBUFF_LENGTH;
circbuff->end_bit = 0;
return status;
}
bool circbuff_is_empty(circbuff_t *circbuff) {
return circbuff->start_byte == circbuff->end_byte;
}
uint8_t circbuff_pop_byte(circbuff_t *circbuff) {
circbuff->start_bit = 0;
if (circbuff_is_empty(circbuff) == false) {
uint8_t data = circbuff->data[circbuff->start_byte];
circbuff->start_byte =
(circbuff->start_byte + 1) % CIRCBUFF_LENGTH;
return data;
}
return 0;
}
bool circbuff_add_bit(circbuff_t *circbuff, uint8_t data) {
bool status = false;
circbuff->data[circbuff->end_byte] |= data << (7 - circbuff->end_bit);
circbuff->end_bit++;
if (circbuff->end_bit > 7) {
if (circbuff_is_full(circbuff) == true) {
circbuff->start_byte =
(circbuff->start_byte + 1) % CIRCBUFF_LENGTH;
circbuff->start_bit = 0;
status = true;
}
circbuff->end_byte = (circbuff->end_byte + 1) % CIRCBUFF_LENGTH;
circbuff->end_bit = 0;
circbuff->data[circbuff->end_byte] = 0;
}
return status;
}
uint8_t circbuff_pop_bit(circbuff_t *circbuff) {
uint8_t data;
uint8_t bit;
data = circbuff->data[circbuff->start_byte];
bit = (data & (1 << (7 - circbuff->start_bit))) >>
(7 - circbuff->start_bit);
circbuff->start_bit++;
if (circbuff->start_bit > 7) {
circbuff_pop_byte(circbuff);
}
return bit;
}
#ifndef _CIRCBUFF_H_
#define _CIRCBUFF_H_
#include <stdbool.h>
#include <stdint.h>
#ifndef CIRCBUFF_LENGTH
#define CIRCBUFF_LENGTH 64U
#endif
typedef struct _circbuff_t {
uint8_t data[CIRCBUFF_LENGTH];
uint8_t start_byte;
uint8_t start_bit;
uint8_t end_byte;
uint8_t end_bit;
} circbuff_t;
void circbuff_init(circbuff_t *circbuff);
bool circbuff_is_full(circbuff_t *circbuff);
bool circbuff_is_empty(circbuff_t *circbuff);
uint8_t circbuff_size(circbuff_t *circbuff);
bool circbuff_add_byte(circbuff_t *circbuff, uint8_t data);
uint8_t circbuff_pop_byte(circbuff_t *circbuff);
bool circbuff_add_bit(circbuff_t *circbuff, uint8_t data);
uint8_t circbuff_pop_bit(circbuff_t *circbuff);
#endif
#include "circbuff.h"
#include <assert.h>
#include <stdio.h>
static circbuff_t buff;
int main() {
circbuff_init(&buff);
// Byte pop test
circbuff_add_byte(&buff, 1);
assert(circbuff_pop_byte(&buff) == 1);
assert(circbuff_is_empty(&buff) == true);
// Bit add test
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 0);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 0);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
assert(circbuff_pop_byte(&buff) == 0xAF);
// Bit add/pop test
circbuff_add_bit(&buff, 1);
assert(circbuff_pop_bit(&buff) == 1); // Not sure if it is the correct behaviour
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 0);
circbuff_add_bit(&buff, 1);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
circbuff_pop_byte(&buff);
// Bit pop test
circbuff_add_byte(&buff, 0x80);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_byte(&buff) == 0x80);
// Stress test
for (int i = 0; i < 65; i++) {
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 0);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 0);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
circbuff_add_bit(&buff, 1);
}
assert(circbuff_is_full(&buff));
for (int i = 0; i < 63; i++) {
assert(circbuff_pop_byte(&buff) == 0xAF);
}
assert(circbuff_is_empty(&buff));
assert(circbuff_pop_byte(&buff) == 0);
// Real world
circbuff_add_byte(&buff, 0xAA);
circbuff_add_byte(&buff, 0x02);
circbuff_add_byte(&buff, 0x03);
circbuff_add_byte(&buff, 0x04);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 1);
assert(circbuff_pop_bit(&buff) == 0);
assert(circbuff_pop_bit(&buff) == 0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment