Elm327 відправка довгих команд на can шину

Shr lnm
Я їжджу на Renault Megane II
Москва, Росія

Те про що я буду писати нижче, цікаво напевно тільки програмістам, які збираються написати що-небудь для роботи з CAN шиною через ELM327 або для дуже захоплених людей, які вже пробували працювати з ELM через термінал. Якщо Ви, шановний читачу, швидше за звичайний користувач, то час на читання витрачати не варто, оскільки ці знання Вам навряд чи стануть в нагоді.

На зовсім прості речі довго зупинятися на буду і зосереджуся на описі того, як працювати з різними блоками на CAN шині (а не тільки з ЕБУ уприскування) і як посилати довгий команди і приймати довгі відповіді на них. Заодно коротко опишу як влаштовані фрейми даних на CAN шині.

В самому кінці статті я приведу лог цілком, а поки розберу процес ініціалізації ELM

> [17: 03: 57.524] at ws
<[0.025]at ws

>

Всі логи нижче будуть приблизно в такому форматі. Знаком ">" відзначені посилаються команди і в квадратних дужках, як Ви здогадалися, зазначено час відправки з точністю до мілісекунди, а знаком "<” отмечены отклики ELM и в квадратных скобках указано время отклика в секундах. Т.е. здесь ответ на команду ATWS пришел через 25 миллисекунд.
ATWS я використовую замість ATZ тому, що ATWS не скидати настройки швидкості COM порту і на початку роботи програми її можна "м'яко" підвищити командою ATBRD

>

Тут включаємо відлуння

>

Тут для економії трафіку на COM порте відключаємо непотрібні пропуски

>

Тут ми відключаємо видачу заголовків фреймів, оскільки там немає для нас нічого цікавого

>

Ще трохи економимо на "line feed", ми ж працюємо не руками через термінал.

Далі команди цікавіше.

>

Команда ATAL дозволяє передавати на CAN шину не 7 байт, як це зроблено за умовчанням, а 8. У CAN фрейм влазить не більше 8 байт, причому перший з них несе особливе значення і власне не відноситься до даних. За замовчуванням, цей байт підставляє сам ELM і цей процес називається "CAN autoformatting", про який мова піде слідом.
Старші 4 біта цього байта можуть мати значення 0, 1, 2 або 3 (це не стосується системних фреймів, де і перший байт фрейма несе в собі дані і відповідно може може мати будь-яке значення)
"0" означає що це єдиний фрейм в послідовності і в молодших 4 бітах вказується довжина команди (але не більше 7)
"1" означає, що це перший фрейм послідовності передавальної довгу команду. Усі наступні будуть починатися з "2". Молодші 4 біти цього байта і весь наступний байт несуть в собі довжину команди. З цього випливає, що одна команда може містити не більше 4095 байт і ще це означає, що в першому фреймі у нас залишилося всього 6 байт під дані
"2" ставиться на початку кожного наступного фрейму в послідовності і молодші 4 біти тут містять циклічно біжить каунтер, за яким можна відстежувати втрати (правда не вийде відстежити 16 послідовних втрат, але це вкрай мало ймовірно)
"3" означає що цей фрейм у нас FlowControl. У ньому немає даних а тільки службова інформація про управління поткамі даних.

Тут відразу зупинюся на вмісті фрейма FlowControl. У ньому всього 3 значущих байта і надсилаються вони приймаючою стороною.
1 байт - старші 4 біти містять "3" (як ми вже знаємо) і молодші 4 біти можуть набувати наступних значень (0 = Clear To Send, 1 = Wait, 2 = Overflow / abort)
2 байт - BS (block size або burst size) кількість фреймів, яке посилає сторона може послати один за одним не чекаючи наступного фрейму FlowControl від приймаючої сторони
3 байт - STmin (Separation Time minimum) або мінімальний допустимий час між черговими фреймами в мілісекундах. Цей байт може приймати значення від 0x00 до 0xF9, причому, якщо значення менше 0xF1 то це мілісекунди, а якщо значення від 0xF1 до 0xF9, то в останній цифрі містяться сотні мілісекунд. Так. 0xF1 - 100 мс, а 0xF9 - 900 мс. При цьому, зверніть увагу, що це мінімальне значення запитувана приймаючою стороною, але ви можете посилати фрейми рідше.

