Files
elmer/doc/claude-analysis-elm-v2.md
T

87 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Анализ деградации ELM-кода в v1.9.0 и план исправления
## 1. Почему v1.9.0 стал ХУЖЕ (ни одного ответа)?
Главная причина — **отключение `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-буфере и перестает отвечать на новые команды вовсе.
## 2. Нужен ли ATWS перед динамикой?
**Да, но с нюансами.**
* `ATWS` (Warm Start) гарантирует, что ELM забыл про "SEARCHING" и сбросил внутренние ошибки протокола.
* **Ожидание после `ATWS`:** Минимум **1000мс** (на v1.3 было 300мс — мало, на v1.9 вообще убрали).
* **ВАЖНО:** После `ATWS` нужно заново послать `ATE0`, `ATL0`, `ATS0`, так как Warm Start сбрасывает их в дефолт.
## 3. Нужен ли drainInput() в write()?
**Да, обязательно**. Но не просто "чистка всего", а **синхронизация**.
Для ELM327 принцип "запрос-ответ" свят. Мы не имеем права слать новую команду, пока не получили `>` от предыдущей ИЛИ не дождались таймаута И вычистили буфер.
## 4. Почему статика работает?
В статике между командами проходят секунды (пока поток UI обработает, пока лог запишется). Этого времени хватает ELM, чтобы "прочихаться". В динамике команды идут пачками, что превращает любую задержку адаптера в фатальный рассинхрон.
## 5. Retry в `exec()` с переповтором команды — ГЛАВНЫЙ БАГ.
Повторная отправка OBD-команды (`010C`) при таймауте — это **яд для ELM327**.
Команда OBD — это не просто AT-запрос. ELM должен отправить запрос в CAN-шину, дождаться ответа от ЭБУ, отформатировать его и выдать. Если мы шлем `010C` второй раз, когда ELM еще ждет ответа от CAN, он может либо зависнуть, либо выдать `BUFFER FULL`.
---
# Необходимые правки кода
### 1. `ElmProtocol.kt`: Убрать вредный retry OBD-команд
```kotlin
// В методе exec():
// БЫЛО:
for (i in 0 until MAX_RETRIES) {
write(cmd) // ← НЕЛЬЗЯ ПЕРЕПОСЫЛАТЬ OBD-команду!
// ...
}
// НАДО:
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()
```