Branch data Line data Source code
1 : : /* ring_buffer.c: Simple ring buffer API */
2 : :
3 : : /*
4 : : * Copyright (c) 2015 Intel Corporation
5 : : *
6 : : * SPDX-License-Identifier: Apache-2.0
7 : : */
8 : :
9 : : #include <zephyr/sys/ring_buffer.h>
10 : : #include <string.h>
11 : :
12 : 0 : uint32_t ring_buf_area_claim(struct ring_buf *buf, struct ring_buf_index *ring,
13 : : uint8_t **data, uint32_t size)
14 : : {
15 : 0 : ring_buf_idx_t head_offset, wrap_size;
16 : :
17 : 0 : head_offset = ring->head - ring->base;
18 [ # # ]: 0 : if (unlikely(head_offset >= buf->size)) {
19 : : /* ring->base is not yet adjusted */
20 : 0 : head_offset -= buf->size;
21 : : }
22 : 0 : wrap_size = buf->size - head_offset;
23 : 0 : size = min(size, wrap_size);
24 : :
25 : 0 : *data = &buf->buffer[head_offset];
26 : 0 : ring->head += size;
27 : :
28 : 0 : return size;
29 : : }
30 : :
31 : 0 : int ring_buf_area_finish(struct ring_buf *buf, struct ring_buf_index *ring,
32 : : uint32_t size)
33 : : {
34 : 0 : ring_buf_idx_t claimed_size, tail_offset;
35 : :
36 : 0 : claimed_size = ring->head - ring->tail;
37 [ # # ]: 0 : if (unlikely(size > claimed_size)) {
38 : : return -EINVAL;
39 : : }
40 : :
41 : 0 : ring->tail += size;
42 : 0 : ring->head = ring->tail;
43 : :
44 : 0 : tail_offset = ring->tail - ring->base;
45 [ # # ]: 0 : if (unlikely(tail_offset >= buf->size)) {
46 : : /* we wrapped: adjust ring->base */
47 : 0 : ring->base += buf->size;
48 : : }
49 : :
50 : : return 0;
51 : : }
52 : :
53 : 0 : uint32_t ring_buf_put(struct ring_buf *buf, const uint8_t *data, uint32_t size)
54 : : {
55 : 0 : uint8_t *dst;
56 : 0 : uint32_t partial_size;
57 : 0 : uint32_t total_size = 0U;
58 : 0 : int err;
59 : :
60 : 0 : do {
61 : 0 : partial_size = ring_buf_put_claim(buf, &dst, size);
62 [ # # ]: 0 : if (partial_size == 0) {
63 : : break;
64 : : }
65 [ # # ]: 0 : memcpy(dst, data, partial_size);
66 : 0 : total_size += partial_size;
67 : 0 : size -= partial_size;
68 : 0 : data += partial_size;
69 [ # # ]: 0 : } while (size != 0);
70 : :
71 : 0 : err = ring_buf_put_finish(buf, total_size);
72 [ # # ]: 0 : __ASSERT_NO_MSG(err == 0);
73 : 0 : ARG_UNUSED(err);
74 : :
75 : 0 : return total_size;
76 : : }
77 : :
78 : 0 : uint32_t ring_buf_get(struct ring_buf *buf, uint8_t *data, uint32_t size)
79 : : {
80 : 0 : uint8_t *src;
81 : 0 : uint32_t partial_size;
82 : 0 : uint32_t total_size = 0U;
83 : 0 : int err;
84 : :
85 : 0 : do {
86 : 0 : partial_size = ring_buf_get_claim(buf, &src, size);
87 [ # # ]: 0 : if (partial_size == 0) {
88 : : break;
89 : : }
90 [ # # ]: 0 : if (data) {
91 : 0 : memcpy(data, src, partial_size);
92 : 0 : data += partial_size;
93 : : }
94 : 0 : total_size += partial_size;
95 : 0 : size -= partial_size;
96 [ # # ]: 0 : } while (size != 0);
97 : :
98 : 0 : err = ring_buf_get_finish(buf, total_size);
99 [ # # ]: 0 : __ASSERT_NO_MSG(err == 0);
100 : 0 : ARG_UNUSED(err);
101 : :
102 : 0 : return total_size;
103 : : }
104 : :
105 : 0 : uint32_t ring_buf_peek(struct ring_buf *buf, uint8_t *data, uint32_t size)
106 : : {
107 : 0 : uint8_t *src;
108 : 0 : uint32_t partial_size;
109 : 0 : uint32_t total_size = 0U;
110 : 0 : int err;
111 : :
112 : 0 : do {
113 : 0 : partial_size = ring_buf_get_claim(buf, &src, size);
114 [ # # ]: 0 : if (partial_size == 0) {
115 : : break;
116 : : }
117 [ # # ]: 0 : __ASSERT_NO_MSG(data != NULL);
118 [ # # ]: 0 : memcpy(data, src, partial_size);
119 : 0 : data += partial_size;
120 : 0 : total_size += partial_size;
121 : 0 : size -= partial_size;
122 [ # # ]: 0 : } while (size != 0);
123 : :
124 : : /* effectively unclaim total_size bytes */
125 : 0 : err = ring_buf_get_finish(buf, 0);
126 [ # # ]: 0 : __ASSERT_NO_MSG(err == 0);
127 : 0 : ARG_UNUSED(err);
128 : :
129 : 0 : return total_size;
130 : : }
131 : :
132 : : /**
133 : : * Internal data structure for a buffer header.
134 : : *
135 : : * We want all of this to fit in a single uint32_t. Every item stored in the
136 : : * ring buffer will be one of these headers plus any extra data supplied
137 : : */
138 : : struct ring_element {
139 : : uint32_t type :16; /**< Application-specific */
140 : : uint32_t length :8; /**< length in 32-bit chunks */
141 : : uint32_t value :8; /**< Room for small integral values */
142 : : };
143 : :
144 : 0 : int ring_buf_item_put(struct ring_buf *buf, uint16_t type, uint8_t value,
145 : : uint32_t *data32, uint8_t size32)
146 : : {
147 : 0 : uint8_t *dst, *data = (uint8_t *)data32;
148 : 0 : struct ring_element *header;
149 : 0 : uint32_t space, size, partial_size, total_size;
150 : 0 : int err;
151 : :
152 : 0 : space = ring_buf_space_get(buf);
153 : 0 : size = size32 * 4;
154 [ # # ]: 0 : if (size + sizeof(struct ring_element) > space) {
155 : : return -EMSGSIZE;
156 : : }
157 : :
158 : 0 : err = ring_buf_put_claim(buf, &dst, sizeof(struct ring_element));
159 [ # # ]: 0 : __ASSERT_NO_MSG(err == sizeof(struct ring_element));
160 : :
161 : 0 : header = (struct ring_element *)dst;
162 : 0 : header->type = type;
163 : 0 : header->length = size32;
164 : 0 : header->value = value;
165 : 0 : total_size = sizeof(struct ring_element);
166 : :
167 : 0 : do {
168 : 0 : partial_size = ring_buf_put_claim(buf, &dst, size);
169 [ # # ]: 0 : if (partial_size == 0) {
170 : : break;
171 : : }
172 [ # # ]: 0 : memcpy(dst, data, partial_size);
173 : 0 : size -= partial_size;
174 : 0 : total_size += partial_size;
175 : 0 : data += partial_size;
176 [ # # ]: 0 : } while (size != 0);
177 [ # # ]: 0 : __ASSERT_NO_MSG(size == 0);
178 : :
179 : 0 : err = ring_buf_put_finish(buf, total_size);
180 [ # # ]: 0 : __ASSERT_NO_MSG(err == 0);
181 : : ARG_UNUSED(err);
182 : :
183 : : return 0;
184 : : }
185 : :
186 : 0 : int ring_buf_item_get(struct ring_buf *buf, uint16_t *type, uint8_t *value,
187 : : uint32_t *data32, uint8_t *size32)
188 : : {
189 : 0 : uint8_t *src, *data = (uint8_t *)data32;
190 : 0 : struct ring_element *header;
191 : 0 : uint32_t size, partial_size, total_size;
192 : 0 : int err;
193 : :
194 [ # # ]: 0 : if (ring_buf_is_empty(buf)) {
195 : : return -EAGAIN;
196 : : }
197 : :
198 : 0 : err = ring_buf_get_claim(buf, &src, sizeof(struct ring_element));
199 [ # # ]: 0 : __ASSERT_NO_MSG(err == sizeof(struct ring_element));
200 : :
201 : 0 : header = (struct ring_element *)src;
202 : :
203 [ # # # # ]: 0 : if (data && (header->length > *size32)) {
204 : 0 : *size32 = header->length;
205 : 0 : ring_buf_get_finish(buf, 0);
206 : 0 : return -EMSGSIZE;
207 : : }
208 : :
209 : 0 : *size32 = header->length;
210 : 0 : *type = header->type;
211 : 0 : *value = header->value;
212 : 0 : total_size = sizeof(struct ring_element);
213 : :
214 : 0 : size = *size32 * 4;
215 : :
216 : 0 : do {
217 : 0 : partial_size = ring_buf_get_claim(buf, &src, size);
218 [ # # ]: 0 : if (partial_size == 0) {
219 : : break;
220 : : }
221 [ # # ]: 0 : if (data) {
222 : 0 : memcpy(data, src, partial_size);
223 : 0 : data += partial_size;
224 : : }
225 : 0 : total_size += partial_size;
226 : 0 : size -= partial_size;
227 [ # # ]: 0 : } while (size != 0);
228 : :
229 : 0 : err = ring_buf_get_finish(buf, total_size);
230 [ # # ]: 0 : __ASSERT_NO_MSG(err == 0);
231 : : ARG_UNUSED(err);
232 : :
233 : : return 0;
234 : : }
|