Skip to content

Commit 7ebed2d

Browse files
christiansandberghardbyte
authored andcommitted
Add timeout argument to send()
Add timeout argument to send() and clarify timeout argument in docs. Give Kvaser a chance to transmit all messages before shutdown()
1 parent 5d864dd commit 7ebed2d

File tree

12 files changed

+61
-39
lines changed

12 files changed

+61
-39
lines changed

can/bus.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,15 @@ def recv(self, timeout=None):
5050
raise NotImplementedError("Trying to read from a write only bus?")
5151

5252
@abc.abstractmethod
53-
def send(self, msg):
53+
def send(self, msg, timeout=None):
5454
"""Transmit a message to CAN bus.
5555
Override this method to enable the transmit path.
5656
5757
:param msg: A :class:`can.Message` object.
58+
:param float timeout:
59+
If > 0, wait up to this many seconds for message to be ACK:ed.
60+
If timeout is exceeded, an exception will be raised.
61+
Might not be supported by all interfaces.
5862
5963
:raise: :class:`can.CanError`
6064
if the message could not be written.

can/interfaces/ixxat/canlib.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ def __check_status(result, function, arguments):
153153
_canlib.map_symbol("canChannelWaitRxEvent", ctypes.c_long, (HANDLE, ctypes.c_uint32), __check_status)
154154
#HRESULT canChannelPostMessage (HANDLE hChannel, PCANMSG pCanMsg );
155155
_canlib.map_symbol("canChannelPostMessage", ctypes.c_long, (HANDLE, structures.PCANMSG), __check_status)
156+
#HRESULT canChannelSendMessage (HANDLE hChannel, UINT32 dwMsTimeout, PCANMSG pCanMsg );
157+
_canlib.map_symbol("canChannelSendMessage", ctypes.c_long, (HANDLE, ctypes.c_uint32, structures.PCANMSG), __check_status)
156158

157159
#EXTERN_C HRESULT VCIAPI canControlOpen( IN HANDLE hDevice, IN UINT32 dwCanNo, OUT PHANDLE phCanCtl );
158160
_canlib.map_symbol("canControlOpen", ctypes.c_long, (HANDLE, ctypes.c_uint32, PHANDLE), __check_status)
@@ -433,7 +435,7 @@ def recv(self, timeout=None):
433435
log.debug('Recv()ed message %s', rx_msg)
434436
return rx_msg
435437

436-
def send(self, msg):
438+
def send(self, msg, timeout=None):
437439
log.debug("Sending message: %s", msg)
438440

439441
# This system is not designed to be very efficient
@@ -447,9 +449,11 @@ def send(self, msg):
447449
adapter = (ctypes.c_uint8 * msg.dlc).from_buffer(msg.data)
448450
ctypes.memmove(self._message.abData, adapter, msg.dlc)
449451

450-
# This does not block but may raise if TX fifo is full
451-
# if you prefer a blocking call use canChannelSendMessage
452-
_canlib.canChannelPostMessage (self._channel_handle, self._message)
452+
if timeout:
453+
_canlib.canChannelSendMessage(
454+
self._channel_handle, int(timeout * 1000), self._message)
455+
else:
456+
_canlib.canChannelPostMessage(self._channel_handle, self._message)
453457

454458
def shutdown(self):
455459
_canlib.canChannelClose(self._channel_handle)

can/interfaces/kvaser/canlib.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -195,18 +195,21 @@ def __check_bus_handle_validity(handle, function, arguments):
195195
restype=canstat.c_canStatus,
196196
errcheck=__check_status_read)
197197

198-
canWriteWait = __get_canlib_function("canWriteWait",
199-
argtypes=[
200-
c_canHandle,
201-
ctypes.c_long,
202-
ctypes.c_void_p,
203-
ctypes.c_uint,
204-
ctypes.c_uint,
205-
ctypes.c_ulong],
198+
canWrite = __get_canlib_function("canWrite",
199+
argtypes=[
200+
c_canHandle,
201+
ctypes.c_long,
202+
ctypes.c_void_p,
203+
ctypes.c_uint,
204+
ctypes.c_uint],
205+
restype=canstat.c_canStatus,
206+
errcheck=__check_status)
207+
208+
canWriteSync = __get_canlib_function("canWriteSync",
209+
argtypes=[c_canHandle, ctypes.c_ulong],
206210
restype=canstat.c_canStatus,
207211
errcheck=__check_status)
208212

209-
210213
canIoCtl = __get_canlib_function("canIoCtl",
211214
argtypes=[c_canHandle, ctypes.c_uint,
212215
ctypes.c_void_p, ctypes.c_uint],
@@ -515,7 +518,7 @@ def recv(self, timeout=None):
515518
#log.debug('read complete -> status not okay')
516519
return None
517520

518-
def send(self, msg):
521+
def send(self, msg, timeout=None):
519522
#log.debug("Writing a message: {}".format(msg))
520523
flags = canstat.canMSG_EXT if msg.id_type else canstat.canMSG_STD
521524
if msg.is_remote_frame:
@@ -524,12 +527,13 @@ def send(self, msg):
524527
flags |= canstat.canMSG_ERROR_FRAME
525528
ArrayConstructor = ctypes.c_byte * msg.dlc
526529
buf = ArrayConstructor(*msg.data)
527-
canWriteWait(self._write_handle,
528-
msg.arbitration_id,
529-
ctypes.byref(buf),
530-
msg.dlc,
531-
flags,
532-
10)
530+
canWrite(self._write_handle,
531+
msg.arbitration_id,
532+
ctypes.byref(buf),
533+
msg.dlc,
534+
flags)
535+
if timeout:
536+
canWriteSync(self._write_handle, int(timeout * 1000))
533537

534538
def flash(self, flash=True):
535539
"""
@@ -547,6 +551,12 @@ def flash(self, flash=True):
547551
log.error('Could not flash LEDs (%s)', e)
548552

