Подопытным кроликом станет мотоцикл CFMOTO 450MT (IBEX), или, как его ласково прозвали мужики в гаражах - "сифа":

В первой части статьи мы посмотрим на архитектурные схемы различных мотоциклов, поймем как обычно принято соединять блоки в сеть.
Во второй части подключимся к CAN-шине, разберемся какие сообщения по ней путешествуют, накидаем заготовку DBC-файла с описанием фреймов и сигналов.
В третьей части достучимся UDS-диагностикой до блоков мотоцикла, научимся читать и толковать ошибки, читать и редактировать конфигурацию.
Для лучшего понимания происходящего в статье могут понадобиться базовые знания о CAN-шине, протоколе UDS и файловом формате DBC. На хабре уже есть много статей на эту тему, кроме них рекомендуются материалы от CSS Electronics в качестве сжатого ликбеза: CAN, UDS, DBC. Историческую справку о зарождении и развитии CAN можно изучить на сайте ЦРУ, посвященном CAN: can-cia.org.
Cервисная документация CFMOTO размещена на американском сайте компании cfmotousa.com.
В качестве основных инструментов традиционно выступят связка библиотек python-can + can-isotp для работы с CAN-шиной и софт SavvyCAN для анализа логов и визуализации сигналов. Интерфейс для подключения подходит любой, который переваривает библиотека python-can.
Материал опубликован в ознакомительных и образовательных целях.
Часть 1. Архитектура мотоциклетных CAN-шин
Слово архитектура звучит громковато для системы из 3 блоков управления, но с чего-то надо начинать. Перед нами схема для CFMOTO 450MT:

Data Link Connector - это разъем для подключения диагностики. ECU управляет работой двигателя, ABS заведует тормозами и трекшн-контролем (TCS), а Dashboard (или Cluster) - это приборная панель. Пунктиром выделен опциональный блок телематики T-Box. На подопытном мотоцикле его не нашлось, теоретически он должен находится под правой боковой панелью бака.
В целом, такой связки из трех блоков достаточно для решения минимального набора современных задач. Инжектор вписывается в эконормы и обходится без вытягивания подсоса для прогрева, ABS и простой трекшн-контроль делают поездки безопаснее, а приборная панель выводит множество данных и ее можно подружить со смартфоном.
К слову, так же выглядит состав блоков для Royal Enfield Himalayan 450, конкурента "сифы" с идентичным объемом двигателя: ECU, ABS, приборка и опциональная телематика.
Если взять старшего брата CFMOTO 800MT-X, то у него внутри уже поинтереснее:

Дополнительно появились блоки BCM (Body Control Module) и IMU (Inertial Measurement Unit). Появление BCM интуитивно понятно - потребовался отдельный мозг для управления более навороченной бортовой электроникой, а вот для IMU нужно краткое пояснение.
Внутри IMU есть гироскоп и акселерометр, показания которых сообщают блоку ABS о текущем состоянии мотоцикла: его ускорения по разным осям, наклонен ли он, и в какую сторону, пытается ли встать на дыбы или, наоборот, собирается опрокинуться через переднее колесо. Эта информация крайне полезна для функций безопасности типа "Cornering ABS" и "Cornering Traction Control". Когда мотоцикл наклонен в повороте, ухудшается его контакт с дорогой и требуется гораздо меньше усилий, чтобы заблокировать его колеса при торможении, или сорвать в пробуксовку заднее колесо при ускорении. Можно еще упомянуть функцию "Anti-Wheelie", препятствующую вставанию на дыбы. Применений у IMU много, особенно с точки зрения безопасности.
Говоря о CFMOTO 800MT-X, сложно не упомянуть его австрийского родственника KTM 790 Adventure, с оглядкой на который он создан. CFMOTO и KTM связывают тесные отношения начиная с 2011 года, а с 2023 года сборку KTM 790 Adventure полностью перенесли в Китай.

Родственные мотоциклы отличаются по архитектурной составляющей:
много функций выполняется отдельными модулями, часть из которых опциональна к установке: система контроля давления в шинах, обогрев ручек, иммобилайзер и управление фарой;
вытекает из первого пункта - отсутствует единый боди-контроллер BCM, его функции разнесены по другим модулям поменьше;
блок связи и панель приборов соединяет BroadR-Reach интерфейс, это двухпроводная автомобильная версия Ethernet. BroadR-Reach вышел в свет в 2011 году, а в 2015 году лег в основу IEEE стандарта 100BASE-T1.
Изучая электросхемы других производителей, я наткнулся на интересный пример эволюции, иллюстрирующий внедрение CAN-шины при смене поколений. Речь идет о переходе Honda Africa Twin от поколения CRF1000L к поколению CRF1100L.
Вот схема сети для CRF1000L, которую начали выпускать в 2015 году, всего пару более десяти лет назад:

На тот момент Honda не стала применять CAN-шину в данном мотоцикле, при этом опционально он мог быть напичкан довольно сложной электроникой. Например, на нем могла стоять впервые адаптированная для езды по бездорожью автоматическая коробка передач с двумя сцеплениями - DCT. Из схемы можно сделать вывод о том, как технически сложные мотоциклы Honda обходились без CAN-шины:
функции, требующие тесного взаимодействия, были реализованы внутри одного блока (PCM + TCM = блок двигателя управлял заодно и коробкой DCT);
для компьютерной диагностики применяли K-Line, а без компьютера могли обойтись SCS (Service Check Signal, при замыкании этого пина на массу лампа индикации неисправностей начинает "телеграфировать" номер ошибки);
для мультиплексирования данных использовали проприетарный протокол M-TXD (Meter Transmit Data), чтобы не тянуть охапку проводов к приборной панели.
Блок ABS тогда еще был в принципе опционален, он станет обязательным во многих странах только к концу 2010-х.
В следующем поколении, Honda прибавила стопку кубиков к объему двигателя и кардинально поменяла архитектуру мотоцикла:

Среди множества отличий:
блок управления DCT отпочковался от блока управления двигателем и обрел независимость, между ними появилась выделенная CAN-шина "Powertrain" для обеспечения надежного обмена данными;
появилась специальная изолированная CAN-шина для диагностики DIAG, которая подключается через блок двигателя, выполняющего роль шлюза к остальным шинам мотоцикла;
появились две раздельные "рамные" CAN-шины: FRM1 соединяет почти все блоки в одну шину, а FRM2 соединяет приборку и дополнительный дисплей.
Новшества в CRF1100L сочетались с консерватизмом - остались на своих местах K-Line и SCS для диагностики некоторых блоков.
Разглядывая схемы Africa Twin, стало интересно, что внутри у ее младшего брата Transalp, вышедшего в свет в 2023 году:

"Транс" занимает место пониже в иерархии Honda и поэтому устроен попроще:
для диагностики есть отдельная CAN-шина DIAG, которая проходит через встроенный в блок двигателя шлюз;
есть одна "рамная" шина FRM, связывающая между собой все блоки мотоцикла.
На своих местах остались традиционные K-Line и SCS для диагностики некоторых блоков.
Таким образом, с ростом технологической сложности мотоцикла, применение в нем одной или сразу нескольких CAN-шин стало неизбежным. На этом заканчиваем глазеть на схемы и переходим к практике.
Часть 2. Разбор трафика и составление DBC
Подключение и анализ фреймов
Точка подключения у 450MT проще некуда, прямо под седлом нас встречает классический полноразмерный OBDII-разъем со стандартной распиновкой: 6 = CAN-High и 14 = CAN-Low:
Кроме распиновки важно знать битрейт шины, чаще всего это 250 или 500 кбит/с, но иногда встречаются более артхаусные варианты. У CFMOTO битрейт оказался стандартным: 500 кбит/с.
В отличие от автомобиля, на мотоцикле некуда безопасно кинуть ноутбук, пишущий логи во время езды. Поэтому для записи логов на ходу был приобретен отдельный и самостоятельный CAN-логгер, со встроенной АКБ и записью на SD-карту:

