1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2012-09-30 Bernard first version.
9 * 2013-05-08 Grissiom reimplement
10 * 2016-08-18 heyuanjie add interface
11 */
12
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 #include <string.h>
16
rt_ringbuffer_status(struct rt_ringbuffer * rb)17 rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
18 {
19 if (rb->read_index == rb->write_index)
20 {
21 if (rb->read_mirror == rb->write_mirror)
22 return RT_RINGBUFFER_EMPTY;
23 else
24 return RT_RINGBUFFER_FULL;
25 }
26 return RT_RINGBUFFER_HALFFULL;
27 }
28
rt_ringbuffer_init(struct rt_ringbuffer * rb,rt_uint8_t * pool,rt_int16_t size)29 void rt_ringbuffer_init(struct rt_ringbuffer *rb,
30 rt_uint8_t *pool,
31 rt_int16_t size)
32 {
33 RT_ASSERT(rb != RT_NULL);
34 RT_ASSERT(size > 0);
35
36 /* initialize read and write index */
37 rb->read_mirror = rb->read_index = 0;
38 rb->write_mirror = rb->write_index = 0;
39
40 /* set buffer pool and size */
41 rb->buffer_ptr = pool;
42 rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
43 }
44 RTM_EXPORT(rt_ringbuffer_init);
45
46 /**
47 * put a block of data into ring buffer
48 */
rt_ringbuffer_put(struct rt_ringbuffer * rb,const rt_uint8_t * ptr,rt_uint16_t length)49 rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
50 const rt_uint8_t *ptr,
51 rt_uint16_t length)
52 {
53 rt_uint16_t size;
54
55 RT_ASSERT(rb != RT_NULL);
56
57 /* whether has enough space */
58 size = rt_ringbuffer_space_len(rb);
59
60 /* no space */
61 if (size == 0)
62 return 0;
63
64 /* drop some data */
65 if (size < length)
66 length = size;
67
68 if (rb->buffer_size - rb->write_index > length)
69 {
70 /* read_index - write_index = empty space */
71 memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
72 /* this should not cause overflow because there is enough space for
73 * length of data in current mirror */
74 rb->write_index += length;
75 return length;
76 }
77
78 memcpy(&rb->buffer_ptr[rb->write_index],
79 &ptr[0],
80 rb->buffer_size - rb->write_index);
81 memcpy(&rb->buffer_ptr[0],
82 &ptr[rb->buffer_size - rb->write_index],
83 length - (rb->buffer_size - rb->write_index));
84
85 /* we are going into the other side of the mirror */
86 rb->write_mirror = ~rb->write_mirror;
87 rb->write_index = length - (rb->buffer_size - rb->write_index);
88
89 return length;
90 }
91 RTM_EXPORT(rt_ringbuffer_put);
92
93 /**
94 * put a block of data into ring buffer
95 *
96 * When the buffer is full, it will discard the old data.
97 */
rt_ringbuffer_put_force(struct rt_ringbuffer * rb,const rt_uint8_t * ptr,rt_uint16_t length)98 rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
99 const rt_uint8_t *ptr,
100 rt_uint16_t length)
101 {
102 rt_uint16_t space_length;
103
104 RT_ASSERT(rb != RT_NULL);
105
106 space_length = rt_ringbuffer_space_len(rb);
107
108 if (length > rb->buffer_size)
109 {
110 ptr = &ptr[length - rb->buffer_size];
111 length = rb->buffer_size;
112 }
113
114 if (rb->buffer_size - rb->write_index > length)
115 {
116 /* read_index - write_index = empty space */
117 memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
118 /* this should not cause overflow because there is enough space for
119 * length of data in current mirror */
120 rb->write_index += length;
121
122 if (length > space_length)
123 rb->read_index = rb->write_index;
124
125 return length;
126 }
127
128 memcpy(&rb->buffer_ptr[rb->write_index],
129 &ptr[0],
130 rb->buffer_size - rb->write_index);
131 memcpy(&rb->buffer_ptr[0],
132 &ptr[rb->buffer_size - rb->write_index],
133 length - (rb->buffer_size - rb->write_index));
134
135 /* we are going into the other side of the mirror */
136 rb->write_mirror = ~rb->write_mirror;
137 rb->write_index = length - (rb->buffer_size - rb->write_index);
138
139 if (length > space_length)
140 {
141 rb->read_mirror = ~rb->read_mirror;
142 rb->read_index = rb->write_index;
143 }
144
145 return length;
146 }
147 RTM_EXPORT(rt_ringbuffer_put_force);
148
149 /**
150 * get data from ring buffer
151 */
rt_ringbuffer_get(struct rt_ringbuffer * rb,rt_uint8_t * ptr,rt_uint16_t length)152 rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
153 rt_uint8_t *ptr,
154 rt_uint16_t length)
155 {
156 rt_size_t size;
157
158 RT_ASSERT(rb != RT_NULL);
159
160 /* whether has enough data */
161 size = rt_ringbuffer_data_len(rb);
162
163 /* no data */
164 if (size == 0)
165 return 0;
166
167 /* less data */
168 if (size < length)
169 length = size;
170
171 if (rb->buffer_size - rb->read_index > length)
172 {
173 /* copy all of data */
174 memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
175 /* this should not cause overflow because there is enough space for
176 * length of data in current mirror */
177 rb->read_index += length;
178 return length;
179 }
180
181 memcpy(&ptr[0],
182 &rb->buffer_ptr[rb->read_index],
183 rb->buffer_size - rb->read_index);
184 memcpy(&ptr[rb->buffer_size - rb->read_index],
185 &rb->buffer_ptr[0],
186 length - (rb->buffer_size - rb->read_index));
187
188 /* we are going into the other side of the mirror */
189 rb->read_mirror = ~rb->read_mirror;
190 rb->read_index = length - (rb->buffer_size - rb->read_index);
191
192 return length;
193 }
194 RTM_EXPORT(rt_ringbuffer_get);
195
196 /**
197 * put a character into ring buffer
198 */
rt_ringbuffer_putchar(struct rt_ringbuffer * rb,const rt_uint8_t ch)199 rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
200 {
201 RT_ASSERT(rb != RT_NULL);
202
203 /* whether has enough space */
204 if (!rt_ringbuffer_space_len(rb))
205 return 0;
206
207 rb->buffer_ptr[rb->write_index] = ch;
208
209 /* flip mirror */
210 if (rb->write_index == rb->buffer_size-1)
211 {
212 rb->write_mirror = ~rb->write_mirror;
213 rb->write_index = 0;
214 }
215 else
216 {
217 rb->write_index++;
218 }
219
220 return 1;
221 }
222 RTM_EXPORT(rt_ringbuffer_putchar);
223
224 /**
225 * put a character into ring buffer
226 *
227 * When the buffer is full, it will discard one old data.
228 */
rt_ringbuffer_putchar_force(struct rt_ringbuffer * rb,const rt_uint8_t ch)229 rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
230 {
231 enum rt_ringbuffer_state old_state;
232
233 RT_ASSERT(rb != RT_NULL);
234
235 old_state = rt_ringbuffer_status(rb);
236
237 rb->buffer_ptr[rb->write_index] = ch;
238
239 /* flip mirror */
240 if (rb->write_index == rb->buffer_size-1)
241 {
242 rb->write_mirror = ~rb->write_mirror;
243 rb->write_index = 0;
244 if (old_state == RT_RINGBUFFER_FULL)
245 {
246 rb->read_mirror = ~rb->read_mirror;
247 rb->read_index = rb->write_index;
248 }
249 }
250 else
251 {
252 rb->write_index++;
253 if (old_state == RT_RINGBUFFER_FULL)
254 rb->read_index = rb->write_index;
255 }
256
257 return 1;
258 }
259 RTM_EXPORT(rt_ringbuffer_putchar_force);
260
261 /**
262 * get a character from a ringbuffer
263 */
rt_ringbuffer_getchar(struct rt_ringbuffer * rb,rt_uint8_t * ch)264 rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
265 {
266 RT_ASSERT(rb != RT_NULL);
267
268 /* ringbuffer is empty */
269 if (!rt_ringbuffer_data_len(rb))
270 return 0;
271
272 /* put character */
273 *ch = rb->buffer_ptr[rb->read_index];
274
275 if (rb->read_index == rb->buffer_size-1)
276 {
277 rb->read_mirror = ~rb->read_mirror;
278 rb->read_index = 0;
279 }
280 else
281 {
282 rb->read_index++;
283 }
284
285 return 1;
286 }
287 RTM_EXPORT(rt_ringbuffer_getchar);
288
289 /**
290 * get the size of data in rb
291 */
rt_ringbuffer_data_len(struct rt_ringbuffer * rb)292 rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
293 {
294 switch (rt_ringbuffer_status(rb))
295 {
296 case RT_RINGBUFFER_EMPTY:
297 return 0;
298 case RT_RINGBUFFER_FULL:
299 return rb->buffer_size;
300 case RT_RINGBUFFER_HALFFULL:
301 default:
302 if (rb->write_index > rb->read_index)
303 return rb->write_index - rb->read_index;
304 else
305 return rb->buffer_size - (rb->read_index - rb->write_index);
306 };
307 }
308 RTM_EXPORT(rt_ringbuffer_data_len);
309
310 /**
311 * empty the rb
312 */
rt_ringbuffer_reset(struct rt_ringbuffer * rb)313 void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
314 {
315 RT_ASSERT(rb != RT_NULL);
316
317 rb->read_mirror = 0;
318 rb->read_index = 0;
319 rb->write_mirror = 0;
320 rb->write_index = 0;
321 }
322 RTM_EXPORT(rt_ringbuffer_reset);
323
324 #ifdef RT_USING_HEAP
325
rt_ringbuffer_create(rt_uint16_t size)326 struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t size)
327 {
328 struct rt_ringbuffer *rb;
329 rt_uint8_t *pool;
330
331 RT_ASSERT(size > 0);
332
333 size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
334
335 rb = rt_malloc(sizeof(struct rt_ringbuffer));
336 if (rb == RT_NULL)
337 goto exit;
338
339 pool = rt_malloc(size);
340 if (pool == RT_NULL)
341 {
342 rt_free(rb);
343 rb = RT_NULL;
344 goto exit;
345 }
346 rt_ringbuffer_init(rb, pool, size);
347
348 exit:
349 return rb;
350 }
351 RTM_EXPORT(rt_ringbuffer_create);
352
rt_ringbuffer_destroy(struct rt_ringbuffer * rb)353 void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
354 {
355 RT_ASSERT(rb != RT_NULL);
356
357 rt_free(rb->buffer_ptr);
358 rt_free(rb);
359 }
360 RTM_EXPORT(rt_ringbuffer_destroy);
361
362 #endif
363