summaryrefslogtreecommitdiff
path: root/components/drivers/src/ringbuffer.c
blob: 6872c19dc3db379171205eb41a44fe4ab9c81b2c (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
#include <rtthread.h>
#include <rtdevice.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 = size;
}

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

	RT_ASSERT(rb != RT_NULL);

	/* whether has enough space */
	if (rb->read_index > rb->write_index)
		size = rb->read_index - rb->write_index;
	else
		size = rb->buffer_size - rb->write_index + rb->read_index;

	/* 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 */
		rt_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 */
			rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
			rb->write_index += length;
		}
		else
		{
			rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr,
				   rb->buffer_size - rb->write_index);
			rt_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_ASSERT(rb != RT_NULL);
	/* whether has enough space */
	next = rb->write_index + 1;
	if (next >= rb->buffer_size) next = 0;

	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_ASSERT(rb != RT_NULL);
	/* whether has enough data  */
	if (rb->read_index > rb->write_index)
		size = rb->buffer_size - rb->read_index + rb->write_index;
	else
		size = rb->write_index - rb->read_index;

	/* 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 */
			rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
			rb->read_index += length;
		}
		else
		{
			/* copy first and second */
			rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index],
				   rb->buffer_size - rb->read_index);
			rt_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
	{
		rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
		rb->read_index += length;
	}

	return length;
}

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

	RT_ASSERT(rb != RT_NULL);
	if (rb->read_index > rb->write_index)
		size = rb->buffer_size - rb->read_index + rb->write_index;
	else
		size = rb->write_index - rb->read_index;

	/* 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);
}