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
121#if EFI_SHAFT_POSITION_INPUT
122 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::EVENT_COUNTERS, 8, /*bus*/0, /*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 static_assert(efi::size(values_1) <= 8);
185 static_assert(efi::size(values_2) <= 8);
186
187
188 // send the first packet
189 {
190 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::RAW_ANALOG_1, 8, /*bus*/0, /*isExtended*/true);
191 for (size_t valueIdx = 0; valueIdx < efi::size(values_1); valueIdx++) {
192 msg[valueIdx] = RAW_TO_BYTE(values_1[valueIdx]);
193 }
194 }
195 {
196 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::RAW_ANALOG_2, 8, /*bus*/0, /*isExtended*/true);
197 for (size_t valueIdx = 0; valueIdx < efi::size(values_2); valueIdx++) {
198 msg[valueIdx] = RAW_TO_BYTE(values_2[valueIdx]);
199 }
200 }
201}
202
203static void sendOutBoardMeta() {
204#if EFI_PROD_CODE
205 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::IO_META_INFO, 8, /*bus*/0, /*isExtended*/true);
206 msg[0] = (int)bench_test_magic_numbers_e::BENCH_HEADER;
207 msg[1] = 0;
208 msg[2] = getBoardMetaOutputsCount();
211#endif // EFI_PROD_CODE
212}
213
215#if EFI_PROD_CODE
216 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::BOARD_STATUS, 8, /*bus*/0, /*isExtended*/true);
217
218 int boardId = getBoardId();
219 msg[0] = TRUNCATE_TO_BYTE(boardId >> 8);
220 msg[1] = TRUNCATE_TO_BYTE(boardId);
221
222 int numSecondsSinceReset = getTimeNowS();
223 msg[2] = TRUNCATE_TO_BYTE(numSecondsSinceReset >> 16);
224 msg[3] = TRUNCATE_TO_BYTE(numSecondsSinceReset >> 8);
225 msg[4] = TRUNCATE_TO_BYTE(numSecondsSinceReset);
226
227 int engineType = (int) engineConfiguration->engineType;
228 msg[5] = engineType >> 8;
229 msg[6] = engineType;
231#endif // EFI_PROD_CODE
232}
233
234#if EFI_PROD_CODE
235static void sendManualPinTest(int id) {
236 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::MANUAL_PIN_TEST, 8, /*bus*/0, /*isExtended*/true);
237 msg[0] = id;
238}
239#endif // EFI_PROD_CODE
240
241static void sendPinStatePackets(int pinToggleCounter, uint32_t durationsInStateMs[2]) {
242 CanTxMessage msg(CanCategory::BENCH_TEST, (int)bench_test_packet_ids_e::PIN_STATE, 8, /*bus*/0, /*isExtended*/true);
243 msg[0] = TRUNCATE_TO_BYTE(pinToggleCounter >> 8);
244 msg[1] = TRUNCATE_TO_BYTE(pinToggleCounter);
245
246 for (int i = 0, mIdx = 2; i < 2; i++) {
247 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i] >> 16);
248 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i] >> 8);
249 msg[mIdx++] = TRUNCATE_TO_BYTE(durationsInStateMs[i]);
250 }
251}
252
253// bench test fuel pump pin #5603
254static void sendPinStatePackets(bench_mode_e benchModePinIdx) {
256 if (pin == nullptr)
257 return;
258#if EFI_SIMULATOR
259 sendPinStatePackets(pin->pinToggleCounter, pin->durationsInStateMs);
260#endif // EFI_SIMULATOR
261}
262
268
269static void resetPinStats(bench_mode_e benchModePinIdx) {
271
272 if (pin == nullptr)
273 return;
274
275#if EFI_SIMULATOR
277#endif // EFI_SIMULATOR
278}
279
281 if (CAN_EID(frame) != (int)bench_test_packet_ids_e::IO_CONTROL) {
282 return;
283 }
284 if (frame.data8[0] != (int)bench_test_magic_numbers_e::BENCH_HEADER) {
285 return;
286 }
287 setHwQcMode();
288 bench_test_io_control_e command = (bench_test_io_control_e)frame.data8[1];
289 if (command == bench_test_io_control_e::CAN_BENCH_GET_COUNT) {
291 } else if (command == bench_test_io_control_e::CAN_QC_OUTPUT_CONTROL_SET) {
292 // see also "bench_setpin" console command
293 setPin(frame, 1);
294 } else if (command == bench_test_io_control_e::CAN_QC_OUTPUT_CONTROL_CLEAR) {
295 setPin(frame, 0);
296 } else if (command == bench_test_io_control_e::CAN_QC_ETB) {
297 uint8_t dcIndex = frame.data8[2];
298 uint8_t direction = frame.data8[3];
299 qcSetEtbState(dcIndex, direction);
300 } else if (command == bench_test_io_control_e::CAN_BENCH_SET_ENGINE_TYPE) {
301 int eType = frame.data8[2];
302 // todo: fix firmware for 'false' to be possible - i.e. more of properties should be applied on the fly
303 setEngineType(eType, true);
304#if EFI_PROD_CODE
306#endif // EFI_PROD_CODE
307} else if (command == bench_test_io_control_e::CAN_BENCH_START_PIN_TEST) {
308 bench_mode_e benchModePinIdx = (bench_mode_e)frame.data8[2];
309 // ignore previous pin state and stats
310 resetPinStats(benchModePinIdx);
311 } else if (command == bench_test_io_control_e::CAN_BENCH_END_PIN_TEST) {
313 } else if (command == bench_test_io_control_e::CAN_BENCH_EXECUTE_BENCH_TEST) {
314 int benchCommandIdx = frame.data8[2];
315 handleBenchCategory(benchCommandIdx);
316 } else if (command == bench_test_io_control_e::CAN_BENCH_QUERY_PIN_STATE) {
317 bench_mode_e benchModePinIdx = (bench_mode_e)frame.data8[2];
318 sendPinStatePackets(benchModePinIdx);
319 }
320}
321#endif // EFI_CAN_SUPPORT
322
324#if EFI_CAN_SUPPORT && EFI_PROD_CODE
325 addConsoleActionII("qc_etb", [](int index, int direction) {
326 qcSetEtbState(index, direction);
327 });
328
329 addConsoleActionI("qc_output", [](int index) {
330 Gpio* boardOutputs = getBoardMetaOutputs();
331 criticalAssertVoid(boardOutputs != nullptr, "outputs not defined");
332 Gpio pin = boardOutputs[index];
333 efiSetPadModeWithoutOwnershipAcquisition("qc_output", pin, PAL_MODE_OUTPUT_PUSHPULL);
334
335 int physicalValue = palReadPad(getHwPort("read", pin), getHwPin("read", pin));
336 efiPrintf("original pin %s value %d", hwPortname(pin), physicalValue);
337 palWritePad(getHwPort("write", pin), getHwPin("write", pin), 1 - physicalValue);
338 sendManualPinTest(index);
339 });
340#endif // EFI_PROD_CODE
341}
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)
void sendQcBenchBoardStatus()
void sendQcBenchRawAnalogValues()
static bool qcDirectPinControlMode
static void sendSavedBenchStatePackets()
void initQcBenchControls()
static void sendOutBoardMeta()
void setHwQcMode()
PinRepository pinRepository
static void resetPinStats(bench_mode_e benchModePinIdx)
void sendQcBenchAuxDigitalCounters()
static void sendPinStatePackets(int pinToggleCounter, uint32_t durationsInStateMs[2])
void sendQcBenchEventCounters()
TriggerCentral triggerCentral
Definition engine.h:304
SwitchedState brakePedalSwitchedState
Definition engine.h:202
SwitchedState clutchUpSwitchedState
Definition engine.h:201
SwitchedState acButtonSwitchedState
Definition engine.h:203
SimpleSwitchedState luaDigitalInputState[LUA_DIGITAL_INPUT_COUNT]
Definition engine.h:204
OutputPin * getOutputPinForBenchMode(bench_mode_e idx)
Definition efi_gpio.cpp:359
Single output pin reference and state.
Definition efi_output.h:50
void resetToggleStats()
Definition efi_gpio.cpp:584
const char *& getBrainUsedPin(size_t idx)
virtual float getRaw() const
Definition sensor.h:148
SwitchedState state
Definition efi_output.h:37
uint16_t getCounter()
int getHwEventCounter(int index) const
int vvtEventFallCounter[CAM_INPUTS_COUNT]
int vvtEventRiseCounter[CAM_INPUTS_COUNT]
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:335
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 Engine *const engine
Definition engine.h:389
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