zephyr/subsys/bluetooth/controller/util/dbuf.h
Piotr Pryga f23fa86449 Bluetooth: Controller: util: Add generic double buffer implementation
There are multiple places where double buffer is used in controlers
code. This commit adds generic implementation of the double buffer.
It can be used in future in all places where the data structure is
in use.

Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
2022-01-04 09:10:05 -05:00

108 lines
3.1 KiB
C

/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Generic double buffer data structure header.
*
* The structure may be used as a header for any kind of data structure that requires
* double buffering.
*/
struct dbuf_hdr {
/* The current element that is in use. */
uint8_t volatile first;
/* Last enqueued element. It will be used after buffer is swapped. */
uint8_t last;
/* Size in a bytes of a single element stored in double buffer. */
uint8_t elem_size;
/* Pointer for actual buffer memory. Its size should be 2 times @p elem_size. */
uint8_t data[0];
};
/**
* @brief Allocate element in double buffer.
*
* The function provides pointer to new element that may be modified by the user.
* For consecutive calls it always returns the same pointer until buffer is swapped
* by dbuf_latest_get operation.
*
* @param hdr Pointer to double buffer header.
* @param idx Pointer to return new element index.
*
* @return Pointer to new element memory.
*/
void *dbuf_alloc(struct dbuf_hdr *hdr, uint8_t *idx);
/**
* @brief Provides pointer to last allocated element.
*
* If it is called before dbuf_alloc it will return pointer to memory that was recently
* enqueued.
*
* @param hdr Pointer to double buffer header.
*
* @return Pointer to last allocated element.
*/
static inline void *dbuf_peek(struct dbuf_hdr *hdr)
{
return &hdr->data[hdr->last * hdr->elem_size];
}
/**
* @brief Enqueue new element for buffer swap.
*
* @param hdr Pointer to double buffer header.
* @param idx Intex of element to be swapped.
*/
static inline void dbuf_enqueue(struct dbuf_hdr *hdr, uint8_t idx)
{
hdr->last = idx;
}
/**
* @brief Get latest element in buffer.
*
* Latest enqueued element is pointed by last member of dbuf_hdr.
* If it points to a different index than member first, then buffer will be
* swapped and @p is_modified will be set to true.
*
* Pointer to lates element is returned.
*
* @param[in] hdr Pointer to double buffer header.
* @param[out] is_modifled Pointer to return information if buffer was swapped.
*
* @return Pointer to latest enqueued buffer element.
*/
void *dbuf_latest_get(struct dbuf_hdr *hdr, uint8_t *is_modified);
/**
* @brief Retruns pointer to the current element, the one after last swap operation.
*
* The function provides access to element that is pointed by member first of dbuf_hrd.
* Returned value always points to latest one, that was swapped after most recent call to
* dbuf_latest_get. The pointer will be the same as the one pointed by last if the dbuf_alloc
* is not called after last dbuf_latest_get call.
*
* @param hdr Pointer to double buffer header.
* @return Pointer to element after last buffer swap.
*/
static inline void *dbuf_curr_get(struct dbuf_hdr *hdr)
{
return &hdr->data[hdr->first * hdr->elem_size];
}
/**
* @brief Return information whether new element was enqueued to a buffer.
*
* @param hdr Pointer to double buffer header.
*
* @return True if there were new element enqueued, false in other case.
*/
static inline bool dbuf_is_modified(const struct dbuf_hdr *hdr)
{
return hdr->first != hdr->last;
}