Files
templates/c/set-protocol/include/pcan_ring.h

72 lines
2.7 KiB
C

/**
* @file pcan_ring.h
* @brief Кольцевой буфер байтов: один писатель, один читатель.
*
* Размер обязан быть степенью двойки - индексы сворачиваются маской,
* поэтому head/tail обновляются одной записью и блокировки между
* фоновым кодом и обработчиком прерывания не нужны.
*
* Отдельно есть pcan_ring_linear(): отдаёт непрерывный участок данных
* без заворота - именно то, что требуется, чтобы отдать кусок в DMA.
*/
#ifndef PCAN_RING_H
#define PCAN_RING_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "pcan_config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint8_t *buf;
uint16_t size; /**< степень двойки */
volatile uint16_t head; /**< пишет производитель */
volatile uint16_t tail; /**< пишет потребитель */
volatile uint32_t dropped; /**< байт потеряно при переполнении */
} pcan_ring_t;
/** @return false, если size не является степенью двойки. */
bool pcan_ring_init(pcan_ring_t *rb, uint8_t *storage, uint16_t size);
uint16_t pcan_ring_count(const pcan_ring_t *rb);
uint16_t pcan_ring_free(const pcan_ring_t *rb);
bool pcan_ring_put(pcan_ring_t *rb, uint8_t byte);
bool pcan_ring_get(pcan_ring_t *rb, uint8_t *byte);
/**
* @brief Кладёт блок целиком либо не кладёт ничего.
*
* Всё-или-ничего принципиально: половина кадра в линии заставила бы
* приёмник ресинхронизироваться.
*/
bool pcan_ring_write(pcan_ring_t *rb, const uint8_t *data, uint16_t len);
/**
* @brief Непрерывный участок готовых к выдаче данных (без заворота).
* @param[out] ptr указатель на начало участка;
* @return длина участка; 0 - данных нет.
*
* После того как участок передан, вызовите pcan_ring_consume().
*/
uint16_t pcan_ring_linear(const pcan_ring_t *rb, const uint8_t **ptr);
/** Помечает len байт как прочитанные. */
void pcan_ring_consume(pcan_ring_t *rb, uint16_t len);
static inline bool pcan_ring_empty(const pcan_ring_t *rb)
{
return rb->head == rb->tail;
}
#ifdef __cplusplus
}
#endif
#endif /* PCAN_RING_H */