Skip to content

Commit 40c1aed

Browse files
authored
Merge pull request #715 from hardbyte/release-3.3.3
Release 3.3.3
2 parents 29a235b + 8b76232 commit 40c1aed

File tree

16 files changed

+171
-49
lines changed

16 files changed

+171
-49
lines changed

CHANGELOG.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
Version 3.3.3
2+
====
3+
4+
Backported fixes from 4.x development branch which targets Python 3.
5+
6+
* #798 Backport caching msg.data value in neovi interface.
7+
* #796 Fix Vector CANlib treatment of empty app name.
8+
* #771 Handle empty CSV file.
9+
* #741 ASCII reader can now handle FD frames.
10+
* #740 Exclude test packages from distribution.
11+
* #713 RTR crash fix in canutils log reader parsing RTR frames.
12+
* #701 Skip J1939 messages in ASC Reader.
13+
* #690 Exposes a configuration option to allow the CAN message player to send error frames
14+
(and sets the default to not send error frames).
15+
* #638 Fixes the semantics provided by periodic tasks in SocketCAN interface.
16+
* #628 Avoid padding CAN_FD_MESSAGE_64 objects to 4 bytes.
17+
* #617 Fixes the broken CANalyst-II interface.
18+
* #605 Socketcan BCM status fix.
19+
20+
121
Version 3.3.2
222
====
323

can/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import logging
1010

11-
__version__ = "3.3.2"
11+
__version__ = "3.3.3"
1212

1313
log = logging.getLogger('can')
1414

can/interfaces/canalystii.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from ctypes import *
23
import logging
34
import platform
@@ -66,17 +67,19 @@ class VCI_CAN_OBJ(Structure):
6667

6768

6869
class CANalystIIBus(BusABC):
69-
def __init__(self, channel, device=0, baud=None, Timing0=None, Timing1=None, can_filters=None):
70+
def __init__(
71+
self, channel, device=0, bitrate=None, baud=None, Timing0=None, Timing1=None, can_filters=None, **kwargs
72+
):
7073
"""
7174
7275
:param channel: channel number
7376
:param device: device number
74-
:param baud: baud rate
77+
:param baud: baud rate. Renamed to bitrate in next release.
7578
:param Timing0: customize the timing register if baudrate is not specified
7679
:param Timing1:
7780
:param can_filters: filters for packet
7881
"""
79-
super(CANalystIIBus, self).__init__(channel, can_filters)
82+
super(CANalystIIBus, self).__init__(channel, can_filters, **kwargs)
8083

