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.
- pyxcp/__init__.py +1 -1
- pyxcp/cmdline.py +14 -29
- pyxcp/config/__init__.py +1257 -1258
- pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
- pyxcp/cpp_ext/bin.hpp +7 -6
- 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/daqlist.hpp +241 -73
- pyxcp/cpp_ext/extension_wrapper.cpp +123 -15
- pyxcp/cpp_ext/framing.hpp +360 -0
- pyxcp/cpp_ext/helper.hpp +280 -280
- pyxcp/cpp_ext/mcobject.hpp +248 -246
- pyxcp/cpp_ext/sxi_framing.hpp +332 -0
- pyxcp/daq_stim/__init__.py +145 -67
- pyxcp/daq_stim/optimize/binpacking.py +2 -2
- pyxcp/daq_stim/scheduler.cpp +8 -8
- pyxcp/errormatrix.py +2 -2
- pyxcp/examples/run_daq.py +5 -4
- pyxcp/examples/xcp_policy.py +6 -6
- 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/errorhandler.py +134 -4
- pyxcp/master/master.py +823 -252
- pyxcp/recorder/.idea/.gitignore +8 -0
- pyxcp/recorder/.idea/misc.xml +4 -0
- pyxcp/recorder/.idea/modules.xml +8 -0
- pyxcp/recorder/.idea/recorder.iml +6 -0
- pyxcp/recorder/.idea/sonarlint/issuestore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +7 -0
- pyxcp/recorder/.idea/sonarlint/issuestore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
- pyxcp/recorder/.idea/sonarlint/issuestore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
- pyxcp/recorder/.idea/sonarlint/issuestore/index.pb +7 -0
- pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +0 -0
- pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
- pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
- pyxcp/recorder/.idea/sonarlint/securityhotspotstore/index.pb +7 -0
- pyxcp/recorder/.idea/vcs.xml +10 -0
- pyxcp/recorder/__init__.py +96 -98
- pyxcp/recorder/converter/__init__.py +4 -10
- pyxcp/recorder/reader.hpp +138 -139
- pyxcp/recorder/reco.py +1 -0
- pyxcp/recorder/rekorder.cpython-310-darwin.so +0 -0
- pyxcp/recorder/rekorder.cpython-311-darwin.so +0 -0
- pyxcp/recorder/rekorder.cpython-312-darwin.so +0 -0
- pyxcp/recorder/rekorder.cpython-313-darwin.so +0 -0
- pyxcp/recorder/rekorder.hpp +274 -274
- pyxcp/recorder/unfolder.hpp +1354 -1319
- pyxcp/recorder/wrap.cpp +184 -183
- 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_daq.py +1 -1
- pyxcp/tests/test_framing.py +262 -0
- pyxcp/tests/test_master.py +210 -100
- pyxcp/tests/test_transport.py +138 -42
- pyxcp/timing.py +1 -1
- pyxcp/transport/__init__.py +8 -5
- pyxcp/transport/base.py +70 -180
- pyxcp/transport/can.py +58 -7
- pyxcp/transport/eth.py +32 -15
- pyxcp/transport/hdf5_policy.py +167 -0
- pyxcp/transport/sxi.py +126 -52
- 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.hpp +214 -0
- pyxcp/transport/transport_wrapper.cpp +249 -0
- pyxcp/transport/usb_transport.py +47 -31
- pyxcp/types.py +0 -13
- pyxcp/{utils.py → utils/__init__.py} +1 -2
- pyxcp/utils/cli.py +78 -0
- {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/METADATA +4 -2
- pyxcp-0.25.7.dist-info/RECORD +158 -0
- {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/WHEEL +1 -1
- pyxcp/examples/conf_sxi.json +0 -9
- pyxcp/examples/conf_sxi.toml +0 -7
- pyxcp-0.23.8.dist-info/RECORD +0 -135
- {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info}/entry_points.txt +0 -0
- {pyxcp-0.23.8.dist-info → pyxcp-0.25.7.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
|
|
2
|
+
T cpp:S5028"8Replace this macro by "const", "constexpr" or an "enum".(����8�1
|
|
3
|
+
cpp:S3806""^non-portable path to file '<windows.h>'; specified path differs in case from file name on disk(��������8�����1
|
|
4
|
+
Tcpp:S954�"8Move these 3 #include directives to the top of the file.(���8ﴔ��1
|
|
5
|
+
T cpp:S5028"8Replace this macro by "const", "constexpr" or an "enum".(����8帔��1
|
|
6
|
+
cpp:S3806""^non-portable path to file '<windows.h>'; specified path differs in case from file name on disk(��������8�Ӕ��1
|
|
7
|
+
Tcpp:S954�"8Move these 3 #include directives to the top of the file.(���8�Ԕ��1
|
|
File without changes
|
|
File without changes
|
pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728
ADDED
|
File without changes
|
pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae
ADDED
|
File without changes
|
pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91
ADDED
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="VcsDirectoryMappings">
|
|
4
|
+
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
|
5
|
+
<mapping directory="$PROJECT_DIR$/lz4" vcs="Git" />
|
|
6
|
+
<mapping directory="$PROJECT_DIR$/mio" vcs="Git" />
|
|
7
|
+
<mapping directory="$PROJECT_DIR$/simde" vcs="Git" />
|
|
8
|
+
<mapping directory="$PROJECT_DIR$/simdjson" vcs="Git" />
|
|
9
|
+
</component>
|
|
10
|
+
</project>
|
pyxcp/recorder/__init__.py
CHANGED
|
@@ -1,98 +1,96 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
"""XCP Frame Recording Facility.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
from pyxcp.recorder.rekorder import
|
|
19
|
-
from pyxcp.recorder.rekorder import
|
|
20
|
-
from pyxcp.recorder.rekorder import
|
|
21
|
-
from pyxcp.recorder.rekorder import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
df =
|
|
75
|
-
df = df.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def finalize(self):
|
|
98
|
-
self._writer.finalize()
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""XCP Frame Recording Facility."""
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
from pyxcp.transport.base import FrameCategory
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import pandas as pd
|
|
12
|
+
except ImportError:
|
|
13
|
+
HAS_PANDAS = False
|
|
14
|
+
else:
|
|
15
|
+
HAS_PANDAS = True
|
|
16
|
+
|
|
17
|
+
from pyxcp.recorder.rekorder import DaqOnlinePolicy # noqa: F401
|
|
18
|
+
from pyxcp.recorder.rekorder import DaqRecorderPolicy # noqa: F401
|
|
19
|
+
from pyxcp.recorder.rekorder import Deserializer # noqa: F401
|
|
20
|
+
from pyxcp.recorder.rekorder import MeasurementParameters # noqa: F401
|
|
21
|
+
from pyxcp.recorder.rekorder import _PyXcpLogFileReader, _PyXcpLogFileWriter, data_types
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
DATA_TYPES = data_types()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class XcpLogFileHeader:
|
|
29
|
+
""" """
|
|
30
|
+
|
|
31
|
+
version: int
|
|
32
|
+
options: int
|
|
33
|
+
num_containers: int
|
|
34
|
+
record_count: int
|
|
35
|
+
size_uncompressed: int
|
|
36
|
+
size_compressed: int
|
|
37
|
+
compression_ratio: float
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
COUNTER_MAX = 0xFFFF
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class XcpLogFileReader:
|
|
44
|
+
""" """
|
|
45
|
+
|
|
46
|
+
def __init__(self, file_name):
|
|
47
|
+
self._reader = _PyXcpLogFileReader(file_name)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def header(self):
|
|
51
|
+
return self._reader.get_header()
|
|
52
|
+
|
|
53
|
+
def get_header(self):
|
|
54
|
+
return XcpLogFileHeader(*self._reader.get_header_as_tuple())
|
|
55
|
+
|
|
56
|
+
def get_metadata(self):
|
|
57
|
+
return self._reader.get_metadata()
|
|
58
|
+
|
|
59
|
+
def __iter__(self):
|
|
60
|
+
while True:
|
|
61
|
+
frames = self._reader.next_block()
|
|
62
|
+
if frames is None:
|
|
63
|
+
break
|
|
64
|
+
for category, counter, timestamp, _, payload in frames:
|
|
65
|
+
yield (FrameCategory(category), counter, timestamp, payload)
|
|
66
|
+
|
|
67
|
+
def reset_iter(self):
|
|
68
|
+
self._reader.reset()
|
|
69
|
+
|
|
70
|
+
def as_dataframe(self):
|
|
71
|
+
if HAS_PANDAS:
|
|
72
|
+
df = pd.DataFrame((f for f in self), columns=["category", "counter", "timestamp", "payload"])
|
|
73
|
+
df = df.set_index("timestamp")
|
|
74
|
+
df.counter = df.counter.astype("uint16")
|
|
75
|
+
df.category = df.category.map({v: k for k, v in FrameCategory.__members__.items()}).astype("category")
|
|
76
|
+
return df
|
|
77
|
+
else:
|
|
78
|
+
raise NotImplementedError("method as_dataframe() requires 'pandas' package")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class XcpLogFileWriter:
|
|
82
|
+
""" """
|
|
83
|
+
|
|
84
|
+
def __init__(self, file_name: str, prealloc=500, chunk_size=1):
|
|
85
|
+
self._writer = _PyXcpLogFileWriter(file_name, prealloc, chunk_size)
|
|
86
|
+
self._finalized = False
|
|
87
|
+
|
|
88
|
+
def __del__(self):
|
|
89
|
+
if not self._finalized:
|
|
90
|
+
self.finalize()
|
|
91
|
+
|
|
92
|
+
def add_frame(self, category: FrameCategory, counter: int, timestamp: float, payload: Union[bytes, bytearray]):
|
|
93
|
+
self._writer.add_frame(category, counter % (COUNTER_MAX + 1), timestamp, len(payload), payload)
|
|
94
|
+
|
|
95
|
+
def finalize(self):
|
|
96
|
+
self._writer.finalize()
|
|
@@ -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:
|
pyxcp/recorder/reader.hpp
CHANGED
|
@@ -1,139 +1,138 @@
|
|
|
1
|
-
|
|
2
|
-
#ifndef RECORDER_READER_HPP
|
|
3
|
-
#define RECORDER_READER_HPP
|
|
4
|
-
|
|
5
|
-
#include <iostream>
|
|
6
|
-
|
|
7
|
-
class XcpLogFileReader {
|
|
8
|
-
public:
|
|
9
|
-
|
|
10
|
-
explicit XcpLogFileReader(const std::string &file_name) {
|
|
11
|
-
if (!file_name.ends_with(detail::FILE_EXTENSION)) {
|
|
12
|
-
m_file_name = file_name + detail::FILE_EXTENSION;
|
|
13
|
-
} else {
|
|
14
|
-
m_file_name = file_name;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
m_mmap = new mio::mmap_source(m_file_name);
|
|
18
|
-
blob_t magic[detail::MAGIC_SIZE + 1];
|
|
19
|
-
|
|
20
|
-
read_bytes(0UL, detail::MAGIC_SIZE, magic);
|
|
21
|
-
if (memcmp(detail::MAGIC.c_str(), magic, detail::MAGIC_SIZE) != 0) {
|
|
22
|
-
throw std::runtime_error("Invalid file magic.");
|
|
23
|
-
}
|
|
24
|
-
m_offset = detail::MAGIC_SIZE;
|
|
25
|
-
|
|
26
|
-
read_bytes(m_offset, detail::FILE_HEADER_SIZE, reinterpret_cast<blob_t *>(&m_header));
|
|
27
|
-
// printf("Sizes: %u %u %.3f\n", m_header.size_uncompressed,
|
|
28
|
-
// m_header.size_compressed,
|
|
29
|
-
// float(m_header.size_uncompressed) / float(m_header.size_compressed));
|
|
30
|
-
if (m_header.hdr_size != detail::FILE_HEADER_SIZE + detail::MAGIC_SIZE) {
|
|
31
|
-
throw std::runtime_error("File header size does not match.");
|
|
32
|
-
}
|
|
33
|
-
if (detail::VERSION != m_header.version) {
|
|
34
|
-
throw std::runtime_error("File version mismatch.");
|
|
35
|
-
}
|
|
36
|
-
#if 0
|
|
37
|
-
if (m_header.num_containers < 1) {
|
|
38
|
-
throw std::runtime_error("At least one container required.");
|
|
39
|
-
}
|
|
40
|
-
#endif
|
|
41
|
-
m_offset += detail::FILE_HEADER_SIZE;
|
|
42
|
-
|
|
43
|
-
if ((m_header.options & XMRAW_HAS_METADATA) == XMRAW_HAS_METADATA) {
|
|
44
|
-
std::size_t metadata_length = 0;
|
|
45
|
-
std::size_t data_start = m_offset + sizeof(std::size_t);
|
|
46
|
-
|
|
47
|
-
read_bytes(m_offset, sizeof(std::size_t), reinterpret_cast<blob_t *>(&metadata_length));
|
|
48
|
-
|
|
49
|
-
std::copy(ptr(data_start), ptr(data_start + metadata_length), std::back_inserter(m_metadata));
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
hdr.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
auto
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
std::
|
|
132
|
-
std::uint64_t
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
#endif // RECORDER_READER_HPP
|
|
1
|
+
|
|
2
|
+
#ifndef RECORDER_READER_HPP
|
|
3
|
+
#define RECORDER_READER_HPP
|
|
4
|
+
|
|
5
|
+
#include <iostream>
|
|
6
|
+
|
|
7
|
+
class XcpLogFileReader {
|
|
8
|
+
public:
|
|
9
|
+
|
|
10
|
+
explicit XcpLogFileReader(const std::string &file_name) {
|
|
11
|
+
if (!file_name.ends_with(detail::FILE_EXTENSION)) {
|
|
12
|
+
m_file_name = file_name + detail::FILE_EXTENSION;
|
|
13
|
+
} else {
|
|
14
|
+
m_file_name = file_name;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
m_mmap = new mio::mmap_source(m_file_name);
|
|
18
|
+
blob_t magic[detail::MAGIC_SIZE + 1];
|
|
19
|
+
|
|
20
|
+
read_bytes(0UL, detail::MAGIC_SIZE, magic);
|
|
21
|
+
if (memcmp(detail::MAGIC.c_str(), magic, detail::MAGIC_SIZE) != 0) {
|
|
22
|
+
throw std::runtime_error("Invalid file magic.");
|
|
23
|
+
}
|
|
24
|
+
m_offset = detail::MAGIC_SIZE;
|
|
25
|
+
|
|
26
|
+
read_bytes(m_offset, detail::FILE_HEADER_SIZE, reinterpret_cast<blob_t *>(&m_header));
|
|
27
|
+
// printf("Sizes: %u %u %.3f\n", m_header.size_uncompressed,
|
|
28
|
+
// m_header.size_compressed,
|
|
29
|
+
// float(m_header.size_uncompressed) / float(m_header.size_compressed));
|
|
30
|
+
if (m_header.hdr_size != detail::FILE_HEADER_SIZE + detail::MAGIC_SIZE) {
|
|
31
|
+
throw std::runtime_error("File header size does not match.");
|
|
32
|
+
}
|
|
33
|
+
if (detail::VERSION != m_header.version) {
|
|
34
|
+
throw std::runtime_error("File version mismatch.");
|
|
35
|
+
}
|
|
36
|
+
#if 0
|
|
37
|
+
if (m_header.num_containers < 1) {
|
|
38
|
+
throw std::runtime_error("At least one container required.");
|
|
39
|
+
}
|
|
40
|
+
#endif
|
|
41
|
+
m_offset += detail::FILE_HEADER_SIZE;
|
|
42
|
+
|
|
43
|
+
if ((m_header.options & XMRAW_HAS_METADATA) == XMRAW_HAS_METADATA) {
|
|
44
|
+
std::size_t metadata_length = 0;
|
|
45
|
+
std::size_t data_start = m_offset + sizeof(std::size_t);
|
|
46
|
+
|
|
47
|
+
read_bytes(m_offset, sizeof(std::size_t), reinterpret_cast<blob_t *>(&metadata_length));
|
|
48
|
+
|
|
49
|
+
std::copy(ptr(data_start), ptr(data_start + metadata_length), std::back_inserter(m_metadata));
|
|
50
|
+
m_offset += (metadata_length + sizeof(std::size_t));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
[[nodiscard]] FileHeaderType get_header() const noexcept {
|
|
55
|
+
return m_header;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[[nodiscard]] auto get_header_as_tuple() const noexcept -> HeaderTuple {
|
|
59
|
+
auto hdr = get_header();
|
|
60
|
+
|
|
61
|
+
return std::make_tuple(
|
|
62
|
+
hdr.version, hdr.options, hdr.num_containers, hdr.record_count, hdr.size_uncompressed, hdr.size_compressed,
|
|
63
|
+
(double)((std::uint64_t)(((double)hdr.size_uncompressed / (double)hdr.size_compressed * 100.0) + 0.5)) / 100.0
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
[[nodiscard]] auto get_metadata() const noexcept {
|
|
68
|
+
return m_metadata;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void reset() noexcept {
|
|
72
|
+
m_current_container = 0;
|
|
73
|
+
m_offset = file_header_size();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
std::optional<FrameVector> next_block() {
|
|
77
|
+
auto container = ContainerHeaderType{};
|
|
78
|
+
auto frame = frame_header_t{};
|
|
79
|
+
std::uint64_t boffs = 0;
|
|
80
|
+
auto result = FrameVector{};
|
|
81
|
+
payload_t payload;
|
|
82
|
+
|
|
83
|
+
if (m_current_container >= m_header.num_containers) {
|
|
84
|
+
return std::nullopt;
|
|
85
|
+
}
|
|
86
|
+
read_bytes(m_offset, detail::CONTAINER_SIZE, reinterpret_cast<blob_t *>(&container));
|
|
87
|
+
__ALIGN auto buffer = new blob_t[container.size_uncompressed];
|
|
88
|
+
m_offset += detail::CONTAINER_SIZE;
|
|
89
|
+
result.reserve(container.record_count);
|
|
90
|
+
const int uc_size = ::LZ4_decompress_safe(
|
|
91
|
+
reinterpret_cast<char const *>(ptr(m_offset)), reinterpret_cast<char *>(buffer), container.size_compressed,
|
|
92
|
+
container.size_uncompressed
|
|
93
|
+
);
|
|
94
|
+
if (uc_size < 0) {
|
|
95
|
+
throw std::runtime_error("LZ4 decompression failed.");
|
|
96
|
+
}
|
|
97
|
+
boffs = 0;
|
|
98
|
+
for (std::uint64_t idx = 0; idx < container.record_count; ++idx) {
|
|
99
|
+
_fcopy(reinterpret_cast<char *>(&frame), reinterpret_cast<char const *>(&(buffer[boffs])), sizeof(frame_header_t));
|
|
100
|
+
boffs += sizeof(frame_header_t);
|
|
101
|
+
result.emplace_back(
|
|
102
|
+
frame.category, frame.counter, frame.timestamp, frame.length, create_payload(frame.length, &buffer[boffs])
|
|
103
|
+
);
|
|
104
|
+
boffs += frame.length;
|
|
105
|
+
}
|
|
106
|
+
m_offset += container.size_compressed;
|
|
107
|
+
m_current_container += 1;
|
|
108
|
+
delete[] buffer;
|
|
109
|
+
|
|
110
|
+
return std::optional<FrameVector>{ result };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
~XcpLogFileReader() noexcept {
|
|
114
|
+
delete m_mmap;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
protected:
|
|
118
|
+
|
|
119
|
+
[[nodiscard]] blob_t const *ptr(std::uint64_t pos = 0) const {
|
|
120
|
+
return reinterpret_cast<blob_t const *>(m_mmap->data() + pos);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void read_bytes(std::uint64_t pos, std::uint64_t count, blob_t *buf) const {
|
|
124
|
+
auto addr = reinterpret_cast<char const *>(ptr(pos));
|
|
125
|
+
_fcopy(reinterpret_cast<char *>(buf), addr, count);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private:
|
|
129
|
+
|
|
130
|
+
std::string m_file_name;
|
|
131
|
+
std::uint64_t m_offset{ 0 };
|
|
132
|
+
std::uint64_t m_current_container{ 0 };
|
|
133
|
+
mio::mmap_source *m_mmap{ nullptr };
|
|
134
|
+
FileHeaderType m_header;
|
|
135
|
+
std::string m_metadata;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
#endif // RECORDER_READER_HPP
|
pyxcp/recorder/reco.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|