LwRB latest-develop documentation

Welcome to the documentation for version latest-develop.

LwRB is a generic FIFO (First In; First Out) buffer library optimized for embedded systems.

_images/logo.svg

Features

  • Written in ANSI C99, compatible with size_t for size data types

  • Platform independent, no architecture specific code

  • FIFO (First In First Out) buffer implementation

  • No dynamic memory allocation, data is static array

  • Uses optimized memory copy instead of loops to read/write data from/to memory

  • Thread safe when used as pipe with single write and single read entries

  • Interrupt safe when used as pipe with single write and single read entries

  • Suitable for DMA transfers from and to memory with zero-copy overhead between buffer and application memory

  • Supports data peek, skip for read and advance for write

  • Implements support for event notifications

  • User friendly MIT license

Requirements

  • C compiler

  • Less than 1kB of non-volatile memory

Contribute

Fresh contributions are always welcome. Simple instructions to proceed:

  1. Fork Github repository

  2. Respect C style & coding rules used by the library

  3. Create a pull request to develop branch with new features or bug fixes

Alternatively you may:

  1. Report a bug

  2. Ask for a feature request

Example code

Minimalistic example code to read and write data to buffer

Example code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/* Buffer variables */
lwrb_t buff;                            /* Declare ring buffer structure */
uint8_t buff_data[8];                       /* Declare raw buffer data array */

/* Application variables */
uint8_t data[2];                            /* Application working data */
size_t len;

/* Application code ... */
lwrb_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */

/* Write 4 bytes of data */
lwrb_write(&buff, "0123", 4);

/* Try to read buffer */
/* len holds number of bytes read */
/* Read until len == 0, when buffer is empty */
while ((len = lwrb_read(&buff, data, sizeof(data))) > 0) {
    printf("Successfully read %d bytes\r\n", (int)len);
}

License

MIT License

Copyright (c) 2020 Tilen MAJERLE

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Table of contents

Getting started

Download library

Library is primarly hosted on Github.

  • Download latest release from releases area on Github

  • Clone develop branch for latest development

Download from releases

All releases are available on Github releases area.

Clone from Github
First-time clone
  • Download and install git if not already

  • Open console and navigate to path in the system to clone repository to. Use command cd your_path

  • Clone repository with one of available 3 options

    • Run git clone --recurse-submodules https://github.com/MaJerle/lwrb command to clone entire repository, including submodules

    • Run git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwrb to clone development branch, including submodules

    • Run git clone --recurse-submodules --branch master https://github.com/MaJerle/lwrb to clone latest stable branch, including submodules

  • Navigate to examples directory and run favourite example

Update cloned to latest version
  • Open console and navigate to path in the system where your resources repository is. Use command cd your_path

  • Run git pull origin master --recurse-submodules command to pull latest changes and to fetch latest changes from submodules

  • Run git submodule foreach git pull origin master to update & merge all submodules

Note

This is preferred option to use when you want to evaluate library and run prepared examples. Repository consists of multiple submodules which can be automatically downloaded when cloning and pulling changes from root repository.

Add library to project

At this point it is assumed that you have successfully download library, either cloned it or from releases page.

  • Copy lwrb folder to your project

  • Add lwrb/src/include folder to include path of your toolchain

  • Add source files from lwrb/src/ folder to toolchain build

  • Build the project

Minimal example code

Run below example to test and verify library

Minimal example code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include "lwrb/lwrb.h"

/* Buffer variables */
lwrb_t buff;                            /* Declare ring buffer structure */
uint8_t buff_data[8];                       /* Declare raw buffer data array */

/* Application variables
uint8_t data[2];                            /* Application working data */

/* Application code ... */
lwrb_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */

/* Write 4 bytes of data */
lwrb_write(&buff, "0123", 4);

/* Print number of bytes in buffer */
printf("Bytes in buffer: %d\r\n", (int)lwrb_get_full(&buff));

/* Will print "4" */

User manual

How it works

This section shows different buffer corner cases and provides basic understanding how data are managed internally.

Different buffer corner cases

Different buffer corner cases

