pyxcp 0.21.10__cp311-cp311-win_amd64.whl → 0.22.23__cp311-cp311-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.

Files changed (179) hide show
  1. pyxcp/__init__.py +12 -20
  2. pyxcp/aml/EtasCANMonitoring.a2l +82 -83
  3. pyxcp/aml/XCP_Common.aml +0 -1
  4. pyxcp/aml/XCPonUSB.aml +1 -1
  5. pyxcp/aml/ifdata_CAN.a2l +0 -1
  6. pyxcp/aml/ifdata_Eth.a2l +0 -1
  7. pyxcp/aml/ifdata_Flx.a2l +0 -1
  8. pyxcp/aml/ifdata_SxI.a2l +0 -1
  9. pyxcp/aml/ifdata_USB.a2l +0 -1
  10. pyxcp/asam/types.py +4 -4
  11. pyxcp/asamkeydll.c +0 -1
  12. pyxcp/checksum.py +0 -1
  13. pyxcp/cmdline.py +32 -50
  14. pyxcp/config/__init__.py +1100 -0
  15. pyxcp/config/legacy.py +120 -0
  16. pyxcp/constants.py +12 -13
  17. pyxcp/cpp_ext/__init__.py +0 -0
  18. pyxcp/cpp_ext/bin.hpp +104 -0
  19. pyxcp/cpp_ext/blockmem.hpp +58 -0
  20. pyxcp/cpp_ext/cpp_ext.cp310-win_amd64.pyd +0 -0
  21. pyxcp/cpp_ext/cpp_ext.cp311-win_amd64.pyd +0 -0
  22. pyxcp/cpp_ext/cpp_ext.cp38-win_amd64.pyd +0 -0
  23. pyxcp/cpp_ext/cpp_ext.cp39-win_amd64.pyd +0 -0
  24. pyxcp/cpp_ext/daqlist.hpp +200 -0
  25. pyxcp/cpp_ext/event.hpp +67 -0
  26. pyxcp/cpp_ext/extension_wrapper.cpp +96 -0
  27. pyxcp/cpp_ext/helper.hpp +280 -0
  28. pyxcp/cpp_ext/mcobject.hpp +246 -0
  29. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  30. pyxcp/daq_stim/__init__.py +228 -0
  31. pyxcp/daq_stim/optimize/__init__.py +67 -0
  32. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  33. pyxcp/daq_stim/scheduler.cpp +28 -0
  34. pyxcp/daq_stim/scheduler.hpp +75 -0
  35. pyxcp/daq_stim/stim.cp310-win_amd64.pyd +0 -0
  36. pyxcp/daq_stim/stim.cp311-win_amd64.pyd +0 -0
  37. pyxcp/daq_stim/stim.cp38-win_amd64.pyd +0 -0
  38. pyxcp/daq_stim/stim.cp39-win_amd64.pyd +0 -0
  39. pyxcp/daq_stim/stim.cpp +13 -0
  40. pyxcp/daq_stim/stim.hpp +604 -0
  41. pyxcp/daq_stim/stim_wrapper.cpp +48 -0
  42. pyxcp/dllif.py +21 -18
  43. pyxcp/errormatrix.py +5 -3
  44. pyxcp/examples/conf_can.toml +4 -2
  45. pyxcp/examples/conf_can_vector.json +9 -9
  46. pyxcp/examples/conf_can_vector.toml +4 -2
  47. pyxcp/examples/conf_eth.toml +5 -2
  48. pyxcp/examples/conf_nixnet.json +18 -18
  49. pyxcp/examples/conf_sxi.json +7 -7
  50. pyxcp/examples/ex_arrow.py +109 -0
  51. pyxcp/examples/ex_csv.py +85 -0
  52. pyxcp/examples/ex_excel.py +95 -0
  53. pyxcp/examples/ex_mdf.py +124 -0
  54. pyxcp/examples/ex_sqlite.py +128 -0
  55. pyxcp/examples/run_daq.py +148 -0
  56. pyxcp/examples/xcp_policy.py +6 -7
  57. pyxcp/examples/xcp_read_benchmark.py +8 -6
  58. pyxcp/examples/xcp_skel.py +0 -2
  59. pyxcp/examples/xcp_unlock.py +1 -1
  60. pyxcp/examples/xcp_user_supplied_driver.py +1 -2
  61. pyxcp/examples/xcphello.py +6 -3
  62. pyxcp/examples/xcphello_recorder.py +4 -4
  63. pyxcp/master/__init__.py +1 -2
  64. pyxcp/master/errorhandler.py +107 -74
  65. pyxcp/master/master.py +201 -119
  66. pyxcp/py.typed +0 -0
  67. pyxcp/recorder/__init__.py +27 -6
  68. pyxcp/recorder/converter/__init__.py +37 -0
  69. pyxcp/recorder/lz4.c +129 -51
  70. pyxcp/recorder/lz4.h +45 -28
  71. pyxcp/recorder/lz4hc.c +560 -156
  72. pyxcp/recorder/lz4hc.h +1 -1
  73. pyxcp/recorder/mio.hpp +721 -767
  74. pyxcp/recorder/reader.hpp +139 -0
  75. pyxcp/recorder/reco.py +5 -8
  76. pyxcp/recorder/rekorder.cp310-win_amd64.pyd +0 -0
  77. pyxcp/recorder/rekorder.cp311-win_amd64.pyd +0 -0
  78. pyxcp/recorder/rekorder.cp38-win_amd64.pyd +0 -0
  79. pyxcp/recorder/rekorder.cp39-win_amd64.pyd +0 -0
  80. pyxcp/recorder/rekorder.cpp +18 -22
  81. pyxcp/recorder/rekorder.hpp +200 -587
  82. pyxcp/recorder/setup.py +11 -10
  83. pyxcp/recorder/test_reko.py +2 -3
  84. pyxcp/recorder/unfolder.hpp +1332 -0
  85. pyxcp/recorder/wrap.cpp +171 -9
  86. pyxcp/recorder/writer.hpp +302 -0
  87. pyxcp/scripts/pyxcp_probe_can_drivers.py +0 -2
  88. pyxcp/scripts/xcp_examples.py +64 -0
  89. pyxcp/scripts/xcp_fetch_a2l.py +15 -10
  90. pyxcp/scripts/xcp_id_scanner.py +2 -6
  91. pyxcp/scripts/xcp_info.py +101 -63
  92. pyxcp/scripts/xcp_profile.py +27 -0
  93. pyxcp/stim/__init__.py +0 -0
  94. pyxcp/tests/test_asam_types.py +2 -2
  95. pyxcp/tests/test_binpacking.py +186 -0
  96. pyxcp/tests/test_can.py +1132 -38
  97. pyxcp/tests/test_checksum.py +2 -1
  98. pyxcp/tests/test_daq.py +193 -0
  99. pyxcp/tests/test_frame_padding.py +6 -3
  100. pyxcp/tests/test_master.py +42 -31
  101. pyxcp/tests/test_transport.py +12 -12
  102. pyxcp/tests/test_utils.py +2 -5
  103. pyxcp/timing.py +0 -2
  104. pyxcp/transport/__init__.py +9 -9
  105. pyxcp/transport/base.py +149 -127
  106. pyxcp/transport/base_transport.hpp +0 -0
  107. pyxcp/transport/can.py +194 -167
  108. pyxcp/transport/eth.py +80 -82
  109. pyxcp/transport/sxi.py +106 -60
  110. pyxcp/transport/transport_wrapper.cpp +0 -0
  111. pyxcp/transport/usb_transport.py +65 -83
  112. pyxcp/types.py +69 -20
  113. pyxcp/utils.py +47 -16
  114. pyxcp/vector/map.py +1 -3
  115. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/METADATA +28 -23
  116. pyxcp-0.22.23.dist-info/RECORD +137 -0
  117. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/WHEEL +1 -1
  118. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/entry_points.txt +2 -0
  119. pyxcp/config.py +0 -57
  120. pyxcp/cxx/asynchiofactory.hpp +0 -24
  121. pyxcp/cxx/blocking_client.cpp +0 -44
  122. pyxcp/cxx/blocking_socket.cpp +0 -43
  123. pyxcp/cxx/blocking_socket.hpp +0 -558
  124. pyxcp/cxx/concurrent_queue.hpp +0 -60
  125. pyxcp/cxx/eth.hpp +0 -57
  126. pyxcp/cxx/exceptions.hpp +0 -30
  127. pyxcp/cxx/iasyncioservice.hpp +0 -31
  128. pyxcp/cxx/iresource.hpp +0 -17
  129. pyxcp/cxx/isocket.hpp +0 -22
  130. pyxcp/cxx/linux/epoll.cpp +0 -51
  131. pyxcp/cxx/linux/epoll.hpp +0 -87
  132. pyxcp/cxx/linux/lit_tester.cpp +0 -19
  133. pyxcp/cxx/linux/socket.hpp +0 -234
  134. pyxcp/cxx/linux/timeout.hpp +0 -81
  135. pyxcp/cxx/memoryblock.hpp +0 -42
  136. pyxcp/cxx/pool.hpp +0 -81
  137. pyxcp/cxx/poolmgr.cpp +0 -6
  138. pyxcp/cxx/poolmgr.hpp +0 -31
  139. pyxcp/cxx/test_queue.cpp +0 -69
  140. pyxcp/cxx/timestamp.hpp +0 -84
  141. pyxcp/cxx/utils.cpp +0 -38
  142. pyxcp/cxx/utils.hpp +0 -29
  143. pyxcp/cxx/win/iocp.cpp +0 -242
  144. pyxcp/cxx/win/iocp.hpp +0 -42
  145. pyxcp/cxx/win/perhandledata.hpp +0 -24
  146. pyxcp/cxx/win/periodata.hpp +0 -97
  147. pyxcp/cxx/win/socket.hpp +0 -185
  148. pyxcp/cxx/win/timeout.hpp +0 -83
  149. pyxcp/examples/conf_can.json +0 -20
  150. pyxcp/examples/conf_eth.json +0 -8
  151. pyxcp/logger.py +0 -67
  152. pyxcp/tests/test_config.py +0 -62
  153. pyxcp/transport/candriver/__init__.py +0 -2
  154. pyxcp/transport/candriver/pc_canalystii.py +0 -27
  155. pyxcp/transport/candriver/pc_etas.py +0 -25
  156. pyxcp/transport/candriver/pc_gsusb.py +0 -23
  157. pyxcp/transport/candriver/pc_iscan.py +0 -23
  158. pyxcp/transport/candriver/pc_ixxat.py +0 -27
  159. pyxcp/transport/candriver/pc_kvaser.py +0 -39
  160. pyxcp/transport/candriver/pc_neovi.py +0 -31
  161. pyxcp/transport/candriver/pc_nican.py +0 -23
  162. pyxcp/transport/candriver/pc_nixnet.py +0 -23
  163. pyxcp/transport/candriver/pc_pcan.py +0 -25
  164. pyxcp/transport/candriver/pc_seeed.py +0 -28
  165. pyxcp/transport/candriver/pc_serial.py +0 -27
  166. pyxcp/transport/candriver/pc_slcan.py +0 -29
  167. pyxcp/transport/candriver/pc_socketcan.py +0 -23
  168. pyxcp/transport/candriver/pc_systec.py +0 -29
  169. pyxcp/transport/candriver/pc_usb2can.py +0 -30
  170. pyxcp/transport/candriver/pc_vector.py +0 -34
  171. pyxcp/transport/candriver/python_can.py +0 -101
  172. pyxcp/transport/cxx_ext/CMakeLists.txt +0 -51
  173. pyxcp/transport/cxx_ext/setup.py +0 -49
  174. pyxcp/transport/cxx_ext/tests/test_basic_socket.cpp +0 -39
  175. pyxcp/transport/cxx_ext/tests/test_pool.cpp +0 -39
  176. pyxcp/transport/cxx_ext/tests/test_timestamp.cpp +0 -27
  177. pyxcp-0.21.10.dist-info/RECORD +0 -147
  178. rekorder.cp311-win_amd64.pyd +0 -0
  179. {pyxcp-0.21.10.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 time import perf_counter
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 SHORT_SLEEP
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(Eth, self).__init__(config, policy)
39
- self.loadConfig(config)
40
- self.host = self.config.get("HOST")
41
- self.port = self.config.get("PORT")
42
- self.protocol = self.config.get("PROTOCOL")
43
- self.ipv6 = self.config.get("IPV6")
44
- self.use_tcp_no_delay = self.config.get("TCP_NODELAY")
45
- address_to_bind = self.config.get("BIND_TO_ADDRESS")
46
- port_to_bind = self.config.get("BIND_TO_PORT")
47
- self._local_address = (address_to_bind, port_to_bind) if address_to_bind else None
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
- raise RuntimeError("IPv6 not supported by your platform.")
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
- addrinfo = socket.getaddrinfo(self.host, self.port, address_family, proto)
56
- (
57
- self.address_family,
58
- self.socktype,
59
- self.proto,
60
- self.canonname,
61
- self.sockaddr,
62
- ) = addrinfo[0]
63
- self.status = 0
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
- raise Exception(f"Failed to bind socket to given address {self._local_address}") from ex
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.startListener()
103
+ self.logger.info(socket_to_str(self.sock))
104
+ self.start_listener()
90
105
  self.status = 1 # connected
91
106
 
92
- def startListener(self):
93
- super().startListener()
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.finishListener()
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.closeConnection()
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 = time()
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
- processResponse = self.processResponse
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, counter = None, None
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
- sleep(SHORT_SLEEP)
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
- processResponse(response, length, counter, timestamp)
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 = time()
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 = time()
208
+ self.post_send_timestamp = self.timestamp.value
211
209
 
212
- def closeConnection(self):
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 time import perf_counter
5
- from time import time
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
- PARAMETER_MAP = {
17
- # Type Req'd Default
18
- "PORT": (str, False, "COM1"),
19
- "BITRATE": (int, False, 38400),
20
- "BYTESIZE": (int, False, 8),
21
- "PARITY": (str, False, "N"),
22
- "STOPBITS": (int, False, 1),
23
- }
24
-
25
- MAX_DATAGRAM_SIZE = 512
26
- TIMEOUT = 0.75
27
- HEADER = struct.Struct("<HH")
28
- HEADER_SIZE = HEADER.size
29
-
30
- def __init__(self, config=None, policy=None):
31
- super(SxI, self).__init__(config, policy)
32
- self.loadConfig(config)
33
- self.portName = self.config.get("PORT")
34
- self.baudrate = self.config.get("BITRATE")
35
-
36
- def __del__(self):
37
- self.closeConnection()
38
-
39
- def connect(self):
40
-
41
- self.logger.debug("Trying to open serial commPort {}.".format(self.portName))
42
- try:
43
- self.commPort = serial.Serial(self.portName, self.baudrate, timeout=SxI.TIMEOUT)
44
- except serial.SerialException as e:
45
- self.logger.error("{}".format(e))
46
- raise
47
- self.logger.info("Serial commPort openend as '{}' @ {} Bits/Sec.".format(self.commPort.portstr, self.baudrate))
48
- self.startListener()
49
-
50
- def output(self, enable):
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.commPort.rts = False
53
- self.commPort.dtr = False
96
+ self.comm_port.rts = False
97
+ self.comm_port.dtr = False
54
98
  else:
55
- self.commPort.rts = True
56
- self.commPort.dtr = True
99
+ self.comm_port.rts = True
100
+ self.comm_port.dtr = True
57
101
 
58
- def flush(self):
59
- self.commPort.flush()
102
+ def flush(self) -> None:
103
+ self.comm_port.flush()
60
104
 
61
- def listen(self):
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.isSet():
110
+ if self.closeEvent.is_set():
65
111
  return
66
- if not self.commPort.inWaiting():
112
+ if not self.comm_port.in_waiting:
67
113
  continue
68
114
 
69
- recv_timestamp = time()
70
- length, counter = self.HEADER.unpack(self.commPort.read(self.HEADER_SIZE))
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.commPort.read(length)
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
- self.processResponse(response, length, counter, recv_timestamp)
79
-
80
- def send(self, frame):
81
- self.pre_send_timestamp = time()
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 closeConnection(self):
86
- if hasattr(self, "commPort") and self.commPort.isOpen():
87
- self.commPort.close()
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