Last active
August 29, 2015 14:01
-
-
Save RickKimball/1a860d229b2370e4e50a to your computer and use it in GitHub Desktop.
another ringbuffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdint.h> | |
#include "ringbuffer.h" | |
struct data_xyz { | |
int x; | |
int y; | |
int z; | |
bool bValid; | |
void print(void) { | |
printf("valid=%s, x=%d,y=%d,z=%d\n",bValid?"t":"f",x,y,z); | |
} | |
data_xyz(): | |
x(-1),y(-1),z(-1),bValid(false) | |
{ | |
} | |
data_xyz(int x, int y, int z) | |
:x(x),y(y),z(z),bValid(true) | |
{ | |
} | |
}; | |
typedef struct data_xyz data_xyz_t; | |
typedef ringbuffer_t<16, data_xyz_t > rb_data; | |
rb_data buff; | |
int main() | |
{ | |
int n = 0; | |
int cnt = 1; | |
data_xyz_t item = { 1,2,3}; | |
while(1) { | |
do { | |
item.x=cnt++; | |
buff.push_back(item); | |
} while(++n < 10); | |
printf("items = %ld\n", buff.size()); | |
n = 0; | |
while(buff.size()) { | |
data_xyz_t item = buff.pop_front(); | |
item.print(); | |
} | |
data_xyz_t bogo = buff.pop_front(); | |
printf("bogo = "); | |
bogo.print(); | |
sleep(1); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: main | |
main: main.cpp | |
gcc -std=c++0x -Os -g -Wall -o $@ $< | |
clean: | |
rm -f main | |
test: | |
./main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ringbuffer_02.h - yet another version of ringbuffer_t optimized for msp430-gcc | |
* | |
* Desc: This template class creates a ringbuffer with arbitrary types. Provides push | |
* and pop methods for adding and removing items. Access function for checking | |
* the number of items in the buffer, capacity and full or empty methods | |
* provide safe access to the info. | |
* | |
* This version has been optimized for the msp430-gcc. It doesn't use disable | |
* or enable any interrupts. It is safe nonetheless for use when there is a single | |
* writer and single reader. This is common when using an interrupt and the main | |
* line thread working together to move data in and out of peripherals on demand. | |
* | |
* Version: 1.0.0 | |
* Created: Jul-24-2012 | |
* Author: rick@kimballsoftware.com | |
* Date: 02-28-2013 | |
* Version: 1.0.0 | |
* | |
* ========================================================================= | |
* Copyright © 2012 Rick Kimball | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
*/ | |
#ifndef RINGBUFFER_T_H_ | |
#define RINGBUFFER_T_H_ | |
#include <stdint.h> | |
/** | |
* uint16x2_t - a union containing 16 bit head and tail offsets into the ring buffer. | |
* The union make it simpler to grab both values with asm. | |
* | |
*/ | |
union uint16x2_t { | |
// access as 32 bit | |
unsigned long both; | |
// -- or as 2 16 bit values -- | |
struct { | |
unsigned head:16; | |
unsigned tail:16; | |
}; | |
}; | |
/** | |
* uint8x2_t - a union containing 2 8 bit values that can be accessed a byte | |
* at a time or a word at a time. The union make it more | |
* efficient to grab both values. | |
* | |
*/ | |
typedef union uint8x2_t { | |
//--- word access | |
uint16_t as_u16; // access both as a word: mask is low byte, data is high byte | |
//--- or --- individual byte access | |
struct { | |
uint8_t as_u8[2]; | |
}; | |
} uint8x2_t; | |
/** | |
* ringbuffer_t - provide a circular_buffer without disabling interrupts | |
* expects a power of 2 container, and only one reader and one writer | |
* container capacity SIZE-1 | |
*/ | |
template < | |
uint16_t SIZE, /* how many elements-1 must be power of 2 */ | |
typename T = uint8_t, /* works with any type */ | |
typename POP_T = int16_t, /* return type of pop_front */ | |
POP_T EMPTY_ELEM = (POP_T)-1 /* default return value when empty */ | |
> | |
struct ringbuffer_t { | |
// --- private structure data --- | |
volatile uint16x2_t offsets; | |
T elements[SIZE]; | |
enum { CAPACITY=SIZE-1 }; | |
is_power_of_two<SIZE> check_buffer_size; // your SIZE is not a power of 2, if you error here | |
public: | |
// --- methods --- | |
inline void init() { | |
offsets.both=0; | |
} | |
inline void clear(void ) { | |
offsets.both=0; | |
} | |
ALWAYS_INLINE size_t size() { | |
register uint16x2_t temp = { offsets.both }; | |
temp.both = (temp.head-temp.tail) & CAPACITY; | |
return temp.both; | |
} | |
ALWAYS_INLINE size_t capacity() { | |
return CAPACITY; | |
} | |
bool inline empty() { | |
return !size(); | |
} | |
bool inline full() { | |
return size() == capacity(); | |
} | |
// affects head, reads tail, element ignored if overflow ~1.68 us @16MHz | |
inline void push_back(const T element) { | |
register uint16_t temp_head = offsets.head; | |
elements[temp_head++] = element; | |
temp_head &= CAPACITY; | |
if ( !(temp_head == offsets.tail) ) { // !full | |
offsets.head = temp_head; | |
} | |
return; | |
} | |
// no bounds check version, affects head ~1.120 us @ 16MHz | |
inline void push_back_nc(const T element) { | |
register uint16_t temp_head = offsets.head; | |
elements[temp_head++] = element; | |
offsets.head = temp_head & CAPACITY; | |
return; | |
} | |
// affects tail, reads head ~1.80 us @ 16MHz | |
inline POP_T pop_front(void) { | |
register uint16x2_t temp = { offsets.both }; | |
if ( (temp.head-temp.tail) & CAPACITY ) { // !empty | |
POP_T elem = elements[temp.tail++]; | |
offsets.tail = temp.tail & CAPACITY; | |
return elem; | |
} | |
return EMPTY_ELEM; // on underflow return default element | |
} | |
// no bounds check, affects tail, reads head ~1.128 us @ 16MHz | |
inline POP_T pop_front_nc(void) { | |
register uint16_t temp_tail = offsets.tail; | |
POP_T elem = elements[temp_tail++]; | |
offsets.tail = temp_tail & CAPACITY; | |
return elem; | |
} | |
}; | |
template <const uint16_t CAPACITY=8, typename value_type=uint8_t > | |
struct ptr_ringbuf { | |
volatile value_type *tail; | |
volatile value_type *head; | |
value_type ring_buf[CAPACITY+1]; | |
void init(void) { | |
head = tail = ring_buf; | |
} | |
// interrupt safe capacity | |
ALWAYS_INLINE unsigned capacity() { | |
return CAPACITY-size(); | |
} | |
// n | |
ALWAYS_INLINE unsigned capacity_() { | |
return CAPACITY-size_(); | |
} | |
ALWAYS_INLINE unsigned size() { | |
register unsigned cnt; | |
__dint(); | |
cnt = size_(); | |
__eint(); | |
return cnt; | |
} | |
/* | |
* size() - return number of unread bytes in buffer | |
*/ | |
ALWAYS_INLINE unsigned size_() { // interrupt safe version | |
#if 1 | |
register unsigned rc; | |
__asm__ ( | |
" mov %[head], %[cnt]\n" | |
" sub %[tail], %[cnt]\n" | |
: [cnt] "=r" (rc) | |
: [head] "m" (head), [tail] "m" (tail) | |
: | |
); | |
#else | |
register unsigned rc=(unsigned)head-(unsigned)tail; | |
#endif | |
return rc; | |
} | |
ALWAYS_INLINE value_type pop_front() { | |
if ( size() ) { | |
return pop_front_nc(); | |
} | |
return value_type(-1); | |
} | |
ALWAYS_INLINE value_type pop_front_nc() { | |
value_type *next_tail=(value_type *)tail+1; | |
if ( next_tail >= ring_buf+CAPACITY ) next_tail=ring_buf; | |
int rc = *tail; | |
tail = next_tail; | |
return rc; | |
} | |
ALWAYS_INLINE void push_back(const value_type c) { | |
if ( capacity_() > 0 ) { | |
register value_type *next_head=(value_type *)head+1; | |
if (next_head >= ring_buf+CAPACITY) next_head = ring_buf; | |
*head = c; | |
head = next_head; | |
} | |
} | |
}; | |
#endif /* RINGBUFFER_T_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment