1+ #include " CANDatabaseAnalysis.h"
2+ #include < algorithm>
3+ #include < cmath>
4+ #include < tuple>
5+
6+ // For each entry: (byte, lr start bit, lr end bit)
7+ struct SignalRange {
8+ uint8_t byte;
9+ uint8_t lr_start_bit;
10+ uint8_t lr_end_bit;
11+ };
12+
13+ using SignalRanges = std::vector<SignalRange>;
14+
15+ /* *
16+ * Few explanations about the attributes:
17+ * lr_start_bit: Start bit position reading from left to right (ie bit 7 of byte 1 is 0, bit 7 of byte 2 is 9, ...)
18+ * lr_end_bit: same but for the end bit.
19+ */
20+ struct SignalLayoutEntry {
21+ SignalLayoutEntry () = delete ;
22+ SignalLayoutEntry (const CANSignal* src, SignalRanges&& r)
23+ : src_signal(src), ranges(r) {
24+
25+ }
26+
27+ SignalLayoutEntry (const SignalLayoutEntry&) = default ;
28+
29+ const CANSignal* src_signal;
30+ SignalRanges ranges;
31+ };
32+
33+ SignalRanges big_endian_ranges (const CANSignal& src) {
34+ SignalRanges result;
35+
36+ // For BigEndian signals, the start bit already represents the left mostbit
37+ // of the signal. Therefore, it is only required to transform it into a "human-readable"
38+ // value, ie. when looking at the frame from left to right.
39+ // ----------------- -----------------
40+ // |*|*|*|*|*|*|*|*| |*|*|*|*|*|*|*|*|
41+ // ----------------- -----------------
42+ // 0 7 instead of 7 0
43+ //
44+ // Example: Start bit 4 becomes LR start bit 3
45+ unsigned bitsAnalyzed = 0 ;
46+ bool is_start_byte = 0 ;
47+
48+ for (unsigned current_byte = src.start_bit () / 8 ; bitsAnalyzed < src.length (); current_byte++, is_start_byte = false ) {
49+ unsigned lbit = is_start_byte ? (7 - src.start_bit () % 8 ) : 0 ;
50+ unsigned rbit = std::min (7u , src.start_bit () - bitsAnalyzed);
51+
52+ // The static_cast are not "necessary" but it removes some warnings
53+ result.push_back ({ static_cast <uint8_t >(current_byte),
54+ static_cast <uint8_t >(lbit),
55+ static_cast <uint8_t >(rbit) });
56+ }
57+
58+ return result;
59+ }
60+
61+ SignalRanges little_endian_ranges (const CANSignal& src) {
62+ SignalRanges result;
63+
64+ // For LittleEndian signals, the start bit represents the LSB of the signal
65+ // which does not really represent anything in terms of layout. So we need
66+ // to compute the ranges for each byte individually anyway.
67+
68+ unsigned byteAnalyzed = 0 ;
69+ bool is_start_byte = 0 ;
70+
71+ return result;
72+ }
73+
74+ std::vector<SignalLayoutEntry> compute_layout (const CANFrame& src) {
75+ std::vector<SignalLayoutEntry> result;
76+
77+ for (const auto & signal: src) {
78+ const CANSignal& sig = *signal.second ;
79+ int lr_start_bit, lr_end_bit;
80+
81+ if (sig.endianness () == CANSignal::BigEndian) {
82+ auto ranges = big_endian_ranges (sig);
83+ result.emplace_back (&sig, std::move (ranges));
84+ }
85+ else {
86+ auto ranges = little_endian_ranges (sig);
87+ result.emplace_back (&sig, std::move (ranges));
88+ }
89+ }
90+
91+ return result;
92+ }
93+
94+ bool CppCAN::analysis::is_frame_layout_ok (const CANFrame& src) {
95+ auto layout = compute_layout (src);
96+
97+ auto overlap = [](const SignalLayoutEntry& e1 , const SignalLayoutEntry& e2 ) -> bool {
98+ return std::any_of (e1 .ranges .begin (), e1 .ranges .end (), [&e2 ](const SignalRange& r1) {
99+ // Find if r2 shares a SignalRange with the same byte with r1
100+ auto r2 = std::find_if (e2 .ranges .begin (), e2 .ranges .end (), [&r1](const SignalRange& e_range) {
101+ return r1.byte == e_range.byte ;
102+ });
103+
104+ // The signals are on completely different bytes
105+ if (r2 == e2 .ranges .end ())
106+ return false ;
107+
108+ // ordered.first is the leftmost SignalRange in the byte
109+ // ordered.second is the rightmost SignalRange in the byte
110+ auto ordered = std::minmax (r1, *r2, [](const SignalRange& r, const SignalRange& rr) {
111+ return r.lr_start_bit < rr.lr_start_bit ;
112+ });
113+
114+ // No overlapping if the last bit of the leftmost is before the first
115+ // bit of the rightmost.
116+ return ordered.first .lr_end_bit < ordered.second .lr_start_bit ;
117+ });
118+ };
119+
120+ for (size_t i = 0 ; i < layout.size (); i++) {
121+ const SignalLayoutEntry& e = layout[i];
122+
123+ for (size_t j = i + 1 ; j < layout.size (); j++) {
124+ if (overlap (layout[i], layout[j]))
125+ return false ;
126+ }
127+ }
128+
129+ return true ;
130+ }
0 commit comments