Друзья, добрый день! Эта заметка немного выходит за рамки автомобильной тематики. Последние несколько лет я занимаюсь разработкой различных устройств на базе ARM — от проектирования печатных плат до прошивок и вспомогательных утилит. В этой работе мне часто приходится иметь дело с распространёнными двухпроводными интерфейсами RS-485 и CAN, а также с различными протоколами, которые их используют. Для отладки устройства важно понимать, что происходит в обмене: какие сообщения оно отправляет, как отвечает на запросы и где возникает ошибка.

Из этой практики и появился Protohaund. Мне нужен был универсальный инструмент как для отладки собственных устройств, так и для анализа обмена и обратного проектирования протоколов — когда по наблюдаемым сообщениям нужно восстановить их структуру, назначение полей и логику взаимодействия устройств. При этом у разных протоколов свои трудности, которые начинаются ещё до расшифровки данных.
При отладке обмена хочется сразу понять, какой запрос отправлен, какой ответ получен и сколько времени прошло между ними. Но для этого сначала нужно выделить сообщения и разобраться в их структуре. Покажу это на двух примерах: Modbus RTU при работе через последовательный порт и мультикадровом обмене по CAN. В первом случае трудности начинаются с поиска границ сообщений в потоке байтов. Во втором — со сборки целого ответа из нескольких CAN-кадров.
Пример 1. Последовательный порт: границы сообщений Modbus RTU
При наблюдении за последовательным обменом нужно решить несколько задач: выделить отдельные сообщения в потоке байтов, сопоставить запросы и ответы и оценить интервалы между ними. Сам последовательный порт не передаёт приложению готовые границы сообщений.
Дополнительную сложность создаёт буферизация в Windows, драйверах и USB-адаптерах. Одно сообщение может поступить в программу несколькими частями, а несколько сообщений — одной порцией. Поэтому границы операций чтения не обязательно совпадают с границами сообщений, а интервалы между поступлениями данных могут отличаться от пауз на линии.
Для Modbus RTU это особенно существенно: сообщения разделяются временными паузами, а специального байта «конец сообщения» нет. Эти правила описаны в спецификации Modbus RTU. Чтобы восстановить обмен по полученным данным, нужно учитывать структуру сообщений, их длину и CRC.
Например, без разделения два сообщения могут выглядеть так:
07 03 00 64 00 02 85 B2 07 03 04 12 34 56 78 E7 07
В этом примере за последовательностью байт скрывается простой обмен:
| Сообщение | Байты | Значение |
|---|---|---|
| Запрос | 07 03 00 64 00 02 85 B2 | Устройство 7, функция 0x03, чтение двух регистров с адреса 100 |
| Ответ | 07 03 04 12 34 56 78 E7 07 | Устройство 7 вернуло два значения: 0x1234 и 0x5678 |
Этот пример показывает первую задачу анализатора последовательного обмена: восстановить границы сообщений с учётом правил конкретного протокола. После этого можно сопоставлять запросы и ответы, искать ошибки и проверять значения.