Забегая вперед, логгер со своей задачей справился без проблем, но и нагрузка на него была небольшая - одна шина и всего три собеседника на ней. Стационарные логи все равно удобнее записывать и анализировать сразу на ноутбуке.
Подключаем провода, пишем первый лог, изучаем список идентификаторов (ID). Для упрощения дальнейшего реверс-инжиниринга полезно сопоставить каждый из блоков со списком фреймов, который он передает. Это сужает список подозреваемых - например, сигнал RPM скорее всего найдется во фреймах ECU, а сигнал скорости переднего колеса - во фреймах ABS.
Проще всего это делать по очереди, отключая предохранители блоков или скидывая с них разъемы, параллельно отмечая какие фреймы пропадут при следующем включении зажигания. Проделав такую операцию, получаем таблицу фреймов с их отправителями:
| id | size | cycle time, ms | sender | |-------|------|----------------|--------| | 0x110 | 8 | 10 | ECU | | 0x111 | 8 | 10 | ECU | | 0x120 | 8 | 20 | CLU | | 0x123 | 8 | 20 | ECU | | 0x12B | 8 | 10 | ABS | | 0x12F | 8 | 20 | ABS | | 0x151 | 8 | 50 | CLU | | 0x153 | 8 | 50 | CLU | | 0x154 | 8 | 50 | CLU | | 0x163 | 8 | 50 | CLU | | 0x251 | 8 | 100 | CLU | | 0x2F3 | 8 | 200 | CLU | | 0x30E | 8 | 500 | CLU | | 0x321 | 8 | 500 | CLU | | 0x402 | 8 | 1000 | CLU |
Итого ECU выдает 3 фрейма, ABS - 2 фрейма, а болтливая приборка занимает все остальные позиции. В некоторых фреймах сразу бросились в глаза циклические счетчики и чексуммы CRC8, посчитанные по алгоритму из SAE J1850.
Составленный в результате реверс-инжиниринга DBC-файл я разместил на гитхабе, возможно он будет дополняться и корректироваться в следующем мотосезоне. Но это не точно.
Таблица комментариев к сигналам из DBC-файла
фрейм |
сигнал |
комментарий |
|---|---|---|
ECU_h110 |
engineSpeed |
тахометр (об/мин) |
engineTemperature |
температура двигателя (°C) |
|
fuelRate |
мгновенный расход (мкл/с) |
|
clutchLeverPressed |
статус сцепления |
|
sideStandUp |
статус подножки |
|
neutralSelected |
статус нейтрали |
|
ECU_h111 |
throttle |
ручка газа (%) |
voltage |
напряжение бортсети (В) |
|
CLU_h120 |
currentGear |
включенная передача (0…6) |
ECU_h123 |
torqueRequestDriver |
момент, запрошенный водителем через ручку газа (%) |
torqueRequestApplied |
момент, примененный ECU по факту (%) |
|
ABS_h12B |
wheelSpeedFront |
скорость переднего колеса (км/ч) |
wheelSpeedRear |
скорость заднего колеса (км/ч) |
|
torqueLimitTraction |
ограничение момента двигателя трекшн-контролем (%) |
|
ABS_h12F |
AbsRearDisableAck |
подтверждение отключения ABS |
TcDisableAck |
подтверждение отключения TCS |
|
RegularBraking |
флаг обычного торможения/остановки |
|
AbsFrontBraking |
флаг срабатывания ABS (перед) |
|
AbsRearBraking |
флаг срабатывания ABS (зад) |
|
AbsNotChecked |
флаг проверки ABS перед поездкой |
|
CLU_h151 |
mileageTotal |
общий пробег (км) |
generalSpeed |
скорость мотоцикла (км/ч) |
|
CLU_h153 |
fuelLevel |
уровень топлива (%) |
mileageTrip1 |
пробег поездки 1 (км) |
|
mileageTrip2 |
пробег поездки 2 (км) |
|
highBeamOn |
статус дальнего света |
|
CLU_h154 |
mileageUntilService |
пробег до сервиса (км) |
CLU_h163 |
timeTrip1 |
время поездки 1 (мин) |
timeTrip2 |
время поездки 2 (мин) |
|
timeTotal |
общее время (мин) |
|
CLU_h251 |
AbsRearDisableCmd |
команда отключения ABS |
TcDisableCmd |
команда отключения TCS |
|
CLU_h30E |
pressureFrontWheel |
давление TPMS перед (кПа) |
pressureRearWheel |
давление TPMS зад (кПа) |
|
temperatureFrontWheel |
температура TPMS перед (°C) |
|
temperatureRearWheel |
температура TPMS зад (°C) |
|
warningFrontWheel |
флаг предупреждения TPMS перед |
|
warningRearWheel |
флаг предупреждения TPMS зад |
Смысл некоторых сигналов достаточно прямолинеен и расписывать отдельно процесс их поиска излишне. Например, к таким сигналам относится highBeamOn: включил дальний свет, посмотрел где и какой бит поменялся, записал. Но есть и любопытные случаи, которые будут описаны подробнее ниже.
Кстати, highBeamOn оказался очень удобен для разметки длинных логов, так как дальний свет кратковременно включается курком на левой ручке. Когда происходило что-то важное, я моргал дальним и потом очень быстро находил этот момент в логе.
Поскольку представленный DBC-файл - это результат гаражного реверс-инжиниринга, его достоверность может хромать.
Для чего может быть полезен DBC-файл?
Подгруженный в SavvyCAN DBC-файл превращает лог из набора байт в осмысленные сигналы, готовые к построению на графике. В частности, вот как выглядит разгон с места до 60 км/ч в обычном городском потоке:

