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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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