Let’s start with reference of abbreviations in picture:

  • R represents Read pointer. Read on read/write operations. Modified on read operation only

  • W represents Write pointer. Read on read/write operations. Modified on write operation only

  • S represents Size of buffer. Used on all operations, never modified (atomic value)

    • Valid number of W and R pointers are between 0 and S - 1

  • Buffer size is S = 8, thus valid number range for W and R pointers is 0 - 7.

    • R and W numbers overflow at S, thus valid range is always 0, 1, 2, 3, ..., S - 2, S - 1, 0, 1, 2, 3, ..., S - 2, S - 1, 0, ...

    • Example S = 4: 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ...

  • Maximal number of bytes buffer can hold is always S - 1, thus example buffer can hold up to 7 bytes

  • R and W pointers always point to the next read/write operation

  • When W == R, buffer is considered empty.

  • When W == R - 1, buffer is considered full.

    • W == R - 1 is valid only if W and R overflow at buffer size S.

    • Always add S to calculated number and then use modulus S to get final value

Note

Example 1, add 2 numbers: 2 + 3 = (3 + 2 + S) % S = (3 + 2 + 4) % 4 = (5 + 4) % 4 = 1

Example 2, subtract 2 numbers: 2 - 3 = (2 - 3 + S) % S = (2 - 3 + 4) % 4 = (-1 + 4) % 4 = 3

Different buffer corner cases

Different buffer corner cases

Different image cases:

  • Case A: Buffer is empty as W == R = 0 == 0

  • Case B: Buffer holds W - R = 4 - 0 = 4 bytes as W > R

  • Case C: Buffer is full as W == R - 1 or 7 == 0 - 1 or 7 = (0 - 1 + S) % S = (0 - 1 + 8) % 8 = (-1 + 8) % 8 = 7

    • R and W can hold S different values, from 0 to S - 1, that is modulus of S

    • Buffer holds W - R = 7 - 0 = 7 bytes as W > R

  • Case D: Buffer holds S - (R - W) = 8 - (5 - 3) = 6 bytes as R > W

  • Case E: Buffer is full as W == R - 1 (4 = 5 - 1) and holds S - (R - W) = 8 - (5 - 4) ) = 7 bytes

Events

When using LwRB in the application, it may be useful to get notification on different events, such as info when something has been written or read to/from buffer.

Library has support for events that get called each time there has been a modification in the buffer data, that means on every read or write operation.

Some use cases:

  • Notify application layer that LwRB operation has been executed and send debug message

  • Unlock semaphore when sufficient amount of bytes have been written/read from/to buffer when application uses operating system

  • Write notification to message queue at operating system level to wakeup another task

Note

Every operation that modified read or write internal pointers, is considered as read or write operation. An exception is reset event that sets both internal pointers to 0

Example code for events
 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
/**
 * \brief           Buffer event function
 */
void
my_buff_evt_fn(lwrb_t* buff, lwrb_evt_type_t type, size_t len) {
    switch (type) {
        case LWRB_EVT_RESET:
            printf("[EVT] Buffer reset event!\r\n");
            break;
        case LWRB_EVT_READ:
            printf("[EVT] Buffer read event: %d byte(s)!\r\n", (int)len);
            break;
        case LWRB_EVT_WRITE:
            printf("[EVT] Buffer write event: %d byte(s)!\r\n", (int)len);
            break;
        default: break;
    }
}

/* Later in the code... */
lwrb_t buff;
uint8_t buff_data[8];

/* Init buffer and set event function */
lwrb_init(&buff, buff_data, sizeof(buff_data));
lwrb_set_evt_fn(&buff, my_buff_evt_fn);

DMA on embedded systems

One of the key features of LwRB library is that it can be seamlessly integrated with DMA controllers on embedded systems.

Note

DMA stands for Direct Memory Access controller and is usually used to off-load CPU. More about DMA is available on Wikipedia.

DMA controllers normally use source and destination memory addresses to transfer data in-between. This features, together with LwRB, allows seamless integration and zero-copy of application data at interrupts after DMA transfer has been completed. Some manual work is necessary to be handled, but this is very minor in comparison of writing byte-by-byte to buffer at (for example) each received character.

Below are 2 common use cases:

  • DMA transfers data from LwRB memory to (usually) some hardware IP

  • DMA transfers data from hardware IP to memory

