GCC Code Coverage Report


Directory: ./
File: firmware/controllers/bench_test.cpp
Date: 2025-10-24 14:26:41
Coverage Exec Excl Total
Lines: 100.0% 4 0 4
Functions: 100.0% 2 0 2
Branches: -% 0 0 0
Decisions: -% 0 - 0

Line Branch Decision Exec Source
1 /**
2 * @file bench_test.cpp
3 * @brief Utility methods related to bench testing.
4 *
5 *
6 * @date Sep 8, 2013
7 * @author Andrey Belomutskiy, (c) 2012-2020
8 *
9 * This file is part of rusEfi - see http://rusefi.com
10 *
11 * rusEfi is free software; you can redistribute it and/or modify it under the terms of
12 * the GNU General Public License as published by the Free Software Foundation; either
13 * version 3 of the License, or (at your option) any later version.
14 *
15 * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
16 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along with this program.
20 * If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "pch.h"
24 #include "tunerstudio.h"
25 #include "tunerstudio_calibration_channel.h"
26 #include "long_term_fuel_trim.h"
27 #include "can_common.h"
28 #include "can_rx.h"
29 #include "value_lookup.h"
30 #include "can_msg_tx.h"
31
32 #include "fw_configuration.h"
33 #include "board_overrides.h"
34
35 static bool isRunningBench = false;
36 static OutputPin *outputOnTheBenchTest = nullptr;
37
38 2093 bool isRunningBenchTest() {
39 2093 return isRunningBench;
40 }
41
42 42123 const OutputPin *getOutputOnTheBenchTest() {
43 42123 return outputOnTheBenchTest;
44 }
45
46 #if !EFI_UNIT_TEST
47
48 #include "flash_main.h"
49 #include "bench_test.h"
50 #include "main_trigger_callback.h"
51 #include "periodic_thread_controller.h"
52 #include "electronic_throttle.h"
53 #include "electronic_throttle_impl.h"
54 #include "malfunction_central.h"
55 #include "trigger_emulator_algo.h"
56 #include "vvt.h"
57 #include "microsecond_timer.h"
58 #include "rusefi_wideband.h"
59
60 #if EFI_PROD_CODE
61 #include "rusefi.h"
62 #include "mpu_util.h"
63 #endif /* EFI_PROD_CODE */
64
65 #if (BOARD_TLE8888_COUNT > 0)
66 #include "gpio/tle8888.h"
67 #endif // BOARD_TLE8888_COUNT
68
69 #if EFI_FILE_LOGGING
70 #include "mmc_card.h"
71 #endif
72
73 static scheduling_s benchSchedStart;
74 static scheduling_s benchSchedEnd;
75
76 #if EFI_SIMULATOR
77 static int savedPinToggleCounter = 0;
78 static uint32_t savedDurationsInStateMs[2] = { 0, 0 };
79 #endif // EFI_SIMULATOR
80
81
82 #define BENCH_MSG "bench"
83
84 static void benchOn(OutputPin* output) {
85 output->setValue(BENCH_MSG, true, /*isForce*/ true);
86 }
87
88 static void benchOff(OutputPin* output) {
89 #if EFI_PROD_CODE && (BOARD_EXT_GPIOCHIPS > 0)
90 static char pin_error[64];
91
92 brain_pin_diag_e diag = output->getDiag();
93 if (diag == PIN_UNKNOWN) {
94 efiPrintf("No Diag on this pin");
95 } else {
96 pinDiag2string(pin_error, sizeof(pin_error), diag);
97 efiPrintf("Diag says %s", pin_error);
98 }
99 #endif // EFI_PROD_CODE
100 output->setValue(BENCH_MSG, false, /*isForce*/ true);
101 }
102
103 static void runBench(OutputPin *output, float onTimeMs, float offTimeMs, int count, bool swapOnOff) {
104 int onTimeUs = MS2US(std::max(0.1f, onTimeMs));
105 int offTimeUs = MS2US(std::max(0.1f, offTimeMs));
106
107 if (onTimeUs > TOO_FAR_INTO_FUTURE_US) {
108 firmwareError(ObdCode::CUSTOM_ERR_BENCH_PARAM, "onTime above limit %dus", TOO_FAR_INTO_FUTURE_US);
109 return;
110 }
111
112 efiPrintf("Running bench: ON_TIME=%d us OFF_TIME=%d us Counter=%d", onTimeUs, offTimeUs, count);
113 efiPrintf("output on %s", hwPortname(output->brainPin));
114
115 isRunningBench = true;
116 outputOnTheBenchTest = output;
117
118 for (int i = 0; isRunningBench && i < count; i++) {
119 engine->outputChannels.testBenchIter = i;
120 efitick_t nowNt = getTimeNowNt();
121 // start in a short time so the scheduler can precisely schedule the start event
122 efitick_t startTime = nowNt + US2NT(50);
123 efitick_t endTime = startTime + US2NT(onTimeUs);
124
125 auto const bstartAction{ swapOnOff ? action_s::make<benchOff>(output) : action_s::make<benchOn>(output) };
126 auto const bendAction{ swapOnOff ? action_s::make<benchOn>(output) : action_s::make<benchOff>(output) };
127
128 // Schedule both events
129 engine->scheduler.schedule("bstart", &benchSchedStart, startTime, bstartAction);
130 engine->scheduler.schedule("bend", &benchSchedEnd, endTime, bendAction);
131
132 // Wait one full cycle time for the event + delay to happen
133 chThdSleepMicroseconds(onTimeUs + offTimeUs);
134 }
135 /* last */
136 engine->outputChannels.testBenchIter++;
137
138 #if EFI_SIMULATOR
139 // save the current counters and durations after the test while the pin is still controlled
140 savedPinToggleCounter = output->pinToggleCounter;
141 savedDurationsInStateMs[0] = output->durationsInStateMs[0];
142 savedDurationsInStateMs[1] = output->durationsInStateMs[1];
143 #endif // EFI_SIMULATOR
144
145 efiPrintf("Done!");
146 outputOnTheBenchTest = nullptr;
147 isRunningBench = false;
148 }
149
150 // todo: migrate to smarter getOutputOnTheBenchTest() approach?
151 static volatile bool isBenchTestPending = false;
152 static bool widebandUpdatePending = false;
153 static uint8_t widebandUpdateHwId = 0;
154 static float globalOnTimeMs;
155 static float globalOffTimeMs;
156 static int globalCount;
157 static OutputPin* pinX;
158 static bool swapOnOff = false;
159
160 static chibios_rt::CounterSemaphore benchSemaphore(0);
161
162 static void pinbench(float ontimeMs, float offtimeMs, int iterations,
163 OutputPin* pinParam, bool p_swapOnOff = false)
164 {
165 globalOnTimeMs = ontimeMs;
166 globalOffTimeMs = offtimeMs;
167 #if EFI_SIMULATOR
168 globalCount = maxI(2, iterations);
169 #else
170 globalCount = iterations;
171 #endif // EFI_SIMULATOR
172 pinX = pinParam;
173 swapOnOff = p_swapOnOff;
174 // let's signal bench thread to wake up
175 isBenchTestPending = true;
176 benchSemaphore.signal();
177 }
178
179 static void cancelBenchTest() {
180 isRunningBench = false;
181 }
182
183 /*==========================================================================*/
184
185 static void doRunFuelInjBench(size_t humanIndex, float onTimeMs, float offTimeMs, int count) {
186 if (humanIndex < 1 || humanIndex > engineConfiguration->cylindersCount) {
187 efiPrintf("Invalid index: %d", humanIndex);
188 return;
189 }
190 pinbench(onTimeMs, offTimeMs, count,
191 &enginePins.injectors[humanIndex - 1]);
192 }
193
194 static void doRunSparkBench(size_t humanIndex, float onTime, float offTime, int count) {
195 if (humanIndex < 1 || humanIndex > engineConfiguration->cylindersCount) {
196 efiPrintf("Invalid index: %d", humanIndex);
197 return;
198 }
199 pinbench(onTime, offTime, count, &enginePins.coils[humanIndex - 1]);
200 }
201
202 static void doRunSolenoidBench(size_t humanIndex, float onTime, float offTime, int count) {
203 if (humanIndex < 1 || humanIndex > TCU_SOLENOID_COUNT) {
204 efiPrintf("Invalid index: %d", humanIndex);
205 return;
206 }
207 pinbench(onTime, offTime, count, &enginePins.tcuSolenoids[humanIndex - 1]);
208 }
209
210 static void doRunBenchTestLuaOutput(size_t humanIndex, float onTimeMs, float offTimeMs, int count) {
211 if (humanIndex < 1 || humanIndex > LUA_PWM_COUNT) {
212 efiPrintf("Invalid index: %d", humanIndex);
213 return;
214 }
215 pinbench(onTimeMs, offTimeMs, count,
216 &enginePins.luaOutputPins[humanIndex - 1]);
217 }
218
219 /**
220 * cylinder #2, 5ms ON, 1000ms OFF, repeat 3 times
221 * fuelInjBenchExt 2 5 1000 3
222 */
223 static void fuelInjBenchExt(float humanIndex, float onTimeMs, float offTimeMs, float count) {
224 doRunFuelInjBench((int)humanIndex, onTimeMs, offTimeMs, (int)count);
225 }
226
227 /**
228 * fuelbench 5 1000 2
229 */
230 static void fuelInjBench(float onTimeMs, float offTimeMs, float count) {
231 fuelInjBenchExt(1, onTimeMs, offTimeMs, count);
232 }
233
234 /**
235 * sparkbench2 1 5 1000 2
236 */
237 static void sparkBenchExt(float humanIndex, float onTime, float offTimeMs, float count) {
238 doRunSparkBench((int)humanIndex, onTime, offTimeMs, (int)count);
239 }
240
241 /**
242 * sparkbench 5 400 2
243 * 5 ms ON, 400 ms OFF, two times
244 */
245 static void sparkBench(float onTime, float offTimeMs, float count) {
246 sparkBenchExt(1, onTime, offTimeMs, count);
247 }
248
249 /**
250 * solenoid #2, 1000ms ON, 1000ms OFF, repeat 3 times
251 * tcusolbench 2 1000 1000 3
252 */
253 static void tcuSolenoidBench(float humanIndex, float onTime, float offTimeMs, float count) {
254 doRunSolenoidBench((int)humanIndex, onTime, offTimeMs, (int)count);
255 }
256
257 static void fanBenchExt(float onTimeMs) {
258 pinbench(onTimeMs, 100.0, 1, &enginePins.fanRelay);
259 }
260
261 void fanBench() {
262 fanBenchExt(BENCH_FAN_DURATION);
263 }
264
265 void fan2Bench() {
266 pinbench(3000.0, 100.0, 1, &enginePins.fanRelay2);
267 }
268
269 /**
270 * we are blinking for 16 seconds so that one can click the button and walk around to see the light blinking
271 */
272 void milBench() {
273 pinbench(500.0, 500.0, 16, &enginePins.checkEnginePin);
274 }
275
276 void starterRelayBench() {
277 pinbench(BENCH_STARTER_DURATION, 100.0, 1, &enginePins.starterControl);
278 }
279
280 static void fuelPumpBenchExt(float durationMs) {
281 pinbench(durationMs, 100.0, 1,
282 &enginePins.fuelPumpRelay);
283 }
284
285 void acRelayBench() {
286 pinbench(BENCH_AC_RELAY_DURATION, 100.0, 1, &enginePins.acRelay);
287 }
288
289 static void mainRelayBench() {
290 pinbench(BENCH_MAIN_RELAY_DURATION, 100.0, 1, &enginePins.mainRelay, true);
291 }
292
293 static void hpfpValveBench() {
294 pinbench(engineConfiguration->benchTestOnTime, engineConfiguration->benchTestOffTime, engineConfiguration->benchTestCount,
295 &enginePins.hpfpValve);
296 }
297
298 void fuelPumpBench() {
299 fuelPumpBenchExt(BENCH_FUEL_PUMP_DURATION);
300 }
301
302 static void vvtValveBench(int vvtIndex) {
303 #if EFI_VVT_PID
304 pinbench(BENCH_VVT_DURATION, 100.0, 1, getVvtOutputPin(vvtIndex));
305 #endif // EFI_VVT_PID
306 }
307
308 static void requestWidebandUpdate(int hwIndex)
309 {
310 widebandUpdateHwId = hwIndex;
311 widebandUpdatePending = true;
312 benchSemaphore.signal();
313 }
314
315 class BenchController : public ThreadController<UTILITY_THREAD_STACK_SIZE> {
316 public:
317 BenchController() : ThreadController("BenchTest", PRIO_BENCH_TEST) { }
318 private:
319 void ThreadTask() override {
320 while (true) {
321 benchSemaphore.wait();
322
323 assertStackVoid("Bench", ObdCode::STACK_USAGE_MISC, EXPECTED_REMAINING_STACK);
324
325 if (isBenchTestPending) {
326 isBenchTestPending = false;
327 runBench(pinX, globalOnTimeMs, globalOffTimeMs, globalCount, swapOnOff);
328 }
329
330 if (widebandUpdatePending) {
331 #if EFI_WIDEBAND_FIRMWARE_UPDATE && EFI_CAN_SUPPORT
332 updateWidebandFirmware(widebandUpdateHwId);
333 #endif
334 widebandUpdatePending = false;
335 }
336 }
337 }
338 };
339
340 static BenchController instance;
341
342 static void auxOutBench(int index) {
343 // todo!
344 UNUSED(index);
345 }
346
347 #if EFI_HD_ACR
348 static void hdAcrBench(int index) {
349 OutputPin* pin = index == 0 ? &enginePins.harleyAcr : &enginePins.harleyAcr2;
350 pinbench(BENCH_AC_RELAY_DURATION, 100.0, 1, pin);
351 }
352 #endif // EFI_HD_ACR
353
354 int luaCommandCounters[LUA_BUTTON_COUNT] = {};
355
356 void handleBenchCategory(uint16_t index) {
357 switch(index) {
358 case BENCH_VVT0_VALVE:
359 vvtValveBench(0);
360 return;
361 case BENCH_VVT1_VALVE:
362 vvtValveBench(1);
363 return;
364 case BENCH_VVT2_VALVE:
365 vvtValveBench(2);
366 return;
367 case BENCH_VVT3_VALVE:
368 vvtValveBench(3);
369 return;
370 case BENCH_AUXOUT0:
371 auxOutBench(0);
372 return;
373 case BENCH_AUXOUT1:
374 auxOutBench(1);
375 return;
376 case BENCH_AUXOUT2:
377 auxOutBench(2);
378 return;
379 case BENCH_AUXOUT3:
380 auxOutBench(3);
381 return;
382 case BENCH_AUXOUT4:
383 auxOutBench(4);
384 return;
385 case BENCH_AUXOUT5:
386 auxOutBench(5);
387 return;
388 case BENCH_AUXOUT6:
389 auxOutBench(6);
390 return;
391 case BENCH_AUXOUT7:
392 auxOutBench(7);
393 return;
394 case LUA_COMMAND_1:
395 luaCommandCounters[0]++;
396 return;
397 case LUA_COMMAND_2:
398 luaCommandCounters[1]++;
399 return;
400 case LUA_COMMAND_3:
401 luaCommandCounters[2]++;
402 return;
403 case LUA_COMMAND_4:
404 luaCommandCounters[3]++;
405 return;
406 #if EFI_LTFT_CONTROL
407 case LTFT_RESET:
408 resetLongTermFuelTrim();
409 return;
410 case LTFT_APPLY_TO_VE:
411 applyLongTermFuelTrimToVe();
412 return;
413 case LTFT_DEV_POKE:
414 devPokeLongTermFuelTrim();
415 return;
416 #endif // EFI_LTFT_CONTROL
417 #if EFI_HD_ACR
418 case HD_ACR:
419 hdAcrBench(0);
420 return;
421 case HD_ACR2:
422 hdAcrBench(1);
423 return;
424 #endif // EFI_HD_ACR
425 case BENCH_HPFP_VALVE:
426 hpfpValveBench();
427 return;
428 case BENCH_FUEL_PUMP:
429 // cmd_test_fuel_pump
430 fuelPumpBench();
431 return;
432 case BENCH_MAIN_RELAY:
433 mainRelayBench();
434 return;
435 case BENCH_STARTER_ENABLE_RELAY:
436 starterRelayBench();
437 return;
438 case BENCH_CHECK_ENGINE_LIGHT:
439 // cmd_test_check_engine_light
440 milBench();
441 return;
442 case BENCH_AC_COMPRESSOR_RELAY:
443 acRelayBench();
444 return;
445 case BENCH_FAN_RELAY:
446 fanBench();
447 return;
448 case BENCH_IDLE_VALVE:
449 // cmd_test_idle_valve
450 #if EFI_IDLE_CONTROL
451 startIdleBench();
452 #endif /* EFI_IDLE_CONTROL */
453 return;
454 case BENCH_FAN_RELAY_2:
455 fan2Bench();
456 return;
457 case BENCH_CANCEL:
458 cancelBenchTest();
459 return;
460 default:
461 criticalError("Unexpected bench function %d", index);
462 }
463 }
464
465 int getSavedBenchTestPinStates(uint32_t durationsInStateMs[2]) {
466 #if EFI_SIMULATOR
467 durationsInStateMs[0] = savedDurationsInStateMs[0];
468 durationsInStateMs[1] = savedDurationsInStateMs[1];
469 return savedPinToggleCounter;
470 #else
471 UNUSED(durationsInStateMs);
472 return 0;
473 #endif // EFI_SIMULATOR
474 }
475
476 static void handleCommandX14(uint16_t index) {
477 // todo: define ts_14_command magic constants and use those in tunerstudio.template.ini file!
478 switch (index) {
479 case TS_GRAB_PEDAL_UP:
480 grabPedalIsUp();
481 return;
482 case TS_GRAB_PEDAL_WOT:
483 grabPedalIsWideOpen();
484 return;
485 case TS_GRAB_TPS_CLOSED:
486 grapTps1PrimaryIsClosed();
487 return;
488 case TS_GRAB_TPS_OPEN:
489 grapTps1PrimaryIsOpen();
490 return;
491 case TS_RESET_TLE8888:
492 #if (BOARD_TLE8888_COUNT > 0)
493 tle8888_req_init();
494 #endif
495 return;
496 case TS_RESET_MC33810:
497 #if EFI_PROD_CODE && (BOARD_MC33810_COUNT > 0)
498 mc33810_req_init();
499 #endif
500 return;
501 #if EFI_SHAFT_POSITION_INPUT
502 case TS_START_STOP_ENGINE:
503 // this is different from starter relay bench test!
504 startStopButtonToggle();
505 return;
506 #endif // EFI_SHAFT_POSITION_INPUT
507 case TS_WRITE_FLASH:
508 // cmd_write_config
509 #if EFI_CONFIGURATION_STORAGE
510 writeToFlashNow();
511 #endif /* EFI_CONFIGURATION_STORAGE */
512 return;
513 case TS_TRIGGER_STIMULATOR_ENABLE:
514 #if EFI_EMULATE_POSITION_SENSORS == TRUE
515 enableTriggerStimulator();
516 #endif /* EFI_EMULATE_POSITION_SENSORS == TRUE */
517 return;
518 case TS_TRIGGER_STIMULATOR_DISABLE:
519 #if EFI_EMULATE_POSITION_SENSORS == TRUE
520 disableTriggerStimulator();
521 #endif /* EFI_EMULATE_POSITION_SENSORS == TRUE */
522 return;
523 case TS_EXTERNAL_TRIGGER_STIMULATOR_ENABLE:
524 #if EFI_EMULATE_POSITION_SENSORS == TRUE
525 enableExternalTriggerStimulator();
526 #endif /* EFI_EMULATE_POSITION_SENSORS == TRUE */
527 return;
528 /*
529 case TS_ETB_RESET:
530 #if EFI_ELECTRONIC_THROTTLE_BODY == TRUE
531 #if EFI_PROD_CODE
532 etbPidReset();
533 #endif
534 #endif // EFI_ELECTRONIC_THROTTLE_BODY
535 return;
536 */
537 #if EFI_ELECTRONIC_THROTTLE_BODY
538 case TS_ETB_AUTOCAL_0:
539 etbAutocal(DC_Throttle1);
540 return;
541 case TS_ETB_AUTOCAL_1:
542 etbAutocal(DC_Throttle2);
543 return;
544 case TS_ETB_AUTOCAL_0_FAST:
545 etbAutocal(DC_Throttle1, false);
546 return;
547 case TS_ETB_AUTOCAL_1_FAST:
548 etbAutocal(DC_Throttle2, false);
549 return;
550 case TS_ETB_START_AUTOTUNE:
551 engine->etbAutoTune = true;
552 return;
553 case TS_ETB_STOP_AUTOTUNE:
554 engine->etbAutoTune = false;
555 #if EFI_TUNER_STUDIO
556 tsCalibrationSetIdle();
557 #endif // EFI_TUNER_STUDIO
558 return;
559 case TS_ETB_DISABLE_JAM_DETECT:
560 engine->etbIgnoreJamProtection = true;
561 return;
562 case TS_EWG_AUTOCAL_0:
563 etbAutocal(DC_Wastegate);
564 return;
565 case TS_EWG_AUTOCAL_0_FAST:
566 etbAutocal(DC_Wastegate, false);
567 return;
568 #endif // EFI_ELECTRONIC_THROTTLE_BODY
569 case TS_WIDEBAND_UPDATE:
570 // broadcast, for old WBO FWs
571 requestWidebandUpdate(0xff);
572 return;
573 case COMMAND_X14_UNUSED_15:
574 return;
575
576 #if EFI_PROD_CODE && EFI_FILE_LOGGING
577 case TS_SD_MOUNT_PC:
578 sdCardRequestMode(SD_MODE_PC);
579 return;
580 case TS_SD_MOUNT_ECU:
581 sdCardRequestMode(SD_MODE_ECU);
582 return;
583 case TS_SD_UNMOUNT:
584 sdCardRequestMode(SD_MODE_UNMOUNT);
585 return;
586 case TS_SD_FORMAT:
587 sdCardRequestMode(SD_MODE_FORMAT);
588 return;
589 case TS_SD_DELETE_REPORTS:
590 sdCardRemoveReportFiles();
591 return;
592 #endif // EFI_FILE_LOGGING
593
594 default:
595 criticalError("Unexpected bench x14 %d", index);
596 }
597 }
598
599 extern bool rebootForPresetPending;
600
601 static void applyPreset(int index) {
602 setEngineType(index);
603 #if EFI_TUNER_STUDIO
604 onApplyPreset();
605 #endif // EFI_TUNER_STUDIO
606 }
607
608 // placeholder to force custom_board_ts_command migration
609 void boardTsAction(uint16_t index) { UNUSED(index); }
610
611 #if EFI_CAN_SUPPORT
612 /**
613 * for example to bench test injector 1
614 * 0x77000C 0x66 0x00 ?? ?? ?? ??
615 * 0x77000C 0x66 0x00 0x14 0x00 0x09 0x00 start/stop engine
616 *
617 * See also more complicated ISO-TP CANBus wrapper of complete TS protocol
618 */
619 static void processCanUserControl(const CANRxFrame& frame) {
620 // reserved data8[1]
621 uint16_t subsystem = getTwoBytesLsb(frame, 2);
622 uint16_t index = getTwoBytesLsb(frame, 4);
623 executeTSCommand(subsystem, index);
624 }
625
626 union FloatIntBytes {
627 float f;
628 int i;
629 uint8_t bytes[sizeof(float)];
630 };
631
632 static void processCanSetCalibration(const CANRxFrame& frame) {
633 // todo allow changes of scalar settings via CANbus
634 UNUSED(frame);
635 }
636 /**
637 * CANbus protocol to query scalar calibrations using hash keys
638 *
639 * see fields_api.txt for well-known fields
640 * see generated_fields_api_header.h for corresponding hashes
641 */
642 static void processCanRequestCalibration(const CANRxFrame& frame) {
643 #if EFI_LUA_LOOKUP
644 int hash = getFourBytesLsb(frame, 2);
645 efiPrintf("processCanRequestCalibration=%x", hash);
646 FloatIntBytes fb;
647 fb.f = getConfigValueByHash(hash);
648
649 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::ECU_GET_CALIBRATION, 8, /*bus*/0, /*isExtended*/true);
650 for (size_t i = 0;i<sizeof(float);i++) {
651 msg[4 + i] = fb.bytes[i];
652 }
653
654 fb.i = hash;
655 // first half of the packed is copy of that hash value so that recipients know what they are processing
656 for (size_t i = 0;i<sizeof(float);i++) {
657 msg[i] = fb.bytes[i];
658 }
659 #endif // EFI_LUA_LOOKUP
660 }
661
662 void processCanEcuControl(const CANRxFrame& frame) {
663 if (frame.data8[0] != (int)bench_test_magic_numbers_e::BENCH_HEADER) {
664 return;
665 }
666
667 int eid = CAN_EID(frame);
668 if (eid == (int)bench_test_packet_ids_e::ECU_SET_CALIBRATION) {
669 processCanSetCalibration(frame);
670 } else if (eid == (int)bench_test_packet_ids_e::ECU_REQ_CALIBRATION) {
671 processCanRequestCalibration(frame);
672 } else if (eid == (int)bench_test_packet_ids_e::ECU_CAN_BUS_USER_CONTROL) {
673 processCanUserControl(frame);
674 }
675 }
676
677 #endif // EFI_CAN_SUPPORT
678
679 std::optional<setup_custom_board_ts_command_override_type> custom_board_ts_command;
680
681 void executeTSCommand(uint16_t subsystem, uint16_t index) {
682 efiPrintf("IO test subsystem=%d index=%d", subsystem, index);
683
684 bool running = !engine->rpmCalculator.isStopped();
685
686 switch (subsystem) {
687 case TS_CLEAR_WARNINGS:
688 clearWarnings();
689 break;
690
691 case TS_DEBUG_MODE:
692 engineConfiguration->debugMode = (debug_mode_e)index;
693 break;
694
695 case TS_IGNITION_CATEGORY:
696 if (!running) {
697 doRunSparkBench(index, engineConfiguration->benchTestOnTime,
698 engineConfiguration->benchTestOffTime, engineConfiguration->benchTestCount);
699 }
700 break;
701
702 case TS_INJECTOR_CATEGORY:
703 if (!running) {
704 doRunFuelInjBench(index, engineConfiguration->benchTestOnTime,
705 engineConfiguration->benchTestOffTime, engineConfiguration->benchTestCount);
706 }
707 break;
708
709 case TS_SOLENOID_CATEGORY:
710 if (!running) {
711 doRunSolenoidBench(index, 1000.0,
712 1000.0, engineConfiguration->benchTestCount);
713 }
714 break;
715
716 case TS_LUA_OUTPUT_CATEGORY:
717 if (!running) {
718 doRunBenchTestLuaOutput(index, 4.0,
719 engineConfiguration->benchTestOffTime, engineConfiguration->benchTestCount);
720 }
721 break;
722
723 case TS_X14:
724 handleCommandX14(index);
725 break;
726 #if EFI_CAN_SUPPORT
727 case TS_WIDEBAND:
728 setWidebandOffset(0xff, index);
729 break;
730 case TS_WIDEBAND_SET_IDX_BY_ID:
731 {
732 uint8_t hwIndex = index >> 8;
733 uint8_t canIndex = index & 0xff;
734
735 // Hack until we fix canReWidebandHwIndex and set "Broadcast" to 0xff
736 // TODO:
737 hwIndex = hwIndex < 8 ? hwIndex : 0xff;
738 setWidebandOffset(hwIndex, canIndex);
739 }
740 break;
741 case TS_WIDEBAND_SET_SENS_BY_ID:
742 {
743 uint8_t hwIndex = index >> 8;
744 uint8_t sensType = index & 0xff;
745
746 // Hack until we fix canReWidebandHwIndex and set "Broadcast" to 0xff
747 // TODO:
748 hwIndex = hwIndex < 8 ? hwIndex : 0xff;
749 setWidebandSensorType(hwIndex, sensType);
750 }
751 break;
752 case TS_WIDEBAND_PING_BY_ID:
753 pingWideband(index >> 8);
754 break;
755
756 case TS_WIDEBAND_FLASH_BY_ID:
757 {
758 uint8_t hwIndex = index >> 8;
759
760 // Hack until we fix canReWidebandHwIndex and set "Broadcast" to 0xff
761 // TODO:
762 widebandUpdateHwId = hwIndex < 8 ? hwIndex : 0xff;
763 requestWidebandUpdate(widebandUpdateHwId);
764 }
765 break;
766 #endif // EFI_CAN_SUPPORT
767 case TS_BENCH_CATEGORY:
768 handleBenchCategory(index);
769 break;
770
771 case TS_SET_ENGINE_TYPE:
772 applyPreset(index);
773 break;
774
775 case TS_BOARD_ACTION:
776 // TODO: use call_board_override
777 if (custom_board_ts_command.has_value()) {
778 custom_board_ts_command.value()(subsystem, index);
779 }
780 break;
781
782 case TS_SET_DEFAULT_ENGINE:
783 applyPreset((int)DEFAULT_ENGINE_TYPE);
784 break;
785
786 case TS_STOP_ENGINE:
787 doScheduleStopEngine(StopRequestedReason::TsCommand);
788 break;
789
790 case 0xba:
791 #if EFI_PROD_CODE && EFI_DFU_JUMP
792 jump_to_bootloader();
793 #endif /* EFI_DFU_JUMP */
794 break;
795
796 case REBOOT_COMMAND:
797 #if EFI_PROD_CODE
798 rebootNow();
799 #endif /* EFI_PROD_CODE */
800 break;
801
802 #if EFI_USE_OPENBLT
803 case 0xbc:
804 /* Jump to OpenBLT if present */
805 jump_to_openblt();
806 break;
807 #endif
808
809 default:
810 criticalError("Unexpected bench subsystem %d %d", subsystem, index);
811 }
812 }
813
814 void onConfigurationChangeBenchTest() {
815 // default values if configuration was not specified
816 if (engineConfiguration->benchTestOnTime == 0) {
817 engineConfiguration->benchTestOnTime = 4;
818 }
819
820 if (engineConfiguration->benchTestOffTime < 5) {
821 engineConfiguration->benchTestOffTime = 500;
822 }
823
824 if (engineConfiguration->benchTestCount < 1) {
825 engineConfiguration->benchTestCount = 3;
826 }
827 }
828
829 void initBenchTest() {
830 addConsoleAction("fuelpumpbench", fuelPumpBench);
831 addConsoleActionF("fuelpumpbench2", fuelPumpBenchExt);
832
833 addConsoleActionFFF(CMD_FUEL_BENCH, fuelInjBench);
834 addConsoleActionFFFF("fuelbench2", fuelInjBenchExt);
835
836 addConsoleActionFFF(CMD_SPARK_BENCH, sparkBench);
837 addConsoleActionFFFF("sparkbench2", sparkBenchExt);
838
839 addConsoleActionFFFF("tcusolbench", tcuSolenoidBench);
840
841 addConsoleAction(CMD_AC_RELAY_BENCH, acRelayBench);
842
843 addConsoleAction(CMD_FAN_BENCH, fanBench);
844 addConsoleAction(CMD_FAN2_BENCH, fan2Bench);
845 addConsoleActionF("fanbench2", fanBenchExt);
846
847 addConsoleAction("mainrelaybench", mainRelayBench);
848
849 #if EFI_CAN_SUPPORT
850 #if EFI_WIDEBAND_FIRMWARE_UPDATE
851 addConsoleActionI("update_wideband", requestWidebandUpdate);
852 #endif // EFI_WIDEBAND_FIRMWARE_UPDATE
853 addConsoleActionII("set_wideband_index", [](int hwIndex, int index) { setWidebandOffset(hwIndex, index); });
854 #endif // EFI_CAN_SUPPORT
855
856 addConsoleAction(CMD_STARTER_BENCH, starterRelayBench);
857 addConsoleAction(CMD_MIL_BENCH, milBench);
858 addConsoleAction(CMD_HPFP_BENCH, hpfpValveBench);
859
860 #if EFI_CAN_SUPPORT
861 addConsoleActionI("ping_wideband", [](int index) {
862 pingWideband(index);
863 });
864 #endif // EFI_CAN_SUPPORT
865
866 #if EFI_LUA
867 // this commands facilitates TS Lua Button scripts development
868 addConsoleActionI("lua_button", [](int index) {
869 if (index < 0 || index > LUA_BUTTON_COUNT)
870 return;
871 luaCommandCounters[index - 1]++;
872 });
873 addConsoleActionFFFF("luabench2", [](float humanIndex, float onTime, float offTimeMs, float count) {
874 doRunBenchTestLuaOutput((int)humanIndex, onTime, offTimeMs, (int)count);
875 });
876 #endif // EFI_LUA
877 instance.start();
878 onConfigurationChangeBenchTest();
879 }
880
881 #endif /* EFI_UNIT_TEST */
882