4 * A two-dimensional bit buffer consisting of bytes
6 * Copyright (C) 2015 Tommy Vestermark
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
13 #include "bitbuffer.h"
18 void bitbuffer_clear(bitbuffer_t *bits) {
20 memset(bits->bits_per_row, 0, BITBUF_ROWS*2);
21 memset(bits->bb, 0, BITBUF_ROWS * BITBUF_COLS);
25 void bitbuffer_add_bit(bitbuffer_t *bits, int bit) {
26 if(bits->num_rows == 0) bits->num_rows++; // Add first row automatically
27 uint16_t col_index = bits->bits_per_row[bits->num_rows-1] / 8;
28 uint16_t bit_index = bits->bits_per_row[bits->num_rows-1] % 8;
29 if((col_index < BITBUF_COLS)
30 && (bits->num_rows <= BITBUF_ROWS)
32 bits->bb[bits->num_rows-1][col_index] |= (bit << (7-bit_index));
33 bits->bits_per_row[bits->num_rows-1]++;
36 // fprintf(stderr, "ERROR: bitbuffer:: Could not add more columns\n"); // Some decoders may add many columns...
41 void bitbuffer_add_row(bitbuffer_t *bits) {
42 if(bits->num_rows == 0) bits->num_rows++; // Add first row automatically
43 if(bits->num_rows < BITBUF_ROWS) {
47 // fprintf(stderr, "ERROR: bitbuffer:: Could not add more rows\n"); // Some decoders may add many rows...
52 void bitbuffer_invert(bitbuffer_t *bits) {
53 for (unsigned row = 0; row < bits->num_rows; ++row) {
54 if (bits->bits_per_row[row] > 0) {
55 const unsigned last_col = (bits->bits_per_row[row]-1) / 8;
56 const unsigned last_bits = ((bits->bits_per_row[row]-1) % 8) +1;
57 for (unsigned col = 0; col <= last_col; ++col) {
58 bits->bb[row][col] = ~bits->bb[row][col]; // Invert
60 bits->bb[row][last_col] ^= 0xFF >> last_bits; // Re-invert unused bits in last byte
66 void bitbuffer_extract_bytes(bitbuffer_t *bitbuffer, unsigned row,
67 unsigned pos, uint8_t *out, unsigned len)
69 uint8_t *bits = bitbuffer->bb[row];
72 memcpy(out, bits + (pos / 8), (len + 7) / 8);
74 unsigned shift = 8 - (pos & 7);
77 pos >>= 3; // Convert to bytes
85 *(out++) = word >> shift;
90 // If we make this an inline function instead of a macro, it means we don't
91 // have to worry about using bit numbers with side-effects (bit++).
92 static inline int bit(const uint8_t *bytes, unsigned bit)
94 return bytes[bit >> 3] >> (7 - (bit & 7)) & 1;
97 unsigned bitbuffer_search(bitbuffer_t *bitbuffer, unsigned row, unsigned start,
98 const uint8_t *pattern, unsigned pattern_bits_len)
100 uint8_t *bits = bitbuffer->bb[row];
101 unsigned len = bitbuffer->bits_per_row[row];
102 unsigned ipos = start;
103 unsigned ppos = 0; // cursor on init pattern
105 while (ipos < len && ppos < pattern_bits_len) {
106 if (bit(bits, ipos) == bit(pattern, ppos)) {
109 if (ppos == pattern_bits_len)
110 return ipos - pattern_bits_len;
121 unsigned bitbuffer_manchester_decode(bitbuffer_t *inbuf, unsigned row, unsigned start,
122 bitbuffer_t *outbuf, unsigned max)
124 uint8_t *bits = inbuf->bb[row];
125 unsigned int len = inbuf->bits_per_row[row];
126 unsigned int ipos = start;
128 if (max && len > start + (max * 2))
129 len = start + (max * 2);
134 bit1 = bit(bits, ipos++);
135 bit2 = bit(bits, ipos++);
140 bitbuffer_add_bit(outbuf, bit2);
147 void bitbuffer_print(const bitbuffer_t *bits) {
148 fprintf(stderr, "bitbuffer:: Number of rows: %d \n", bits->num_rows);
149 for (uint16_t row = 0; row < bits->num_rows; ++row) {
150 fprintf(stderr, "[%02d] {%d} ", row, bits->bits_per_row[row]);
151 for (uint16_t col = 0; col < (bits->bits_per_row[row]+7)/8; ++col) {
152 fprintf(stderr, "%02x ", bits->bb[row][col]);
154 // Print binary values also?
155 if (bits->bits_per_row[row] <= BITBUF_MAX_PRINT_BITS) {
156 fprintf(stderr, ": ");
157 for (uint16_t bit = 0; bit < bits->bits_per_row[row]; ++bit) {
158 if (bits->bb[row][bit/8] & (0x80 >> (bit % 8))) {
159 fprintf(stderr, "1");
161 fprintf(stderr, "0");
163 if ((bit % 8) == 7) { fprintf(stderr, " "); } // Add byte separators
166 fprintf(stderr, "\n");
171 int compare_rows(bitbuffer_t *bits, unsigned row_a, unsigned row_b) {
172 return (bits->bits_per_row[row_a] == bits->bits_per_row[row_b] &&
173 !memcmp(bits->bb[row_a], bits->bb[row_b],
174 (bits->bits_per_row[row_a] + 7) / 8));
177 unsigned count_repeats(bitbuffer_t *bits, unsigned row) {
179 for (int i = 0; i < bits->num_rows; ++i) {
180 if (compare_rows(bits, row, i)) {
187 int bitbuffer_find_repeated_row(bitbuffer_t *bits, unsigned min_repeats, unsigned min_bits) {
188 for (int i = 0; i < bits->num_rows; ++i) {
189 if (bits->bits_per_row[i] >= min_bits &&
190 count_repeats(bits, i) >= min_repeats) {
199 // gcc -I include/ -std=gnu11 -D _TEST src/bitbuffer.c
201 int main(int argc, char **argv) {
202 fprintf(stderr, "bitbuffer:: test\n");
204 bitbuffer_t bits = {0};
206 fprintf(stderr, "TEST: bitbuffer:: The empty buffer\n");
207 bitbuffer_print(&bits);
209 fprintf(stderr, "TEST: bitbuffer:: Add 1 bit\n");
210 bitbuffer_add_bit(&bits, 1);
211 bitbuffer_print(&bits);
213 fprintf(stderr, "TEST: bitbuffer:: Add 1 new row\n");
214 bitbuffer_add_row(&bits);
215 bitbuffer_print(&bits);
217 fprintf(stderr, "TEST: bitbuffer:: Fill row\n");
218 for (int i=0; i < BITBUF_COLS*8; ++i) {
219 bitbuffer_add_bit(&bits, i%2);
221 bitbuffer_print(&bits);
223 fprintf(stderr, "TEST: bitbuffer:: Add row and fill 1 column too many\n");
224 bitbuffer_add_row(&bits);
225 for (int i=0; i <= BITBUF_COLS*8; ++i) {
226 bitbuffer_add_bit(&bits, i%2);
228 bitbuffer_print(&bits);
230 fprintf(stderr, "TEST: bitbuffer:: invert\n");
231 bitbuffer_invert(&bits);
232 bitbuffer_print(&bits);
234 fprintf(stderr, "TEST: bitbuffer:: Clear\n");
235 bitbuffer_clear(&bits);
236 bitbuffer_print(&bits);
238 fprintf(stderr, "TEST: bitbuffer:: Add 1 row too many\n");
239 for (int i=0; i <= BITBUF_ROWS; ++i) {
240 bitbuffer_add_row(&bits);
242 bitbuffer_add_bit(&bits, 1);
243 bitbuffer_print(&bits);