Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /** | |||
2 | * @file engine_controller.cpp | |||
3 | * @brief Controllers package entry point code | |||
4 | * | |||
5 | * | |||
6 | * | |||
7 | * @date Feb 7, 2013 | |||
8 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
9 | * | |||
10 | * This file is part of rusEfi - see http://rusefi.com | |||
11 | * | |||
12 | * rusEfi is free software; you can redistribute it and/or modify it under the terms of | |||
13 | * the GNU General Public License as published by the Free Software Foundation; either | |||
14 | * version 3 of the License, or (at your option) any later version. | |||
15 | * | |||
16 | * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without | |||
17 | * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
18 | * GNU General Public License for more details. | |||
19 | * | |||
20 | * You should have received a copy of the GNU General Public License along with this program. | |||
21 | * If not, see <http://www.gnu.org/licenses/>. | |||
22 | */ | |||
23 | ||||
24 | #include "pch.h" | |||
25 | ||||
26 | ||||
27 | #include "trigger_central.h" | |||
28 | #include "script_impl.h" | |||
29 | #include "idle_thread.h" | |||
30 | #include "main_trigger_callback.h" | |||
31 | #include "flash_main.h" | |||
32 | #include "bench_test.h" | |||
33 | #include "mmc_card.h" | |||
34 | #include "electronic_throttle.h" | |||
35 | #include "trigger_emulator_algo.h" | |||
36 | #include "high_pressure_fuel_pump.h" | |||
37 | #include "malfunction_central.h" | |||
38 | #include "malfunction_indicator.h" | |||
39 | #include "speed_density.h" | |||
40 | #include "local_version_holder.h" | |||
41 | #include "alternator_controller.h" | |||
42 | #include "can_bench_test.h" | |||
43 | #include "engine_emulator.h" | |||
44 | #include "fuel_math.h" | |||
45 | #include "defaults.h" | |||
46 | #include "spark_logic.h" | |||
47 | #include "status_loop.h" | |||
48 | #include "aux_valves.h" | |||
49 | #include "accelerometer.h" | |||
50 | #include "vvt.h" | |||
51 | #include "boost_control.h" | |||
52 | #include "launch_control.h" | |||
53 | #include "speedometer.h" | |||
54 | #include "gppwm.h" | |||
55 | #include "date_stamp.h" | |||
56 | #include "rusefi_lua.h" | |||
57 | #include "buttonshift.h" | |||
58 | #include "start_stop.h" | |||
59 | #include "dynoview.h" | |||
60 | #include "vr_pwm.h" | |||
61 | #include "adc_subscription.h" | |||
62 | #include "gc_generic.h" | |||
63 | #include "tuner_detector_utils.h" | |||
64 | ||||
65 | ||||
66 | #if EFI_TUNER_STUDIO | |||
67 | #include "tunerstudio.h" | |||
68 | #endif /* EFI_TUNER_STUDIO */ | |||
69 | ||||
70 | #if EFI_LOGIC_ANALYZER | |||
71 | #include "logic_analyzer.h" | |||
72 | #endif /* EFI_LOGIC_ANALYZER */ | |||
73 | ||||
74 | #if defined(EFI_BOOTLOADER_INCLUDE_CODE) | |||
75 | #include "bootloader/bootloader.h" | |||
76 | #endif /* EFI_BOOTLOADER_INCLUDE_CODE */ | |||
77 | ||||
78 | #include "periodic_task.h" | |||
79 | ||||
80 | #ifdef MODULE_MAP_AVERAGING | |||
81 | #include "map_averaging.h" | |||
82 | #endif | |||
83 | ||||
84 | #if ! EFI_UNIT_TEST | |||
85 | #include "init.h" | |||
86 | #include "mpu_util.h" | |||
87 | #endif /* EFI_UNIT_TEST */ | |||
88 | ||||
89 | #if !EFI_UNIT_TEST | |||
90 | ||||
91 | /** | |||
92 | * Would love to pass reference to configuration object into constructor but C++ does allow attributes after parenthesized initializer | |||
93 | */ | |||
94 | Engine ___engine CCM_OPTIONAL; | |||
95 | ||||
96 | #else // EFI_UNIT_TEST | |||
97 | ||||
98 | Engine * engine; | |||
99 | ||||
100 | #endif /* EFI_UNIT_TEST */ | |||
101 | ||||
102 | using namespace rusefi::stringutil; | |||
103 | ||||
104 | 585 | void initDataStructures() { | ||
105 | #if EFI_ENGINE_CONTROL | |||
106 | 585 | initFuelMap(); | ||
107 | 585 | initSpeedDensity(); | ||
108 | 585 | IgnitionEventList &events = engine->ignitionEvents; | ||
109 |
2/2✓ Branch 1 taken 7020 times.
✓ Branch 2 taken 585 times.
|
2/2✓ Decision 'true' taken 7020 times.
✓ Decision 'false' taken 585 times.
|
7605 | for (size_t i=0;i<efi::size(events.elements);i++) { |
110 | // above-zero value helps distinguish events | |||
111 | 7020 | events.elements[i].sparkCounter = 1; | ||
112 | } | |||
113 | // above-zero value helps distinguish events | |||
114 | 585 | engine->engineState.globalSparkCounter = 1; | ||
115 | #endif // EFI_ENGINE_CONTROL | |||
116 | 585 | } | ||
117 | ||||
118 | #if !EFI_UNIT_TEST | |||
119 | ||||
120 | static void doPeriodicSlowCallback(); | |||
121 | ||||
122 | class PeriodicFastController : public PeriodicTimerController { | |||
123 | void PeriodicTask() override { | |||
124 | engine->periodicFastCallback(); | |||
125 | } | |||
126 | ||||
127 | int getPeriodMs() override { | |||
128 | return FAST_CALLBACK_PERIOD_MS; | |||
129 | } | |||
130 | }; | |||
131 | ||||
132 | class PeriodicSlowController : public PeriodicTimerController { | |||
133 | void PeriodicTask() override { | |||
134 | doPeriodicSlowCallback(); | |||
135 | } | |||
136 | ||||
137 | int getPeriodMs() override { | |||
138 | // no reason to have this configurable, looks like everyone is happy with 20Hz | |||
139 | return SLOW_CALLBACK_PERIOD_MS; | |||
140 | } | |||
141 | }; | |||
142 | ||||
143 | static PeriodicFastController fastController; | |||
144 | static PeriodicSlowController slowController; | |||
145 | ||||
146 | class EngineStateBlinkingTask : public PeriodicTimerController { | |||
147 | int getPeriodMs() override { | |||
148 | return 50; | |||
149 | } | |||
150 | ||||
151 | void PeriodicTask() override { | |||
152 | #if EFI_SHAFT_POSITION_INPUT | |||
153 | bool is_running = engine->rpmCalculator.isRunning(); | |||
154 | #else | |||
155 | bool is_running = false; | |||
156 | #endif /* EFI_SHAFT_POSITION_INPUT */ | |||
157 | ||||
158 | if (is_running) { | |||
159 | // blink in running mode | |||
160 | enginePins.runningLedPin.toggle(); | |||
161 | } else { | |||
162 | bool is_cranking = engine->rpmCalculator.isCranking(); | |||
163 | enginePins.runningLedPin.setValue(is_cranking); | |||
164 | } | |||
165 | } | |||
166 | }; | |||
167 | ||||
168 | static EngineStateBlinkingTask engineStateBlinkingTask; | |||
169 | ||||
170 | static void resetAccel() { | |||
171 | engine->module<TpsAccelEnrichment>()->resetAE(); | |||
172 | ||||
173 | #if EFI_ENGINE_CONTROL | |||
174 | for (size_t i = 0; i < efi::size(engine->injectionEvents.elements); i++) | |||
175 | { | |||
176 | engine->injectionEvents.elements[i].getWallFuel().resetWF(); | |||
177 | } | |||
178 | #endif // EFI_ENGINE_CONTROL | |||
179 | } | |||
180 | ||||
181 | static void doPeriodicSlowCallback() { | |||
182 | #if EFI_SHAFT_POSITION_INPUT | |||
183 | efiAssertVoid(ObdCode::CUSTOM_ERR_6661, getCurrentRemainingStack() > 64, "lowStckOnEv"); | |||
184 | ||||
185 | slowStartStopButtonCallback(); | |||
186 | ||||
187 | engine->rpmCalculator.onSlowCallback(); | |||
188 | if (engine->rpmCalculator.isStopped()) { | |||
189 | resetAccel(); | |||
190 | } | |||
191 | #endif /* EFI_SHAFT_POSITION_INPUT */ | |||
192 | ||||
193 | engine->periodicSlowCallback(); | |||
194 | ||||
195 | #if EFI_TCU | |||
196 | if (engineConfiguration->tcuEnabled && engineConfiguration->gearControllerMode != GearControllerMode::None) { | |||
197 | if (engine->gearController == NULL) { | |||
198 | initGearController(); | |||
199 | } else if (engine->gearController->getMode() != engineConfiguration->gearControllerMode) { | |||
200 | initGearController(); | |||
201 | } | |||
202 | engine->gearController->update(); | |||
203 | } | |||
204 | #endif // EFI_TCU | |||
205 | ||||
206 | tryResetWatchdog(); | |||
207 | } | |||
208 | ||||
209 | void initPeriodicEvents() { | |||
210 | slowController.start(); | |||
211 | fastController.start(); | |||
212 | } | |||
213 | ||||
214 | char * getPinNameByAdcChannel(const char *msg, adc_channel_e hwChannel, char *buffer, size_t bufferSize) { | |||
215 | #if HAL_USE_ADC | |||
216 | if (!isAdcChannelValid(hwChannel)) { | |||
217 | snprintf(buffer, bufferSize, "NONE"); | |||
218 | } else { | |||
219 | const char *name = portname(getAdcChannelPort(msg, hwChannel)); | |||
220 | snprintf(buffer, bufferSize, "%s%d", name ? name : "null", getAdcChannelPin(hwChannel)); | |||
221 | } | |||
222 | #else | |||
223 | snprintf(buffer, bufferSize, "NONE"); | |||
224 | #endif /* HAL_USE_ADC */ | |||
225 | return buffer; | |||
226 | } | |||
227 | ||||
228 | #if EFI_PROD_CODE | |||
229 | static void printSensorInfo() { | |||
230 | #if HAL_USE_ADC | |||
231 | // Print info about analog mappings | |||
232 | AdcSubscription::PrintInfo(); | |||
233 | #endif // HAL_USE_ADC | |||
234 | ||||
235 | // Print info about all sensors | |||
236 | Sensor::showAllSensorInfo(); | |||
237 | } | |||
238 | #endif // EFI_PROD_CODE | |||
239 | ||||
240 | #define isOutOfBounds(offset) ((offset<0) || (offset) >= (int) sizeof(engine_configuration_s)) | |||
241 | ||||
242 | static void getShort(int offset) { | |||
243 | if (isOutOfBounds(offset)) | |||
244 | return; | |||
245 | uint16_t *ptr = (uint16_t *) (&((char *) engineConfiguration)[offset]); | |||
246 | uint16_t value = *ptr; | |||
247 | /** | |||
248 | * this response is part of rusEfi console API | |||
249 | */ | |||
250 | efiPrintf("short%s%d is %d", CONSOLE_DATA_PROTOCOL_TAG, offset, value); | |||
251 | } | |||
252 | ||||
253 | static void getByte(int offset) { | |||
254 | if (isOutOfBounds(offset)) | |||
255 | return; | |||
256 | uint8_t *ptr = (uint8_t *) (&((char *) engineConfiguration)[offset]); | |||
257 | uint8_t value = *ptr; | |||
258 | /** | |||
259 | * this response is part of rusEfi console API | |||
260 | */ | |||
261 | efiPrintf("byte%s%d is %d", CONSOLE_DATA_PROTOCOL_TAG, offset, value); | |||
262 | } | |||
263 | ||||
264 | static void setBit(const char *offsetStr, const char *bitStr, const char *valueStr) { | |||
265 | int offset = atoi(offsetStr); | |||
266 | if (absI(offset) == absI(ATOI_ERROR_CODE)) { | |||
267 | efiPrintf("invalid offset [%s]", offsetStr); | |||
268 | return; | |||
269 | } | |||
270 | if (isOutOfBounds(offset)) { | |||
271 | return; | |||
272 | } | |||
273 | int bit = atoi(bitStr); | |||
274 | if (absI(bit) == absI(ATOI_ERROR_CODE)) { | |||
275 | efiPrintf("invalid bit [%s]", bitStr); | |||
276 | return; | |||
277 | } | |||
278 | int value = atoi(valueStr); | |||
279 | if (absI(value) == absI(ATOI_ERROR_CODE)) { | |||
280 | efiPrintf("invalid value [%s]", valueStr); | |||
281 | return; | |||
282 | } | |||
283 | int *ptr = (int *) (&((char *) engineConfiguration)[offset]); | |||
284 | *ptr ^= (-value ^ *ptr) & (1 << bit); | |||
285 | /** | |||
286 | * this response is part of rusEfi console API | |||
287 | */ | |||
288 | efiPrintf("bit%s%d/%d is %d", CONSOLE_DATA_PROTOCOL_TAG, offset, bit, value); | |||
289 | incrementGlobalConfigurationVersion("setBit"); | |||
290 | } | |||
291 | ||||
292 | static void setShort(const int offset, const int value) { | |||
293 | if (isOutOfBounds(offset)) | |||
294 | return; | |||
295 | uint16_t *ptr = (uint16_t *) (&((char *) engineConfiguration)[offset]); | |||
296 | *ptr = (uint16_t) value; | |||
297 | getShort(offset); | |||
298 | incrementGlobalConfigurationVersion("setShort"); | |||
299 | } | |||
300 | ||||
301 | static void setByte(const int offset, const int value) { | |||
302 | if (isOutOfBounds(offset)) | |||
303 | return; | |||
304 | uint8_t *ptr = (uint8_t *) (&((char *) engineConfiguration)[offset]); | |||
305 | *ptr = (uint8_t) value; | |||
306 | getByte(offset); | |||
307 | incrementGlobalConfigurationVersion("setByte"); | |||
308 | } | |||
309 | ||||
310 | static void getBit(int offset, int bit) { | |||
311 | if (isOutOfBounds(offset)) | |||
312 | return; | |||
313 | int *ptr = (int *) (&((char *) engineConfiguration)[offset]); | |||
314 | int value = (*ptr >> bit) & 1; | |||
315 | /** | |||
316 | * this response is part of rusEfi console API | |||
317 | */ | |||
318 | efiPrintf("bit%s%d/%d is %d", CONSOLE_DATA_PROTOCOL_TAG, offset, bit, value); | |||
319 | } | |||
320 | ||||
321 | static void getInt(int offset) { | |||
322 | if (isOutOfBounds(offset)) | |||
323 | return; | |||
324 | int *ptr = (int *) (&((char *) engineConfiguration)[offset]); | |||
325 | int value = *ptr; | |||
326 | /** | |||
327 | * this response is part of rusEfi console API | |||
328 | */ | |||
329 | efiPrintf("int%s%d is %d", CONSOLE_DATA_PROTOCOL_TAG, offset, value); | |||
330 | } | |||
331 | ||||
332 | static void setInt(const int offset, const int value) { | |||
333 | if (isOutOfBounds(offset)) | |||
334 | return; | |||
335 | int *ptr = (int *) (&((char *) engineConfiguration)[offset]); | |||
336 | *ptr = value; | |||
337 | getInt(offset); | |||
338 | incrementGlobalConfigurationVersion("setInt"); | |||
339 | } | |||
340 | ||||
341 | static void getFloat(int offset) { | |||
342 | if (isOutOfBounds(offset)) | |||
343 | return; | |||
344 | float *ptr = (float *) (&((char *) engineConfiguration)[offset]); | |||
345 | float value = *ptr; | |||
346 | /** | |||
347 | * this response is part of rusEfi console API | |||
348 | */ | |||
349 | efiPrintf("float%s%d is %.5f", CONSOLE_DATA_PROTOCOL_TAG, offset, value); | |||
350 | } | |||
351 | ||||
352 | static void setFloat(const char *offsetStr, const char *valueStr) { | |||
353 | int offset = atoi(offsetStr); | |||
354 | if (absI(offset) == absI(ATOI_ERROR_CODE)) { | |||
355 | efiPrintf("invalid offset [%s]", offsetStr); | |||
356 | return; | |||
357 | } | |||
358 | if (isOutOfBounds(offset)) | |||
359 | return; | |||
360 | float value = atoff(valueStr); | |||
361 | if (std::isnan(value)) { | |||
362 | efiPrintf("invalid value [%s]", valueStr); | |||
363 | return; | |||
364 | } | |||
365 | float *ptr = (float *) (&((char *) engineConfiguration)[offset]); | |||
366 | *ptr = value; | |||
367 | getFloat(offset); | |||
368 | incrementGlobalConfigurationVersion("setFloat"); | |||
369 | } | |||
370 | ||||
371 | static void initConfigActions() { | |||
372 | addConsoleActionSS("set_float", (VoidCharPtrCharPtr) setFloat); | |||
373 | addConsoleActionII("set_int", (VoidIntInt) setInt); | |||
374 | addConsoleActionII("set_short", (VoidIntInt) setShort); | |||
375 | addConsoleActionII("set_byte", (VoidIntInt) setByte); | |||
376 | addConsoleActionSSS("set_bit", setBit); | |||
377 | ||||
378 | addConsoleActionI("get_float", getFloat); | |||
379 | addConsoleActionI("get_int", getInt); | |||
380 | addConsoleActionI("get_short", getShort); | |||
381 | addConsoleActionI("get_byte", getByte); | |||
382 | addConsoleActionII("get_bit", getBit); | |||
383 | } | |||
384 | #endif /* EFI_UNIT_TEST */ | |||
385 | ||||
386 | // one-time start-up | |||
387 | // this method is used by real firmware and simulator and unit test | |||
388 | 584 | void commonInitEngineController() { | ||
389 | #if EFI_PROD_CODE | |||
390 | addConsoleAction("sensorinfo", printSensorInfo); | |||
391 | addConsoleAction("reset_accel", resetAccel); | |||
392 | #endif /* EFI_PROD_CODE */ | |||
393 | ||||
394 | #if EFI_SIMULATOR || EFI_UNIT_TEST | |||
395 | 584 | printf("commonInitEngineController\n"); | ||
396 | #endif | |||
397 | ||||
398 | #if !EFI_UNIT_TEST | |||
399 | initConfigActions(); | |||
400 | #endif /* EFI_UNIT_TEST */ | |||
401 | ||||
402 | #if EFI_ENGINE_CONTROL | |||
403 | /** | |||
404 | * This has to go after 'enginePins.startPins()' in order to | |||
405 | * properly detect un-assigned output pins | |||
406 | */ | |||
407 | 584 | prepareOutputSignals(); | ||
408 | ||||
409 | 584 | engine->injectionEvents.addFuelEvents(); | ||
410 | #endif // EFI_ENGINE_CONTROL | |||
411 | ||||
412 | ||||
413 | #if EFI_PROD_CODE || EFI_SIMULATOR | |||
414 | initSettings(); | |||
415 | ||||
416 | if (hasFirmwareError()) { | |||
417 | return; | |||
418 | } | |||
419 | #endif | |||
420 | ||||
421 | #if ! EFI_UNIT_TEST && EFI_ENGINE_CONTROL | |||
422 | initBenchTest(); | |||
423 | #endif /* ! EFI_UNIT_TEST && EFI_ENGINE_CONTROL */ | |||
424 | ||||
425 | #if EFI_ALTERNATOR_CONTROL | |||
426 | 584 | initAlternatorCtrl(); | ||
427 | #endif /* EFI_ALTERNATOR_CONTROL */ | |||
428 | ||||
429 | #if EFI_VVT_PID | |||
430 | initVvtActuators(); | |||
431 | #endif /* EFI_VVT_PID */ | |||
432 | ||||
433 | #if EFI_MALFUNCTION_INDICATOR | |||
434 | initMalfunctionIndicator(); | |||
435 | #endif /* EFI_MALFUNCTION_INDICATOR */ | |||
436 | ||||
437 | #if !EFI_UNIT_TEST | |||
438 | // This is tested independently - don't configure sensors for tests. | |||
439 | // This lets us selectively mock them for each test. | |||
440 | initNewSensors(); | |||
441 | #endif /* EFI_UNIT_TEST */ | |||
442 | ||||
443 | 584 | initSensors(); | ||
444 | ||||
445 | 584 | initAccelEnrichment(); | ||
446 | ||||
447 | 584 | initScriptImpl(); | ||
448 | ||||
449 | 584 | initGpPwm(); | ||
450 | ||||
451 | #if EFI_IDLE_CONTROL | |||
452 | 584 | startIdleThread(); | ||
453 | #endif /* EFI_IDLE_CONTROL */ | |||
454 | ||||
455 | #if EFI_TCU | |||
456 | initGearController(); | |||
457 | #endif | |||
458 | ||||
459 | 584 | initButtonDebounce(); | ||
460 | ||||
461 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
462 | 584 | initElectronicThrottle(); | ||
463 | #endif /* EFI_ELECTRONIC_THROTTLE_BODY */ | |||
464 | ||||
465 | #if EFI_MAP_AVERAGING && defined (MODULE_MAP_AVERAGING) | |||
466 | 584 | engine->module<MapAveragingModule>()->init(); | ||
467 | #else | |||
468 | efiPrintf("No MapAveraging support!"); | |||
469 | #endif /* EFI_MAP_AVERAGING */ | |||
470 | ||||
471 | #if EFI_BOOST_CONTROL | |||
472 | 584 | initBoostCtrl(); | ||
473 | #endif /* EFI_BOOST_CONTROL */ | |||
474 | ||||
475 | #if EFI_LAUNCH_CONTROL | |||
476 | 584 | initLaunchControl(); | ||
477 | #endif | |||
478 | ||||
479 | 584 | initIgnitionAdvanceControl(); | ||
480 | ||||
481 | #if EFI_UNIT_TEST | |||
482 | 584 | engine->rpmCalculator.Register(); | ||
483 | #endif /* EFI_UNIT_TEST */ | |||
484 | ||||
485 | #if EFI_AUX_VALVES | |||
486 | 584 | initAuxValves(); | ||
487 | #endif /* EFI_AUX_VALVES */ | |||
488 | ||||
489 | #ifdef MODULE_TACHOMETER | |||
490 | 584 | engine->module<TachometerModule>()->init(); | ||
491 | #endif | |||
492 | ||||
493 | 584 | initSpeedometer(); | ||
494 | ||||
495 | 584 | initStft(); | ||
496 | #if EFI_LTFT_CONTROL | |||
497 | 584 | initLtft(); | ||
498 | #endif | |||
499 | 584 | } | ||
500 | ||||
501 | 584 | PUBLIC_API_WEAK bool validateBoardConfig() { | ||
502 | 584 | return true; | ||
503 | } | |||
504 | ||||
505 | 584 | static bool validateGdi() { | ||
506 | 584 | auto lobes = engineConfiguration->hpfpCamLobes; | ||
507 |
2/2✓ Branch 0 taken 582 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 582 times.
✓ Decision 'false' taken 2 times.
|
584 | if (!lobes) { |
508 | 582 | return true; | ||
509 | } | |||
510 | 2 | int expectedLastLobeProfileAngle = 360 / lobes; | ||
511 | 2 | float actualLastAngle = config->hpfpLobeProfileAngle[efi::size(config->hpfpLobeProfileAngle) - 1]; | ||
512 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (expectedLastLobeProfileAngle != actualLastAngle) { |
513 | ✗ | criticalError("Last HPFP angle expected %d got %f", expectedLastLobeProfileAngle, actualLastAngle); | ||
514 | ✗ | return false; | ||
515 | } | |||
516 | ||||
517 | 2 | return true; | ||
518 | } | |||
519 | ||||
520 | // Returns false if there's an obvious problem with the loaded configuration | |||
521 | 584 | bool validateConfigOnStartUpOrBurn() { | ||
522 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (!validateBoardConfig()) { |
523 | ✗ | return false; | ||
524 | } | |||
525 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (!validateGdi()) { |
526 | ✗ | return false; | ||
527 | } | |||
528 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (engineConfiguration->etbMinimumPosition + 1 >= engineConfiguration->etbMaximumPosition) { |
529 | ✗ | criticalError("Broken ETB min/max %d %d", | ||
530 | engineConfiguration->etbMinimumPosition, | |||
531 | engineConfiguration->etbMaximumPosition); | |||
532 | ✗ | return false; | ||
533 | } | |||
534 | ||||
535 | 584 | defaultsOrFixOnBurn(); | ||
536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (engineConfiguration->cylindersCount > MAX_CYLINDER_COUNT) { |
537 | ✗ | criticalError("Invalid cylinder count: %d", engineConfiguration->cylindersCount); | ||
538 | ✗ | return false; | ||
539 | } | |||
540 | #if EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0) | |||
541 | float maxConfiguredCorr = config->dwellVoltageCorrValues[0]; | |||
542 | for (size_t i = 0;i<efi::size(config->dwellVoltageCorrValues);i++) { | |||
543 | maxConfiguredCorr = std::max(maxConfiguredCorr, (float)config->dwellVoltageCorrValues[i]); | |||
544 | } | |||
545 | float maxConfiguredDwell = config->sparkDwellValues[0]; | |||
546 | for (size_t i = 0;i<efi::size(config->sparkDwellValues);i++) { | |||
547 | maxConfiguredDwell = std::max(maxConfiguredDwell, (float)config->sparkDwellValues[i]); | |||
548 | } | |||
549 | int maxAllowedDwell = getMc33810maxDwellTimer(engineConfiguration->mc33810maxDwellTimer); | |||
550 | if (maxConfiguredCorr * maxConfiguredDwell > maxAllowedDwell) { | |||
551 | criticalError("Dwell=%.2f/corr=%.2f while 33810 limit %d", maxConfiguredDwell, maxConfiguredCorr, maxAllowedDwell); | |||
552 | } | |||
553 | ||||
554 | #endif // EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0) | |||
555 |
2/4✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (engineConfiguration->adcVcc > 5.0f || engineConfiguration->adcVcc < 1.0f) { |
556 | ✗ | criticalError("Invalid adcVcc: %f", engineConfiguration->adcVcc); | ||
557 | ✗ | return false; | ||
558 | } | |||
559 | ||||
560 | 584 | ensureArrayIsAscending("Injector deadtime vBATT", engineConfiguration->injector.battLagCorrBattBins); | ||
561 | 584 | ensureArrayIsAscending("Injector deadtime Pressure", engineConfiguration->injector.battLagCorrPressBins); | ||
562 | ||||
563 | #if EFI_ENGINE_CONTROL | |||
564 | // Fueling | |||
565 | { | |||
566 | 584 | ensureArrayIsAscending("VE load", config->veLoadBins); | ||
567 | 584 | ensureArrayIsAscending("VE RPM", config->veRpmBins); | ||
568 | ||||
569 | 584 | ensureArrayIsAscending("Lambda/AFR load", config->lambdaLoadBins); | ||
570 | 584 | ensureArrayIsAscending("Lambda/AFR RPM", config->lambdaRpmBins); | ||
571 | ||||
572 | 584 | ensureArrayIsAscending("Fuel CLT mult", config->cltFuelCorrBins); | ||
573 | 584 | ensureArrayIsAscending("Fuel IAT mult", config->iatFuelCorrBins); | ||
574 | ||||
575 | 584 | ensureArrayIsAscendingOrDefault("Boost CLT mult", config->cltBoostCorrBins); | ||
576 | 584 | ensureArrayIsAscendingOrDefault("Boost IAT mult", config->iatBoostCorrBins); | ||
577 | ||||
578 | 584 | ensureArrayIsAscending("Injection phase load", config->injPhaseLoadBins); | ||
579 | 584 | ensureArrayIsAscending("Injection phase RPM", config->injPhaseRpmBins); | ||
580 | ||||
581 | 584 | ensureArrayIsAscendingOrDefault("Fuel Level Sensor", config->fuelLevelBins); | ||
582 | ||||
583 | 584 | ensureArrayIsAscendingOrDefault("STFT Rpm", config->fuelTrimRpmBins); | ||
584 | 584 | ensureArrayIsAscendingOrDefault("STFT Load", config->fuelTrimLoadBins); | ||
585 | ||||
586 | 584 | ensureArrayIsAscendingOrDefault("TC slip", engineConfiguration->tractionControlSlipBins); | ||
587 | 584 | ensureArrayIsAscendingOrDefault("TC speed", engineConfiguration->tractionControlSpeedBins); | ||
588 | ||||
589 | 584 | ensureArrayIsAscending("TPS/TPS AE from", config->tpsTpsAccelFromRpmBins); | ||
590 | 584 | ensureArrayIsAscending("TPS/TPS AE to", config->tpsTpsAccelToRpmBins); | ||
591 | ||||
592 | 584 | ensureArrayIsAscendingOrDefault("TPS TPS RPM correction", config->tpsTspCorrValuesBins); | ||
593 | ||||
594 | 584 | ensureArrayIsAscendingOrDefault("Staging Load", config->injectorStagingLoadBins); | ||
595 | 584 | ensureArrayIsAscendingOrDefault("Staging RPM", config->injectorStagingRpmBins); | ||
596 | } | |||
597 | ||||
598 | // Ignition | |||
599 | { | |||
600 | 584 | ensureArrayIsAscending("Dwell RPM", config->sparkDwellRpmBins); | ||
601 | ||||
602 | 584 | ensureArrayIsAscending("Ignition load", config->ignitionLoadBins); | ||
603 | 584 | ensureArrayIsAscending("Ignition RPM", config->ignitionRpmBins); | ||
604 | 584 | ensureArrayIsAscendingOrDefault("Ign Trim Rpm", config->ignTrimRpmBins); | ||
605 | 584 | ensureArrayIsAscendingOrDefault("Ign Trim Load", config->ignTrimLoadBins); | ||
606 | ||||
607 | 584 | ensureArrayIsAscending("Ignition CLT corr CLT", config->ignitionCltCorrTempBins); | ||
608 | 584 | ensureArrayIsAscending("Ignition CLT corr Load", config->ignitionCltCorrLoadBins); | ||
609 | ||||
610 | 584 | ensureArrayIsAscending("Ignition IAT corr IAT", config->ignitionIatCorrTempBins); | ||
611 | 584 | ensureArrayIsAscending("Ignition IAT corr Load", config->ignitionIatCorrLoadBins); | ||
612 | } | |||
613 | ||||
614 | 584 | ensureArrayIsAscendingOrDefault("Map estimate TPS", config->mapEstimateTpsBins); | ||
615 | 584 | ensureArrayIsAscendingOrDefault("Map estimate RPM", config->mapEstimateRpmBins); | ||
616 | #endif // EFI_ENGINE_CONTROL | |||
617 | ||||
618 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 1", config->scriptCurve1Bins); | ||
619 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 2", config->scriptCurve2Bins); | ||
620 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 3", config->scriptCurve3Bins); | ||
621 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 4", config->scriptCurve4Bins); | ||
622 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 5", config->scriptCurve5Bins); | ||
623 | 584 | ensureArrayIsAscendingOrDefault("Script Curve 6", config->scriptCurve6Bins); | ||
624 | ||||
625 | // todo: huh? why does this not work on CI? ensureArrayIsAscendingOrDefault("Dwell Correction Voltage", engineConfiguration->dwellVoltageCorrVoltBins); | |||
626 | ||||
627 | 584 | ensureArrayIsAscending("MAF transfer function", config->mafDecodingBins); | ||
628 | ||||
629 | // Cranking tables | |||
630 | 584 | ensureArrayIsAscending("Cranking fuel mult", config->crankingFuelBins); | ||
631 | 584 | ensureArrayIsAscending("Cranking duration", config->crankingCycleBins); | ||
632 | 584 | ensureArrayIsAscending("Cranking Fuel CLT", config->crankingCycleFuelCltBins); | ||
633 | 584 | ensureArrayIsAscending("Cranking TPS", config->crankingTpsBins); | ||
634 | ||||
635 | // Idle tables | |||
636 | 584 | ensureArrayIsAscending("Idle target RPM", config->cltIdleRpmBins); | ||
637 | 584 | ensureArrayIsAscending("Idle warmup mult CLT", config->cltIdleCorrBins); | ||
638 | 584 | ensureArrayIsAscending("Idle warmup mult RPM", config->rpmIdleCorrBins); | ||
639 | 584 | ensureArrayIsAscendingOrDefault("Idle coasting RPM", config->iacCoastingRpmBins); | ||
640 | 584 | ensureArrayIsAscendingOrDefault("Idle VE RPM", config->idleVeRpmBins); | ||
641 | 584 | ensureArrayIsAscendingOrDefault("Idle VE Load", config->idleVeLoadBins); | ||
642 | 584 | ensureArrayIsAscendingOrDefault("Idle timing", config->idleAdvanceBins); | ||
643 | ||||
644 |
2/2✓ Branch 1 taken 1168 times.
✓ Branch 2 taken 584 times.
|
2/2✓ Decision 'true' taken 1168 times.
✓ Decision 'false' taken 584 times.
|
1752 | for (size_t index = 0; index < efi::size(engineConfiguration->vrThreshold); index++) { |
645 | 1168 | auto& cfg = engineConfiguration->vrThreshold[index]; | ||
646 | ||||
647 |
1/2✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 1168 times.
✗ Decision 'false' not taken.
|
1168 | if (cfg.pin == Gpio::Unassigned) { |
648 | 1168 | continue; | ||
649 | } | |||
650 | ✗ | ensureArrayIsAscending("VR threshold", cfg.rpmBins); | ||
651 | } | |||
652 | ||||
653 | #if EFI_BOOST_CONTROL | |||
654 | // Boost | |||
655 | 584 | ensureArrayIsAscending("Boost control Load [open loop]", config->boostOpenLoopLoadBins); | ||
656 | 584 | ensureArrayIsAscending("Boost control Load [closed loop]", config->boostClosedLoopLoadBins); | ||
657 | 584 | ensureArrayIsAscending("Boost control RPM [open+closed loop]", config->boostRpmBins); | ||
658 | #endif // EFI_BOOST_CONTROL | |||
659 | ||||
660 | #if EFI_ANTILAG_SYSTEM | |||
661 | // ALS | |||
662 | 584 | ensureArrayIsAscendingOrDefault("ign ALS TPS", config->alsIgnRetardLoadBins); | ||
663 | 584 | ensureArrayIsAscendingOrDefault("ign ALS RPM", config->alsIgnRetardrpmBins); | ||
664 | 584 | ensureArrayIsAscendingOrDefault("fuel ALS TPS", config->alsFuelAdjustmentLoadBins); | ||
665 | 584 | ensureArrayIsAscendingOrDefault("fuel ALS RPM", config->alsFuelAdjustmentrpmBins); | ||
666 | #endif // EFI_ANTILAG_SYSTEM | |||
667 | ||||
668 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
669 | // ETB | |||
670 | 584 | ensureArrayIsAscending("Pedal map pedal", config->pedalToTpsPedalBins); | ||
671 | 584 | ensureArrayIsAscending("Pedal map RPM", config->pedalToTpsRpmBins); | ||
672 | #endif // EFI_ELECTRONIC_THROTTLE_BODY | |||
673 | ||||
674 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 582 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 582 times.
|
584 | if (isGdiEngine()) { |
675 | 2 | ensureArrayIsAscending("HPFP compensation", config->hpfpCompensationRpmBins); | ||
676 | 2 | ensureArrayIsAscending("HPFP deadtime", config->hpfpDeadtimeVoltsBins); | ||
677 | 2 | ensureArrayIsAscending("HPFP lobe profile", config->hpfpLobeProfileQuantityBins); | ||
678 | 2 | ensureArrayIsAscending("HPFP target rpm", config->hpfpTargetRpmBins); | ||
679 | 2 | ensureArrayIsAscending("HPFP target load", config->hpfpTargetLoadBins); | ||
680 | ||||
681 | 2 | ensureArrayIsAscending("HPFP fuel mass compensation fuel pressure", config->hpfpFuelMassCompensationFuelPressure); | ||
682 | 2 | ensureArrayIsAscending("HPFP fuel mass compensation fuel mass", config->hpfpFuelMassCompensationFuelMass); | ||
683 | ||||
684 | } | |||
685 | ||||
686 | // VVT | |||
687 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 579 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 579 times.
|
584 | if (isBrainPinValid(engineConfiguration->camInputs[0])) { |
688 | 5 | ensureArrayIsAscending("VVT intake load", config->vvtTable1LoadBins); | ||
689 | 5 | ensureArrayIsAscending("VVT intake RPM", config->vvtTable1RpmBins); | ||
690 | } | |||
691 | ||||
692 | #if CAM_INPUTS_COUNT != 1 | |||
693 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (isBrainPinValid(engineConfiguration->camInputs[1])) { |
694 | ✗ | ensureArrayIsAscending("VVT exhaust load", config->vvtTable2LoadBins); | ||
695 | ✗ | ensureArrayIsAscending("VVT exhaust RPM", config->vvtTable2RpmBins); | ||
696 | } | |||
697 | #endif | |||
698 | ||||
699 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 584 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 584 times.
|
584 | if (engineConfiguration->enableOilPressureProtect) { |
700 | ✗ | ensureArrayIsAscending("Oil pressure protection", config->minimumOilPressureBins); | ||
701 | } | |||
702 | ||||
703 | 584 | return true; | ||
704 | } | |||
705 | ||||
706 | #if !EFI_UNIT_TEST | |||
707 | ||||
708 | void commonEarlyInit() { | |||
709 | // Start this early - it will start LED blinking and such | |||
710 | startStatusThreads(); | |||
711 | ||||
712 | #if EFI_SHAFT_POSITION_INPUT | |||
713 | // todo: figure out better startup logic | |||
714 | initTriggerCentral(); | |||
715 | #endif /* EFI_SHAFT_POSITION_INPUT */ | |||
716 | ||||
717 | /** | |||
718 | * Initialize hardware drivers | |||
719 | */ | |||
720 | initHardware(); | |||
721 | ||||
722 | initQcBenchControls(); | |||
723 | ||||
724 | #if EFI_FILE_LOGGING | |||
725 | initMmcCard(); | |||
726 | #endif /* EFI_FILE_LOGGING */ | |||
727 | ||||
728 | #if EFI_ENGINE_EMULATOR | |||
729 | initEngineEmulator(); | |||
730 | #endif | |||
731 | ||||
732 | #if EFI_LUA | |||
733 | startLua(); | |||
734 | #endif // EFI_LUA | |||
735 | ||||
736 | #if EFI_CAN_SERIAL | |||
737 | // needs to be called after initCan() inside initHardware() | |||
738 | startCanConsole(); | |||
739 | #endif /* EFI_CAN_SERIAL */ | |||
740 | ||||
741 | } | |||
742 | ||||
743 | // one-time start-up | |||
744 | void initRealHardwareEngineController() { | |||
745 | commonInitEngineController(); | |||
746 | initWarningRunningPins(); | |||
747 | ||||
748 | #if EFI_LOGIC_ANALYZER | |||
749 | if (engineConfiguration->isWaveAnalyzerEnabled) { | |||
750 | initWaveAnalyzer(); | |||
751 | } | |||
752 | #endif /* EFI_LOGIC_ANALYZER */ | |||
753 | ||||
754 | if (hasFirmwareError()) { | |||
755 | return; | |||
756 | } | |||
757 | ||||
758 | engineStateBlinkingTask.start(); | |||
759 | ||||
760 | initVrThresholdPwm(); | |||
761 | } | |||
762 | ||||
763 | /** | |||
764 | * See also SIGNATURE_HASH | |||
765 | */ | |||
766 | int getRusEfiVersion() { | |||
767 | #if defined(EFI_BOOTLOADER_INCLUDE_CODE) | |||
768 | // make bootloader code happy too | |||
769 | if (initBootloader() != 0) | |||
770 | return 123; | |||
771 | #endif /* EFI_BOOTLOADER_INCLUDE_CODE */ | |||
772 | return VCS_DATE; | |||
773 | } | |||
774 | #endif /* EFI_UNIT_TEST */ | |||
775 |