Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /* | |||
2 | * sent_decoder.cpp | |||
3 | * | |||
4 | * SENT protocol decoder | |||
5 | * | |||
6 | * TODO support MAF sensors like 04E906051 see https://github.com/rusefi/rusefi-hardware/issues/146 | |||
7 | * | |||
8 | * @date Oct 01, 2022 | |||
9 | * @author Andrey Gusakov <dron0gus@gmail.com>, (c) 2022-2024 | |||
10 | */ | |||
11 | ||||
12 | #include <stddef.h> | |||
13 | #include "sent_decoder.h" | |||
14 | ||||
15 | /*==========================================================================*/ | |||
16 | /* Misc helpers. */ | |||
17 | /*==========================================================================*/ | |||
18 | #define BIT(n) (UINT32_C(1) << (n)) | |||
19 | ||||
20 | /*==========================================================================*/ | |||
21 | /* Protocol definitions. */ | |||
22 | /*==========================================================================*/ | |||
23 | ||||
24 | /* Signals only */ | |||
25 | #define SENT_MSG_DATA_SIZE 6 | |||
26 | /* Status + two 12-bit signals + CRC: 8 pulses */ | |||
27 | #define SENT_MSG_PAYLOAD_SIZE (1 + SENT_MSG_DATA_SIZE + 1) // Size of payload | |||
28 | /* Sync + Status + Signals + CRC: 9 pulses */ | |||
29 | #define SENT_MSG_TOTAL (1 + SENT_MSG_PAYLOAD_SIZE) | |||
30 | ||||
31 | #define SENT_OFFSET_INTERVAL 12 | |||
32 | #define SENT_SYNC_INTERVAL (56 - SENT_OFFSET_INTERVAL) // 56 ticks - 12 | |||
33 | ||||
34 | #define SENT_MIN_INTERVAL 12 | |||
35 | #define SENT_MAX_INTERVAL 15 | |||
36 | ||||
37 | #define SENT_CRC_SEED 0x05 | |||
38 | ||||
39 | /* use 3 full frames + one additional pulse for unit time calibration */ | |||
40 | #define SENT_CALIBRATION_PULSES (1 + 3 * SENT_MSG_PAYLOAD_SIZE) | |||
41 | ||||
42 | /*==========================================================================*/ | |||
43 | /* Decoder configuration */ | |||
44 | /*==========================================================================*/ | |||
45 | ||||
46 | /*==========================================================================*/ | |||
47 | /* Decoder */ | |||
48 | /*==========================================================================*/ | |||
49 | ||||
50 | /* Helpers for Msg manipulations */ | |||
51 | /* nibbles order: status, sig0_MSN, sig0_MidN, sig0_LSN, sig1_MSN, sig1_MidN, sig1_LSN, CRC */ | |||
52 | /* we shift rxReg left for 4 bits on each nibble received and put newest nibble | |||
53 | * in [3:0] bits of rxReg, so when full message is received: | |||
54 | * CRC is [3:0] - nibble 7 | |||
55 | * status is [31:28] - nibble 0 | |||
56 | * sig0 is [27:16], sig1 is [15:4] */ | |||
57 | #define MsgGetNibble(msg, n) (((msg) >> (4 * (7 - (n)))) & 0xf) | |||
58 | #define MsgGetStat(msg) MsgGetNibble(msg, 0) | |||
59 | #define MsgGetSig0(msg) (((msg) >> (4 * 4)) & 0xfff) | |||
60 | #define MsgGetSig1(msg) (((msg) >> (1 * 4)) & 0xfff) | |||
61 | #define MsgGetCrc(msg) MsgGetNibble(msg, 7) | |||
62 | ||||
63 | /* convert CPU ticks to float Us */ | |||
64 | #define TicksToUs(ticks) ((float)(ticks) * 1000.0 * 1000.0 / CORE_CLOCK) | |||
65 | ||||
66 | 2 | void sent_channel::restart() { | ||
67 | 2 | state = SENT_STATE_CALIB; | ||
68 | 2 | pulseCounter = 0; | ||
69 | 2 | currentStatePulseCounter = 0; | ||
70 | 2 | pausePulseReceived = false; | ||
71 | 2 | tickPerUnit = 0; | ||
72 | ||||
73 | /* reset slow channels */ | |||
74 | 2 | SlowChannelDecoderReset(); | ||
75 | ||||
76 | #if SENT_STATISTIC_COUNTERS | |||
77 | 2 | statistic.ShortIntervalErr = 0; | ||
78 | 2 | statistic.LongIntervalErr = 0; | ||
79 | 2 | statistic.SyncErr = 0; | ||
80 | 2 | statistic.CrcErrCnt = 0; | ||
81 | 2 | statistic.FrameCnt = 0; | ||
82 | 2 | statistic.PauseCnt = 0; | ||
83 | 2 | statistic.sc12 = 0; | ||
84 | 2 | statistic.sc16 = 0; | ||
85 | 2 | statistic.scCrcErr = 0; | ||
86 | 2 | statistic.RestartCnt++; | ||
87 | #endif | |||
88 | 2 | } | ||
89 | ||||
90 | 16407 | void sent_channel::calcTickPerUnit(uint32_t clocks) { | ||
91 | /* int division with rounding */ | |||
92 | 16407 | tickPerUnit = (clocks + (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) / 2) / | ||
93 | (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL); | |||
94 | 16407 | } | ||
95 | ||||
96 | 147580 | float sent_channel::getTickTime() { | ||
97 | 147580 | return tickPerUnit; | ||
98 | } | |||
99 | ||||
100 | 33594 | bool sent_channel::isSyncPulse(uint32_t clocks) | ||
101 | { | |||
102 | /* check if pulse looks like sync with allowed +/-20% deviation */ | |||
103 | 33594 | uint32_t syncClocks = (SENT_SYNC_INTERVAL + SENT_OFFSET_INTERVAL) * tickPerUnit; | ||
104 | ||||
105 |
2/2✓ Branch 0 taken 21486 times.
✓ Branch 1 taken 12108 times.
|
2/2✓ Decision 'true' taken 16343 times.
✓ Decision 'false' taken 17251 times.
|
33594 | if (((100 * clocks) >= (syncClocks * 80)) && |
106 |
2/2✓ Branch 0 taken 16343 times.
✓ Branch 1 taken 5143 times.
|
21486 | ((100 * clocks) <= (syncClocks * 120))) | |
107 | 16343 | return 1; | ||
108 | ||||
109 | 17251 | return 0; | ||
110 | } | |||
111 | ||||
112 | 147571 | int sent_channel::FastChannelDecoder(uint32_t clocks) { | ||
113 | 147571 | pulseCounter++; | ||
114 | ||||
115 | /* special case - tick time calculation */ | |||
116 |
2/2✓ Branch 0 taken 157 times.
✓ Branch 1 taken 147414 times.
|
2/2✓ Decision 'true' taken 157 times.
✓ Decision 'false' taken 147414 times.
|
147571 | if (state == SENT_STATE_CALIB) { |
117 |
3/4✓ Branch 0 taken 145 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 145 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 145 times.
|
157 | if ((tickPerUnit == 0) || (currentStatePulseCounter == 0)) { |
118 | /* invalid or not yet calculated tickPerUnit */ | |||
119 | 12 | calcTickPerUnit(clocks); | ||
120 | /* lets assume this is sync pulse... */ | |||
121 | 12 | currentStatePulseCounter = 1; | ||
122 | } else { | |||
123 | /* some tickPerUnit calculated... | |||
124 | * Check next 1 + 6 + 1 pulses if they are valid with current tickPerUnit */ | |||
125 | 145 | int checkInterval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL; | ||
126 |
4/4✓ Branch 0 taken 144 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 51 times.
|
2/2✓ Decision 'true' taken 93 times.
✓ Decision 'false' taken 52 times.
|
145 | if ((checkInterval >= 0) && (checkInterval <= SENT_MAX_INTERVAL)) { |
127 | 93 | currentStatePulseCounter++; | ||
128 | /* Should end up with CRC pulse */ | |||
129 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 82 times.
|
2/2✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 82 times.
|
93 | if (currentStatePulseCounter == (1 + SENT_MSG_PAYLOAD_SIZE)) { |
130 | 11 | pulseCounter = 0; | ||
131 | 11 | currentStatePulseCounter = 0; | ||
132 | 11 | state = SENT_STATE_INIT; | ||
133 | } | |||
134 | } else { | |||
135 | 52 | currentStatePulseCounter = 1; | ||
136 | 52 | calcTickPerUnit(clocks); | ||
137 | } | |||
138 | } | |||
139 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 157 times.
|
157 | if (pulseCounter >= SENT_CALIBRATION_PULSES) { |
140 | /* failed to calculate valid tickPerUnit, restart */ | |||
141 | ✗ | restart(); | ||
142 | } | |||
143 | 157 | return 0; | ||
144 | } | |||
145 | ||||
146 | /* special case for out-of-sync state */ | |||
147 |
2/2✓ Branch 0 taken 1892 times.
✓ Branch 1 taken 145522 times.
|
2/2✓ Decision 'true' taken 1892 times.
✓ Decision 'false' taken 145522 times.
|
147414 | if (state == SENT_STATE_INIT) { |
148 |
2/2✓ Branch 1 taken 326 times.
✓ Branch 2 taken 1566 times.
|
2/2✓ Decision 'true' taken 326 times.
✓ Decision 'false' taken 1566 times.
|
1892 | if (isSyncPulse(clocks)) { |
149 | /* adjust unit time */ | |||
150 | 326 | calcTickPerUnit(clocks); | ||
151 | /* we get here from calibration phase. calibration phase end with CRC nibble | |||
152 | * if we had to skip ONE pulse before we get sync - that means device may send pause | |||
153 | * pulse in between of messages */ | |||
154 | 326 | pausePulseReceived = false; | ||
155 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 298 times.
|
2/2✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 298 times.
|
326 | if (currentStatePulseCounter == 1) { |
156 | 28 | pausePulseReceived = true; | ||
157 | } | |||
158 | /* next state */ | |||
159 | 326 | currentStatePulseCounter = 0; | ||
160 | 326 | state = SENT_STATE_STATUS; | ||
161 | } else { | |||
162 | 1566 | currentStatePulseCounter++; | ||
163 | /* 3 frames skipped, no SYNC detected - recalibrate */ | |||
164 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1564 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1564 times.
|
1566 | if (currentStatePulseCounter >= (SENT_MSG_TOTAL * 3)) { |
165 | 2 | restart(); | ||
166 | } | |||
167 | } | |||
168 | /* done for this pulse */ | |||
169 | 1892 | return 0; | ||
170 | } | |||
171 | ||||
172 | 145522 | int interval = (clocks + tickPerUnit / 2) / tickPerUnit - SENT_OFFSET_INTERVAL; | ||
173 | ||||
174 |
2/2✓ Branch 0 taken 279 times.
✓ Branch 1 taken 145243 times.
|
2/2✓ Decision 'true' taken 279 times.
✓ Decision 'false' taken 145243 times.
|
145522 | if (interval < 0) { |
175 | #if SENT_STATISTIC_COUNTERS | |||
176 | 279 | statistic.ShortIntervalErr++; | ||
177 | #endif //SENT_STATISTIC_COUNTERS | |||
178 | 279 | state = SENT_STATE_INIT; | ||
179 | 279 | return -1; | ||
180 | } | |||
181 | ||||
182 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 20250 times.
✓ Branch 2 taken 16310 times.
✓ Branch 3 taken 108683 times.
✗ Branch 4 not taken.
|
145243 | switch(state) | |
183 | { | |||
184 | ✗ | case SENT_STATE_CALIB: | ||
185 | case SENT_STATE_INIT: | |||
186 | /* handled above, should not get in here */ | |||
187 | ✗ | return -1; | ||
188 | ||||
189 |
1/1✓ Decision 'true' taken 20250 times.
|
20250 | case SENT_STATE_SYNC: | |
190 |
2/2✓ Branch 1 taken 15374 times.
✓ Branch 2 taken 4876 times.
|
2/2✓ Decision 'true' taken 15374 times.
✓ Decision 'false' taken 4876 times.
|
20250 | if (isSyncPulse(clocks)) |
191 | { | |||
192 | /* measured tick interval will be used until next sync pulse */ | |||
193 | 15374 | calcTickPerUnit(clocks); | ||
194 | 15374 | rxReg = 0; | ||
195 | 15374 | state = SENT_STATE_STATUS; | ||
196 | } | |||
197 | else | |||
198 | { | |||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4876 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 4876 times.
|
4876 | if (pausePulseReceived) { |
200 | #if SENT_STATISTIC_COUNTERS | |||
201 | // Increment sync interval err count | |||
202 | ✗ | statistic.SyncErr++; | ||
203 | ✗ | if (interval > SENT_SYNC_INTERVAL) | ||
204 | { | |||
205 | ✗ | statistic.LongIntervalErr++; | ||
206 | } | |||
207 | else | |||
208 | { | |||
209 | ✗ | statistic.ShortIntervalErr++; | ||
210 | } | |||
211 | #endif // SENT_STATISTIC_COUNTERS | |||
212 | /* wait for next sync and recalibrate tickPerUnit */ | |||
213 | ✗ | state = SENT_STATE_INIT; | ||
214 | ✗ | return -1; | ||
215 | } else { | |||
216 | /* This is possibly pause pulse */ | |||
217 | /* TODO: check: | |||
218 | * Minimum Length 12 ticks (equivalent to a nibble with 0 value) - this is already checked | |||
219 | * Maximum Length 768 ticks (3 * 256) */ | |||
220 | #if SENT_STATISTIC_COUNTERS | |||
221 | 4876 | statistic.PauseCnt++; | ||
222 | #endif // SENT_STATISTIC_COUNTERS | |||
223 | 4876 | pausePulseReceived = true; | ||
224 | } | |||
225 | } | |||
226 | 20250 | return 0; | ||
227 | ||||
228 |
1/1✓ Decision 'true' taken 16310 times.
|
16310 | case SENT_STATE_STATUS: | |
229 | /* it is possible that pause pulse was threaded as sync and we are here with sync pulse */ | |||
230 |
6/6✓ Branch 0 taken 11452 times.
✓ Branch 1 taken 4858 times.
✓ Branch 3 taken 643 times.
✓ Branch 4 taken 10809 times.
✓ Branch 5 taken 643 times.
✓ Branch 6 taken 15667 times.
|
2/2✓ Decision 'true' taken 643 times.
✓ Decision 'false' taken 15667 times.
|
16310 | if ((pausePulseReceived == false) && isSyncPulse(clocks)) { |
231 | #if SENT_STATISTIC_COUNTERS | |||
232 | 643 | statistic.PauseCnt++; | ||
233 | #endif // SENT_STATISTIC_COUNTERS | |||
234 | /* measured tick interval will be used until next sync pulse */ | |||
235 | 643 | calcTickPerUnit(clocks); | ||
236 | 643 | return 0; | ||
237 | } | |||
238 | // fallthrough | |||
239 | case SENT_STATE_SIG1_DATA1: | |||
240 | case SENT_STATE_SIG1_DATA2: | |||
241 | case SENT_STATE_SIG1_DATA3: | |||
242 | case SENT_STATE_SIG2_DATA1: | |||
243 | case SENT_STATE_SIG2_DATA2: | |||
244 | case SENT_STATE_SIG2_DATA3: | |||
245 | case SENT_STATE_CRC: | |||
246 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 124312 times.
|
2/2✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 124312 times.
|
124350 | if (interval > SENT_MAX_INTERVAL) |
247 | { | |||
248 | #if SENT_STATISTIC_COUNTERS | |||
249 | 38 | statistic.LongIntervalErr++; | ||
250 | #endif | |||
251 | ||||
252 | 38 | state = SENT_STATE_INIT; | ||
253 | 38 | return -1; | ||
254 | } | |||
255 | ||||
256 | 124312 | rxReg = (rxReg << 4) | (uint32_t)interval; | ||
257 | ||||
258 |
2/2✓ Branch 0 taken 108880 times.
✓ Branch 1 taken 15432 times.
|
2/2✓ Decision 'true' taken 108880 times.
✓ Decision 'false' taken 15432 times.
|
124312 | if (state != SENT_STATE_CRC) |
259 | { | |||
260 | /* TODO: refactor */ | |||
261 | 108880 | state = (SENT_STATE_enum)((int)state + 1); | ||
262 | 108880 | return 0; | ||
263 | } | |||
264 | ||||
265 | #if SENT_STATISTIC_COUNTERS | |||
266 | 15432 | statistic.FrameCnt++; | ||
267 | #endif // SENT_STATISTIC_COUNTERS | |||
268 | 15432 | pausePulseReceived = false; | ||
269 | 15432 | state = SENT_STATE_SYNC; | ||
270 | /* CRC check */ | |||
271 | /* TODO: find correct way to calculate CRC */ | |||
272 | 15432 | if ((MsgGetCrc(rxReg) == crc4(rxReg)) || | ||
273 |
5/6✓ Branch 0 taken 12252 times.
✓ Branch 1 taken 3180 times.
✓ Branch 3 taken 4436 times.
✓ Branch 4 taken 7816 times.
✓ Branch 5 taken 15432 times.
✗ Branch 6 not taken.
|
19868 | (MsgGetCrc(rxReg) == crc4_gm(rxReg)) || | |
274 |
1/2✓ Branch 1 taken 4436 times.
✗ Branch 2 not taken.
|
4436 | (MsgGetCrc(rxReg) == crc4_gm_v2(rxReg))) | |
275 | { | |||
276 | /* Full packet with correct CRC has been received */ | |||
277 | 15432 | rxLast = rxReg; | ||
278 | 15432 | hasValidFast = true; | ||
279 | /* TODO: add timestamp? */ | |||
280 | 15432 | return 1; | ||
281 | } | |||
282 | else | |||
283 | { | |||
284 | #if SENT_STATISTIC_COUNTERS | |||
285 | ✗ | statistic.CrcErrCnt++; | ||
286 | #endif // SENT_STATISTIC_COUNTERS | |||
287 | ✗ | return -1; | ||
288 | } | |||
289 | return 0; | |||
290 | } | |||
291 | ||||
292 | ✗ | return 0; | ||
293 | } | |||
294 | ||||
295 | 147571 | int sent_channel::Decoder(uint32_t clocks, uint8_t flags) { | ||
296 | int ret; | |||
297 | ||||
298 | #if SENT_STATISTIC_COUNTERS | |||
299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 147571 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 147571 times.
|
147571 | if (flags & SENT_FLAG_HW_OVERFLOW) { |
300 | ✗ | statistic.hwOverflowCnt++; | ||
301 | } | |||
302 | #endif | |||
303 | ||||
304 | /* TODO: handle flags */ | |||
305 | (void)flags; | |||
306 | ||||
307 | 147571 | ret = FastChannelDecoder(clocks); | ||
308 |
2/2✓ Branch 0 taken 15432 times.
✓ Branch 1 taken 132139 times.
|
2/2✓ Decision 'true' taken 15432 times.
✓ Decision 'false' taken 132139 times.
|
147571 | if (ret > 0) { |
309 | /* valid packet received, can process slow channels */ | |||
310 | 15432 | SlowChannelDecoder(); | ||
311 |
2/2✓ Branch 0 taken 317 times.
✓ Branch 1 taken 131822 times.
|
2/2✓ Decision 'true' taken 317 times.
✓ Decision 'false' taken 131822 times.
|
132139 | } else if (ret < 0) { |
312 | /* packet is incorrect, reset slow channel state machine */ | |||
313 | 317 | SlowChannelDecoderReset(); | ||
314 | } | |||
315 | ||||
316 | 147571 | return ret; | ||
317 | } | |||
318 | ||||
319 | 15450 | int sent_channel::GetMsg(uint32_t* rx) { | ||
320 |
2/2✓ Branch 0 taken 15441 times.
✓ Branch 1 taken 9 times.
|
2/2✓ Decision 'true' taken 15441 times.
✓ Decision 'false' taken 9 times.
|
15450 | if (rx) { |
321 | 15441 | *rx = rxLast; | ||
322 | } | |||
323 | ||||
324 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 15449 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 15449 times.
|
15450 | if (!hasValidFast) { |
325 | 1 | return -1; | ||
326 | } | |||
327 | /* TODO: add check for time since last message received */ | |||
328 | 15449 | return 0; | ||
329 | } | |||
330 | ||||
331 | 15441 | int sent_channel::GetSignals(uint8_t *pStat, uint16_t *pSig0, uint16_t *pSig1) { | ||
332 | 15441 | uint32_t rx; | ||
333 |
1/1✓ Branch 1 taken 15441 times.
|
15441 | int ret = GetMsg(&rx); | |
334 | ||||
335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15441 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 15441 times.
|
15441 | if (ret < 0) { |
336 | ✗ | return ret; | ||
337 | } | |||
338 | ||||
339 | /* NOTE different MSB packing for sig0 and sig1 | |||
340 | * is it protocol-defined or device-specific? | |||
341 | * Also looks like some devices send 16 + 8 bit, not 12 + 12 */ | |||
342 |
1/2✓ Branch 0 taken 15441 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 15441 times.
✗ Decision 'false' not taken.
|
15441 | if (pStat) { |
343 | 15441 | *pStat = MsgGetStat(rx); | ||
344 | } | |||
345 | ||||
346 |
1/2✓ Branch 0 taken 15441 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 15441 times.
✗ Decision 'false' not taken.
|
15441 | if (pSig0) { |
347 | 15441 | uint16_t tmp = MsgGetSig0(rx); | ||
348 | 15441 | *pSig0 = tmp; | ||
349 | } | |||
350 | ||||
351 |
1/2✓ Branch 0 taken 15441 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 15441 times.
✗ Decision 'false' not taken.
|
15441 | if (pSig1) { |
352 | 15441 | uint16_t tmp = MsgGetSig1(rx); | ||
353 | /* swap */ | |||
354 | 15441 | tmp = ((tmp >> 8) & 0x00f) | | ||
355 | 15441 | ((tmp << 8) & 0xf00) | | ||
356 | 15441 | (tmp & 0x0f0); | ||
357 | 15441 | *pSig1 = tmp; | ||
358 | } | |||
359 | ||||
360 | 15441 | return 0; | ||
361 | } | |||
362 | ||||
363 | 319 | int sent_channel::StoreSlowChannelValue(uint8_t id, uint16_t data) | ||
364 | { | |||
365 | size_t i; | |||
366 | ||||
367 | /* Update already allocated messagebox? */ | |||
368 |
2/2✓ Branch 0 taken 2499 times.
✓ Branch 1 taken 47 times.
|
2/2✓ Decision 'true' taken 2499 times.
✓ Decision 'false' taken 47 times.
|
2546 | for (i = 0; i < SENT_SLOW_CHANNELS_MAX; i++) { |
369 |
4/4✓ Branch 1 taken 1301 times.
✓ Branch 2 taken 1198 times.
✓ Branch 4 taken 272 times.
✓ Branch 5 taken 1029 times.
|
2/2✓ Decision 'true' taken 272 times.
✓ Decision 'false' taken 2227 times.
|
2499 | if ((scMsg[i].valid) && (scMsg[i].id == id)) { |
370 | 272 | scMsg[i].data = data; | ||
371 | 272 | return 0; | ||
372 | } | |||
373 | } | |||
374 | ||||
375 | /* New message? Allocate messagebox */ | |||
376 |
1/2✓ Branch 0 taken 353 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 353 times.
✗ Decision 'false' not taken.
|
353 | for (i = 0; i < SENT_SLOW_CHANNELS_MAX; i++) { |
377 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 306 times.
|
2/2✓ Decision 'true' taken 47 times.
✓ Decision 'false' taken 306 times.
|
353 | if (scMsg[i].valid == false) |
378 | { | |||
379 | 47 | scMsg[i].data = data; | ||
380 | 47 | scMsg[i].id = id; | ||
381 | 47 | scMsg[i].valid = true; | ||
382 | 47 | return 0; | ||
383 | } | |||
384 | } | |||
385 | ||||
386 | /* No free mailboxes for new ID */ | |||
387 | ✗ | return -1; | ||
388 | } | |||
389 | ||||
390 | 2304 | int sent_channel::GetSlowChannelValue(uint8_t id) | ||
391 | { | |||
392 | size_t i; | |||
393 | ||||
394 |
2/2✓ Branch 0 taken 73070 times.
✓ Branch 1 taken 2273 times.
|
2/2✓ Decision 'true' taken 73070 times.
✓ Decision 'false' taken 2273 times.
|
75343 | for (i = 0; i < SENT_SLOW_CHANNELS_MAX; i++) { |
395 |
4/4✓ Branch 1 taken 7633 times.
✓ Branch 2 taken 65437 times.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 7602 times.
|
2/2✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 73039 times.
|
73070 | if ((scMsg[i].valid) && (scMsg[i].id == id)) { |
396 | 31 | return scMsg[i].data; | ||
397 | } | |||
398 | } | |||
399 | ||||
400 | /* not found */ | |||
401 | 2273 | return -1; | ||
402 | } | |||
403 | ||||
404 | 15432 | int sent_channel::SlowChannelDecoder() | ||
405 | { | |||
406 | /* bit 2 and bit 3 from status nibble are used to transfer short messages */ | |||
407 | 15432 | bool b2 = !!(MsgGetStat(rxLast) & BIT(2)); | ||
408 | 15432 | bool b3 = !!(MsgGetStat(rxLast) & BIT(3)); | ||
409 | ||||
410 | /* shift in new data */ | |||
411 | 15432 | scShift2 = (scShift2 << 1) | b2; | ||
412 | 15432 | scShift3 = (scShift3 << 1) | b3; | ||
413 | 15432 | scCrcShift = (scCrcShift << 2) | ((uint32_t)b2 << 1) | b3; | ||
414 | ||||
415 | if (1) { | |||
416 | /* Short Serial Message format */ | |||
417 | ||||
418 | /* 0b1000.0000.0000.0000? */ | |||
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15432 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 15432 times.
|
15432 | if ((scShift3 & 0xffff) == 0x8000) { |
420 | /* Done receiving */ | |||
421 | ||||
422 | /* TODO: add crc check */ | |||
423 | ||||
424 | ✗ | uint8_t id = (scShift2 >> 12) & 0x0f; | ||
425 | ✗ | uint16_t data = (scShift2 >> 4) & 0xff; | ||
426 | ||||
427 | ✗ | return StoreSlowChannelValue(id, data); | ||
428 | } | |||
429 | } | |||
430 | if (1) { | |||
431 | /* Enhanced Serial Message format */ | |||
432 | ||||
433 | /* 0b11.1111.0xxx.xx0x.xxx0 ? */ | |||
434 |
2/2✓ Branch 0 taken 319 times.
✓ Branch 1 taken 15113 times.
|
2/2✓ Decision 'true' taken 319 times.
✓ Decision 'false' taken 15113 times.
|
15432 | if ((scShift3 & 0x3f821) == 0x3f000) { |
435 | /* C-flag: configuration bit is used to indicate 16 bit format */ | |||
436 | 319 | bool sc16Bit = !!(scShift3 & (1 << 10)); | ||
437 | ||||
438 | 319 | uint8_t crc = (scShift2 >> 12) & 0x3f; | ||
439 | #if SENT_STATISTIC_COUNTERS | |||
440 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 319 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 319 times.
|
319 | if (sc16Bit) { |
441 | ✗ | statistic.sc16++; | ||
442 | } else { | |||
443 | 319 | statistic.sc12++; | ||
444 | } | |||
445 | #endif | |||
446 |
1/2✓ Branch 1 taken 319 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 319 times.
✗ Decision 'false' not taken.
|
319 | if (crc == crc6(scCrcShift)) { |
447 |
1/2✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 319 times.
✗ Decision 'false' not taken.
|
319 | if (!sc16Bit) { |
448 | /* 12 bit message, 8 bit ID */ | |||
449 | 319 | uint8_t id = ((scShift3 >> 1) & 0x0f) | | ||
450 | 319 | ((scShift3 >> 2) & 0xf0); | ||
451 | 319 | uint16_t data = scShift2 & 0x0fff; /* 12 bit */ | ||
452 | ||||
453 | 319 | return StoreSlowChannelValue(id, data); | ||
454 | } else { | |||
455 | /* 16 bit message, 4 bit ID */ | |||
456 | ✗ | uint8_t id = (scShift3 >> 6) & 0x0f; | ||
457 | ✗ | uint16_t data = (scShift2 & 0x0fff) | | ||
458 | ✗ | (((scShift3 >> 1) & 0x0f) << 12); | ||
459 | ||||
460 | ✗ | return StoreSlowChannelValue(id, data); | ||
461 | } | |||
462 | } else { | |||
463 | #if SENT_STATISTIC_COUNTERS | |||
464 | ✗ | statistic.scCrcErr++; | ||
465 | #endif | |||
466 | } | |||
467 | } | |||
468 | } | |||
469 | ||||
470 | 15113 | return 0; | ||
471 | } | |||
472 | ||||
473 | 319 | void sent_channel::SlowChannelDecoderReset() | ||
474 | { | |||
475 | /* packet is incorrect, reset slow channel state machine */ | |||
476 | 319 | scShift2 = 0; | ||
477 | 319 | scShift3 = 0; | ||
478 | ||||
479 |
2/2✓ Branch 0 taken 10208 times.
✓ Branch 1 taken 319 times.
|
2/2✓ Decision 'true' taken 10208 times.
✓ Decision 'false' taken 319 times.
|
10527 | for (size_t i = 0; i < SENT_SLOW_CHANNELS_MAX; i++) { |
480 | 10208 | scMsg[i].valid = false; | ||
481 | } | |||
482 | 319 | } | ||
483 | ||||
484 | /* This is correct for Si7215 */ | |||
485 | /* This CRC is calculated for WHOLE message expect last nibble (CRC) */ | |||
486 | 15432 | uint8_t sent_channel::crc4(uint32_t data) | ||
487 | { | |||
488 | size_t i; | |||
489 | 15432 | uint8_t crc = SENT_CRC_SEED; // initialize checksum with seed "0101" | ||
490 | 15432 | const uint8_t CrcLookup[16] = {0, 13, 7, 10, 14, 3, 9, 4, 1, 12, 6, 11, 15, 2, 8, 5}; | ||
491 | ||||
492 |
2/2✓ Branch 0 taken 108024 times.
✓ Branch 1 taken 15432 times.
|
2/2✓ Decision 'true' taken 108024 times.
✓ Decision 'false' taken 15432 times.
|
123456 | for (i = 0; i < 7; i++) { |
493 | 108024 | crc = crc ^ MsgGetNibble(data, i); | ||
494 | 108024 | crc = CrcLookup[crc]; | ||
495 | } | |||
496 | ||||
497 | 15432 | return crc; | ||
498 | } | |||
499 | ||||
500 | /* TODO: double check two following and use same CRC routine? */ | |||
501 | ||||
502 | /* This is correct for GM throttle body */ | |||
503 | /* This CRC is calculated for message expect status nibble and minus CRC nibble */ | |||
504 | 12252 | uint8_t sent_channel::crc4_gm(uint32_t data) | ||
505 | { | |||
506 | size_t i; | |||
507 | 12252 | uint8_t crc = SENT_CRC_SEED; // initialize checksum with seed "0101" | ||
508 | 12252 | const uint8_t CrcLookup[16] = {0, 13, 7, 10, 14, 3, 9, 4, 1, 12, 6, 11, 15, 2, 8, 5}; | ||
509 | ||||
510 |
2/2✓ Branch 0 taken 73512 times.
✓ Branch 1 taken 12252 times.
|
2/2✓ Decision 'true' taken 73512 times.
✓ Decision 'false' taken 12252 times.
|
85764 | for (i = 1; i < 7; i++) { |
511 | 73512 | crc = CrcLookup[crc]; | ||
512 | 73512 | crc = (crc ^ MsgGetNibble(data, i)) & 0xf; | ||
513 | } | |||
514 | ||||
515 | 12252 | return crc; | ||
516 | } | |||
517 | ||||
518 | /* This is correct for GDI fuel pressure sensor */ | |||
519 | /* This CRC is calculated for message expect status nibble and minus CRC nibble */ | |||
520 | 4436 | uint8_t sent_channel::crc4_gm_v2(uint32_t data) | ||
521 | { | |||
522 | size_t i; | |||
523 | 4436 | uint8_t crc = SENT_CRC_SEED; // initialize checksum with seed "0101" | ||
524 | 4436 | const uint8_t CrcLookup[16] = {0, 13, 7, 10, 14, 3, 9, 4, 1, 12, 6, 11, 15, 2, 8, 5}; | ||
525 | ||||
526 |
2/2✓ Branch 0 taken 26616 times.
✓ Branch 1 taken 4436 times.
|
2/2✓ Decision 'true' taken 26616 times.
✓ Decision 'false' taken 4436 times.
|
31052 | for (i = 1; i < 7; i++) { |
527 | 26616 | crc = CrcLookup[crc]; | ||
528 | 26616 | crc = (crc ^ MsgGetNibble(data, i)) & 0xf; | ||
529 | } | |||
530 | // One more round with 0 as input | |||
531 | 4436 | crc = CrcLookup[crc]; | ||
532 | ||||
533 | 4436 | return crc; | ||
534 | } | |||
535 | ||||
536 | 319 | uint8_t sent_channel::crc6(uint32_t data) | ||
537 | { | |||
538 | size_t i; | |||
539 | /* Seed 0x15 (21) */ | |||
540 | 319 | uint8_t crc = 0x15; | ||
541 | /* CRC table for poly = 0x59 (x^6 + x^4 + x^3 + 1) */ | |||
542 | 319 | const uint8_t crc6_table[64] = { | ||
543 | 0, 25, 50, 43, 61, 36, 15, 22, 35, 58, 17, 8, 30, 7, 44, 53, | |||
544 | 31, 6, 45, 52, 34, 59, 16, 9, 60, 37, 14, 23, 1, 24, 51, 42, | |||
545 | 62, 39, 12, 21, 3, 26, 49, 40, 29, 4, 47, 54, 32, 57, 18, 11, | |||
546 | 33, 56, 19, 10, 28, 5, 46, 55, 2, 27, 48, 41, 63, 38, 13, 20 }; | |||
547 | ||||
548 |
2/2✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 319 times.
|
2/2✓ Decision 'true' taken 1276 times.
✓ Decision 'false' taken 319 times.
|
1595 | for (i = 0; i < 4; i++) { |
549 | 1276 | uint8_t tmp = (data >> (24 - 6 * (i + 1))) & 0x3f; | ||
550 | 1276 | crc = tmp ^ crc6_table[crc]; | ||
551 | } | |||
552 | // Extra round with 0 input | |||
553 | 319 | crc = 0 ^ crc6_table[crc]; | ||
554 | ||||
555 | 319 | return crc; | ||
556 | } | |||
557 |