代码来源silicon labs的sdk。
一 源码
app_queue.h
#ifndef APP_QUEUE_H
#define APP_QUEUE_H
#include <stdint.h>
#include <stdbool.h>
typedef enum{
QUEUE_STATUS_OK, /**< successful. */
QUEUE_STATUS_NULL_POINTER, /**< Invalid pointer. */
QUEUE_STATUS_NOT_INITIALIZED, /**< not initialized. */
QUEUE_STATUS_WOULD_OVERFLOW, /**< Queue would overflow. */
QUEUE_STATUS_EMPTY, /**< queue is empty. */
}queue_status_t;
//Implement critical protection according to the platform
#define CORE_DECLARE_IRQ_STATE
#define CORE_ENTER_CRITICAL()
#define CORE_EXIT_CRITICAL()
// -----------------------------------------------------------------------------
// Structures and Types
/// Application Queue pointer type forward declaration
typedef struct app_queue *app_queue_ptr_t;
/***************************************************************************//**
* Prototype of queue overflow callback function.
*
* @param[in] queue Pointer to the queue structure being overflowed.
* @param[in] data Pointer to the item being considered for removal from
* the queue on overflow.
*
* @retval true Discard the queue item being considered for removal
* (default behavior).
* @retval false Nothing to be discarded from the queue.
******************************************************************************/
typedef bool (*app_queue_overflow_callback_t)(app_queue_ptr_t queue, \
uint8_t *data);
/// Application Queue structure
typedef struct app_queue {
uint16_t head; ///< Head position
uint16_t count; ///< Count of items in the list
uint16_t size; ///< Size of the queue
uint16_t item_size; ///< Size of one queue item
app_queue_overflow_callback_t callback; ///< Overflow callback
uint8_t *data; ///< Data storage for the queue
} app_queue_t;
/***************************************************************************//**
* Static allocation macro
*
* @param[in] HANDLE Handle name of the queue.
* @param[in] TYPE Base element type of the queue
* @param[in] SIZE Requested size of the queue in elements.
******************************************************************************/
#define APP_QUEUE(HANDLE, TYPE, SIZE) \
app_queue_t HANDLE; \
static TYPE HANDLE##_data[SIZE]
/***************************************************************************//**
* Initialization macro
*
* @param[in] HANDLE Handle name of the queue.
* @param[in] TYPE Base element type of the queue
* @param[in] SIZE Requested size of the queue in elements.
*
* @retval QUEUE_STATUS_OK Initialization was successful.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
******************************************************************************/
#define APP_QUEUE_INIT(HANDLE, TYPE, SIZE) \
app_queue_init(HANDLE, SIZE, sizeof(TYPE), (void *)HANDLE##_data)
// -----------------------------------------------------------------------------
// Queue Functions
/***************************************************************************//**
* Initialize the queue.
*
* @param[in] queue Pointer to the queue structure to initialize.
* @param[in] size The number of entries to store in this queue
* @param[in] item_size The size of a queue element.
* @param[in] data Pointer to the data storage.
*
* @retval QUEUE_STATUS_OK Initialization was successful.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
******************************************************************************/
queue_status_t app_queue_init(app_queue_t *queue,
uint16_t size,
uint16_t item_size,
uint8_t *data);
/***************************************************************************//**
* Add item to the end of the queue.
*
* If the queue is full, the oldest queued item will be replaced by default.
* Register an overflow callback to change this default behavior.
*
* @param[in] queue The queue to add the item to.
* @param[in] data The pointer object to store in the queue.
*
* @retval QUEUE_STATUS_OK Adding item was successful.
* @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
* @retval QUEUE_STATUS_WOULD_OVERFLOW Queue would overflow and the overflow event
* was not handled.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
******************************************************************************/
queue_status_t app_queue_add(app_queue_t *queue, uint8_t *data);
/***************************************************************************//**
* Specify a callback to be called upon queue overflow.
*
* The oldest queued item being considered for removal on queue overflow is
* provided by this callback.
*
* @param[in] queue The queue to specify an overflow callback for.
* @param[in] callback The callback to be called on queue overflow. If callback
* is NULL, no callback will be issued on queue overflow.
*
* @retval QUEUE_STATUS_OK Setting callback was successful.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue is invalid.
******************************************************************************/
queue_status_t app_queue_set_overflow_callback(app_queue_t *queue,
app_queue_overflow_callback_t callback);
/***************************************************************************//**
* Get a pointer to the head of the queue without removing that item.
*
* @param[in] queue The queue to peek at the item from.
* @param[out] data Data output for the item to copy into.
*
* @retval QUEUE_STATUS_OK Getting item was successful.
* @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
* @retval QUEUE_STATUS_EMPTY Queue is empty.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
******************************************************************************/
queue_status_t app_queue_peek(app_queue_t *queue, uint8_t *data);
/***************************************************************************//**
* Remove an item from the head of the queue and return its data pointer.
*
* @param[in] queue The queue to remove the item from.
* @param[out] data Data output for the item to copy into.
*
* @retval QUEUE_STATUS_OK Removing item was successful.
* @retval QUEUE_STATUS_NOT_INITIALIZED Queue was not initialized.
* @retval QUEUE_STATUS_EMPTY Queue is empty.
* @retval QUEUE_STATUS_NULL_POINTER Pointer to the queue or data is invalid.
******************************************************************************/
queue_status_t app_queue_remove(app_queue_t *queue, uint8_t *data);
/***************************************************************************//**
* Determine if the given queue is empty.
*
* @param[in] queue The queue to check the status of.
*
* @return True, if the queue is empty.
******************************************************************************/
bool app_queue_is_empty(app_queue_t *queue);
/***************************************************************************//**
* Determine if the given queue is full.
*
* @param[in] queue The queue to check the status of.
*
* @return True, if the queue is full.
******************************************************************************/
bool app_queue_is_full(app_queue_t *queue);
#endif // APP_QUEUE_H
app_queue.c
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "app_queue.h"
// -----------------------------------------------------------------------------
// Public functions
queue_status_t app_queue_init(app_queue_t *queue,
uint16_t size,
uint16_t item_size,
uint8_t *data)
{
if (queue == NULL || data == NULL) {
return QUEUE_STATUS_NULL_POINTER;
}
// Atomically initialize the queue structure
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
queue->item_size = item_size;
queue->data = data;
queue->size = size;
queue->head = 0;
queue->count = 0;
queue->callback = NULL;
CORE_EXIT_CRITICAL();
return QUEUE_STATUS_OK;
}
queue_status_t app_queue_set_overflow_callback(app_queue_t *queue,
app_queue_overflow_callback_t callback)
{
if (queue == NULL) {
return QUEUE_STATUS_NULL_POINTER;
}
queue->callback = callback;
return QUEUE_STATUS_OK;
}
queue_status_t app_queue_add(app_queue_t *queue, uint8_t *data)
{
queue_status_t sc = QUEUE_STATUS_OK;
bool added = false;
// Do nothing if there's no queue or data given
if (queue == NULL || data == NULL) {
return QUEUE_STATUS_NULL_POINTER;
}
if (queue->data == NULL) {
return QUEUE_STATUS_NOT_INITIALIZED;
}
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
if (queue->count < queue->size) {
uint16_t offset = (queue->head + queue->count) % queue->size;
// Insert this item at the end of the queue
uint8_t *ptr = queue->data + (offset * queue->item_size);
memcpy(ptr, data, queue->item_size);
queue->count++;
added = true;
} else {
// If an overflow callback exists, call it to see if the oldest queued
// item is to be replaced (default) or not.
uint8_t *ptr = (queue->data + (queue->head * queue->item_size));
if (queue->callback != NULL) {
added = queue->callback(queue, ptr);
} else {
// There is no callback set, queue would overflow
sc = QUEUE_STATUS_WOULD_OVERFLOW;
}
// Overwrite what's at the head of the queue since we're out of space
if (added) {
memcpy(ptr, data, queue->item_size);
queue->head = (queue->head + 1) % queue->size;
}
}
CORE_EXIT_CRITICAL();
return sc;
}
queue_status_t app_queue_peek(app_queue_t *queue, uint8_t * data)
{
queue_status_t sc = QUEUE_STATUS_OK;
uint8_t *ptr = NULL;
// Do nothing if there's no queue or data given
if (queue == NULL || data == NULL) {
return QUEUE_STATUS_NULL_POINTER;
}
if (queue->data == NULL) {
return QUEUE_STATUS_NOT_INITIALIZED;
}
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
if (queue->count > 0) {
ptr = (queue->data + (queue->head * queue->item_size));
memcpy(data, ptr, queue->item_size);
} else {
sc = QUEUE_STATUS_EMPTY;
}
CORE_EXIT_CRITICAL();
return sc;
}
queue_status_t app_queue_remove(app_queue_t *queue, uint8_t * data)
{
queue_status_t sc = QUEUE_STATUS_OK;
uint8_t *ptr = NULL;
// Do nothing if there's no queue or data given
if (queue == NULL || data == NULL) {
return QUEUE_STATUS_NULL_POINTER;
}
if (queue->data == NULL) {
return QUEUE_STATUS_NOT_INITIALIZED;
}
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
if (queue->count > 0) {
ptr = (queue->data + queue->head * queue->item_size);
memcpy(data, ptr, queue->item_size);
queue->head = (queue->head + 1) % queue->size;
queue->count--;
} else {
sc = QUEUE_STATUS_EMPTY;
}
CORE_EXIT_CRITICAL();
return sc;
}
bool app_queue_is_empty(app_queue_t *queue)
{
bool result;
// Do nothing if there's no queue or output given
if (queue == NULL) {
return true;
}
if (queue->data == NULL) {
return true;
}
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
result = (queue->count == 0);
CORE_EXIT_CRITICAL();
return result;
}
bool app_queue_is_full(app_queue_t *queue)
{
bool result;
// Do nothing if there's no queue or output given
if (queue == NULL) {
return false;
}
if (queue->data == NULL) {
return false;
}
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
result = (queue->count == queue->size);
CORE_EXIT_CRITICAL();
return result;
}
二 用法
unit_test.h
#include <stdint.h>
typedef struct __attribute__((__packed__))
{
uint16_t size;
uint8_t age;
}unit_payload_t;
void unit_init_queue(void);
void unit_print_queue(void);
unit_test.c
#include "app_queue.h"
#include "unit.h"
#include "app_log.h"
#define UNIT_QUEUE_SIZE 5
//定义了一个队列,名字为unit_queue, 队列中存放的数据类型为unit_payload_t,一共可以存放UNIT_QUEUE_SIZE
APP_QUEUE(unit_queue, unit_payload_t, UNIT_QUEUE_SIZE);
app_queue_t* p_unit_queue = &unit_queue;
//队列溢出时处理方法,返回true表示覆盖最早的数据,返回false表示不覆盖
bool unit_queue_overflow_callback(app_queue_ptr_t queue, uint8_t *data)
{
(void)queue;
(void)data;
return true;
}
//初始化队列
void unit_init_queue(void)
{
APP_QUEUE_INIT(&unit_queue, unit_payload_t, UNIT_QUEUE_SIZE);
//设置队列的溢出回调函数
app_queue_set_overflow_callback(p_unit_queue, unit_queue_overflow_callback);
//给队列赋值
for(int i = 0; i < 6; i++){
unit_payload_t payload;
payload.size = i;
payload.age = i * 10;
app_queue_add(p_unit_queue, (uint8_t*)&payload);
}
}
void unit_print_queue(void)
{
while(app_queue_is_empty(p_unit_queue) == false){
unit_payload_t payload;
if(app_queue_remove(p_unit_queue, (uint8_t*)&payload) == SL_STATUS_OK){
app_log_debug("size: %d, age: %d\n", payload.size, payload.age);
}else{
app_log_debug("queue remote failed\n");
}
}
}
main.c
void main(void)
{
unit_init_queue();
unit_print_queue();
}
打印结果:
size: 1, age: 10
size: 2, age: 20
size: 3, age: 30
size: 4, age: 40
size: 5, age: 50
如果函数unit_queue_overflow_callback返回false,打印结果为
size: 0, age: 0
size: 1, age: 10
size: 2, age: 20
size: 3, age: 30
size: 4, age: 40