From 50431e20cc628c557c3e33cbbf7cb1502f464a59 Mon Sep 17 00:00:00 2001 From: ATATC Date: Thu, 14 Nov 2024 02:26:30 -0500 Subject: [PATCH 1/5] Added `SOBD`. (#447) --- leads/dt/sobd.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 leads/dt/sobd.py diff --git a/leads/dt/sobd.py b/leads/dt/sobd.py new file mode 100644 index 0000000..363c074 --- /dev/null +++ b/leads/dt/sobd.py @@ -0,0 +1,70 @@ +from typing import Literal as _Literal, override as _override + +from serial import Serial as _Serial + +from leads.comm import Entity, Callback, Service +from leads.dt.device import Device +from leads.logger import L +from leads_comm_serial import SerialConnection as _SerialConnection, AutoIdentity as _AutoIdentity + + +class SOBD(Device, Entity, _AutoIdentity): + def __init__(self, port: str | _Literal["auto"], baud_rate: int = 9600) -> None: + Device.__init__(self) + Entity.__init__(self, -1, _SOBDCallback(self)) + _AutoIdentity.__init__(self, port == "auto") + self._serial: _Serial = _Serial() + self._serial.baudrate = baud_rate + self._connection: _SerialConnection | None = None + self._serial.port = self.suggest_next_port() if port == "auto" else port + + @_override + def port(self) -> str: + return self._serial.port + + @_override + def initialize(self, *parent_tags: str) -> None: + super().initialize(*parent_tags) + self.start(True) + + @_override + def update(self, data: str) -> None: + # todo + pass + + @_override + def check_identity(self, connection: _SerialConnection) -> bool: + connection.send(b"ic") + return (msg := connection.receive()) and msg.startswith(self.tag().encode()) + + @_override + def run(self) -> None: + self._callback.on_initialize(self) + self._connection = self.establish_connection(self._serial) + self._callback.on_connect(self, self._connection) + self._stage(self._connection) + + @_override + def write(self, payload: bytes) -> None: + if not self._connection: + raise IOError("Target must be connected to perform this operation") + self._connection.send(payload) + + @_override + def close(self) -> None: + if self._connection: + self._connection.close() + + +class _SOBDCallback(Callback): + def __init__(self, sobd: SOBD) -> None: + super().__init__() + self._sobd: SOBD = sobd + + @_override + def on_receive(self, service: Service, msg: bytes) -> None: + self.super(service=service, msg=msg) + try: + self._sobd.update(msg.decode()) + except UnicodeDecodeError: + L.debug(f"Discarding this message: {msg}") From 09cae00a3d0fc6bf39c3a0c42a356f9aebed0a1f Mon Sep 17 00:00:00 2001 From: ATATC Date: Thu, 14 Nov 2024 13:43:51 -0500 Subject: [PATCH 2/5] Implemented `update()`. (#447) --- leads/dt/sobd.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/leads/dt/sobd.py b/leads/dt/sobd.py index 363c074..6e4d500 100644 --- a/leads/dt/sobd.py +++ b/leads/dt/sobd.py @@ -2,6 +2,7 @@ from serial import Serial as _Serial +from leads import require_config from leads.comm import Entity, Callback, Service from leads.dt.device import Device from leads.logger import L @@ -29,8 +30,10 @@ def initialize(self, *parent_tags: str) -> None: @_override def update(self, data: str) -> None: - # todo - pass + if data.startswith("dbl="): + require_config().w_debug_level = data[4:].upper() + else: + self.write("\n".join(L.history_messages()).encode()) @_override def check_identity(self, connection: _SerialConnection) -> bool: From 18a1b0e4bc6a73a2f645d4c9b4e76f46d21fc06a Mon Sep 17 00:00:00 2001 From: ATATC Date: Thu, 14 Nov 2024 13:44:18 -0500 Subject: [PATCH 3/5] Exported `SOBD`. (#447) --- leads/dt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/leads/dt/__init__.py b/leads/dt/__init__.py index 12a82d1..f137de8 100644 --- a/leads/dt/__init__.py +++ b/leads/dt/__init__.py @@ -3,3 +3,4 @@ from leads.dt.odometer import * from leads.dt.predefined_tags import * from leads.dt.registry import * +from leads.dt.sobd import * From 4c6bfdde17eb67168563319acab0d2d254ad0fa0 Mon Sep 17 00:00:00 2001 From: ATATC Date: Mon, 18 Nov 2024 09:32:20 -0500 Subject: [PATCH 4/5] Added authentication. (#447) --- leads/dt/sobd.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/leads/dt/sobd.py b/leads/dt/sobd.py index 6e4d500..e3a1e64 100644 --- a/leads/dt/sobd.py +++ b/leads/dt/sobd.py @@ -10,7 +10,7 @@ class SOBD(Device, Entity, _AutoIdentity): - def __init__(self, port: str | _Literal["auto"], baud_rate: int = 9600) -> None: + def __init__(self, port: str | _Literal["auto"], baud_rate: int = 9600, password: str = "") -> None: Device.__init__(self) Entity.__init__(self, -1, _SOBDCallback(self)) _AutoIdentity.__init__(self, port == "auto") @@ -18,6 +18,8 @@ def __init__(self, port: str | _Literal["auto"], baud_rate: int = 9600) -> None: self._serial.baudrate = baud_rate self._connection: _SerialConnection | None = None self._serial.port = self.suggest_next_port() if port == "auto" else port + self._password: str = password + self._locked: bool = password != "" @_override def port(self) -> str: @@ -30,6 +32,13 @@ def initialize(self, *parent_tags: str) -> None: @_override def update(self, data: str) -> None: + if data.startswith("pwd="): + if data[4:] != self._password: + self.close() + else: + self._locked = False + if self._locked: + return if data.startswith("dbl="): require_config().w_debug_level = data[4:].upper() else: From 59037091e932def81ce7f5b5b31ae1986b01b9a6 Mon Sep 17 00:00:00 2001 From: ATATC Date: Tue, 19 Nov 2024 10:12:14 -0500 Subject: [PATCH 5/5] Package reorganized. (#447) --- leads/dt/__init__.py | 1 - leads_comm_serial/__init__.py | 1 + leads_comm_serial/sobd/__init__.py | 1 + {leads/dt => leads_comm_serial/sobd}/sobd.py | 31 ++++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 leads_comm_serial/sobd/__init__.py rename {leads/dt => leads_comm_serial/sobd}/sobd.py (69%) diff --git a/leads/dt/__init__.py b/leads/dt/__init__.py index f137de8..12a82d1 100644 --- a/leads/dt/__init__.py +++ b/leads/dt/__init__.py @@ -3,4 +3,3 @@ from leads.dt.odometer import * from leads.dt.predefined_tags import * from leads.dt.registry import * -from leads.dt.sobd import * diff --git a/leads_comm_serial/__init__.py b/leads_comm_serial/__init__.py index a9b38a3..4d0be22 100644 --- a/leads_comm_serial/__init__.py +++ b/leads_comm_serial/__init__.py @@ -5,3 +5,4 @@ from leads_comm_serial.connection import * from leads_comm_serial.identity import * +from leads_comm_serial.sobd import * diff --git a/leads_comm_serial/sobd/__init__.py b/leads_comm_serial/sobd/__init__.py new file mode 100644 index 0000000..6e9756f --- /dev/null +++ b/leads_comm_serial/sobd/__init__.py @@ -0,0 +1 @@ +from leads_comm_serial.sobd import * diff --git a/leads/dt/sobd.py b/leads_comm_serial/sobd/sobd.py similarity index 69% rename from leads/dt/sobd.py rename to leads_comm_serial/sobd/sobd.py index e3a1e64..fe1d38a 100644 --- a/leads/dt/sobd.py +++ b/leads_comm_serial/sobd/sobd.py @@ -2,21 +2,20 @@ from serial import Serial as _Serial -from leads import require_config -from leads.comm import Entity, Callback, Service -from leads.dt.device import Device -from leads.logger import L -from leads_comm_serial import SerialConnection as _SerialConnection, AutoIdentity as _AutoIdentity +from leads import require_config as _require_config, Device as _Device, L as _L +from leads.comm import Entity as _Entity, Callback as _Callback, Service as _Service +from leads_comm_serial.connection import SerialConnection +from leads_comm_serial.identity import AutoIdentity -class SOBD(Device, Entity, _AutoIdentity): +class SOBD(_Device, _Entity, AutoIdentity): def __init__(self, port: str | _Literal["auto"], baud_rate: int = 9600, password: str = "") -> None: - Device.__init__(self) - Entity.__init__(self, -1, _SOBDCallback(self)) - _AutoIdentity.__init__(self, port == "auto") + _Device.__init__(self) + _Entity.__init__(self, -1, _SOBDCallback(self)) + AutoIdentity.__init__(self, port == "auto") self._serial: _Serial = _Serial() self._serial.baudrate = baud_rate - self._connection: _SerialConnection | None = None + self._connection: SerialConnection | None = None self._serial.port = self.suggest_next_port() if port == "auto" else port self._password: str = password self._locked: bool = password != "" @@ -40,12 +39,12 @@ def update(self, data: str) -> None: if self._locked: return if data.startswith("dbl="): - require_config().w_debug_level = data[4:].upper() + _require_config().w_debug_level = data[4:].upper() else: - self.write("\n".join(L.history_messages()).encode()) + self.write("\n".join(_L.history_messages()).encode()) @_override - def check_identity(self, connection: _SerialConnection) -> bool: + def check_identity(self, connection: SerialConnection) -> bool: connection.send(b"ic") return (msg := connection.receive()) and msg.startswith(self.tag().encode()) @@ -68,15 +67,15 @@ def close(self) -> None: self._connection.close() -class _SOBDCallback(Callback): +class _SOBDCallback(_Callback): def __init__(self, sobd: SOBD) -> None: super().__init__() self._sobd: SOBD = sobd @_override - def on_receive(self, service: Service, msg: bytes) -> None: + def on_receive(self, service: _Service, msg: bytes) -> None: self.super(service=service, msg=msg) try: self._sobd.update(msg.decode()) except UnicodeDecodeError: - L.debug(f"Discarding this message: {msg}") + _L.debug(f"Discarding this message: {msg}")