bump v1.11.0-dev
This commit is contained in:
@@ -1,86 +1,40 @@
|
||||
# Анализ деградации ELM-кода в v1.9.0 и план исправления
|
||||
# Анализ: ELM327 динамический тест
|
||||
|
||||
## 1. Почему v1.9.0 стал ХУЖЕ (ни одного ответа)?
|
||||
## 1. exec() — retry с повторной write(cmd) — ГЛАВНЫЙ БАГ
|
||||
|
||||
Главная причина — **отключение `drainInput()` в `write()`** совмещенное с агрессивной работой `exec()`.
|
||||
* В v1.3.0 `drainInput()` вызывался перед каждой командой. Если ELM "подлагивал" и присылал ответ на предыдущую команду с опозданием, `drainInput()` вычищал этот мусор, и `read()` начинал ждать с чистого листа.
|
||||
* В v1.9.0 `drainInput()` выключен. Если первая команда батча (`010C`) дает таймаут, `exec()` делает **10 RETRY**.
|
||||
* Сценарий катастрофы:
|
||||
1. Послали `010C`. Тайм-аут.
|
||||
2. Послали `010C` (retry 1). В этот момент ELM прислал ответ на #1.
|
||||
3. `read()` в retry 1 видит ответ от #1, но ELM уже занят обработкой #2.
|
||||
4. Следующие команды накладываются друг на друга. Буфер Bluetooth забивается ответами, которые не соответствуют командам.
|
||||
5. ELM v1.5 "захлебывается" потоком данных в TX-буфере и перестает отвечать на новые команды вовсе.
|
||||
При таймауте ELM уже отправил запрос в CAN-шину и ждёт ответа от ЭБУ. write(cmd) снова вызывает drainInput() — сбрасывает буфер с ответом, которого мы ждём — и шлёт команду повторно. ELM получает 010C пока обрабатывает предыдущий 010C → BUFFER FULL / зависание. 10 retry = 10 одновременных CAN-запросов. Статика не задевает этот путь, потому что там таймауты не случаются (пауза между командами — секунды).
|
||||
|
||||
## 2. Нужен ли ATWS перед динамикой?
|
||||
## 2. Почему v1.9.0 (без drainInput) стало хуже
|
||||
|
||||
**Да, но с нюансами.**
|
||||
* `ATWS` (Warm Start) гарантирует, что ELM забыл про "SEARCHING" и сбросил внутренние ошибки протокола.
|
||||
* **Ожидание после `ATWS`:** Минимум **1000мс** (на v1.3 было 300мс — мало, на v1.9 вообще убрали).
|
||||
* **ВАЖНО:** После `ATWS` нужно заново послать `ATE0`, `ATL0`, `ATS0`, так как Warm Start сбрасывает их в дефолт.
|
||||
drainInput() в write() — единственный механизм синхронизации запрос/ответ. Без него:
|
||||
|
||||
## 3. Нужен ли drainInput() в write()?
|
||||
- Ответ на команду N читается как ответ на команду N+1
|
||||
- read() видит > из старого ответа — возвращает мусор, считает успехом
|
||||
- К 3-му PID цикла батча сдвиг накопился: ответы не совпадают с командами
|
||||
- BT-буфер на стороне ELM забивается необработанными данными → ELM перестаёт отвечать
|
||||
|
||||
**Да, обязательно**. Но не просто "чистка всего", а **синхронизация**.
|
||||
Для ELM327 принцип "запрос-ответ" свят. Мы не имеем права слать новую команду, пока не получили `>` от предыдущей ИЛИ не дождались таймаута И вычистили буфер.
|
||||
В v1.3.0 drainInput() маскировал проблему retry: хотя бы буфер чистился перед каждой командой.
|
||||
|
||||
## 4. Почему статика работает?
|
||||
## 3. ATWS — нужен ли, сколько ждать
|
||||
|
||||
В статике между командами проходят секунды (пока поток UI обработает, пока лог запишется). Этого времени хватает ELM, чтобы "прочихаться". В динамике команды идут пачками, что превращает любую задержку адаптера в фатальный рассинхрон.
|
||||
Нужен: сбрасывает SEARCHING..., очищает внутренние ошибки CAN-протокола ELM.
|
||||
|
||||
## 5. Retry в `exec()` с переповтором команды — ГЛАВНЫЙ БАГ.
|
||||
Проблемы текущего использования:
|
||||
- Пауза 800 мс — мало. CAN-шина после warm start поднимается 700–1000 мс, плюс ATSP0 negotiate. Нужно 1200–1500 мс.
|
||||
- После ATWS ELM сбрасывает настройки в дефолт: ATE1 (эхо ON), ATL1 (LF ON), ATS1 (пробелы ON). Код не восстанавливает ATE0/ATL0/ATS0 → read() начинает видеть эхо команды и переносы строк → парсинг ломается.
|
||||
|
||||
Повторная отправка OBD-команды (`010C`) при таймауте — это **яд для ELM327**.
|
||||
Команда OBD — это не просто AT-запрос. ELM должен отправить запрос в CAN-шину, дождаться ответа от ЭБУ, отформатировать его и выдать. Если мы шлем `010C` второй раз, когда ELM еще ждет ответа от CAN, он может либо зависнуть, либо выдать `BUFFER FULL`.
|
||||
## 4. sleep(350) между PID — правильно?
|
||||
|
||||
---
|
||||
Для ELM327 v1.5 — приемлемо. Адаптер не успевает переключаться быстрее 100–200 мс между разными PID (CAN frame turnaround). Но 350 мс не решает проблему, потому что рассинхрон возникает раньше — внутри retry в exec(). Пауза между командами маскирует, но не лечит.
|
||||
|
||||
# Необходимые правки кода
|
||||
## 5. Почему статика работает, динамика нет
|
||||
|
||||
### 1. `ElmProtocol.kt`: Убрать вредный retry OBD-команд
|
||||
Статика: пауза между командами — секунды (UI-обработка). ELM успевает ответить. Retry не срабатывает. Накопления сдвига нет.
|
||||
|
||||
```kotlin
|
||||
// В методе exec():
|
||||
// БЫЛО:
|
||||
for (i in 0 until MAX_RETRIES) {
|
||||
write(cmd) // ← НЕЛЬЗЯ ПЕРЕПОСЫЛАТЬ OBD-команду!
|
||||
// ...
|
||||
}
|
||||
Динамика: пауза 350–500 мс. При первом таймауте retry запускает цепочку дублей. Синхронизация батча ломается. Следующий батч начинается на сломанном состоянии.
|
||||
|
||||
// НАДО:
|
||||
private fun exec(cmd: String, timeout: Long): String {
|
||||
write(cmd)
|
||||
var t = timeout
|
||||
try {
|
||||
return handle(read(t))
|
||||
} catch (_: TimeoutException) {
|
||||
increaseTimeout()
|
||||
// Очищаем буфер, так как команда "протухла"
|
||||
drainInput()
|
||||
return ""
|
||||
}
|
||||
}
|
||||
```
|
||||
## Итог: приоритет причин
|
||||
|
||||
### 2. `ElmProtocol.kt`: Вернуть `drainInput()` в `write()`
|
||||
Без него мы читаем ответы на позапрошлые команды.
|
||||
|
||||
### 3. `DynamicCollector.kt`: Добавить микро-паузу между PID
|
||||
ELM v1.5 физически не может переключаться между PID быстрее чем за 100-200мс.
|
||||
|
||||
```kotlin
|
||||
// В цикле for (step in steps):
|
||||
val raw = elm.sendCommand(step.cmd)
|
||||
Thread.sleep(150) // Пауза для стабильности v1.5
|
||||
```
|
||||
|
||||
### 4. `MainActivity.kt`: Правильная инициализация перед тестом
|
||||
```kotlin
|
||||
// Перед стартом DynamicCollector:
|
||||
elmProto.sendCommand("ATWS")
|
||||
Thread.sleep(1200) // Ждем инициализации
|
||||
elmProto.sendCommand("ATE0") // Эхо выкл
|
||||
elmProto.sendCommand("ATL0") // Переносы выкл
|
||||
elmProto.sendCommand("ATS0") // Пробелы выкл (КРИТИЧНО для скорости)
|
||||
elmProto.drainInput()
|
||||
```
|
||||
1. exec() повторяет write(cmd) при таймауте — нельзя дублировать OBD-команды в CAN (первична)
|
||||
2. Убрали drainInput() в write() — потеряна синхронизация запрос/ответ
|
||||
3. После ATWS не восстанавливают ATE0/ATL0/ATS0 — парсинг ответов ломается
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
<img src="/static/logo.png" alt="elmAI" style="width:96px;height:96px;border-radius:20px;margin-bottom:10px;">
|
||||
<h1>elmAI</h1>
|
||||
<p class="subtitle">Диагностика авто через ELM327 + ИИ</p>
|
||||
<p class="subtitle" style="font-size:12px;opacity:0.7;">v1.10.0-dev — 7 июня 2026</p>
|
||||
<p class="subtitle" style="font-size:12px;opacity:0.7;">v1.11.0-dev — 7 июня 2026</p>
|
||||
|
||||
<div class="card" style="text-align:center;margin-bottom:20px;">
|
||||
<p style="margin:0 0 10px 0;">📱 Скачай приложение на телефон:</p>
|
||||
<a href="/static/app-debug.apk" style="color:#ff6b35;font-size:18px;font-weight:bold;text-decoration:none;">
|
||||
⬇️ Скачать elmAI APK
|
||||
</a>
|
||||
<p style="font-size:11px;opacity:0.6;margin:4px 0 0 0;">v1.10.0-dev • нажмите чтобы скачать</p>
|
||||
<p style="font-size:11px;opacity:0.6;margin:4px 0 0 0;">v1.11.0-dev • нажмите чтобы скачать</p>
|
||||
</div>
|
||||
|
||||
<!-- Кнопка десктоп-диагностики скрыта — только для разработчика с прямым ELM327 -->
|
||||
|
||||
Reference in New Issue
Block a user