text: #include <stdlib.h>
  #include <stdint.h>
  #include <stddef.h>
  #include <assert.h>
  
  #include "circular_buffer.h"
  
  // Circular buffer definition
  struct circular_buffer_t {
      uint8_t * buffer;
      size_t head;
      size_t tail;
      size_t max_size;
      bool full; 
  };
  
  cbuf_handle_t circular_buf_init(uint8_t* buffer, size_t size)
  {
      assert(buffer && size);
  
      cbuf_handle_t cbuf = malloc(sizeof(circular_buffer_t));
      assert(cbuf);
  
      cbuf->buffer = buffer;
      cbuf->max_size = size;
      circular_buf_reset(cbuf);
  
      assert(circular_buf_empty(cbuf));
  
      return cbuf;
  }
  
  void circular_buf_free(cbuf_handle_t cbuf)
  {
      assert(cbuf);
      free(cbuf);
  }
  
  void circular_buf_reset(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      cbuf->head = 0;
      cbuf->tail = 0;
      cbuf->full = false;
  }
  
  bool circular_buf_full(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      return cbuf->full;
  }
  
  bool circular_buf_empty(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      return (!cbuf->full && (cbuf->head == cbuf->tail));
  }
  
  size_t circular_buf_capacity(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      return cbuf->max_size;
  }
  
  size_t circular_buf_size(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      size_t size = cbuf->max_size;
  
      if(!cbuf->full)
      {
          if(cbuf->head >= cbuf->tail)
          {
              size = (cbuf->head - cbuf->tail);
          }
          else
          {
              size = (cbuf->max_size + cbuf->head - cbuf->tail);
          }
      }
  
      return size;
  }
  
  static void advance_pointer(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      if(cbuf->full)
     	{
          if (++(cbuf->tail) == cbuf->max_size) 
          { 
              cbuf->tail = 0;
          }
      }
  
      if (++(cbuf->head) == cbuf->max_size) 
      { 
          cbuf->head = 0;
      }
      cbuf->full = (cbuf->head == cbuf->tail);
  }
  
  static void retreat_pointer(cbuf_handle_t cbuf)
  {
      assert(cbuf);
  
      cbuf->full = false;
      if (++(cbuf->tail) == cbuf->max_size) 
      { 
          cbuf->tail = 0;
      }
  }
  
  void circular_buf_put(cbuf_handle_t cbuf, uint8_t data)
  {
      assert(cbuf && cbuf->buffer);
  
      cbuf->buffer[cbuf->head] = data;
  
      advance_pointer(cbuf);
  }
  
  int circular_buf_get(cbuf_handle_t cbuf, uint8_t * data)
  {
      assert(cbuf && data && cbuf->buffer);
  
      int ret = -1;
  
      if(!circular_buf_empty(cbuf))
      {
          *data = cbuf->buffer[cbuf->tail];
          retreat_pointer(cbuf);
  
          ret = 0;
      }
  
      return ret;
  }
  
  