pyxcp 0.25.4__cp313-cp313-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.
Files changed (157) hide show
  1. pyxcp/__init__.py +20 -0
  2. pyxcp/aml/EtasCANMonitoring.a2l +82 -0
  3. pyxcp/aml/EtasCANMonitoring.aml +67 -0
  4. pyxcp/aml/XCP_Common.aml +408 -0
  5. pyxcp/aml/XCPonCAN.aml +78 -0
  6. pyxcp/aml/XCPonEth.aml +33 -0
  7. pyxcp/aml/XCPonFlx.aml +113 -0
  8. pyxcp/aml/XCPonSxI.aml +66 -0
  9. pyxcp/aml/XCPonUSB.aml +106 -0
  10. pyxcp/aml/ifdata_CAN.a2l +20 -0
  11. pyxcp/aml/ifdata_Eth.a2l +11 -0
  12. pyxcp/aml/ifdata_Flx.a2l +94 -0
  13. pyxcp/aml/ifdata_SxI.a2l +13 -0
  14. pyxcp/aml/ifdata_USB.a2l +81 -0
  15. pyxcp/asam/__init__.py +0 -0
  16. pyxcp/asam/types.py +131 -0
  17. pyxcp/asamkeydll.c +116 -0
  18. pyxcp/asamkeydll.exe +0 -0
  19. pyxcp/asamkeydll.sh +2 -0
  20. pyxcp/checksum.py +732 -0
  21. pyxcp/cmdline.py +71 -0
  22. pyxcp/config/__init__.py +1257 -0
  23. pyxcp/config/legacy.py +120 -0
  24. pyxcp/constants.py +47 -0
  25. pyxcp/cpp_ext/__init__.py +0 -0
  26. pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
  27. pyxcp/cpp_ext/bin.hpp +105 -0
  28. pyxcp/cpp_ext/blockmem.hpp +58 -0
  29. pyxcp/cpp_ext/cpp_ext.cp310-win_amd64.pyd +0 -0
  30. pyxcp/cpp_ext/cpp_ext.cp311-win_amd64.pyd +0 -0
  31. pyxcp/cpp_ext/cpp_ext.cp312-win_amd64.pyd +0 -0
  32. pyxcp/cpp_ext/cpp_ext.cp313-win_amd64.pyd +0 -0
  33. pyxcp/cpp_ext/daqlist.hpp +374 -0
  34. pyxcp/cpp_ext/event.hpp +67 -0
  35. pyxcp/cpp_ext/extension_wrapper.cpp +131 -0
  36. pyxcp/cpp_ext/framing.hpp +360 -0
  37. pyxcp/cpp_ext/helper.hpp +280 -0
  38. pyxcp/cpp_ext/mcobject.hpp +248 -0
  39. pyxcp/cpp_ext/sxi_framing.hpp +332 -0
  40. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  41. pyxcp/daq_stim/__init__.py +291 -0
  42. pyxcp/daq_stim/optimize/__init__.py +67 -0
  43. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  44. pyxcp/daq_stim/scheduler.cpp +62 -0
  45. pyxcp/daq_stim/scheduler.hpp +75 -0
  46. pyxcp/daq_stim/stim.cp310-win_amd64.pyd +0 -0
  47. pyxcp/daq_stim/stim.cp311-win_amd64.pyd +0 -0
  48. pyxcp/daq_stim/stim.cp312-win_amd64.pyd +0 -0
  49. pyxcp/daq_stim/stim.cp313-win_amd64.pyd +0 -0
  50. pyxcp/daq_stim/stim.cpp +13 -0
  51. pyxcp/daq_stim/stim.hpp +604 -0
  52. pyxcp/daq_stim/stim_wrapper.cpp +50 -0
  53. pyxcp/dllif.py +100 -0
  54. pyxcp/errormatrix.py +878 -0
  55. pyxcp/examples/conf_can.toml +19 -0
  56. pyxcp/examples/conf_can_user.toml +16 -0
  57. pyxcp/examples/conf_can_vector.json +11 -0
  58. pyxcp/examples/conf_can_vector.toml +11 -0
  59. pyxcp/examples/conf_eth.toml +9 -0
  60. pyxcp/examples/conf_nixnet.json +20 -0
  61. pyxcp/examples/conf_socket_can.toml +12 -0
  62. pyxcp/examples/run_daq.py +165 -0
  63. pyxcp/examples/xcp_policy.py +60 -0
  64. pyxcp/examples/xcp_read_benchmark.py +38 -0
  65. pyxcp/examples/xcp_skel.py +48 -0
  66. pyxcp/examples/xcp_unlock.py +36 -0
  67. pyxcp/examples/xcp_user_supplied_driver.py +43 -0
  68. pyxcp/examples/xcphello.py +65 -0
  69. pyxcp/examples/xcphello_recorder.py +107 -0
  70. pyxcp/master/__init__.py +10 -0
  71. pyxcp/master/errorhandler.py +677 -0
  72. pyxcp/master/master.py +2641 -0
  73. pyxcp/py.typed +0 -0
  74. pyxcp/recorder/.idea/.gitignore +8 -0
  75. pyxcp/recorder/.idea/misc.xml +4 -0
  76. pyxcp/recorder/.idea/modules.xml +8 -0
  77. pyxcp/recorder/.idea/recorder.iml +6 -0
  78. pyxcp/recorder/.idea/sonarlint/issuestore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +7 -0
  79. pyxcp/recorder/.idea/sonarlint/issuestore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  80. pyxcp/recorder/.idea/sonarlint/issuestore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  81. pyxcp/recorder/.idea/sonarlint/issuestore/index.pb +7 -0
  82. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +0 -0
  83. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  84. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  85. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/index.pb +7 -0
  86. pyxcp/recorder/.idea/vcs.xml +10 -0
  87. pyxcp/recorder/__init__.py +96 -0
  88. pyxcp/recorder/build_clang.cmd +1 -0
  89. pyxcp/recorder/build_clang.sh +2 -0
  90. pyxcp/recorder/build_gcc.cmd +1 -0
  91. pyxcp/recorder/build_gcc.sh +2 -0
  92. pyxcp/recorder/build_gcc_arm.sh +2 -0
  93. pyxcp/recorder/converter/__init__.py +444 -0
  94. pyxcp/recorder/lz4.c +2829 -0
  95. pyxcp/recorder/lz4.h +879 -0
  96. pyxcp/recorder/lz4hc.c +2041 -0
  97. pyxcp/recorder/lz4hc.h +413 -0
  98. pyxcp/recorder/mio.hpp +1714 -0
  99. pyxcp/recorder/reader.hpp +138 -0
  100. pyxcp/recorder/reco.py +278 -0
  101. pyxcp/recorder/recorder.rst +0 -0
  102. pyxcp/recorder/rekorder.cp310-win_amd64.pyd +0 -0
  103. pyxcp/recorder/rekorder.cp311-win_amd64.pyd +0 -0
  104. pyxcp/recorder/rekorder.cp312-win_amd64.pyd +0 -0
  105. pyxcp/recorder/rekorder.cp313-win_amd64.pyd +0 -0
  106. pyxcp/recorder/rekorder.cpp +59 -0
  107. pyxcp/recorder/rekorder.hpp +274 -0
  108. pyxcp/recorder/setup.py +41 -0
  109. pyxcp/recorder/test_reko.py +34 -0
  110. pyxcp/recorder/unfolder.hpp +1354 -0
  111. pyxcp/recorder/wrap.cpp +184 -0
  112. pyxcp/recorder/writer.hpp +302 -0
  113. pyxcp/scripts/__init__.py +0 -0
  114. pyxcp/scripts/pyxcp_probe_can_drivers.py +20 -0
  115. pyxcp/scripts/xcp_examples.py +64 -0
  116. pyxcp/scripts/xcp_fetch_a2l.py +40 -0
  117. pyxcp/scripts/xcp_id_scanner.py +18 -0
  118. pyxcp/scripts/xcp_info.py +159 -0
  119. pyxcp/scripts/xcp_profile.py +26 -0
  120. pyxcp/scripts/xmraw_converter.py +31 -0
  121. pyxcp/stim/__init__.py +0 -0
  122. pyxcp/tests/test_asam_types.py +24 -0
  123. pyxcp/tests/test_binpacking.py +186 -0
  124. pyxcp/tests/test_can.py +1324 -0
  125. pyxcp/tests/test_checksum.py +95 -0
  126. pyxcp/tests/test_daq.py +193 -0
  127. pyxcp/tests/test_daq_opt.py +426 -0
  128. pyxcp/tests/test_frame_padding.py +156 -0
  129. pyxcp/tests/test_framing.py +262 -0
  130. pyxcp/tests/test_master.py +2116 -0
  131. pyxcp/tests/test_transport.py +177 -0
  132. pyxcp/tests/test_utils.py +30 -0
  133. pyxcp/timing.py +60 -0
  134. pyxcp/transport/__init__.py +13 -0
  135. pyxcp/transport/base.py +484 -0
  136. pyxcp/transport/base_transport.hpp +0 -0
  137. pyxcp/transport/can.py +660 -0
  138. pyxcp/transport/eth.py +254 -0
  139. pyxcp/transport/hdf5_policy.py +129 -0
  140. pyxcp/transport/sxi.py +209 -0
  141. pyxcp/transport/transport_ext.cp310-win_amd64.pyd +0 -0
  142. pyxcp/transport/transport_ext.cp311-win_amd64.pyd +0 -0
  143. pyxcp/transport/transport_ext.cp312-win_amd64.pyd +0 -0
  144. pyxcp/transport/transport_ext.cp313-win_amd64.pyd +0 -0
  145. pyxcp/transport/transport_ext.hpp +214 -0
  146. pyxcp/transport/transport_wrapper.cpp +249 -0
  147. pyxcp/transport/usb_transport.py +229 -0
  148. pyxcp/types.py +987 -0
  149. pyxcp/utils/__init__.py +127 -0
  150. pyxcp/utils/cli.py +78 -0
  151. pyxcp/vector/__init__.py +0 -0
  152. pyxcp/vector/map.py +82 -0
  153. pyxcp-0.25.4.dist-info/METADATA +341 -0
  154. pyxcp-0.25.4.dist-info/RECORD +157 -0
  155. pyxcp-0.25.4.dist-info/WHEEL +4 -0
  156. pyxcp-0.25.4.dist-info/entry_points.txt +9 -0
  157. pyxcp-0.25.4.dist-info/licenses/LICENSE +165 -0