Сигнал engineSpeed содержит RPM и уменьшен в 100 раз, чтобы влезть на график.
Похожие графики можно получить и опрашивая мотоцикл любым OBDII свистком, но у анализа сырых логов есть ряд преимуществ:
штатные фреймы могут передаваться чаще, чем происходит опрос диагностикой (вплоть до 100 раз в секунду, в случае 450MT);
частый опрос диагностикой создает дополнительную нагрузку на CAN-шину, а обычное прослушивание - нет;
записанный лог наиболее полно передает картину происходящего на данный момент в мотоцикле, его можно проиграть обратно в шину и вызвать у блоков соответствующую реакцию;
некоторые из сырых сигналов уникальны и попросту недоступны для чтения диагностикой (но может быть и наоборот).
Естественно, для лучшего понимания техники, важно уметь пользоваться и диагностикой и сырыми логами.
Скорость, реальная и завышенная
В таблице присутствуют три разных сигнала скорости: wheelSpeedRear, wheelSpeedFront и generalSpeed. Отличие последней в том, что это именно та скорость, которая выводится на спидометр для водителя. А она, как известно, завышается по ряду причин практических и юридических.
На графике изображен процесс поиска сигнала generalSpeed:

Катаясь по пустырю, я моргал дальним 1 раз, когда видел ровно 10 км/ч на спидометре, 2 раза - 20 км/ч, 3 раза - 30 км/ч. Соотношение вышло один к одному, даже конвертировать не нужно.
С определением точной скорости колес нам поможет любое навигационное приложение с вменяемой индикацией скорости. Когда спидометр 450MT показывает ровно 60 км/ч, навигация показывает 56 км/ч. Используем это отличие для вычисления коэффициента для перевода и построим графики:

Коэффициент для перевода равен 0.05625, не самое популярное значение, но такое же встречается у автомобилей Subaru в проекте opendbc. Почему именно так: изначально сигнал передает значение в м/c с множителем 0.015625 (1/64). Для перевода в км/ч домножаем на 3.6 и получаем искомые 0.05625.
Торможение и ABS
Перед изучением работы ABS, проверим как выглядит торможение без нее. Отключаем систему кнопкой "ABS ON/OFF" на руле, разгоняемся до 20 км/ч и аккуратно притаптываем задний тормоз до блокировки колеса:

Сигнал wheelSpeedRear обвалился до нуля, колесо успешно заблокировано.
Сигналов концевиков заднего и/или переднего тормоза в CAN-шине не нашлось. Судя по электросхемам, концевики только включают стоп-сигнал и больше никуда не подключены, поэтому и некому отправлять их состояние в CAN. Зато нашлись логические сигналы RegularBraking, AbsFrontBraking, AbsRearBraking, соответствующие различным видам торможения.
Повторим тот же эксперимент с задним тормозом, но оставим ABS включенным, для демонстрации работы системы:

Изначально система расценивает торможение обычным (RegularBraking = 1), но при блокировке колеса переходит в режим ABS (AbsRearBraking = 1), активно вмешиваясь в процесс и пульсируя лапкой тормоза. Блокировка заднего колеса не оказывает влияния на общую скорость generalSpeed, передаваемую приборкой, т.к. заднее колесо редко используется для надежной оценки скорости - оно ведущее и часто проскальзывает.
Тормозим передним тормозом, ABS оставим включенным:

Начинается все, как и в прошлый раз, обычным торможением, которое переходит в режим ABS, но только теперь активизируется сигнал переднего колеса (AbsFrontBraking = 1). Его блокировка ожидаемо приводит к небольшому скачку общей скорости generalSpeed.
Использование переднего колеса для оценки скорости это популярная практика для мотоциклов. В "механическом" случае, приборная панель соединяется тросиком с передней ступицей и считает обороты колеса. Достаточно скинуть этот тросик, чтобы заморозить пробег и порадовать следующего владельца мотоцикла.
Разгон и TCS
Система TCS должна детектировать пробуксовку заднего колеса и вмешиваться в работу двигателя, чтобы сбавить обороты и восстановить сцепление колеса с дорогой. Самый логичный путь - прикрыть электронный дроссель. У "сифы" дроссель олдскульный тросиковый, но даже такой двигатель можно придушить, управляя искрой и впрыском топлива.
С самого начала анализа фреймов ECU выделялись два занятных, почти одинаковых сигнала. Оба сигнала переставали быть нулевыми после запуска двигателя, росли вместе с откручиванием ручки газа, но внезапно становились отрицательными на ходу, когда ручка газа была полностью закрыта, что оказалось важной зацепкой.
В поисках информации о блоках ECU от фирмы Bosch попались материалы, описывающие "torque-based" подход к управлению автомобильными двигателями. В простом случае, педаль газа напрямую управляет отдачей двигателя. В случае "torque-oriented" ECU сначала собирает пожелания к целевому крутящему моменту двигателя от всех участников системы. Например, водитель хочет X момента, кондиционер - Y, трекшн-контроль - Z. Все эти воздействия оцениваются ECU и он рассчитывает финальное значение момента, которое будет воплощено в жизнь через открытие дросселя, подачу искры и впрыск топлива.
Характерное поведение подозреваемых сигналов сходится с "torque-based" подходом, поэтому обзываем их соответственно: torqueRequestDriver - это запрос от водителя, а torqueRequestApplied - это то, что ECU реально исполнит. Позже нашелся сигнал ограничения момента torqueLimitTraction, задающий потолок отдачи двигателя при срабатывании TCS.
На графике ниже я выехал на грунтовку, открутил ручку газа примерно наполовину и удерживал, чтобы вызвать пробуксовку:

