Skip to content

Commit 3dcfcbb

Browse files
authored
Merge pull request #516 from hardbyte/release-3.1.0
Release 3.1.0
2 parents 4b93f21 + 0348433 commit 3dcfcbb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3874
-281
lines changed

CHANGELOG.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
Version 3.1.0
2+
====
3+
4+
Major features
5+
--------------
6+
7+
Two new interfaces this release:
8+
9+
- SYSTEC contributed by @idaniel86 in PR #466
10+
- CANalyst-II contributed by @smeng9 in PR #476
11+
12+
13+
Other notable changes
14+
---------------------
15+
16+
- #477 The kvaser interface now supports bus statistics via a custom bus method.
17+
- #434 neovi now supports receiving own messages
18+
- #490 Adding option to override the neovi library name
19+
- #488 Allow simultaneous access to IXXAT cards
20+
- #447 Improvements to serial interface:
21+
* to allow receiving partial messages
22+
* to fix issue with DLC of remote frames
23+
* addition of unit tests
24+
- #497 Small API changes to `Message` and added unit tests
25+
- #471 Fix CAN FD issue in kvaser interface
26+
- #462 Fix `Notifier` issue with asyncio
27+
- #481 Fix PCAN support on OSX
28+
- #455 Fix to `Message` initializer
29+
- Small bugfixes and improvements
30+
31+
132
Version 3.0.0
233
====
334

CONTRIBUTORS.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ Boris Wenzlaff
2222
Pierre-Luc Tessier Gagné
2323
Felix Divo <felix.divo@gmail.com>
2424
Kristian Sloth Lauszus <lauszus@gmail.com>
25+
Shaoyu Meng <shaoyu@life-foundry.com>
26+
Alexander Mueller<XelaRellum@web.de>
27+
Jan Goeteyn
28+
"ykzheng" <wishdo@gmail.com>

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Example usage
6767
receive_own_messages=True)
6868
6969
# send a message
70-
message = can.Message(arbitration_id=123, extended_id=True,
70+
message = can.Message(arbitration_id=123, is_extended_id=True,
7171
data=[0x11, 0x22, 0x33])
7272
bus.send(message, timeout=0.2)
7373

can/__init__.py

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

99
import logging
1010

11-
__version__ = "3.0.0"
11+
__version__ = "3.1.0"
1212

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

@@ -21,6 +21,7 @@ class CanError(IOError):
2121
"""
2222
pass
2323

24+
2425
from .listener import Listener, BufferedReader, RedirectReader
2526
try:
2627
from .listener import AsyncBufferedReader

can/broadcastmanager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ def modify_data(self, message):
8585

8686

8787
class MultiRateCyclicSendTaskABC(CyclicSendTaskABC):
88-
"""Exposes more of the full power of the TX_SETUP opcode.
88+
"""A Cyclic send task that supports switches send frequency after a set time.
8989
"""
9090

9191
def __init__(self, channel, message, count, initial_period, subsequent_period):
9292
"""
9393
Transmits a message `count` times at `initial_period` then continues to
9494
transmit message at `subsequent_period`.
9595
96-
:param can.interface.Bus channel:
96+
:param channel: See interface specific documentation.
9797
:param can.Message message:
9898
:param int count:
9999
:param float initial_period:

can/bus.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ def send_periodic(self, msg, period, duration=None, store_task=True):
167167
- the (optional) duration expires
168168
- the Bus instance goes out of scope
169169
- the Bus instance is shutdown
170-
- :meth:`Bus.stop_all_periodic_tasks()` is called
171-
- the task's :meth:`Task.stop()` method is called.
170+
- :meth:`BusABC.stop_all_periodic_tasks()` is called
171+
- the task's :meth:`CyclicTask.stop()` method is called.
172172
173173
:param can.Message msg:
174174
Message to transmit
@@ -368,6 +368,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
368368
def state(self):
369369
"""
370370
Return the current state of the hardware
371+
371372
:return: ACTIVE, PASSIVE or ERROR
372373
:rtype: NamedTuple
373374
"""
@@ -377,6 +378,7 @@ def state(self):
377378
def state(self, new_state):
378379
"""
379380
Set the new state of the hardware
381+
380382
:param new_state: BusState.ACTIVE, BusState.PASSIVE or BusState.ERROR
381383
"""
382384
raise NotImplementedError("Property is not implemented.")

can/interface.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# coding: utf-8
22

33
"""
4-
This module contains the base implementation of `can.Bus` as well
5-
as a list of all avalibale backends and some implemented
4+
This module contains the base implementation of :class:`can.BusABC` as well
5+
as a list of all available backends and some implemented
66
CyclicSendTasks.
77
"""
88

@@ -11,7 +11,6 @@
1111
import sys
1212
import importlib
1313
import logging
14-
import re
1514

1615
import can
1716
from .bus import BusABC
@@ -145,7 +144,7 @@ def detect_available_configs(interfaces=None):
145144
- `None` to search in all known interfaces.
146145
:rtype: list[dict]
147146
:return: an iterable of dicts, each suitable for usage in
148-
the constructor of :class:`can.interface.Bus`.
147+
the constructor of :class:`can.BusABC`.
149148
"""
150149

151150
# Figure out where to search

can/interfaces/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
'virtual': ('can.interfaces.virtual', 'VirtualBus'),
2222
'neovi': ('can.interfaces.ics_neovi', 'NeoViBus'),
2323
'vector': ('can.interfaces.vector', 'VectorBus'),
24-
'slcan': ('can.interfaces.slcan', 'slcanBus')
24+
'slcan': ('can.interfaces.slcan', 'slcanBus'),
25+
'canalystii': ('can.interfaces.canalystii', 'CANalystIIBus'),
26+
'systec': ('can.interfaces.systec', 'UcanBus')
2527
}
2628