8184
if isinstance(channel, (list, tuple)):
8285
self.channels = channel
@@ -91,10 +94,15 @@ def __init__(self, channel, device=0, baud=None, Timing0=None, Timing1=None, can
9194
self.channel_info = "CANalyst-II: device {}, channels {}".format(self.device, self.channels)
9295

9396
if baud is not None:
97+
warnings.warn('Argument baud will be deprecated in version 4, use bitrate instead',
98+
PendingDeprecationWarning)
99+
bitrate = baud
100+
101+
if bitrate is not None:
94102
try:
95-
Timing0, Timing1 = TIMING_DICT[baud]
103+
Timing0, Timing1 = TIMING_DICT[bitrate]
96104
except KeyError:
97-
raise ValueError("Baudrate is not supported")
105+
raise ValueError("Bitrate is not supported")
98106

99107
if Timing0 is None or Timing1 is None:
100108
raise ValueError("Timing registers are not set")

can/interfaces/ics_neovi/neovi_bus.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,12 @@ def send(self, msg, timeout=None):
334334
flag3 |= ics.SPY_STATUS3_CANFD_ESI
335335

336336
message.ArbIDOrHeader = msg.arbitration_id
337-
message.NumberBytesData = len(msg.data)
338-
message.Data = tuple(msg.data[:8])
339-
if msg.is_fd and len(msg.data) > 8:
337+
msg_data = msg.data
338+
message.NumberBytesData = len(msg_data)
339+
message.Data = tuple(msg_data[:8])
340+
if msg.is_fd and len(msg_data) > 8:
340341
message.ExtraDataPtrEnabled = 1
341-
message.ExtraDataPtr = tuple(msg.data)
342+
message.ExtraDataPtr = tuple(msg_data)
342343
message.StatusBitField = flag0
343344
message.StatusBitField2 = 0
344345
message.StatusBitField3 = flag3

can/interfaces/socketcan/constants.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
CAN_EFF_FLAG = 0x80000000
1010

1111
# BCM opcodes
12-
CAN_BCM_TX_SETUP = 1
13-
CAN_BCM_TX_DELETE = 2
12+
CAN_BCM_TX_SETUP = 1
13+
CAN_BCM_TX_DELETE = 2
14+
CAN_BCM_TX_READ = 3
1415

1516
# BCM flags
1617
SETTIMER = 0x0001

can/interfaces/socketcan/socketcan.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,40 @@ def _tx_setup(self, message):
346346
count = 0
347347
ival1 = 0
348348
ival2 = self.period
349-
header = build_bcm_transmit_header(self.can_id_with_flags, count, ival1,
350-
ival2, self.flags)
349+
350+
# First do a TX_READ before creating a new task, and check if we get
351+
# EINVAL. If so, then we are referring to a CAN message with the same
352+
# ID
353+
check_header = build_bcm_header(
354+
opcode=CAN_BCM_TX_READ,
355+
flags=0,
356+
count=0,
357+
ival1_seconds=0,
358+
ival1_usec=0,
359+
ival2_seconds=0,
360+
ival2_usec=0,
361+
can_id=self.can_id_with_flags,
362+
nframes=0,
363+
)
364+
try:
365+
self.bcm_socket.send(check_header)
366+
except OSError as e:
367+
if e.errno != errno.EINVAL:
368+
raise e
369+
else:
370+
raise ValueError(
371+
"A periodic Task for Arbitration ID {} has already been created".format(
372+
message.arbitration_id
373+
)
374+
)
375+
376+
header = build_bcm_transmit_header(
377+
self.can_id_with_flags,
378+
count,
379+
ival1,
380+
ival2,
381+
self.flags
382+
)
351383
frame = build_can_frame(message)
352384
log.debug("Sending BCM command")
353385
send_bcm(self.bcm_socket, header + frame)

can/interfaces/vector/canlib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def __init__(self, channel, can_filters=None, poll_interval=0.01,
8787
else:
8888
# Assume comma separated string of channels
8989
self.channels = [int(ch.strip()) for ch in channel.split(',')]
90-
self._app_name = app_name.encode() if app_name is not None else ''
90+
self._app_name = app_name.encode() if app_name is not None else b''
9191
self.channel_info = 'Application %s: %s' % (
9292
app_name, ', '.join('CAN %d' % (ch + 1) for ch in self.channels))
9393

can/io/asc.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
class ASCReader(BaseIOHandler):
3030
"""
31-
Iterator of CAN messages from a ASC logging file.
31+
Iterator of CAN messages from a ASC logging file. Meta data (comments,
32+
bus statistics, J1939 Transport Protocol messages) is ignored.
3233
3334
TODO: turn relative timestamps back to absolute form
3435
"""
@@ -58,9 +59,13 @@ def __iter__(self):
5859
temp = line.strip()
5960
if not temp or not temp[0].isdigit():
6061
continue
61-
62+
is_fd = False
6263
try:
6364
timestamp, channel, dummy = temp.split(None, 2) # , frameType, dlc, frameData
65+
if channel == "CANFD":
66+
timestamp, _, channel, _, dummy = temp.split(None, 4)
67+
is_fd = True
68+
6469
except ValueError:
6570
# we parsed an empty comment
6671
continue
@@ -77,7 +82,10 @@ def __iter__(self):
7782
channel=channel)
7883
yield msg
7984

80-
elif not isinstance(channel, int) or dummy.strip()[0:10].lower() == 'statistic:':
85+
elif (not isinstance(channel, int)
86+
or dummy.strip()[0:10].lower() == 'statistic:'
87+
or dummy.split(None, 1)[0] == "J1939TP"
88+
):
8189
pass
8290

8391
elif dummy[-1:].lower() == 'r':
@@ -91,16 +99,32 @@ def __iter__(self):
9199
yield msg
92100

93101
else:
102+
brs = None
103+
esi = None
104+
data_length = 0
94105
try:
95-
# this only works if dlc > 0 and thus data is availabe
96-
can_id_str, _, _, dlc, data = dummy.split(None, 4)
106+
# this only works if dlc > 0 and thus data is available
107+
if not is_fd:
108+
can_id_str, _, _, dlc, data = dummy.split(None, 4)
109+
else:
110+
can_id_str, frame_name, brs, esi, dlc, data_length, data = dummy.split(
111+
None, 6
112+
)
113+
if frame_name.isdigit():
114+
# Empty frame_name
115+
can_id_str, brs, esi, dlc, data_length, data = dummy.split(
116+
None, 5
117+
)
97118
except ValueError:
98119
# but if not, we only want to get the stuff up to the dlc
99120
can_id_str, _, _, dlc = dummy.split(None, 3)
100121
# and we set data to an empty sequence manually
101122
data = ''
102-
103-
dlc = int(dlc)
123+
dlc = int(dlc, 16)
124+
if is_fd:
125+
# For fd frames, dlc and data length might not be equal and
126+
# data_length is the actual size of the data
127+
dlc = int(data_length)
104128
frame = bytearray()
105129
data = data.split()
106130
for byte in data[0:dlc]:
@@ -115,7 +139,10 @@ def __iter__(self):
115139
is_remote_frame=False,
116140
dlc=dlc,
117141
data=frame,
118-
channel=channel
142+
is_fd=is_fd,
143+
channel=channel,
144+
bitrate_switch=is_fd and brs == "1",
145+
error_state_indicator=is_fd and esi == "1",
119146
)
120147

