# Транспортный кадр ## Формат ``` +------+------+-----+-----+-------+----------------+-------------+-------+-------+ | 0xAA | 0x55 | LEN | SEQ | FLAGS | ID0 ID1 ID2 ID3| DATA[0..8] | CRC_L | CRC_H | +------+------+-----+-----+-------+----------------+-------------+-------+-------+ ``` | Поле | Байт | Описание | |---|---:|---| | SOF | 2 | сигнатура `0xAA 0x55` | | `LEN` | 1 | длина участка `SEQ..DATA` = `6 + DLC`, диапазон 6..14 | | `SEQ` | 1 | счётчик кадров 0..255, инкремент на каждый успешно отданный кадр | | `FLAGS` | 1 | см. ниже | | `ID` | 4 | 29-битный CAN-идентификатор, little-endian (старшие 3 бита = 0) | | `DATA` | 0..8 | `DLC = LEN - 6` байт данных CAN | | `CRC` | 2 | CRC-16/CCITT-FALSE, little-endian | CRC считается по байтам от `LEN` до последнего байта `DATA` включительно; сигнатура SOF в расчёт не входит. Полином `0x1021`, начальное значение `0xFFFF`, без рефлексии и без финального XOR — контрольное значение для строки `123456789` равно `0x29B1`. Максимальный размер кадра — 19 байт (`PCAN_FRAME_MAX`). ## FLAGS | Бит | Имя | Значение | |---:|---|---| | 0 | `IDE` | 1 = расширенный ID (29 бит), 0 = стандартный (11 бит) | | 1 | `RTR` | 1 = remote frame | | 2 | `DIR` | 0 = кадр пришёл из CAN, 1 = кадр надо передать в CAN | | 3 | `ERR` | 1 = служебный кадр моста (диагностика), не трафик шины | | 7..4 | — | резерв, передавать нулями | ## Синхронизация Приёмник ищет `0xAA 0x55`, читает `LEN`, проверяет диапазон `6..14`, набирает `LEN + 2` байт и сверяет CRC. При неверном `LEN` или несовпадении CRC разборщик возвращается к поиску сигнатуры, причём байт, оборвавший разбор, сам проверяется на `0xAA` — последовательность `AA AA 55` тоже распознаётся. Потеря синхронизации стоит не больше одного кадра. Счётчики разбора (`pcan_parse_stats_t`) отдельно считают кадры, ошибки CRC, неверные `LEN` и байты вне кадров — по ним видно, шумит линия или сбоит источник. ## SEQ `SEQ` инкрементируется только на успешно отданном кадре: если кадр не влез в очередь передачи, счётчик не двигается, и приёмник не засчитает потерю там, где кадра просто не было. Разрыв в `SEQ` на приёме означает реальную потерю в линии. ## Почему так - **Длина плюс CRC, без байт-стаффинга.** Стаффинг раздувает кадр непредсказуемо и усложняет расчёт таймингов на полудуплексной линии. Фиксированный заголовок даёт заранее известный максимум 19 байт. - **Сигнатура из двух байт.** Один байт слишком часто встречается в случайных данных; два дают приемлемую вероятность ложного старта, который всё равно отсеет CRC. - **`LEN` в начале.** Приёмник сразу знает, сколько байт набирать, и не зависит от содержимого данных. - **Little-endian везде.** Совпадает с порядком регистров в `PROTOCAN_SEND_GENERAL_ADDRESS_SPACE()` и с обоими целевыми МК. ## Пример CAN-кадр: ID `0x1234567`, DLC 2, данные `AA BB`, `SEQ = 1`, флаг `IDE`. ``` AA 55 08 01 01 67 45 23 01 AA BB FE 14 ``` `LEN = 6 + 2 = 8`, `FLAGS = 0x01`, CRC = `0x14FE`.