#ifndef __AVRBUF_H__
#define __AVRBUF_H__

#include <stdint.h>

/* 
   Routines for a <circular buffer> or <stack> (i.e. if sta always == 0)
 */

struct buf_t {
  uint8_t *buf;   // buffer storage
  uint8_t sz;  // size of buf
  uint8_t len; // number of stored chars
  uint8_t sta; // index of first stored char
};

// first the simple stuff

void buf_init(struct buf_t *p, void *buf, uint8_t sz);
uint8_t buf_sz(struct buf_t *p);
uint8_t buf_len(struct buf_t *p);
void buf_flush(struct buf_t *p);
uint8_t buf_end(struct buf_t *p); // return index of last stored char, only valid if p->len > 1
uint8_t buf_nxt(struct buf_t *p); // return index of position just past last stored char
int8_t buf_check(struct buf_t *p); // argument check, 0 => ok

////////////////
//  returns
// # of chars transferred to/from buffer
// 0 => error, buffer full (for write), or buffer empty (for read)

uint8_t buf_putlast( struct buf_t *p, uint8_t cc); // push
uint8_t buf_getlast( struct buf_t *p, uint8_t *cc); // pop
uint8_t buf_peeklast(struct buf_t *p, uint8_t *cc); // as _get without changing p
uint8_t buf_droplast(struct buf_t *p); // as _get without returning any value

uint8_t buf_putfirst(struct buf_t *p, uint8_t cc); // unshift
uint8_t buf_getfirst(struct buf_t *p, uint8_t *cc); // shift
uint8_t buf_peekfirst(struct buf_t *p, uint8_t *cc);
uint8_t buf_dropfirst(struct buf_t *p);

#define buf_push(   p, cc) buf_putlast( (p),(cc))
#define buf_pop(    p, cc) buf_getlast( (p),(cc))

#define buf_unshift(p, cc) buf_putfirst((p),(cc))
#define buf_shift(  p, cc) buf_getfirst((p),(cc))

uint8_t buf_read(struct buf_t *p, uint8_t *buf, uint8_t len);
uint8_t buf_write(struct buf_t *p, const uint8_t *buf, uint8_t len);

// convenience functions

uint8_t buf_chars(struct buf_t *p, const char *buf); // same as buf_write(p, buf, strlen(buf))
uint8_t buf_nl(struct buf_t *p); // write "\r\n"
uint8_t buf_uint8 (struct buf_t *p, uint8_t  val);
uint8_t buf_uint16(struct buf_t *p, uint16_t val);
uint8_t buf_uint32(struct buf_t *p, uint32_t val);
uint8_t buf_float (struct buf_t *p, float val);
uint8_t buf_double(struct buf_t *p, double val);

#endif
