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,360 @@
|
|
|
1
|
+
|
|
2
|
+
#if !defined(__FRAMING_HPP)
|
|
3
|
+
#define __FRAMING_HPP
|
|
4
|
+
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
|
|
7
|
+
#include <atomic>
|
|
8
|
+
#include <bit>
|
|
9
|
+
#include <optional>
|
|
10
|
+
#include <iostream>
|
|
11
|
+
#include <map>
|
|
12
|
+
#include <mutex>
|
|
13
|
+
#include <optional>
|
|
14
|
+
#include <set>
|
|
15
|
+
#include <thread>
|
|
16
|
+
#include <tuple>
|
|
17
|
+
#include <variant>
|
|
18
|
+
#include <vector>
|
|
19
|
+
#include <cstring>
|
|
20
|
+
|
|
21
|
+
namespace py = pybind11;
|
|
22
|
+
|
|
23
|
+
using FrameType = py::bytes;
|
|
24
|
+
using CommandType = std::variant<std::monostate, std::uint8_t, std::uint16_t, std::uint32_t>;
|
|
25
|
+
|
|
26
|
+
std::uint8_t find_msb(std::uint32_t val) {
|
|
27
|
+
std::uint8_t position = 0;
|
|
28
|
+
|
|
29
|
+
if (val == 0) {
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
while ((val >>= 1)) {
|
|
33
|
+
++position;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return position + 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
std::uint8_t byte_count(std::uint32_t val) {
|
|
40
|
+
std::uint8_t count = 1;
|
|
41
|
+
|
|
42
|
+
auto high_bit = find_msb(val);
|
|
43
|
+
if (high_bit > 24) {
|
|
44
|
+
count = 4;
|
|
45
|
+
} else if (high_bit > 16) {
|
|
46
|
+
count = 3;
|
|
47
|
+
} else if (high_bit > 8) {
|
|
48
|
+
count = 2;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return count;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
std::vector<std::uint8_t> serialize_cmd_value(std::uint32_t value) {
|
|
55
|
+
std::vector<std::uint8_t> result;
|
|
56
|
+
|
|
57
|
+
auto bc = byte_count(value);
|
|
58
|
+
result.reserve(bc);
|
|
59
|
+
|
|
60
|
+
switch (bc) {
|
|
61
|
+
case 4:
|
|
62
|
+
result.push_back(static_cast<std::uint8_t>(static_cast<std::uint32_t>(((value & 0xff000000UL)) >> 24)));
|
|
63
|
+
[[fallthrough]];
|
|
64
|
+
case 3:
|
|
65
|
+
result.push_back(static_cast<std::uint8_t>(static_cast<std::uint32_t>(((value & 0xff0000UL)) >> 16)));
|
|
66
|
+
[[fallthrough]];
|
|
67
|
+
case 2:
|
|
68
|
+
result.push_back(static_cast<std::uint8_t>(static_cast<std::uint16_t>(((value & 0xff00UL)) >> 8)));
|
|
69
|
+
[[fallthrough]];
|
|
70
|
+
case 1:
|
|
71
|
+
result.push_back(static_cast<std::uint8_t>(value & 0xffUL));
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
std::vector<std::uint8_t> serialize_word_le(std::uint16_t value) {
|
|
79
|
+
std::vector<std::uint8_t> result;
|
|
80
|
+
result.reserve(2);
|
|
81
|
+
|
|
82
|
+
result.push_back(static_cast<std::uint8_t>(value & 0xffUL));
|
|
83
|
+
result.push_back(static_cast<std::uint8_t>(static_cast<std::uint16_t>(((value & 0xff00UL)) >> 8)));
|
|
84
|
+
result.resize(2);
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
std::string_view bytes_as_string_view(const py::bytes& data) {
|
|
89
|
+
// Zero-copy view into Python bytes; lifetime is tied to 'data' which
|
|
90
|
+
// outlives this function call.
|
|
91
|
+
char* buf = nullptr;
|
|
92
|
+
Py_ssize_t len = 0;
|
|
93
|
+
// PyBytes_AsStringAndSize returns 0 on success.
|
|
94
|
+
if (PyBytes_AsStringAndSize(data.ptr(), &buf, &len) != 0 || buf == nullptr || len < 0) {
|
|
95
|
+
// Fallback: empty view on error (should be rare)
|
|
96
|
+
return std::string_view{};
|
|
97
|
+
}
|
|
98
|
+
return std::string_view(buf, static_cast<std::size_t>(len));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
enum class ChecksumType : std::uint8_t {
|
|
102
|
+
NO_CHECKSUM = 0,
|
|
103
|
+
BYTE_CHECKSUM = 1,
|
|
104
|
+
WORD_CHECKSUM = 2
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
enum class XcpTransportLayerType : std::uint8_t {
|
|
108
|
+
CAN,
|
|
109
|
+
ETH,
|
|
110
|
+
SXI,
|
|
111
|
+
USB
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
struct XcpFramingConfig {
|
|
115
|
+
XcpTransportLayerType transport_layer_type;
|
|
116
|
+
std::uint8_t header_len;
|
|
117
|
+
std::uint8_t header_ctr;
|
|
118
|
+
std::uint8_t header_fill;
|
|
119
|
+
|
|
120
|
+
bool tail_fill;
|
|
121
|
+
ChecksumType tail_cs;
|
|
122
|
+
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
class XcpFraming {
|
|
126
|
+
public:
|
|
127
|
+
|
|
128
|
+
XcpFraming(const XcpFramingConfig& framing_type) : m_counter_send(0),
|
|
129
|
+
m_framing_type(framing_type) {
|
|
130
|
+
|
|
131
|
+
m_send_buffer = new std::uint8_t[0xff + 8];
|
|
132
|
+
reset_send_buffer_pointer();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
XcpFraming() = delete;
|
|
136
|
+
XcpFraming(const XcpFraming&) = delete;
|
|
137
|
+
XcpFraming(XcpFraming&&) = delete;
|
|
138
|
+
|
|
139
|
+
FrameType prepare_request(std::uint32_t cmd, py::args data) {
|
|
140
|
+
|
|
141
|
+
std::vector<std::uint8_t> command_bytes{};
|
|
142
|
+
std::uint8_t frame_header_size{0};
|
|
143
|
+
std::uint8_t frame_tail_size{0};
|
|
144
|
+
|
|
145
|
+
reset_send_buffer_pointer();
|
|
146
|
+
|
|
147
|
+
command_bytes = serialize_cmd_value(cmd);
|
|
148
|
+
|
|
149
|
+
auto xcp_packet_size = data.size() + command_bytes.size();
|
|
150
|
+
|
|
151
|
+
if (m_framing_type.header_len > 0) {
|
|
152
|
+
frame_header_size += m_framing_type.header_len;
|
|
153
|
+
if (m_framing_type.header_len == 1) {
|
|
154
|
+
set_send_buffer(static_cast<std::uint8_t>(xcp_packet_size & 0xff));
|
|
155
|
+
} else {
|
|
156
|
+
auto packet_size_bytes = serialize_word_le(xcp_packet_size);
|
|
157
|
+
set_send_buffer(packet_size_bytes);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (m_framing_type.header_ctr > 0) {
|
|
161
|
+
frame_header_size += m_framing_type.header_ctr;
|
|
162
|
+
if (m_framing_type.header_ctr == 1) {
|
|
163
|
+
set_send_buffer(static_cast<std::uint8_t>(m_counter_send & 0xff));
|
|
164
|
+
} else {
|
|
165
|
+
auto counter_bytes = serialize_word_le(m_counter_send);
|
|
166
|
+
set_send_buffer(counter_bytes);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (m_framing_type.header_fill > 0) {
|
|
170
|
+
fill_send_buffer(m_framing_type.header_fill);
|
|
171
|
+
frame_header_size += m_framing_type.header_fill;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
set_send_buffer(command_bytes);
|
|
175
|
+
set_send_buffer(data);
|
|
176
|
+
|
|
177
|
+
if (m_framing_type.transport_layer_type == XcpTransportLayerType::SXI) {
|
|
178
|
+
if (m_framing_type.tail_fill == true) {
|
|
179
|
+
// Align to a word boundary if word checksum is used
|
|
180
|
+
if (m_framing_type.tail_cs == ChecksumType::WORD_CHECKSUM && (current_send_buffer_pointer() % 2 != 0)) {
|
|
181
|
+
fill_send_buffer(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (m_framing_type.tail_cs != ChecksumType::NO_CHECKSUM) {
|
|
186
|
+
if (m_framing_type.tail_cs == ChecksumType::BYTE_CHECKSUM) {
|
|
187
|
+
auto cs = checksum_byte(0, current_send_buffer_pointer());
|
|
188
|
+
set_send_buffer(cs);
|
|
189
|
+
frame_tail_size += 1;
|
|
190
|
+
}
|
|
191
|
+
else if (m_framing_type.tail_cs == ChecksumType::WORD_CHECKSUM) {
|
|
192
|
+
// Align to a word boundary before calculating word checksum
|
|
193
|
+
if (current_send_buffer_pointer() % 2 != 0) {
|
|
194
|
+
fill_send_buffer(1);
|
|
195
|
+
}
|
|
196
|
+
auto cs = checksum_word(0, current_send_buffer_pointer());
|
|
197
|
+
auto cs_bytes = serialize_word_le(cs);
|
|
198
|
+
set_send_buffer(cs_bytes);
|
|
199
|
+
frame_tail_size += 2;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
m_counter_send++;
|
|
205
|
+
py::bytes result(reinterpret_cast<const char*>(m_send_buffer), current_send_buffer_pointer());
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
FrameType prepare_request(std::uint32_t cmd, const std::vector<std::uint8_t>& data_vec) {
|
|
210
|
+
py::tuple data_tuple(data_vec.size());
|
|
211
|
+
for (size_t i = 0; i < data_vec.size(); ++i) {
|
|
212
|
+
data_tuple[i] = py::int_(data_vec[i]);
|
|
213
|
+
}
|
|
214
|
+
return prepare_request(cmd, data_tuple);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
std::optional<std::tuple<std::uint16_t, std::uint16_t>> unpack_header(const py::bytes& data, std::uint16_t initial_offset=0) const noexcept {
|
|
218
|
+
auto data_view = bytes_as_string_view(data);
|
|
219
|
+
if (std::size(data_view) >= (get_header_size() + initial_offset)) {
|
|
220
|
+
auto offset = initial_offset;
|
|
221
|
+
std::uint16_t length = 0U;
|
|
222
|
+
std::uint16_t counter = 0U;
|
|
223
|
+
|
|
224
|
+
// Read length field starting at current offset (if present)
|
|
225
|
+
if (m_framing_type.header_len > 0) {
|
|
226
|
+
if (m_framing_type.header_len == 1) {
|
|
227
|
+
length = static_cast<std::uint16_t>(static_cast<std::uint8_t>(data_view[offset]));
|
|
228
|
+
} else {
|
|
229
|
+
auto b0 = static_cast<std::uint8_t>(data_view[offset]);
|
|
230
|
+
auto b1 = static_cast<std::uint8_t>(data_view[offset + 1]);
|
|
231
|
+
length = static_cast<std::uint16_t>(static_cast<std::uint16_t>(b0) | (static_cast<std::uint16_t>(b1) << 8));
|
|
232
|
+
}
|
|
233
|
+
offset += m_framing_type.header_len;
|
|
234
|
+
}
|
|
235
|
+
// Read counter field starting after length (if present)
|
|
236
|
+
if (m_framing_type.header_ctr > 0) {
|
|
237
|
+
if (m_framing_type.header_ctr == 1) {
|
|
238
|
+
counter = static_cast<std::uint16_t>(static_cast<std::uint8_t>(data_view[offset]));
|
|
239
|
+
} else {
|
|
240
|
+
auto c0 = static_cast<std::uint8_t>(data_view[offset]);
|
|
241
|
+
auto c1 = static_cast<std::uint8_t>(data_view[offset + 1]);
|
|
242
|
+
counter = static_cast<std::uint16_t>(static_cast<std::uint16_t>(c0) | (static_cast<std::uint16_t>(c1) << 8));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return std::make_tuple(length, counter);
|
|
246
|
+
}
|
|
247
|
+
return std::nullopt;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
bool verify_checksum(const py::bytes& data) const noexcept {
|
|
251
|
+
if (m_framing_type.transport_layer_type != XcpTransportLayerType::SXI || m_framing_type.tail_cs == ChecksumType::NO_CHECKSUM) {
|
|
252
|
+
return true; // No checksum verification needed
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
auto data_view = bytes_as_string_view(data);
|
|
256
|
+
auto data_size = std::size(data_view);
|
|
257
|
+
|
|
258
|
+
if (m_framing_type.tail_cs == ChecksumType::BYTE_CHECKSUM) {
|
|
259
|
+
if (data_size < 1) return false;
|
|
260
|
+
std::uint8_t received_cs = static_cast<std::uint8_t>(data_view[data_size - 1]);
|
|
261
|
+
std::uint8_t calculated_cs = 0;
|
|
262
|
+
for (size_t i = 0; i < data_size - 1; ++i) {
|
|
263
|
+
calculated_cs += static_cast<std::uint8_t>(data_view[i]);
|
|
264
|
+
}
|
|
265
|
+
return received_cs == calculated_cs;
|
|
266
|
+
}
|
|
267
|
+
else if (m_framing_type.tail_cs == ChecksumType::WORD_CHECKSUM) {
|
|
268
|
+
if (data_size < 2 || data_size % 2 != 0) return false; // Must have even length for word checksum
|
|
269
|
+
|
|
270
|
+
std::uint16_t received_cs = static_cast<std::uint16_t>(
|
|
271
|
+
static_cast<std::uint8_t>(data_view[data_size - 2]) |
|
|
272
|
+
(static_cast<std::uint16_t>(static_cast<std::uint8_t>(data_view[data_size - 1])) << 8)
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
std::uint16_t calculated_cs = 0;
|
|
276
|
+
for (size_t i = 0; i < data_size - 2; i += 2) {
|
|
277
|
+
calculated_cs += static_cast<std::uint16_t>(
|
|
278
|
+
static_cast<std::uint8_t>(data_view[i]) |
|
|
279
|
+
(static_cast<std::uint16_t>(static_cast<std::uint8_t>(data_view[i + 1])) << 8)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return received_cs == calculated_cs;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return true; // Should not be reached if NO_CHECKSUM is handled
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
std::uint16_t get_header_size() const noexcept {
|
|
289
|
+
return m_framing_type.header_len + m_framing_type.header_ctr + m_framing_type.header_fill;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
std::uint16_t get_counter_send() const noexcept {
|
|
293
|
+
return m_counter_send;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
void set_counter_send(std::uint16_t counter) noexcept {
|
|
297
|
+
m_counter_send = counter;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
private:
|
|
302
|
+
void set_send_buffer(std::uint8_t value) noexcept {
|
|
303
|
+
m_send_buffer[m_send_buffer_offset] = value;
|
|
304
|
+
m_send_buffer_offset++;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
void set_send_buffer(const std::vector<std::uint8_t>& values) noexcept {
|
|
308
|
+
if (!values.empty()) {
|
|
309
|
+
std::memcpy(m_send_buffer + m_send_buffer_offset, values.data(), values.size());
|
|
310
|
+
m_send_buffer_offset += static_cast<std::uint16_t>(values.size());
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
void set_send_buffer(const py::args& values) noexcept {
|
|
315
|
+
for (auto idx=0; idx < values.size(); ++idx) {
|
|
316
|
+
m_send_buffer[m_send_buffer_offset] = values[idx].cast<std::uint8_t>();
|
|
317
|
+
m_send_buffer_offset++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
void fill_send_buffer(uint16_t n) noexcept {
|
|
322
|
+
for (auto idx=0; idx < n; ++idx) {
|
|
323
|
+
m_send_buffer[m_send_buffer_offset] = 0;
|
|
324
|
+
m_send_buffer_offset++;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
void reset_send_buffer_pointer() noexcept {
|
|
329
|
+
m_send_buffer_offset = 0UL;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
std::uint16_t current_send_buffer_pointer() const noexcept {
|
|
333
|
+
return m_send_buffer_offset;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
std::uint8_t checksum_byte(std::uint16_t begin, std::uint16_t end) const noexcept {
|
|
337
|
+
uint8_t cs = 0;
|
|
338
|
+
for (auto idx = begin; idx < end; ++idx) {
|
|
339
|
+
cs += m_send_buffer[idx];
|
|
340
|
+
}
|
|
341
|
+
return cs;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
std::uint16_t checksum_word(std::uint16_t begin, std::uint16_t end) const noexcept {
|
|
345
|
+
std::uint16_t cs = 0UL;
|
|
346
|
+
|
|
347
|
+
for (auto idx = begin; idx < end; idx+=2) {
|
|
348
|
+
cs += static_cast<std::uint16_t>(m_send_buffer[idx] | (m_send_buffer[idx + 1] << 8));
|
|
349
|
+
}
|
|
350
|
+
return cs;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private:
|
|
354
|
+
std::uint16_t m_counter_send;
|
|
355
|
+
XcpFramingConfig m_framing_type;
|
|
356
|
+
std::uint8_t * m_send_buffer = nullptr;
|
|
357
|
+
std::uint16_t m_send_buffer_offset = 0UL;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
#endif // __FRAMING_HPP
|
pyxcp/cpp_ext/helper.hpp
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
|
|
2
|
+
#if !defined(__HELPER_HPP)
|
|
3
|
+
#define __HELPER_HPP
|
|
4
|
+
|
|
5
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
6
|
+
|
|
7
|
+
#else
|
|
8
|
+
#include <sys/time.h>
|
|
9
|
+
#include <time.h>
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
#include <bit>
|
|
13
|
+
#include <chrono>
|
|
14
|
+
#include <iostream>
|
|
15
|
+
#include <map>
|
|
16
|
+
#include <utility>
|
|
17
|
+
#include <variant>
|
|
18
|
+
|
|
19
|
+
#if __has_include(<version>)
|
|
20
|
+
#include <version> // Needed for feature testing.
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
#ifdef __has_include
|
|
24
|
+
#if __has_include(<stdfloat>)
|
|
25
|
+
#include <stdfloat>
|
|
26
|
+
#endif
|
|
27
|
+
#if defined(__STDCPP_BFLOAT16_T__)
|
|
28
|
+
#define HAS_BFLOAT16 (1)
|
|
29
|
+
#else
|
|
30
|
+
#define HAS_BFLOAT16 (0)
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#if defined(__STDCPP_FLOAT16_T__)
|
|
34
|
+
#define HAS_FLOAT16 (1)
|
|
35
|
+
#else
|
|
36
|
+
#define HAS_FLOAT16 (0)
|
|
37
|
+
#endif
|
|
38
|
+
#else
|
|
39
|
+
#define HAS_FLOAT16 (0)
|
|
40
|
+
#define HAS_BFLOAT16 (0)
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
constexpr std::endian target_byteorder() {
|
|
44
|
+
return std::endian::native;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
template<typename... Args>
|
|
48
|
+
constexpr void DBG_PRINTN(Args &&...args) noexcept {
|
|
49
|
+
((std::cout << std::forward<Args>(args) << " "), ...);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// NOTE: C++23 has std::byteswap()
|
|
53
|
+
constexpr auto _bswap(std::uint64_t v) noexcept {
|
|
54
|
+
return ((v & UINT64_C(0x0000'0000'0000'00FF)) << 56) | ((v & UINT64_C(0x0000'0000'0000'FF00)) << 40) |
|
|
55
|
+
((v & UINT64_C(0x0000'0000'00FF'0000)) << 24) | ((v & UINT64_C(0x0000'0000'FF00'0000)) << 8) |
|
|
56
|
+
((v & UINT64_C(0x0000'00FF'0000'0000)) >> 8) | ((v & UINT64_C(0x0000'FF00'0000'0000)) >> 24) |
|
|
57
|
+
((v & UINT64_C(0x00FF'0000'0000'0000)) >> 40) | ((v & UINT64_C(0xFF00'0000'0000'0000)) >> 56);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
constexpr auto _bswap(std::uint32_t v) noexcept {
|
|
61
|
+
return ((v & UINT32_C(0x0000'00FF)) << 24) | ((v & UINT32_C(0x0000'FF00)) << 8) | ((v & UINT32_C(0x00FF'0000)) >> 8) |
|
|
62
|
+
((v & UINT32_C(0xFF00'0000)) >> 24);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
constexpr auto _bswap(std::uint16_t v) noexcept {
|
|
66
|
+
return ((v & UINT16_C(0x00FF)) << 8) | ((v & UINT16_C(0xFF00)) >> 8);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
template<typename T>
|
|
70
|
+
inline std::string to_binary(const T &value) {
|
|
71
|
+
std::string result;
|
|
72
|
+
|
|
73
|
+
auto ptr = reinterpret_cast<const std::string::value_type *>(&value);
|
|
74
|
+
for (std::size_t idx = 0; idx < sizeof(T); ++idx) {
|
|
75
|
+
auto ch = ptr[idx];
|
|
76
|
+
result.push_back(ch);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
template<>
|
|
82
|
+
inline std::string to_binary<std::string>(const std::string &value) {
|
|
83
|
+
std::string result;
|
|
84
|
+
|
|
85
|
+
auto ptr = reinterpret_cast<const std::string::value_type *>(value.c_str());
|
|
86
|
+
const std::size_t length = std::size(value);
|
|
87
|
+
|
|
88
|
+
// We are using Pascal strings as serialization format.
|
|
89
|
+
auto len_bin = to_binary(length);
|
|
90
|
+
std::copy(len_bin.begin(), len_bin.end(), std::back_inserter(result));
|
|
91
|
+
for (std::size_t idx = 0; idx < length; ++idx) {
|
|
92
|
+
auto ch = ptr[idx];
|
|
93
|
+
result.push_back(ch);
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
inline auto bool_to_string(bool value) {
|
|
99
|
+
return (value == true) ? "True" : "False";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
inline auto byte_order_to_string(int value) {
|
|
103
|
+
switch (value) {
|
|
104
|
+
case 0:
|
|
105
|
+
return "INTEL";
|
|
106
|
+
case 1:
|
|
107
|
+
return "MOTOROLA";
|
|
108
|
+
default:
|
|
109
|
+
return "<UNKNOWN>";
|
|
110
|
+
}
|
|
111
|
+
return "<UNKNOWN>";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
template<typename K, typename V>
|
|
115
|
+
static std::map<V, K> reverse_map(const std::map<K, V> &m) {
|
|
116
|
+
std::map<V, K> result;
|
|
117
|
+
for (const auto &[k, v] : m) {
|
|
118
|
+
result[v] = k;
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
enum class TimestampType : std::uint8_t {
|
|
124
|
+
ABSOLUTE_TS,
|
|
125
|
+
RELATIVE_TS
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
class TimestampInfo {
|
|
129
|
+
public:
|
|
130
|
+
|
|
131
|
+
TimestampInfo(const TimestampInfo &) = default;
|
|
132
|
+
TimestampInfo(TimestampInfo &&) = default;
|
|
133
|
+
TimestampInfo &operator=(const TimestampInfo &) = default;
|
|
134
|
+
TimestampInfo &operator=(TimestampInfo &&) = default;
|
|
135
|
+
virtual ~TimestampInfo() {}
|
|
136
|
+
|
|
137
|
+
TimestampInfo() : m_timestamp_ns(0), m_timezone{}, m_utc_offset(0), m_dst_offset(0) {
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
TimestampInfo(std::uint64_t timestamp_ns, const std::string &timezone, std::int16_t utc_offset, std::int16_t dst_offset) :
|
|
141
|
+
m_timestamp_ns(timestamp_ns), m_timezone(timezone), m_utc_offset(utc_offset), m_dst_offset(dst_offset) {
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
explicit TimestampInfo(std::uint64_t timestamp_ns) : m_timestamp_ns(timestamp_ns) {
|
|
145
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
146
|
+
m_timezone = std::chrono::current_zone()->name();
|
|
147
|
+
#else
|
|
148
|
+
tzset();
|
|
149
|
+
m_timezone = tzname[0];
|
|
150
|
+
|
|
151
|
+
#endif // _WIN32 || _WIN64
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
std::string get_timezone() const noexcept {
|
|
155
|
+
return m_timezone;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
void set_timezone(const std::string &value) noexcept {
|
|
159
|
+
m_timezone = value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
std::uint64_t get_timestamp_ns() const noexcept {
|
|
163
|
+
return m_timestamp_ns;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
void set_utc_offset(std::int16_t value) noexcept {
|
|
167
|
+
m_utc_offset = value;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
std::int16_t get_utc_offset() const noexcept {
|
|
171
|
+
return m_utc_offset;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
void set_dst_offset(std::int16_t value) noexcept {
|
|
175
|
+
m_dst_offset = value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
std::int16_t get_dst_offset() const noexcept {
|
|
179
|
+
return m_dst_offset;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
std::string to_string() const noexcept {
|
|
183
|
+
std::stringstream ss;
|
|
184
|
+
ss << "TimestamInfo(\n";
|
|
185
|
+
ss << "\ttimestamp_ns=" << m_timestamp_ns << ",\n";
|
|
186
|
+
ss << "\ttimezone=\"" << m_timezone << "\",\n";
|
|
187
|
+
ss << "\tutc_offset=" << m_utc_offset << ",\n";
|
|
188
|
+
ss << "\tdst_offset=" << m_dst_offset << "\n";
|
|
189
|
+
ss << ");";
|
|
190
|
+
return ss.str();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
virtual void dummy() const noexcept {};
|
|
194
|
+
|
|
195
|
+
private:
|
|
196
|
+
|
|
197
|
+
std::uint64_t m_timestamp_ns;
|
|
198
|
+
std::string m_timezone{};
|
|
199
|
+
std::int16_t m_utc_offset{ 0 };
|
|
200
|
+
std::int16_t m_dst_offset{ 0 };
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
class Timestamp {
|
|
204
|
+
public:
|
|
205
|
+
|
|
206
|
+
explicit Timestamp(TimestampType ts_type) : m_type(ts_type) {
|
|
207
|
+
m_initial = absolute();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Timestamp(const Timestamp &) = default;
|
|
211
|
+
Timestamp(Timestamp &&) = default;
|
|
212
|
+
|
|
213
|
+
std::uint64_t get_value() const noexcept {
|
|
214
|
+
if (m_type == TimestampType::ABSOLUTE_TS) {
|
|
215
|
+
return absolute();
|
|
216
|
+
} else if (m_type == TimestampType::RELATIVE_TS) {
|
|
217
|
+
return relative();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
std::uint64_t get_initial_value() const noexcept {
|
|
222
|
+
return m_initial;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
std::uint64_t absolute() const noexcept {
|
|
226
|
+
std::uint64_t current;
|
|
227
|
+
|
|
228
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
229
|
+
current = std::chrono::duration_cast<std::chrono::nanoseconds>(m_clk.now().time_since_epoch()).count();
|
|
230
|
+
#else
|
|
231
|
+
// On MacOS `clock_gettime_nsec_np` could be used.
|
|
232
|
+
timespec ts;
|
|
233
|
+
clock_gettime(CLOCK_REALTIME, &ts);
|
|
234
|
+
current = static_cast<std::uint64_t>(ts.tv_sec) * 1'000'000'000 + ts.tv_nsec;
|
|
235
|
+
#endif // _WIN32 || _WIN64
|
|
236
|
+
return current;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
std::uint64_t relative() const noexcept {
|
|
240
|
+
return absolute() - m_initial;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private:
|
|
244
|
+
|
|
245
|
+
TimestampType m_type;
|
|
246
|
+
#if defined(_WIN32) || defined(_WIN64)
|
|
247
|
+
std::chrono::utc_clock m_clk;
|
|
248
|
+
#else
|
|
249
|
+
|
|
250
|
+
#endif // _WIN32 || _WIN64
|
|
251
|
+
std::uint64_t m_initial;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
template<typename T, typename V>
|
|
255
|
+
T variant_get(V&& value) {
|
|
256
|
+
|
|
257
|
+
T result;
|
|
258
|
+
|
|
259
|
+
const T* value_ptr = std::get_if<T>(&value);
|
|
260
|
+
if (value_ptr == nullptr) {
|
|
261
|
+
result = T{};
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
result = *value_ptr;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#if 0
|
|
271
|
+
inline void sleep_ms(std::uint64_t milliseconds) {
|
|
272
|
+
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
inline void sleep_ns(std::uint64_t nanoseconds) {
|
|
276
|
+
std::this_thread::sleep_for(std::chrono::nanoseconds(nanoseconds));
|
|
277
|
+
}
|
|
278
|
+
#endif
|
|
279
|
+
|
|
280
|
+
#endif // __HELPER_HPP
|