GCC Code Coverage Report


Directory: ./
File: firmware/controllers/engine_controller.cpp
Date: 2025-11-16 14:52:24
Coverage Exec Excl Total
Lines: 90.1% 128 0 142
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 592 void initDataStructures() {
103 #if EFI_ENGINE_CONTROL
104 592 initFuelMap();
105 592 initSpeedDensity();
106 592 IgnitionEventList &events = engine->ignitionEvents;
107
2/2
✓ Branch 1 taken 7104 times.
✓ Branch 2 taken 592 times.
2/2
✓ Decision 'true' taken 7104 times.
✓ Decision 'false' taken 592 times.
7696 for (size_t i=0;i<efi::size(events.elements);i++) {
108 // above-zero value helps distinguish events
109 7104 events.elements[i].sparkCounter = 1;
110 }
111 // above-zero value helps distinguish events
112 592 engine->engineState.globalSparkCounter = 1;
113 #endif // EFI_ENGINE_CONTROL
114 592 }
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 591 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 591 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 591 prepareOutputSignals();
406
407 591 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 591 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 591 initSensors();
442
443 591 initAccelEnrichment();
444
445 591 initScriptImpl();
446
447 591 initGpPwm();
448
449 #if EFI_IDLE_CONTROL
450 591 startIdleThread();
451 #endif /* EFI_IDLE_CONTROL */
452
453 #if EFI_TCU
454 591 initGearController();
455 #endif
456
457 591 initButtonDebounce();
458
459 #if EFI_ELECTRONIC_THROTTLE_BODY
460 591 initElectronicThrottle();
461 #endif /* EFI_ELECTRONIC_THROTTLE_BODY */
462
463 #if EFI_MAP_AVERAGING && defined (MODULE_MAP_AVERAGING)
464 591 engine->module<MapAveragingModule>()->init();
465 #else
466 efiPrintf("No MapAveraging support!");
467 #endif /* EFI_MAP_AVERAGING */
468
469 #if EFI_BOOST_CONTROL
470 591 initBoostCtrl();
471 #endif /* EFI_BOOST_CONTROL */
472
473 #if EFI_LAUNCH_CONTROL
474 591 initLaunchControl();
475 #endif
476
477 591 initIgnitionAdvanceControl();
478
479 #if EFI_UNIT_TEST
480 591 engine->rpmCalculator.Register();
481 #endif /* EFI_UNIT_TEST */
482
483 #if EFI_AUX_VALVES
484 591 initAuxValves();
485 #endif /* EFI_AUX_VALVES */
486
487 #ifdef MODULE_TACHOMETER
488 591 engine->module<TachometerModule>()->init();
489 #endif
490
491 591 initSpeedometer();
492
493 591 initStft();
494 #if EFI_LTFT_CONTROL
495 591 initLtft();
496 #endif
497 591 }
498
499 591 PUBLIC_API_WEAK bool validateBoardConfig() {
500 591 return true;
501 }
502
503 591 static bool validateGdi() {
504 591 auto lobes = engineConfiguration->hpfpCamLobes;
505
2/2
✓ Branch 0 taken 589 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 589 times.
✓ Decision 'false' taken 2 times.
591 if (!lobes) {
506 589 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 591 bool validateConfigOnStartUpOrBurn() {
520
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (!validateBoardConfig()) {
521 return false;
522 }
523 #if defined(HW_HELLEN_UAEFI)
524 // todo: make this board-specific validation callback!
525 pickEtbOrStepper();
526 #endif
527
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (!validateGdi()) {
528 return false;
529 }
530
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (engineConfiguration->etbMinimumPosition + 1 >= engineConfiguration->etbMaximumPosition) {
531 criticalError("Broken ETB min/max %d %d",
532 engineConfiguration->etbMinimumPosition,
533 engineConfiguration->etbMaximumPosition);
534 return false;
535 }
536
537 591 defaultsOrFixOnBurn();
538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (engineConfiguration->cylindersCount > MAX_CYLINDER_COUNT) {
539 criticalError("Invalid cylinder count: %d", engineConfiguration->cylindersCount);
540 return false;
541 }
542 #if EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0)
543 float maxConfiguredCorr = config->dwellVoltageCorrValues[0];
544 for (size_t i = 0;i<efi::size(config->dwellVoltageCorrValues);i++) {
545 maxConfiguredCorr = std::max(maxConfiguredCorr, (float)config->dwellVoltageCorrValues[i]);
546 }
547 float maxConfiguredDwell = config->sparkDwellValues[0];
548 for (size_t i = 0;i<efi::size(config->sparkDwellValues);i++) {
549 maxConfiguredDwell = std::max(maxConfiguredDwell, (float)config->sparkDwellValues[i]);
550 }
551 int maxAllowedDwell = getMc33810maxDwellTimer(engineConfiguration->mc33810maxDwellTimer);
552 if (maxConfiguredCorr * maxConfiguredDwell > maxAllowedDwell) {
553 criticalError("Dwell=%.2f/corr=%.2f while 33810 limit %d", maxConfiguredDwell, maxConfiguredCorr, maxAllowedDwell);
554 }
555
556 #endif // EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0)
557
2/4
✓ Branch 0 taken 591 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (engineConfiguration->adcVcc > 5.0f || engineConfiguration->adcVcc < 1.0f) {
558 criticalError("Invalid adcVcc: %f", engineConfiguration->adcVcc);
559 return false;
560 }
561
562 591 ensureArrayIsAscending("Injector deadtime vBATT", engineConfiguration->injector.battLagCorrBattBins);
563 591 ensureArrayIsAscending("Injector deadtime Pressure", engineConfiguration->injector.battLagCorrPressBins);
564
565 #if EFI_ENGINE_CONTROL
566 // Fueling
567 {
568 591 ensureArrayIsAscending("VE load", config->veLoadBins);
569 591 ensureArrayIsAscending("VE RPM", config->veRpmBins);
570
571 591 ensureArrayIsAscending("Lambda/AFR load", config->lambdaLoadBins);
572 591 ensureArrayIsAscending("Lambda/AFR RPM", config->lambdaRpmBins);
573
574 591 ensureArrayIsAscending("Fuel CLT mult", config->cltFuelCorrBins);
575 591 ensureArrayIsAscending("Fuel IAT mult", config->iatFuelCorrBins);
576
577 591 ensureArrayIsAscendingOrDefault("Boost CLT mult", config->cltBoostCorrBins);
578 591 ensureArrayIsAscendingOrDefault("Boost IAT mult", config->iatBoostCorrBins);
579
580 591 ensureArrayIsAscending("Injection phase load", config->injPhaseLoadBins);
581 591 ensureArrayIsAscending("Injection phase RPM", config->injPhaseRpmBins);
582
583 591 ensureArrayIsAscendingOrDefault("Fuel Level Sensor", config->fuelLevelBins);
584
585 591 ensureArrayIsAscendingOrDefault("STFT Rpm", config->fuelTrimRpmBins);
586 591 ensureArrayIsAscendingOrDefault("STFT Load", config->fuelTrimLoadBins);
587
588 591 ensureArrayIsAscendingOrDefault("TC slip", engineConfiguration->tractionControlSlipBins);
589 591 ensureArrayIsAscendingOrDefault("TC speed", engineConfiguration->tractionControlSpeedBins);
590
591 591 ensureArrayIsAscending("TPS/TPS AE from", config->tpsTpsAccelFromRpmBins);
592 591 ensureArrayIsAscending("TPS/TPS AE to", config->tpsTpsAccelToRpmBins);
593
594 591 ensureArrayIsAscendingOrDefault("TPS TPS RPM correction", config->tpsTspCorrValuesBins);
595
596 591 ensureArrayIsAscendingOrDefault("Staging Load", config->injectorStagingLoadBins);
597 591 ensureArrayIsAscendingOrDefault("Staging RPM", config->injectorStagingRpmBins);
598 }
599
600 // Ignition
601 {
602 591 ensureArrayIsAscending("Dwell RPM", config->sparkDwellRpmBins);
603
604 591 ensureArrayIsAscending("Ignition load", config->ignitionLoadBins);
605 591 ensureArrayIsAscending("Ignition RPM", config->ignitionRpmBins);
606 591 ensureArrayIsAscendingOrDefault("Ign Trim Rpm", config->ignTrimRpmBins);
607 591 ensureArrayIsAscendingOrDefault("Ign Trim Load", config->ignTrimLoadBins);
608
609 591 ensureArrayIsAscending("Ignition CLT corr CLT", config->ignitionCltCorrTempBins);
610 591 ensureArrayIsAscending("Ignition CLT corr Load", config->ignitionCltCorrLoadBins);
611
612 591 ensureArrayIsAscending("Ignition IAT corr IAT", config->ignitionIatCorrTempBins);
613 591 ensureArrayIsAscending("Ignition IAT corr Load", config->ignitionIatCorrLoadBins);
614 }
615
616 591 ensureArrayIsAscendingOrDefault("Map estimate TPS", config->mapEstimateTpsBins);
617 591 ensureArrayIsAscendingOrDefault("Map estimate RPM", config->mapEstimateRpmBins);
618 #endif // EFI_ENGINE_CONTROL
619
620 591 ensureArrayIsAscendingOrDefault("Script Curve 1", config->scriptCurve1Bins);
621 591 ensureArrayIsAscendingOrDefault("Script Curve 2", config->scriptCurve2Bins);
622 591 ensureArrayIsAscendingOrDefault("Script Curve 3", config->scriptCurve3Bins);
623 591 ensureArrayIsAscendingOrDefault("Script Curve 4", config->scriptCurve4Bins);
624 591 ensureArrayIsAscendingOrDefault("Script Curve 5", config->scriptCurve5Bins);
625 591 ensureArrayIsAscendingOrDefault("Script Curve 6", config->scriptCurve6Bins);
626
627 // todo: huh? why does this not work on CI? ensureArrayIsAscendingOrDefault("Dwell Correction Voltage", engineConfiguration->dwellVoltageCorrVoltBins);
628
629 591 ensureArrayIsAscending("MAF transfer function", config->mafDecodingBins);
630
631 // Cranking tables
632 591 ensureArrayIsAscending("Cranking fuel mult", config->crankingFuelBins);
633 591 ensureArrayIsAscending("Cranking duration", config->crankingCycleBins);
634 591 ensureArrayIsAscending("Cranking Fuel CLT", config->crankingCycleFuelCltBins);
635 591 ensureArrayIsAscending("Cranking TPS", config->crankingTpsBins);
636
637 // Idle tables
638 591 ensureArrayIsAscending("Idle target RPM", config->cltIdleRpmBins);
639 591 ensureArrayIsAscending("Idle warmup mult CLT", config->cltIdleCorrBins);
640 591 ensureArrayIsAscending("Idle warmup mult RPM", config->rpmIdleCorrBins);
641 591 ensureArrayIsAscendingOrDefault("Idle coasting RPM", config->iacCoastingRpmBins);
642 591 ensureArrayIsAscendingOrDefault("Idle VE RPM", config->idleVeRpmBins);
643 591 ensureArrayIsAscendingOrDefault("Idle VE Load", config->idleVeLoadBins);
644 591 ensureArrayIsAscendingOrDefault("Idle timing", config->idleAdvanceBins);
645
646
2/2
✓ Branch 1 taken 1182 times.
✓ Branch 2 taken 591 times.
2/2
✓ Decision 'true' taken 1182 times.
✓ Decision 'false' taken 591 times.
1773 for (size_t index = 0; index < efi::size(engineConfiguration->vrThreshold); index++) {
647 1182 auto& cfg = engineConfiguration->vrThreshold[index];
648
649
1/2
✓ Branch 0 taken 1182 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1182 times.
✗ Decision 'false' not taken.
1182 if (cfg.pin == Gpio::Unassigned) {
650 1182 continue;
651 }
652 ensureArrayIsAscending("VR threshold", cfg.rpmBins);
653 }
654
655 #if EFI_BOOST_CONTROL
656 // Boost
657 591 ensureArrayIsAscending("Boost control Load [open loop]", config->boostOpenLoopLoadBins);
658 591 ensureArrayIsAscending("Boost control Load [closed loop]", config->boostClosedLoopLoadBins);
659 591 ensureArrayIsAscending("Boost control RPM [open+closed loop]", config->boostRpmBins);
660 #endif // EFI_BOOST_CONTROL
661
662 #if EFI_ANTILAG_SYSTEM
663 // ALS
664 591 ensureArrayIsAscendingOrDefault("ign ALS TPS", config->alsIgnRetardLoadBins);
665 591 ensureArrayIsAscendingOrDefault("ign ALS RPM", config->alsIgnRetardrpmBins);
666 591 ensureArrayIsAscendingOrDefault("fuel ALS TPS", config->alsFuelAdjustmentLoadBins);
667 591 ensureArrayIsAscendingOrDefault("fuel ALS RPM", config->alsFuelAdjustmentrpmBins);
668 #endif // EFI_ANTILAG_SYSTEM
669
670 #if EFI_ELECTRONIC_THROTTLE_BODY
671 // ETB
672 591 ensureArrayIsAscending("Pedal map pedal", config->pedalToTpsPedalBins);
673 591 ensureArrayIsAscending("Pedal map RPM", config->pedalToTpsRpmBins);
674 #endif // EFI_ELECTRONIC_THROTTLE_BODY
675
676
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 589 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 589 times.
591 if (isGdiEngine()) {
677 2 ensureArrayIsAscending("HPFP compensation", config->hpfpCompensationRpmBins);
678 2 ensureArrayIsAscending("HPFP deadtime", config->hpfpDeadtimeVoltsBins);
679 2 ensureArrayIsAscending("HPFP lobe profile", config->hpfpLobeProfileQuantityBins);
680 2 ensureArrayIsAscending("HPFP target rpm", config->hpfpTargetRpmBins);
681 2 ensureArrayIsAscending("HPFP target load", config->hpfpTargetLoadBins);
682
683 2 ensureArrayIsAscending("HPFP fuel mass compensation fuel pressure", config->hpfpFuelMassCompensationFuelPressure);
684 2 ensureArrayIsAscending("HPFP fuel mass compensation fuel mass", config->hpfpFuelMassCompensationFuelMass);
685
686 }
687
688 // VVT
689
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 586 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 586 times.
591 if (isBrainPinValid(engineConfiguration->camInputs[0])) {
690 5 ensureArrayIsAscending("VVT intake load", config->vvtTable1LoadBins);
691 5 ensureArrayIsAscending("VVT intake RPM", config->vvtTable1RpmBins);
692 }
693
694 #if CAM_INPUTS_COUNT != 1
695
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (isBrainPinValid(engineConfiguration->camInputs[1])) {
696 ensureArrayIsAscending("VVT exhaust load", config->vvtTable2LoadBins);
697 ensureArrayIsAscending("VVT exhaust RPM", config->vvtTable2RpmBins);
698 }
699 #endif
700
701
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 591 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 591 times.
591 if (engineConfiguration->enableOilPressureProtect) {
702 ensureArrayIsAscending("Oil pressure protection", config->minimumOilPressureBins);
703 }
704
705 591 ConfigurationWizard::onConfigOnStartUpOrBurn();
706
707 591 return true;
708 }
709
710 #if !EFI_UNIT_TEST
711
712 void commonEarlyInit() {
713 // Start this early - it will start LED blinking and such
714 startStatusThreads();
715
716 #if EFI_SHAFT_POSITION_INPUT
717 // todo: figure out better startup logic
718 initTriggerCentral();
719 #endif /* EFI_SHAFT_POSITION_INPUT */
720
721 /**
722 * Initialize hardware drivers
723 */
724 initHardware();
725
726 initQcBenchControls();
727
728 #if EFI_FILE_LOGGING
729 initMmcCard();
730 #endif /* EFI_FILE_LOGGING */
731
732 #if EFI_ENGINE_EMULATOR
733 initEngineEmulator();
734 #endif
735
736 #if EFI_LUA
737 startLua();
738 #endif // EFI_LUA
739
740 #if EFI_CAN_SERIAL
741 // needs to be called after initCan() inside initHardware()
742 startCanConsole();
743 #endif /* EFI_CAN_SERIAL */
744
745 }
746
747 // one-time start-up
748 void initRealHardwareEngineController() {
749 commonInitEngineController();
750 initWarningRunningPins();
751
752 #if EFI_LOGIC_ANALYZER
753 if (engineConfiguration->isWaveAnalyzerEnabled) {
754 initWaveAnalyzer();
755 }
756 #endif /* EFI_LOGIC_ANALYZER */
757
758 if (hasFirmwareError()) {
759 return;
760 }
761
762 engineStateBlinkingTask.start();
763
764 initVrThresholdPwm();
765 }
766
767 /**
768 * See also SIGNATURE_HASH
769 */
770 int getRusEfiVersion() {
771 #if defined(EFI_BOOTLOADER_INCLUDE_CODE)
772 // make bootloader code happy too
773 if (initBootloader() != 0)
774 return 123;
775 #endif /* EFI_BOOTLOADER_INCLUDE_CODE */
776 return VCS_DATE;
777 }
778 #endif /* EFI_UNIT_TEST */
779