pyxcp 0.22.33__cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.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.

Files changed (134) hide show
  1. pyxcp/__init__.py +20 -0
  2. pyxcp/aml/EtasCANMonitoring.a2l +82 -0
  3. pyxcp/aml/EtasCANMonitoring.aml +67 -0
  4. pyxcp/aml/XCP_Common.aml +408 -0
  5. pyxcp/aml/XCPonCAN.aml +78 -0
  6. pyxcp/aml/XCPonEth.aml +33 -0
  7. pyxcp/aml/XCPonFlx.aml +113 -0
  8. pyxcp/aml/XCPonSxI.aml +66 -0
  9. pyxcp/aml/XCPonUSB.aml +106 -0
  10. pyxcp/aml/ifdata_CAN.a2l +20 -0
  11. pyxcp/aml/ifdata_Eth.a2l +11 -0
  12. pyxcp/aml/ifdata_Flx.a2l +94 -0
  13. pyxcp/aml/ifdata_SxI.a2l +13 -0
  14. pyxcp/aml/ifdata_USB.a2l +81 -0
  15. pyxcp/asam/__init__.py +0 -0
  16. pyxcp/asam/types.py +131 -0
  17. pyxcp/asamkeydll.c +116 -0
  18. pyxcp/asamkeydll.sh +2 -0
  19. pyxcp/checksum.py +732 -0
  20. pyxcp/cmdline.py +52 -0
  21. pyxcp/config/__init__.py +1102 -0
  22. pyxcp/config/legacy.py +120 -0
  23. pyxcp/constants.py +47 -0
  24. pyxcp/cpp_ext/__init__.py +0 -0
  25. pyxcp/cpp_ext/bin.hpp +104 -0
  26. pyxcp/cpp_ext/blockmem.hpp +58 -0
  27. pyxcp/cpp_ext/cpp_ext.cpython-310-aarch64-linux-gnu.so +0 -0
  28. pyxcp/cpp_ext/cpp_ext.cpython-311-aarch64-linux-gnu.so +0 -0
  29. pyxcp/cpp_ext/cpp_ext.cpython-312-aarch64-linux-gnu.so +0 -0
  30. pyxcp/cpp_ext/cpp_ext.cpython-313-aarch64-linux-gnu.so +0 -0
  31. pyxcp/cpp_ext/daqlist.hpp +206 -0
  32. pyxcp/cpp_ext/event.hpp +67 -0
  33. pyxcp/cpp_ext/extension_wrapper.cpp +100 -0
  34. pyxcp/cpp_ext/helper.hpp +280 -0
  35. pyxcp/cpp_ext/mcobject.hpp +246 -0
  36. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  37. pyxcp/daq_stim/__init__.py +232 -0
  38. pyxcp/daq_stim/optimize/__init__.py +67 -0
  39. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  40. pyxcp/daq_stim/scheduler.cpp +28 -0
  41. pyxcp/daq_stim/scheduler.hpp +75 -0
  42. pyxcp/daq_stim/stim.cpp +13 -0
  43. pyxcp/daq_stim/stim.cpython-310-aarch64-linux-gnu.so +0 -0
  44. pyxcp/daq_stim/stim.cpython-311-aarch64-linux-gnu.so +0 -0
  45. pyxcp/daq_stim/stim.cpython-312-aarch64-linux-gnu.so +0 -0
  46. pyxcp/daq_stim/stim.cpython-313-aarch64-linux-gnu.so +0 -0
  47. pyxcp/daq_stim/stim.hpp +604 -0
  48. pyxcp/daq_stim/stim_wrapper.cpp +50 -0
  49. pyxcp/dllif.py +95 -0
  50. pyxcp/errormatrix.py +878 -0
  51. pyxcp/examples/conf_can.toml +19 -0
  52. pyxcp/examples/conf_can_user.toml +16 -0
  53. pyxcp/examples/conf_can_vector.json +11 -0
  54. pyxcp/examples/conf_can_vector.toml +11 -0
  55. pyxcp/examples/conf_eth.toml +9 -0
  56. pyxcp/examples/conf_nixnet.json +20 -0
  57. pyxcp/examples/conf_socket_can.toml +12 -0
  58. pyxcp/examples/conf_sxi.json +9 -0
  59. pyxcp/examples/conf_sxi.toml +7 -0
  60. pyxcp/examples/run_daq.py +163 -0
  61. pyxcp/examples/xcp_policy.py +60 -0
  62. pyxcp/examples/xcp_read_benchmark.py +38 -0
  63. pyxcp/examples/xcp_skel.py +49 -0
  64. pyxcp/examples/xcp_unlock.py +38 -0
  65. pyxcp/examples/xcp_user_supplied_driver.py +54 -0
  66. pyxcp/examples/xcphello.py +79 -0
  67. pyxcp/examples/xcphello_recorder.py +107 -0
  68. pyxcp/master/__init__.py +9 -0
  69. pyxcp/master/errorhandler.py +442 -0
  70. pyxcp/master/master.py +2046 -0
  71. pyxcp/py.typed +0 -0
  72. pyxcp/recorder/__init__.py +101 -0
  73. pyxcp/recorder/build_clang.cmd +1 -0
  74. pyxcp/recorder/build_clang.sh +2 -0
  75. pyxcp/recorder/build_gcc.cmd +1 -0
  76. pyxcp/recorder/build_gcc.sh +2 -0
  77. pyxcp/recorder/build_gcc_arm.sh +2 -0
  78. pyxcp/recorder/converter/__init__.py +451 -0
  79. pyxcp/recorder/lz4.c +2829 -0
  80. pyxcp/recorder/lz4.h +879 -0
  81. pyxcp/recorder/lz4hc.c +2041 -0
  82. pyxcp/recorder/lz4hc.h +413 -0
  83. pyxcp/recorder/mio.hpp +1714 -0
  84. pyxcp/recorder/reader.hpp +139 -0
  85. pyxcp/recorder/reco.py +277 -0
  86. pyxcp/recorder/recorder.rst +0 -0
  87. pyxcp/recorder/rekorder.cpp +59 -0
  88. pyxcp/recorder/rekorder.cpython-310-aarch64-linux-gnu.so +0 -0
  89. pyxcp/recorder/rekorder.cpython-311-aarch64-linux-gnu.so +0 -0
  90. pyxcp/recorder/rekorder.cpython-312-aarch64-linux-gnu.so +0 -0
  91. pyxcp/recorder/rekorder.cpython-313-aarch64-linux-gnu.so +0 -0
  92. pyxcp/recorder/rekorder.hpp +274 -0
  93. pyxcp/recorder/setup.py +41 -0
  94. pyxcp/recorder/test_reko.py +34 -0
  95. pyxcp/recorder/unfolder.hpp +1332 -0
  96. pyxcp/recorder/wrap.cpp +189 -0
  97. pyxcp/recorder/writer.hpp +302 -0
  98. pyxcp/scripts/__init__.py +0 -0
  99. pyxcp/scripts/pyxcp_probe_can_drivers.py +20 -0
  100. pyxcp/scripts/xcp_examples.py +64 -0
  101. pyxcp/scripts/xcp_fetch_a2l.py +40 -0
  102. pyxcp/scripts/xcp_id_scanner.py +19 -0
  103. pyxcp/scripts/xcp_info.py +146 -0
  104. pyxcp/scripts/xcp_profile.py +27 -0
  105. pyxcp/scripts/xmraw_converter.py +31 -0
  106. pyxcp/stim/__init__.py +0 -0
  107. pyxcp/tests/test_asam_types.py +24 -0
  108. pyxcp/tests/test_binpacking.py +186 -0
  109. pyxcp/tests/test_can.py +1324 -0
  110. pyxcp/tests/test_checksum.py +95 -0
  111. pyxcp/tests/test_daq.py +193 -0
  112. pyxcp/tests/test_daq_opt.py +426 -0
  113. pyxcp/tests/test_frame_padding.py +156 -0
  114. pyxcp/tests/test_master.py +2006 -0
  115. pyxcp/tests/test_transport.py +81 -0
  116. pyxcp/tests/test_utils.py +30 -0
  117. pyxcp/timing.py +60 -0
  118. pyxcp/transport/__init__.py +10 -0
  119. pyxcp/transport/base.py +440 -0
  120. pyxcp/transport/base_transport.hpp +0 -0
  121. pyxcp/transport/can.py +441 -0
  122. pyxcp/transport/eth.py +219 -0
  123. pyxcp/transport/sxi.py +135 -0
  124. pyxcp/transport/transport_wrapper.cpp +0 -0
  125. pyxcp/transport/usb_transport.py +213 -0
  126. pyxcp/types.py +1000 -0
  127. pyxcp/utils.py +127 -0
  128. pyxcp/vector/__init__.py +0 -0
  129. pyxcp/vector/map.py +82 -0
  130. pyxcp-0.22.33.dist-info/LICENSE +165 -0
  131. pyxcp-0.22.33.dist-info/METADATA +107 -0
  132. pyxcp-0.22.33.dist-info/RECORD +134 -0
  133. pyxcp-0.22.33.dist-info/WHEEL +6 -0
  134. pyxcp-0.22.33.dist-info/entry_points.txt +9 -0
pyxcp/transport/sxi.py ADDED
@@ -0,0 +1,135 @@
1
+ import struct
2
+ from collections import deque
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+ import serial
7
+
8
+ import pyxcp.types as types
9
+ from pyxcp.transport.base import BaseTransport
10
+
11
+
12
+ @dataclass
13
+ class HeaderValues:
14
+ length: int = 0
15
+ counter: int = 0
16
+ filler: int = 0
17
+
18
+
19
+ RECV_SIZE = 16384
20
+
21
+
22
+ class SxI(BaseTransport):
23
+ """"""
24
+
25
+ def __init__(self, config=None, policy=None, transport_layer_interface: Optional[serial.Serial] = None) -> None:
26
+ super().__init__(config, policy, transport_layer_interface)
27
+ self.load_config(config)
28
+ self.port_name = self.config.port
29
+ self.baudrate = self.config.bitrate
30
+ self.bytesize = self.config.bytesize
31
+ self.parity = self.config.parity
32
+ self.stopbits = self.config.stopbits
33
+ self.mode = self.config.mode
34
+ self.header_format = self.config.header_format
35
+ self.tail_format = self.config.tail_format
36
+ self.framing = self.config.framing
37
+ self.esc_sync = self.config.esc_sync
38
+ self.esc_esc = self.config.esc_esc
39
+ self.make_header()
40
+ self.comm_port: serial.Serial
41
+
42
+ if self.has_user_supplied_interface and transport_layer_interface:
43
+ self.comm_port = transport_layer_interface
44
+ else:
45
+ self.logger.info(f"XCPonSxI - trying to open serial comm_port {self.port_name!r}.")
46
+ try:
47
+ self.comm_port = serial.Serial(
48
+ port=self.port_name,
49
+ baudrate=self.baudrate,
50
+ bytesize=self.bytesize,
51
+ parity=self.parity,
52
+ stopbits=self.stopbits,
53
+ timeout=self.timeout,
54
+ write_timeout=self.timeout,
55
+ )
56
+ except serial.SerialException as e:
57
+ self.logger.critical(f"XCPonSxI - {e}")
58
+ raise
59
+ self._packets = deque()
60
+
61
+ def __del__(self) -> None:
62
+ self.close_connection()
63
+
64
+ def make_header(self) -> None:
65
+ def unpack_len(args):
66
+ (length,) = args
67
+ return HeaderValues(length=length)
68
+
69
+ def unpack_len_counter(args):
70
+ length, counter = args
71
+ return HeaderValues(length=length, counter=counter)
72
+
73
+ def unpack_len_filler(args):
74
+ length, filler = args
75
+ return HeaderValues(length=length, filler=filler)
76
+
77
+ HEADER_FORMATS = {
78
+ "HEADER_LEN_BYTE": ("B", unpack_len),
79
+ "HEADER_LEN_CTR_BYTE": ("BB", unpack_len_counter),
80
+ "HEADER_LEN_FILL_BYTE": ("BB", unpack_len_filler),
81
+ "HEADER_LEN_WORD": ("H", unpack_len),
82
+ "HEADER_LEN_CTR_WORD": ("HH", unpack_len_counter),
83
+ "HEADER_LEN_FILL_WORD": ("HH", unpack_len_filler),
84
+ }
85
+ fmt, unpacker = HEADER_FORMATS[self.header_format]
86
+ self.HEADER = struct.Struct(f"<{fmt}")
87
+ self.HEADER_SIZE = self.HEADER.size
88
+ self.unpacker = unpacker
89
+
90
+ def connect(self) -> None:
91
+ self.logger.info(
92
+ f"XCPonSxI - serial comm_port {self.comm_port.portstr!r} openend [{self.baudrate}/{self.bytesize}-{self.parity}-{self.stopbits}]"
93
+ )
94
+ self.start_listener()
95
+
96
+ def output(self, enable) -> None:
97
+ if enable:
98
+ self.comm_port.rts = False
99
+ self.comm_port.dtr = False
100
+ else:
101
+ self.comm_port.rts = True
102
+ self.comm_port.dtr = True
103
+
104
+ def flush(self) -> None:
105
+ self.comm_port.flush()
106
+
107
+ def start_listener(self) -> None:
108
+ super().start_listener()
109
+
110
+ def listen(self) -> None:
111
+ while True:
112
+ if self.closeEvent.is_set():
113
+ return
114
+ if not self.comm_port.in_waiting:
115
+ continue
116
+
117
+ recv_timestamp = self.timestamp.value
118
+ header_values = self.unpacker(self.HEADER.unpack(self.comm_port.read(self.HEADER_SIZE)))
119
+ length, counter, _ = header_values.length, header_values.counter, header_values.filler
120
+
121
+ response = self.comm_port.read(length)
122
+ self.timing.stop()
123
+
124
+ if len(response) != length:
125
+ raise types.FrameSizeError("Size mismatch.")
126
+ self.process_response(response, length, counter, recv_timestamp)
127
+
128
+ def send(self, frame) -> None:
129
+ self.pre_send_timestamp = self.timestamp.value
130
+ self.comm_port.write(frame)
131
+ self.post_send_timestamp = self.timestamp.value
132
+
133
+ def close_connection(self) -> None:
134
+ if hasattr(self, "comm_port") and self.comm_port.is_open and not self.has_user_supplied_interface:
135
+ self.comm_port.close()
File without changes
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env python
2
+ import struct
3
+ import threading
4
+ from array import array
5
+ from collections import deque
6
+ from typing import Optional
7
+
8
+ import usb.backend.libusb0 as libusb0
9
+ import usb.backend.libusb1 as libusb1
10
+ import usb.backend.openusb as openusb
11
+ import usb.core
12
+ import usb.util
13
+ from usb.core import USBError, USBTimeoutError
14
+
15
+ from pyxcp.transport.base import BaseTransport
16
+ from pyxcp.utils import short_sleep
17
+
18
+
19
+ RECV_SIZE = 16384
20
+ FIVE_MS = 5_000_000 # Five milliseconds in nanoseconds.
21
+
22
+
23
+ class Usb(BaseTransport):
24
+ """"""
25
+
26
+ HEADER = struct.Struct("<2H")
27
+ HEADER_SIZE = HEADER.size
28
+
29
+ def __init__(self, config=None, policy=None, transport_layer_interface: Optional[usb.core.Device] = None):
30
+ super().__init__(config, policy, transport_layer_interface)
31
+ self.load_config(config)
32
+ self.serial_number: str = self.config.serial_number
33
+ self.vendor_id: int = self.config.vendor_id
34
+ self.product_id: int = self.config.product_id
35
+ self.configuration_number: int = self.config.configuration_number
36
+ self.interface_number: int = self.config.interface_number
37
+ self.library: str = self.config.library
38
+ self.header_format: str = self.config.header_format
39
+ self.library = self.config.get("library")
40
+ self.device = None
41
+
42
+ ## IN-EP (RES/ERR, DAQ, and EV/SERV) Parameters.
43
+ self.in_ep_number: int = self.config.in_ep_number
44
+ self.in_ep_transfer_type = self.config.in_ep_transfer_type
45
+ self.in_ep_max_packet_size: int = self.config.in_ep_max_packet_size
46
+ self.in_ep_polling_interval: int = self.config.in_ep_polling_interval
47
+ self.in_ep_message_packing = self.config.in_ep_message_packing
48
+ self.in_ep_alignment = self.config.in_ep_alignment
49
+ self.in_ep_recommended_host_bufsize: int = self.config.in_ep_recommended_host_bufsize
50
+
51
+ ## OUT-EP (CMD and STIM) Parameters.
52
+ self.out_ep_number: int = self.config.out_ep_number
53
+
54
+ self.device: Optional[usb.core.Device] = None
55
+ self.status = 0
56
+
57
+ self._packet_listener = threading.Thread(
58
+ target=self._packet_listen,
59
+ args=(),
60
+ kwargs={},
61
+ )
62
+ self._packets = deque()
63
+
64
+ def connect(self):
65
+ if self.library:
66
+ for backend_provider in (libusb1, libusb0, openusb):
67
+ backend = backend_provider.get_backend(find_library=lambda x: self.library)
68
+ if backend:
69
+ break
70
+ else:
71
+ backend = None
72
+
73
+ if self.vendor_id and self.product_id:
74
+ kwargs = {
75
+ "find_all": True,
76
+ "idVendor": self.vendor_id,
77
+ "idProduct": self.product_id,
78
+ "backend": backend,
79
+ }
80
+ else:
81
+ kwargs = {
82
+ "find_all": True,
83
+ "backend": backend,
84
+ }
85
+
86
+ for device in usb.core.find(**kwargs):
87
+ try:
88
+ if device.serial_number.strip().strip("\0").lower() == self.serial_number.lower():
89
+ self.device = device
90
+ break
91
+ except (USBError, USBTimeoutError):
92
+ continue
93
+ else:
94
+ raise Exception(f"XCPonUSB - device with serial {self.serial_number!r} not found")
95
+
96
+ current_configuration = self.device.get_active_configuration()
97
+ if current_configuration.bConfigurationValue != self.configuration_number:
98
+ self.device.set_configuration(self.configuration_number)
99
+ cfg = self.device.get_active_configuration()
100
+
101
+ interface = cfg[(self.interface_number, 0)]
102
+
103
+ self.out_ep = interface[self.out_ep_number]
104
+ self.in_ep = interface[self.in_ep_number]
105
+
106
+ self.start_listener()
107
+ self.status = 1 # connected
108
+
109
+ def start_listener(self):
110
+ super().start_listener()
111
+ if self._packet_listener.is_alive():
112
+ self._packet_listener.join()
113
+ self._packet_listener = threading.Thread(target=self._packet_listen)
114
+ self._packet_listener.start()
115
+
116
+ def close(self):
117
+ """Close the transport-layer connection and event-loop."""
118
+ self.finish_listener()
119
+ if self.listener.is_alive():
120
+ self.listener.join()
121
+ if self._packet_listener.is_alive():
122
+ self._packet_listener.join()
123
+ self.close_connection()
124
+
125
+ def _packet_listen(self):
126
+ close_event_set = self.closeEvent.is_set
127
+ _packets = self._packets
128
+ read = self.in_ep.read
129
+ buffer = array("B", bytes(RECV_SIZE))
130
+ buffer_view = memoryview(buffer)
131
+ while True:
132
+ try:
133
+ if close_event_set():
134
+ return
135
+ try:
136
+ recv_timestamp = self.timestamp.value
137
+ read_count = read(buffer, 100) # 100ms timeout
138
+ if read_count != RECV_SIZE:
139
+ _packets.append((buffer_view[:read_count].tobytes(), recv_timestamp))
140
+ else:
141
+ _packets.append((buffer.tobytes(), recv_timestamp))
142
+ except (USBError, USBTimeoutError):
143
+ # print(format_exc())
144
+ short_sleep()
145
+ continue
146
+ except BaseException: # noqa: B036
147
+ # Note: catch-all only permitted if the intention is re-raising.
148
+ self.status = 0 # disconnected
149
+ break
150
+
151
+ def listen(self):
152
+ HEADER_UNPACK_FROM = self.HEADER.unpack_from
153
+ HEADER_SIZE = self.HEADER_SIZE
154
+ popleft = self._packets.popleft
155
+ process_response = self.process_response
156
+ close_event_set = self.closeEvent.is_set
157
+ _packets = self._packets
158
+ length: Optional[int] = None
159
+ counter: int = 0
160
+ data: bytearray = bytearray(b"")
161
+ last_sleep: int = self.timestamp.value
162
+
163
+ while True:
164
+ if close_event_set():
165
+ return
166
+ count: int = len(_packets)
167
+ if not count:
168
+ short_sleep()
169
+ last_sleep = self.timestamp.value
170
+ continue
171
+ for _ in range(count):
172
+ bts, timestamp = popleft()
173
+ data += bts
174
+ current_size: int = len(data)
175
+ current_position: int = 0
176
+ while True:
177
+ if self.timestamp.value - last_sleep >= FIVE_MS:
178
+ short_sleep()
179
+ last_sleep = self.timestamp.value
180
+ if length is None:
181
+ if current_size >= HEADER_SIZE:
182
+ length, counter = HEADER_UNPACK_FROM(data, current_position)
183
+ current_position += HEADER_SIZE
184
+ current_size -= HEADER_SIZE
185
+ else:
186
+ data = data[current_position:]
187
+ break
188
+ else:
189
+ if current_size >= length:
190
+ response = data[current_position : current_position + length]
191
+ process_response(response, length, counter, timestamp)
192
+ current_size -= length
193
+ current_position += length
194
+ length = None
195
+ else:
196
+ data = data[current_position:]
197
+ break
198
+
199
+ def send(self, frame):
200
+ self.pre_send_timestamp = self.timestamp.value
201
+ try:
202
+ self.out_ep.write(frame)
203
+ except (USBError, USBTimeoutError):
204
+ # sometimes usb.core.USBError: [Errno 5] Input/Output Error is raised
205
+ # even though the command is send and a reply is received from the device.
206
+ # Ignore this here since a Timeout error will be raised anyway if
207
+ # the device does not respond
208
+ pass
209
+ self.post_send_timestamp = self.timestamp.value
210
+
211
+ def close_connection(self):
212
+ if self.device is not None:
213
+ usb.util.dispose_resources(self.device)