GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 4 / 0 / 4
Functions: 100.0% 2 / 0 / 2
Branches: -% 0 / 0 / 0
Decisions: -% 0 / - / 0

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