Tracer в Protohaund берёт на себя восстановление RTU-сообщений из поступающих данных: использует структуру поддерживаемых функций, длину, CRC и ожидание недостающих частей с учётом буферизованной доставки. После этого обмен можно читать как отдельные сообщения и фильтровать по их полям. Точное измерение физических пауз на линии — отдельная задача: время поступления порции данных в Windows не равно времени каждого байта на RS-485.
Пример 2. CAN: разбор CANopen, UDS и KWP2000
Теперь рассмотрим обмен по CAN. Здесь контроллер уже выделяет границы кадров, и через CAN-адаптер программа получает отдельные записи с идентификатором, длиной и данными. Какие байты принадлежат одному кадру, известно сразу. Описание CAN от CiA.
Однако границы кадров решают лишь часть задачи. Чтобы понять обмен, нужно определить назначение кадров, связать запросы с ответами и, когда данные передаются частями, восстановить их целиком.
В CANopen это хорошо видно при чтении длинной строки через сегментированную передачу SDO. Индекс и подындекс объекта задаются в начале обмена и не повторяются в каждом сегменте. Для восстановления значения нужно связать сегменты с исходным обращением, проследить их последовательность и подтверждения, учесть возможное прерывание передачи. Поэтому по одному кадру из середины обмена нельзя понять всё обращение. Описание SDO от CiA, структура сообщений SDO в CANopenNode.
При анализе UDS или KWP2000 поверх CAN добавляется разделение на транспортный и диагностический уровни. Сначала нужно собрать сообщение и отделить служебный обмен, затем определить сервис, его параметры и результат выполнения запроса. Например, в диагностике VAG длинный ответ UDS передаётся через ISO-TP: начальный кадр, кадры продолжения и управление потоком. Описание передачи ISO-TP.
В рассматриваемых сценариях VAG встречаются две цепочки:
| Исходные кадры | Транспортный протокол | Диагностический протокол |
|---|---|---|
| CAN | ISO-TP: разделение и сборка сообщения, управление потоком | UDS: сервисы, идентификаторы данных и ответы ЭБУ |
| CAN | TP2.0: установка канала, передача частей сообщения и подтверждения | KWP2000: диагностические запросы и ответы |
Возьмём чтение VIN через UDS. Ниже пример для классического CAN с обычной адресацией ISO-TP, без дополнительного адресного байта. CAN ID 0x714 и 0x77E выбраны для примера, VIN также условный.
| CAN ID | Данные кадра | Что происходит |
|---|---|---|
0x714 | 03 22 F1 90 55 55 55 55 | Прибор запрашивает DID 0xF190 — VIN; запрос помещается в один кадр |
0x77E | 10 14 62 F1 90 59 59 59 | ЭБУ начинает ответ общей длиной 20 байт; здесь только первые 6 байт сообщения UDS |
0x714 | 30 00 00 55 55 55 55 55 | Прибор разрешает продолжить передачу: это управление потоком ISO-TP |
0x77E | 21 59 59 59 59 59 59 59 | Первая часть продолжения ответа |
0x77E | 22 59 59 59 59 59 59 59 | Вторая часть продолжения ответа |
В исходной таблице это пять CAN-кадров. Чтобы понять обмен вручную, нужно отличить служебные байты от данных, учесть объявленную длину, проверить порядок частей и собрать ответ. Например, 22 в начале последнего кадра — признак кадра продолжения с номером 2, а не сервис UDS 0x22. Поиск одного байта без учёта уровня протокола легко приводит к неверной интерпретации.

После сборки ответ UDS выглядит так:
62 F1 90 59 59 59 59 59 59 59 59 59 59 59 59 59
59 59 59 59Теперь его смысл можно выразить одной фразой: положительный ответ на чтение DID 0xF190, значение VIN – YYYYYYYYYYYYYYYYY. Кадр управления потоком в эти данные не входит. В Tracer на Physical видны исходные кадры, на Transport — транспортные сообщения, а на Protocol — диагностический запрос и собранный ответ. Поэтому можно отбирать обмен по uds.service и uds.did, не собирая сообщение вручную из строк CAN.

При работе через TP2.0/KWP2000 задача похожая, но добавляется контекст канала: его параметры и CAN-идентификаторы согласуются при установлении связи. Для полноценного разбора полезно видеть и начало этого обмена. Просто найти знакомый CAN ID или байт сервиса в середине записи недостаточно.
Эти примеры показывают разные задачи анализа: восстановить сообщения Modbus RTU из потока байтов, связать сегменты SDO в CANopen или собрать и разобрать диагностический обмен UDS/KWP2000. В каждом случае важно учитывать правила протокола и связь сообщений между собой. Именно такой переход от исходных данных к понятному обмену лежит в основе Tracer.
Поэтому сейчас я представляю Protohaund — предварительную версию программы для анализа обмена данными в промышленных и автомобильных сетях. В этой заметке сосредоточимся на трёх направлениях: Modbus RTU, CANopen и автомобильной диагностике VAG. Главный инструмент обзора — Tracer. Также немного посмотрим на Monitor: он помогает следить за повторяющимися сообщениями и текущими наблюдаемыми значениями.
Tracer: увидеть последовательность событий
Tracer показывает историю обмена: время, адреса или идентификаторы, тип сообщения, данные и доступное описание. Можно изучать поступающий трафик или загрузить ранее сохранённую запись. Во время работы с подключённым источником трасса собирается автоматически; отдельного запуска записи не требуется. Кнопка Save сохраняет накопленные данные в файл.
Для CAN доступен взгляд с нескольких уровней. На Physical видны исходные кадры. В профиле Automotive VAG на уровне Transport можно разбирать ISO-TP и TP2.0, а на Protocol — UDS и KWP2000. В профиле Industrial CANopen используются исходный уровень CAN и прикладной уровень CANopen. Это позволяет переходить от вопроса «какие байты пришли?» к вопросу «какой объект читали или какой сервис вызвали?» одним движением слайдера.

