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
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
4
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/recorder.iml" filepath="$PROJECT_DIR$/.idea/recorder.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module classpath="CMake" type="CPP_MODULE" version="4">
3
+ <component name="SonarLintModuleSettings">
4
+ <option name="uniqueId" value="ce2142a1-5ccc-4675-8d23-c6ee960ba851" />
5
+ </component>
6
+ </module>
@@ -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
@@ -0,0 +1,7 @@
1
+
2
+ >
3
+ CMakeLists.txt,9\a\9a2aa4db38d3115ed60da621e012c0efc0172aae
4
+ 8
5
+ wrap.cpp,b\4\b49006702b459496a8e8c94ebe60947108361b91
6
+ <
7
+ rekorder.hpp,3\8\3808afc69ac1edb9d760000a2f137335b1b99728
@@ -0,0 +1,7 @@
1
+
2
+ >
3
+ CMakeLists.txt,9\a\9a2aa4db38d3115ed60da621e012c0efc0172aae
4
+ 8
5
+ wrap.cpp,b\4\b49006702b459496a8e8c94ebe60947108361b91
6
+ <
7
+ rekorder.hpp,3\8\3808afc69ac1edb9d760000a2f137335b1b99728
@@ -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>
@@ -1,98 +1,96 @@
1
- #!/usr/bin/env python
2
- """XCP Frame Recording Facility.
3
- """
4
-
5
- from dataclasses import dataclass
6
- from typing import Union
7
-
8
- from pyxcp.types import FrameCategory
9
-
10
-
11
- try:
12
- import pandas as pd
13
- except ImportError:
14
- HAS_PANDAS = False
15
- else:
16
- HAS_PANDAS = True
17
-
18
- from pyxcp.recorder.rekorder import DaqOnlinePolicy # noqa: F401
19
- from pyxcp.recorder.rekorder import DaqRecorderPolicy # noqa: F401
20
- from pyxcp.recorder.rekorder import Deserializer # noqa: F401
21
- from pyxcp.recorder.rekorder import MeasurementParameters # noqa: F401
22
- from pyxcp.recorder.rekorder import XcpLogFileDecoder as _XcpLogFileDecoder
23
- from pyxcp.recorder.rekorder import _PyXcpLogFileReader, _PyXcpLogFileWriter, data_types
24
-
25
-
26
- DATA_TYPES = data_types()
27
-
28
-
29
- @dataclass
30
- class XcpLogFileHeader:
31
- """ """
32
-
33
- version: int
34
- options: int
35
- num_containers: int
36
- record_count: int
37
- size_uncompressed: int
38
- size_compressed: int
39
- compression_ratio: float
40
-
41
-
42
- COUNTER_MAX = 0xFFFF
43
-
44
-
45
- class XcpLogFileReader:
46
- """ """
47
-
48
- def __init__(self, file_name):
49
- self._reader = _PyXcpLogFileReader(file_name)
50
-
51
- @property
52
- def header(self):
53
- return self._reader.get_header()
54
-
55
- def get_header(self):
56
- return XcpLogFileHeader(*self._reader.get_header_as_tuple())
57
-
58
- def get_metadata(self):
59
- return self._reader.get_metadata()
60
-
61
- def __iter__(self):
62
- while True:
63
- frames = self._reader.next_block()
64
- if frames is None:
65
- break
66
- for category, counter, timestamp, _, payload in frames:
67
- yield (FrameCategory(category), counter, timestamp, payload)
68
-
69
- def reset_iter(self):
70
- self._reader.reset()
71
-
72
- def as_dataframe(self):
73
- if HAS_PANDAS:
74
- df = pd.DataFrame((f for f in self), columns=["category", "counter", "timestamp", "payload"])
75
- df = df.set_index("timestamp")
76
- df.counter = df.counter.astype("uint16")
77
- df.category = df.category.map({v: k for k, v in FrameCategory.__members__.items()}).astype("category")
78
- return df
79
- else:
80
- raise NotImplementedError("method as_dataframe() requires 'pandas' package")
81
-
82
-
83
- class XcpLogFileWriter:
84
- """ """
85
-
86
- def __init__(self, file_name: str, prealloc=500, chunk_size=1):
87
- self._writer = _PyXcpLogFileWriter(file_name, prealloc, chunk_size)
88
- self._finalized = False
89
-
90
- def __del__(self):
91
- if not self._finalized:
92
- self.finalize()
93
-
94
- def add_frame(self, category: FrameCategory, counter: int, timestamp: float, payload: Union[bytes, bytearray]):
95
- self._writer.add_frame(category, counter % (COUNTER_MAX + 1), timestamp, len(payload), payload)
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
- try:
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}({', '.join(['timestamp0', 'timestamp1'] + [r.name for r in sc.arr])})"""
371
- f""" VALUES({', '.join(["?" for _ in range(len(sc.arr) + 2)])})"""
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
- // std::cout << "Metadata: " << m_metadata << std::endl;
51
- m_offset += (metadata_length + sizeof(std::size_t));
52
- }
53
- }
54
-
55
- [[nodiscard]] FileHeaderType get_header() const noexcept {
56
- return m_header;
57
- }
58
-
59
- [[nodiscard]] auto get_header_as_tuple() const noexcept -> HeaderTuple {
60
- auto hdr = get_header();
61
-
62
- return std::make_tuple(
63
- hdr.version, hdr.options, hdr.num_containers, hdr.record_count, hdr.size_uncompressed, hdr.size_compressed,
64
- (double)((std::uint64_t)(((double)hdr.size_uncompressed / (double)hdr.size_compressed * 100.0) + 0.5)) / 100.0
65
- );
66
- }
67
-
68
- [[nodiscard]] auto get_metadata() const noexcept {
69
- return m_metadata;
70
- }
71
-
72
- void reset() noexcept {
73
- m_current_container = 0;
74
- m_offset = file_header_size();
75
- }
76
-
77
- std::optional<FrameVector> next_block() {
78
- auto container = ContainerHeaderType{};
79
- auto frame = frame_header_t{};
80
- std::uint64_t boffs = 0;
81
- auto result = FrameVector{};
82
- payload_t payload;
83
-
84
- if (m_current_container >= m_header.num_containers) {
85
- return std::nullopt;
86
- }
87
- read_bytes(m_offset, detail::CONTAINER_SIZE, reinterpret_cast<blob_t *>(&container));
88
- __ALIGN auto buffer = new blob_t[container.size_uncompressed];
89
- m_offset += detail::CONTAINER_SIZE;
90
- result.reserve(container.record_count);
91
- const int uc_size = ::LZ4_decompress_safe(
92
- reinterpret_cast<char const *>(ptr(m_offset)), reinterpret_cast<char *>(buffer), container.size_compressed,
93
- container.size_uncompressed
94
- );
95
- if (uc_size < 0) {
96
- throw std::runtime_error("LZ4 decompression failed.");
97
- }
98
- boffs = 0;
99
- for (std::uint64_t idx = 0; idx < container.record_count; ++idx) {
100
- _fcopy(reinterpret_cast<char *>(&frame), reinterpret_cast<char const *>(&(buffer[boffs])), sizeof(frame_header_t));
101
- boffs += sizeof(frame_header_t);
102
- result.emplace_back(
103
- frame.category, frame.counter, frame.timestamp, frame.length, create_payload(frame.length, &buffer[boffs])
104
- );
105
- boffs += frame.length;
106
- }
107
- m_offset += container.size_compressed;
108
- m_current_container += 1;
109
- delete[] buffer;
110
-
111
- return std::optional<FrameVector>{ result };
112
- }
113
-
114
- ~XcpLogFileReader() noexcept {
115
- delete m_mmap;
116
- }
117
-
118
- protected:
119
-
120
- [[nodiscard]] blob_t const *ptr(std::uint64_t pos = 0) const {
121
- return reinterpret_cast<blob_t const *>(m_mmap->data() + pos);
122
- }
123
-
124
- void read_bytes(std::uint64_t pos, std::uint64_t count, blob_t *buf) const {
125
- auto addr = reinterpret_cast<char const *>(ptr(pos));
126
- _fcopy(reinterpret_cast<char *>(buf), addr, count);
127
- }
128
-
129
- private:
130
-
131
- std::string m_file_name;
132
- std::uint64_t m_offset{ 0 };
133
- std::uint64_t m_current_container{ 0 };
134
- mio::mmap_source *m_mmap{ nullptr };
135
- FileHeaderType m_header;
136
- std::string m_metadata;
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
@@ -12,6 +12,7 @@ See
12
12
 
13
13
  - ``_ for reading.
14
14
  """
15
+
15
16
  import enum
16
17
  import mmap
17
18
  import struct