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 проходят.
This commit is contained in:
71
c/protocan-transport/include/pcan_ring.h
Normal file
71
c/protocan-transport/include/pcan_ring.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @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 */
|
||||
Reference in New Issue
Block a user