pyxcp 0.25.1__cp314-cp314-macosx_11_0_arm64.whl → 0.25.9__cp314-cp314-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.
- pyxcp/__init__.py +2 -2
- pyxcp/cmdline.py +14 -29
- pyxcp/config/__init__.py +1257 -1257
- pyxcp/cpp_ext/aligned_buffer.hpp +1 -1
- pyxcp/cpp_ext/cpp_ext.cpython-310-darwin.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-311-darwin.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-312-darwin.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-313-darwin.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-314-darwin.so +0 -0
- pyxcp/cpp_ext/extension_wrapper.cpp +79 -2
- pyxcp/cpp_ext/framing.hpp +1 -1
- pyxcp/cpp_ext/helper.hpp +280 -280
- pyxcp/cpp_ext/sxi_framing.hpp +1 -1
- pyxcp/daq_stim/__init__.py +95 -32
- pyxcp/daq_stim/optimize/binpacking.py +2 -2
- pyxcp/daq_stim/scheduler.cpp +8 -8
- pyxcp/errormatrix.py +2 -2
- pyxcp/examples/xcp_read_benchmark.py +2 -2
- pyxcp/examples/xcp_skel.py +1 -2
- pyxcp/examples/xcp_unlock.py +10 -12
- pyxcp/examples/xcp_user_supplied_driver.py +1 -2
- pyxcp/examples/xcphello.py +2 -15
- pyxcp/examples/xcphello_recorder.py +2 -2
- pyxcp/master/__init__.py +1 -0
- pyxcp/master/master.py +14 -20
- pyxcp/recorder/.idea/misc.xml +1 -1
- pyxcp/recorder/.idea/modules.xml +1 -1
- pyxcp/recorder/.idea/recorder.iml +1 -1
- pyxcp/recorder/.idea/vcs.xml +1 -1
- pyxcp/recorder/converter/__init__.py +4 -10
- pyxcp/recorder/reader.hpp +138 -138
- pyxcp/recorder/reco.py +1 -0
- pyxcp/recorder/rekorder.hpp +274 -274
- pyxcp/recorder/wrap.cpp +184 -184
- pyxcp/recorder/writer.hpp +302 -302
- pyxcp/scripts/xcp_daq_recorder.py +54 -0
- pyxcp/scripts/xcp_fetch_a2l.py +2 -2
- pyxcp/scripts/xcp_id_scanner.py +1 -2
- pyxcp/scripts/xcp_info.py +66 -51
- pyxcp/scripts/xcp_profile.py +1 -2
- pyxcp/tests/test_binpacking.py +1 -0
- pyxcp/tests/test_daq.py +1 -1
- pyxcp/tests/test_framing.py +1 -1
- pyxcp/tests/test_master.py +104 -83
- pyxcp/tests/test_transport.py +0 -1
- pyxcp/timing.py +1 -1
- pyxcp/transport/base.py +1 -1
- pyxcp/transport/can.py +1 -1
- pyxcp/transport/eth.py +1 -1
- pyxcp/transport/hdf5_policy.py +167 -0
- pyxcp/transport/sxi.py +1 -1
- pyxcp/transport/transport_ext.cpython-310-darwin.so +0 -0
- pyxcp/transport/transport_ext.cpython-311-darwin.so +0 -0
- pyxcp/transport/transport_ext.cpython-312-darwin.so +0 -0
- pyxcp/transport/transport_ext.cpython-313-darwin.so +0 -0
- pyxcp/transport/transport_ext.cpython-314-darwin.so +0 -0
- pyxcp/transport/usb_transport.py +1 -1
- pyxcp/{utils.py → utils/__init__.py} +1 -2
- pyxcp/utils/cli.py +78 -0
- {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/METADATA +1 -1
- {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/RECORD +64 -56
- {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/WHEEL +1 -1
- {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/entry_points.txt +0 -0
- {pyxcp-0.25.1.dist-info → pyxcp-0.25.9.dist-info}/licenses/LICENSE +0 -0
pyxcp/daq_stim/__init__.py
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
import json
|
|
3
5
|
from time import time_ns
|
|
4
|
-
from typing import Dict, List, Optional, TextIO, Union
|
|
6
|
+
from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
|
|
7
|
+
|
|
8
|
+
from pyxcp.cpp_ext.cpp_ext import DaqList, PredefinedDaqList
|
|
5
9
|
|
|
6
10
|
from pyxcp import types
|
|
7
11
|
from pyxcp.config import get_application
|
|
8
|
-
from pyxcp.cpp_ext.cpp_ext import DaqList, PredefinedDaqList
|
|
9
12
|
from pyxcp.daq_stim.optimize import make_continuous_blocks
|
|
10
13
|
from pyxcp.daq_stim.optimize.binpacking import first_fit_decreasing
|
|
11
14
|
from pyxcp.recorder import DaqOnlinePolicy as _DaqOnlinePolicy
|
|
@@ -27,6 +30,83 @@ DAQ_TIMESTAMP_SIZE = {
|
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
def load_daq_lists_from_json(file_path: str) -> List[DaqList]:
|
|
34
|
+
"""Load and validate DAQ-list from JSON file."""
|
|
35
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
36
|
+
config = json.load(f)
|
|
37
|
+
|
|
38
|
+
if not isinstance(config, list):
|
|
39
|
+
raise ValueError("DAQ configuration must be a JSON array (list)")
|
|
40
|
+
|
|
41
|
+
daq_lists: List[DaqList] = []
|
|
42
|
+
for idx, entry in enumerate(config):
|
|
43
|
+
if not isinstance(entry, dict):
|
|
44
|
+
raise TypeError(f"Entry {idx} must be an object/dict")
|
|
45
|
+
|
|
46
|
+
required = {"name", "event_num", "stim", "enable_timestamps", "measurements", "priority", "prescaler"}
|
|
47
|
+
missing = required - set(entry.keys())
|
|
48
|
+
if missing:
|
|
49
|
+
raise ValueError(f"Entry {idx} missing required keys: {missing}")
|
|
50
|
+
|
|
51
|
+
# Basic type conversions / checks
|
|
52
|
+
name = entry["name"]
|
|
53
|
+
if not isinstance(name, str):
|
|
54
|
+
raise TypeError(f"Entry {idx} 'name' must be a string")
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
event_num = int(entry["event_num"])
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise TypeError(f"Entry {idx} 'event_num' must be an integer") from e
|
|
60
|
+
|
|
61
|
+
stim = bool(entry["stim"])
|
|
62
|
+
enable_timestamps = bool(entry["enable_timestamps"])
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
priority = int(entry["priority"])
|
|
66
|
+
prescaler = int(entry["prescaler"])
|
|
67
|
+
except Exception as e:
|
|
68
|
+
raise TypeError(f"Entry {idx} 'priority' and 'prescaler' must be integers") from e
|
|
69
|
+
|
|
70
|
+
measurements_raw = entry["measurements"]
|
|
71
|
+
if not isinstance(measurements_raw, list):
|
|
72
|
+
raise TypeError(f"Entry {idx} 'measurements' must be a list")
|
|
73
|
+
|
|
74
|
+
measurements: List[Tuple[str, int, int, str]] = []
|
|
75
|
+
for m_idx, m in enumerate(measurements_raw):
|
|
76
|
+
if not (isinstance(m, (list, tuple)) and len(m) == 4):
|
|
77
|
+
raise ValueError(f"Entry {idx} measurement {m_idx} must be a 4-element list/tuple")
|
|
78
|
+
m_name, m_addr, m_offset, m_type = m
|
|
79
|
+
|
|
80
|
+
if not isinstance(m_name, str):
|
|
81
|
+
raise TypeError(f"Entry {idx} measurement {m_idx} name must be a string")
|
|
82
|
+
try:
|
|
83
|
+
m_addr = int(m_addr)
|
|
84
|
+
except Exception as e:
|
|
85
|
+
raise TypeError(f"Entry {idx} measurement {m_idx} address must be an integer") from e
|
|
86
|
+
try:
|
|
87
|
+
m_offset = int(m_offset)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
raise TypeError(f"Entry {idx} measurement {m_idx} offset must be an integer") from e
|
|
90
|
+
if not isinstance(m_type, str):
|
|
91
|
+
raise TypeError(f"Entry {idx} measurement {m_idx} type must be a string")
|
|
92
|
+
|
|
93
|
+
measurements.append((m_name, m_addr, m_offset, m_type))
|
|
94
|
+
|
|
95
|
+
daq_kwargs: Dict[str, Any] = {
|
|
96
|
+
"name": name,
|
|
97
|
+
"event_num": event_num,
|
|
98
|
+
"stim": stim,
|
|
99
|
+
"enable_timestamps": enable_timestamps,
|
|
100
|
+
"measurements": measurements,
|
|
101
|
+
"priority": priority,
|
|
102
|
+
"prescaler": prescaler,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
daq_lists.append(DaqList(**daq_kwargs))
|
|
106
|
+
|
|
107
|
+
return daq_lists
|
|
108
|
+
|
|
109
|
+
|
|
30
110
|
class DaqProcessor:
|
|
31
111
|
def __init__(self, daq_lists: List[Union[DaqList, PredefinedDaqList]]):
|
|
32
112
|
self.daq_lists = daq_lists
|
|
@@ -74,14 +154,13 @@ class DaqProcessor:
|
|
|
74
154
|
self.selectable_timestamps = False
|
|
75
155
|
max_payload_size_first = max_payload_size
|
|
76
156
|
if not self.supports_timestampes:
|
|
77
|
-
|
|
78
|
-
pass
|
|
157
|
+
self.log.info("No timestamp support")
|
|
79
158
|
else:
|
|
80
159
|
if self.ts_fixed:
|
|
81
|
-
|
|
160
|
+
self.log.debug("Fixed timestamps")
|
|
82
161
|
max_payload_size_first = max_payload_size - self.ts_size
|
|
83
162
|
else:
|
|
84
|
-
|
|
163
|
+
self.log.debug("Variable timestamps.")
|
|
85
164
|
self.selectable_timestamps = True
|
|
86
165
|
except Exception as e:
|
|
87
166
|
raise TypeError(f"DAQ_INFO corrupted: {e}") from e
|
|
@@ -159,8 +238,6 @@ class DaqProcessor:
|
|
|
159
238
|
)
|
|
160
239
|
res = self.xcp_master.startStopDaqList(0x02, i)
|
|
161
240
|
self._first_pids.append(res.firstPid)
|
|
162
|
-
if start_datetime:
|
|
163
|
-
pass
|
|
164
241
|
self.measurement_params = MeasurementParameters(
|
|
165
242
|
byte_order,
|
|
166
243
|
header_len,
|
|
@@ -184,26 +261,21 @@ class DaqProcessor:
|
|
|
184
261
|
# If a fatal OS error occurred during acquisition, skip sending stop to the slave to avoid
|
|
185
262
|
# cascading timeouts/unrecoverable errors and shut down transport gracefully instead.
|
|
186
263
|
if getattr(self, "_fatal_os_error", False):
|
|
187
|
-
|
|
264
|
+
with suppress(Exception):
|
|
188
265
|
self.log.error(
|
|
189
266
|
"DAQ stop skipped due to previous fatal OS error (e.g., disk full or out-of-memory). Closing transport."
|
|
190
267
|
)
|
|
191
|
-
except Exception:
|
|
192
|
-
pass # nosec
|
|
193
268
|
try:
|
|
194
269
|
# Best-effort: stop listener and close transport so threads finish cleanly.
|
|
195
270
|
if hasattr(self.xcp_master, "transport") and self.xcp_master.transport is not None:
|
|
196
271
|
# Signal listeners to stop
|
|
197
|
-
|
|
272
|
+
with suppress(Exception):
|
|
198
273
|
if hasattr(self.xcp_master.transport, "closeEvent"):
|
|
199
274
|
self.xcp_master.transport.closeEvent.set()
|
|
200
|
-
|
|
201
|
-
pass # nosec
|
|
275
|
+
|
|
202
276
|
# Close transport connection
|
|
203
|
-
|
|
277
|
+
with suppress(Exception):
|
|
204
278
|
self.xcp_master.transport.close()
|
|
205
|
-
except Exception:
|
|
206
|
-
pass # nosec
|
|
207
279
|
finally:
|
|
208
280
|
return
|
|
209
281
|
self.xcp_master.startStopSynch(0x00)
|
|
@@ -268,30 +340,21 @@ class DaqToCsv(DaqOnlinePolicy):
|
|
|
268
340
|
except (OSError, MemoryError) as ex:
|
|
269
341
|
# Mark fatal condition to alter shutdown path and avoid further writes/commands.
|
|
270
342
|
self._fatal_os_error = True
|
|
271
|
-
|
|
343
|
+
with suppress(Exception):
|
|
272
344
|
self.log.critical(f"DAQ file write failed: {ex.__class__.__name__}: {ex}. Initiating graceful shutdown.")
|
|
273
|
-
|
|
274
|
-
pass # nosec
|
|
345
|
+
|
|
275
346
|
# Stop listener to prevent more DAQ traffic and avoid thread crashes.
|
|
276
|
-
|
|
347
|
+
with suppress(Exception):
|
|
277
348
|
if hasattr(self.xcp_master, "transport") and self.xcp_master.transport is not None:
|
|
278
349
|
if hasattr(self.xcp_master.transport, "closeEvent"):
|
|
279
350
|
self.xcp_master.transport.closeEvent.set()
|
|
280
|
-
except Exception:
|
|
281
|
-
pass # nosec
|
|
282
351
|
# Best-effort: close any opened files to flush buffers and release resources.
|
|
283
|
-
|
|
352
|
+
with suppress(Exception):
|
|
284
353
|
for f in getattr(self, "files", {}).values():
|
|
285
|
-
|
|
354
|
+
with suppress(Exception):
|
|
286
355
|
f.flush()
|
|
287
|
-
|
|
288
|
-
pass # nosec
|
|
289
|
-
try:
|
|
356
|
+
with suppress(Exception):
|
|
290
357
|
f.close()
|
|
291
|
-
except Exception:
|
|
292
|
-
pass # nosec
|
|
293
|
-
except Exception:
|
|
294
|
-
pass # nosec
|
|
295
358
|
# Do not re-raise; allow the system to continue to a controlled shutdown.
|
|
296
359
|
return
|
|
297
360
|
|
pyxcp/daq_stim/scheduler.cpp
CHANGED
|
@@ -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
pyxcp/examples/xcp_skel.py
CHANGED
pyxcp/examples/xcp_unlock.py
CHANGED
|
@@ -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
|
-
|
|
12
|
-
if args.sk_dll:
|
|
13
|
-
master.seedNKeyDLL = args.sk_dll
|
|
6
|
+
from pyxcp.cmdline import ArgumentParser
|
|
14
7
|
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
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
|
|
pyxcp/examples/xcphello.py
CHANGED
|
@@ -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
|
-
|
|
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()
|
pyxcp/master/__init__.py
CHANGED
pyxcp/master/master.py
CHANGED
|
@@ -6,14 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
.. [1] XCP Specification, Part 2 - Protocol Layer Specification
|
|
8
8
|
"""
|
|
9
|
-
from __future__ import annotations
|
|
10
9
|
|
|
11
10
|
import functools
|
|
12
11
|
import logging
|
|
13
12
|
import struct
|
|
14
13
|
import traceback
|
|
15
14
|
import warnings
|
|
16
|
-
from
|
|
15
|
+
from contextlib import suppress
|
|
16
|
+
from typing import Any, Callable, Collection, TypeVar
|
|
17
|
+
|
|
18
|
+
from pyxcp.daq_stim.stim import DaqEventInfo, Stim
|
|
17
19
|
|
|
18
20
|
from pyxcp import checksum, types
|
|
19
21
|
from pyxcp.constants import (
|
|
@@ -26,7 +28,6 @@ from pyxcp.constants import (
|
|
|
26
28
|
makeWordPacker,
|
|
27
29
|
makeWordUnpacker,
|
|
28
30
|
)
|
|
29
|
-
from pyxcp.daq_stim.stim import DaqEventInfo, Stim
|
|
30
31
|
from pyxcp.master.errorhandler import (
|
|
31
32
|
SystemExit,
|
|
32
33
|
disable_error_handling,
|
|
@@ -37,7 +38,6 @@ from pyxcp.master.errorhandler import (
|
|
|
37
38
|
from pyxcp.transport.base import create_transport
|
|
38
39
|
from pyxcp.utils import decode_bytes, delay, short_sleep
|
|
39
40
|
|
|
40
|
-
|
|
41
41
|
# Type variables for better type hinting
|
|
42
42
|
T = TypeVar("T")
|
|
43
43
|
R = TypeVar("R")
|
|
@@ -211,7 +211,7 @@ class Master:
|
|
|
211
211
|
self.slaveProperties.pgmProcessor = SlaveProperties()
|
|
212
212
|
self.slaveProperties.transport_layer = self.transport_name.upper()
|
|
213
213
|
|
|
214
|
-
def __enter__(self)
|
|
214
|
+
def __enter__(self):
|
|
215
215
|
"""Context manager entry part.
|
|
216
216
|
|
|
217
217
|
This method is called when entering a context manager block.
|
|
@@ -225,9 +225,7 @@ class Master:
|
|
|
225
225
|
self.transport.connect()
|
|
226
226
|
return self
|
|
227
227
|
|
|
228
|
-
def __exit__(
|
|
229
|
-
self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: traceback.TracebackType | None
|
|
230
|
-
) -> None:
|
|
228
|
+
def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb) -> None:
|
|
231
229
|
"""Context manager exit part.
|
|
232
230
|
|
|
233
231
|
This method is called when exiting a context manager block.
|
|
@@ -541,11 +539,7 @@ class Master:
|
|
|
541
539
|
"""
|
|
542
540
|
# Send GET_ID command to the slave
|
|
543
541
|
response = self.transport.request(types.Command.GET_ID, mode)
|
|
544
|
-
|
|
545
|
-
# Parse the response with the correct byte order
|
|
546
542
|
result = types.GetIDResponse.parse(response, byteOrder=self.slaveProperties.byteOrder)
|
|
547
|
-
|
|
548
|
-
# Extract the length from the response
|
|
549
543
|
result.length = self.DWORD_unpack(response[3:7])[0]
|
|
550
544
|
|
|
551
545
|
return result
|
|
@@ -751,15 +745,14 @@ class Master:
|
|
|
751
745
|
# Larger sizes will send in multiple CAN messages
|
|
752
746
|
# Each valid message will start with 0xFF followed by the upload bytes
|
|
753
747
|
# The last message might be padded to the required DLC
|
|
754
|
-
remaining_bytes = byte_count - len(response)
|
|
755
|
-
while remaining_bytes:
|
|
748
|
+
remaining_bytes = byte_count - len(response) # NOTE: Due to padding the result may negative!
|
|
749
|
+
while remaining_bytes > 0:
|
|
756
750
|
if len(self.transport.resQueue):
|
|
757
751
|
data = self.transport.resQueue.popleft()
|
|
758
752
|
response += data[1 : remaining_bytes + 1]
|
|
759
753
|
remaining_bytes = byte_count - len(response)
|
|
760
754
|
else:
|
|
761
755
|
short_sleep()
|
|
762
|
-
|
|
763
756
|
return response
|
|
764
757
|
|
|
765
758
|
@wrapped
|
|
@@ -2326,7 +2319,7 @@ class Master:
|
|
|
2326
2319
|
if self.currentProtectionStatus is None:
|
|
2327
2320
|
try:
|
|
2328
2321
|
status = self.getStatus()
|
|
2329
|
-
except Exception
|
|
2322
|
+
except Exception: # may temporary ERR_OUT_OF_RANGE
|
|
2330
2323
|
return {"dbg": None, "pgm": None, "stim": None, "daq": None, "calpag": None}
|
|
2331
2324
|
self._setProtectionStatus(status.resourceProtectionStatus)
|
|
2332
2325
|
return self.currentProtectionStatus
|
|
@@ -2499,7 +2492,10 @@ class Master:
|
|
|
2499
2492
|
name = STD_IDS[id_value]
|
|
2500
2493
|
else:
|
|
2501
2494
|
name = f"USER_{idx}"
|
|
2502
|
-
yield
|
|
2495
|
+
yield (
|
|
2496
|
+
id_value,
|
|
2497
|
+
name,
|
|
2498
|
+
)
|
|
2503
2499
|
|
|
2504
2500
|
return generate()
|
|
2505
2501
|
|
|
@@ -2590,10 +2586,8 @@ class Master:
|
|
|
2590
2586
|
return (types.TryCommandResult.OK, res)
|
|
2591
2587
|
finally:
|
|
2592
2588
|
# Ensure suppression flag is restored even on success/other exceptions
|
|
2593
|
-
|
|
2589
|
+
with suppress(Exception):
|
|
2594
2590
|
set_suppress_xcp_error_log(_prev_suppress)
|
|
2595
|
-
except Exception:
|
|
2596
|
-
pass # nosec B110
|
|
2597
2591
|
|
|
2598
2592
|
|
|
2599
2593
|
def ticks_to_seconds(ticks, resolution):
|
pyxcp/recorder/.idea/misc.xml
CHANGED
pyxcp/recorder/.idea/modules.xml
CHANGED
pyxcp/recorder/.idea/vcs.xml
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Convert pyXCPs .xmraw files to common data formats."""
|
|
2
2
|
|
|
3
|
+
from contextlib import suppress
|
|
3
4
|
import csv
|
|
4
5
|
import logging
|
|
5
6
|
import os
|
|
@@ -119,10 +120,8 @@ class XcpLogFileDecoder(_XcpLogFileDecoder):
|
|
|
119
120
|
self.out_file_suffix = out_file_suffix
|
|
120
121
|
self.target_type_map = target_type_map or {}
|
|
121
122
|
if remove_file:
|
|
122
|
-
|
|
123
|
+
with suppress(FileNotFoundError):
|
|
123
124
|
os.unlink(self.out_file_name)
|
|
124
|
-
except FileNotFoundError:
|
|
125
|
-
pass
|
|
126
125
|
|
|
127
126
|
def initialize(self) -> None:
|
|
128
127
|
self.on_initialize()
|
|
@@ -154,7 +153,6 @@ class XcpLogFileDecoder(_XcpLogFileDecoder):
|
|
|
154
153
|
|
|
155
154
|
|
|
156
155
|
class CollectRows:
|
|
157
|
-
|
|
158
156
|
def on_daq_list(self, daq_list_num: int, timestamp0: int, timestamp1: int, measurements: list) -> None:
|
|
159
157
|
storage_container = self.tables[daq_list_num]
|
|
160
158
|
storage_container.timestamp0.append(timestamp0)
|
|
@@ -214,7 +212,6 @@ class ArrowConverter(CollectRows, XcpLogFileDecoder):
|
|
|
214
212
|
|
|
215
213
|
|
|
216
214
|
class CsvConverter(XcpLogFileDecoder):
|
|
217
|
-
|
|
218
215
|
def __init__(self, recording_file_name: str, target_file_name: str = ""):
|
|
219
216
|
super().__init__(
|
|
220
217
|
recording_file_name=recording_file_name, out_file_suffix=".csv", remove_file=False, target_file_name=target_file_name
|
|
@@ -242,7 +239,6 @@ class CsvConverter(XcpLogFileDecoder):
|
|
|
242
239
|
|
|
243
240
|
|
|
244
241
|
class ExcelConverter(XcpLogFileDecoder):
|
|
245
|
-
|
|
246
242
|
def __init__(self, recording_file_name: str, target_file_name: str = ""):
|
|
247
243
|
super().__init__(recording_file_name=recording_file_name, out_file_suffix=".xlsx", target_file_name=target_file_name)
|
|
248
244
|
|
|
@@ -273,7 +269,6 @@ class ExcelConverter(XcpLogFileDecoder):
|
|
|
273
269
|
|
|
274
270
|
|
|
275
271
|
class HdfConverter(CollectRows, XcpLogFileDecoder):
|
|
276
|
-
|
|
277
272
|
def __init__(self, recording_file_name: str, target_file_name: str = ""):
|
|
278
273
|
super().__init__(recording_file_name=recording_file_name, out_file_suffix=".h5", target_file_name=target_file_name)
|
|
279
274
|
|
|
@@ -296,7 +291,6 @@ class HdfConverter(CollectRows, XcpLogFileDecoder):
|
|
|
296
291
|
|
|
297
292
|
|
|
298
293
|
class MdfConverter(CollectRows, XcpLogFileDecoder):
|
|
299
|
-
|
|
300
294
|
def __init__(self, recording_file_name: str, target_file_name: str = ""):
|
|
301
295
|
super().__init__(
|
|
302
296
|
recording_file_name=recording_file_name,
|
|
@@ -367,8 +361,8 @@ class SqliteConverter(XcpLogFileDecoder):
|
|
|
367
361
|
self.create_table(sc)
|
|
368
362
|
self.logger.info(f"Creating table {sc.name!r}.")
|
|
369
363
|
self.insert_stmt[sc.name] = (
|
|
370
|
-
f"""INSERT INTO {sc.name}({
|
|
371
|
-
f""" VALUES({
|
|
364
|
+
f"""INSERT INTO {sc.name}({", ".join(["timestamp0", "timestamp1"] + [r.name for r in sc.arr])})"""
|
|
365
|
+
f""" VALUES({", ".join(["?" for _ in range(len(sc.arr) + 2)])})"""
|
|
372
366
|
)
|
|
373
367
|
|
|
374
368
|
def on_finalize(self) -> None:
|