ringbuffer.c 8.5 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8
 *
 * Change Logs:
 * Date           Author       Notes
 * 2012-09-30     Bernard      first version.
9
 * 2013-05-08     Grissiom     reimplement
B
bernard 已提交
10
 * 2016-08-18     heyuanjie    add interface
11 12 13 14 15 16
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>

B
bernard 已提交
17 18 19 20 21 22 23 24 25 26 27 28
rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
{
    if (rb->read_index == rb->write_index)
    {
        if (rb->read_mirror == rb->write_mirror)
            return RT_RINGBUFFER_EMPTY;
        else
            return RT_RINGBUFFER_FULL;
    }
    return RT_RINGBUFFER_HALFFULL;
}

29 30
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
                        rt_uint8_t           *pool,
G
Grissiom 已提交
31
                        rt_int16_t            size)
32 33
{
    RT_ASSERT(rb != RT_NULL);
B
bernard 已提交
34
    RT_ASSERT(size > 0);
35 36

    /* initialize read and write index */
G
Grissiom 已提交
37 38
    rb->read_mirror = rb->read_index = 0;
    rb->write_mirror = rb->write_index = 0;
39 40 41 42 43 44 45

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

46 47 48
/**
 * put a block of data into ring buffer
 */
49 50 51 52 53
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
                            const rt_uint8_t     *ptr,
                            rt_uint16_t           length)
{
    rt_uint16_t size;
54

55 56 57
    RT_ASSERT(rb != RT_NULL);

    /* whether has enough space */
G
Grissiom 已提交
58
    size = rt_ringbuffer_space_len(rb);
59 60 61 62

    /* no space */
    if (size == 0)
        return 0;
G
Grissiom 已提交
63

64 65 66 67
    /* drop some data */
    if (size < length)
        length = size;

G
Grissiom 已提交
68
    if (rb->buffer_size - rb->write_index > length)
69 70
    {
        /* read_index - write_index = empty space */
G
Grissiom 已提交
71 72 73 74 75
        memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
        /* this should not cause overflow because there is enough space for
         * length of data in current mirror */
        rb->write_index += length;
        return length;
76
    }
G
Grissiom 已提交
77 78 79 80 81 82 83 84 85 86 87

    memcpy(&rb->buffer_ptr[rb->write_index],
           &ptr[0],
           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));

    /* we are going into the other side of the mirror */
    rb->write_mirror = ~rb->write_mirror;
    rb->write_index = length - (rb->buffer_size - rb->write_index);
88 89 90 91 92

    return length;
}
RTM_EXPORT(rt_ringbuffer_put);

93 94 95 96 97 98 99 100 101
/**
 * put a block of data into ring buffer
 *
 * When the buffer is full, it will discard the old data.
 */
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
                            const rt_uint8_t     *ptr,
                            rt_uint16_t           length)
{
102
    rt_uint16_t space_length;
103 104 105

    RT_ASSERT(rb != RT_NULL);

106
    space_length = rt_ringbuffer_space_len(rb);
107

还_没_想_好's avatar
还_没_想_好 已提交
108 109 110
    if (length > rb->buffer_size)
    {
        ptr = &ptr[length - rb->buffer_size];
111
        length = rb->buffer_size;
还_没_想_好's avatar
还_没_想_好 已提交
112
    }
113 114 115 116 117 118 119 120 121

    if (rb->buffer_size - rb->write_index > length)
    {
        /* read_index - write_index = empty space */
        memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
        /* this should not cause overflow because there is enough space for
         * length of data in current mirror */
        rb->write_index += length;

122
        if (length > space_length)
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
            rb->read_index = rb->write_index;

        return length;
    }

    memcpy(&rb->buffer_ptr[rb->write_index],
           &ptr[0],
           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));

    /* we are going into the other side of the mirror */
    rb->write_mirror = ~rb->write_mirror;
    rb->write_index = length - (rb->buffer_size - rb->write_index);

139
    if (length > space_length)
140 141 142 143 144 145 146 147 148
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = rb->write_index;
    }

    return length;
}
RTM_EXPORT(rt_ringbuffer_put_force);

149 150 151 152 153 154 155 156 157 158
/**
 *  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);
G
Grissiom 已提交
159

160
    /* whether has enough data  */
G
Grissiom 已提交
161
    size = rt_ringbuffer_data_len(rb);
162 163 164 165

    /* no data */
    if (size == 0)
        return 0;
G
Grissiom 已提交
166

167 168 169 170
    /* less data */
    if (size < length)
        length = size;

G
Grissiom 已提交
171
    if (rb->buffer_size - rb->read_index > length)
