pyxcp 0.25.2__cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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 +20 -0
- pyxcp/aml/EtasCANMonitoring.a2l +82 -0
- pyxcp/aml/EtasCANMonitoring.aml +67 -0
- pyxcp/aml/XCP_Common.aml +408 -0
- pyxcp/aml/XCPonCAN.aml +78 -0
- pyxcp/aml/XCPonEth.aml +33 -0
- pyxcp/aml/XCPonFlx.aml +113 -0
- pyxcp/aml/XCPonSxI.aml +66 -0
- pyxcp/aml/XCPonUSB.aml +106 -0
- pyxcp/aml/ifdata_CAN.a2l +20 -0
- pyxcp/aml/ifdata_Eth.a2l +11 -0
- pyxcp/aml/ifdata_Flx.a2l +94 -0
- pyxcp/aml/ifdata_SxI.a2l +13 -0
- pyxcp/aml/ifdata_USB.a2l +81 -0
- pyxcp/asam/__init__.py +0 -0
- pyxcp/asam/types.py +131 -0
- pyxcp/asamkeydll +0 -0
- pyxcp/asamkeydll.c +116 -0
- pyxcp/asamkeydll.sh +2 -0
- pyxcp/checksum.py +732 -0
- pyxcp/cmdline.py +83 -0
- pyxcp/config/__init__.py +1257 -0
- pyxcp/config/legacy.py +120 -0
- pyxcp/constants.py +47 -0
- pyxcp/cpp_ext/__init__.py +0 -0
- pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
- pyxcp/cpp_ext/bin.hpp +105 -0
- pyxcp/cpp_ext/blockmem.hpp +58 -0
- pyxcp/cpp_ext/cpp_ext.cpython-310-x86_64-linux-gnu.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-311-x86_64-linux-gnu.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-312-x86_64-linux-gnu.so +0 -0
- pyxcp/cpp_ext/cpp_ext.cpython-313-x86_64-linux-gnu.so +0 -0
- pyxcp/cpp_ext/daqlist.hpp +374 -0
- pyxcp/cpp_ext/event.hpp +67 -0
- pyxcp/cpp_ext/extension_wrapper.cpp +131 -0
- pyxcp/cpp_ext/framing.hpp +360 -0
- pyxcp/cpp_ext/helper.hpp +280 -0
- pyxcp/cpp_ext/mcobject.hpp +248 -0
- pyxcp/cpp_ext/sxi_framing.hpp +332 -0
- pyxcp/cpp_ext/tsqueue.hpp +46 -0
- pyxcp/daq_stim/__init__.py +306 -0
- pyxcp/daq_stim/optimize/__init__.py +67 -0
- pyxcp/daq_stim/optimize/binpacking.py +41 -0
- pyxcp/daq_stim/scheduler.cpp +62 -0
- pyxcp/daq_stim/scheduler.hpp +75 -0
- pyxcp/daq_stim/stim.cpp +13 -0
- pyxcp/daq_stim/stim.cpython-310-x86_64-linux-gnu.so +0 -0
- pyxcp/daq_stim/stim.cpython-311-x86_64-linux-gnu.so +0 -0
- pyxcp/daq_stim/stim.cpython-312-x86_64-linux-gnu.so +0 -0
- pyxcp/daq_stim/stim.cpython-313-x86_64-linux-gnu.so +0 -0
- pyxcp/daq_stim/stim.hpp +604 -0
- pyxcp/daq_stim/stim_wrapper.cpp +50 -0
- pyxcp/dllif.py +100 -0
- pyxcp/errormatrix.py +878 -0
- pyxcp/examples/conf_can.toml +19 -0
- pyxcp/examples/conf_can_user.toml +16 -0
- pyxcp/examples/conf_can_vector.json +11 -0
- pyxcp/examples/conf_can_vector.toml +11 -0
- pyxcp/examples/conf_eth.toml +9 -0
- pyxcp/examples/conf_nixnet.json +20 -0
- pyxcp/examples/conf_socket_can.toml +12 -0
- pyxcp/examples/run_daq.py +165 -0
- pyxcp/examples/xcp_policy.py +60 -0
- pyxcp/examples/xcp_read_benchmark.py +38 -0
- pyxcp/examples/xcp_skel.py +48 -0
- pyxcp/examples/xcp_unlock.py +38 -0
- pyxcp/examples/xcp_user_supplied_driver.py +43 -0
- pyxcp/examples/xcphello.py +79 -0
- pyxcp/examples/xcphello_recorder.py +107 -0
- pyxcp/master/__init__.py +10 -0
- pyxcp/master/errorhandler.py +677 -0
- pyxcp/master/master.py +2645 -0
- pyxcp/py.typed +0 -0
- 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 -0
- pyxcp/recorder/build_clang.cmd +1 -0
- pyxcp/recorder/build_clang.sh +2 -0
- pyxcp/recorder/build_gcc.cmd +1 -0
- pyxcp/recorder/build_gcc.sh +2 -0
- pyxcp/recorder/build_gcc_arm.sh +2 -0
- pyxcp/recorder/converter/__init__.py +445 -0
- pyxcp/recorder/lz4.c +2829 -0
- pyxcp/recorder/lz4.h +879 -0
- pyxcp/recorder/lz4hc.c +2041 -0
- pyxcp/recorder/lz4hc.h +413 -0
- pyxcp/recorder/mio.hpp +1714 -0
- pyxcp/recorder/reader.hpp +138 -0
- pyxcp/recorder/reco.py +278 -0
- pyxcp/recorder/recorder.rst +0 -0
- pyxcp/recorder/rekorder.cpp +59 -0
- pyxcp/recorder/rekorder.cpython-310-x86_64-linux-gnu.so +0 -0
- pyxcp/recorder/rekorder.cpython-311-x86_64-linux-gnu.so +0 -0
- pyxcp/recorder/rekorder.cpython-312-x86_64-linux-gnu.so +0 -0
- pyxcp/recorder/rekorder.cpython-313-x86_64-linux-gnu.so +0 -0
- pyxcp/recorder/rekorder.hpp +274 -0
- pyxcp/recorder/setup.py +41 -0
- pyxcp/recorder/test_reko.py +34 -0
- pyxcp/recorder/unfolder.hpp +1354 -0
- pyxcp/recorder/wrap.cpp +184 -0
- pyxcp/recorder/writer.hpp +302 -0
- pyxcp/scripts/__init__.py +0 -0
- pyxcp/scripts/pyxcp_probe_can_drivers.py +20 -0
- pyxcp/scripts/xcp_examples.py +64 -0
- pyxcp/scripts/xcp_fetch_a2l.py +40 -0
- pyxcp/scripts/xcp_id_scanner.py +18 -0
- pyxcp/scripts/xcp_info.py +144 -0
- pyxcp/scripts/xcp_profile.py +26 -0
- pyxcp/scripts/xmraw_converter.py +31 -0
- pyxcp/stim/__init__.py +0 -0
- pyxcp/tests/test_asam_types.py +24 -0
- pyxcp/tests/test_binpacking.py +186 -0
- pyxcp/tests/test_can.py +1324 -0
- pyxcp/tests/test_checksum.py +95 -0
- pyxcp/tests/test_daq.py +193 -0
- pyxcp/tests/test_daq_opt.py +426 -0
- pyxcp/tests/test_frame_padding.py +156 -0
- pyxcp/tests/test_framing.py +262 -0
- pyxcp/tests/test_master.py +2116 -0
- pyxcp/tests/test_transport.py +177 -0
- pyxcp/tests/test_utils.py +30 -0
- pyxcp/timing.py +60 -0
- pyxcp/transport/__init__.py +13 -0
- pyxcp/transport/base.py +484 -0
- pyxcp/transport/base_transport.hpp +0 -0
- pyxcp/transport/can.py +660 -0
- pyxcp/transport/eth.py +254 -0
- pyxcp/transport/sxi.py +209 -0
- pyxcp/transport/transport_ext.hpp +214 -0
- pyxcp/transport/transport_wrapper.cpp +249 -0
- pyxcp/transport/usb_transport.py +229 -0
- pyxcp/types.py +987 -0
- pyxcp/utils.py +127 -0
- pyxcp/vector/__init__.py +0 -0
- pyxcp/vector/map.py +82 -0
- pyxcp-0.25.2.dist-info/METADATA +341 -0
- pyxcp-0.25.2.dist-info/RECORD +151 -0
- pyxcp-0.25.2.dist-info/WHEEL +6 -0
- pyxcp-0.25.2.dist-info/entry_points.txt +9 -0
- pyxcp-0.25.2.dist-info/licenses/LICENSE +165 -0
|
@@ -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)
|