Сигнал fuelRate уменьшен в 100 раз, чтобы влезть на график.
Изначально разгон выглядит стабильным, сигналы torqueRequestDriver и torqueRequestApplied почти идеально повторяют друг-друга, двигатель беспрекословно исполняет команду от ручки газа throttle.
Как только разница скоростей между колес стала больше ~5 км/ч, на момент torqueRequestApplied сверху обрушился потолок в виде torqueLimitTraction, препятствующий дальнейшему набору скорости. При этом положение ручки газа throttle и torqueRequestDriver остаются неизменными - водитель хочет ускоряться дальше, но ограничение срабатывает, и разность скоростей колес уменьшается.
Обратите внимание на мгновенный расход fuelRate, он не обваливается во время срабатывания трекш-контроля, а значит удушение двигателя на данном этапе происходит именно системой зажигания.
После полного закрытия ручки газа и снижения скорости, TCS считает, что кризисная ситуация миновала и снимает ограничение torqueLimitTraction. Сигналы torqueRequestDriver и torqueRequestApplied снова становятся почти одинаковыми и проваливаются ниже нуля, поскольку происходит торможение двигателем.
Расход топлива
Во время движения на приборной панели мотоцикла отображается мгновенный расход топлива. Сама по себе панель не может обладать достаточной информацией для его расчета, стало быть, она ее получает по CAN-шине от ECU. Вопрос в какой форме, и как его сконвертировать в классические л/100 км?
Изначально рассматривались самые разные теории (длительность импульсов форсунок, косвенное вычисление по RPM и нагрузке на двигатель и т.п.), пока круг подозреваемых не сузился до одного сигнала, названного в дальнейшем fuelRate. Данный сигнал содержит посчитанный ECU мгновенный расход топлива в мкл/с. Сперва микролитр звучал абсурдно малой единицей измерения для такого применения, но расчеты указывали именно на него. А позже нашлись упоминания микролитров у производителей Toyota, Volkswagen, Ford.
Чтобы превратить мкл/c в л/100 км, приборке потребуется проделать нехитрую операцию, не забыв про перевод единиц измерения:
Важно: в расчетах нельзя использовать завышенную скорость со спидометра generalSpeed, это приведет к искаженному результату. Нужна точная скорость переднего колеса wheelSpeedFront.
Посчитаем на практическом примере - на графике ниже я старался плавно поддерживать скорость и радостно моргал дальним четыре раза, когда видел расход ровно 4 л/100 км:

Сигнал fuelRate уменьшен в 10 раз, чтобы влезть на график. Наглядно видна реакция расхода на положение ручки газа.
В точке интереса приблизительные значения fuelRate = 465 мкл/с и wheelSpeedFront = 42 км/ч:
Результат близок к искомому значению 4 л/100 км.
Где расход, там и уровень топлива. Сигнал fuelLevel был посчитан подкидыванием резисторов различного номинала, в диапазоне от 10 Ом (полный) до 450 Ом (пустой). Пользуясь значениями уровня топлива и мгновенного расхода можно собирать полезную топливную статистику поездок.
Часть 3. UDS-диагностика и попытка активации функций
В этой части мы переходим от пассивного прослушивания CAN-шины к активной отправке запросов и изучению ответов.
Здесь нужен очевидный дисклеймер о том, что неудачное компостирование мозгов мотоцикла может превратить его в беговел. Если вы новичок - потренируйтесь сначала на блоках с разборки, окирпичив пару штук на столе.
Поиск информации
Предварительно внимательно изучаем сервисную документацию на предмет полезной информации о диагностике. В PDF-файлах нашлись таблицы ошибок для некоторых блоков и описание фирменного софта для диагностики D-SCAN, который работает со своим специализированным интерфейсом.
Софт D-SCAN на момент проведения экспериментов распространялся свободно, но для его работы, естественно, нужны зарегистрированный логин, подключение к интернету и тот самый интерфейс. Впрочем, много полезной информации можно получить и не запуская софт, достаточно внимательно изучить его файлы. Особый интерес представляют текстовые файлы популярных форматов CSV, XML и JSON, в них могут содержаться описания ошибок (DTC), идентификаторы данных (DID) и многое другое.
Чтение и толкование ошибок
Для установления UDS сессии нужно знать два CAN ID - по одному мы передаем запрос, а по другому слушаем ответ. Их можно подобрать самостоятельно или подсмотреть в файлах D-SCAN:
| module | tx id | rx id | |--------|-------|-------| | ECU | 0x7E0 | 0x7E8 | | ABS | 0x7E1 | 0x7E9 | | CLU | 0x714 | 0x794 |
Блок управления двигателем без проблем читается любым стандартным OBDII-сканером, поэтому его можно пропустить и сразу перейти к проприетарным блокам - панели приборов и блоку ABS.
Для чтения ошибок будем использовать UDS-сервис 0x19 "Read DTC Information", а разобраться с форматом ошибок нам помогут стандарты ISO 15031-6 и SAE J2012.
Ошибки приборной панели
Таблица DTC для приборной панели
DTC |
Description |
|---|---|
B111716 |
Vehicle power supply voltage below threshold |
B111717 |
Vehicle power supply voltage above threshold |
U007388 |
CAN bus off fault of BICAN |
B110011 |
SWC Up key short to GND |
B111011 |
SWC Down key short to GND |
B112011 |
SWC Left key short to GND |
B113011 |
SWC Right key short to GND |
U220D00 |
LimpHome DTC |
U114087 |
Lost ABS communicaiton |
U118087 |
Lost TBOX communicaiton |
U11C087 |
Lost BCM communicaiton |
U11C487 |
Lost communication of PEPS |
B114016 |
TPMS Low Battery |
Информации о CAN ID и базового понимания UDS достаточно, чтобы самостоятельно стряпать запросы на чтение ошибок и попытаться понять, на что жалуется блок. Потренируемся на приборке и спросим, какие у нее есть ошибки:
-> 19 02 09 <- 59 02 09 C0 73 88 08
Панель сразу возвращает одну единственную ошибку 0xC0738808:

