CYCLIC
Description
Manages an already allocated buffer of uint8_t
elements to
perform a cyclic (also called circular or ring) buffer access to memory
as if both buffer ends were connected. Please see the Wikipedia article on
circular buffers for detailed information about this data structure.
The typical use case is buffering of data streams where a consumer reads
data at a different pace than the producer.
Elements are inserted to (Data IN) or extracted from (Data OUT) the
CYCLIC
instance.
Input sources (producers) are single octets, buffers,
null-terminated strings, string with variable arguments
(see VARIANT
) and octets provided by streams
(see STREAM
). Output destinations (consumers) are single octets,
buffers or streams. Produced input data can be discarded, peeked,
overwritten or replaced before consumed. The figure below depicts producers,
consumers and operations on buffered data.
Note
Inserted data may overflow the available buffer capacity,
overwriting older values not yet consumed; this is especially
true when reading from a STREAM
. That’s not a bug,
but a feature™. The user must employ a buffer with an appropriate
size for the intended application to avoid this data structure
feature.
There are three CYCLIC
buffer usage metrics:
- Capacity
Total amount of
uint8_t
buffer elements. SeeCYCLIC_Capacity()
.- Elements
Number of inserted elements waiting to be consumed. See
CYCLIC_Elements()
.- Available
Free space to insert further elements.
On a given time, the actual uint8_t
linear memory buffer usage may
look as in the following figure:
Current IN and OUT buffer pointers are managed by the CYCLIC
instance and are opaque to the user.
API guide
Status functions
Data IN
Data OUT
Peek, overwrite and replace contents
Design and development status
Feature-complete.
Changelog
Version |
Date* |
Author |
Comment |
---|---|---|---|
1.0.0 |
2022.9.7 |
sgermino |
Initial release. |
* Date format is Year.Month.Day.
API reference
-
CYCLIC_IN_FromParsedString(_c, _m, _s, ...)
Automatically instances the parameters list and parameter count required to call
CYCLIC_IN_FromParsedStringArgs()
.- Parameters
_c – The
CYCLIC
instance._u –
MaxOctets
, seeCYCLIC_IN_FromParsedStringArgs()
._s –
Str
, seeCYCLIC_IN_FromParsedStringArgs()
.... – Up to 16 parameters consisting of generic supported types.
-
struct CYCLIC
The user should treat this as an opaque structure. No member should be directly accessed or modified.
-
void CYCLIC_Init(struct CYCLIC *const C, uint8_t *const Buffer, const uint32_t Capacity)
Initializes a
CYCLIC
instance.- Parameters
Buffer – An already allocated
uint8_t
buffer.Capacity – Buffer capacity, in
uint8_t
elements.
Warning
Buffer capacity must be a power of two. This condition is asserted.
-
void CYCLIC_Reset(struct CYCLIC *const C)
Resets the state of a
CYCLIC
instance, keeping theuint8_t
buffer pointer, its declared capacity and usage statistics.
-
uint32_t CYCLIC_Capacity(struct CYCLIC *const C)
Returns buffer capacity passed when initializing this
CYCLIC
instance.- Returns
Number of
uint8_t
elements, as declared at initialization.
-
uint32_t CYCLIC_Elements(struct CYCLIC *const C)
Return elements inserted and not yet consumed.
- Returns
Number of
uint8_t
elements available to consume.
-
uint32_t CYCLIC_Available(struct CYCLIC *const C)
Returns space available to insert elements.
- Returns
Number of
uint8_t
elements available.
-
void CYCLIC_IN_FromOctet(struct CYCLIC *const C, const uint8_t Octet)
[Data IN] Inserts a single
uint8_t
element.- Parameters
Octet – Element value to insert.
-
void CYCLIC_IN_FromBuffer(struct CYCLIC *const C, const uint8_t *const Data, const uint32_t Count)
[Data IN] Inserts an array of
uint8_t
elements.- Parameters
Data – Array of
uint8_t
elements.Count – Number of
uint8_t
elements to insert.
-
void CYCLIC_IN_FromString(struct CYCLIC *const C, const char *const Str, const size_t MaxLen)
[Data IN] Inserts a null-terminated string.
- Parameters
str – Pointer to a null-terminated string.
MaxLen – The null termination in
str
must be found before processing this maximum amount ofchar
elements. This condition is asserted.
-
void CYCLIC_IN_FromParsedStringArgs(struct CYCLIC *const C, const size_t MaxOctets, const char *const Str, struct VARIANT *const ArgValues, const uint32_t ArgCount)
[Data IN] Inserts a null-terminated string with
VARIANT
argument substitution.- Parameters
Str – Pointer to a null-terminated string with indexed argument placeholders.
MaxOctets – The null termination in
Str
must be found before reachingMaxOctets
; this condition is asserted.ArgValues – Array of
VARIANT
elements whose values will replace the argument placeholders inStr
.ArgCount – Number of indexed elements in the
VARIANT
array.
-
void CYCLIC_IN_FromStream(struct CYCLIC *const C, struct STREAM *const S)
[Data IN] Reads a
STREAM
and insert eachuint8_t
element until theSTREAM
signals an end of file (EOF).- Parameters
S –
STREAM
to read and insert elements until EOF.
-
uint8_t CYCLIC_OUT_ToOctet(struct CYCLIC *const C)
[Data OUT] Consumes an octet and returns its value. The caller must have confirmed with
CYCLIC_Elements()
that there is at least one octet to consume; this condition is asserted.- Returns
The octet value.
-
void CYCLIC_OUT_ToBuffer(struct CYCLIC *const C, uint8_t *const Data, const uint32_t Count)
[Data OUT] Consumes a given amount of octets by storing them in an
uint8_t
array already allocated by the user. The user must have confirmed withCYCLIC_Elements()
that the required amount of elements is available; this condition is asserted.- Parameters
Data – Already allocated
uint8_t
array.Count – Number of octets to consume by storing them in the array.
-
void CYCLIC_OUT_ToStream(struct CYCLIC *const C, struct STREAM *const S)
[Data OUT] Tries to consume all elements transferring them to a
STREAM
. The user must have confirmed that there is at least one element to consume; this condition is asserted. After the call, the user must not assume all elements were effectively consumed. The operation may stop prematurely if the stream is unable to receive more items. Depending on the actualSTREAM
implementation, the user may need to wait some time and repeatedly call this function until all elements are consumed. SeeCYCLIC_Elements()
andSTREAM_IN_Count()
.Below is an usage example:
// "s" is an instance of a hypothetical STREAM implementation to handle a // particular hardware UART. Suppose this UART has a limited baud rate and // TX buffering, so it may not send all cyclic elements at once. That is why // CYCLIC_OUT_ToStream() may return before consuming every element. // // "retries" is the maximum number of times to keep calling // CYCLIC_OUT_ToStream() after a STREAM EOF. uint32_t retries = 10; while (retries --) { // Consume elements from the cyclic instance "c" and send them to the // STREAM "s". CYCLIC_OUT_ToStream (&c, &s); // Call returned. // Check for STREAM EOF if (!STREAM_EOF (&s)) { // Not an EOF. CYCLIC_OUT_ToStream should have consumed and sent all // elements. // TEST: Assert that all elements have been consumed. BOARD_AssertState (CYCLIC_Elements(&c) == 0); // Do not retry anymore. break; } else { // STREAM EOF. Keep trying. } } // TEST: invalid states. // 1) Not a STREAM EOF and no more retries. // 2) STREAM EOF and all elements consumed. BOARD_AssertState (!STREAM_EOF(&s) && !retries); BOARD_AssertState (STREAM_EOF(&s) && CYCLIC_Elements(&c) == 0); // There are two valid states: // A) STREAM EOF, run out of retries and not all elements consumed. // B) not a STREAM EOF and all elements consumed.
- Parameters
S –
STREAM
instance to transfer consumed elements. The STREAM may abort the operation at any time.
-
uint8_t CYCLIC_Peek(struct CYCLIC *const C, const uint32_t Index)
Peeks an inserted element before consuming it. The user must check that there are enough inserted elements for the requested
Index
; otherwise, the return value will be invalid.- Parameters
Index – A Zero-based
Index
selects which element to peek; zero is the first element consumed.
- Returns
A copy of the element.
-
void CYCLIC_PeekToBuffer(struct CYCLIC *const C, const uint32_t Index, uint8_t *const Data, const uint32_t Count)
Peeks inserted elements before consuming them by copying their values to an already allocated array of
uint8_t
. The user must check that there are enough inserted elements for the requestedIndex
plusCount
; otherwise, the return value will be invalid.- Parameters
Index – A Zero-based
Index
selects from which element it starts to peek; zero is the first element consumed.Data –
uint8_t
array to copy element values.Count – Number of elements to peek, starting from
Index
.
-
void CYCLIC_PeekToCyclic(struct CYCLIC *const C, const uint32_t Index, const uint32_t Count, struct CYCLIC *const D)
Peek inserted elements before consuming them by inserting a copy of their values to another c:struct:CYCLIC instance. The user must check that there are enough inserted elements for the requested
Index
plusCount
; otherwise, the return value will be invalid.- Parameters
Index – A Zero-based
Index
selects from which element it starts to peek; zero is the first element consumed.Count – Number of elements to peek, starting from
Index
.D – c:struct:CYCLIC instance to store a copy of the elements.
-
void CYCLIC_Overwrite(struct CYCLIC *const C, const uint32_t Index, const uint8_t Octet)
Overwrites an inserted element. The user must check that there are enough inserted elements for the requested
Index
; this condition is asserted.- Parameters
Index – A Zero-based
Index
selects which element to overwrite; zero is the first element consumed.Octet – Overwrite the inserted element with this value.
-
void CYCLIC_OverwriteFromBuffer(struct CYCLIC *const C, const uint32_t Index, const uint8_t *const Data, const uint32_t Count)
Overwrites inserted elements by replacing their values with the ones in an array of
uint8_t
. The user must check that there are enough inserted elements for the requestedIndex
plusCount
; this condition is asserted.- Parameters
Index – A Zero-based
Index
selects from which element it starts to overwrite; zero is the first element consumed.Data – Overwrite the inserted elements with the ones from this
uint8_t
array.Count – Number of elements to overwrite starting from
Index
.
-
void CYCLIC_Replace(struct CYCLIC *const C, const uint32_t Index, const uint32_t Count, const uint8_t Match, const uint8_t Replace)
Replaces an inserted element that is equal to a given value. The user must check that there are enough inserted elements for the requested
Index
plusCount
; this condition is asserted.- Parameters
Index – A Zero-based
Index
selects from which element it starts to check; zero is the first element consumed.Count – Number of elements to check, starting from
Index
.Match – Value to check for equality.
Replace – If equal, replace with this value.
-
void CYCLIC_ReplaceAll(struct CYCLIC *const C, const uint8_t Match, const uint8_t Replace)
Replaces all inserted elements that are equal to a given value. The user must check that there is at least one element; this condition is asserted.
- Parameters
Match – Value to check for equality.
Replace – If equal, replace with this value.