pyxcp 0.21.9__cp310-cp310-win_amd64.whl → 0.22.23__cp310-cp310-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyxcp might be problematic. Click here for more details.
- pyxcp/__init__.py +12 -20
- pyxcp/aml/EtasCANMonitoring.a2l +82 -83
- pyxcp/aml/XCP_Common.aml +0 -1
- pyxcp/aml/XCPonUSB.aml +1 -1
- pyxcp/aml/ifdata_CAN.a2l +0 -1
- pyxcp/aml/ifdata_Eth.a2l +0 -1
- pyxcp/aml/ifdata_Flx.a2l +0 -1
- pyxcp/aml/ifdata_SxI.a2l +0 -1
- pyxcp/aml/ifdata_USB.a2l +0 -1
- pyxcp/asam/types.py +4 -4
- pyxcp/asamkeydll.c +0 -1
- pyxcp/checksum.py +0 -1
- pyxcp/cmdline.py +32 -50
- pyxcp/config/__init__.py +1100 -0
- pyxcp/config/legacy.py +120 -0
- pyxcp/constants.py +12 -13
- pyxcp/cpp_ext/__init__.py +0 -0
- pyxcp/cpp_ext/bin.hpp +104 -0
- pyxcp/cpp_ext/blockmem.hpp +58 -0
- pyxcp/cpp_ext/cpp_ext.cp310-win_amd64.pyd +0 -0
- pyxcp/cpp_ext/cpp_ext.cp38-win_amd64.pyd +0 -0
- pyxcp/cpp_ext/cpp_ext.cp39-win_amd64.pyd +0 -0
- pyxcp/cpp_ext/daqlist.hpp +200 -0
- pyxcp/cpp_ext/event.hpp +67 -0
- pyxcp/cpp_ext/extension_wrapper.cpp +96 -0
- pyxcp/cpp_ext/helper.hpp +280 -0
- pyxcp/cpp_ext/mcobject.hpp +246 -0
- pyxcp/cpp_ext/tsqueue.hpp +46 -0
- pyxcp/daq_stim/__init__.py +228 -0
- pyxcp/daq_stim/optimize/__init__.py +67 -0
- pyxcp/daq_stim/optimize/binpacking.py +41 -0
- pyxcp/daq_stim/scheduler.cpp +28 -0
- pyxcp/daq_stim/scheduler.hpp +75 -0
- pyxcp/daq_stim/stim.cp310-win_amd64.pyd +0 -0
- pyxcp/daq_stim/stim.cp38-win_amd64.pyd +0 -0
- pyxcp/daq_stim/stim.cp39-win_amd64.pyd +0 -0
- pyxcp/daq_stim/stim.cpp +13 -0
- pyxcp/daq_stim/stim.hpp +604 -0
- pyxcp/daq_stim/stim_wrapper.cpp +48 -0
- pyxcp/dllif.py +21 -18
- pyxcp/errormatrix.py +5 -3
- pyxcp/examples/conf_can.toml +4 -2
- pyxcp/examples/conf_can_vector.json +9 -9
- pyxcp/examples/conf_can_vector.toml +4 -2
- pyxcp/examples/conf_eth.toml +5 -2
- pyxcp/examples/conf_nixnet.json +18 -18
- pyxcp/examples/conf_sxi.json +7 -7
- pyxcp/examples/ex_arrow.py +109 -0
- pyxcp/examples/ex_csv.py +85 -0
- pyxcp/examples/ex_excel.py +95 -0
- pyxcp/examples/ex_mdf.py +124 -0
- pyxcp/examples/ex_sqlite.py +128 -0
- pyxcp/examples/run_daq.py +148 -0
- pyxcp/examples/xcp_policy.py +6 -7
- pyxcp/examples/xcp_read_benchmark.py +8 -6
- pyxcp/examples/xcp_skel.py +0 -2
- pyxcp/examples/xcp_unlock.py +1 -1
- pyxcp/examples/xcp_user_supplied_driver.py +1 -2
- pyxcp/examples/xcphello.py +6 -3
- pyxcp/examples/xcphello_recorder.py +4 -4
- pyxcp/master/__init__.py +1 -2
- pyxcp/master/errorhandler.py +107 -74
- pyxcp/master/master.py +196 -114
- pyxcp/py.typed +0 -0
- pyxcp/recorder/__init__.py +27 -6
- pyxcp/recorder/converter/__init__.py +37 -0
- pyxcp/recorder/lz4.c +129 -51
- pyxcp/recorder/lz4.h +45 -28
- pyxcp/recorder/lz4hc.c +560 -156
- pyxcp/recorder/lz4hc.h +1 -1
- pyxcp/recorder/mio.hpp +721 -767
- pyxcp/recorder/reader.hpp +139 -0
- pyxcp/recorder/reco.py +5 -8
- pyxcp/recorder/rekorder.cp310-win_amd64.pyd +0 -0
- pyxcp/recorder/rekorder.cp38-win_amd64.pyd +0 -0
- pyxcp/recorder/rekorder.cp39-win_amd64.pyd +0 -0
- pyxcp/recorder/rekorder.cpp +18 -22
- pyxcp/recorder/rekorder.hpp +200 -587
- pyxcp/recorder/setup.py +11 -10
- pyxcp/recorder/test_reko.py +2 -3
- pyxcp/recorder/unfolder.hpp +1332 -0
- pyxcp/recorder/wrap.cpp +171 -9
- pyxcp/recorder/writer.hpp +302 -0
- pyxcp/scripts/pyxcp_probe_can_drivers.py +0 -2
- pyxcp/scripts/xcp_examples.py +64 -0
- pyxcp/scripts/xcp_fetch_a2l.py +15 -10
- pyxcp/scripts/xcp_id_scanner.py +2 -6
- pyxcp/scripts/xcp_info.py +101 -63
- pyxcp/scripts/xcp_profile.py +27 -0
- pyxcp/stim/__init__.py +0 -0
- pyxcp/tests/test_asam_types.py +2 -2
- pyxcp/tests/test_binpacking.py +186 -0
- pyxcp/tests/test_can.py +1132 -38
- pyxcp/tests/test_checksum.py +2 -1
- pyxcp/tests/test_daq.py +193 -0
- pyxcp/tests/test_frame_padding.py +6 -3
- pyxcp/tests/test_master.py +42 -31
- pyxcp/tests/test_transport.py +12 -12
- pyxcp/tests/test_utils.py +2 -5
- pyxcp/timing.py +0 -2
- pyxcp/transport/__init__.py +9 -9
- pyxcp/transport/base.py +149 -127
- pyxcp/transport/base_transport.hpp +0 -0
- pyxcp/transport/can.py +194 -167
- pyxcp/transport/eth.py +80 -82
- pyxcp/transport/sxi.py +106 -60
- pyxcp/transport/transport_wrapper.cpp +0 -0
- pyxcp/transport/usb_transport.py +65 -83
- pyxcp/types.py +69 -20
- pyxcp/utils.py +47 -16
- pyxcp/vector/map.py +1 -3
- {pyxcp-0.21.9.dist-info → pyxcp-0.22.23.dist-info}/METADATA +28 -23
- pyxcp-0.22.23.dist-info/RECORD +134 -0
- {pyxcp-0.21.9.dist-info → pyxcp-0.22.23.dist-info}/WHEEL +1 -1
- {pyxcp-0.21.9.dist-info → pyxcp-0.22.23.dist-info}/entry_points.txt +2 -0
- pyxcp/config.py +0 -57
- pyxcp/cxx/asynchiofactory.hpp +0 -24
- pyxcp/cxx/blocking_client.cpp +0 -44
- pyxcp/cxx/blocking_socket.cpp +0 -43
- pyxcp/cxx/blocking_socket.hpp +0 -558
- pyxcp/cxx/concurrent_queue.hpp +0 -60
- pyxcp/cxx/eth.hpp +0 -57
- pyxcp/cxx/exceptions.hpp +0 -30
- pyxcp/cxx/iasyncioservice.hpp +0 -31
- pyxcp/cxx/iresource.hpp +0 -17
- pyxcp/cxx/isocket.hpp +0 -22
- pyxcp/cxx/linux/epoll.cpp +0 -51
- pyxcp/cxx/linux/epoll.hpp +0 -87
- pyxcp/cxx/linux/lit_tester.cpp +0 -19
- pyxcp/cxx/linux/socket.hpp +0 -234
- pyxcp/cxx/linux/timeout.hpp +0 -81
- pyxcp/cxx/memoryblock.hpp +0 -42
- pyxcp/cxx/pool.hpp +0 -81
- pyxcp/cxx/poolmgr.cpp +0 -6
- pyxcp/cxx/poolmgr.hpp +0 -31
- pyxcp/cxx/test_queue.cpp +0 -69
- pyxcp/cxx/timestamp.hpp +0 -84
- pyxcp/cxx/utils.cpp +0 -38
- pyxcp/cxx/utils.hpp +0 -29
- pyxcp/cxx/win/iocp.cpp +0 -242
- pyxcp/cxx/win/iocp.hpp +0 -42
- pyxcp/cxx/win/perhandledata.hpp +0 -24
- pyxcp/cxx/win/periodata.hpp +0 -97
- pyxcp/cxx/win/socket.hpp +0 -185
- pyxcp/cxx/win/timeout.hpp +0 -83
- pyxcp/examples/conf_can.json +0 -20
- pyxcp/examples/conf_eth.json +0 -8
- pyxcp/logger.py +0 -67
- pyxcp/tests/test_config.py +0 -62
- pyxcp/transport/candriver/__init__.py +0 -2
- pyxcp/transport/candriver/pc_canalystii.py +0 -27
- pyxcp/transport/candriver/pc_etas.py +0 -25
- pyxcp/transport/candriver/pc_gsusb.py +0 -23
- pyxcp/transport/candriver/pc_iscan.py +0 -23
- pyxcp/transport/candriver/pc_ixxat.py +0 -27
- pyxcp/transport/candriver/pc_kvaser.py +0 -39
- pyxcp/transport/candriver/pc_neovi.py +0 -31
- pyxcp/transport/candriver/pc_nican.py +0 -23
- pyxcp/transport/candriver/pc_nixnet.py +0 -23
- pyxcp/transport/candriver/pc_pcan.py +0 -25
- pyxcp/transport/candriver/pc_seeed.py +0 -28
- pyxcp/transport/candriver/pc_serial.py +0 -27
- pyxcp/transport/candriver/pc_slcan.py +0 -29
- pyxcp/transport/candriver/pc_socketcan.py +0 -23
- pyxcp/transport/candriver/pc_systec.py +0 -29
- pyxcp/transport/candriver/pc_usb2can.py +0 -30
- pyxcp/transport/candriver/pc_vector.py +0 -34
- pyxcp/transport/candriver/python_can.py +0 -101
- pyxcp/transport/cxx_ext/CMakeLists.txt +0 -51
- pyxcp/transport/cxx_ext/setup.py +0 -49
- pyxcp/transport/cxx_ext/tests/test_basic_socket.cpp +0 -39
- pyxcp/transport/cxx_ext/tests/test_pool.cpp +0 -39
- pyxcp/transport/cxx_ext/tests/test_timestamp.cpp +0 -27
- pyxcp-0.21.9.dist-info/RECORD +0 -147
- rekorder.cp310-win_amd64.pyd +0 -0
- {pyxcp-0.21.9.dist-info/licenses → pyxcp-0.22.23.dist-info}/LICENSE +0 -0
pyxcp/transport/can.py
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
"""
|
|
4
3
|
"""
|
|
5
|
-
|
|
4
|
+
|
|
6
5
|
import functools
|
|
7
6
|
import operator
|
|
8
7
|
from bisect import bisect_left
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
from
|
|
8
|
+
from typing import Any, Dict, Optional, Type
|
|
9
|
+
|
|
10
|
+
from can import CanError, CanInitializationError, Message, detect_available_configs
|
|
11
|
+
from can.bus import BusABC
|
|
12
|
+
from can.interface import _get_class_for_interface
|
|
13
|
+
from rich.console import Console
|
|
12
14
|
|
|
13
|
-
from pyxcp.config import
|
|
15
|
+
from pyxcp.config import CAN_INTERFACE_MAP
|
|
14
16
|
from pyxcp.transport.base import BaseTransport
|
|
15
17
|
|
|
18
|
+
from ..utils import seconds_to_nanoseconds
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
16
22
|
|
|
17
23
|
CAN_EXTENDED_ID = 0x80000000
|
|
18
24
|
MAX_11_BIT_IDENTIFIER = (1 << 11) - 1
|
|
@@ -27,7 +33,7 @@ class IdentifierOutOfRangeError(Exception):
|
|
|
27
33
|
pass
|
|
28
34
|
|
|
29
35
|
|
|
30
|
-
def
|
|
36
|
+
def is_extended_identifier(identifier: int) -> bool:
|
|
31
37
|
"""Check for extendend CAN identifier.
|
|
32
38
|
|
|
33
39
|
Parameters
|
|
@@ -75,8 +81,8 @@ def samplePointToTsegs(tqs: int, samplePoint: float) -> tuple:
|
|
|
75
81
|
return (tseg1, tseg2)
|
|
76
82
|
|
|
77
83
|
|
|
78
|
-
def
|
|
79
|
-
"""Pad frame to next discrete DLC value.
|
|
84
|
+
def pad_frame(frame: bytes, pad_frame: bool, padding_value: int) -> bytes:
|
|
85
|
+
"""Pad frame to next discrete DLC value (CAN-FD) or on request (CAN-Classic).
|
|
80
86
|
|
|
81
87
|
References:
|
|
82
88
|
-----------
|
|
@@ -85,9 +91,9 @@ def padFrame(frame: bytes, padding_value: int, padding_len: int = 0) -> bytes:
|
|
|
85
91
|
AUTOSAR CP Release 4.3.0, Specification of CAN Driver; [SWS_CAN_00502], [ECUC_Can_00485]
|
|
86
92
|
AUTOSAR CP Release 4.3.0, Requirements on CAN; [SRS_Can_01073], [SRS_Can_01086], [SRS_Can_01160]
|
|
87
93
|
"""
|
|
88
|
-
frame_len =
|
|
94
|
+
frame_len = len(frame)
|
|
89
95
|
if frame_len <= MAX_DLC_CLASSIC:
|
|
90
|
-
actual_len = MAX_DLC_CLASSIC
|
|
96
|
+
actual_len = MAX_DLC_CLASSIC if pad_frame else frame_len
|
|
91
97
|
else:
|
|
92
98
|
actual_len = CAN_FD_DLCS[bisect_left(CAN_FD_DLCS, frame_len)]
|
|
93
99
|
# append fill bytes up to MAX_DLC resp. next discrete FD DLC.
|
|
@@ -112,13 +118,13 @@ class Identifier:
|
|
|
112
118
|
def __init__(self, raw_id: int):
|
|
113
119
|
self._raw_id = raw_id
|
|
114
120
|
self._id = stripIdentifier(raw_id)
|
|
115
|
-
self._is_extended =
|
|
121
|
+
self._is_extended = is_extended_identifier(raw_id)
|
|
116
122
|
if self._is_extended:
|
|
117
123
|
if self._id > MAX_29_BIT_IDENTIFIER:
|
|
118
|
-
raise IdentifierOutOfRangeError("29-bit identifier
|
|
124
|
+
raise IdentifierOutOfRangeError(f"29-bit identifier {self._id!r} is out of range")
|
|
119
125
|
else:
|
|
120
126
|
if self._id > MAX_11_BIT_IDENTIFIER:
|
|
121
|
-
raise IdentifierOutOfRangeError("11-bit identifier
|
|
127
|
+
raise IdentifierOutOfRangeError(f"11-bit identifier {self._id!r} is out of range")
|
|
122
128
|
|
|
123
129
|
@property
|
|
124
130
|
def id(self) -> int:
|
|
@@ -151,8 +157,20 @@ class Identifier:
|
|
|
151
157
|
"""
|
|
152
158
|
return self._is_extended
|
|
153
159
|
|
|
160
|
+
@property
|
|
161
|
+
def type_str(self) -> str:
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
str
|
|
167
|
+
- "S" - 11-bit identifier.
|
|
168
|
+
- "E" - 29-bit identifier.
|
|
169
|
+
"""
|
|
170
|
+
return "E" if self.is_extended else "S"
|
|
171
|
+
|
|
154
172
|
@staticmethod
|
|
155
|
-
def make_identifier(identifier: int, extended: bool) ->
|
|
173
|
+
def make_identifier(identifier: int, extended: bool) -> "Identifier":
|
|
156
174
|
"""Factory method.
|
|
157
175
|
|
|
158
176
|
Parameters
|
|
@@ -174,81 +192,107 @@ class Identifier:
|
|
|
174
192
|
"""
|
|
175
193
|
return Identifier(identifier if not extended else (identifier | CAN_EXTENDED_ID))
|
|
176
194
|
|
|
177
|
-
def
|
|
195
|
+
def create_filter_from_id(self) -> Dict:
|
|
196
|
+
"""Create a single CAN filter entry.
|
|
197
|
+
s. https://python-can.readthedocs.io/en/stable/bus.html#filtering
|
|
198
|
+
"""
|
|
199
|
+
return {
|
|
200
|
+
"can_id": self.id,
|
|
201
|
+
"can_mask": MAX_29_BIT_IDENTIFIER if self.is_extended else MAX_11_BIT_IDENTIFIER,
|
|
202
|
+
"extended": self.is_extended,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
def __eq__(self, other) -> bool:
|
|
178
206
|
return (self.id == other.id) and (self.is_extended == other.is_extended)
|
|
179
207
|
|
|
180
|
-
def __str__(self):
|
|
181
|
-
return "Identifier(id = 0x{:08x}, is_extended = {
|
|
208
|
+
def __str__(self) -> str:
|
|
209
|
+
return f"Identifier(id = 0x{self.id:08x}, is_extended = {self.is_extended})"
|
|
182
210
|
|
|
183
|
-
def __repr__(self):
|
|
184
|
-
return "Identifier(0x{:08x})"
|
|
211
|
+
def __repr__(self) -> str:
|
|
212
|
+
return f"Identifier(0x{self.raw_id:08x})"
|
|
185
213
|
|
|
186
214
|
|
|
187
215
|
class Frame:
|
|
188
216
|
""""""
|
|
189
217
|
|
|
190
|
-
def __init__(self, id_: Identifier, dlc: int, data: bytes, timestamp: int):
|
|
191
|
-
self.id = id_
|
|
192
|
-
self.dlc = dlc
|
|
193
|
-
self.data = data
|
|
194
|
-
self.timestamp = timestamp
|
|
218
|
+
def __init__(self, id_: Identifier, dlc: int, data: bytes, timestamp: int) -> None:
|
|
219
|
+
self.id: Identifier = id_
|
|
220
|
+
self.dlc: int = dlc
|
|
221
|
+
self.data: bytes = data
|
|
222
|
+
self.timestamp: int = timestamp
|
|
195
223
|
|
|
196
|
-
def __repr__(self):
|
|
197
|
-
return "Frame(id = 0x{:08x}, dlc = {}, data = {}, timestamp = {
|
|
224
|
+
def __repr__(self) -> str:
|
|
225
|
+
return f"Frame(id = 0x{self.id:08x}, dlc = {self.dlc}, data = {self.data}, timestamp = {self.timestamp})"
|
|
198
226
|
|
|
199
227
|
__str__ = __repr__
|
|
200
228
|
|
|
201
229
|
|
|
202
|
-
class
|
|
203
|
-
"""
|
|
204
|
-
Abstract CAN interface handler that can be implemented for any actual CAN device driver
|
|
205
|
-
"""
|
|
206
|
-
|
|
207
|
-
PARAMETER_MAP = {}
|
|
208
|
-
|
|
209
|
-
@abc.abstractmethod
|
|
210
|
-
def init(self, parent, receive_callback):
|
|
211
|
-
"""
|
|
212
|
-
Must implement any required action for initing the can interface
|
|
213
|
-
|
|
214
|
-
Parameters
|
|
215
|
-
----------
|
|
216
|
-
parent: :class:`Can`
|
|
217
|
-
Refers to owner.
|
|
218
|
-
receive_callback: callable
|
|
219
|
-
Receive callback function to register with the following argument: payload: bytes
|
|
220
|
-
"""
|
|
221
|
-
|
|
222
|
-
@abc.abstractmethod
|
|
223
|
-
def transmit(self, payload: bytes):
|
|
224
|
-
"""
|
|
225
|
-
Must transmit the given payload on the master can id.
|
|
226
|
-
|
|
227
|
-
Parameters
|
|
228
|
-
----------
|
|
229
|
-
payload: bytes
|
|
230
|
-
payload to transmit
|
|
231
|
-
"""
|
|
230
|
+
class PythonCanWrapper:
|
|
231
|
+
"""Wrapper around python-can - github.com/hardbyte/python-can"""
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
def __init__(self, parent, interface_name: str, timeout: int, **parameters) -> None:
|
|
234
|
+
self.parent = parent
|
|
235
|
+
self.interface_name: str = interface_name
|
|
236
|
+
self.timeout: int = timeout
|
|
237
|
+
self.parameters = parameters
|
|
238
|
+
self.can_interface_class: Type[BusABC] = _get_class_for_interface(self.interface_name)
|
|
239
|
+
self.can_interface: BusABC
|
|
240
|
+
self.connected: bool = False
|
|
236
241
|
|
|
237
|
-
@abc.abstractmethod
|
|
238
242
|
def connect(self):
|
|
239
|
-
|
|
243
|
+
if self.connected:
|
|
244
|
+
return
|
|
245
|
+
can_filters = []
|
|
246
|
+
can_filters.append(self.parent.can_id_slave.create_filter_from_id()) # Primary CAN filter.
|
|
247
|
+
if self.parent.has_user_supplied_interface:
|
|
248
|
+
self.can_interface = self.parent.transport_layer_interface
|
|
249
|
+
else:
|
|
250
|
+
self.can_interface = self.can_interface_class(interface=self.interface_name, **self.parameters)
|
|
251
|
+
if self.parent.daq_identifier:
|
|
252
|
+
# Add filters for DAQ identifiers.
|
|
253
|
+
for daq_id in self.parent.daq_identifier:
|
|
254
|
+
can_filters.append(daq_id.create_filter_from_id())
|
|
255
|
+
self.can_interface.set_filters(can_filters)
|
|
256
|
+
self.parent.logger.info(f"XCPonCAN - Using Interface: '{self.can_interface!s}'")
|
|
257
|
+
self.parent.logger.info(f"XCPonCAN - Filters used: {self.can_interface.filters}")
|
|
258
|
+
self.parent.logger.info(f"XCPonCAN - State: {self.can_interface.state!s}")
|
|
259
|
+
self.connected = True
|
|
240
260
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
261
|
+
def close(self):
|
|
262
|
+
if self.connected and not self.parent.has_user_supplied_interface:
|
|
263
|
+
self.can_interface.shutdown()
|
|
264
|
+
self.connected = False
|
|
265
|
+
|
|
266
|
+
def transmit(self, payload: bytes) -> None:
|
|
267
|
+
frame = Message(
|
|
268
|
+
arbitration_id=self.parent.can_id_master.id,
|
|
269
|
+
is_extended_id=True if self.parent.can_id_master.is_extended else False,
|
|
270
|
+
is_fd=self.parent.fd,
|
|
271
|
+
data=payload,
|
|
272
|
+
)
|
|
273
|
+
self.can_interface.send(frame)
|
|
244
274
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
275
|
+
def read(self) -> Optional[Frame]:
|
|
276
|
+
if not self.connected:
|
|
277
|
+
return None
|
|
278
|
+
try:
|
|
279
|
+
frame = self.can_interface.recv(self.timeout)
|
|
280
|
+
except CanError:
|
|
281
|
+
return None
|
|
282
|
+
else:
|
|
283
|
+
if frame is None or not len(frame.data):
|
|
284
|
+
return None # Timeout condition.
|
|
285
|
+
extended = frame.is_extended_id
|
|
286
|
+
identifier = Identifier.make_identifier(frame.arbitration_id, extended)
|
|
287
|
+
return Frame(
|
|
288
|
+
id_=identifier,
|
|
289
|
+
dlc=frame.dlc,
|
|
290
|
+
data=frame.data,
|
|
291
|
+
timestamp=seconds_to_nanoseconds(frame.timestamp),
|
|
292
|
+
)
|
|
248
293
|
|
|
249
|
-
def
|
|
250
|
-
|
|
251
|
-
self.config = Configuration(self.PARAMETER_MAP or {}, config or {})
|
|
294
|
+
def get_timestamp_resolution(self) -> int:
|
|
295
|
+
return 10 * 1000
|
|
252
296
|
|
|
253
297
|
|
|
254
298
|
class EmptyHeader:
|
|
@@ -258,106 +302,114 @@ class EmptyHeader:
|
|
|
258
302
|
return b""
|
|
259
303
|
|
|
260
304
|
|
|
261
|
-
# can.detect_available_configs()
|
|
262
|
-
|
|
263
|
-
|
|
264
305
|
class Can(BaseTransport):
|
|
265
306
|
""""""
|
|
266
307
|
|
|
267
|
-
PARAMETER_MAP = {
|
|
268
|
-
# Type Req'd Default
|
|
269
|
-
"CAN_DRIVER": (str, True, None),
|
|
270
|
-
"CHANNEL": (str, False, ""),
|
|
271
|
-
"MAX_DLC_REQUIRED": (bool, False, False),
|
|
272
|
-
"MAX_CAN_FD_DLC": (int, False, 64),
|
|
273
|
-
"PADDING_VALUE": (int, False, 0),
|
|
274
|
-
"CAN_USE_DEFAULT_LISTENER": (bool, False, True),
|
|
275
|
-
# defaults to True, in this case the default listener thread is used.
|
|
276
|
-
# If the canInterface implements a listener service, this parameter
|
|
277
|
-
# can be set to False, and the default listener thread won't be started.
|
|
278
|
-
"CAN_ID_MASTER": (int, True, None),
|
|
279
|
-
"CAN_ID_SLAVE": (int, True, None),
|
|
280
|
-
"CAN_ID_BROADCAST": (int, False, None),
|
|
281
|
-
"BITRATE": (int, False, 250000),
|
|
282
|
-
"RECEIVE_OWN_MESSAGES": (bool, False, False),
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
PARAMETER_TO_KW_ARG_MAP = {
|
|
286
|
-
"RECEIVE_OWN_MESSAGES": "receive_own_messages",
|
|
287
|
-
"CHANNEL": "channel",
|
|
288
|
-
"BITRATE": "bitrate",
|
|
289
|
-
}
|
|
290
|
-
|
|
291
308
|
MAX_DATAGRAM_SIZE = 7
|
|
292
309
|
HEADER = EmptyHeader()
|
|
293
310
|
HEADER_SIZE = 0
|
|
294
311
|
|
|
295
|
-
def __init__(self, config=None,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
self.
|
|
301
|
-
|
|
302
|
-
interfaceName = self.config.get("CAN_DRIVER")
|
|
303
|
-
if interfaceName not in drivers:
|
|
304
|
-
raise ValueError("{} is an invalid driver name -- choose from {}".format(interfaceName, [x for x in drivers.keys()]))
|
|
305
|
-
canInterfaceClass = drivers[interfaceName]
|
|
306
|
-
self.canInterface = canInterfaceClass()
|
|
307
|
-
self.useDefaultListener = self.config.get("CAN_USE_DEFAULT_LISTENER")
|
|
308
|
-
self.can_id_master = Identifier(self.config.get("CAN_ID_MASTER"))
|
|
309
|
-
self.can_id_slave = Identifier(self.config.get("CAN_ID_SLAVE"))
|
|
310
|
-
self.canInterface.loadConfig(config)
|
|
311
|
-
self.canInterface.init(self, self.dataReceived)
|
|
312
|
-
#
|
|
312
|
+
def __init__(self, config, policy=None, transport_layer_interface: Optional[BusABC] = None):
|
|
313
|
+
super().__init__(config, policy, transport_layer_interface)
|
|
314
|
+
self.load_config(config)
|
|
315
|
+
self.useDefaultListener = self.config.use_default_listener
|
|
316
|
+
self.can_id_master = Identifier(self.config.can_id_master)
|
|
317
|
+
self.can_id_slave = Identifier(self.config.can_id_slave)
|
|
318
|
+
|
|
313
319
|
# Regarding CAN-FD s. AUTOSAR CP Release 4.3.0, Requirements on CAN; [SRS_Can_01160] Padding of bytes due to discrete CAN FD DLC]:
|
|
314
320
|
# "... If a PDU does not exactly match these configurable sizes the unused bytes shall be padded."
|
|
315
321
|
#
|
|
316
|
-
self.
|
|
317
|
-
self.
|
|
318
|
-
|
|
322
|
+
self.fd = self.config.fd
|
|
323
|
+
self.daq_identifier = []
|
|
324
|
+
if self.config.daq_identifier:
|
|
325
|
+
for daq_id in self.config.daq_identifier:
|
|
326
|
+
self.daq_identifier.append(Identifier(daq_id))
|
|
327
|
+
self.max_dlc_required = self.config.max_dlc_required
|
|
328
|
+
self.padding_value = self.config.padding_value
|
|
329
|
+
self.interface_name = self.config.interface
|
|
330
|
+
self.interface_configuration = detect_available_configs(interfaces=[self.interface_name])
|
|
331
|
+
parameters = self.get_interface_parameters()
|
|
332
|
+
self.can_interface = PythonCanWrapper(self, self.interface_name, config.timeout, **parameters)
|
|
333
|
+
self.logger.info(f"XCPonCAN - Interface-Type: {self.interface_name!r} Parameters: {list(parameters.items())}")
|
|
334
|
+
self.logger.info(
|
|
335
|
+
f"XCPonCAN - Master-ID (Tx): 0x{self.can_id_master.id:08X}{self.can_id_master.type_str} -- "
|
|
336
|
+
f"Slave-ID (Rx): 0x{self.can_id_slave.id:08X}{self.can_id_slave.type_str}"
|
|
337
|
+
)
|
|
319
338
|
|
|
320
|
-
def
|
|
321
|
-
self.
|
|
339
|
+
def get_interface_parameters(self) -> Dict[str, Any]:
|
|
340
|
+
result = dict(channel=self.config.channel)
|
|
341
|
+
|
|
342
|
+
can_interface_config_class = CAN_INTERFACE_MAP[self.interface_name]
|
|
343
|
+
|
|
344
|
+
# Optional base class parameters.
|
|
345
|
+
optional_parameters = [(p, p.removeprefix("has_")) for p in can_interface_config_class.OPTIONAL_BASE_PARAMS]
|
|
346
|
+
for o, n in optional_parameters:
|
|
347
|
+
opt = getattr(can_interface_config_class, o)
|
|
348
|
+
value = getattr(self.config, n)
|
|
349
|
+
if opt:
|
|
350
|
+
if value is not None:
|
|
351
|
+
result[n] = value
|
|
352
|
+
elif value is not None:
|
|
353
|
+
self.logger.warning(f"XCPonCAN - {self.interface_name!r} has no support for parameter {n!r}.")
|
|
354
|
+
|
|
355
|
+
# Parameter names that need to be mapped.
|
|
356
|
+
for base_name, name in can_interface_config_class.CAN_PARAM_MAP.items():
|
|
357
|
+
value = getattr(self.config, base_name)
|
|
358
|
+
if value is not None:
|
|
359
|
+
result[name] = value
|
|
360
|
+
|
|
361
|
+
# Interface specific parameters.
|
|
362
|
+
cxx = getattr(self.config, self.interface_name)
|
|
363
|
+
for name in can_interface_config_class.class_own_traits().keys():
|
|
364
|
+
value = getattr(cxx, name)
|
|
365
|
+
if value is not None:
|
|
366
|
+
result[name] = value
|
|
367
|
+
return result
|
|
368
|
+
|
|
369
|
+
def data_received(self, payload: bytes, recv_timestamp: int):
|
|
370
|
+
self.process_response(
|
|
322
371
|
payload,
|
|
323
372
|
len(payload),
|
|
324
|
-
counter=(self.
|
|
373
|
+
counter=(self.counter_received + 1) & 0xFFFF,
|
|
325
374
|
recv_timestamp=recv_timestamp,
|
|
326
375
|
)
|
|
327
376
|
|
|
328
377
|
def listen(self):
|
|
329
378
|
while True:
|
|
330
|
-
if self.closeEvent.
|
|
379
|
+
if self.closeEvent.is_set():
|
|
331
380
|
return
|
|
332
|
-
frame = self.
|
|
381
|
+
frame = self.can_interface.read()
|
|
333
382
|
if frame:
|
|
334
|
-
self.
|
|
383
|
+
self.data_received(frame.data, frame.timestamp)
|
|
335
384
|
|
|
336
385
|
def connect(self):
|
|
337
386
|
if self.useDefaultListener:
|
|
338
|
-
self.
|
|
339
|
-
|
|
387
|
+
self.start_listener()
|
|
388
|
+
try:
|
|
389
|
+
self.can_interface.connect()
|
|
390
|
+
except CanInitializationError:
|
|
391
|
+
console.print("[red]\nThere may be a problem with the configuration of your CAN-interface.\n")
|
|
392
|
+
console.print(f"[grey]Current configuration of interface {self.interface_name!r}:")
|
|
393
|
+
console.print(self.interface_configuration)
|
|
394
|
+
raise
|
|
340
395
|
self.status = 1 # connected
|
|
341
396
|
|
|
342
|
-
def send(self, frame):
|
|
343
|
-
# XCP on CAN trailer: if required, FILL bytes must be appended
|
|
344
|
-
if self.max_dlc_required:
|
|
345
|
-
frame = padFrame(frame, self.padding_value, self.padding_len)
|
|
397
|
+
def send(self, frame: bytes) -> None:
|
|
346
398
|
# send the request
|
|
347
|
-
self.pre_send_timestamp =
|
|
348
|
-
self.
|
|
349
|
-
self.post_send_timestamp =
|
|
399
|
+
self.pre_send_timestamp = self.timestamp.value
|
|
400
|
+
self.can_interface.transmit(payload=pad_frame(frame, self.max_dlc_required, self.padding_value))
|
|
401
|
+
self.post_send_timestamp = self.timestamp.value
|
|
350
402
|
|
|
351
|
-
def
|
|
352
|
-
if hasattr(self, "
|
|
353
|
-
self.
|
|
403
|
+
def close_connection(self):
|
|
404
|
+
if hasattr(self, "can_interface"):
|
|
405
|
+
self.can_interface.close()
|
|
354
406
|
|
|
355
407
|
def close(self):
|
|
356
|
-
self.
|
|
357
|
-
self.
|
|
408
|
+
self.finish_listener()
|
|
409
|
+
self.close_connection()
|
|
358
410
|
|
|
359
411
|
|
|
360
|
-
def
|
|
412
|
+
def set_DLC(length: int):
|
|
361
413
|
"""Return DLC value according to CAN-FD.
|
|
362
414
|
|
|
363
415
|
:param length: Length value to be mapped to a valid CAN-FD DLC.
|
|
@@ -376,41 +428,16 @@ def setDLC(length: int):
|
|
|
376
428
|
raise ValueError("DLC could be at most 64.")
|
|
377
429
|
|
|
378
430
|
|
|
379
|
-
def
|
|
431
|
+
def calculate_filter(ids: list):
|
|
380
432
|
"""
|
|
381
433
|
:param ids: An iterable (usually list or tuple) containing CAN identifiers.
|
|
382
434
|
|
|
383
435
|
:return: Calculated filter and mask.
|
|
384
436
|
:rtype: tuple (int, int)
|
|
385
437
|
"""
|
|
386
|
-
any_extended_ids = any(
|
|
438
|
+
any_extended_ids = any(is_extended_identifier(i) for i in ids)
|
|
387
439
|
raw_ids = [stripIdentifier(i) for i in ids]
|
|
388
440
|
cfilter = functools.reduce(operator.and_, raw_ids)
|
|
389
441
|
cmask = functools.reduce(operator.or_, raw_ids) ^ cfilter
|
|
390
442
|
cmask ^= 0x1FFFFFFF if any_extended_ids else 0x7FF
|
|
391
443
|
return (cfilter, cmask)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
def try_to_install_system_supplied_drivers():
|
|
395
|
-
"""Register available pyxcp CAN drivers."""
|
|
396
|
-
import importlib
|
|
397
|
-
import pkgutil
|
|
398
|
-
import pyxcp.transport.candriver as cdr
|
|
399
|
-
|
|
400
|
-
for _, modname, _ in pkgutil.walk_packages(cdr.__path__, "{}.".format(cdr.__name__)):
|
|
401
|
-
try:
|
|
402
|
-
importlib.import_module(modname)
|
|
403
|
-
except Exception:
|
|
404
|
-
pass
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
def registered_drivers():
|
|
408
|
-
"""
|
|
409
|
-
Returns
|
|
410
|
-
-------
|
|
411
|
-
dict (name, class)
|
|
412
|
-
Dictionary containing CAN driver names and classes of all
|
|
413
|
-
available drivers (pyxcp supplied and user-defined).
|
|
414
|
-
"""
|
|
415
|
-
sub_classes = CanInterfaceBase.__subclasses__()
|
|
416
|
-
return OrderedDict(zip(([c.__name__ for c in sub_classes]), sub_classes))
|