1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @brief Generic double buffer data structure header.
9  *
10  * The structure may be used as a header for any kind of data structure that requires
11  * double buffering.
12  */
13 struct dbuf_hdr {
14 	/* The current element that is in use. */
15 	uint8_t volatile first;
16 	/* Last enqueued element. It will be used after buffer is swapped. */
17 	uint8_t last;
18 	/* Size in a bytes of a single element stored in double buffer. */
19 	uint8_t elem_size;
20 	/* Pointer for actual buffer memory. Its size should be 2 times @p elem_size. */
21 	uint8_t data[0];
22 };
23 
24 /**
25  * @brief Allocate element in double buffer.
26  *
27  * The function provides pointer to new element that may be modified by the user.
28  * For consecutive calls it always returns the same pointer until buffer is swapped
29  * by dbuf_latest_get operation.
30  *
31  * @param hdr Pointer to double buffer header.
32  * @param idx Pointer to return new element index.
33  *
34  * @return Pointer to new element memory.
35  */
36 void *dbuf_alloc(struct dbuf_hdr *hdr, uint8_t *idx);
37 
38 /**
39  * @brief Provides pointer to last allocated element.
40  *
41  * If it is called before dbuf_alloc it will return pointer to memory that was recently
42  * enqueued.
43  *
44  * @param hdr Pointer to double buffer header.
45  *
46  * @return Pointer to last allocated element.
47  */
dbuf_peek(struct dbuf_hdr * hdr)48 static inline void *dbuf_peek(struct dbuf_hdr *hdr)
49 {
50 	return &hdr->data[hdr->last * hdr->elem_size];
51 }
52 
53 /**
54  * @brief  Enqueue new element for buffer swap.
55  *
56  * @param hdr Pointer to double buffer header.
57  * @param idx Index of element to be swapped.
58  */
dbuf_enqueue(struct dbuf_hdr * hdr,uint8_t idx)59 static inline void dbuf_enqueue(struct dbuf_hdr *hdr, uint8_t idx)
60 {
61 	hdr->last = idx;
62 }
63 
64 /**
65  * @brief Get latest element in buffer.
66  *
67  * Latest enqueued element is pointed by last member of dbuf_hdr.
68  * If it points to a different index than member first, then buffer will be
69  * swapped and @p is_modified will be set to true.
70  *
71  * Pointer to latest element is returned.
72  *
73  * @param[in] hdr Pointer to double buffer header.
74  * @param[out] is_modified Pointer to return information if buffer was swapped.
75  *
76  * @return Pointer to latest enqueued buffer element.
77  */
78 void *dbuf_latest_get(struct dbuf_hdr *hdr, uint8_t *is_modified);
79 
80 /**
81  * @brief Returns pointer to the current element, the one after last swap operation.
82  *
83  * The function provides access to element that is pointed by member first of dbuf_hrd.
84  * Returned value always points to latest one, that was swapped after most recent call to
85  * dbuf_latest_get. The pointer will be the same as the one pointed by last if the dbuf_alloc
86  * is not called after last dbuf_latest_get call.
87  *
88  * @param hdr Pointer to double buffer header.
89 
90  * @return Pointer to element after last buffer swap.
91  */
dbuf_curr_get(struct dbuf_hdr * hdr)92 static inline void *dbuf_curr_get(struct dbuf_hdr *hdr)
93 {
94 	return &hdr->data[hdr->first * hdr->elem_size];
95 }
96 
97 /**
98  * @brief Return information whether new element was enqueued to a buffer.
99  *
100  * @param hdr Pointer to double buffer header.
101  *
102  * @return True if there were new element enqueued, false in other case.
103  */
dbuf_is_modified(const struct dbuf_hdr * hdr)104 static inline bool dbuf_is_modified(const struct dbuf_hdr *hdr)
105 {
106 	return hdr->first != hdr->last;
107 }
108