pyxcp 0.23.8__cp313-cp313-macosx_11_0_arm64.whl → 0.25.7__cp313-cp313-macosx_11_0_arm64.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.
Files changed (89) hide show
  1. pyxcp/__init__.py +1 -1
  2. pyxcp/cmdline.py +14 -29
  3. pyxcp/config/__init__.py +1257 -1258
  4. pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
  5. pyxcp/cpp_ext/bin.hpp +7 -6
  6. pyxcp/cpp_ext/cpp_ext.cpython-310-darwin.so +0 -0
  7. pyxcp/cpp_ext/cpp_ext.cpython-311-darwin.so +0 -0
  8. pyxcp/cpp_ext/cpp_ext.cpython-312-darwin.so +0 -0
  9. pyxcp/cpp_ext/cpp_ext.cpython-313-darwin.so +0 -0
  10. pyxcp/cpp_ext/daqlist.hpp +241 -73
  11. pyxcp/cpp_ext/extension_wrapper.cpp +123 -15
  12. pyxcp/cpp_ext/framing.hpp +360 -0
  13. pyxcp/cpp_ext/helper.hpp +280 -280
  14. pyxcp/cpp_ext/mcobject.hpp +248 -246
  15. pyxcp/cpp_ext/sxi_framing.hpp +332 -0
  16. pyxcp/daq_stim/__init__.py +145 -67
  17. pyxcp/daq_stim/optimize/binpacking.py +2 -2
  18. pyxcp/daq_stim/scheduler.cpp +8 -8
  19. pyxcp/errormatrix.py +2 -2
  20. pyxcp/examples/run_daq.py +5 -4
  21. pyxcp/examples/xcp_policy.py +6 -6
  22. pyxcp/examples/xcp_read_benchmark.py +2 -2
  23. pyxcp/examples/xcp_skel.py +1 -2
  24. pyxcp/examples/xcp_unlock.py +10 -12
  25. pyxcp/examples/xcp_user_supplied_driver.py +1 -2
  26. pyxcp/examples/xcphello.py +2 -15
  27. pyxcp/examples/xcphello_recorder.py +2 -2
  28. pyxcp/master/__init__.py +1 -0
  29. pyxcp/master/errorhandler.py +134 -4
  30. pyxcp/master/master.py +823 -252
  31. pyxcp/recorder/.idea/.gitignore +8 -0
  32. pyxcp/recorder/.idea/misc.xml +4 -0
  33. pyxcp/recorder/.idea/modules.xml +8 -0
  34. pyxcp/recorder/.idea/recorder.iml +6 -0
  35. pyxcp/recorder/.idea/sonarlint/issuestore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +7 -0
  36. pyxcp/recorder/.idea/sonarlint/issuestore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  37. pyxcp/recorder/.idea/sonarlint/issuestore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  38. pyxcp/recorder/.idea/sonarlint/issuestore/index.pb +7 -0
  39. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +0 -0
  40. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  41. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  42. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/index.pb +7 -0
  43. pyxcp/recorder/.idea/vcs.xml +10 -0
  44. pyxcp/recorder/__init__.py +96 -98
  45. pyxcp/recorder/converter/__init__.py +4 -10
  46. pyxcp/recorder/reader.hpp +138 -139
  47. pyxcp/recorder/reco.py +1 -0
  48. pyxcp/recorder/rekorder.cpython-310-darwin.so +0 -0
  49. pyxcp/recorder/rekorder.cpython-311-darwin.so +0 -0
  50. pyxcp/recorder/rekorder.cpython-312-darwin.so +0 -0
  51. pyxcp/recorder/rekorder.cpython-313-darwin.so +0 -0
  52. pyxcp/recorder/rekorder.hpp +274 -274
  53. pyxcp/recorder/unfolder.hpp +1354 -1319
  54. pyxcp/recorder/wrap.cpp +184 -183
  55. pyxcp/recorder/writer.hpp +302 -302
  56. pyxcp/scripts/xcp_daq_recorder.py +54 -0
  57. pyxcp/scripts/xcp_fetch_a2l.py +2 -2
  58. pyxcp/scripts/xcp_id_scanner.py +1 -2
  59. pyxcp/scripts/xcp_info.py +66 -51
  60. pyxcp/scripts/xcp_profile.py +1 -2
  61. pyxcp/tests/test_daq.py +1 -1
  62. pyxcp/tests/test_framing.py +262 -0
  63. pyxcp/tests/test_master.py +210 -100
  64. pyxcp/tests/test_transport.py +138 -42
  65. pyxcp/timing.py +1 -1
  66. pyxcp/transport/__init__.py +8 -5
  67. pyxcp/transport/base.py +70 -180
  68. pyxcp/transport/can.py +58 -7
  69. pyxcp/transport/eth.py +32 -15
  70. pyxcp/transport/hdf5_policy.py +167 -0
  71. pyxcp/transport/sxi.py +126 -52
  72. pyxcp/transport/transport_ext.cpython-310-darwin.so +0 -0
  73. pyxcp/transport/transport_ext.cpython-311-darwin.so +0 -0
  74. pyxcp/transport/transport_ext.cpython-312-darwin.so +0 -0
  75. pyxcp/transport/transport_ext.cpython-313-darwin.so +0 -0
  76. pyxcp/transport/transport_ext.hpp +214 -0
  77. pyxcp/transport/transport_wrapper.cpp +249 -0
  78. pyxcp/transport/usb_transport.py +47 -31
  79. pyxcp/types.py +0 -13
  80. pyxcp/{utils.py → utils/__init__.py} +1 -2
  81. pyxcp/utils/cli.py +78 -0
  82. {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/METADATA +4 -2
  83. pyxcp-0.25.7.dist-info/RECORD +158 -0
  84. {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/WHEEL +1 -1
  85. pyxcp/examples/conf_sxi.json +0 -9
  86. pyxcp/examples/conf_sxi.toml +0 -7
  87. pyxcp-0.23.8.dist-info/RECORD +0 -135
  88. {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/entry_points.txt +0 -0
  89. {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info/licenses}/LICENSE +0 -0
@@ -10,10 +10,10 @@ VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
10
10
  std::printf("TimerRoutine lpParam is NULL\n");
11
11
  return;
12
12
  }
13
-
13
+
14
14
  const auto* param = static_cast<const int*>(lpParam);
15
15
  std::printf("Timer routine called. Parameter is %d.\n", *param);
16
-
16
+
17
17
  if (TimerOrWaitFired) {
18
18
  std::printf("The wait timed out.\n");
19
19
  } else {
@@ -30,10 +30,10 @@ namespace {
30
30
 
31
31
  #if defined(_M_X64) || defined(_M_IX86) || defined(__SSE__)
32
32
  #include <xmmintrin.h>
33
-
33
+
34
34
  void mul4_vectorized(float* ptr) {
35
35
  if (ptr == nullptr) return;
36
-
36
+
37
37
  __m128 f = _mm_loadu_ps(ptr);
38
38
  f = _mm_mul_ps(f, f);
39
39
  _mm_storeu_ps(ptr, f);
@@ -41,10 +41,10 @@ namespace {
41
41
 
42
42
  #elif defined(_M_ARM64) || defined(__ARM_NEON)
43
43
  #include <arm_neon.h>
44
-
44
+
45
45
  void mul4_vectorized(float* ptr) {
46
46
  if (ptr == nullptr) return;
47
-
47
+
48
48
  float32x4_t f = vld1q_f32(ptr);
49
49
  f = vmulq_f32(f, f);
50
50
  vst1q_f32(ptr, f);
@@ -54,9 +54,9 @@ namespace {
54
54
  // Scalar fallback
55
55
  void mul4_vectorized(float* ptr) {
56
56
  if (ptr == nullptr) return;
57
-
57
+
58
58
  for (size_t i = 0; i < VECTOR_SIZE; ++i) {
59
59
  ptr[i] *= ptr[i];
60
60
  }
61
61
  }
62
- #endif
62
+ #endif
pyxcp/errormatrix.py CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Types and structures to support error-handling as specified by XCP.
3
- """
2
+ """Types and structures to support error-handling as specified by XCP."""
3
+
4
4
  import enum
5
5
  from collections import namedtuple
6
6
 
pyxcp/examples/run_daq.py CHANGED
@@ -129,8 +129,9 @@ else:
129
129
  ),
130
130
  ]
131
131
 
132
- daq_parser = DaqToCsv(DAQ_LISTS) # Record to CSV file(s).
133
- # daq_parser = DaqRecorder(DAQ_LISTS, "run_daq_02092025_01", 4) # Record to ".xmraw" file.
132
+
133
+ # daq_parser = DaqToCsv(DAQ_LISTS) # Record to CSV file(s).
134
+ daq_parser = DaqRecorder(DAQ_LISTS, "run_daq_21092025_01", 8) # Record to ".xmraw" file.
134
135
 
135
136
  with ap.run(policy=daq_parser) as x:
136
137
  try:
@@ -149,8 +150,8 @@ with ap.run(policy=daq_parser) as x:
149
150
  print("start DAQ lists.")
150
151
  daq_parser.start() # Start DAQ lists.
151
152
 
152
- time.sleep(2.0 * 60.0)
153
- # time.sleep(2.0 * 60.0 * 60.0) # Run for 15 minutes.
153
+ # time.sleep(2.0 * 60.0)
154
+ time.sleep(0.25 * 60.0 * 60.0) # Run for 15 minutes.
154
155
 
155
156
  print("Stop DAQ....")
156
157
  daq_parser.stop() # Stop DAQ lists.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Demostrates how to use frame recording policies including recorder extension.
3
- """
2
+ """Demostrates how to use frame recording policies including recorder extension."""
3
+
4
4
  from pprint import pprint
5
5
 
6
6
  from pyxcp.cmdline import ArgumentParser
@@ -11,11 +11,11 @@ ap = ArgumentParser(description="pyXCP frame recording policy example.")
11
11
 
12
12
  LOG_FILE = "pyxcp"
13
13
 
14
- policy = FrameRecorderPolicy(LOG_FILE)
15
- use_recorder = True
14
+ # policy = FrameRecorderPolicy(LOG_FILE)
15
+ # use_recorder = True
16
16
 
17
- # policy = StdoutPolicy() # You may also try this one.
18
- # use_recorder = False
17
+ policy = StdoutPolicy() # You may also try this one.
18
+ use_recorder = False
19
19
 
20
20
  with ap.run(policy=policy) as x:
21
21
  x.connect()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
2
+ """Very basic hello-world example."""
3
+
4
4
  import time
5
5
 
6
6
  import matplotlib.pyplot as plt
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python
2
- """Use this as a copy-and-paste template for your own scripts.
3
- """
2
+ """Use this as a copy-and-paste template for your own scripts."""
4
3
 
5
4
  from pyxcp.cmdline import ArgumentParser
6
5
 
@@ -1,20 +1,13 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
4
- from pyxcp.cmdline import ArgumentParser
5
-
6
-
7
- """
8
- """
2
+ """Very basic hello-world example."""
9
3
 
4
+ import argparse
10
5
 
11
- def callout(master, args):
12
- if args.sk_dll:
13
- master.seedNKeyDLL = args.sk_dll
6
+ from pyxcp.cmdline import ArgumentParser
14
7
 
15
8
 
16
- ap = ArgumentParser(callout)
17
- ap.parser.add_argument(
9
+ parser = argparse.ArgumentParser(description="XCP unlock example")
10
+ parser.add_argument(
18
11
  "-s",
19
12
  "--sk-dll",
20
13
  dest="sk_dll",
@@ -23,7 +16,12 @@ ap.parser.add_argument(
23
16
  default=None,
24
17
  )
25
18
 
19
+ ap = ArgumentParser(parser)
20
+
26
21
  with ap.run() as x:
22
+ if ap.args.sk_dll:
23
+ x.seedNKeyDLL = ap.args.sk_dll
24
+
27
25
  x.connect()
28
26
 
29
27
  print("")
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
 
3
- from typing import Dict, List, Optional
3
+ from typing import Optional
4
4
 
5
5
  import can
6
6
 
@@ -9,7 +9,6 @@ from pyxcp.transport.can import CanInterfaceBase
9
9
 
10
10
 
11
11
  class CustomCANInterface(CanInterfaceBase):
12
-
13
12
  def init(self):
14
13
  """Initialize the CAN interface here."""
15
14
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  """Very basic hello-world example."""
3
+
3
4
  from pprint import pprint
4
5
 
5
6
  from pyxcp.cmdline import ArgumentParser
@@ -9,21 +10,7 @@ from pyxcp.utils import decode_bytes
9
10
  daq_info = False
10
11
 
11
12
 
12
- def callout(master, args):
13
- global daq_info
14
- if args.daq_info:
15
- daq_info = True
16
-
17
-
18
- ap = ArgumentParser(description="pyXCP hello world.", callout=callout)
19
- ap.parser.add_argument(
20
- "-d",
21
- "--daq-info",
22
- dest="daq_info",
23
- help="Display DAQ-info",
24
- default=False,
25
- action="store_true",
26
- )
13
+ ap = ArgumentParser(description="pyXCP hello world.")
27
14
 
28
15
  with ap.run() as x:
29
16
  x.connect()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Very basic hello-world example.
3
- """
2
+ """Very basic hello-world example."""
3
+
4
4
  from pprint import pprint
5
5
 
6
6
  from pyxcp.cmdline import ArgumentParser
pyxcp/master/__init__.py CHANGED
@@ -6,4 +6,5 @@
6
6
 
7
7
  .. [1] XCP Specification, Part 2 - Protocol Layer Specification
8
8
  """
9
+
9
10
  from .master import Master # noqa: F401
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
- """Implements error-handling according to XCP spec.
3
- """
2
+ """Implements error-handling according to XCP spec."""
3
+
4
4
  import functools
5
5
  import logging
6
6
  import threading
@@ -18,7 +18,6 @@ from pyxcp.types import COMMAND_CATEGORIES, XcpError, XcpResponseError, XcpTimeo
18
18
  handle_errors = True # enable/disable XCP error-handling.
19
19
 
20
20
  # Thread-local flag to suppress logging for expected XCP negative responses
21
- import threading
22
21
 
23
22
 
24
23
  _thread_flags = threading.local()
@@ -240,10 +239,141 @@ class Handler:
240
239
  return ""
241
240
 
242
241
  def _append_diag(self, msg: str) -> str:
242
+ # Suppress diagnostics entirely when XCP error logging is suppressed (e.g., try_command probing)
243
+ if is_suppress_xcp_error_log():
244
+ return msg
243
245
  if not self._diagnostics_enabled():
244
246
  return msg
245
247
  diag = self._build_transport_diagnostics()
246
- return msg + ("\n" + diag if diag else "")
248
+ if not diag:
249
+ return msg
250
+ # Prefer a Rich-formatted table for compact, readable diagnostics.
251
+ try:
252
+ header = "--- Diagnostics (for troubleshooting) ---"
253
+ body = diag
254
+ if "\n" in diag and diag.startswith("--- Diagnostics"):
255
+ header, body = diag.split("\n", 1)
256
+
257
+ # Try to parse the structured JSON body produced by transports
258
+ import json as _json # Local import to avoid hard dependency at module import time
259
+
260
+ payload = _json.loads(body)
261
+ transport_params = payload.get("transport_params") or {}
262
+ last_pdus = payload.get("last_pdus") or []
263
+
264
+ # Try to use rich if available
265
+ try:
266
+ from rich.console import Console
267
+ from rich.table import Table
268
+ from rich.panel import Panel
269
+ from textwrap import shorten
270
+
271
+ console = Console(file=None, force_terminal=False, width=120, record=True, markup=False)
272
+
273
+ # Transport parameters table
274
+ tp_table = Table(title="Transport Parameters", title_style="bold", show_header=True, header_style="bold magenta")
275
+ tp_table.add_column("Key", style="cyan", no_wrap=True)
276
+ tp_table.add_column("Value", style="white")
277
+ from rich.markup import escape as _escape
278
+
279
+ for k, v in (transport_params or {}).items():
280
+ # Convert complex values to compact repr
281
+ sv = repr(v)
282
+ sv = shorten(sv, width=80, placeholder="…")
283
+ tp_table.add_row(_escape(str(k)), _escape(sv))
284
+
285
+ # Last PDUs table (most recent last)
286
+ pdu_table = Table(
287
+ title="Last PDUs (most recent last)", title_style="bold", show_header=True, header_style="bold magenta"
288
+ )
289
+ for col in ("dir", "cat", "ctr", "ts", "len", "data"):
290
+ pdu_table.add_column(col, no_wrap=(col in {"dir", "cat", "ctr", "len"}), style="white")
291
+ for pdu in last_pdus:
292
+ try:
293
+ dir_ = str(pdu.get("dir", ""))
294
+ cat = str(pdu.get("cat", ""))
295
+ ctr = str(pdu.get("ctr", ""))
296
+ # Format timestamp: convert ns -> s with 5 decimals if numeric
297
+ ts_val = pdu.get("ts", "")
298
+ try:
299
+ ts_num = int(ts_val)
300
+ ts = f"{ts_num / 1_000_000_000:.5f}"
301
+ except Exception:
302
+ ts = str(ts_val)
303
+ ln = str(pdu.get("len", ""))
304
+ # Prefer showing actual data content; avoid repr quotes
305
+ data_val = pdu.get("data", "")
306
+ try:
307
+ if isinstance(data_val, (bytes, bytearray, list, tuple)):
308
+ # Lazily import to avoid hard dependency
309
+ from pyxcp.utils import hexDump as _hexDump
310
+
311
+ data_str = _hexDump(data_val)
312
+ else:
313
+ data_str = str(data_val)
314
+ except Exception:
315
+ data_str = str(data_val)
316
+ # Shorten potentially huge values to keep table compact
317
+ from textwrap import shorten as _shorten
318
+
319
+ ts = _shorten(ts, width=20, placeholder="…")
320
+ data = _shorten(data_str, width=40, placeholder="…")
321
+ # Escape strings to avoid Rich markup interpretation (e.g., '[' ']' in hex dumps)
322
+ dir_e = _escape(dir_)
323
+ cat_e = _escape(cat)
324
+ ctr_e = _escape(ctr)
325
+ ts_e = _escape(ts)
326
+ ln_e = _escape(ln)
327
+ data_e = _escape(data)
328
+ pdu_table.add_row(dir_e, cat_e, ctr_e, ts_e, ln_e, data_e)
329
+ except Exception:
330
+ # If anything odd in structure, add a single-cell row with repr
331
+ from textwrap import shorten as _shorten
332
+
333
+ pdu_table.add_row(_shorten(repr(pdu), width=80, placeholder="…"), "", "", "", "", "")
334
+
335
+ # Combine into a single panel and capture as text
336
+ console.print(Panel.fit(tp_table, title=header))
337
+ if last_pdus:
338
+ console.print(pdu_table)
339
+ rendered = console.export_text(clear=False)
340
+
341
+ except Exception:
342
+ # Rich not available or rendering failed; fallback to compact logger lines
343
+ self.logger.error(header)
344
+ if transport_params:
345
+ self.logger.error("transport_params: %s", transport_params)
346
+ if last_pdus:
347
+ self.logger.error("last_pdus (most recent last):")
348
+ for pdu in last_pdus:
349
+ try:
350
+ ts_val = pdu.get("ts", "")
351
+ try:
352
+ ts_num = int(ts_val)
353
+ ts_fmt = f"{ts_num / 1_000_000_000:.5f}"
354
+ except Exception:
355
+ ts_fmt = str(ts_val)
356
+ data_val = pdu.get("data", "")
357
+ if isinstance(data_val, (bytes, bytearray, list, tuple)):
358
+ from pyxcp.utils import hexDump as _hexDump
359
+
360
+ data_str = _hexDump(data_val)
361
+ else:
362
+ data_str = str(data_val)
363
+ pdu_copy = dict(pdu)
364
+ pdu_copy["ts"] = ts_fmt
365
+ pdu_copy["data"] = data_str
366
+ self.logger.error("%s", pdu_copy)
367
+ except Exception:
368
+ self.logger.error("%s", pdu)
369
+ except Exception:
370
+ # As a last resort, emit the whole diagnostics blob verbatim
371
+ try:
372
+ for line in diag.splitlines():
373
+ self.logger.error(line)
374
+ except Exception:
375
+ pass
376
+ return msg
247
377
 
248
378
  def __str__(self):
249
379
  return f"Handler(func = {func_name(self.func)} -- {self.arguments} service = {self.service} error_code = {self.error_code})"