/** * @file pcan_ring.h * @brief Кольцевой буфер байтов: один писатель, один читатель. * * Размер обязан быть степенью двойки - индексы сворачиваются маской, * поэтому head/tail обновляются одной записью и блокировки между * фоновым кодом и обработчиком прерывания не нужны. * * Отдельно есть pcan_ring_linear(): отдаёт непрерывный участок данных * без заворота - именно то, что требуется, чтобы отдать кусок в DMA. */ #ifndef PCAN_RING_H #define PCAN_RING_H #include #include #include #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 */