PageRenderTime 33ms CodeModel.GetById 16ms app.highlight 13ms RepoModel.GetById 2ms app.codeStats 0ms

/ringbuffer.c

https://bitbucket.org/a84/gs_public/
C | 181 lines | 115 code | 41 blank | 25 comment | 19 complexity | 517225b671e59f5f1ec07e12be0d794d MD5 | raw file
  1
  2#include <stdlib.h>
  3#include <stdint.h>
  4#include <string.h>
  5#include <sys/param.h>
  6#include <assert.h>
  7
  8/*
  9 * Ringbuffer implementation
 10 *
 11 *
 12 * head==tail		Ringbuffer empty
 13 * head==tail-1		Ringbuffer full
 14 *
 15 * H                 H
 16 * 1234567 -> 1234567
 17 * T          T
 18 *
 19 *
 20 *
 21 *
 22 *
 23 *
 24 */
 25
 26struct ringbuffer_s {
 27	uint8_t		*buffer;
 28
 29	unsigned int	atoms;
 30	unsigned int	atomsize;
 31
 32	unsigned int	used;
 33	unsigned int	head;
 34	unsigned int	tail;
 35};
 36
 37struct ringbuffer_s *ringbuffer_init(unsigned int atoms, unsigned int atomsize) {
 38	struct ringbuffer_s *rb;
 39
 40	rb=calloc(1, sizeof(struct ringbuffer_s));
 41	if (!rb)
 42		return NULL;
 43
 44	rb->atoms=atoms;
 45	rb->atomsize=atomsize;
 46	rb->buffer=malloc(atomsize*atoms);
 47
 48	if (!rb->buffer) {
 49		free(rb);
 50		return NULL;
 51	}
 52
 53	return rb;
 54}
 55
 56static int ringbuffer_headroom(struct ringbuffer_s *rb) {
 57
 58	/* If head == tail we are either full or empty */
 59	if (rb->used >= rb->atoms)
 60		return 0;
 61
 62	if (rb->tail > rb->head)
 63		return rb->tail-rb->head;
 64
 65	return rb->atoms-rb->head;
 66}
 67
 68static void ringbuffer_push(struct ringbuffer_s *rb, int num) {
 69	rb->head+=num;
 70
 71	if (rb->head >= rb->atoms)
 72		rb->head-=rb->atoms;
 73
 74	rb->used+=num;
 75
 76	assert(rb->used <= rb->atoms);
 77}
 78
 79static int ringbuffer_add_atoms(struct ringbuffer_s *rb, uint8_t *atom, int num) {
 80	int		headroom, atoms;
 81	uint8_t		*dptr;
 82
 83	headroom=ringbuffer_headroom(rb);
 84	if (!headroom)
 85		return 0;
 86
 87	atoms=MIN(headroom, num);
 88	dptr=&rb->buffer[rb->head*rb->atomsize];
 89	memcpy(dptr, atom, atoms*rb->atomsize);
 90
 91	ringbuffer_push(rb, atoms);
 92
 93	return atoms;
 94}
 95
 96/*
 97 * Add atoms to the ringbuffer - We are using ringbuffer_add_atoms which
 98 * will not know about wrapping. As we know we call it twice and summ up
 99 * the result.
100 *
101 */
102int ringbuffer_add(struct ringbuffer_s *rb, uint8_t *atom, int num) {
103	int		atoms;
104
105	atoms=ringbuffer_add_atoms(rb, atom, num);
106	if (atoms >= num)
107		return atoms;
108
109	atoms+=ringbuffer_add_atoms(rb, &atom[atoms*rb->atomsize], num-atoms);
110
111	return atoms;
112}
113
114void ringbuffer_free(struct ringbuffer_s *rb) {
115	free(rb->buffer),
116	free(rb);
117}
118
119#ifdef TEST
120
121#include <stdio.h>
122
123void dump_hex(char *prefix, uint8_t *buf, int size) {
124	int		i;
125	unsigned char	ch;
126	char		sascii[17];
127	char		linebuffer[16*4+1];
128
129	sascii[16]=0x0;
130
131	for(i=0;i<size;i++) {
132		ch=buf[i];
133		if (i%16 == 0) {
134			sprintf(linebuffer, "%04x ", i);
135		}
136		sprintf(&linebuffer[(i%16)*3], "%02x ", ch);
137		if (ch >= ' ' && ch <= '}')
138			sascii[i%16]=ch;
139		else
140			sascii[i%16]='.';
141
142		if (i%16 == 15)
143			printf("%s %s  %s\n", prefix, linebuffer, sascii);
144	}
145
146	/* i++ after loop */
147	if (i%16 != 0) {
148		for(;i%16 != 0;i++) {
149			sprintf(&linebuffer[(i%16)*3], "   ");
150			sascii[i%16]=' ';
151		}
152
153		printf("%s %s  %s\n", prefix, linebuffer, sascii);
154	}
155}
156
157
158void ringbuffer_dump(struct ringbuffer_s *rb) {
159	printf("Atoms: %d AtomSize: %d Head: %d Tail: %d Used: %d\n", 
160			rb->atoms, rb->atomsize, rb->head, rb->tail, rb->used);
161	dump_hex(" ", rb->buffer, rb->atoms*rb->atomsize);
162	printf("\n");
163}
164
165int main(void ) {
166	struct ringbuffer_s	*rb=ringbuffer_init(7, 1);
167	int			i, j;
168	uint8_t			add[2];
169
170	for(i=1;i<=5;i++) {
171		add[0]=i;
172		add[1]=i;
173		ringbuffer_dump(rb);
174		printf("Trying to add 2 bytes... \n");
175		j=ringbuffer_add(rb, add, 2);
176		printf("... returned j=%d\n", j);
177		ringbuffer_dump(rb);
178	}
179}
180
181#endif