-
Notifications
You must be signed in to change notification settings - Fork 577
/
ring_buffer.h
497 lines (462 loc) · 15.3 KB
/
ring_buffer.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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/* ring_buffer.h: Simple ring buffer API */
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/** @file */
#ifndef ZEPHYR_INCLUDE_SYS_RING_BUFFER_H_
#define ZEPHYR_INCLUDE_SYS_RING_BUFFER_H_
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <errno.h>
#ifdef __cplusplus
extern "C" {
#endif
/* The limit is used by algorithm for distinguishing between empty and full
* state.
*/
#define RING_BUFFER_MAX_SIZE 0x80000000U
#define RING_BUFFER_SIZE_ASSERT_MSG \
"Size too big"
/**
* @brief A structure to represent a ring buffer
*/
struct ring_buf {
uint8_t *buffer;
int32_t put_head;
int32_t put_tail;
int32_t put_base;
int32_t get_head;
int32_t get_tail;
int32_t get_base;
uint32_t size;
};
/**
* @brief Function to force ring_buf internal states to given value
*
* Any value other than 0 makes sense only in validation testing context.
*/
static inline void ring_buf_internal_reset(struct ring_buf *buf, int32_t value)
{
buf->put_head = buf->put_tail = buf->put_base = value;
buf->get_head = buf->get_tail = buf->get_base = value;
}
/**
* @brief Data Structure APIs
* @defgroup datastructure_apis Data Structure APIs
*/
/**
* @defgroup ring_buffer_apis Ring Buffer APIs
* @ingroup datastructure_apis
* @{
*/
/**
* @brief Define and initialize a ring buffer for byte data.
*
* This macro establishes a ring buffer of an arbitrary size.
* The basic storage unit is a byte.
*
* The ring buffer can be accessed outside the module where it is defined
* using:
*
* @code extern struct ring_buf <name>; @endcode
*
* @param name Name of the ring buffer.
* @param size8 Size of ring buffer (in bytes).
*/
#define RING_BUF_DECLARE(name, size8) \
BUILD_ASSERT(size8 < RING_BUFFER_MAX_SIZE,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint8_t __noinit _ring_buffer_data_##name[size8]; \
struct ring_buf name = { \
.buffer = _ring_buffer_data_##name, \
.size = size8 \
}
/**
* @brief Define and initialize an "item based" ring buffer.
*
* This macro establishes an "item based" ring buffer. Each data item is
* an array of 32-bit words (from zero to 1020 bytes in length), coupled
* with a 16-bit type identifier and an 8-bit integer value.
*
* The ring buffer can be accessed outside the module where it is defined
* using:
*
* @code extern struct ring_buf <name>; @endcode
*
* @param name Name of the ring buffer.
* @param size32 Size of ring buffer (in 32-bit words).
*/
#define RING_BUF_ITEM_DECLARE(name, size32) \
BUILD_ASSERT((size32) < RING_BUFFER_MAX_SIZE / 4,\
RING_BUFFER_SIZE_ASSERT_MSG); \
static uint32_t __noinit _ring_buffer_data_##name[size32]; \
struct ring_buf name = { \
.buffer = (uint8_t *) _ring_buffer_data_##name, \
.size = 4 * (size32) \
}
/**
* @brief Define and initialize an "item based" ring buffer.
*
* This exists for backward compatibility reasons. @ref RING_BUF_ITEM_DECLARE
* should be used instead.
*
* @param name Name of the ring buffer.
* @param size32 Size of ring buffer (in 32-bit words).
*/
#define RING_BUF_ITEM_DECLARE_SIZE(name, size32) \
RING_BUF_ITEM_DECLARE(name, size32)
/**
* @brief Define and initialize a power-of-2 sized "item based" ring buffer.
*
* This macro establishes an "item based" ring buffer by specifying its
* size using a power of 2. This exists mainly for backward compatibility
* reasons. @ref RING_BUF_ITEM_DECLARE should be used instead.
*
* @param name Name of the ring buffer.
* @param pow Ring buffer size exponent.
*/
#define RING_BUF_ITEM_DECLARE_POW2(name, pow) \
RING_BUF_ITEM_DECLARE(name, BIT(pow))
/**
* @brief Compute the ring buffer size in 32-bit needed to store an element
*
* The argument can be a type or an expression.
* Note: rounds up if the size is not a multiple of 32 bits.
*
* @param expr Expression or type to compute the size of
*/
#define RING_BUF_ITEM_SIZEOF(expr) \
((sizeof(expr) + sizeof(uint32_t) - 1) / sizeof(uint32_t))
/**
* @brief Initialize a ring buffer for byte data.
*
* This routine initializes a ring buffer, prior to its first use. It is only
* used for ring buffers not defined using RING_BUF_DECLARE.
*
* @param buf Address of ring buffer.
* @param size Ring buffer size (in bytes).
* @param data Ring buffer data area (uint8_t data[size]).
*/
static inline void ring_buf_init(struct ring_buf *buf,
uint32_t size,
uint8_t *data)
{
__ASSERT(size < RING_BUFFER_MAX_SIZE, RING_BUFFER_SIZE_ASSERT_MSG);
buf->size = size;
buf->buffer = data;
ring_buf_internal_reset(buf, 0);
}
/**
* @brief Initialize an "item based" ring buffer.
*
* This routine initializes a ring buffer, prior to its first use. It is only
* used for ring buffers not defined using RING_BUF_ITEM_DECLARE.
*
* Each data item is an array of 32-bit words (from zero to 1020 bytes in
* length), coupled with a 16-bit type identifier and an 8-bit integer value.
*
* Each data item is an array of 32-bit words (from zero to 1020 bytes in
* length), coupled with a 16-bit type identifier and an 8-bit integer value.
*
* @param buf Address of ring buffer.
* @param size Ring buffer size (in 32-bit words)
* @param data Ring buffer data area (uint32_t data[size]).
*/
static inline void ring_buf_item_init(struct ring_buf *buf,
uint32_t size,
uint32_t *data)
{
__ASSERT(size < RING_BUFFER_MAX_SIZE / 4, RING_BUFFER_SIZE_ASSERT_MSG);
ring_buf_init(buf, 4 * size, (uint8_t *)data);
}
/**
* @brief Determine if a ring buffer is empty.
*
* @param buf Address of ring buffer.
*
* @return true if the ring buffer is empty, or false if not.
*/
static inline bool ring_buf_is_empty(struct ring_buf *buf)
{
return buf->get_head == buf->put_tail;
}
/**
* @brief Reset ring buffer state.
*
* @param buf Address of ring buffer.
*/
static inline void ring_buf_reset(struct ring_buf *buf)
{
ring_buf_internal_reset(buf, 0);
}
/**
* @brief Determine free space in a ring buffer.
*
* @param buf Address of ring buffer.
*
* @return Ring buffer free space (in bytes).
*/
static inline uint32_t ring_buf_space_get(struct ring_buf *buf)
{
return buf->size - (buf->put_head - buf->get_tail);
}
/**
* @brief Determine free space in an "item based" ring buffer.
*
* @param buf Address of ring buffer.
*
* @return Ring buffer free space (in 32-bit words).
*/
static inline uint32_t ring_buf_item_space_get(struct ring_buf *buf)
{
return ring_buf_space_get(buf) / 4;
}
/**
* @brief Return ring buffer capacity.
*
* @param buf Address of ring buffer.
*
* @return Ring buffer capacity (in bytes).
*/
static inline uint32_t ring_buf_capacity_get(struct ring_buf *buf)
{
return buf->size;
}
/**
* @brief Determine used space in a ring buffer.
*
* @param buf Address of ring buffer.
*
* @return Ring buffer space used (in bytes).
*/
static inline uint32_t ring_buf_size_get(struct ring_buf *buf)
{
return buf->put_tail - buf->get_head;
}
/**
* @brief Allocate buffer for writing data to a ring buffer.
*
* With this routine, memory copying can be reduced since internal ring buffer
* can be used directly by the user. Once data is written to allocated area
* number of bytes written must be confirmed (see @ref ring_buf_put_finish).
*
* @warning
* Use cases involving multiple writers to the ring buffer must prevent
* concurrent write operations, either by preventing all writers from
* being preempted or by using a mutex to govern writes to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item access
* (calls prefixed with ring_buf_item_).
*
* @param[in] buf Address of ring buffer.
* @param[out] data Pointer to the address. It is set to a location within
* ring buffer.
* @param[in] size Requested allocation size (in bytes).
*
* @return Size of allocated buffer which can be smaller than requested if
* there is not enough free space or buffer wraps.
*/
uint32_t ring_buf_put_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size);
/**
* @brief Indicate number of bytes written to allocated buffers.
*
* The number of bytes must be equal to or lower than the sum corresponding
* to all preceding @ref ring_buf_put_claim invocations (or even 0). Surplus
* bytes will be returned to the available free buffer space.
*
* @warning
* Use cases involving multiple writers to the ring buffer must prevent
* concurrent write operations, either by preventing all writers from
* being preempted or by using a mutex to govern writes to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item access
* (calls prefixed with ring_buf_item_).
*
* @param buf Address of ring buffer.
* @param size Number of valid bytes in the allocated buffers.
*
* @retval 0 Successful operation.
* @retval -EINVAL Provided @a size exceeds free space in the ring buffer.
*/
int ring_buf_put_finish(struct ring_buf *buf, uint32_t size);
/**
* @brief Write (copy) data to a ring buffer.
*
* This routine writes data to a ring buffer @a buf.
*
* @warning
* Use cases involving multiple writers to the ring buffer must prevent
* concurrent write operations, either by preventing all writers from
* being preempted or by using a mutex to govern writes to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item access
* (calls prefixed with ring_buf_item_).
*
* @param buf Address of ring buffer.
* @param data Address of data.
* @param size Data size (in bytes).
*
* @retval Number of bytes written.
*/
uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size);
/**
* @brief Get address of a valid data in a ring buffer.
*
* With this routine, memory copying can be reduced since internal ring buffer
* can be used directly by the user. Once data is processed it must be freed
* using @ref ring_buf_get_finish.
*
* @warning
* Use cases involving multiple reads of the ring buffer must prevent
* concurrent read operations, either by preventing all readers from
* being preempted or by using a mutex to govern reads to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item access
* (calls prefixed with ring_buf_item_).
*
* @param[in] buf Address of ring buffer.
* @param[out] data Pointer to the address. It is set to a location within
* ring buffer.
* @param[in] size Requested size (in bytes).
*
* @return Number of valid bytes in the provided buffer which can be smaller
* than requested if there is not enough free space or buffer wraps.
*/
uint32_t ring_buf_get_claim(struct ring_buf *buf,
uint8_t **data,
uint32_t size);
/**
* @brief Indicate number of bytes read from claimed buffer.
*
* The number of bytes must be equal or lower than the sum corresponding to
* all preceding @ref ring_buf_get_claim invocations (or even 0). Surplus
* bytes will remain available in the buffer.
*
* @warning
* Use cases involving multiple reads of the ring buffer must prevent
* concurrent read operations, either by preventing all readers from
* being preempted or by using a mutex to govern reads to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item mode
* (calls prefixed with ring_buf_item_).
*
* @param buf Address of ring buffer.
* @param size Number of bytes that can be freed.
*
* @retval 0 Successful operation.
* @retval -EINVAL Provided @a size exceeds valid bytes in the ring buffer.
*/
int ring_buf_get_finish(struct ring_buf *buf, uint32_t size);
/**
* @brief Read data from a ring buffer.
*
* This routine reads data from a ring buffer @a buf.
*
* @warning
* Use cases involving multiple reads of the ring buffer must prevent
* concurrent read operations, either by preventing all readers from
* being preempted or by using a mutex to govern reads to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item mode
* (calls prefixed with ring_buf_item_).
*
* @param buf Address of ring buffer.
* @param data Address of the output buffer. Can be NULL to discard data.
* @param size Data size (in bytes).
*
* @retval Number of bytes written to the output buffer.
*/
uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size);
/**
* @brief Peek at data from a ring buffer.
*
* This routine reads data from a ring buffer @a buf without removal.
*
* @warning
* Use cases involving multiple reads of the ring buffer must prevent
* concurrent read operations, either by preventing all readers from
* being preempted or by using a mutex to govern reads to the ring buffer.
*
* @warning
* Ring buffer instance should not mix byte access and item mode
* (calls prefixed with ring_buf_item_).
*
* @warning
* Multiple calls to peek will result in the same data being 'peeked'
* multiple times. To remove data, use either @ref ring_buf_get or
* @ref ring_buf_get_claim followed by @ref ring_buf_get_finish with a
* non-zero `size`.
*
* @param buf Address of ring buffer.
* @param data Address of the output buffer. Cannot be NULL.
* @param size Data size (in bytes).
*
* @retval Number of bytes written to the output buffer.
*/
uint32_t ring_buf_peek(struct ring_buf *buf, uint8_t *data, uint32_t size);
/**
* @brief Write a data item to a ring buffer.
*
* This routine writes a data item to ring buffer @a buf. The data item
* is an array of 32-bit words (from zero to 1020 bytes in length),
* coupled with a 16-bit type identifier and an 8-bit integer value.
*
* @warning
* Use cases involving multiple writers to the ring buffer must prevent
* concurrent write operations, either by preventing all writers from
* being preempted or by using a mutex to govern writes to the ring buffer.
*
* @param buf Address of ring buffer.
* @param type Data item's type identifier (application specific).
* @param value Data item's integer value (application specific).
* @param data Address of data item.
* @param size32 Data item size (number of 32-bit words).
*
* @retval 0 Data item was written.
* @retval -EMSGSIZE Ring buffer has insufficient free space.
*/
int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
uint32_t *data, uint8_t size32);
/**
* @brief Read a data item from a ring buffer.
*
* This routine reads a data item from ring buffer @a buf. The data item
* is an array of 32-bit words (up to 1020 bytes in length),
* coupled with a 16-bit type identifier and an 8-bit integer value.
*
* @warning
* Use cases involving multiple reads of the ring buffer must prevent
* concurrent read operations, either by preventing all readers from
* being preempted or by using a mutex to govern reads to the ring buffer.
*
* @param buf Address of ring buffer.
* @param type Area to store the data item's type identifier.
* @param value Area to store the data item's integer value.
* @param data Area to store the data item. Can be NULL to discard data.
* @param size32 Size of the data item storage area (number of 32-bit chunks).
*
* @retval 0 Data item was fetched; @a size32 now contains the number of
* 32-bit words read into data area @a data.
* @retval -EAGAIN Ring buffer is empty.
* @retval -EMSGSIZE Data area @a data is too small; @a size32 now contains
* the number of 32-bit words needed.
*/
int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value,
uint32_t *data, uint8_t *size32);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_SYS_RING_BUFFER_H_ */