Files
templates/c/protocan-transport/include/pcan_ring.h
Andrey Kruchinkin 3dc636e012 feat(protocan-transport): транспортный уровень ProtoCAN и каталог GUI
Перенесён из репозитория protocan-transport, который подключался
сабмодулем в CAN_to_RS485.

Кадрирование AA 55 с CRC16 поверх любого байтового потока (RS485, RS232,
USB CDC), разбор 29-битного идентификатора, общее адресное пространство
регистров и каталог с подпиской на поток значений для SETGUI. Состояние
живёт в структурах вызывающего, поэтому в одной прошивке поднимается
сколько угодно независимых каналов. Порт STM32F4 (USART + DMA) в комплекте.

Хостовые тесты test_transport и test_gui проходят.
2026-08-23 01:15:35 +03:00

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 */