GCC Code Coverage Report


Directory: ./
File: firmware/controllers/engine_controller.cpp
Date: 2025-10-24 14:26:41
Coverage Exec Excl Total
Lines: 90.0% 126 0 140
Functions: 100.0% 5 0 5
Branches: 66.7% 20 0 30
Decisions: 67.9% 19 - 28

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