hardbyte / hardbyte/python-can

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

Đang mở
#2,060 3 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug
Ngôn ngữ chính
Python
Star
1.6k
Fork
697
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

### 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.