1 /*
2  * @brief Common ring buffer support functions
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include <string.h>
33 #include "ring_buffer.h"
34 
35 /*****************************************************************************
36  * Private types/enumerations/variables
37  ****************************************************************************/
38 
39 #define RB_INDH(rb)                ((rb)->head & ((rb)->count - 1))
40 #define RB_INDT(rb)                ((rb)->tail & ((rb)->count - 1))
41 
42 /*****************************************************************************
43  * Public types/enumerations/variables
44  ****************************************************************************/
45 
46 /*****************************************************************************
47  * Private functions
48  ****************************************************************************/
49 
50 /*****************************************************************************
51  * Public functions
52  ****************************************************************************/
53 
54 /* Initialize ring buffer */
RingBuffer_Init(RINGBUFF_T * RingBuff,void * buffer,int itemSize,int count)55 int RingBuffer_Init(RINGBUFF_T *RingBuff, void *buffer, int itemSize, int count)
56 {
57 	RingBuff->data = buffer;
58 	RingBuff->count = count;
59 	RingBuff->itemSz = itemSize;
60 	RingBuff->head = RingBuff->tail = 0;
61 
62 	return 1;
63 }
64 
65 /* Insert a single item into Ring Buffer */
RingBuffer_Insert(RINGBUFF_T * RingBuff,const void * data)66 int RingBuffer_Insert(RINGBUFF_T *RingBuff, const void *data)
67 {
68 	uint8_t *ptr = RingBuff->data;
69 
70 	/* We cannot insert when queue is full */
71 	if (RingBuffer_IsFull(RingBuff))
72 		return 0;
73 
74 	ptr += RB_INDH(RingBuff) * RingBuff->itemSz;
75 	memcpy(ptr, data, RingBuff->itemSz);
76 	RingBuff->head++;
77 
78 	return 1;
79 }
80 
81 /* Insert multiple items into Ring Buffer */
RingBuffer_InsertMult(RINGBUFF_T * RingBuff,const void * data,int num)82 int RingBuffer_InsertMult(RINGBUFF_T *RingBuff, const void *data, int num)
83 {
84 	uint8_t *ptr = RingBuff->data;
85 	int cnt1, cnt2;
86 
87 	/* We cannot insert when queue is full */
88 	if (RingBuffer_IsFull(RingBuff))
89 		return 0;
90 
91 	/* Calculate the segment lengths */
92 	cnt1 = cnt2 = RingBuffer_GetFree(RingBuff);
93 	if (RB_INDH(RingBuff) + cnt1 >= RingBuff->count)
94 		cnt1 = RingBuff->count - RB_INDH(RingBuff);
95 	cnt2 -= cnt1;
96 
97 	cnt1 = MIN(cnt1, num);
98 	num -= cnt1;
99 
100 	cnt2 = MIN(cnt2, num);
101 	num -= cnt2;
102 
103 	/* Write segment 1 */
104 	ptr += RB_INDH(RingBuff) * RingBuff->itemSz;
105 	memcpy(ptr, data, cnt1 * RingBuff->itemSz);
106 	RingBuff->head += cnt1;
107 
108 	/* Write segment 2 */
109 	ptr = (uint8_t *) RingBuff->data + RB_INDH(RingBuff) * RingBuff->itemSz;
110 	data = (const uint8_t *) data + cnt1 * RingBuff->itemSz;
111 	memcpy(ptr, data, cnt2 * RingBuff->itemSz);
112 	RingBuff->head += cnt2;
113 
114 	return cnt1 + cnt2;
115 }
116 
117 /* Pop single item from Ring Buffer */
RingBuffer_Pop(RINGBUFF_T * RingBuff,void * data)118 int RingBuffer_Pop(RINGBUFF_T *RingBuff, void *data)
119 {
120 	uint8_t *ptr = RingBuff->data;
121 
122 	/* We cannot pop when queue is empty */
123 	if (RingBuffer_IsEmpty(RingBuff))
124 		return 0;
125 
126 	ptr += RB_INDT(RingBuff) * RingBuff->itemSz;
127 	memcpy(data, ptr, RingBuff->itemSz);
128 	RingBuff->tail++;
129 
130 	return 1;
131 }
132 
133 /* Pop multiple items from Ring buffer */
RingBuffer_PopMult(RINGBUFF_T * RingBuff,void * data,int num)134 int RingBuffer_PopMult(RINGBUFF_T *RingBuff, void *data, int num)
135 {
136 	uint8_t *ptr = RingBuff->data;
137 	int cnt1, cnt2;
138 
139 	/* We cannot insert when queue is empty */
140 	if (RingBuffer_IsEmpty(RingBuff))
141 		return 0;
142 
143 	/* Calculate the segment lengths */
144 	cnt1 = cnt2 = RingBuffer_GetCount(RingBuff);
145 	if (RB_INDT(RingBuff) + cnt1 >= RingBuff->count)
146 		cnt1 = RingBuff->count - RB_INDT(RingBuff);
147 	cnt2 -= cnt1;
148 
149 	cnt1 = MIN(cnt1, num);
150 	num -= cnt1;
151 
152 	cnt2 = MIN(cnt2, num);
153 	num -= cnt2;
154 
155 	/* Write segment 1 */
156 	ptr += RB_INDT(RingBuff) * RingBuff->itemSz;
157 	memcpy(data, ptr, cnt1 * RingBuff->itemSz);
158 	RingBuff->tail += cnt1;
159 
160 	/* Write segment 2 */
161 	ptr = (uint8_t *) RingBuff->data + RB_INDT(RingBuff) * RingBuff->itemSz;
162 	data = (uint8_t *) data + cnt1 * RingBuff->itemSz;
163 	memcpy(data, ptr, cnt2 * RingBuff->itemSz);
164 	RingBuff->tail += cnt2;
165 
166 	return cnt1 + cnt2;
167 }
168