172 173
    {
        /* copy all of data */
G
Grissiom 已提交
174 175 176 177 178
        memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
        /* this should not cause overflow because there is enough space for
         * length of data in current mirror */
        rb->read_index += length;
        return length;
179
    }
G
Grissiom 已提交
180 181 182 183 184 185 186 187 188 189 190

    memcpy(&ptr[0],
           &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));

    /* we are going into the other side of the mirror */
    rb->read_mirror = ~rb->read_mirror;
    rb->read_index = length - (rb->buffer_size - rb->read_index);
191 192 193 194 195

    return length;
}
RTM_EXPORT(rt_ringbuffer_get);

196 197 198 199 200 201 202 203
/**
 * put a character into ring buffer
 */
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
    RT_ASSERT(rb != RT_NULL);

    /* whether has enough space */
G
Grissiom 已提交
204
    if (!rt_ringbuffer_space_len(rb))
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        return 0;

    rb->buffer_ptr[rb->write_index] = ch;

    /* flip mirror */
    if (rb->write_index == rb->buffer_size-1)
    {
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
    }
    else
    {
        rb->write_index++;
    }

    return 1;
}
RTM_EXPORT(rt_ringbuffer_putchar);

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
/**
 * put a character into ring buffer
 *
 * When the buffer is full, it will discard one old data.
 */
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
    enum rt_ringbuffer_state old_state;

    RT_ASSERT(rb != RT_NULL);

    old_state = rt_ringbuffer_status(rb);

    rb->buffer_ptr[rb->write_index] = ch;

    /* flip mirror */
    if (rb->write_index == rb->buffer_size-1)
    {
        rb->write_mirror = ~rb->write_mirror;
        rb->write_index = 0;
        if (old_state == RT_RINGBUFFER_FULL)
        {
            rb->read_mirror = ~rb->read_mirror;
            rb->read_index = rb->write_index;
        }
    }
    else
    {
        rb->write_index++;
        if (old_state == RT_RINGBUFFER_FULL)
            rb->read_index = rb->write_index;
    }

    return 1;
}
RTM_EXPORT(rt_ringbuffer_putchar_force);

261 262 263 264 265 266
/**
 * get a character from a ringbuffer
 */
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
    RT_ASSERT(rb != RT_NULL);
G
Grissiom 已提交
267

268
    /* ringbuffer is empty */
G
Grissiom 已提交
269
    if (!rt_ringbuffer_data_len(rb))
270 271 272
        return 0;

    /* put character */
G
Grissiom 已提交
273 274 275 276 277 278 279 280 281 282 283
    *ch = rb->buffer_ptr[rb->read_index];

    if (rb->read_index == rb->buffer_size-1)
    {
        rb->read_mirror = ~rb->read_mirror;
        rb->read_index = 0;
    }
    else
    {
        rb->read_index++;
    }
284 285 286 287

    return 1;
}
RTM_EXPORT(rt_ringbuffer_getchar);
288

B
bernard 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
/** 
 * get the size of data in rb 
 */
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{
    switch (rt_ringbuffer_status(rb))
    {
    case RT_RINGBUFFER_EMPTY:
        return 0;
    case RT_RINGBUFFER_FULL:
        return rb->buffer_size;
    case RT_RINGBUFFER_HALFFULL:
    default:
        if (rb->write_index > rb->read_index)
            return rb->write_index - rb->read_index;
        else
            return rb->buffer_size - (rb->read_index - rb->write_index);
    };
}
RTM_EXPORT(rt_ringbuffer_data_len);

/** 
 * empty the rb 
 */
void rt_ringbuffer_reset(struct rt_ringbuffer *rb)
{
    RT_ASSERT(rb != RT_NULL);

    rb->read_mirror = 0;
    rb->read_index = 0;
    rb->write_mirror = 0;
    rb->write_index = 0;
}
RTM_EXPORT(rt_ringbuffer_reset);

#ifdef RT_USING_HEAP

struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t size)
{
    struct rt_ringbuffer *rb;
    rt_uint8_t *pool;

	RT_ASSERT(size > 0);

    size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);

    rb = rt_malloc(sizeof(struct rt_ringbuffer));
    if (rb == RT_NULL)
        goto exit;

    pool = rt_malloc(size);
    if (pool == RT_NULL)
    {
        rt_free(rb);
        goto exit;
    }
    rt_ringbuffer_init(rb, pool, size);

exit:
    return rb;
}
RTM_EXPORT(rt_ringbuffer_create);

void rt_ringbuffer_destroy(struct rt_ringbuffer *rb)
{
    RT_ASSERT(rb != RT_NULL);

    rt_free(rb->buffer_ptr);
    rt_free(rb);
}
RTM_EXPORT(rt_ringbuffer_destroy);

#endif