> [17: 03: 57.629] at caf0
<[0.016]at caf0
OK

>

ATCAF0 відключає автоматичне форматування фреймів для CAN шини. Це означає, що ділити нашу довгу команду на фрейми і підставляти перший байт, про який ми щойно говорили, ми відтепер будемо самостійно.

> [17: 03: 57.645] at cfc0
<[0.016]at cfc0
OK

ATCFC0 відключає автоматичну обробку фреймів FlowControl. У більшості випадків, включати такий режим немає необхідності. Правильний ELM нормально справляється з цим завданням і відправляти довгі команди зазвичай виходить і без цього (якщо приймаюча сторона досить швидка), але от прийняти довгий відповідь може не вийти з обмежену швидкість роботи COM порту.

Тепер приступимо до налаштування CAN для роботи з панеллю приладів.

> [17: 03: 57.677] at cra 763
<[0.016]at cra 763
OK

>

Налаштовуємо RX Filter на CAN ID = 0х763, з цим CAN ID будуть приходити відповіді на наші запити від приладової панелі, і щоб не відволікати ELM на обробку системних фреймів ми явно вказали, звідки потрібно чекати відповіді.

> [17: 03: 57.693] at fc sh 743
<[0.016]at fc sh 743
OK

Тут ми почали налаштовувати параметри для автоматичного FlowControl. В даному випадку це зайве, оскільки ми раніше відключили автоматичний FC, але для порядку налаштуємо. ATFCSH встановлює CAN ID для відправляються фреймів FlowControl і він дорівнює тому, що ми ставили в команді ATSH

> [17: 03: 57.709] at fc sd 30 00 00
<[0.016]at fc sd 30 00 00
OK

Тут встановлюється дефолтний значення відправляються фреймів FC. BS = 0 означає, що ми готові прийняти будь-яку кількість фреймів. STmin = 0 означає, що ми готові приймати їх з будь-яким інтервалом, так швидко як тільки зможе послати наша приладова панель.

> [17: 03: 57.725] at fc sm 1
<[0.016]at fc sm 1
OK

ATFCSM1 означає, що ELM повинен керуватися параметрами FC, які ми тільки що встановили.

> [17: 03: 57.741] at st ff
<[0.016]at st ff
OK

Установка внутрішнього таймера ELM, протягом якого він очікує відповідь про ЕБУ. Значення цього таймера автоматично регулюється самим ELM для забезпечення оптимального часу відгуку. ELM чомусь не заглядає всередину фреймів, а саме в їх перший байт, інакше він би "знав" коли всі фрейми відповіді отримані і коли передача закінчена. Замість цього ELM має цей таймер і динамічно оптимізує його, правда є можливість відключити цю автоматичне підстроювання і іноді це необхідно.

> [17: 03: 57.757] at at 0
<[0.016]at at 0
OK

>

Відключаємо адаптивний таймінг, тобто підстроювання таймера st, який ми вище виставили в максимальне значення. Нам це необхідно для ініціалізації протоколу, яку ми далі будемо робити і просто для скидання його, оскільки ми перемикається на роботу з новим блоком.

> [17: 03: 57.773] at sp 6
<[0.016]at sp 6
OK

