pyxcp 0.21.9__cp39-cp39-win_amd64.whl → 0.22.23__cp39-cp39-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.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.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.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 +131 -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.cp39-win_amd64.pyd +0 -0
- {pyxcp-0.21.9.dist-info/licenses → pyxcp-0.22.23.dist-info}/LICENSE +0 -0
pyxcp/transport/eth.py
CHANGED
|
@@ -1,66 +1,78 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
import selectors
|
|
4
3
|
import socket
|
|
5
4
|
import struct
|
|
6
5
|
import threading
|
|
7
6
|
from collections import deque
|
|
8
|
-
from
|
|
9
|
-
from time import sleep
|
|
10
|
-
from time import time
|
|
7
|
+
from typing import Optional
|
|
11
8
|
|
|
12
9
|
from pyxcp.transport.base import BaseTransport
|
|
13
|
-
from pyxcp.utils import
|
|
10
|
+
from pyxcp.utils import short_sleep
|
|
11
|
+
|
|
14
12
|
|
|
15
13
|
DEFAULT_XCP_PORT = 5555
|
|
16
14
|
RECV_SIZE = 8196
|
|
17
15
|
|
|
18
16
|
|
|
17
|
+
def socket_to_str(sock: socket.socket) -> str:
|
|
18
|
+
peer = sock.getpeername()
|
|
19
|
+
local = sock.getsockname()
|
|
20
|
+
AF = {
|
|
21
|
+
socket.AF_INET: "AF_INET",
|
|
22
|
+
socket.AF_INET6: "AF_INET6",
|
|
23
|
+
}
|
|
24
|
+
TYPE = {
|
|
25
|
+
socket.SOCK_DGRAM: "SOCK_DGRAM",
|
|
26
|
+
socket.SOCK_STREAM: "SOCK_STREAM",
|
|
27
|
+
}
|
|
28
|
+
family = AF.get(sock.family, "OTHER")
|
|
29
|
+
typ = TYPE.get(sock.type, "UNKNOWN")
|
|
30
|
+
res = f"XCPonEth - Connected to: {peer[0]}:{peer[1]} local address: {local[0]}:{local[1]} [{family}][{typ}]"
|
|
31
|
+
return res
|
|
32
|
+
|
|
33
|
+
|
|
19
34
|
class Eth(BaseTransport):
|
|
20
35
|
""""""
|
|
21
36
|
|
|
22
|
-
PARAMETER_MAP = {
|
|
23
|
-
# Type Req'd Default
|
|
24
|
-
"HOST": (str, False, "localhost"),
|
|
25
|
-
"PORT": (int, False, 5555),
|
|
26
|
-
"BIND_TO_ADDRESS": (str, False, ""),
|
|
27
|
-
"BIND_TO_PORT": (int, False, 5555),
|
|
28
|
-
"PROTOCOL": (str, False, "TCP"),
|
|
29
|
-
"IPV6": (bool, False, False),
|
|
30
|
-
"TCP_NODELAY": (bool, False, False),
|
|
31
|
-
}
|
|
32
|
-
|
|
33
37
|
MAX_DATAGRAM_SIZE = 512
|
|
34
38
|
HEADER = struct.Struct("<HH")
|
|
35
39
|
HEADER_SIZE = HEADER.size
|
|
36
40
|
|
|
37
|
-
def __init__(self, config=None, policy=None):
|
|
38
|
-
super(
|
|
39
|
-
self.
|
|
40
|
-
self.host = self.config.
|
|
41
|
-
self.port = self.config.
|
|
42
|
-
self.protocol = self.config.
|
|
43
|
-
self.ipv6 = self.config.
|
|
44
|
-
self.use_tcp_no_delay = self.config.
|
|
45
|
-
address_to_bind = self.config.
|
|
46
|
-
|
|
47
|
-
self._local_address = (address_to_bind,
|
|
41
|
+
def __init__(self, config=None, policy=None, transport_layer_interface: Optional[socket.socket] = None) -> None:
|
|
42
|
+
super().__init__(config, policy, transport_layer_interface)
|
|
43
|
+
self.load_config(config)
|
|
44
|
+
self.host: str = self.config.host
|
|
45
|
+
self.port: int = self.config.port
|
|
46
|
+
self.protocol: int = self.config.protocol
|
|
47
|
+
self.ipv6: bool = self.config.ipv6
|
|
48
|
+
self.use_tcp_no_delay: bool = self.config.tcp_nodelay
|
|
49
|
+
address_to_bind: str = self.config.bind_to_address
|
|
50
|
+
bind_to_port: int = self.config.bind_to_port
|
|
51
|
+
self._local_address = (address_to_bind, bind_to_port) if address_to_bind else None
|
|
48
52
|
if self.ipv6 and not socket.has_ipv6:
|
|
49
|
-
|
|
53
|
+
msg = "XCPonEth - IPv6 not supported by your platform."
|
|
54
|
+
self.logger.critical(msg)
|
|
55
|
+
raise RuntimeError(msg)
|
|
50
56
|
else:
|
|
51
57
|
address_family = socket.AF_INET6 if self.ipv6 else socket.AF_INET
|
|
52
58
|
proto = socket.SOCK_STREAM if self.protocol == "TCP" else socket.SOCK_DGRAM
|
|
53
59
|
if self.host.lower() == "localhost":
|
|
54
60
|
self.host = "::1" if self.ipv6 else "localhost"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.address_family,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
addrinfo = socket.getaddrinfo(self.host, self.port, address_family, proto)
|
|
64
|
+
(
|
|
65
|
+
self.address_family,
|
|
66
|
+
self.socktype,
|
|
67
|
+
self.proto,
|
|
68
|
+
self.canonname,
|
|
69
|
+
self.sockaddr,
|
|
70
|
+
) = addrinfo[0]
|
|
71
|
+
except BaseException as ex: # noqa: B036
|
|
72
|
+
msg = f"XCPonEth - Failed to resolve address {self.host}:{self.port}"
|
|
73
|
+
self.logger.critical(msg)
|
|
74
|
+
raise Exception(msg) from ex
|
|
75
|
+
self.status: int = 0
|
|
64
76
|
self.sock = socket.socket(self.address_family, self.socktype, self.proto)
|
|
65
77
|
self.selector = selectors.DefaultSelector()
|
|
66
78
|
self.selector.register(self.sock, selectors.EVENT_READ)
|
|
@@ -74,8 +86,10 @@ class Eth(BaseTransport):
|
|
|
74
86
|
if self._local_address:
|
|
75
87
|
try:
|
|
76
88
|
self.sock.bind(self._local_address)
|
|
77
|
-
except BaseException as ex:
|
|
78
|
-
|
|
89
|
+
except BaseException as ex: # noqa: B036
|
|
90
|
+
msg = f"XCPonEth - Failed to bind socket to given address {self._local_address}"
|
|
91
|
+
self.logger.critical(msg)
|
|
92
|
+
raise Exception(msg) from ex
|
|
79
93
|
self._packet_listener = threading.Thread(
|
|
80
94
|
target=self._packet_listen,
|
|
81
95
|
args=(),
|
|
@@ -83,43 +97,40 @@ class Eth(BaseTransport):
|
|
|
83
97
|
)
|
|
84
98
|
self._packets = deque()
|
|
85
99
|
|
|
86
|
-
def connect(self):
|
|
100
|
+
def connect(self) -> None:
|
|
87
101
|
if self.status == 0:
|
|
88
102
|
self.sock.connect(self.sockaddr)
|
|
89
|
-
self.
|
|
103
|
+
self.logger.info(socket_to_str(self.sock))
|
|
104
|
+
self.start_listener()
|
|
90
105
|
self.status = 1 # connected
|
|
91
106
|
|
|
92
|
-
def
|
|
93
|
-
super().
|
|
107
|
+
def start_listener(self) -> None:
|
|
108
|
+
super().start_listener()
|
|
94
109
|
if self._packet_listener.is_alive():
|
|
95
110
|
self._packet_listener.join()
|
|
96
111
|
self._packet_listener = threading.Thread(target=self._packet_listen)
|
|
97
112
|
self._packet_listener.start()
|
|
98
113
|
|
|
99
|
-
def close(self):
|
|
114
|
+
def close(self) -> None:
|
|
100
115
|
"""Close the transport-layer connection and event-loop."""
|
|
101
|
-
self.
|
|
116
|
+
self.finish_listener()
|
|
102
117
|
if self.listener.is_alive():
|
|
103
118
|
self.listener.join()
|
|
104
119
|
if self._packet_listener.is_alive():
|
|
105
120
|
self._packet_listener.join()
|
|
106
|
-
self.
|
|
121
|
+
self.close_connection()
|
|
107
122
|
|
|
108
|
-
def _packet_listen(self):
|
|
109
|
-
use_tcp = self.use_tcp
|
|
123
|
+
def _packet_listen(self) -> None:
|
|
124
|
+
use_tcp: bool = self.use_tcp
|
|
110
125
|
EVENT_READ = selectors.EVENT_READ
|
|
111
|
-
|
|
112
126
|
close_event_set = self.closeEvent.is_set
|
|
113
127
|
socket_fileno = self.sock.fileno
|
|
114
128
|
select = self.selector.select
|
|
115
|
-
|
|
116
129
|
_packets = self._packets
|
|
117
|
-
|
|
118
130
|
if use_tcp:
|
|
119
131
|
sock_recv = self.sock.recv
|
|
120
132
|
else:
|
|
121
133
|
sock_recv = self.sock.recvfrom
|
|
122
|
-
|
|
123
134
|
while True:
|
|
124
135
|
try:
|
|
125
136
|
if close_event_set() or socket_fileno() == -1:
|
|
@@ -127,8 +138,7 @@ class Eth(BaseTransport):
|
|
|
127
138
|
sel = select(0.02)
|
|
128
139
|
for _, events in sel:
|
|
129
140
|
if events & EVENT_READ:
|
|
130
|
-
recv_timestamp =
|
|
131
|
-
|
|
141
|
+
recv_timestamp = self.timestamp.value
|
|
132
142
|
if use_tcp:
|
|
133
143
|
response = sock_recv(RECV_SIZE)
|
|
134
144
|
if not response:
|
|
@@ -145,41 +155,33 @@ class Eth(BaseTransport):
|
|
|
145
155
|
break
|
|
146
156
|
else:
|
|
147
157
|
_packets.append((response, recv_timestamp))
|
|
148
|
-
except BaseException:
|
|
158
|
+
except BaseException: # noqa: B036
|
|
149
159
|
self.status = 0 # disconnected
|
|
150
160
|
break
|
|
151
161
|
|
|
152
|
-
def listen(self):
|
|
162
|
+
def listen(self) -> None:
|
|
153
163
|
HEADER_UNPACK_FROM = self.HEADER.unpack_from
|
|
154
164
|
HEADER_SIZE = self.HEADER_SIZE
|
|
155
|
-
|
|
165
|
+
process_response = self.process_response
|
|
156
166
|
popleft = self._packets.popleft
|
|
157
|
-
|
|
158
167
|
close_event_set = self.closeEvent.is_set
|
|
159
168
|
socket_fileno = self.sock.fileno
|
|
160
|
-
|
|
161
169
|
_packets = self._packets
|
|
162
|
-
length
|
|
163
|
-
|
|
164
|
-
data = bytearray(b"")
|
|
165
|
-
|
|
170
|
+
length: Optional[int] = None
|
|
171
|
+
counter: int = 0
|
|
172
|
+
data: bytearray = bytearray(b"")
|
|
166
173
|
while True:
|
|
167
174
|
if close_event_set() or socket_fileno() == -1:
|
|
168
175
|
return
|
|
169
|
-
|
|
170
|
-
count = len(_packets)
|
|
171
|
-
|
|
176
|
+
count: int = len(_packets)
|
|
172
177
|
if not count:
|
|
173
|
-
|
|
178
|
+
short_sleep()
|
|
174
179
|
continue
|
|
175
|
-
|
|
176
180
|
for _ in range(count):
|
|
177
181
|
bts, timestamp = popleft()
|
|
178
|
-
|
|
179
182
|
data += bts
|
|
180
|
-
current_size = len(data)
|
|
181
|
-
current_position = 0
|
|
182
|
-
|
|
183
|
+
current_size: int = len(data)
|
|
184
|
+
current_position: int = 0
|
|
183
185
|
while True:
|
|
184
186
|
if length is None:
|
|
185
187
|
if current_size >= HEADER_SIZE:
|
|
@@ -192,24 +194,20 @@ class Eth(BaseTransport):
|
|
|
192
194
|
else:
|
|
193
195
|
if current_size >= length:
|
|
194
196
|
response = data[current_position : current_position + length]
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
process_response(response, length, counter, timestamp)
|
|
197
198
|
current_size -= length
|
|
198
199
|
current_position += length
|
|
199
|
-
|
|
200
200
|
length = None
|
|
201
|
-
|
|
202
201
|
else:
|
|
203
|
-
|
|
204
202
|
data = data[current_position:]
|
|
205
203
|
break
|
|
206
204
|
|
|
207
|
-
def send(self, frame):
|
|
208
|
-
self.pre_send_timestamp =
|
|
205
|
+
def send(self, frame) -> None:
|
|
206
|
+
self.pre_send_timestamp = self.timestamp.value
|
|
209
207
|
self.sock.send(frame)
|
|
210
|
-
self.post_send_timestamp =
|
|
208
|
+
self.post_send_timestamp = self.timestamp.value
|
|
211
209
|
|
|
212
|
-
def
|
|
210
|
+
def close_connection(self) -> None:
|
|
213
211
|
if not self.invalidSocket:
|
|
214
212
|
# Seems to be problematic /w IPv6
|
|
215
213
|
# if self.status == 1:
|
|
@@ -217,5 +215,5 @@ class Eth(BaseTransport):
|
|
|
217
215
|
self.sock.close()
|
|
218
216
|
|
|
219
217
|
@property
|
|
220
|
-
def invalidSocket(self):
|
|
218
|
+
def invalidSocket(self) -> bool:
|
|
221
219
|
return not hasattr(self, "sock") or self.sock.fileno() == -1
|
pyxcp/transport/sxi.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
1
|
import struct
|
|
4
|
-
from
|
|
5
|
-
from
|
|
2
|
+
from collections import deque
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Optional
|
|
6
5
|
|
|
7
6
|
import serial
|
|
8
7
|
|
|
@@ -10,78 +9,125 @@ import pyxcp.types as types
|
|
|
10
9
|
from pyxcp.transport.base import BaseTransport
|
|
11
10
|
|
|
12
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
|
+
|
|
13
22
|
class SxI(BaseTransport):
|
|
14
23
|
""""""
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
self.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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}.")
|
|
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(f"XCPonSxI - serial comm_port openend: {self.comm_port.portstr}@{self.baudrate} Bits/Sec.")
|
|
92
|
+
self.start_listener()
|
|
93
|
+
|
|
94
|
+
def output(self, enable) -> None:
|
|
51
95
|
if enable:
|
|
52
|
-
self.
|
|
53
|
-
self.
|
|
96
|
+
self.comm_port.rts = False
|
|
97
|
+
self.comm_port.dtr = False
|
|
54
98
|
else:
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
99
|
+
self.comm_port.rts = True
|
|
100
|
+
self.comm_port.dtr = True
|
|
57
101
|
|
|
58
|
-
def flush(self):
|
|
59
|
-
self.
|
|
102
|
+
def flush(self) -> None:
|
|
103
|
+
self.comm_port.flush()
|
|
60
104
|
|
|
61
|
-
def
|
|
105
|
+
def start_listener(self) -> None:
|
|
106
|
+
super().start_listener()
|
|
62
107
|
|
|
108
|
+
def listen(self) -> None:
|
|
63
109
|
while True:
|
|
64
|
-
if self.closeEvent.
|
|
110
|
+
if self.closeEvent.is_set():
|
|
65
111
|
return
|
|
66
|
-
if not self.
|
|
112
|
+
if not self.comm_port.in_waiting:
|
|
67
113
|
continue
|
|
68
114
|
|
|
69
|
-
recv_timestamp =
|
|
70
|
-
|
|
115
|
+
recv_timestamp = self.timestamp.value
|
|
116
|
+
header_values = self.unpacker(self.HEADER.unpack(self.comm_port.read(self.HEADER_SIZE)))
|
|
117
|
+
length, counter, _ = header_values.length, header_values.counter, header_values.filler
|
|
71
118
|
|
|
72
|
-
response = self.
|
|
119
|
+
response = self.comm_port.read(length)
|
|
73
120
|
self.timing.stop()
|
|
74
121
|
|
|
75
122
|
if len(response) != length:
|
|
76
123
|
raise types.FrameSizeError("Size mismatch.")
|
|
124
|
+
self.process_response(response, length, counter, recv_timestamp)
|
|
77
125
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
self.
|
|
82
|
-
self.commPort.write(frame)
|
|
83
|
-
self.post_send_timestamp = time()
|
|
126
|
+
def send(self, frame) -> None:
|
|
127
|
+
self.pre_send_timestamp = self.timestamp.value
|
|
128
|
+
self.comm_port.write(frame)
|
|
129
|
+
self.post_send_timestamp = self.timestamp.value
|
|
84
130
|
|
|
85
|
-
def
|
|
86
|
-
if hasattr(self, "
|
|
87
|
-
self.
|
|
131
|
+
def close_connection(self) -> None:
|
|
132
|
+
if hasattr(self, "comm_port") and self.comm_port.is_open and not self.has_user_supplied_interface:
|
|
133
|
+
self.comm_port.close()
|
|
File without changes
|