diff --git a/obd/protocol.py b/obd/protocol.py index 5243fb8..d95a3ed 100644 --- a/obd/protocol.py +++ b/obd/protocol.py @@ -56,6 +56,7 @@ class AndrOBD: INIT_TMO = 10000 # мс — таймаут для команд инициализации DEF_TMO = 200 # мс — начальный таймаут + ATST_CLONE = 0x96 # 150×4=600ms — фиксированный для клонов def __init__(self, port: str, baudrate: int = 38400): self._transport = SerialTransport(port, baudrate) @@ -73,20 +74,39 @@ class AndrOBD: self._transport.close() def init(self): - """Базовая инициализация ELM327 (уровень 0 — все клоны). + """Канонический init: ATE0→ATL0→ATS0→ATI→[ветвление]→ATSP0. - ТОЛЬКО команды которые есть у ВСЕХ клонов: - ATE0 ATL0 ATS0 ATH1 ATSP0 + Эхо ПЕРВЫМ. ATI ДО протокола. Клон: ATST фикс, без ATAT1. """ logger.info("AndrOBD: init (L0)") self._state = State.INITIALIZING + + # Шаг 1: clone-safe, без протокола self._exec("ATE0", self.DEF_TMO * 5) + self._transport.try_read(500) # drain после AT-команды self._exec("ATL0", self.DEF_TMO * 5) + self._transport.try_read(500) self._exec("ATS0", self.DEF_TMO * 5) - self._exec("ATH1", self.DEF_TMO * 5) + self._transport.try_read(500) + + # Шаг 2: ATI → detectClone ДО ветвления + ati = self._exec("ATI", self.DEF_TMO * 5) + self._transport.try_read(500) + is_clone = "v1.5" in ati.lower() + if is_clone: + logger.info("AndrOBD: clone v1.5 — ATST fixed, no ATAT1") + self._exec(f"ATST{self.ATST_CLONE:02X}", self.DEF_TMO * 5) + self._transport.try_read(500) + else: + self._exec("ATAT1", self.DEF_TMO * 5) + self._transport.try_read(500) + + # Шаг 3: протокол self._exec("ATSP0", self.INIT_TMO) + self._transport.try_read(500) + self._state = State.READY - logger.info("AndrOBD: ready (L0)") + logger.info(f"AndrOBD: ready (L0, clone={is_clone})") def init_l1(self): """Инициализация уровня 1: база + адаптивный тайминг.""" @@ -111,6 +131,7 @@ class AndrOBD: self._recover() self._state = State.BUSY result = self._exec(cmd, self._timing.ms) + self._transport.try_read(500) # drain после read — клон v1.5 if self._state == State.BUSY: self._state = State.READY return result