Тут ми переключили ELM в режим роботи по шині CAN зі швидкістю 500 Кбіт / сек. (При цьому потрібно пам'ятати, що реальна пропускна здатність в перерахунку на корисні дані, буде в районі 280 Кбіт / сек)

> [17: 03: 57.789] at at 1
<[0.016]at at 1
OK

Знову включаємо адаптивний таймінг - тепер він нам стане в нагоді.

Починаємо працювати безпосередньо з панеллю приладів.

Тут зі знака # починається лог вставлений програмою pyren. В даному випадку він означає, що після відправки предидущей команди пройшло більше 5 секунд і швидше за все діагностична сесія до ЕБУ закрилася з таймаут - так чинить більшість ЕБУ. В цьому випадку потрібно повторити команду відкриття сесії перед відправкою наступних команд.

>

А тут довгий відповідь на команду 2181. Це команду читання поточного VIN з приладової панелі. Послідовність дій така:
1) відправляємо команду 2181, попередньо обвіс її "02" спереду і "1" ззаду
2) отримуємо перший фрейм відповіді "1015618131313131" Тут усе своєю чергою "1"-означає, що відповідь буде складатися з декількох фреймів, наступні 12 біт "015" - це дина очікуваної відповіді 0х015 = 21 байт (2 байта позитивної відповіді + 17 байт VIN коду + 2 байта CRC). У першому фреймі ми отримали тільки 6 корисних байт "618131313131" (як перевірити що це початок позитивної відповіді ми вже знаємо). Залишилося отримати (21-6) / 7 = 3 фрейма.
3) щоб продовжити отримання відповіді ми повинні відправити фрейм FlowControl "300300". Нагадаю, перший байт "30" - власне означає, що це FC, другий байт "03" - ми говоримо посилає стороні, що готові прийняти три залишилися фрейма, третій байт "00" - означає, що ми готові приймати залишилися фрейми з максимальною швидкістю . Остання "3" як і раніше, призначена для ELM і повідомляє йому, що він повинен повернути нам відповідь, як тільки отримає три фрейми.
4) отримуємо залишилися фрейми. Вони все починаються з "2" і другим символом у нас просто лічильник, який біжить по колу від 0 до F. Далі в кожному фреймі (крім останнього) по 7 байт даних. В останньому тільки один байт даних і 6 байт паддінга до 8 байт.

Таким чином ми отримали відповідь "618131313131" + "31313131313131" + "3131313131319F" + "B5". Як бачимо, VIN код у нас складався з 17 одиниць в ASCII коді і CRC = "9FB5".

Тепер сформуємо і відправимо команду на запис нового VIN складається з 17 двійок. Команда записи VIN в моїй приладової панелі "3B81". За нею повинно бути 17 байт в ASCII і 2 байта нового CRC. Разом, нам потрібно послати команду "3B8132323232323232323232323232323232327E70". Спочатку поділимо її на фрейми. У перший влізе 6 байт, в другій і третій по 7, а на останній залишиться 1 байт.

Поки ми розкладали команду на фрейми, пройшло більше 5 секунд і довелося знову відкривати сесію.
Тепер посилаємо перший фрейм (що означає 1015 в початку, ми вже знаємо)

У відповідь отримуємо від приладової панелі фрейм FC, який говорить нам, що слідом можна послати тільки один фрейм і не раніше ніж через 0х14 мс. "8484848484" - як завжди паддінг.

>

Відправили другий фрейм і отримали чергову вказівку як бути далі у вигляді нового FC

>

Відправили третій фрейм команди і знову отримали FC

І ось відправили останній фрейм команди і у відповідь отримали "037F3B23". "03" - означає, що відповідь на нашу довгу команду записи VIN складається з 3 байт "7F3B23". Відповідь починається з "7F" і це негативну відповідь, але засмучуватися поки рано. Давайте розшифруємо. Другий байт негативної відповіді дорівнює першому байту тієї команди до якої відноситься цей негативний відповідь. Третій байт "23" це код помилки і pyren для нас його розшифрував

# [0.380845069885] rsp: 7F 3B 23: NR: Routine Not Complete

Негативну відповідь тут означає, що панель приладів команду прийняла і почала її відпрацьовувати, але поки роботу не закінчила.
Подивимося що буде далі. Спробуємо вважати наш новий VIN і для цього знову відправляємо команду 2181

Але ми знову отримали негативну відповідь "7F2121". Тепер вже на команду "21" і код помилки тут теж "21". Цей код помилки означає "NR: Busy Repeat Request". Тобто приладова панель ще зайнята виконанням предидущей команди і просить нас повторити команду через якийсь час. Pyren чекає 500 мс і повторює команду

>

Цього разу ми отримали позитивну відповідь і з нього видно, що наш новий VIN в приладовій панелі складається з 17 двійок.

Тепер для зручності повторю весь лог разом без моїх нудних коментарів