121148
self.stop()

can/io/blf.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,11 @@ def __iter__(self):
195195
raise BLFParseError()
196196

197197
obj_size = header[3]
198+
obj_type = header[4]
198199
# Calculate position of next object
199-
next_pos = pos + obj_size + (obj_size % 4)
200+
next_pos = pos + obj_size
201+
if obj_type != CAN_FD_MESSAGE_64:
202+
next_pos += obj_size % 4
200203
if next_pos > len(data):
201204
# Object continues in next log container
202205
break
@@ -222,7 +225,6 @@ def __iter__(self):
222225
factor = 1e-9
223226
timestamp = timestamp * factor + self.start_timestamp
224227

225-
obj_type = header[4]
226228
# Both CAN message types have the same starting content
227229
if obj_type in (CAN_MESSAGE, CAN_MESSAGE2):
228230
(channel, flags, dlc, can_id,

can/io/canutils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def __iter__(self):
6262
else:
6363
isExtended = False
6464
canId = int(canId, 16)
65-
65+
dataBin = None
6666
if data and data[0].lower() == 'r':
6767
isRemoteFrame = True
6868
if len(data) > 1:

can/io/csv.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ def __init__(self, file):
9191

9292
def __iter__(self):
9393
# skip the header line
94-
next(self.file)
94+
try:
95+
next(self.file)
96+
except StopIteration:
97+
# don't crash on a file with only a header
98+
return
9599

96100
for line in self.file:
97101

can/player.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ def main():
4747
help='''Ignore timestamps (send all frames immediately with minimum gap between frames)''',
4848
action='store_false')
4949

50+
parser.add_argument(
51+
"--error-frames",
52+
help="Also send error frames to the interface.",
53+
action="store_true",
54+
)
55+
5056
parser.add_argument('-g', '--gap', type=float, help='''<s> minimum time between replayed frames''',
5157
default=0.0001)
5258
parser.add_argument('-s', '--skip', type=float, default=60*60*24,
@@ -68,6 +74,8 @@ def main():
6874
logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)]
6975
can.set_logging_level(logging_level_name)
7076

77+
error_frames = results.error_frames
78+
7179
config = {"single_handle": True}
7280
if results.interface:
7381
config["interface"] = results.interface
@@ -84,6 +92,8 @@ def main():
8492

8593
try:
8694
for m in in_sync:
95+
if m.is_error_frame and not error_frames:
96+
continue
8797
if verbosity >= 3:
8898
print(m)
8999
bus.send(m)

doc/configuration.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,7 @@ Lookup table of interface names:
126126
+---------------------+-------------------------------------+
127127
| ``"virtual"`` | :doc:`interfaces/virtual` |
128128
+---------------------+-------------------------------------+
129+
| ``"canalystii"`` | :doc:`interfaces/canalystii` |
130+
+---------------------+-------------------------------------+
131+
| ``"systec"`` | :doc:`interfaces/systec` |
132+
+---------------------+-------------------------------------+

setup.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@
3333
'mock~=2.0',
3434
'pytest~=4.3',
3535
'pytest-timeout~=1.3',
36-
'pytest-cov~=2.6',
36+
'pytest-cov~=2.8',
37+
# coveragepy==5.0 fails with `Safety level may not be changed inside a transaction`
38+
# on python 3.6 on MACOS
39+
'coverage<5',
3740
'codecov~=2.0',
3841
'future',
3942
'six',
40-
'hypothesis'
43+
'hypothesis~=4.56'
4144
] + extras_require['serial']
4245

4346
extras_require['test'] = tests_require
@@ -87,7 +90,7 @@
8790

8891
# Code
8992
version=version,
90-
packages=find_packages(exclude=["test", "doc", "scripts", "examples"]),
93+
packages=find_packages(exclude=["test*", "doc", "scripts", "examples"]),
9194
scripts=list(filter(isfile, (join("scripts/", f) for f in listdir("scripts/")))),
9295

9396
# Author

0 commit comments

Comments
 (0)