@@ -0,0 +1,214 @@
1
+
2
+ #include <cstdint>
3
+
4
+ #include <bit>
5
+ #include <optional>
6
+ #include <iostream>
7
+ #include <map>
8
+ #include <set>
9
+ #include <tuple>
10
+ #include <vector>
11
+
12
+ #include "rekorder.hpp"
13
+
14
+ const std::map<FrameCategory, std::string> FrameCategoryName {
15
+ {FrameCategory::META, "METADATA"},
16
+ {FrameCategory::CMD, "CMD"},
17
+ {FrameCategory::RES, "RESPONSE"},
18
+ {FrameCategory::ERR, "ERROR"},
19
+ {FrameCategory::EV, "EVENT"},
20
+ {FrameCategory::SERV, "SERV"},
21
+ {FrameCategory::DAQ, "DAQ"},
22
+ {FrameCategory::STIM, "STIM"},
23
+ };
24
+
25
+ /*
26
+ Base class for all frame acquisition policies.
27
+
28
+ Parameters
29
+ ---------
30
+ filter_out: set or None
31
+ A set of frame types to filter out.
32
+ If None, all frame types are accepted for further processing.
33
+
34
+ Example: (FrameType.REQUEST, FrameType.RESPONSE, FrameType.EVENT, FrameType.SERV)
35
+ ==> care only about DAQ frames.
36
+ */
37
+ class FrameAcquisitionPolicy {
38
+ public:
39
+
40
+ using payload_t = std::string;
41
+ using filter_t = std::set<FrameCategory>;
42
+ using frame_t = std::tuple<std::uint32_t, std::uint64_t, const payload_t>;
43
+
44
+
45
+ FrameAcquisitionPolicy(const std::optional<filter_t>& filter_out) {
46
+ if (!filter_out) {
47
+ m_filter_out = filter_t{};
48
+ } else {
49
+ m_filter_out = filter_out;
50
+ }
51
+ }
52
+
53
+ std::optional<filter_t> get_filtered_out() const {
54
+ return m_filter_out;
55
+ }
56
+
57
+ FrameAcquisitionPolicy(const FrameAcquisitionPolicy&) = delete;
58
+ FrameAcquisitionPolicy(FrameAcquisitionPolicy&&) = delete;
59
+ FrameAcquisitionPolicy() = delete;
60
+
61
+ virtual ~FrameAcquisitionPolicy() {}
62
+
63
+ virtual void feed(FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload) = 0;
64
+
65
+ virtual void finalize() = 0;
66
+
67
+ protected:
68
+
69
+ std::optional<filter_t> m_filter_out;
70
+
71
+ };
72
+
73
+
74
+ /*
75
+ No operation / do nothing policy.
76
+ */
77
+ class NoOpPolicy : public FrameAcquisitionPolicy {
78
+ public:
79
+
80
+ NoOpPolicy(const std::optional<filter_t>& filter_out) : FrameAcquisitionPolicy(filter_out) {}
81
+
82
+ void feed(FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload) override {}
83
+
84
+ void finalize() override {}
85
+ };
86
+
87
+
88
+ /*
89
+ Dequeue based frame acquisition policy.
90
+
91
+ Deprecated: Use only for compatibility reasons.
92
+ */
93
+ class LegacyFrameAcquisitionPolicy : public FrameAcquisitionPolicy {
94
+ public:
95
+
96
+ using deque_t = TsQueue<frame_t>;
97
+
98
+ LegacyFrameAcquisitionPolicy(const std::optional<filter_t>& filter_out) : FrameAcquisitionPolicy(filter_out) {
99
+
100
+ m_queue_map[FrameCategory::CMD] = std::make_shared<deque_t>();
101
+ m_queue_map[FrameCategory::RES] = std::make_shared<deque_t>();
102
+ m_queue_map[FrameCategory::EV] = std::make_shared<deque_t>();
103
+ m_queue_map[FrameCategory::SERV] = std::make_shared<deque_t>();
104
+ m_queue_map[FrameCategory::DAQ] = std::make_shared<deque_t>();
105
+ m_queue_map[FrameCategory::META] = std::make_shared<deque_t>();
106
+ m_queue_map[FrameCategory::ERR] = std::make_shared<deque_t>();
107
+ m_queue_map[FrameCategory::STIM] = std::make_shared<deque_t>();
108
+
109
+ }
110
+
111
+ LegacyFrameAcquisitionPolicy() = delete;
112
+ LegacyFrameAcquisitionPolicy(const LegacyFrameAcquisitionPolicy&) = delete;
113
+ LegacyFrameAcquisitionPolicy(LegacyFrameAcquisitionPolicy&&) = delete;
114
+
115
+ void feed(FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload) override {
116
+ if (m_filter_out && (!(*m_filter_out).contains(frame_category))) {
117
+ m_queue_map[frame_category]->put({counter, timestamp, payload});
118
+ }
119
+ }
120
+
121
+ std::shared_ptr<deque_t> get_req_queue() {
122
+ return m_queue_map.at(FrameCategory::CMD);
123
+ }
124
+
125
+ std::shared_ptr<deque_t> get_res_queue() {
126
+ return m_queue_map.at(FrameCategory::RES);
127
+ }
128
+
129
+ std::shared_ptr<deque_t> get_daq_queue() {
130
+ return m_queue_map.at(FrameCategory::DAQ);
131
+ }
132
+
133
+ std::shared_ptr<deque_t> get_ev_queue() {
134
+ return m_queue_map.at(FrameCategory::EV);
135
+ }
136
+
137
+ std::shared_ptr<deque_t> get_serv_queue() {
138
+ return m_queue_map.at(FrameCategory::SERV);
139
+ }
140
+
141
+ std::shared_ptr<deque_t> get_meta_queue() {
142
+ return m_queue_map.at(FrameCategory::META);
143
+ }
144
+
145
+ std::shared_ptr<deque_t> get_error_queue() {
146
+ return m_queue_map.at(FrameCategory::ERR);
147
+ }
148
+
149
+ std::shared_ptr<deque_t> get_stim_queue() {
150
+ return m_queue_map.at(FrameCategory::STIM);
151
+ }
152
+
153
+ void finalize() override {}
154
+
155
+ private:
156
+
157
+ std::map<FrameCategory, std::shared_ptr<deque_t>> m_queue_map{};
158
+ };
159
+
160
+ std::string hex_bytes(std::string_view payload) {
161
+ std::stringstream ss;
162
+
163
+ for (auto ch: payload) {
164
+ ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(static_cast<unsigned char>(ch)) << " ";
165
+ }
166
+ return ss.str();
167
+ }
168
+
169
+ /*
170
+ Frame acquisition policy that prints frames to stdout.
171
+ */
172
+ class StdoutPolicy : public FrameAcquisitionPolicy {
173
+ public:
174
+ StdoutPolicy(const std::optional<filter_t>& filter_out) : FrameAcquisitionPolicy(filter_out) {}
175
+
176
+ StdoutPolicy() = delete;
177
+ StdoutPolicy(const StdoutPolicy&) = delete;
178
+ StdoutPolicy(StdoutPolicy&&) = delete;
179
+
180
+ void feed(FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload) override {
181
+ if (m_filter_out && (!(*m_filter_out).contains(frame_category))) {
182
+ std::cout << std::left << std::setw(8) << FrameCategoryName.at(frame_category) << " " << std::right <<
183
+ std::setw(6) << counter << " " << std::setw(8) << timestamp << " [ " << std::left << hex_bytes(payload) << "]" << std::endl;
184
+ }
185
+ }
186
+
187
+ void finalize() override { }
188
+
189
+ };
190
+
191
+ class FrameRecorderPolicy : public FrameAcquisitionPolicy {
192
+ public:
193
+
194
+ FrameRecorderPolicy(const std::string& file_name, const std::optional<filter_t>& filter_out, uint32_t prealloc = 10UL, uint32_t chunk_size = 1) : FrameAcquisitionPolicy(filter_out) {
195
+ m_writer = std::make_unique<XcpLogFileWriter>(file_name, prealloc, chunk_size);
196
+ }
197
+
198
+ FrameRecorderPolicy() = delete;
199
+ FrameRecorderPolicy(const FrameRecorderPolicy&) = delete;
200
+ FrameRecorderPolicy(FrameRecorderPolicy&&) = delete;
201
+
202
+ void feed(FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload) override {
203
+ if (m_filter_out && (!(*m_filter_out).contains(frame_category))) {
204
+ m_writer->add_frame(static_cast<std::uint8_t>(frame_category), counter, timestamp, payload.size(), std::bit_cast<const char *>(payload.data()));
205
+ }
206
+ }
207
+
208
+ void finalize() override {
209
+ m_writer->finalize();
210
+ }
211
+
212
+ private:
213
+ std::unique_ptr<XcpLogFileWriter> m_writer;
214
+ };
@@ -0,0 +1,249 @@
1
+
2
+
3
+ #include <pybind11/chrono.h>
4
+ #include <pybind11/functional.h>
5
+ #include <pybind11/numpy.h>
6
+ #include <pybind11/pybind11.h>
7
+ #include <pybind11/stl.h>
8
+
9
+ #include <cstdint>
10
+
11
+ #include "transport_ext.hpp"
12
+ #include "framing.hpp"
13
+ #include "sxi_framing.hpp"
14
+
15
+
16
+ namespace py = pybind11;
17
+ using namespace pybind11::literals;
18
+
19
+ using SxiFrLBCN = SxiReceiver< SxiHeaderFormat::LenByte, SxiChecksumType::None>;
20
+ using SxiFrLBC8 = SxiReceiver< SxiHeaderFormat::LenByte, SxiChecksumType::Sum8>;
21
+ using SxiFrLBC16 = SxiReceiver< SxiHeaderFormat::LenByte, SxiChecksumType::Sum16>;
22
+
23
+ using SxiFrLCBCN = SxiReceiver< SxiHeaderFormat::LenCtrByte, SxiChecksumType::None>;
24
+ using SxiFrLCBC8 = SxiReceiver< SxiHeaderFormat::LenCtrByte, SxiChecksumType::Sum8>;
25
+ using SxiFrLCBC16 = SxiReceiver< SxiHeaderFormat::LenCtrByte, SxiChecksumType::Sum16>;
26
+
27
+ using SxiFrLFBCN = SxiReceiver< SxiHeaderFormat::LenFillByte, SxiChecksumType::None>;
28
+ using SxiFrLFBC8 = SxiReceiver< SxiHeaderFormat::LenFillByte, SxiChecksumType::Sum8>;
29
+ using SxiFrLFBC16 = SxiReceiver< SxiHeaderFormat::LenFillByte, SxiChecksumType::Sum16>;
30
+
31
+ using SxiFrLWCN = SxiReceiver< SxiHeaderFormat::LenWord, SxiChecksumType::None>;
32
+ using SxiFrLWC8 = SxiReceiver< SxiHeaderFormat::LenWord, SxiChecksumType::Sum8>;
33
+ using SxiFrLWC16 = SxiReceiver< SxiHeaderFormat::LenWord, SxiChecksumType::Sum16>;
34
+
35
+ using SxiFrLCWCN = SxiReceiver< SxiHeaderFormat::LenCtrWord, SxiChecksumType::None>;
36
+ using SxiFrLCWC8 = SxiReceiver< SxiHeaderFormat::LenCtrWord, SxiChecksumType::Sum8>;
37
+ using SxiFrLCWC16 = SxiReceiver< SxiHeaderFormat::LenCtrWord, SxiChecksumType::Sum16>;
38
+
39
+ using SxiFrLFWCN = SxiReceiver< SxiHeaderFormat::LenFillWord, SxiChecksumType::None>;
40
+ using SxiFrLFWC8 = SxiReceiver< SxiHeaderFormat::LenFillWord, SxiChecksumType::Sum8>;
41
+ using SxiFrLFWC16 = SxiReceiver< SxiHeaderFormat::LenFillWord, SxiChecksumType::Sum16>;
42
+
43
+
44
+ class PyFrameAcquisitionPolicy : public FrameAcquisitionPolicy {
45
+ public:
46
+
47
+ using FrameAcquisitionPolicy::FrameAcquisitionPolicy;
48
+
49
+ void feed(
50
+ FrameCategory frame_category, std::uint32_t counter, std::uint64_t timestamp, const payload_t& payload
51
+ ) override {
52
+ PYBIND11_OVERRIDE_PURE(void, FrameAcquisitionPolicy, feed, frame_category, counter, timestamp, payload);
53
+ }
54
+
55
+
56
+ void finalize() override {
57
+ PYBIND11_OVERRIDE_PURE(void, FrameAcquisitionPolicy, finalize);
58
+ }
59
+ };
60
+
61
+
62
+ PYBIND11_MODULE(transport_ext, m) {
63
+ m.doc() = "pyXCP transport-layer base classes.";
64
+
65
+ py::enum_<FrameCategory>(m, "FrameCategory")
66
+ .value("METADATA", FrameCategory::META)
67
+ .value("CMD", FrameCategory::CMD)
68
+ .value("RESPONSE", FrameCategory::RES)
69
+ .value("ERROR", FrameCategory::ERR)
70
+ .value("EVENT", FrameCategory::EV)
71
+ .value("SERV", FrameCategory::SERV)
72
+ .value("DAQ", FrameCategory::DAQ)
73
+ .value("STIM", FrameCategory::STIM)
74
+ ;
75
+
76
+ py::class_<FrameAcquisitionPolicy, PyFrameAcquisitionPolicy>(m, "FrameAcquisitionPolicy", py::dynamic_attr())
77
+ .def(py::init<const std::optional<FrameAcquisitionPolicy::filter_t>&>(), py::arg("filtered_out") = std::nullopt)
78
+ .def("feed", &FrameAcquisitionPolicy::feed)
79
+ .def("finalize", &FrameAcquisitionPolicy::finalize)
80
+ .def_property_readonly("filtered_out", &FrameAcquisitionPolicy::get_filtered_out)
81
+ ;
82
+
83
+ py::class_<LegacyFrameAcquisitionPolicy>(m, "LegacyFrameAcquisitionPolicy", py::dynamic_attr())
84
+ .def(py::init<const std::optional<FrameAcquisitionPolicy::filter_t>&>(), py::arg("filtered_out") = std::nullopt)
85
+ .def("feed", &FrameAcquisitionPolicy::feed)
86
+ .def("finalize", &FrameAcquisitionPolicy::finalize)
87
+ .def_property_readonly("reqQueue", &LegacyFrameAcquisitionPolicy::get_req_queue)
88
+ .def_property_readonly("resQueue", &LegacyFrameAcquisitionPolicy::get_res_queue)
89
+ .def_property_readonly("daqQueue", &LegacyFrameAcquisitionPolicy::get_daq_queue)
90
+ .def_property_readonly("evQueue", &LegacyFrameAcquisitionPolicy::get_ev_queue)
91
+ .def_property_readonly("servQueue", &LegacyFrameAcquisitionPolicy::get_serv_queue)
92
+ .def_property_readonly("metaQueue", &LegacyFrameAcquisitionPolicy::get_meta_queue)
93
+ .def_property_readonly("errorQueue", &LegacyFrameAcquisitionPolicy::get_error_queue)
94
+ .def_property_readonly("stimQueue", &LegacyFrameAcquisitionPolicy::get_stim_queue)
95
+ ;
96
+
97
+ py::class_<NoOpPolicy>(m, "NoOpPolicy", py::dynamic_attr())
98
+ .def(py::init<const std::optional<FrameAcquisitionPolicy::filter_t>&>(), py::arg("filtered_out") = std::nullopt)
99
+ .def("feed", &FrameAcquisitionPolicy::feed)
100
+ .def("finalize", &FrameAcquisitionPolicy::finalize)
101
+ ;
102
+
103
+ py::class_<StdoutPolicy>(m, "StdoutPolicy", py::dynamic_attr())
104
+ .def(py::init<const std::optional<FrameAcquisitionPolicy::filter_t>&>(), py::arg("filtered_out") = std::nullopt)
105
+ .def("feed", &FrameAcquisitionPolicy::feed)
106
+ .def("finalize", &FrameAcquisitionPolicy::finalize)
107
+ ;
108
+
109
+ py::class_<FrameRecorderPolicy>(m, "FrameRecorderPolicy", py::dynamic_attr())
110
+ .def(py::init<const std::string&, const std::optional<FrameAcquisitionPolicy::filter_t>&, uint32_t, uint32_t>(),
111
+ py::arg("file_name"), py::arg("filtered_out") = std::nullopt, py::arg("prealloc") = 10UL, py::arg("chunk_size") = 1)
112
+ .def("feed", &FrameAcquisitionPolicy::feed)
113
+ .def("finalize", &FrameAcquisitionPolicy::finalize)
114
+ ;
115
+ // Transport layer type enum
116
+ py::enum_<XcpTransportLayerType>(m, "XcpTransportLayerType")
117
+ .value("CAN", XcpTransportLayerType::CAN)
118
+ .value("ETH", XcpTransportLayerType::ETH)
119
+ .value("SXI", XcpTransportLayerType::SXI)
120
+ .value("USB", XcpTransportLayerType::USB);
121
+
122
+ // XCP checksum type enum
123
+ py::enum_<ChecksumType>(m, "ChecksumType")
124
+ .value("NO_CHECKSUM", ChecksumType::NO_CHECKSUM)
125
+ .value("BYTE_CHECKSUM", ChecksumType::BYTE_CHECKSUM)
126
+ .value("WORD_CHECKSUM", ChecksumType::WORD_CHECKSUM);
127
+
128
+ // XCP framing configuration and helper
129
+ py::class_<XcpFramingConfig>(m, "XcpFramingConfig")
130
+ .def(py::init<>())
131
+ .def(py::init<XcpTransportLayerType, std::uint8_t, std::uint8_t, std::uint8_t, bool, ChecksumType>(),
132
+ "transport_layer_type"_a, "header_len"_a, "header_ctr"_a, "header_fill"_a, "tail_fill"_a = false, "tail_cs"_a = ChecksumType::NO_CHECKSUM)
133
+ .def_property_readonly("transport_layer_type", [](const XcpFramingConfig &self) { return self.transport_layer_type; })
134
+ .def_property_readonly("header_len", [](const XcpFramingConfig &self) { return self.header_len; })
135
+ .def_property_readonly("header_ctr", [](const XcpFramingConfig &self) { return self.header_ctr; })
136
+ .def_property_readonly("header_fill", [](const XcpFramingConfig &self) { return self.header_fill; })
137
+ .def_property_readonly("tail_fill", [](const XcpFramingConfig &self) { return self.tail_fill; })
138
+ .def_property_readonly("tail_cs", [](const XcpFramingConfig &self) { return self.tail_cs; });
139
+
140
+ py::class_<XcpFraming>(m, "XcpFraming")
141
+ .def(py::init<const XcpFramingConfig&>())
142
+ .def("prepare_request", [](XcpFraming &self, std::uint32_t cmd, py::bytes data) {
143
+ std::string s = data;
144
+ std::vector<uint8_t> data_vec(s.begin(), s.end());
145
+ return self.prepare_request(cmd, data_vec);
146
+ }, "cmd"_a, "data"_a)
147
+ .def("prepare_request", [](XcpFraming &self, std::uint32_t cmd, py::args data) {
148
+ std::vector<uint8_t> data_vec;
149
+ for (auto item : data) {
150
+ data_vec.push_back(py::cast<uint8_t>(item));
151
+ }
152
+ return self.prepare_request(cmd, data_vec);
153
+ }, "cmd"_a)
154
+ .def("unpack_header", &XcpFraming::unpack_header, py::arg("data"), py::arg("initial_offset") = 0)
155
+ .def("verify_checksum", &XcpFraming::verify_checksum)
156
+ .def_property("counter_send", &XcpFraming::get_counter_send, &XcpFraming::set_counter_send)
157
+ .def_property_readonly("header_size", &XcpFraming::get_header_size);
158
+
159
+ py::class_<SxiFrLBCN>(m, "SxiFrLBCN")
160
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
161
+ .def("feed_bytes", &SxiFrLBCN::feed_bytes, py::arg("data"))
162
+ ;
163
+
164
+ py::class_<SxiFrLBC8>(m, "SxiFrLBC8")
165
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
166
+ .def("feed_bytes", &SxiFrLBC8::feed_bytes, py::arg("data"))
167
+ ;
168
+
169
+ py::class_<SxiFrLBC16>(m, "SxiFrLBC16")
170
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
171
+ .def("feed_bytes", &SxiFrLBC16::feed_bytes, py::arg("data"))
172
+ ;
173
+
174
+ py::class_<SxiFrLCBCN>(m, "SxiFrLCBCN")
175
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
176
+ .def("feed_bytes", &SxiFrLCBCN::feed_bytes, py::arg("data"))
177
+ ;
178
+
179
+ py::class_<SxiFrLCBC8>(m, "SxiFrLCBC8")
180
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
181
+ .def("feed_bytes", &SxiFrLCBC8::feed_bytes, py::arg("data"))
182
+ ;
183
+
184
+ py::class_<SxiFrLCBC16>(m, "SxiFrLCBC16")
185
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
186
+ .def("feed_bytes", &SxiFrLCBC16::feed_bytes, py::arg("data"))
187
+ ;
188
+
189
+ py::class_<SxiFrLFBCN>(m, "SxiFrLFBCN")
190
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
191
+ .def("feed_bytes", &SxiFrLFBCN::feed_bytes, py::arg("data"))
192
+ ;
193
+
194
+ py::class_<SxiFrLFBC8>(m, "SxiFrLFBC8")
195
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
196
+ .def("feed_bytes", &SxiFrLFBC8::feed_bytes, py::arg("data"))
197
+ ;
198
+
199
+ py::class_<SxiFrLFBC16>(m, "SxiFrLFBC16")
200
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
201
+ .def("feed_bytes", &SxiFrLFBC16::feed_bytes, py::arg("data"))
202
+ ;
203
+
204
+ py::class_<SxiFrLWCN>(m, "SxiFrLWCN")
205
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
206
+ .def("feed_bytes", &SxiFrLWCN::feed_bytes, py::arg("data"))
207
+ ;
208
+
209
+ py::class_<SxiFrLWC8>(m, "SxiFrLWC8")
210
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
211
+ .def("feed_bytes", &SxiFrLWC8::feed_bytes, py::arg("data"))
212
+ ;
213
+
214
+ py::class_<SxiFrLWC16>(m, "SxiFrLWC16")
215
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
216
+ .def("feed_bytes", &SxiFrLWC16::feed_bytes, py::arg("data"))
217
+ ;
218
+
219
+ py::class_<SxiFrLCWCN>(m, "SxiFrLCWCN")
220
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
221
+ .def("feed_bytes", &SxiFrLCWCN::feed_bytes, py::arg("data"))
222
+ ;
223
+
224
+ py::class_<SxiFrLCWC8>(m, "SxiFrLCWC8")
225
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
226
+ .def("feed_bytes", &SxiFrLCWC8::feed_bytes, py::arg("data"))
227
+ ;
228
+
229
+ py::class_<SxiFrLCWC16>(m, "SxiFrLCWC16")
230
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
231
+ .def("feed_bytes", &SxiFrLCWC16::feed_bytes, py::arg("data"))
232
+ ;
233
+
234
+ py::class_<SxiFrLFWCN>(m, "SxiFrLFWCN")
235
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
236
+ .def("feed_bytes", &SxiFrLFWCN::feed_bytes, py::arg("data"))
237
+ ;
238
+
239
+ py::class_<SxiFrLFWC8>(m, "SxiFrLFWC8")
240
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
241
+ .def("feed_bytes", &SxiFrLFWC8::feed_bytes, py::arg("data"))
242
+ ;
243
+
244
+ py::class_<SxiFrLFWC16>(m, "SxiFrLFWC16")
245
+ .def(py::init<std::function<void(const std::vector<uint8_t>&, uint16_t, uint16_t)>>(), py::arg("dispatch_handler"))
246
+ .def("feed_bytes", &SxiFrLFWC16::feed_bytes, py::arg("data"))
247
+ ;
248
+
249
+ }
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env python
2
+
3
+ import threading
4
+ from array import array
5
+ from collections import deque
6
+ from typing import Optional
7
+
8
+ import usb.backend.libusb0 as libusb0
9
+ import usb.backend.libusb1 as libusb1
10
+ import usb.backend.openusb as openusb
11
+ import usb.core
12
+ import usb.util
13
+ from usb.core import USBError, USBTimeoutError
14
+
15
+ from pyxcp.transport.base import (
16
+ BaseTransport,
17
+ ChecksumType,
18
+ XcpFramingConfig,
19
+ XcpTransportLayerType,
20
+ parse_header_format,
21
+ )
22
+ from pyxcp.utils import short_sleep
23
+
24
+
25
+ RECV_SIZE = 16384
26
+ FIVE_MS = 5_000_000 # Five milliseconds in nanoseconds.
27
+
28
+
29
+ class Usb(BaseTransport):
30
+ """"""
31
+
32
+ def __init__(self, config=None, policy=None, transport_layer_interface: Optional[usb.core.Device] = None):
33
+ self.load_config(config)
34
+ header_len, header_ctr, header_fill = parse_header_format(self.config.header_format)
35
+ framing_config = XcpFramingConfig(
36
+ transport_layer_type=XcpTransportLayerType.USB,
37
+ header_len=header_len,
38
+ header_ctr=header_ctr,
39
+ header_fill=header_fill,
40
+ tail_fill=False,
41
+ tail_cs=ChecksumType.NO_CHECKSUM,
42
+ )
43
+ self.serial_number: str = self.config.serial_number
44
+ self.vendor_id: int = self.config.vendor_id
45
+ self.product_id: int = self.config.product_id
46
+ self.configuration_number: int = self.config.configuration_number
47
+ self.interface_number: int = self.config.interface_number
48
+ self.library: str = self.config.library
49
+ self.library = self.config.get("library")
50
+ self.device = None
51
+ super().__init__(config, framing_config, policy, transport_layer_interface)
52
+
53
+ ## IN-EP (RES/ERR, DAQ, and EV/SERV) Parameters.
54
+ self.in_ep_number: int = self.config.in_ep_number
55
+ self.in_ep_transfer_type = self.config.in_ep_transfer_type
56
+ self.in_ep_max_packet_size: int = self.config.in_ep_max_packet_size
57
+ self.in_ep_polling_interval: int = self.config.in_ep_polling_interval
58
+ self.in_ep_message_packing = self.config.in_ep_message_packing
59
+ self.in_ep_alignment = self.config.in_ep_alignment
60
+ self.in_ep_recommended_host_bufsize: int = self.config.in_ep_recommended_host_bufsize
61
+
62
+ ## OUT-EP (CMD and STIM) Parameters.
63
+ self.out_ep_number: int = self.config.out_ep_number
64
+
65
+ self.device: Optional[usb.core.Device] = None
66
+ self.status = 0
67
+
68
+ self._packet_listener = threading.Thread(
69
+ target=self._packet_listen,
70
+ args=(),
71
+ kwargs={},
72
+ daemon=True,
73
+ )
74
+ self._packets = deque()
75
+
76
+ def connect(self):
77
+ if self.library:
78
+ for backend_provider in (libusb1, libusb0, openusb):
79
+ backend = backend_provider.get_backend(find_library=lambda x: self.library)
80
+ if backend:
81
+ break
82
+ else:
83
+ backend = None
84
+
85
+ if self.vendor_id and self.product_id:
86
+ kwargs = {
87
+ "find_all": True,
88
+ "idVendor": self.vendor_id,
89
+ "idProduct": self.product_id,
90
+ "backend": backend,
91
+ }
92
+ else:
93
+ kwargs = {
94
+ "find_all": True,
95
+ "backend": backend,
96
+ }
97
+
98
+ for device in usb.core.find(**kwargs):
99
+ try:
100
+ if device.serial_number.strip().strip("\0").lower() == self.serial_number.lower():
101
+ self.device = device
102
+ break
103
+ except (USBError, USBTimeoutError):
104
+ continue
105
+ else:
106
+ raise Exception(f"XCPonUSB - device with serial {self.serial_number!r} not found")
107
+
108
+ current_configuration = self.device.get_active_configuration()
109
+ if current_configuration.bConfigurationValue != self.configuration_number:
110
+ self.device.set_configuration(self.configuration_number)
111
+ cfg = self.device.get_active_configuration()
112
+
113
+ interface = cfg[(self.interface_number, 0)]
114
+
115
+ self.out_ep = interface[self.out_ep_number]
116
+ self.in_ep = interface[self.in_ep_number]
117
+
118
+ self.start_listener()
119
+ self.status = 1 # connected
120
+
121
+ def start_listener(self):
122
+ super().start_listener()
123
+ if self._packet_listener.is_alive():
124
+ self._packet_listener.join(timeout=2.0)
125
+ self._packet_listener = threading.Thread(target=self._packet_listen, daemon=True)
126
+ self._packet_listener.start()
127
+
128
+ def close(self):
129
+ """Close the transport-layer connection and event-loop."""
130
+ self.finish_listener()
131
+ try:
132
+ if self.listener.is_alive():
133
+ self.listener.join(timeout=2.0)
134
+ except Exception:
135
+ pass
136
+ try:
137
+ if self._packet_listener.is_alive():
138
+ self._packet_listener.join(timeout=2.0)
139
+ except Exception:
140
+ pass
141
+ self.close_connection()
142
+
143
+ def _packet_listen(self):
144
+ close_event_set = self.closeEvent.is_set
145
+ _packets = self._packets
146
+ read = self.in_ep.read
147
+ buffer = array("B", bytes(RECV_SIZE))
148
+ buffer_view = memoryview(buffer)
149
+ while True:
150
+ try:
151
+ if close_event_set():
152
+ return
153
+ try:
154
+ recv_timestamp = self.timestamp.value
155
+ read_count = read(buffer, 100) # 100ms timeout
156
+ if read_count != RECV_SIZE:
157
+ _packets.append((buffer_view[:read_count].tobytes(), recv_timestamp))
158
+ else:
159
+ _packets.append((buffer.tobytes(), recv_timestamp))
160
+ except (USBError, USBTimeoutError):
161
+ # print(format_exc())
162
+ short_sleep()
163
+ continue
164
+ except BaseException: # noqa: B036
165
+ # Note: catch-all only permitted if the intention is re-raising.
166
+ self.status = 0 # disconnected
167
+ break
168
+
169
+ def send(self, frame):
170
+ self.pre_send_timestamp = self.timestamp.value
171
+ try:
172
+ self.out_ep.write(frame)
173
+ except (USBError, USBTimeoutError):
174
+ # sometimes usb.core.USBError: [Errno 5] Input/Output Error is raised
175
+ # even though the command is send and a reply is received from the device.
176
+ # Ignore this here since a Timeout error will be raised anyway if
177
+ # the device does not respond
178
+ pass
179
+ self.post_send_timestamp = self.timestamp.value
180
+
181
+ def listen(self):
182
+ popleft = self._packets.popleft
183
+ process_response = self.process_response
184
+ close_event_set = self.closeEvent.is_set
185
+ _packets = self._packets
186
+ length: Optional[int] = None
187
+ counter: int = 0
188
+ data: bytearray = bytearray(b"")
189
+ last_sleep: int = self.timestamp.value
190
+
191
+ while True:
192
+ if close_event_set():
193
+ return
194
+ count: int = len(_packets)
195
+ if not count:
196
+ short_sleep()
197
+ last_sleep = self.timestamp.value
198
+ continue
199
+ for _ in range(count):
200
+ bts, timestamp = popleft()
201
+ data += bts
202
+ current_size: int = len(data)
203
+ current_position: int = 0
204
+ while True:
205
+ if self.timestamp.value - last_sleep >= FIVE_MS:
206
+ short_sleep()
207
+ last_sleep = self.timestamp.value
208
+ if length is None:
209
+ if current_size >= self.framing.header_size:
210
+ length, counter = self.framing.unpack_header(bytes(data), initial_offset=current_position)
211
+ current_position += self.framing.header_size
212
+ current_size -= self.framing.header_size
213
+ else:
214
+ data = data[current_position:]
215
+ break
216
+ else:
217
+ if current_size >= length:
218
+ response = data[current_position : current_position + length]
219
+ process_response(response, length, counter, timestamp)
220
+ current_size -= length
221
+ current_position += length
222
+ length = None
223
+ else:
224
+ data = data[current_position:]
225
+ break
226
+
227
+ def close_connection(self):
228
+ if self.device is not None:
229
+ usb.util.dispose_resources(self.device)