Составляем строку "TEXT" слева направо: U - ошибка относится к Network, 0 - ошибка стандартная и ее действительно можно найти в SAE J2012; в документации CFMOTO она называется "CAN bus off fault of BICAN". Тип ошибки - "Bus off", что порождает забавную тавтологию, статус ошибки - ошибка подтверждена.
Возможно она возникла из-за ненадежного подключении к CAN-шине, что довело приборную панель до состояния "Bus off".
Ошибки блока ABS
Таблица DTC блока ABS
DTC |
Description |
|---|---|
C102100 |
ABS Control unit failure |
C101900 |
ABS Valve relay failure |
C105400 |
ABS Inlet valve failure Front |
C105200 |
ABS Inlet valve failure Rear |
C104900 |
ABS Outlet valve failure Front |
C104800 |
ABS Outlet valve failure Front Rear |
C105900 |
ABS Voltage High |
C105800 |
ABS Voltage Low |
C101500 |
ABS Pump Failure |
C101700 |
ABS Motor Failure |
C103300 |
ABS WSS ohmic failure Front |
C103100 |
ABS WSS ohmic failure Rear |
C103400 |
ABS WSS plausibility failure Front |
C103200 |
ABS WSS plausibility failure Rear |
C103600 |
WSS long-term signal disturbance (Suspicious) Front |
C103700 |
WSS long-term signal disturbance (Suspicious) Rear |
C102400 |
ABS WSS generic failure |
U292200 |
CAN Bus Off Failure |
U292100 |
CAN Controller generic failure |
U292400 |
CAN Engine Frame failure |
U292500 |
CAN Engine Signal failure |
U293400 |
CAN BCM timeout/DLC failure |
U292900 |
CAN gear frame failure |
U293200 |
CAN gear signal failure |
U294400 |
CAN Meter Info timeout/DLC failure |
C110000 |
Wrong variant in FEE/NVM |
C120000 |
Variant out of Range in FEE/NVM |
U293100 |
Net over voltage |
U293000 |
Net under voltage |
Отправляем запрос на чтение ошибок:
-> 19 02 2f <- 7f 19 78 <- 59 02 2f 50 34 00 28 e9 32 00 28
Блок попросил нас подождать (0x78 = "Request Correctly Received - Response Pending"), а затем выдал 2 ошибки 0x50340028 и 0xe9320028:

Что общего у этих двух ошибок:
они обе кастомные, из диапазона "Manufacturer Controlled", и их описаний нет в стандартах;
они обе не используют Failure Type Byte, информация в базовом DTC полагается достаточной;
они обе подтверждены и возникли после последнего сброса памяти ошибок.
Ошибка C1034 означает, что сигнал с переднего датчика скорости валиден по электрическим характеристикам, но не выглядит корректным в сравнении с другими данными, например, передает скорость 10 км/ч, когда блок ABS однозначно считает, что мотоцикл стоит на месте. Если гуглить этот код, то находятся ошибки с похожим описанием у Ducati Monster и Harley-Davidson V-ROD, что однозначно намекает на кровное родство этих мотоциклов с "сифой".
Ошибка U2932 означает, что были проблемы с сигналом "Gear", который скорее всего содержит включенную передачу. Из составленной ранее DBC мы уже знаем, что отправителем этого сигнала является приборная панель, которая как раз падала в состояние "Bus off" с ошибкой U0073.
В целом, приведенных примеров достаточно для проведения несложной диагностики самостоятельно. Будут отличаться коды ошибок и их количество, но общая логика остается неизменной.
Знакомство с датчиками TPMS
Во время очередного поиска в интернете различных улучшайзингов для мотоцикла, я наткнулся на это:
Это штатные датчики давления шин для мотоциклов CFMOTO. Нюанс в том, что с завода они на 450MT никогда не ставились, так как предназначены для более дорогих моделей. На этой же странице лежит набор скриншотов на китайском (легко гуглится и на английском), описывающих процесс прописывания датчиков в приборке мотоцикла.
Только вот делается это через диагностический комплекс D-SCAN, которого у нас нет. Но если поискать в XML-файлах строки со скриншотов, то можно найти кусочки информации, которые склеиваются в рецепт ниже:
1) перевести панель в диагностическую сессию;
2) запросить seed и сгенерировать ответный key;
3) считать и отредактировать битовую маску конфигурации (DID 0xF010);
4) вписать уникальные идентификаторы датчиков (DID 0x0802).
Теоретически этот рецепт выполним своими силами, с помощью Python и подручного CAN-интерфейса. Для проверки на практике из Китая были заказаны два датчика TPMS с партномерами 6WWV-150850-5A01:

Гравировкой на корпус каждого датчика нанесен его ID длиной в 4 байта. В целях конспирации обзовем их 57 B1 XX XX и 57 B8 XX XX. Как показали дальнейшие эксперименты, ID датчиков абсолютно статичны и не меняются во время работы с ними, что потенциально удобно для слежки.
Датчики TPMS - сущности молчаливые и берегущие энергию. Чтобы заставить их передавать данные, нужно поместить их под давление, затем сбросить его. Обойтись без установки датчика в колесо нам поможет народный лайфхак - барокамера из бутылки с ниппелем:

Накачивая и стравливая давление туда-сюда велосипедным насосом, параллельно мониторим BLE эфир на предмет посылок от датчиков. В качестве софта для мониторинга я использовал InsideBlue BLE Tool, в нем было удобно фильтровать датчики по строке "TPMSS" в имени:
Обратите внимание, как ID датчиков рифмуются с их BLE MAC-адресами:
57 B1 XX XX = 57:B1:00:00:XX:XX 57 B8 XX XX = 57:B8:00:00:XX:XX
Зная TPMS ID, можно получить BLE MAC, достаточно раздвинуть байты посередине и вставить туда нули. Так ли это для всех датчиков - неизвестно, но эти два оказались именно такими.
Каждая из полезных посылок имеет размер в 17 байт. Попробуем разбить ее на отдельные поля и придать им смысл:
| ? | TPMS ID | pressure | temperature | battery? | BLE MAC | | XXXXXXXX | 57B1XXXX | 63 | 15 | BB | 57B10000XXXX |
Первое поле полезной нагрузки не несет, в нем содержится нечто вроде счетчика посылок. После него однозначно определяются: TPMS ID, давление, температура и BLE MAC.
Давлению в 310 kPa на панели соответствовало сырое значение 0x63 (99). Подходящий коэффициент перевода должен быть в районе 3.1. Если прикидывать точнее, то наиболее вероятно он равен 3.125 (800/256), где 800 kPa - это часто встречающийся предел измерения датчиков TPMS, а на 256 легко делить битовым сдвигом. Проверим наш пример:
С температурой все еще проще, достаточно перевода в десятичный вид: 0x15 = 21 градусов Цельсия.
Кроме этих данных по-хорошему датчик должен передавать уровень заряда своей батарейки, чтобы оповещать водителя о ее разряде. Возможно уровень содержится в поле "battery?".
Поиск алгоритма расчета ключа
Вернемся к рецепту из прошлого пункта, поскольку в нем осталось белое пятно. Нам известно все, кроме алгоритма расчета ключа, без него блок не даст доступа к записи.
В текстовом формате такие алгоритмы хранить не принято по понятным причинам, поэтому искать их нужно в исполняемых файлах.
В процессе поисков был найден DLL-файл с подозрительным названием, намекающим на принадлежность к приборной панели. Можно попробовать дизассемблировать его и извлечь алгоритм расчета, а можно пойти ленивым путем - научиться вызывать функцию и получать ее результат, например, из скрипта на Python. Анализ DLL показал, что внутри есть функция GenerateKeyEx(), а при поиске информации о ней в первых строчках всплывает application note от Vector с подробным описанием:
VKeyGenResultEx GenerateKeyEx ( const unsigned char* ipSeedArray, unsigned int iSeedArraySize, const unsigned int iSecurityLevel, const char* ipVariant, unsigned char* iopKeyArray, unsigned int iMaxKeyArraySize, unsigned int& oActualKeyArraySize );
Алгоритм расчета ключа могут паковать в DLL с подобным стандартизированным API, это позволяет производителю делиться алгоритмом с контрагентами, не открывая его исходники. Например, отдать блок и DLL в сертификационный орган, где может потребоваться доступ к закрытой диагностике для тестов. Кроме софта от Vector, с такими DLL "из коробки" еще умеет работать его китайский конкурент - TSMaster от компании TOSUN.
Поскольку DLL 32-битная, то и работать с ней нужно из 32-битной версией Python. Напишем простой скрипт, вызывающий функцию GenerateKeyEx():
import ctypes mylib = ctypes.WinDLL("./XXXX.dll") seed = (ctypes.c_ubyte * 4)(0x12, 0x34, 0x56, 0x78) # seed from the ECU, e.g. 12345678 key = (ctypes.c_ubyte * 4)() # contains the key (after DLL call) keylength = ctypes.c_uint(4) # contains the actual key length (after DLL call) mylib.GenerateKeyEx( ctypes.pointer(seed), # seed from the ECU ctypes.c_uint(4), # seed length = 4 bytes ctypes.c_uint(1), # security Level = 1 ctypes.POINTER(ctypes.c_int)(), # NULL = No variant string ctypes.pointer(key), # key to send back to the ECU ctypes.c_uint(4), # max key length = 4 bytes ctypes.pointer(keylength), # actual key length = 4 bytes )
Убеждаемся, что скрипт действительно импортирует DLL и дергает из нее нужную функцию, дописываем в него взаимодействие с блоком по CAN-шине. И проверяем корректность расчета ключа, не забыв перейти в расширенную диагностическую сессию:
# switch to extended diagnostic session -> 10 03 <- 50 03 00 32 01 f4 # get seed -> 27 01 <- 67 01 af e7 ce 25 # send key -> 27 02 a0 a1 a0 b0 <- 67 02
Ключ действительно подходит! Переходим к следующей операции - активации отображения TPMS-информации. Рецепт состоит из нескольких шагов, для наглядности процесса мы будем выполнять их по очереди, отслеживая реакцию приборки после каждого шага.
Обратите внимание на выделенный участок экрана приборной панели, сейчас там пусто:

Считываем дефолтную конфигурацию, редактируем бит отвечающий за наличие TPMS, записываем обратно:
# read configuration -> 22 f0 10 <- 62 f0 10 00 00 00 80 04 00 2c 80 00 00 00 00 00 00 00 00 # write configuration -> 2e f0 10 00 00 00 80 44 00 2c 80 00 00 00 00 00 00 00 00 <- 6e f0 10
После таких операций панель начала ругаться по-китайски, онлайн-переводчик перевел эти иероглифы, как "НЕОБУЧЕНО!":

Похоже теперь панель ждет записи TPMS ID для привязки датчиков. Поскольку один DID содержит сразу оба TPMS ID, пока непонятно, какой из них окажется передним, а какой - задним. Порядок бит тоже неизвестен, поэтому для первой попытки пишем как читаем:
# read TPMS IDs -> 22 08 02 <- 62 08 02 ff ff ff ff ff ff ff ff # write TPMS IDs -> 2e 08 02 57 b1 xx xx 57 b8 xx xx <- 6e 08 02
По умолчанию поля TPMS ID забиты FF-ами и панель это воспринимает, как признак необученности. После привязки ругательства исчезли и появилась индикация давления и температуры, заполненная прочерками. Панель ждет, когда датчики выйдут на связь:

Наступил момент истины - закидываем датчики в бутылку и по отработанной схеме пробуждаем их:

Вот и все! Привязываем бутылку к мотоциклу и наслаждаемся уникальной возможностью отслеживать давление внутри нее.
По очереди пытая датчики в бутылке, устанавливаем, что 57 B1 XX XX прописался в качестве переднего, а 57 B8 XX XX - заднего. Порядок бит тоже оказался правильным.
Уже после активации и привязки датчиков TPMS, в CAN-шине ожил фрейм 0x30E и в нем обнаружились значения давлений и температур, которые были добавлены в DBC-файл. Возможно эти значения должен слушать опциональный блок телематики, для дальнейшей передачи в приложение пользователя.
Заключение
Хоть в современных мотоциклах и меньше блоков управления, чем в автомобилях, исследовать их не менее интересно.
Мотоциклетная CAN-шина содержит множество полезной информации, которую можно использовать на свое усмотрение - логировать и анализировать поездки, считывать диагностическую информацию и не только.