Zero-copy data from memory

This describes how to pass LwRB output memory address as pointer to DMA (or any other processing function). After all the data are successfully processed, application can skip processed data and free buff for new data being written to it.

Data transfer from memory to hardware IP

Data transfer from memory to hardware IP

  • Case A: Initial state, buffer is full and holds 7 bytes

  • Case B: State after skipping R pointer for 3 bytes. Buffer now holds 4 remaining bytes

  • Case C: Buffer is empty, no more memory available for read operation

Code example:

Skip buffer data after usage
 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

#include "lwrb/lwrb.h"

/* Declare buffer variables */
lwrb_t buff;
uint8_t buff_data[8];

size_t len;
uint8_t* data;

/* Initialize buffer, use buff_data as data array */
lwrb_init(&buff, buff_data, sizeof(buff_data));

/* Use write, read operations, process data */
/* ... */

/* IMAGE PART A */

/* At this stage, we have buffer as on image above */
/* R = 5, W = 4, buffer is considered full */

/* Get length of linear memory at read pointer */
/* Function returns 3 as we can read 3 bytes from buffer in sequence */
/* When function returns 0, there is no memory available in the buffer for read anymore */
if ((len = lwrb_get_linear_block_read_length(&buff)) > 0) {
    /* Get pointer to first element in linear block at read address */
    /* Function returns &buff_data[5] */
    data = lwrb_get_linear_block_read_address(&buff);

    /* Send data via DMA and wait to finish (for sake of example) */
    send_data(data, len);

    /* Now skip sent bytes from buffer = move read pointer */
    lwrb_skip(&buff, len);

    /* Now R points to top of buffer, R = 0 */
    /* At this point, we are at image part B */
}

/* IMAGE PART B */

/* Get length of linear memory at read pointer */
/* Function returns 4 as we can read 4 bytes from buffer in sequence */
/* When function returns 0, there is no memory available in the buffer for read anymore */
if ((len = lwrb_get_linear_block_read_length(&buff)) > 0) {
    /* Get pointer to first element in linear block at read address */
    /* Function returns &buff_data[0] */
    data = lwrb_get_linear_block_read_address(&buff);

    /* Send data via DMA and wait to finish (for sake of example) */
    send_data(data, len);

    /* Now skip sent bytes from buffer = move read pointer */
    /* Read pointer is moved for len bytes */
    lwrb_skip(&buff, len);

    /* Now R points to 4, that is R == W and buffer is now empty */
    /* At this point, we are at image part C */
}

/* IMAGE PART C */

/* Buffer is considered empty as R == W */

Part A on image clearly shows that not all data bytes are linked in single contiguous block of memory. To send all bytes from lwrb, it might be necessary to repeat procedure multiple times

Skip buffer data for non-contiguous block
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/* Initialization part skipped */

/* Get length of linear memory at read pointer */
/* When function returns 0, there is no memory available in the buffer for read anymore */
while ((len = lwrb_get_linear_block_read_length(&buff)) > 0) {
    /* Get pointer to first element in linear block at read address */
    data = lwrb_get_linear_block_read_address(&buff);

    /* If max length needs to be considered */
    /* simply decrease it and use smaller len on skip function */
    if (len > max_len) {
        len = max_len;
    }

    /* Send data via DMA and wait to finish (for sake of example) */
    send_data(data, len);

    /* Now skip sent bytes from buffer = move read pointer */
    lwrb_skip(&buff, len);
}
Zero-copy data to memory

Similar to reading data from buffer with zero-copy overhead, it is possible to write to lwrb with zero-copy overhead too. Only difference is that application now needs pointer to write memory address and length of maximal number of bytes to directly copy in buffer. After processing is successful, buffer advance operation is necessary to manually increase write pointer and to increase number of bytes in buffer.

Data transfer from memory to hardware IP
  • Case A: Initial state, buffer is empty as R == W

    • Based on W pointer position, application could write 4 bytes to contiguous block of memory

  • Case B: State after advancing W pointer for 4 bytes. Buffer now holds 4 bytes and has 3 remaining available

  • Case C: Buffer is full, no more free memory available for write operation

Code example:

Advance buffer pointer for manually written bytes
 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
