hardbyte / hardbyte/python-can

slcan doesn't receive corresponding response after sending can message.

Offen
#2,060 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug
Vorherrschende Sprache
Python
Sterne
1.6k
Forks
697
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### Describe the bug
While calling slcanBus.send, the corresponding response isn't read. This makes it report false success even on failed messages.

### To Reproduce
Setup two can devices, both configured to send ack on successful can message receive. Disconnect the can wires after some time.

### Expected behavior
Expected to receive ack when wire is connected (slcan should report successful transmission)
Expected to receive nack(bel) when wire is disconnected (slcan should report failed transmission)

### Additional context

OS and version: Ubuntu 24.04.3 LTS
Python version: Python 3.11.14
python-can version: 4.6.1
python-can interface/s: slcan with custom slcan device (esp32s3)

The following implementation solves that problem (introduces other ones)

```python
import can
from can.interfaces.slcan import slcanBus
import threading

class SLCANBusWithErrorCheck(slcanBus):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._tx_lock = threading.Lock()

def send(self, msg, timeout=None):
if timeout != self.serialPortOrig.write_timeout:
self.serialPortOrig.write_timeout = timeout

if msg.is_remote_frame:
if msg.is_extended_id:
sendStr = f"R{msg.arbitration_id:08X}{msg.dlc:d}"
else:
sendStr = f"r{msg.arbitration_id:03X}{msg.dlc:d}"
else:
if msg.is_extended_id:
sendStr = f"T{msg.arbitration_id:08X}{msg.dlc:d}"
else:
sendStr = f"t{msg.arbitration_id:03X}{msg.dlc:d}"
sendStr += msg.data.hex().upper()

with self._tx_lock:
# Drain any leftover bytes from a previous error before sending
self.serialPortOrig.reset_input_buffer()
self._buffer.clear()

self._write(sendStr)
response = self._read(timeout=max(timeout or 0, 2.0))

if response is None:
raise can.CanError("TX timeout - no response from adapter")
if self._ERROR.decode() in response:
raise can.CanError("TX failed - BEL received (no ACK on bus)")

def recv(self, timeout=None):
if self._tx_lock.locked():
return None
return super().recv(timeout=timeout)
```

I know following are the errors in the provided solution:
- If we are mid receive, then any call to send can create race condition (clear the serial buffers mid receive)
- the timeout logic is also incorrect (additional 2.0 second for timeout < 2.0 second, patch for some other problem)
- Receive fails immediately if transmission is going on

Any solution i came up for these problems seemed patchy as best. So, expecting it to solve inside of python-can itself or provide a better solution than locking.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.