-
Notifications
You must be signed in to change notification settings - Fork 41
/
ring_buffer_lib.h
220 lines (200 loc) · 8.41 KB
/
ring_buffer_lib.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* @file ring_buffer_lib.h
* @brief A collection of multi-core safe functions for managing ring buffers
* @note This library depends on the Raspberry Pi Pico SDK for
* managing critical sections
*
* MIT License
* Copyright (c) 2022 rppicomidi
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef RING_BUFFER_LIB_H
#define RING_BUFFER_LIB_H
#include <stdint.h>
#include "pico/stdlib.h"
#include "ring_buffer_lib_config.h"
// Define RING_BUFFER_SIZE_TYPE to the data type appropriate for storing
// the number of bytes in the buffer
// The default size can hold up to 255 entries.
#ifndef RING_BUFFER_SIZE_TYPE
#define RING_BUFFER_SIZE_TYPE uint8_t
#endif
#ifndef RING_BUFFER_MULTICORE_SUPPORT
#define RING_BUFFER_MULTICORE_SUPPORT 0
#endif
#if RING_BUFFER_MULTICORE_SUPPORT
#include "pico/critical_section.h"
#else
#include "pico/sync.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RING_BUFFER_ENTER_CRITICAL
#define RING_BUFFER_ENTER_CRITICAL(X) \
uint32_t X; \
do { X=save_and_disable_interrupts();} while(0)
#endif
#ifndef RING_BUFFER_EXIT_CRITICAL
#define RING_BUFFER_EXIT_CRITICAL(X) \
do {restore_interrupts(X); } while(0)
#endif
/**
* @struct a ring buffer
*/
typedef struct ring_buffer_s
{
uint8_t *buf; // A pointer to the ring buffer storage
RING_BUFFER_SIZE_TYPE bufsize; // the number of bytes in the buffer
RING_BUFFER_SIZE_TYPE in_idx; // the index into the buffer where the next data byte is written
RING_BUFFER_SIZE_TYPE out_idx; // the index into the buffer where the least recently written byte is stored
RING_BUFFER_SIZE_TYPE num_buffered; // the number of bytes in the buffer
#if RING_BUFFER_MULTICORE_SUPPORT
critical_section_t crit; // a poiter to the critical section
#else
uint32_t critical_section_data; // data used by the critical section macros; application specific
#endif
} ring_buffer_t;
#if RING_BUFFER_MULTICORE_SUPPORT
/**
* @brief initialize a ring buffer structure
* @param ring_buf a pointer to the ring buffer structure
* @param buf a pointer to the storage the ring buffer will use
* @param buf_len the number of bytes allocated for the buffer
* @param lock_num the critical section spinlock number to use for this ring buffer
*/
void ring_buffer_init(ring_buffer_t *ring_buf, uint8_t* buf, RING_BUFFER_SIZE_TYPE buf_len, uint lock_num);
#else
/**
* @brief initialize a ring buffer structure
* @param ring_buf a pointer to the ring buffer structure
* @param buf a pointer to the storage the ring buffer will use
* @param buf_len the number of bytes allocated for the buffer
* @param critical_section_data application specific data value used for managing critical sections (e.g. an IRQ number)
*/
void ring_buffer_init(ring_buffer_t *ring_buf, uint8_t* buf, RING_BUFFER_SIZE_TYPE buf_len, uint32_t critical_section_data);
#endif
/**
* @brief put nvals bytes in a ring buffer without disabling interrupts
* @param ring_buf pointer to the ring buffer structure
* @param vals a buffer of bytes to put in the ring buffer
* @param nvals the number of values to push
* @returns the number of values pushed
*/
RING_BUFFER_SIZE_TYPE ring_buffer_push_unsafe(ring_buffer_t *ring_buf, const uint8_t* vals, RING_BUFFER_SIZE_TYPE nvals);
/**
* @brief enter a critical section and then put byte in a ring buffer
* @param ring_buf pointer to the ring buffer structure
* @param val the byte to put in the ring buffer
* @returns the number of values pushed
*/
RING_BUFFER_SIZE_TYPE ring_buffer_push(ring_buffer_t *ring_buf, const uint8_t* vals, RING_BUFFER_SIZE_TYPE nvals);
/**
* @brief enter a critical section and then put byte in a ring buffer overwriting old data
* @param ring_buf pointer to the ring buffer structure
* @param val the byte to put in the ring buffer
*/
void ring_buffer_push_ovr(ring_buffer_t *ring_buf, const uint8_t *vals, RING_BUFFER_SIZE_TYPE nvals);
/**
* @brief wait for the spinlock but do not disable interrupts before
* getting the number of bytes currently stored in the buffer
*
* @param ring_buf a pointer to the ring buffer structure
* @return the number of bytes in the buffer (may be 0)
*/
RING_BUFFER_SIZE_TYPE ring_buffer_get_num_bytes_unsafe(ring_buffer_t *ring_buf);
/**
* @brief wait for the spinlock and disable interrupts before
* getting the number of bytes currently stored in the buffer
*
* @param ring_buf a pointer to the ring buffer structure
* @return the number of bytes in the buffer (may be 0)
*/
RING_BUFFER_SIZE_TYPE ring_buffer_get_num_bytes(ring_buffer_t *ring_buf);
/**
* @brief wait for the spinlock but do not disable interrupts before
* checking if the ring buffer is full
*
* @param ring_buf a pointer to the ring buffer structure
* @return true if the ring buffer is full
*/
bool ring_buffer_is_full_unsafe(ring_buffer_t *ring_buf);
/**
* @brief wait for the spinlock and disable interrupts before
* checking if the ring buffer is full
*
* @param ring_buf a pointer to the ring buffer structure
* @return true if the ring buffer is full
*/
bool ring_buffer_is_full(ring_buffer_t *ring_buf);
/**
* @brief do not disable interrupts but do take spinlock
* before checking if ring buffer is empty
*
* @param ring_buf a pointer to the ring buffer structure
* @return true if the ring buffer is empty
*/
bool ring_buffer_is_empty_unsafe(ring_buffer_t *ring_buf);
/**
* @brief disable interrupts on this processor and wait for
* spinlock before checking if the ring buffer is empty
*
* @param ring_buf a pointer to the ring buffer structure
* @return true if the ring buffer is empty
*/
bool ring_buffer_is_empty(ring_buffer_t *ring_buf);
/**
* @brief read and remove a byte from the ring buffer without disabling interrupts
*
* @param ring_buf a pointer to the ring buffer structure
* @param vals a pointer to a byte buffer to hold the values read
* @param maxvals the maximum number of values to read.
* @return the number of bytes popped
*/
RING_BUFFER_SIZE_TYPE ring_buffer_pop_unsafe(ring_buffer_t *ring_buf, uint8_t* vals, RING_BUFFER_SIZE_TYPE maxvals);
/**
* @brief entering a critical section, then read and remove a byte from the ring buffer
*
* @param ring_buf a pointer to the ring buffer structure
* @param vals a pointer to a byte buffer to hold the values read
* @param maxvals the maximum number of values to read.
* @return the number of bytes popped
*/
RING_BUFFER_SIZE_TYPE ring_buffer_pop(ring_buffer_t *ring_buf, uint8_t* vals, RING_BUFFER_SIZE_TYPE maxvals);
/**
* @brief read bytes from the ring buffer without removing them from the buffer and without disabling interrupts
*
* @param ring_buf a pointer to the ring buffer structure
* @param vals a pointer to a byte buffer to hold the values read
* @param maxvals the maximum number of values to read.
* @return the number of bytes read into the vals buffer
*/
RING_BUFFER_SIZE_TYPE ring_buffer_peek_unsafe(ring_buffer_t *ring_buf, uint8_t* vals, RING_BUFFER_SIZE_TYPE maxvals);
/**
* @brief enter a critical section, then read bytes from the ring buffer without removing it from the buffer
*
* @param ring_buf a pointer to the ring buffer structure
* @param vals a pointer to a byte buffer to hold the values read
* @param maxvals the maximum number of values to read.
* @return the number of bytes read into the vals buffer
*/
RING_BUFFER_SIZE_TYPE ring_buffer_peek(ring_buffer_t *ring_buf, uint8_t* vals, RING_BUFFER_SIZE_TYPE maxvals);
#ifdef __cplusplus
}
#endif
#endif //RING_BUFFER_LIB_H