549553
def shutdown(self):
554+
# Wait for transmit queue to be cleared
555+
try:
556+
canWriteSync(self._write_handle, 100)
557+
except CANLIBError as e:
558+
log.warning("There may be messages in the transmit queue that could "
559+
"not be transmitted before going bus off (%s)", e)
550560
if not self.single_handle:
551561
canBusOff(self._read_handle)
552562
canClose(self._read_handle)
@@ -570,7 +580,7 @@ def get_channel_info(channel):
570580
ctypes.byref(number), ctypes.sizeof(number))
571581

572582
return '%s, S/N %d (#%d)' % (
573-
name.value.decode(), serial.value, number.value + 1)
583+
name.value.decode("ascii"), serial.value, number.value + 1)
574584

575585

576586
init_kvaser_library()

can/interfaces/nican.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def recv(self, timeout=None):
225225
data=raw_msg.data[:dlc])
226226
return msg
227227

228-
def send(self, msg):
228+
def send(self, msg, timeout=None):
229229
"""
230230
Send a message to NI-CAN.
231231
@@ -252,7 +252,7 @@ def send(self, msg):
252252
# bit overkill at the moment.
253253
#state = ctypes.c_ulong()
254254
#nican.ncWaitForState(
255-
# self.handle, NC_ST_WRITE_SUCCESS, 10, ctypes.byref(state))
255+
# self.handle, NC_ST_WRITE_SUCCESS, int(timeout * 1000), ctypes.byref(state))
256256

257257
def flush_tx_buffer(self):
258258
"""

can/interfaces/pcan/pcan.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def recv(self, timeout=None):
190190

191191
return rx_msg
192192

193-
def send(self, msg):
193+
def send(self, msg, timeout=None):
194194
if msg.id_type:
195195
msgType = PCAN_MESSAGE_EXTENDED
196196
else:

can/interfaces/remote/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def recv(self, timeout=None):
9191
raise event.exc
9292
return None
9393