/* Declare buffer variables */
lwrb_t buff;
uint8_t buff_data[8];

size_t len;
uint8_t* data;

/* Initialize buffer, use buff_data as data array */
lwrb_init(&buff, buff_data, sizeof(buff_data));

/* Use write, read operations, process data */
/* ... */

/* IMAGE PART A */

/* At this stage, we have buffer as on image above */
/* R = 4, W = 4, buffer is considered empty */

/* Get length of linear memory at write pointer */
/* Function returns 4 as we can write 4 bytes to buffer in sequence */
/* When function returns 0, there is no memory available in the buffer for write anymore */
if ((len = lwrb_get_linear_block_write_length(&buff)) > 0) {
    /* Get pointer to first element in linear block at write address */
    /* Function returns &buff_data[4] */
    data = lwrb_get_linear_block_write_address(&buff);

    /* Receive data via DMA and wait to finish (for sake of example) */
    /* Any other hardware may directly write to data array */
    /* Data array has len bytes length */
    /* Or use memcpy(data, my_array, len); */
    receive_data(data, len);

    /* Now advance buffer for written bytes to buffer = move write pointer */
    /* Write pointer is moved for len bytes */
    lwrb_advance(&buff, len);

    /* Now W points to top of buffer, W = 0 */
    /* At this point, we are at image part B */
}

/* IMAGE PART B */

/* Get length of linear memory at write pointer */
/* Function returns 3 as we can write 3 bytes to buffer in sequence */
/* When function returns 0, there is no memory available in the buffer for write anymore */
if ((len = lwrb_get_linear_block_read_length(&buff)) > 0) {
    /* Get pointer to first element in linear block at write address */
    /* Function returns &buff_data[0] */
    data = lwrb_get_linear_block_read_address(&buff);

    /* Receive data via DMA and wait to finish (for sake of example) */
    /* Any other hardware may directly write to data array */
    /* Data array has len bytes length */
    /* Or use memcpy(data, my_array, len); */
    receive_data(data, len);

    /* Now advance buffer for written bytes to buffer = move write pointer */
    /* Write pointer is moved for len bytes */
    lwrb_advance(&buff, len);

    /* Now W points to 3, R points to 4, that is R == W + 1 and buffer is now full */
    /* At this point, we are at image part C */
}

/* IMAGE PART C */

/* Buffer is considered full as R == W + 1 */
Example for DMA transfer from memory

This is an example showing pseudo code for implementing data transfer using DMA with zero-copy overhead. For read operation purposes, application gets direct access to LwRB read pointer and length of contigouos memory.

It is assumed that after DMA transfer completes, interrupt is generated (embedded system) and buffer is skipped in the interrupt.

Note

Buffer skip operation is used to mark sent data as processed and to free memory for new writes to buffer

DMA usage with buffer
 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
/* Buffer */
lwrb_t buff;
uint8_t buff_data[8];

/* Working data length */
size_t len;

/* Send data function */
void send_data(void);

int
main(void) {
    /* Initialize buffer */
    lwrb_init(&buff, buff_data, sizeof(buff_data));

    /* Write 4 bytes of data */
    lwrb_write(&buff, "0123", 4);

    /* Send data over DMA */
    send_data();

    while (1);
}

/* Send data over DMA */
void
send_data(void) {
    /* If len > 0, DMA transfer is on-going */
    if (len > 0) {
        return;
    }

    /* Get maximal length of buffer to read data as linear memory */
    len = lwrb_get_linear_block_read_length(&buff);
    if (len > 0) {
        /* Get pointer to read memory */
        uint8_t* data = lwrb_get_linear_block_read_address(&buff);

        /* Start DMA transfer */
        start_dma_transfer(data, len);
    }

    /* Function does not wait for transfer to finish */
}

/* Interrupt handler */
/* Called on DMA transfer finish */
void
DMA_Interrupt_handler(void) {
    /* Transfer finished */
    if (len > 0) {
        /* Now skip the data (move read pointer) as they were successfully transferred over DMA */
        lwrb_skip(&buff, len);

        /* Reset length = DMA is not active */
        len = 0;

        /* Try to send more */
        send_data();
    }
}

Tip

Check STM32 UART DMA TX RX Github repository for use cases.

Tips & tricks

Application buffer size

Buffer size shall always be 1 byte bigger than anticipated data size.

When application uses buffer for some data block N times, it is advised to set buffer size to 1 byte more than N * block_size is. This is due to R and W pointers alignment.

Note

For more information, check How it works.

Application buffer size assignment
 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
#include "lwrb/lwrb.h"

/* Number of data blocks to write */
#define N          3

/* Create custom data structure */
/* Data is array of 2 32-bit words, 8-bytes */
uint32_t d[2];

/* Create buffer structures */
lwrb_t buff_1;
lwrb_t buff_2;

/* Create data for buffers. Use sizeof structure, multiplied by N (for N instances) */
/* Buffer with + 1 bytes bigger memory */
uint8_t buff_data_1[sizeof(d) * N + 1];
/* Buffer without + 1 at the end */
uint8_t buff_data_2[sizeof(d) * N];

/* Write result values */
size_t len_1;
size_t len_2;

/* Initialize buffers */
lwrb_init(&buff_1, buff_data_1, sizeof(buff_data_1));
lwrb_init(&buff_2, buff_data_2, sizeof(buff_data_2));

/* Write data to buffer */
for (size_t i = 0; i < N; ++i) {
    /* Prepare data */
    d.a = i;
    d.b = i * 2;

    /* Write data to both buffers, memory copy from d to buffer */
    len_1 = lwrb_write(&buff_1, d, sizeof(d));
    len_2 = lwrb_write(&buff_2, d, sizeof(d));

    /* Print results */
    printf("Write buffer 1: %d/%d bytes; buffer 2: %d/%d\r\n",
        (int)len_1, (int)sizeof(d),
        (int)len_2, (int)sizeof(d));
}

When the code is executed, it produces following output:

Application buffer size assignment output
Write: buffer 1: 8/8; buffer 2: 8/8
Write: buffer 1: 8/8; buffer 2: 8/8
Write: buffer 1: 8/8; buffer 2: 7/8 <-- See here -->

API reference

List of all the modules:

LwRB

group LWRB

Lightweight ring buffer manager.

Defines

LWRB_VOLATILE

Enable buffer structure pointer parameter as volatile To use this feature, uncomment keyword below.

LWRB_USE_MAGIC

Adds 2 magic words to make sure if memory is corrupted application can detect wrong data pointer and maximum size.

Typedefs

void(* lwrb_evt_fn )(LWRB_VOLATILE struct lwrb *buff, lwrb_evt_type_t evt, size_t bp)

Event callback function type.

Parameters
  • [in] buff: Buffer handle for event

  • [in] evt: Event type

  • [in] bp: Number of bytes written or read (when used), depends on event type

Enums

enum lwrb_evt_type_t

Event type for buffer operations.

Values:

enumerator LWRB_EVT_READ

Read event

enumerator LWRB_EVT_WRITE

Write event

enumerator LWRB_EVT_RESET

Reset event

Functions

uint8_t lwrb_init (LWRB_VOLATILE lwrb_t *buff, void *buffdata, size_t size)

Initialize buffer handle to default values with size and buffer data array.

Return

1 on success, 0 otherwise

Parameters
  • [in] buff: Buffer handle

  • [in] buffdata: Pointer to memory to use as buffer data

  • [in] size: Size of buffdata in units of bytes Maximum number of bytes buffer can hold is size - 1

uint8_t lwrb_is_ready (LWRB_VOLATILE lwrb_t *buff)

Check if buff is initialized and ready to use.

Return

1 if ready, 0 otherwise

Parameters
  • [in] buff: Buffer handle

void lwrb_free (LWRB_VOLATILE lwrb_t *buff)

Free buffer memory.

Note

Since implementation does not use dynamic allocation, it just sets buffer handle to NULL

Parameters
  • [in] buff: Buffer handle

void lwrb_reset (LWRB_VOLATILE lwrb_t *buff)

Resets buffer to default values. Buffer size is not modified.

Parameters
  • [in] buff: Buffer handle

void lwrb_set_evt_fn (LWRB_VOLATILE lwrb_t *buff, lwrb_evt_fn fn)

