1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 * @file circular_buffer.h
15 * @brief A circular buffer implementation
16 */
17
18#pragma once
19
20#include <stdbool.h>
21#include <sys/types.h>
22#include <stdint.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <errno.h>
26
27#include <utils/zf_log.h>
28
29
30
31/* Circular Buffer */
32typedef struct circ_buf {
33    off_t head;
34    off_t tail;
35    size_t size;
36    uint8_t buf[];
37} circ_buf_t;
38
39
40static inline off_t _next_pos(circ_buf_t *cb, off_t pos)
41{
42    return (pos + 1) % cb->size;
43}
44
45
46/**
47 * Initialise a new circular buffer
48 *
49 * @param size The size of the buffer in bytes.
50 * @param[in] cb Circular buffer structure allocated by the user.
51 *
52 * @return NULL on failure.
53 */
54static inline int circ_buf_init(size_t size, circ_buf_t *cb) {
55    if (size == 0 || !cb) {
56        ZF_LOGE("Invalid arguments\n");
57        return EINVAL;
58    }
59
60    cb->head = 0;
61    cb->tail = 0;
62    cb->size = size;
63
64    return 0;
65}
66
67/**
68 * Check if the circular buffer is full
69 *
70 * @param cb Circular buffer to check
71 *
72 * @return true indicates the buffer is full, false otherwise.
73 */
74static inline bool circ_buf_is_full(circ_buf_t *cb) {
75    return _next_pos(cb, cb->tail) == cb->head;
76}
77
78/**
79 * Check if the circular buffer is empty
80 *
81 * @param cb Circular buffer to check
82 *
83 * @return true indicates the buffer is empty, false otherwise.
84 */
85static inline bool circ_buf_is_empty(circ_buf_t *cb) {
86    return cb->tail == cb->head;
87}
88
89/**
90 * Put a byte
91 *
92 * @param cb Circular buffer to put via.
93 * @param c  Byte to send.
94 */
95static inline void circ_buf_put(circ_buf_t *cb, uint8_t c) {
96    cb->buf[cb->tail] = c;
97    cb->tail = _next_pos(cb, cb->tail);
98}
99
100/**
101 * Get a byte
102 *
103 * @param cb Circular buffer to get from.
104 *
105 * @return The byte received.
106 */
107static inline uint8_t circ_buf_get(circ_buf_t *cb) {
108    uint8_t c = cb->buf[cb->head];
109    cb->head = _next_pos(cb, cb->head);
110
111    return c;
112}
113
114