94-
def send(self, msg):
94+
def send(self, msg, timeout=None):
9595
"""Transmit a message to CAN bus.
9696
9797
:param can.Message msg: A Message object.

can/interfaces/serial/serial_can.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(self, channel, *args, **kwargs):
3636
self.ser = serial.Serial(channel, baudrate=115200, timeout=0.1)
3737
super(SerialBus, self).__init__(*args, **kwargs)
3838

39-
def send(self, msg):
39+
def send(self, msg, timeout=None):
4040
raise NotImplementedError("This serial interface doesn't support transmit.")
4141

4242
def recv(self, timeout=None):

can/interfaces/socketcan/socketcan_ctypes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ def __init__(self,
5151
self.socket = createSocket()
5252

5353
log.debug("Result of createSocket was %d", self.socket)
54-
54+
5555
# Add any socket options such as can frame filters
5656
if 'can_filters' in kwargs and len(kwargs['can_filters']) > 0:
5757
log.debug("Creating a filtered can bus")
5858
self.set_filters(kwargs['can_filters'])
59-
59+
6060
error = bindSocket(self.socket, channel)
6161

6262
if receive_own_messages:
@@ -86,7 +86,7 @@ def set_filters(self, can_filters=None):
8686
# TODO Is this serious enough to raise a CanError exception?
8787
if res != 0:
8888
log.error('Setting filters failed: ' + str(res))
89-
89+
9090
def recv(self, timeout=None):
9191

9292
log.debug("Trying to read a msg")
@@ -117,7 +117,7 @@ def recv(self, timeout=None):
117117

118118
return rx_msg
119119

120-
def send(self, msg):
120+
def send(self, msg, timeout=None):
121121
frame = _build_can_frame(msg)
122122
bytes_sent = libc.write(self.socket, ctypes.byref(frame), ctypes.sizeof(frame))
123123
if bytes_sent == -1:

can/interfaces/socketcan/socketcan_native.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def recv(self, timeout=None):
383383

384384
return rx_msg
385385

386-
def send(self, msg):
386+
def send(self, msg, timeout=None):
387387
log.debug("We've been asked to write a message to the bus")
388388
arbitration_id = msg.arbitration_id
389389
if msg.id_type:

can/interfaces/usb2can/usb2canInterface.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,12 @@ def __init__(self, channel, *args, **kwargs):
123123

124124
self.handle = self.can.open(connector, enable_flags)
125125

126-
def send(self, msg):
126+
def send(self, msg, timeout=None):
127127
tx = message_convert_tx(msg)
128-
self.can.send(self.handle, byref(tx))
128+
if timeout:
129+
self.can.blocking_send(self.handle, byref(tx), int(timeout * 1000))
130+
else:
131+
self.can.send(self.handle, byref(tx))
129132

130133
def recv(self, timeout=None):
131134

can/interfaces/virtual.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import logging
1313
import time
1414
try:
15-
import queue as queue
15+
import queue
1616
except ImportError:
1717
import Queue as queue
1818
from can.bus import BusABC
@@ -49,7 +49,7 @@ def recv(self, timeout=None):
4949
logger.log(9, 'Received message:\n%s', msg)
5050
return msg
5151

52-
def send(self, msg):
52+
def send(self, msg, timeout=None):
5353
msg.timestamp = time.time()
5454
# Add message to all listening on this channel
5555
for bus_queue in self.channel:

test/test_kvaser.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
class KvaserTest(unittest.TestCase):
18-
18+
1919
def setUp(self):
2020
canlib.canGetNumberOfChannels = Mock(return_value=1)
2121
canlib.canOpenChannel = Mock(return_value=0)
@@ -27,7 +27,8 @@ def setUp(self):
2727
canlib.canSetBusOutputControl = Mock()
2828
canlib.canGetChannelData = Mock()
2929
canlib.canSetAcceptanceFilter = Mock()
30-
canlib.canWriteWait = self.canWriteWait
30+
canlib.canWriteSync = Mock()
31+
canlib.canWrite = self.canWrite
3132
canlib.canReadWait = self.canReadWait
3233

3334
self.msg = {}
@@ -160,7 +161,7 @@ def test_recv_standard(self):
160161
self.assertEqual(msg.id_type, False)
161162
self.assertSequenceEqual(msg.data, [100, 101])
162163

163-
def canWriteWait(self, handle, arb_id, buf, dlc, flags, timeout):
164+
def canWrite(self, handle, arb_id, buf, dlc, flags):
164165
self.msg['arb_id'] = arb_id
165166
self.msg['dlc'] = dlc
166167
self.msg['flags'] = flags

0 commit comments

Comments
 (0)