#10 transport (obdcore/transport.py):
- TcpTransport.read raises IOError on a real socket error or peer-close instead
of swallowing it as a timeout, so a dead WiFi link surfaces (via the #8 poll
handler) as 'connection lost' rather than a frozen dashboard.
- TcpTransport.reset_input_buffer drains at most 64 chunks — never spins forever.
- BleTransport closes the client + stops the event-loop thread on connect
timeout (no leak), caps the notification buffer at 64 KiB, and close() is
robust when only partially initialised.
#11 controller (gui/controller.py, obdcore/store.py):
- connect() closes the transport and nulls the link if init()/connect() raises,
so a failed/retried connect doesn't orphan sockets/threads.
- stop_record() unhooks store.recorder BEFORE closing it, and CsvRecorder now
has a 'closed' guard so a poll-thread write racing close() is a no-op instead
of an I/O-on-closed-file crash.
Closes#10Closes#11
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs