pyxcp 0.21.10__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.

Files changed (173) 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.cp38-win_amd64.pyd +0 -0
  21. pyxcp/cpp_ext/cpp_ext.cp39-win_amd64.pyd +0 -0
  22. pyxcp/cpp_ext/daqlist.hpp +200 -0
  23. pyxcp/cpp_ext/event.hpp +67 -0
  24. pyxcp/cpp_ext/extension_wrapper.cpp +96 -0
  25. pyxcp/cpp_ext/helper.hpp +280 -0
  26. pyxcp/cpp_ext/mcobject.hpp +246 -0
  27. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  28. pyxcp/daq_stim/__init__.py +228 -0
  29. pyxcp/daq_stim/optimize/__init__.py +67 -0
  30. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  31. pyxcp/daq_stim/scheduler.cpp +28 -0
  32. pyxcp/daq_stim/scheduler.hpp +75 -0
  33. pyxcp/daq_stim/stim.cp38-win_amd64.pyd +0 -0
  34. pyxcp/daq_stim/stim.cp39-win_amd64.pyd +0 -0
  35. pyxcp/daq_stim/stim.cpp +13 -0
  36. pyxcp/daq_stim/stim.hpp +604 -0
  37. pyxcp/daq_stim/stim_wrapper.cpp +48 -0
  38. pyxcp/dllif.py +21 -18
  39. pyxcp/errormatrix.py +5 -3
  40. pyxcp/examples/conf_can.toml +4 -2
  41. pyxcp/examples/conf_can_vector.json +9 -9
  42. pyxcp/examples/conf_can_vector.toml +4 -2
  43. pyxcp/examples/conf_eth.toml +5 -2
  44. pyxcp/examples/conf_nixnet.json +18 -18
  45. pyxcp/examples/conf_sxi.json +7 -7
  46. pyxcp/examples/ex_arrow.py +109 -0
  47. pyxcp/examples/ex_csv.py +85 -0
  48. pyxcp/examples/ex_excel.py +95 -0
  49. pyxcp/examples/ex_mdf.py +124 -0
  50. pyxcp/examples/ex_sqlite.py +128 -0
  51. pyxcp/examples/run_daq.py +148 -0
  52. pyxcp/examples/xcp_policy.py +6 -7
  53. pyxcp/examples/xcp_read_benchmark.py +8 -6
  54. pyxcp/examples/xcp_skel.py +0 -2
  55. pyxcp/examples/xcp_unlock.py +1 -1
  56. pyxcp/examples/xcp_user_supplied_driver.py +1 -2
  57. pyxcp/examples/xcphello.py +6 -3
  58. pyxcp/examples/xcphello_recorder.py +4 -4
  59. pyxcp/master/__init__.py +1 -2
  60. pyxcp/master/errorhandler.py +107 -74
  61. pyxcp/master/master.py +201 -119
  62. pyxcp/py.typed +0 -0
  63. pyxcp/recorder/__init__.py +27 -6
  64. pyxcp/recorder/converter/__init__.py +37 -0
  65. pyxcp/recorder/lz4.c +129 -51
  66. pyxcp/recorder/lz4.h +45 -28
  67. pyxcp/recorder/lz4hc.c +560 -156
  68. pyxcp/recorder/lz4hc.h +1 -1
  69. pyxcp/recorder/mio.hpp +721 -767
  70. pyxcp/recorder/reader.hpp +139 -0
  71. pyxcp/recorder/reco.py +5 -8
  72. pyxcp/recorder/rekorder.cp38-win_amd64.pyd +0 -0
  73. pyxcp/recorder/rekorder.cp39-win_amd64.pyd +0 -0
  74. pyxcp/recorder/rekorder.cpp +18 -22
  75. pyxcp/recorder/rekorder.hpp +200 -587
  76. pyxcp/recorder/setup.py +11 -10
  77. pyxcp/recorder/test_reko.py +2 -3
  78. pyxcp/recorder/unfolder.hpp +1332 -0
  79. pyxcp/recorder/wrap.cpp +171 -9
  80. pyxcp/recorder/writer.hpp +302 -0
  81. pyxcp/scripts/pyxcp_probe_can_drivers.py +0 -2
  82. pyxcp/scripts/xcp_examples.py +64 -0
  83. pyxcp/scripts/xcp_fetch_a2l.py +15 -10
  84. pyxcp/scripts/xcp_id_scanner.py +2 -6
  85. pyxcp/scripts/xcp_info.py +101 -63
  86. pyxcp/scripts/xcp_profile.py +27 -0
  87. pyxcp/stim/__init__.py +0 -0
  88. pyxcp/tests/test_asam_types.py +2 -2
  89. pyxcp/tests/test_binpacking.py +186 -0
  90. pyxcp/tests/test_can.py +1132 -38
  91. pyxcp/tests/test_checksum.py +2 -1
  92. pyxcp/tests/test_daq.py +193 -0
  93. pyxcp/tests/test_frame_padding.py +6 -3
  94. pyxcp/tests/test_master.py +42 -31
  95. pyxcp/tests/test_transport.py +12 -12
  96. pyxcp/tests/test_utils.py +2 -5
  97. pyxcp/timing.py +0 -2
  98. pyxcp/transport/__init__.py +9 -9
  99. pyxcp/transport/base.py +149 -127
  100. pyxcp/transport/base_transport.hpp +0 -0
  101. pyxcp/transport/can.py +194 -167
  102. pyxcp/transport/eth.py +80 -82
  103. pyxcp/transport/sxi.py +106 -60
  104. pyxcp/transport/transport_wrapper.cpp +0 -0
  105. pyxcp/transport/usb_transport.py +65 -83
  106. pyxcp/types.py +69 -20
  107. pyxcp/utils.py +47 -16
  108. pyxcp/vector/map.py +1 -3
  109. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/METADATA +28 -23
  110. pyxcp-0.22.23.dist-info/RECORD +131 -0
  111. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/WHEEL +1 -1
  112. {pyxcp-0.21.10.dist-info → pyxcp-0.22.23.dist-info}/entry_points.txt +2 -0
  113. pyxcp/config.py +0 -57
  114. pyxcp/cxx/asynchiofactory.hpp +0 -24
  115. pyxcp/cxx/blocking_client.cpp +0 -44
  116. pyxcp/cxx/blocking_socket.cpp +0 -43
  117. pyxcp/cxx/blocking_socket.hpp +0 -558
  118. pyxcp/cxx/concurrent_queue.hpp +0 -60
  119. pyxcp/cxx/eth.hpp +0 -57
  120. pyxcp/cxx/exceptions.hpp +0 -30
  121. pyxcp/cxx/iasyncioservice.hpp +0 -31
  122. pyxcp/cxx/iresource.hpp +0 -17
  123. pyxcp/cxx/isocket.hpp +0 -22
  124. pyxcp/cxx/linux/epoll.cpp +0 -51
  125. pyxcp/cxx/linux/epoll.hpp +0 -87
  126. pyxcp/cxx/linux/lit_tester.cpp +0 -19
  127. pyxcp/cxx/linux/socket.hpp +0 -234
  128. pyxcp/cxx/linux/timeout.hpp +0 -81
  129. pyxcp/cxx/memoryblock.hpp +0 -42
  130. pyxcp/cxx/pool.hpp +0 -81
  131. pyxcp/cxx/poolmgr.cpp +0 -6
  132. pyxcp/cxx/poolmgr.hpp +0 -31
  133. pyxcp/cxx/test_queue.cpp +0 -69
  134. pyxcp/cxx/timestamp.hpp +0 -84
  135. pyxcp/cxx/utils.cpp +0 -38
  136. pyxcp/cxx/utils.hpp +0 -29
  137. pyxcp/cxx/win/iocp.cpp +0 -242
  138. pyxcp/cxx/win/iocp.hpp +0 -42
  139. pyxcp/cxx/win/perhandledata.hpp +0 -24
  140. pyxcp/cxx/win/periodata.hpp +0 -97
  141. pyxcp/cxx/win/socket.hpp +0 -185
  142. pyxcp/cxx/win/timeout.hpp +0 -83
  143. pyxcp/examples/conf_can.json +0 -20
  144. pyxcp/examples/conf_eth.json +0 -8
  145. pyxcp/logger.py +0 -67
  146. pyxcp/tests/test_config.py +0 -62
  147. pyxcp/transport/candriver/__init__.py +0 -2
  148. pyxcp/transport/candriver/pc_canalystii.py +0 -27
  149. pyxcp/transport/candriver/pc_etas.py +0 -25
  150. pyxcp/transport/candriver/pc_gsusb.py +0 -23
  151. pyxcp/transport/candriver/pc_iscan.py +0 -23
  152. pyxcp/transport/candriver/pc_ixxat.py +0 -27
  153. pyxcp/transport/candriver/pc_kvaser.py +0 -39
  154. pyxcp/transport/candriver/pc_neovi.py +0 -31
  155. pyxcp/transport/candriver/pc_nican.py +0 -23
  156. pyxcp/transport/candriver/pc_nixnet.py +0 -23
  157. pyxcp/transport/candriver/pc_pcan.py +0 -25
  158. pyxcp/transport/candriver/pc_seeed.py +0 -28
  159. pyxcp/transport/candriver/pc_serial.py +0 -27
  160. pyxcp/transport/candriver/pc_slcan.py +0 -29
  161. pyxcp/transport/candriver/pc_socketcan.py +0 -23
  162. pyxcp/transport/candriver/pc_systec.py +0 -29
  163. pyxcp/transport/candriver/pc_usb2can.py +0 -30
  164. pyxcp/transport/candriver/pc_vector.py +0 -34
  165. pyxcp/transport/candriver/python_can.py +0 -101
  166. pyxcp/transport/cxx_ext/CMakeLists.txt +0 -51
  167. pyxcp/transport/cxx_ext/setup.py +0 -49
  168. pyxcp/transport/cxx_ext/tests/test_basic_socket.cpp +0 -39
  169. pyxcp/transport/cxx_ext/tests/test_pool.cpp +0 -39
  170. pyxcp/transport/cxx_ext/tests/test_timestamp.cpp +0 -27
  171. pyxcp-0.21.10.dist-info/RECORD +0 -147
  172. rekorder.cp39-win_amd64.pyd +0 -0
  173. {pyxcp-0.21.10.dist-info/licenses → pyxcp-0.22.23.dist-info}/LICENSE +0 -0
@@ -1,28 +1,24 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  """Implements error-handling according to XCP spec.
4
3
  """
5
4
  import functools
6
5
  import logging
7
- import os
8
6
  import threading
9
7
  import time
10
8
  import types
11
9
  from collections import namedtuple
12
- from pyxcp.errormatrix import Action
13
- from pyxcp.errormatrix import ERROR_MATRIX
14
- from pyxcp.errormatrix import PreAction
15
- from pyxcp.types import COMMAND_CATEGORIES
16
- from pyxcp.types import XcpError
17
- from pyxcp.types import XcpResponseError
18
- from pyxcp.types import XcpTimeoutError
10
+ from typing import Generic, List, Optional, TypeVar
11
+
12
+ import can
13
+
14
+ from pyxcp.errormatrix import ERROR_MATRIX, Action, PreAction
15
+ from pyxcp.types import COMMAND_CATEGORIES, XcpError, XcpResponseError, XcpTimeoutError
19
16
 
20
17
 
21
18
  handle_errors = True # enable/disable XCP error-handling.
22
19
 
23
- logger = logging.getLogger("pyxcp.errorhandler")
24
20
 
25
- class SingletonBase(object):
21
+ class SingletonBase:
26
22
  _lock = threading.Lock()
27
23
 
28
24
  def __new__(cls, *args, **kws):
@@ -31,7 +27,7 @@ class SingletonBase(object):
31
27
  try:
32
28
  cls._lock.acquire()
33
29
  if not hasattr(cls, "_instance"):
34
- cls._instance = super(SingletonBase, cls).__new__(cls)
30
+ cls._instance = super().__new__(cls)
35
31
  finally:
36
32
  cls._lock.release()
37
33
  return cls._instance
@@ -44,9 +40,19 @@ class InternalError(Exception):
44
40
  """Indicates an internal error, like invalid service."""
45
41
 
46
42
 
47
- class UnhandledError(Exception):
43
+ class SystemExit(Exception):
48
44
  """"""
49
45
 
46
+ def __init__(self, msg: str, error_code: int = None, *args, **kws):
47
+ super().__init__(*args, **kws)
48
+ self.error_code = error_code
49
+ self.msg = msg
50
+
51
+ def __str__(self):
52
+ return f"SystemExit(error_code={self.error_code}, message={self.msg!r})"
53
+
54
+ __repr__ = __str__
55
+
50
56
 
51
57
  class UnrecoverableError(Exception):
52
58
  """"""
@@ -78,10 +84,10 @@ def getActions(service, error_code):
78
84
  eh = getErrorHandler(service)
79
85
  if eh is None:
80
86
  raise InternalError(f"Invalid Service 0x{service:02x}")
81
- print(f"Try to handle error -- Service: {service.name} Error-Code: {error_code}")
87
+ # print(f"Try to handle error -- Service: {service.name} Error-Code: {error_code}")
82
88
  handler = eh.get(error_str)
83
89
  if handler is None:
84
- raise UnhandledError(f"Service '{service.name}' has no handler for '{error_code}'.")
90
+ raise SystemExit(f"Service {service.name!r} has no handler for {error_code}.", error_code=error_code)
85
91
  preActions, actions = handler
86
92
  return preActions, actions
87
93
 
@@ -89,8 +95,7 @@ def getActions(service, error_code):
89
95
  def actionIter(actions):
90
96
  """Iterate over action from :file:`errormatrix.py`"""
91
97
  if isinstance(actions, (tuple, list)):
92
- for item in actions:
93
- yield item
98
+ yield from actions
94
99
  else:
95
100
  yield actions
96
101
 
@@ -116,12 +121,14 @@ class Arguments:
116
121
  self.args = tuple(args)
117
122
  self.kwargs = kwargs or {}
118
123
 
119
- def __str__(self):
124
+ def __str__(self) -> str:
120
125
  res = f"{self.__class__.__name__}(ARGS = {self.args}, KWS = {self.kwargs})"
121
126
  return res
122
127
 
123
- def __eq__(self, other):
124
- return (self.args == other.args if other is not None else ()) and (self.kwargs == other.kwargs if other is not None else {})
128
+ def __eq__(self, other) -> bool:
129
+ return (self.args == other.args if other is not None else False) and (
130
+ self.kwargs == other.kwargs if other is not None else False
131
+ )
125
132
 
126
133
  __repr__ = __str__
127
134
 
@@ -144,7 +151,7 @@ class Repeater:
144
151
 
145
152
  def __init__(self, initial_value: int):
146
153
  self._counter = initial_value
147
- #print("\tREPEATER ctor", hex(id(self)))
154
+ # print("\tREPEATER ctor", hex(id(self)))
148
155
 
149
156
  def repeat(self):
150
157
  """Check if repetition is required.
@@ -153,7 +160,7 @@ class Repeater:
153
160
  -------
154
161
  bool
155
162
  """
156
- #print("\t\tCOUNTER:", hex(id(self)), self._counter)
163
+ # print("\t\tCOUNTER:", hex(id(self)), self._counter)
157
164
  if self._counter == Repeater.INFINITE:
158
165
  return True
159
166
  elif self._counter > 0:
@@ -174,8 +181,6 @@ def display_error():
174
181
  class Handler:
175
182
  """"""
176
183
 
177
- logger = logger
178
-
179
184
  def __init__(self, instance, func, arguments, error_code=None):
180
185
  self.instance = instance
