summaryrefslogtreecommitdiff
path: root/components/drivers/src/ringbuffer.c
blob: 80606469af4b58f9780178b3d70b7c8c9f22ecd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>

void rt_ringbuffer_init(struct rt_ringbuffer* rb, rt_uint8_t *pool, rt_uint16_t size)
{
	RT_ASSERT(rb != RT_NULL);

	/* initialize read and write index */
	rb->read_index = rb->write_index = 0;

	/* set buffer pool and size */
	rb->buffer_ptr = pool;
	rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}

rt_size_t rt_ringbuffer_put(struct rt_ringbuffer* rb, const rt_uint8_t *ptr, rt_uint16_t length)
{
	rt_uint16_t size;
	rt_uint16_t mask;

	RT_ASSERT(rb != RT_NULL);

	mask = rb->buffer_size - 1;
	/* whether has enough space */
	size = rb->buffer_size - ((rb->write_index - rb->read_index) & mask);

	/* no space */
	if (size == 0) return 0;
	/* drop some data */
	if (size < length) length = size;

	if (rb->read_index > rb->write_index)
	{
		/* read_index - write_index = empty space */
		memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
		rb->write_index += length;
	}
	else
	{
		if (rb->buffer_size - rb->write_index >= length)
		{
			/* there is enough space after write_index */
			memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
			rb->write_index = (rb->write_index + length) & mask;
		}
		else
		{
			memcpy(&rb->buffer_ptr[rb->write_index], ptr,
					rb->buffer_size - rb->write_index);
			memcpy(&rb->buffer_ptr[0], &ptr[rb->buffer_size - rb->write_index],
					length - (rb->buffer_size - rb->write_index));
			rb->write_index = length - (rb->buffer_size - rb->write_index);
		}
	}

	return length;
}

/**
 * put a character into ring buffer
 */
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer* rb, const rt_uint8_t ch)
{
	rt_uint16_t next;
	rt_uint16_t mask;

	RT_ASSERT(rb != RT_NULL);
	/* whether has enough space */
	mask = rb->buffer_size - 1;
	next = (rb->write_index + 1) & mask;

	if (next == rb->read_index) return 0;

	/* put character */
	rb->buffer_ptr[rb->write_index] = ch;
	rb->write_index = next;

	return 1;
}

/**
 *  get data from ring buffer
 */
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer* rb, rt_uint8_t *ptr, rt_uint16_t length)
{
	rt_size_t size;
	rt_uint16_t mask;

	RT_ASSERT(rb != RT_NULL);
	/* whether has enough data  */
	mask = rb->buffer_size - 1;
	size = (rb->write_index - rb->read_index) & mask;

	/* no data */
	if (size == 0) return 0;
	/* less data */
	if (size < length) length = size;

	if (rb->read_index > rb->write_index)
	{
		if (rb->buffer_size - rb->read_index >= length)
		{
			/* copy directly */
			memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
			rb->read_index = (rb->read_index + length) & mask;
		}
		else
		{
			/* copy first and second */
			memcpy(ptr, &rb->buffer_ptr[rb->read_index],
				   rb->buffer_size - rb->read_index);
			memcpy(&ptr[rb->buffer_size - rb->read_index], &rb->buffer_ptr[0],
				   length - rb->buffer_size + rb->read_index);
			rb->read_index = length - rb->buffer_size + rb->read_index;
		}
	}
	else
	{
		memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
		rb->read_index += length;
	}

	return length;
}

rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer* rb, rt_uint8_t *ch)
{
	rt_uint16_t next;
	rt_uint16_t mask;

	RT_ASSERT(rb != RT_NULL);
	
	/* ringbuffer is empty */
	if (rb->read_index == rb->write_index) return 0;

	/* whether has data */
	mask = rb->buffer_size - 1;
	next = (rb->read_index + 1) & mask;

	/* put character */
	*ch = rb->buffer_ptr[rb->read_index];
	rb->read_index = next;

	return 1;
}

/**
 * get available data size
 */
rt_size_t rt_ringbuffer_available_size(struct rt_ringbuffer* rb)
{
	rt_size_t size;
	rt_uint16_t mask;

	RT_ASSERT(rb != RT_NULL);

	mask = rb->buffer_size - 1;
	size = (rb->write_index - rb->read_index) & mask;

	/* return the available size */
	return size;
}

/**
 * get empty space size
 */
rt_size_t rt_ringbuffer_emptry_size(struct rt_ringbuffer* rb)
{
	RT_ASSERT(rb != RT_NULL);

	return rb->buffer_size - rt_ringbuffer_available_size(rb);
}