rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
can_bench_test.cpp
Go to the documentation of this file.
1/*
2 * file can_bench_test.cpp
3 * see also https://github.com/rusefi/rusefi/wiki/CAN BENCH_TEST_BASE_ADDRESS 0x770000
4 *
5 * primary recipient is https://github.com/rusefi/rusefi-hardware/tree/main/digital-inputs/firmware
6 *
7 * todo: shall we not broadcast by default but wait until stim firmware wakes us up?
8 */
9
10#include "pch.h"
11#include "bench_test.h"
12#include "board_id.h"
13#include "can_bench_test.h"
14#include "can_msg_tx.h"
15#include "can_common.h"
16#include "frequency_sensor.h"
17#include "settings.h"
18#include "gpio/gpio_ext.h"
19
20#ifdef HW_HELLEN
21#include "hellen_meta.h"
22#endif // HW_HELLEN
23
25
26// todo: WHAT?! document why do we manually truncate higher bits?
27#define TRUNCATE_TO_BYTE(i) ((i) & 0xff)
28// raw values are 0..5V, convert it to 8-bit (0..255)
29#define RAW_TO_BYTE(v) TRUNCATE_TO_BYTE((int)(v * 255.0 / 5.0))
30
31#if EFI_PROD_CODE
32/**
33 * QC direct output control API is used by https://github.com/rusefi/stim test device
34 * quite different from bench testing user functionality: QC direct should never be engaged on a real vehicle
35 * Once QC direct control mode is activated the only way out is to reboot the unit!
36 */
37static bool qcDirectPinControlMode = false;
38#endif
39
40/*board public API*/bool isHwQcMode() {
41#if EFI_PROD_CODE
43#else
44 return false;
45#endif // EFI_PROD_CODE
46}
47
49#if EFI_PROD_CODE
51#if HW_HELLEN
52 if (!getHellenBoardEnabled()) {
53 hellenEnableEn("HW QC");
54 }
55#endif // HW_HELLEN
56#endif // EFI_PROD_CODE
57}
58
59#if EFI_CAN_SUPPORT
60
61static void directWritePad(Gpio pin, int value, const char *msg = "") {
62 if (!isBrainPinValid(pin)) {
63 criticalError("QC of invalid pin %d %s", (int)pin, msg);
64 return;
65 }
66
67#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
69 palWritePad(getHwPort("can_write", pin), getHwPin("can_write", pin), value);
70 } else {
71#if (BOARD_EXT_GPIOCHIPS > 0)
72 gpiochips_writePad(pin, value);
73#endif
74 }
75#endif // EFI_GPIO_HARDWARE && EFI_PROD_CODE
76}
77
78static void qcSetEtbState(uint8_t dcIndex, uint8_t direction) {
80 const dc_io *io = &engineConfiguration->etbIo[dcIndex];
81 Gpio controlPin = io->controlPin;
82 directWritePad(controlPin, 1, "DC control");
84 // TLE7209 and L6205
85 // let's force proper pin mode to work around potentially uninitialized subsystem
86 efiSetPadModeWithoutOwnershipAcquisition("QC_ETB_1", io->directionPin1, PAL_MODE_OUTPUT_PUSHPULL);
87 efiSetPadModeWithoutOwnershipAcquisition("QC_ETB_2", io->directionPin2, PAL_MODE_OUTPUT_PUSHPULL);
88
89 directWritePad(io->directionPin1, direction, "DC dir1");
90 directWritePad(io->directionPin2, !direction, "DC dir2");
91 } else {
92 // TLE9201 and VNH2SP30
93 efiSetPadModeWithoutOwnershipAcquisition("QC_ETB", controlPin, PAL_MODE_OUTPUT_PUSHPULL);
94 directWritePad(io->directionPin1, direction, "DC dir");
95 directWritePad(io->disablePin, 0, "DC dis"); // disable pin is inverted - here we ENABLE. direct pin access due to qcDirectPinControlMode
96 }
97}
98
99static void setPin(const CANRxFrame& frame, int value) {
100 size_t outputIndex = frame.data8[2];
101 if (outputIndex >= getBoardMetaOutputsCount()) {
102 criticalError("QC pin index %d out of range", outputIndex);
103 return;
104 }
105#if EFI_GPIO_HARDWARE && EFI_PROD_CODE
106 Gpio* boardOutputs = getBoardMetaOutputs();
107 criticalAssertVoid(boardOutputs != nullptr, "outputs not defined");
108 Gpio pin = boardOutputs[outputIndex];
109
110 int hwIndex = brainPin_to_index(pin);
111 if (pinRepository.getBrainUsedPin(hwIndex) == nullptr) {
112 // if pin is assigned we better configure it
113 efiSetPadModeWithoutOwnershipAcquisition("QC_SET", pin, PAL_MODE_OUTPUT_PUSHPULL);
114 }
115
116 directWritePad(pin, value);
117#endif // EFI_GPIO_HARDWARE && EFI_PROD_CODE
118}
119
120void sendQcBenchEventCounters(size_t bus) {
121#if EFI_SHAFT_POSITION_INPUT
122 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::EVENT_COUNTERS, 8, bus, /*isExtended*/true);
123
128
129 msg[0] = TRUNCATE_TO_BYTE(primaryRise + primaryFall);
130 msg[1] = TRUNCATE_TO_BYTE(secondaryRise + secondaryFall);
131
132 for (int camIdx = 0; camIdx < 4; camIdx++) {
133 int vvtRise = 0, vvtFall = 0;
134 if (camIdx < CAM_INPUTS_COUNT) {
135 vvtRise = engine->triggerCentral.vvtEventRiseCounter[camIdx];
136 vvtFall = engine->triggerCentral.vvtEventFallCounter[camIdx];
137 }
138
139 msg[2 + camIdx] = TRUNCATE_TO_BYTE(vvtRise + vvtFall);
140 }
141
143 msg[6] = TRUNCATE_TO_BYTE(vehicleSpeedSensor.eventCounter);
144#endif // EFI_SHAFT_POSITION_INPUT
145}
146
148 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::BUTTON_COUNTERS, 8, /*bus*/0, /*isExtended*/true);
149 msg[0] = TRUNCATE_TO_BYTE(engine->brakePedalSwitchedState.getCounter());
150 msg[1] = TRUNCATE_TO_BYTE(engine->clutchUpSwitchedState.getCounter());
151 msg[2] = TRUNCATE_TO_BYTE(engine->acButtonSwitchedState.getCounter());
152 // todo: start button
153}
154
156 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::AUX_DIGITAL_COUNTERS, 8, /*bus*/0, /*isExtended*/true);
157 for (int i =0;i<LUA_DIGITAL_INPUT_COUNT;i++) {
158 msg[i] = TRUNCATE_TO_BYTE(engine->luaDigitalInputState[i].state.getCounter());
159 }
160}
161
163 const float values_1[] = {
172 };
173
174 const float values_2[] = {
183 };
184 const float lua_values_1[] = {
193 };
194 static_assert(efi::size(values_1) <= 8);
195 static_assert(efi::size(values_2) <= 8);
196 static_assert(efi::size(lua_values_1) <= 8);
197
198
199 // send the first packet
200 {
201 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::RAW_ANALOG_1, 8, bus, /*isExtended*/true);
202 for (size_t valueIdx = 0; valueIdx < efi::size(values_1); valueIdx++) {
203 msg[valueIdx] = RAW_TO_BYTE(values_1[valueIdx]);
204 }
205 }
206 {
207 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::RAW_ANALOG_2, 8, bus, /*isExtended*/true);
208 for (size_t valueIdx = 0; valueIdx < efi::size(values_2); valueIdx++) {
209 msg[valueIdx] = RAW_TO_BYTE(values_2[valueIdx]);
210 }
211 }
212 // todo: time to extract method already?
213 {
214 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::RAW_LUA_ANALOG_1, 8, bus, /*isExtended*/true);
215 for (size_t valueIdx = 0; valueIdx < efi::size(lua_values_1); valueIdx++) {
216 msg[valueIdx] = RAW_TO_BYTE(lua_values_1[valueIdx]);
217 }
218 }
219}
220
221static void sendOutBoardMeta(size_t bus) {
222#if EFI_PROD_CODE
223 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::IO_META_INFO, 8, bus, /*isExtended*/true);
224 msg[0] = (int)bench_test_magic_numbers_e::BENCH_HEADER;
225 msg[1] = 0;
226 msg[2] = getBoardMetaOutputsCount();
229#endif // EFI_PROD_CODE
230}
231
232void sendQcBenchBoardStatus(size_t bus) {
233#if EFI_PROD_CODE
234 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::BOARD_STATUS, 8, bus, /*isExtended*/true);
235
236 int boardId = getBoardId();
237 msg[0] = TRUNCATE_TO_BYTE(boardId >> 8);
238 msg[1] = TRUNCATE_TO_BYTE(boardId);
239
240 int numSecondsSinceReset = getTimeNowS();
241 msg[2] = TRUNCATE_TO_BYTE(numSecondsSinceReset >> 16);
242 msg[3] = TRUNCATE_TO_BYTE(numSecondsSinceReset >> 8);
243 msg[4] = TRUNCATE_TO_BYTE(numSecondsSinceReset);
244
245 int engineType = (int) engineConfiguration->engineType;
246 msg[5] = engineType >> 8;
247 msg[6] = engineType;
248 sendOutBoardMeta(bus);
249#endif // EFI_PROD_CODE
250}
251
252#if EFI_PROD_CODE
253static void sendManualPinTest(int id) {
254 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::MANUAL_PIN_TEST, 8, /*bus*/0, /*isExtended*/true);
255 msg[0] = id;
256}
257#endif // EFI_PROD_CODE
258
259static void sendPinStatePackets(int pinToggleCounter, uint32_t durationsInStateMs[2]) {
260 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::PIN_STATE, 8, /*bus*/0, /*isExtended*/true);
261 msg[0] = TRUNCATE_TO_BYTE(pinToggleCounter >> 8);
262 msg[1] = TRUNCATE_TO_BYTE(pinToggleCounter);
263
264 for (int i = 0, mIdx = 2; i < 2; i++) {
265 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i] >> 16);
266 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i] >> 8);
267 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i]);
268 }
269}
270
271// bench test fuel pump pin #5603
272static void sendPinStatePackets(bench_mode_e benchModePinIdx) {
274 if (pin == nullptr)
275 return;
276#if EFI_SIMULATOR
277 sendPinStatePackets(pin->pinToggleCounter, pin->durationsInStateMs);
278#endif // EFI_SIMULATOR
279}
280
286
287static void resetPinStats(bench_mode_e benchModePinIdx) {
289
290 if (pin == nullptr)
291 return;
292
293#if EFI_SIMULATOR
295#endif // EFI_SIMULATOR
296}
297
299 if (CAN_EID(frame) != (int)bench_test_packet_ids_e::HW_QC_IO_CONTROL) {
300 return;
301 }
302 if (frame.data8[0] != (int)bench_test_magic_numbers_e::BENCH_HEADER) {
303 return;
304 }
305 setHwQcMode();
306 bench_test_io_control_e command = (bench_test_io_control_e)frame.data8[1];
307 if (command == bench_test_io_control_e::CAN_BENCH_GET_COUNT) {
309 } else if (command == bench_test_io_control_e::CAN_QC_OUTPUT_CONTROL_SET) {
310 // see also "bench_setpin" console command
311 setPin(frame, 1);
312 } else if (command == bench_test_io_control_e::CAN_QC_OUTPUT_CONTROL_CLEAR) {
313 setPin(frame, 0);
314 } else if (command == bench_test_io_control_e::CAN_QC_ETB) {
315 uint8_t dcIndex = frame.data8[2];
316 uint8_t direction = frame.data8[3];
317 qcSetEtbState(dcIndex, direction);
318 } else if (command == bench_test_io_control_e::CAN_BENCH_SET_ENGINE_TYPE) {
319 int eType = frame.data8[2];
320 // todo: fix firmware for 'false' to be possible - i.e. more of properties should be applied on the fly
321 setEngineType(eType, true);
322#if EFI_PROD_CODE
324#endif // EFI_PROD_CODE
325} else if (command == bench_test_io_control_e::CAN_BENCH_START_PIN_TEST) {
326 bench_mode_e benchModePinIdx = (bench_mode_e)frame.data8[2];
327 // ignore previous pin state and stats
328 resetPinStats(benchModePinIdx);
329 } else if (command == bench_test_io_control_e::CAN_BENCH_END_PIN_TEST) {
331 } else if (command == bench_test_io_control_e::CAN_BENCH_EXECUTE_BENCH_TEST) {
332 int benchCommandIdx = frame.data8[2];
333 handleBenchCategory(benchCommandIdx);
334 } else if (command == bench_test_io_control_e::CAN_BENCH_QUERY_PIN_STATE) {
335 bench_mode_e benchModePinIdx = (bench_mode_e)frame.data8[2];
336 sendPinStatePackets(benchModePinIdx);
337 }
338}
339#endif // EFI_CAN_SUPPORT
340
342#if EFI_CAN_SUPPORT && EFI_PROD_CODE
343 addConsoleActionII("qc_etb", [](int index, int direction) {
344 qcSetEtbState(index, direction);
345 });
346
347 addConsoleActionI("qc_output", [](int index) {
348 Gpio* boardOutputs = getBoardMetaOutputs();
349 criticalAssertVoid(boardOutputs != nullptr, "outputs not defined");
350 Gpio pin = boardOutputs[index];
351 efiSetPadModeWithoutOwnershipAcquisition("qc_output", pin, PAL_MODE_OUTPUT_PUSHPULL);
352
353 int physicalValue = palReadPad(getHwPort("read", pin), getHwPin("read", pin));
354 efiPrintf("original pin %s value %d", hwPortname(pin), physicalValue);
355 palWritePad(getHwPort("write", pin), getHwPin("write", pin), 1 - physicalValue);
356 sendManualPinTest(index);
357 });
358#endif // EFI_PROD_CODE
359}
int getSavedBenchTestPinStates(uint32_t durationsInStateMs[2])
static uint32_t savedDurationsInStateMs[2]
void handleBenchCategory(uint16_t index)
static int savedPinToggleCounter
Utility methods related to bench testing.
board_id_t getBoardId()
Definition board_id.cpp:15
void sendQcBenchButtonCounters()
static void sendManualPinTest(int id)
static void directWritePad(Gpio pin, int value, const char *msg="")
static void setPin(const CANRxFrame &frame, int value)
void processCanQcBenchTest(const CANRxFrame &frame)
bool isHwQcMode()
static void qcSetEtbState(uint8_t dcIndex, uint8_t direction)
static bool qcDirectPinControlMode
static void sendSavedBenchStatePackets()
void initQcBenchControls()
void setHwQcMode()
PinRepository pinRepository
static void resetPinStats(bench_mode_e benchModePinIdx)
void sendQcBenchRawAnalogValues(size_t bus)
void sendQcBenchBoardStatus(size_t bus)
static void sendOutBoardMeta(size_t bus)
void sendQcBenchAuxDigitalCounters()
void sendQcBenchEventCounters(size_t bus)
static void sendPinStatePackets(int pinToggleCounter, uint32_t durationsInStateMs[2])
TriggerCentral triggerCentral
Definition engine.h:318
SwitchedState brakePedalSwitchedState
Definition engine.h:215
SwitchedState clutchUpSwitchedState
Definition engine.h:214
SwitchedState acButtonSwitchedState
Definition engine.h:216
SimpleSwitchedState luaDigitalInputState[LUA_DIGITAL_INPUT_COUNT]
Definition engine.h:217
OutputPin * getOutputPinForBenchMode(bench_mode_e idx)
Definition efi_gpio.cpp:356
Single output pin reference and state.
Definition efi_output.h:49
void resetToggleStats()
Definition efi_gpio.cpp:598
const char *& getBrainUsedPin(size_t idx)
virtual float getRaw() const
Definition sensor.h:148
uint16_t getCounter() const
int getHwEventCounter(int index) const
void addConsoleActionII(const char *token, VoidIntInt callback)
Register a console command with two Integer parameters.
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
int gpiochips_writePad(brain_pin_e pin, int value)
Set value to gpio of gpiochip.
Definition core.cpp:336
EnginePins enginePins
Definition efi_gpio.cpp:24
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
efitimesec_t getTimeNowS()
Current system time in seconds (32 bits)
Definition efitime.cpp:42
void scheduleReboot()
Definition rusefi.cpp:158
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
bench_mode_e
int getBoardMetaOutputsCount()
Gpio * getBoardMetaOutputs()
int getBoardMetaLowSideOutputsCount()
int getBoardMetaDcOutputsCount()
void hellenEnableEn(const char *msg)
bool getHellenBoardEnabled()
FrequencySensor vehicleSpeedSensor(SensorType::VehicleSpeed, MS2NT(500))
void efiSetPadModeWithoutOwnershipAcquisition(const char *msg, brain_pin_e brainPin, iomode_t mode)
Definition io_pins.cpp:61
int brainPin_to_index(Gpio brainPin)
const char * hwPortname(brain_pin_e brainPin)
bool brain_pin_is_onchip(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
@ AcceleratorPedalPrimary
@ AcceleratorPedalSecondary
void setEngineType(int value, bool isWriteToFlash)
Definition settings.cpp:735
This file is about configuring engine via the human-readable protocol.
@ SHAFT_SECONDARY_RISING
@ SHAFT_SECONDARY_FALLING
@ SHAFT_PRIMARY_FALLING
@ SHAFT_PRIMARY_RISING
brain_pin_e pin
Definition stm32_adc.cpp:15
uint8_t data8[8]
Frame data.
Definition can_mocks.h:55
SwitchedState state
Definition efi_output.h:36
uint16_t vvtEventRiseCounter[CAM_INPUTS_COUNT]
uint16_t vvtEventFallCounter[CAM_INPUTS_COUNT]