181
186
  if hasattr(func, "__closure__") and func.__closure__:
@@ -185,29 +190,40 @@ class Handler:
185
190
  self.func = func
186
191
  self.arguments = arguments
187
192
  self.service = self.instance.service
188
- self.error_code = error_code
193
+ self._error_code: int = 0
194
+ if error_code is not None:
195
+ self._error_code = error_code
189
196
  self._repeater = None
197
+ self.logger = logging.getLogger("PyXCP")
190
198
 
191
199
  def __str__(self):
192
- return f"Handler(func = {func_name(self.func)} arguments = {self.arguments} service = {self.service} error_code = {self.error_code})"
200
+ return f"Handler(func = {func_name(self.func)} -- {self.arguments} service = {self.service} error_code = {self.error_code})"
193
201
 
194
202
  def __eq__(self, other):
195
203
  if other is None:
196
204
  return False
197
205
  return (self.instance == other.instance) and (self.func == other.func) and (self.arguments == other.arguments)
198
206
 
207
+ @property
208
+ def error_code(self) -> int:
209
+ return self._error_code
210
+
211
+ @error_code.setter
212
+ def error_code(self, value: int) -> None:
213
+ self._error_code = value
214
+
199
215
  @property
200
216
  def repeater(self):
201
- #print("\tGet repeater", hex(id(self._repeater)), self._repeater is None)
217
+ # print("\tGet repeater", hex(id(self._repeater)), self._repeater is None)
202
218
  return self._repeater
203
219
 
204
220
  @repeater.setter
205
221
  def repeater(self, value):
206
- #print("\tSet repeater", hex(id(value)))
222
+ # print("\tSet repeater", hex(id(value)))
207
223
  self._repeater = value
208
224
 
209
225
  def execute(self):
210
- self.logger.debug(f"EXECUTE func = {func_name(self.func)} arguments = {self.arguments})")
226
+ self.logger.debug(f"Execute({func_name(self.func)} -- {self.arguments})")
211
227
  if isinstance(self.func, types.MethodType):
212
228
  return self.func(*self.arguments.args, **self.arguments.kwargs)
213
229
  else:
@@ -227,40 +243,42 @@ class Handler:
227
243
  fn = Function(self.instance.synch, Arguments())
228
244
  result_pre_actions.append(fn)
229
245
  elif item == PreAction.GET_SEED_UNLOCK:
230
- raise NotImplementedError("GET_SEED_UNLOCK")
246
+ raise NotImplementedError("Pre-action GET_SEED_UNLOCK")
231
247
  elif item == PreAction.SET_MTA:
232
248
  fn = Function(self.instance.setMta, Arguments(self.instance.mta))
233
249
  result_pre_actions.append(fn)
234
250
  elif item == PreAction.SET_DAQ_PTR:
235
251
  fn = Function(self.instance.setDaqPtr, Arguments(self.instance.currentDaqPtr))
236
252
  elif item == PreAction.START_STOP_X:
237
- raise NotImplementedError("START_STOP_X")
253
+ raise NotImplementedError("Pre-action START_STOP_X")
238
254
  elif item == PreAction.REINIT_DAQ:
239
- raise NotImplementedError("REINIT_DAQ")
255
+ raise NotImplementedError("Pre-action REINIT_DAQ")
240
256
  elif item == PreAction.DISPLAY_ERROR:
241
257
  pass
242
258
  elif item == PreAction.DOWNLOAD:
243
- raise NotImplementedError("DOWNLOAD")
259
+ raise NotImplementedError("Pre-action DOWNLOAD")
244
260
  elif item == PreAction.PROGRAM:
245
- raise NotImplementedError("PROGRAM")
261
+ raise NotImplementedError("Pre-action PROGRAM")
246
262
  elif item == PreAction.UPLOAD:
247
- raise NotImplementedError("UPLOAD")
263
+ raise NotImplementedError("Pre-action UPLOAD")
248
264
  elif item == PreAction.UNLOCK_SLAVE:
249
265
  resource = COMMAND_CATEGORIES.get(self.instance.service) # noqa: F841
250
- raise NotImplementedError("UNLOCK_SLAVE")
266
+ raise NotImplementedError("Pre-action UNLOCK_SLAVE")
251
267
  for item in actionIter(actions):
252
268
  if item == Action.NONE:
253
269
  pass
254
270
  elif item == Action.DISPLAY_ERROR:
255
- raise UnhandledError("Could not proceed due to unhandled error.")
271
+ raise SystemExit("Could not proceed due to unhandled error (DISPLAY_ERROR).", self.error_code)
256
272
  elif item == Action.RETRY_SYNTAX:
257
- raise UnhandledError("Could not proceed due to unhandled error.")
273
+ raise SystemExit("Could not proceed due to unhandled error (RETRY_SYNTAX).", self.error_code)
258
274
  elif item == Action.RETRY_PARAM:
259
- raise UnhandledError("Could not proceed due to unhandled error.")
275
+ raise SystemExit("Could not proceed due to unhandled error (RETRY_PARAM).", self.error_code)
260
276
  elif item == Action.USE_A2L:
261
- raise UnhandledError("Could not proceed due to unhandled error.")
277
+ raise SystemExit("Could not proceed due to unhandled error (USE_A2L).", self.error_code)
262
278
  elif item == Action.USE_ALTERATIVE:
263
- raise UnhandledError("Could not proceed due to unhandled error.") # TODO: check alternatives.
279
+ raise SystemExit(
280
+ "Could not proceed due to unhandled error (USE_ALTERATIVE).", self.error_code
281
+ ) # TODO: check alternatives.
264
282
  elif item == Action.REPEAT:
265
283
  repetitionCount = Repeater.REPEAT
266
284
  elif item == Action.REPEAT_2_TIMES:
@@ -268,49 +286,53 @@ class Handler:
268
286
  elif item == Action.REPEAT_INF_TIMES:
269
287
  repetitionCount = Repeater.INFINITE
270
288
  elif item == Action.RESTART_SESSION:
271
- raise UnhandledError("Could not proceed due to unhandled error.")
289
+ raise SystemExit("Could not proceed due to unhandled error (RESTART_SESSION).", self.error_code)
272
290
  elif item == Action.TERMINATE_SESSION:
273
- raise UnhandledError("Could not proceed due to unhandled error.")
291
+ raise SystemExit("Could not proceed due to unhandled error (TERMINATE_SESSION).", self.error_code)
274
292
  elif item == Action.SKIP:
275
293
  pass
276
294
  elif item == Action.NEW_FLASH_WARE:
277
- raise UnhandledError("Could not proceed due to unhandled error")
295
+ raise SystemExit("Could not proceed due to unhandled error (NEW_FLASH_WARE)", self.error_code)
278
296
  return result_pre_actions, result_actions, Repeater(repetitionCount)
279
297
 
280
298
 
281
- class HandlerStack:
299
+ T = TypeVar("T")
300
+
301
+
302
+ class HandlerStack(Generic[T]):
282
303
  """"""
283
304
 
284
- def __init__(self):
285
- self._stack = []
305
+ def __init__(self) -> None:
306
+ self._stack: List[T] = []
286
307
 
287
- def push(self, handler):
288
- if handler != self.tos():
289
- self._stack.append(handler)
308
+ def push(self, value: T):
309
+ if value != self.tos():
310
+ self._stack.append(value)
290
311
 
291
- def pop(self):
312
+ def pop(self) -> None:
292
313
  if len(self) > 0:
293
314
  self._stack.pop()
294
315
 
295
- def tos(self):
316
+ def tos(self) -> Optional[T]:
296
317
  if len(self) > 0:
297
318
  return self._stack[-1]
298
319
  else:
299
320
  return None
321
+ # raise ValueError("empty stack.")
300
322
 
301
- def empty(self):
323
+ def empty(self) -> bool:
302
324
  return self._stack == []
303
325
 
304
- def __len__(self):
326
+ def __len__(self) -> int:
305
327
  return len(self._stack)
306
328
 
307
- def __repr__(self):
329
+ def __repr__(self) -> str:
308
330
  result = []
309
331
  for idx in range(len(self)):
310
332
  result.append(str(self[idx]))
311
333
  return "\n".join(result)
312
334
 
313
- def __getitem__(self, ndx):
335
+ def __getitem__(self, ndx: int) -> T:
314
336
  return self._stack[ndx]
315
337
 
316
338
  __str__ = __repr__
@@ -319,44 +341,53 @@ class HandlerStack:
319
341
  class Executor(SingletonBase):
320
342
  """"""
321
343
 
322
- handlerStack = HandlerStack()
323
- repeater = None
324
- logger = logger
325
- previous_error_code = None
326
- error_code = None
327
- func = None
328
- arguments = None
344
+ def __init__(self):
345
+ self.handlerStack = HandlerStack()
346
+ self.repeater = None
347
+ self.logger = logging.getLogger("PyXCP")
348
+ self.previous_error_code = None
349
+ self.error_code = None
350
+ self.func = None
351
+ self.arguments = None
329
352
 
330
353
  def __call__(self, inst, func, arguments):
331
- self.logger.debug(f"__call__({func.__qualname__})")
332
354
  self.inst = inst
333
355
  self.func = func
334
356
  self.arguments = arguments
335
357
  handler = Handler(inst, func, arguments)
336
358
  self.handlerStack.push(handler)
337
- #print("\tENTER handler:", hex(id(handler)))
338
359
  try:
339
360
  while True:
340
361
  try:
341
362
  handler = self.handlerStack.tos()
342
- #print("\t\tEXEC", hex(id(handler)))
343
363
  res = handler.execute()
344
364
  except XcpResponseError as e:
345
- self.logger.error(f"XcpResponseError [{str(e)}]")
365
+ # self.logger.critical(f"XcpResponseError [{e.get_error_code()}]")
346
366
  self.error_code = e.get_error_code()
347
- except XcpTimeoutError as e:
348
- self.logger.error(f"XcpTimeoutError [{str(e)}]")
367
+ handler.error_code = self.error_code
368
+ except XcpTimeoutError:
369
+ # self.logger.error(f"XcpTimeoutError [{str(e)}]")
349
370
  self.error_code = XcpError.ERR_TIMEOUT
350
- except Exception as e:
351
- raise UnrecoverableError(f"Don't know how to handle exception '{repr(e)}'") from e
371
+ handler.error_code = self.error_code
372
+ except TimeoutError:
373
+ raise
374
+ except can.CanError:
375
+ # self.logger.critical(f"Exception raised by Python CAN [{str(e)}]")
376
+ raise
377
+ except Exception:
378
+ # self.logger.critical(f"Exception [{str(e)}]")
379
+ raise
352
380
  else:
353
381
  self.error_code = None
354
- # print("\t\t\t*** SUCCESS ***")
355
382
  self.handlerStack.pop()
356
383
  if self.handlerStack.empty():
357
- # print("OK, all handlers passed: '{}'.".format(res))
358
384
  return res
359
385
 
386
+ if self.error_code == XcpError.ERR_CMD_SYNCH:
387
+ # Don't care about SYNCH for now...
388
+ self.inst.logger.info("SYNCH received.")
389
+ continue
390
+
360
391
  if self.error_code is not None:
361
392
  preActions, actions, repeater = handler.actions(*getActions(inst.service, self.error_code))
362
393
  if handler.repeater is None:
@@ -368,7 +399,9 @@ class Executor(SingletonBase):
368
399
  if handler.repeater.repeat():
369
400
  continue
370
401
  else:
371
- raise UnrecoverableError(f"Max. repetition count reached while trying to execute service '{handler.func.__name__}'.")
402
+ raise UnrecoverableError(
403
+ f"Max. repetition count reached while trying to execute service {handler.func.__name__!r}."
404
+ )
372
405
  finally:
373
406
  # cleanup of class variables
374
407
  self.previous_error_code = None