Set event function callback for different buffer operations.

Parameters
  • [in] buff: Buffer handle

  • [in] evt_fn: Callback function

size_t lwrb_write (LWRB_VOLATILE lwrb_t *buff, const void *data, size_t btw)

Write data to buffer. Copies data from data array to buffer and marks buffer as full for maximum btw number of bytes.

Return

Number of bytes written to buffer. When returned value is less than btw, there was no enough memory available to copy full data array

Parameters
  • [in] buff: Buffer handle

  • [in] data: Pointer to data to write into buffer

  • [in] btw: Number of bytes to write

size_t lwrb_read (LWRB_VOLATILE lwrb_t *buff, void *data, size_t btr)

Read data from buffer. Copies data from buffer to data array and marks buffer as free for maximum btr number of bytes.

Return

Number of bytes read and copied to data array

Parameters
  • [in] buff: Buffer handle

  • [out] data: Pointer to output memory to copy buffer data to

  • [in] btr: Number of bytes to read

size_t lwrb_peek (LWRB_VOLATILE lwrb_t *buff, size_t skip_count, void *data, size_t btp)

Read from buffer without changing read pointer (peek only)

Return

Number of bytes peeked and written to output array

Parameters
  • [in] buff: Buffer handle

  • [in] skip_count: Number of bytes to skip before reading data

  • [out] data: Pointer to output memory to copy buffer data to

  • [in] btp: Number of bytes to peek

size_t lwrb_get_free (LWRB_VOLATILE lwrb_t *buff)

Get available size in buffer for write operation.

Return

Number of free bytes in memory

Parameters
  • [in] buff: Buffer handle

size_t lwrb_get_full (LWRB_VOLATILE lwrb_t *buff)

Get number of bytes currently available in buffer.

Return

Number of bytes ready to be read

Parameters
  • [in] buff: Buffer handle

void * lwrb_get_linear_block_read_address (LWRB_VOLATILE lwrb_t *buff)

Get linear address for buffer for fast read.

Return

Linear buffer start address

Parameters
  • [in] buff: Buffer handle

size_t lwrb_get_linear_block_read_length (LWRB_VOLATILE lwrb_t *buff)

Get length of linear block address before it overflows for read operation.

Return

Linear buffer size in units of bytes for read operation

Parameters
  • [in] buff: Buffer handle

size_t lwrb_skip (LWRB_VOLATILE lwrb_t *buff, size_t len)

Skip (ignore; advance read pointer) buffer data Marks data as read in the buffer and increases free memory for up to len bytes.

Note

Useful at the end of streaming transfer such as DMA

Return

Number of bytes skipped

Parameters
  • [in] buff: Buffer handle

  • [in] len: Number of bytes to skip and mark as read

void * lwrb_get_linear_block_write_address (LWRB_VOLATILE lwrb_t *buff)

Get linear address for buffer for fast read.

Return

Linear buffer start address

Parameters
  • [in] buff: Buffer handle

size_t lwrb_get_linear_block_write_length (LWRB_VOLATILE lwrb_t *buff)

Get length of linear block address before it overflows for write operation.

Return

Linear buffer size in units of bytes for write operation

Parameters
  • [in] buff: Buffer handle

size_t lwrb_advance (LWRB_VOLATILE lwrb_t *buff, size_t len)

Advance write pointer in the buffer. Similar to skip function but modifies write pointer instead of read.

Note

Useful when hardware is writing to buffer and application needs to increase number of bytes written to buffer by hardware

Return

Number of bytes advanced for write operation

Parameters
  • [in] buff: Buffer handle

  • [in] len: Number of bytes to advance

struct lwrb_t
#include <lwrb.h>

Buffer structure.

Public Members

uint32_t magic1

Magic 1 word

uint8_t *buff

Pointer to buffer data. Buffer is considered initialized when buff != NULL and size > 0

size_t size

Size of buffer data. Size of actual buffer is 1 byte less than value holds

size_t r

Next read pointer. Buffer is considered empty when r == w and full when w == r - 1

size_t w

Next write pointer. Buffer is considered empty when r == w and full when w == r - 1

lwrb_evt_fn evt_fn

Pointer to event callback function

uint32_t magic2

Magic 2 word