# Анализ причин отказа 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)`.