Важные места можно помечать собственными метками. Например, отметить начало проверки и сообщение, после которого изменилось поведение устройства. Сохранённая трасса позволяет вернуться к этому эпизоду позже, уже без подключения к оборудованию.
Фильтр, который понимает поля протокола
Одна из возможностей, на которой я хочу сделать особый акцент, — фильтрация по полям сообщения. В строке фильтра можно задать понятное условие: оставить один адрес, выбранные функции, определённый объект CANopen или отрицательные ответы диагностического блока.
Например, в Modbus RTU нас интересуют только ответы с исключением от устройства с адресом 7:
modbus.unitId == 7 and modbus.exception == true Здесь modbus.unitId — адрес устройства, а modbus.exception — признак ответа с исключением. Программа проверяет разобранные поля сообщения. Совпадение случайного байта 07 внутри данных не попадёт в выборку только потому, что адрес тоже равен 7.
Условия можно объединять через and, or и not, группировать скобками, сравнивать числа и выбирать несколько значений через in. Для работы с данными есть поиск последовательности байтов и обращение к отдельному байту по индексу. Ввод поддерживает подсказки полей и значений; ошибки в выражении показываются рядом с фильтром.
Несколько полей, с которых удобно начать знакомство:
| Поле | Что позволяет отобрать |
|---|---|
can.id, can.frameType | CAN-идентификатор и формат std / ext на исходном уровне |
can.data | Байты CAN-кадра, включая поиск фрагмента данных |
modbus.unitId, modbus.function | Адрес устройства и код функции Modbus |
modbus.startAddress, modbus.quantity | Начальный адрес и количество элементов, когда они есть в сообщении |
modbus.exceptionCode, modbus.valid | Код исключения и результат проверки записи |
canopen.nodeId, canopen.type | Узел и семейство сообщений CANopen |
canopen.index, canopen.subIndex | Объект словаря CANopen |
canopen.abortCode, canopen.emcyCode | Прерывание SDO/USDO и код аварийного сообщения |
uds.service, uds.did | Сервис UDS и идентификатор данных |
uds.negativeResponseCode | Причину отрицательного ответа UDS |
kwp.service, kwp.localId | Сервис и локальный идентификатор KWP2000 |
isotp.flowStatus, tp20.rnr | Управление потоком ISO-TP и состояние готовности получателя TP2.0 |
Поля зависят от выбранного уровня. Условие по can.id вводится на Physical, а по uds.service — на Protocol. Для каждого уровня CAN хранится своё выражение. Полные таблицы и особенности каждого поля собраны
в справочнике.
Фильтр меняет отображение таблицы. Исходные сообщения продолжают собираться, а Save сохраняет исходную трассу в текущих границах документа, включая скрытые фильтром записи. Поэтому после сохранения можно проверить другую гипотезу и увидеть соседние события.
Modbus RTU: почему устройство не выполняет запрос
Представим стенд с несколькими устройствами. Ведущий циклически читает регистры, и среди обычных ответов иногда появляется исключение. Сначала оставим обмен с адресом 7:
modbus.unitId == 7Теперь сузим выборку до чтения регистров хранения:
modbus.unitId == 7 and modbus.function == 0x03Поле modbus.function содержит код функции без бита исключения. Поэтому такая выборка сохраняет запросы, обычные ответы и распознанные ответы с исключением для функции 0x03. Не нужно отдельно искать код ответа 0x83.
Если требуется разобраться с конкретным диапазоном, можно выбрать запросы по modbus.startAddress и modbus.quantity. Адреса в фильтре начинаются с нуля. Обозначение регистра вроде 40001 из инструкции устройства сначала нужно сопоставить с его адресом в протоколе.
Для чтения ответ обычно не содержит начальный адрес. Поэтому фильтр по диапазону покажет запрос, но не обязан показать соответствующий ответ. Для просмотра обеих сторон обмена удобнее оставить адрес устройства и функцию, а затем изучить последовательность сообщений.
Отдельная полезная проверка:
modbus.valid == falseОна выделяет записи, не прошедшие проверку структуры или CRC. Это повод проверить параметры линии и исходные данные. Сам фильтр не устанавливает физическую причину ошибки.
Monitor дополняет этот разбор: группирует наблюдаемые операции по устройству, функции и диапазону, показывает значения из сопоставленных ответов, наблюдаемый период и давность активности. Открытие Monitor не запускает опрос. Если запросов на линии нет, новые значения сами по себе не появятся =)
CANopen: найти нужный узел и объект
В сети CANopen рядом идут PDO, служебные сообщения, контроль состояния узлов и обращения к словарю объектов. В Tracer можно работать с их смыслом: выбрать узел, семейство сообщений или конкретный индекс и подындекс.
Допустим, нужно проверить обращение к объекту 0x1018:1 узла 5:
canopen.nodeId == 5 and canopen.type == sdo and canopen.index == 0x1018 and canopen.subIndex == 1Такой фильтр оставит SDO-сообщения с указанным объектом. Для сегментированной передачи часть сообщений не несёт индекса и подындекса. Если нужна вся последовательность, условие по объекту лучше убрать и оставить узел с типом sdo.
Для поиска прерываний передачи достаточно проверить наличие кода:
canopen.nodeId == 5 and exists(canopen.abortCode)А при разборе неожиданной остановки узла полезно собрать рядом команды управления сетью, запуск узла, сообщения о состоянии и авариях:
canopen.type in (nmt, bootup, heartbeat, nodeGuard, emcy)Это даёт последовательность, по которой можно проверить: была ли команда NMT, появлялось ли сообщение запуска, передавался ли EMCY. Наличие или отсутствие одного сообщения ещё не доказывает причину остановки, но помогает сузить поиск.
Если к узлу привязано подходящее описание EDS или DCF, трасса может показывать имена и типы объектов, а при корректном отображении PDO — разобранные значения, но в бета версии возможность загрузить EDC/DCF отключена.
В Monitor удобно наблюдать повторяющиеся CAN-кадры: последнее содержимое, период, количество сообщений и подсветку изменившихся байтов и битов. Это помогает заметить, какой поток меняется при действии на стенде. Проверять точную последовательность после этого удобнее в Tracer.
Automotive VAG: от CAN-кадра к диагностическому ответу
При разборе автомобильной диагностики VAG приходится связывать несколько представлений одного обмена. Tracer в профиле VAG объединяет исходные CAN-кадры, транспортные сообщения ISO-TP / TP2.0 и прикладные сообщения UDS / KWP2000.
Например, нас интересует чтение данных UDS:
uds.service == 0x22uds.service — нормализованный сервис. В выборку попадают распознанный запрос с SID 0x22, положительный ответ с SID 0x62 и отрицательный ответ на этот сервис. Если нужен именно фактический первый байт сообщения, используется другое поле — uds.rawSid.
Чтение VIN можно сузить по DID:
uds.service == 0x22 and uds.did == 0xF190 Но отрицательный ответ вида 7F 22 … не содержит DID. Чтобы не потерять его при анализе, нужно вернуться к более широкому условию по сервису или отдельно посмотреть отрицательные ответы.
uds.negativeResponse == trueЗдесь полезен uds.negativeResponseCode: например, 0x78 означает, что запрос принят, но ответ ещё не готов. Это нельзя автоматически считать тайм-аутом или окончательным отказом. В трассе нужно посмотреть, что пришло следом.
Для KWP2000 действует та же логика: есть поля kwp.service, kwp.rawSid, признаки запроса и ответа, код отрицательного ответа, локальный и общий идентификаторы. На транспортном уровне можно отдельно исследовать управление потоком ISO-TP или сообщения канала TP2.0. Периодические TesterPresent можно скрыть отдельным переключателем, чтобы сосредоточиться на интересующем обмене.
Этот обзор касается анализа диагностического трафика VAG по CAN. Он не обещает универсальной поддержки всех блоков и автомобилей или готового сценария программирования ЭБУ.
Требования к ПК и поддерживаемые адаптеры
Для работы с программой потребуется:
- ПК с процессором x86 или x64 и Windows 10 либо Windows 11. Версия и редакция Windows должны соответствовать требованиям .NET 10.
- Среда .NET 10 Desktop Runtime. Она входит в установщик Protohaund и устанавливается автоматически при необходимости.
- Доступ к интернету для загрузки и обновления дополнительных пакетов программы.
Для подключения к устройствам предусмотрены следующие варианты:
| Интерфейс | Адаптер | Условия подключения |
|---|---|---|
| RS-485, Modbus RTU | USB–RS-485 или другой преобразователь с COM-портом | Стандартный последовательный порт Windows |
| CAN | CANable и CANable 2.0 | Совместимая прошивка SLCAN для CANable |
| CAN | Lawicel CANUSB | Драйвер FTDI |
| CAN | UCCB | Подключение через COM-порт |
| CAN | VCDS-совместимые адаптеры на FTDI | Совместимость зависит от исполнения адаптера; используется драйвер FTDI |
| CAN | J2534 Pass-Thru | Драйвер производителя с поддержкой обмена исходными CAN-кадрами |
Поддержка CAN-адаптеров устанавливается через раздел пакетов в настройках программы: доступны пакеты CANable, J2534, FTDI (Lawicel и VCDS) и UCCB. Драйверы самих устройств при необходимости устанавливаются отдельно. Возможности подключения зависят от конкретного адаптера, его прошивки и драйвера.
Для некоторых сценариев работы с J2534 предусмотрен DriverBridge — вспомогательное приложение, позволяющее 64-разрядной версии Protohaund использовать старые 32-разрядные библиотеки драйвера адаптера. Компонент входит в пакет J2534.
Для открытия и анализа сохранённой трассы адаптер не нужен — знакомство с Tracer и фильтрами можно начать без оборудования.
Вместо заключения
Если вы, как и я, разрабатываете устройства, отлаживаете обмен или исследуете протоколы, буду рад, если попробуете Protohaund на своих задачах и поделитесь впечатлениями. Мне интересно узнать, где программа окажется полезной, чего вам будет не хватать и что можно сделать удобнее. Возможно, ваши задачи похожи на мои, но, возможно, вы увидите применение, о котором я пока не думал.
В ближайшей перспективе планирую открыть для тестирования ещё несколько инструментов, которые по разным причинам пока готовы широкому тестированию, — в том числе симулятор виртуальных устройств и плеер для воспроизведения трасс. За рамками этого обзора остался и сервер MCP: часть его возможностей уже доступна, и их можно использовать для подключения ИИ-ассистентов и автоматизации работы с программой. Если будет интерес к этому сценарию, я обязательно расскажу об этом отдельно.
К сожалению, в программе пока ещё есть ошибки и белые пятна в реализации, поэтому для сообщений об ошибках в Protohaund встроена специальная форма. Если получится приложить сохранённую трассу или описать, при каких действиях возникла проблема, мне будет проще разобраться. Пользоваться формой можно не только для отправки баг-репортов, но и для предложений по развитию, пишите, я обязательно рассмотрю каждое из них.
Если программа вас заинтересовала, то ссылку на пакет установщика и тестовую лицензию вы найдёте в личном кабинете пользователя на моем сайте https://osoTEC.com
А на этом пока все. Всем добра!