/ringbuffer.c

https://bitbucket.org/a84/gs_public/ · C · 181 lines · 115 code · 41 blank · 25 comment · 19 complexity · 517225b671e59f5f1ec07e12be0d794d MD5 · raw file

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