2729
BACKENDS.update({

can/interfaces/canalystii.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
from ctypes import *
2+
import logging
3+
import platform
4+
from can import BusABC, Message
5+
6+
logger = logging.getLogger(__name__)
7+
8+
9+
class VCI_INIT_CONFIG(Structure):
10+
_fields_ = [("AccCode", c_int32),
11+
("AccMask", c_int32),
12+
("Reserved", c_int32),
13+
("Filter", c_ubyte),
14+
("Timing0", c_ubyte),
15+
("Timing1", c_ubyte),
16+
("Mode", c_ubyte)]
17+
18+
19+
class VCI_CAN_OBJ(Structure):
20+
_fields_ = [("ID", c_uint),
21+
("TimeStamp", c_int),
22+
("TimeFlag", c_byte),
23+
("SendType", c_byte),
24+
("RemoteFlag", c_byte),
25+
("ExternFlag", c_byte),
26+
("DataLen", c_byte),
27+
("Data", c_ubyte * 8),
28+
("Reserved", c_byte * 3)]
29+
30+
31+
VCI_USBCAN2 = 4
32+
33+
STATUS_OK = 0x01
34+
STATUS_ERR = 0x00
35+
36+
TIMING_DICT = {
37+
5000: (0xBF, 0xFF),
38+
10000: (0x31, 0x1C),
39+
20000: (0x18, 0x1C),
40+
33330: (0x09, 0x6F),
41+
40000: (0x87, 0xFF),
42+
50000: (0x09, 0x1C),
43+
66660: (0x04, 0x6F),
44+
80000: (0x83, 0xFF),
45+
83330: (0x03, 0x6F),
46+
100000: (0x04, 0x1C),
47+
125000: (0x03, 0x1C),
48+
200000: (0x81, 0xFA),
49+
250000: (0x01, 0x1C),
50+
400000: (0x80, 0xFA),
51+
500000: (0x00, 0x1C),
52+
666000: (0x80, 0xB6),
53+
800000: (0x00, 0x16),
54+
1000000: (0x00, 0x14),
55+
}
56+
57+
try:
58+
if platform.system() == "Windows":
59+
CANalystII = WinDLL("./ControlCAN.dll")
60+
else:
61+
CANalystII = CDLL("./libcontrolcan.so")
62+
logger.info("Loaded CANalystII library")
63+
except OSError as e:
64+
CANalystII = None
65+
logger.info("Cannot load CANalystII library")
66+
67+
68+
class CANalystIIBus(BusABC):
69+
def __init__(self, channel, device=0, baud=None, Timing0=None, Timing1=None, can_filters=None):
70+
"""
71+
72+
:param channel: channel number
73+
:param device: device number
74+
:param baud: baud rate
75+
:param Timing0: customize the timing register if baudrate is not specified
76+
:param Timing1:
77+
:param can_filters: filters for packet
78+
"""
79+
super(CANalystIIBus, self).__init__(channel, can_filters)
80+
81+
if isinstance(channel, (list, tuple)):
82+
self.channels = channel
83+
elif isinstance(channel, int):
84+
self.channels = [channel]
85+
else:
86+
# Assume comma separated string of channels
87+
self.channels = [int(ch.strip()) for ch in channel.split(',')]
88+
89+
self.device = device
90+
91+
self.channel_info = "CANalyst-II: device {}, channels {}".format(self.device, self.channels)
92+
93+
if baud is not None:
94+
try:
95+
Timing0, Timing1 = TIMING_DICT[baud]
96+
except KeyError:
97+
raise ValueError("Baudrate is not supported")
98+
99+
if Timing0 is None or Timing1 is None:
100+
raise ValueError("Timing registers are not set")
101+
102+
self.init_config = VCI_INIT_CONFIG(0, 0xFFFFFFFF, 0, 1, Timing0, Timing1, 0)
103+
104+
if CANalystII.VCI_OpenDevice(VCI_USBCAN2, self.device, 0) == STATUS_ERR:
105+
logger.error("VCI_OpenDevice Error")
106+
107+
for channel in self.channels:
108+
if CANalystII.VCI_InitCAN(VCI_USBCAN2, self.device, channel, byref(self.init_config)) == STATUS_ERR:
109+
logger.error("VCI_InitCAN Error")
110+
self.shutdown()
111+
return
112+
113+
if CANalystII.VCI_StartCAN(VCI_USBCAN2, self.device, channel) == STATUS_ERR:
114+
logger.error("VCI_StartCAN Error")
115+
self.shutdown()
116+
return
117+
118+
def send(self, msg, timeout=None):
119+
"""
120+
121+
:param msg: message to send
122+
:param timeout: timeout is not used here
123+
:return:
124+
"""
125+
extern_flag = 1 if msg.is_extended_id else 0
126+
raw_message = VCI_CAN_OBJ(msg.arbitration_id, 0, 0, 1, msg.is_remote_frame, extern_flag, msg.dlc, (c_ubyte * 8)(*msg.data), (c_byte * 3)(*[0, 0, 0]))
127+
128+
if msg.channel is not None:
129+
channel = msg.channel
130+
elif len(self.channels) == 1:
131+
channel = self.channels[0]
132+
else:
133+
raise ValueError(
134+
"msg.channel must be set when using multiple channels.")
135+
136+
CANalystII.VCI_Transmit(VCI_USBCAN2, self.device, channel, byref(raw_message), 1)
137+
138+
def _recv_internal(self, timeout=None):
139+
"""
140+
141+
:param timeout: float in seconds
142+
:return:
143+
"""
144+
raw_message = VCI_CAN_OBJ()
145+
146+
timeout = -1 if timeout is None else int(timeout * 1000)
147+
148+
if CANalystII.VCI_Receive(VCI_USBCAN2, self.device, self.channels[0], byref(raw_message), 1, timeout) <= STATUS_ERR:
149+
return None, False
150+
else:
151+
return (
152+
Message(
153+
timestamp=raw_message.TimeStamp if raw_message.TimeFlag else 0.0,
154+
arbitration_id=raw_message.ID,
155+
is_remote_frame=raw_message.RemoteFlag,
156+
channel=0,
157+
dlc=raw_message.DataLen,
158+
data=raw_message.Data,
159+
),
160+
False,
161+
)
162+
163+
def flush_tx_buffer(self):
164+
for channel in self.channels:
165+
CANalystII.VCI_ClearBuffer(VCI_USBCAN2, self.device, channel)
166+
167+
def shutdown(self):
168+
CANalystII.VCI_CloseDevice(VCI_USBCAN2, self.device)

can/interfaces/ics_neovi/neovi_bus.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def __init__(self, channel, can_filters=None, **config):
7575
:type channel: int or str or list(int) or list(str)
7676
:param list can_filters:
7777
See :meth:`can.BusABC.set_filters` for details.
78+
:param bool receive_own_messages:
79+
If transmitted messages should also be received by this bus.
7880
:param bool use_system_timestamp:
7981
Use system timestamp for can messages instead of the hardware time
8082
stamp
@@ -89,6 +91,8 @@ def __init__(self, channel, can_filters=None, **config):
8991
:param int data_bitrate:
9092
Which bitrate to use for data phase in CAN FD.
9193
Defaults to arbitration bitrate.
94+
:param override_library_name:
95+
Absolute path or relative path to the library including filename.
9296
"""
9397
if ics is None:
9498
raise ImportError('Please install python-ics')
@@ -99,6 +103,9 @@ def __init__(self, channel, can_filters=None, **config):
99103
logger.info("CAN Filters: {}".format(can_filters))
100104
logger.info("Got configuration of: {}".format(config))
101105

106+
if 'override_library_name' in config:
107+
ics.override_library_name(config.get('override_library_name'))
108+
102109
if isinstance(channel, (list, tuple)):
103110
self.channels = channel
104111
elif isinstance(channel, int):
@@ -127,6 +134,7 @@ def __init__(self, channel, can_filters=None, **config):
127134
self._use_system_timestamp = bool(
128135
config.get('use_system_timestamp', False)
129136
)
137+
self._receive_own_messages = config.get('receive_own_messages', True)
130138

131139
self.channel_info = '%s %s CH:%s' % (
132140
self.dev.Name,
@@ -222,6 +230,9 @@ def _process_msg_queue(self, timeout=0.1):
222230
for ics_msg in messages:
223231
if ics_msg.NetworkID not in self.channels:
224232
continue
233+
is_tx = bool(ics_msg.StatusBitField & ics.SPY_STATUS_TX_MSG)
234+
if not self._receive_own_messages and is_tx:
235+
continue
225236
self.rx_buffer.append(ics_msg)
226237
if errors:
227238
logger.warning("%d error(s) found" % errors)
@@ -262,7 +273,7 @@ def _ics_msg_to_message(self, ics_msg):
262273
arbitration_id=ics_msg.ArbIDOrHeader,
263274
data=data,
264275
dlc=ics_msg.NumberBytesData,
265-
extended_id=bool(
276+
is_extended_id=bool(
266277
ics_msg.StatusBitField & ics.SPY_STATUS_XTD_FRAME
267278
),
268279
is_fd=is_fd,
@@ -283,7 +294,7 @@ def _ics_msg_to_message(self, ics_msg):
283294
arbitration_id=ics_msg.ArbIDOrHeader,
284295
data=ics_msg.Data[:ics_msg.NumberBytesData],
285296
dlc=ics_msg.NumberBytesData,
286-
extended_id=bool(
297+
is_extended_id=bool(
287298
ics_msg.StatusBitField & ics.SPY_STATUS_XTD_FRAME
288299
),
289300
is_fd=is_fd,

0 commit comments

Comments
 (0)