GCC Code Coverage Report


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