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

Из этой практики и появился Protohaund. Программа помогает разбирать сообщения с учётом правил протокола, фильтровать обмен по его полям и исследовать взаимодействие устройств. Она пригодится и при разработке собственных устройств, и при обратном проектировании протоколов.
В этой статье покажу два инструмента: Tracer — для изучения последовательности сообщений и Monitor — для наблюдения за повторяющимся обменом и значениями. Разберём их на примерах Modbus RTU, CANopen и автомобильной диагностики VAG.
Пример 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.
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 — для разбора передаваемых значений.
В Monitor удобно наблюдать повторяющиеся CAN-кадры: последнее содержимое, период, количество сообщений и подсветку изменившихся байтов и битов. Это помогает заметить, какой поток меняется при действии на стенде. Проверять точную последовательность после этого удобнее в Tracer.
Automotive VAG: от CAN-кадра к диагностическому ответу
При разборе автомобильной диагностики VAG приходится связывать несколько представлений одного обмена. Tracer в профиле VAG объединяет исходные CAN-кадры, транспортные сообщения ISO-TP / TP2.0 и прикладные сообщения UDS / KWP2000.
Например, нас интересует чтение данных UDS:
uds.service == 0x22
uds.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 и устанавливается автоматически при необходимости.
- Доступ к интернету для загрузки и обновления дополнительных пакетов программы.
Для подключения к устройствам предусмотрены следующие варианты:
| Интерфейс | Адаптер | Условия подключения |
|---|---|---|
| Serial | USB–RS-485/RS-422 или другой преобразователь с 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
А на этом пока все. Всем добра!