Files
templates/c/protocan-transport/docs/GAS.md
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

88 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Общее адресное пространство (GAS)
Плоское пространство 16-битных регистров с адресом `0x0000..0xFFFF`.
Пространство собирается из **регионов**; регионы не перекрываются и
хранятся отсортированными по адресу, поиск — двоичный.
## Регион
```c
typedef struct pcan_gas_region {
uint16_t base; /* адрес первого регистра */
uint16_t count; /* число регистров */
uint16_t *storage; /* массив либо NULL */
pcan_gas_read_fn read;
pcan_gas_write_fn write;
uint8_t flags; /* PCAN_GAS_RDONLY / PCAN_GAS_WRONLY */
void *user;
const char *name;
} pcan_gas_region_t;
```
Если `storage != NULL`, чтение и запись идут прямо в массив — это самый
дешёвый вариант для обычных уставок. Если нужен вычисляемый регистр
(счётчик, состояние периферии, время работы), задайте `read`/`write`:
колбэк получает смещение внутри региона и указатель `user`.
`pcan_gas_map_validate()` проверяет карту на этапе старта: нулевые регионы,
выход за `0xFFFF`, перекрытие, нарушение порядка и регион без источника
данных. Вызывайте её один раз при инициализации — ошибка в таблице ловится
сразу, а не через месяц в поле.
## Доступ
```c
uint16_t v;
pcan_gas_read(&map, 0x0002, &v);
pcan_gas_write(&map, 0x0002, 0x1234);
uint16_t block[4];
uint16_t n = pcan_gas_read_block(&map, 0x0000, block, 4);
```
Блочное чтение обрывается на первом адресе, которого нет в карте, поэтому
вызывающий всегда получает непрерывный кусок и знает его длину.
## Отображение на кадры ProtoCAN
Тип сообщения `PCAN_MSG_GAS` (`0b0011`). Адрес первого регистра лежит
в `MsgBody`, данные — до 4 регистров подряд, младшим байтом вперёд.
Это ровно то, что делает `PROTOCAN_SEND_GENERAL_ADDRESS_SPACE()`
в `SETCAN/Src/protocan.c`, поэтому обмен совместим с существующими
устройствами.
| Кадр | DLC | Смысл |
|---|---:|---|
| GAS, `MsgBody = addr` | 0 | **запрос на чтение** |
| GAS, `MsgBody = addr` | 2..8 | значения регистров начиная с `addr` |
Запрос на чтение с `DLC = 0`**расширение**: в исходном коде SETCAN
такой кодировки нет, там ответы на GAS формировала заглушка `ProtoCanMsgToGeneralAddressSpace()`,
возвращавшая строку `GAS-XXXX`. Кодировка выбрана так, чтобы не занимать
новых типов сообщений и не конфликтовать с существующим форматом ответа.
```c
pcan_frame_t rsp;
if (pcan_gas_handle(&map, &incoming, &rsp)) {
pcan_link_send(&link, &rsp); /* был запрос на чтение */
}
```
`pcan_gas_handle()`:
- на запрос чтения кладёт в `rsp` до 4 регистров и переключает `Route`
на `FROM_DEVICE`, возвращает `true`;
- на запись пишет регистры в карту и возвращает `false` — ответа нет;
- если адреса нет в карте, возвращает `false`: отвечать нечем, а молчание
честнее, чем ответ с нулями.
## Ограничения
- В один кадр помещается не больше 4 регистров (`PCAN_GAS_REGS_PER_FRAME`).
Длинные блоки разбивайте на несколько кадров.
- Частичная запись: если в середине блока попался адрес вне карты или
регион только для чтения, запись обрывается на нём. `pcan_gas_write_block()`
возвращает число фактически записанных регистров.
- Атомарности между регистрами нет. Если два регистра обязаны меняться
вместе, заведите колбэк, который применяет их по записи второго.