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