Files
elmer/doc/claude-analysis-elm.md
T
2026-06-10 22:44:43 +04:00

6.1 KiB
Raw Blame History

Анализ причин отказа ELM327 v1.5 при динамическом опросе

Анализ кода ElmProtocol.kt, DynamicCollector.kt и ElmChecker.kt выявил ряд критических проблем, которые в совокупности приводят к "зависанию" адаптера ELM327 (особенно дешевых клонов v1.5) при переходе к быстрому циклу опроса.

Ответы на вопросы

1. Почему ELM327 v1.5 замолкает после первых 2 ответов?

Основная причина — десинхронизация и переполнение буфера.

  • ATWS прямо перед циклом: Команда ATWS (Warm Start) сбрасывает микроконтроллер. Ему требуется время на инициализацию (обычно 500-1000 мс). Код в MainActivity ждет всего 300 мс. Первые команды 010C прилетают, когда ELM еще "просыпается" или находится в неопределенном состоянии.
  • Эффект домино в exec(): Если первый PID в цикле (010C) не успел ответить вовремя, exec возвращает пустую строку, но ELM продолжает обработку. Следующий вызов sendCommand через write() делает drainInput(), удаляя запоздавший ответ, и посылает новую команду. Для клона v1.5 типична ситуация, когда он "захлебывается", если получает новую команду, не закончив передачу предыдущего ответа или символа >.

2. Может ли drainInput() в write() съедать ответ?

Да, и это главная проблема надежности. Если ELM327 ответил на 50 мс позже таймаута, данные уже лежат в буфере Bluetooth-сокета. Вызов write() для следующей команды в цикле безусловно их очищает. В итоге read() следующей команды видит пустоту, провоцируя новые таймауты и ретраи. Происходит рассинхрон: приложение ждет ответ на команду B, а ELM (если не завис) шлет ответ на команду A.

3. Критична ли последовательность: static -> speed-test -> ATWS -> dynamic?

Последовательность перегружена сбросами.

  • ATWS сбрасывает настройки ATAT1, ATSP, ATL0 и т.д., которые были установлены в init().
  • После ATWS протокол может вернуться к AUTO (ATSP0), что заставляет ELM тратить время на "SEARCHING..." при первом же запросе 010C. Это гарантированный таймаут в динамическом тесте.

4. Нужно ли переподключать ELM вместо ATWS?

Переподключать Bluetooth-сокет не обязательно, но вместо ATWS лучше вызвать серию настроечных команд, гарантирующих состояние:

  1. ATE0 (эхо выкл)
  2. ATL0 (переносы строк выкл)
  3. ATS0 (пробелы выкл) — крайне важно для скорости и предотвращения переполнения буфера.
  4. ATSP X (принудительная установка протокола, найденного в checkDevice), чтобы исключить стадию поиска.

5. Как правильно реализовать динамический опрос для v1.5?

Для минимизации ошибок на медленных адаптерах:

  1. Убрать Thread.sleep(350) внутри цикла for (step in steps). Пауза должна быть только между пакетами (батчами) PID, если нужно ограничить частоту. Внутри батча команды должны идти максимально плотно: послал -> дождался > -> сразу следующий.
  2. Увеличить таймаут для v1.5. 500 мс — это предел для v1.5. Первичный запрос (особенно после сброса) может занимать до 1500 мс.
  3. Оптимизировать read(): v1.5 очень чувствителен к таймингам. Текущий Thread.sleep(1) в read() — это хорошо, но логика drainInput должна быть перемещена: чистить буфер нужно только один раз перед стартом всего динамического теста, а не перед каждой командой.

Рекомендации по исправлению

  1. В ElmProtocol.kt:
    • Сделать drainInput() опциональным параметром в write() или убрать его из sendCommand по умолчанию.
    • В handle() при получении NODATA или ERROR не делать ATWS мгновенно, так как это убивает сессию опроса.
  2. В DynamicCollector.kt:
    • Удалить Thread.sleep(350) в цикле for. Вместо этого полагаться на таймауты ElmProtocol.
  3. В MainActivity.kt:
    • Убрать ATWS перед стартом. Если нужен сброс — использовать ATZ и ждать 2 секунды, после чего заново прогнать весь init().
    • Перед запуском DynamicCollector зафиксировать протокол: elmProto.sendCommand("ATSP" + currentProtocol).