GCC Code Coverage Report


Directory: ./
File: firmware/controllers/engine_controller.cpp
Date: 2025-10-03 00:57:22
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 #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