rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
engine_sniffer.cpp
Go to the documentation of this file.
1/**
2 * @file engine_sniffer.cpp
3 * @brief rusEfi console wave sniffer logic
4 *
5 * Here we have our own build-in logic analyzer. The data we aggregate here is sent to the
6 * java UI rusEfi Console so that it can be displayed nicely in the Sniffer tab.
7 *
8 * Both external events (see logic_analyzer.cpp) and internal (see signal executors) are supported
9 *
10 * @date Jun 23, 2013
11 * @author Andrey Belomutskiy, (c) 2012-2020
12 *
13 * This file is part of rusEfi - see http://rusefi.com
14 *
15 * rusEfi is free software; you can redistribute it and/or modify it under the terms of
16 * the GNU General Public License as published by the Free Software Foundation; either
17 * version 3 of the License, or (at your option) any later version.
18 *
19 * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
20 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along with this program.
24 * If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#include "pch.h"
28
29#include "engine_sniffer.h"
30
31// a bit weird because of conditional compilation
32static char shaft_signal_msg_index[15];
33
34#if EFI_ENGINE_SNIFFER
35#define addEngineSnifferEvent(name, msg) { if (getTriggerCentral()->isEngineSnifferEnabled) { waveChart.addEvent3((name), (msg)); } }
36 #else
37#define addEngineSnifferEvent(name, msg) { UNUSED(name); }
38#endif /* EFI_ENGINE_SNIFFER */
39
40#if EFI_ENGINE_SNIFFER
41
42#include "eficonsole.h"
43#include "status_loop.h"
44
45#define CHART_DELIMETER '!'
46extern WaveChart waveChart;
47
48/**
49 * This is the number of events in the digital chart which would be displayed
50 * on the 'digital sniffer' pane
51 */
52#if EFI_PROD_CODE
53#define WAVE_LOGGING_SIZE 5000
54#else
55#define WAVE_LOGGING_SIZE 35000
56#endif
57
58static char WAVE_LOGGING_BUFFER[WAVE_LOGGING_SIZE] CCM_OPTIONAL;
59
61
62/**
63 * We want to skip some engine cycles to skip what was scheduled before parameters were changed
64 */
65static uint32_t skipUntilEngineCycle = 0;
66
67#if ! EFI_UNIT_TEST
69static void resetNow() {
70 skipUntilEngineCycle = getRevolutionCounter() + 3;
72}
73#endif // EFI_UNIT_TEST
74
75WaveChart::WaveChart() : logging("wave chart", WAVE_LOGGING_BUFFER, sizeof(WAVE_LOGGING_BUFFER)) {
76}
77
79 isInitialized = true;
80 reset();
81}
82
84 logging.reset();
85 counter = 0;
86 startTimeNt = 0;
87 collectingData = false;
88 logging.appendPrintf( "%s%s", PROTOCOL_ENGINE_SNIFFER, LOG_DELIMITER);
89}
90
94
96 /**
97 * Say at 300rpm we should get at least four events per revolution.
98 * That's 300/60*4=20 events per second
99 * engineChartSize/20 is the longest meaningful chart.
100 *
101 */
102 efidur_t chartDurationNt = getTimeNowNt() - startTimeNt;
103 return startTimeNt != 0 && NT2US(chartDurationNt) > engineConfiguration->engineChartSize * 1000000 / 20;
104}
105
109
111 return counter;
112}
113
114#if ! EFI_UNIT_TEST
115static void printStatus() {
116 efiPrintf("engine sniffer: %s", boolToString(getTriggerCentral()->isEngineSnifferEnabled));
117 efiPrintf("engine sniffer size=%lu", engineConfiguration->engineChartSize);
118}
119
120void setChartSize(int newSize) {
121 if (newSize < 5) {
122 return;
123 }
125 printStatus();
126}
127#endif // EFI_UNIT_TEST
128
130 if (isFull() || isStartedTooLongAgo()) {
131 publish();
132 reset();
133 }
134}
135
137#if EFI_ENGINE_SNIFFER
138 logging.appendPrintf( LOG_DELIMITER);
140
141 if (getTriggerCentral()->isEngineSnifferEnabled) {
143 }
144#endif /* EFI_ENGINE_SNIFFER */
145}
146
147/**
148 * @brief Register an event for digital sniffer
149 */
150void WaveChart::addEvent3(const char *name, const char * msg) {
151#if EFI_TEXT_LOGGING
153 efitick_t nowNt = getTimeNowNt();
154
155 if (nowNt < pauseEngineSnifferUntilNt) {
156 return;
157 }
158 if (!getTriggerCentral()->isEngineSnifferEnabled) {
159 return;
160 }
161 if (skipUntilEngineCycle != 0 && getRevolutionCounter() < skipUntilEngineCycle)
162 return;
163#if EFI_SIMULATOR
164 if (!collectingData) {
165 return;
166 }
167#endif
168 efiAssertVoid(ObdCode::CUSTOM_ERR_6651, name!=NULL, "WC: NULL name");
169
170#if EFI_PROD_CODE
171 efiAssertVoid(ObdCode::CUSTOM_ERR_6652, getCurrentRemainingStack() > 32, "lowstck#2c");
172#endif /* EFI_PROD_CODE */
173
174 efiAssertVoid(ObdCode::CUSTOM_ERR_6653, isInitialized, "chart not initialized");
175
176 if (isFull()) {
177 return;
178 }
179
180 // we have multiple threads writing to the same output buffer
181 chibios_rt::CriticalSectionLocker csl;
182
183 if (counter == 0) {
184 startTimeNt = nowNt;
185 }
186 counter++;
187
188 /**
189 * We want smaller times within a chart in order to reduce packet size.
190 */
191 /**
192 * todo: migrate to binary fractions in order to eliminate
193 * this division? I do not like division
194 *
195 * at least that's 32 bit division now
196 */
197 uint32_t diffNt = nowNt - startTimeNt;
198 uint32_t time100 = NT2US(diffNt / ENGINE_SNIFFER_UNIT_US);
199
200 if (logging.remainingSize() > 35) {
201 /**
202 * printf is a heavy method, append is used here as a performance optimization
203 */
204 logging.appendFast(name);
205 logging.appendChar(CHART_DELIMETER);
206 logging.appendFast(msg);
207 logging.appendChar(CHART_DELIMETER);
208// time100 -= startTime100;
209
210 itoa10(timeBuffer, time100);
212 logging.appendChar(CHART_DELIMETER);
214 }
215#endif /* EFI_TEXT_LOGGING */
216}
217
219 strcpy((char*) shaft_signal_msg_index, "x_");
220 /**
221 * constructor does not work because we need specific initialization order
222 */
223 chart->init();
224
225#if EFI_HISTOGRAMS
226 initHistogram(&engineSnifferHisto, "engine sniffer");
227#endif /* EFI_HISTOGRAMS */
228
229#if ! EFI_UNIT_TEST
230 printStatus();
231 addConsoleActionI("chartsize", setChartSize);
232 // this is used by HW CI
233 addConsoleAction(CMD_RESET_ENGINE_SNIFFER, resetNow);
234#endif // EFI_UNIT_TEST
235}
236
237#endif /* EFI_ENGINE_SNIFFER */
238
241 addEngineSnifferEvent(pin->getShortName(), frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
242 }
243}
244
246 static char rpmBuffer[_MAX_FILLER];
247 itoa10(rpmBuffer, rpm);
248#if EFI_ENGINE_SNIFFER
250#endif
251 addEngineSnifferEvent(TOP_DEAD_CENTER_MESSAGE, (char* ) rpmBuffer);
252}
253
254void addEngineSnifferLogicAnalyzerEvent(int laIndex, FrontDirection frontDirection) {
255 extern const char *laNames[];
256 const char *name = laNames[laIndex];
257
258 addEngineSnifferEvent(name, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
259}
260
261void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection) {
262 static const char *crankName[2] = { PROTOCOL_CRANK1, PROTOCOL_CRANK2 };
263
264 shaft_signal_msg_index[0] = frontDirection == FrontDirection::UP ? 'u' : 'd';
265 // shaft_signal_msg_index[1] is assigned once and forever in the init method below
266 itoa10(&shaft_signal_msg_index[2], triggerEventIndex);
267
268 addEngineSnifferEvent(crankName[wheelIndex], (char* ) shaft_signal_msg_index);
269}
270
271void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection) {
272 extern const char *vvtNames[];
273 const char *vvtName = vvtNames[vvtIndex];
274
275 addEngineSnifferEvent(vvtName, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
276}
void appendFast(const char *text)
void appendChar(char c)
Definition datalogging.h:40
size_t remainingSize() const
Definition datalogging.h:49
void terminate()
Definition datalogging.h:33
size_t loggingSize() const
Definition datalogging.h:45
void reset()
void appendPrintf(const char *fmt,...) __attribute__((format(printf
rusEfi console sniffer data buffer
volatile int isInitialized
efitick_t startTimeNt
void startDataCollection()
void addEvent3(const char *name, const char *msg)
Register an event for digital sniffer.
bool isFull() const
bool isStartedTooLongAgo() const
char timeBuffer[_MAX_FILLER+2]
Logging logging
void publishIfFull()
efitick_t pauseEngineSnifferUntilNt
uint32_t counter
bool collectingData
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
const char * laNames[]
Definition efi_gpio.cpp:40
const char * vvtNames[]
Definition efi_gpio.cpp:34
Console package entry point header.
const char * boolToString(bool value)
Definition efilib.cpp:19
char * itoa10(char *p, int num)
Definition efilib.cpp:107
efitick_t getTimeNowNt()
Definition efitime.cpp:19
int waveChartUsedSize
TriggerCentral * getTriggerCentral()
Definition engine.cpp:590
static constexpr engine_configuration_s * engineConfiguration
int waveChartUsedSize
void setChartSize(int newSize)
static void printStatus()
void addEngineSnifferOutputPinEvent(NamedOutputPin *pin, FrontDirection frontDirection)
static void resetNow()
void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection)
void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection)
static uint32_t skipUntilEngineCycle
static char WAVE_LOGGING_BUFFER[WAVE_LOGGING_SIZE] CCM_OPTIONAL
void addEngineSnifferTdcEvent(int rpm)
static char shaft_signal_msg_index[15]
void addEngineSnifferLogicAnalyzerEvent(int laIndex, FrontDirection frontDirection)
void initWaveChart(WaveChart *chart)
WaveChart waveChart
rusEfi console wave sniffer
FrontDirection
void initHistogram(histogram_s *h, const char *name)
Reset histogram_s to orignal state.
Definition histogram.cpp:89
void scheduleLogging(Logging *logging)
@ CUSTOM_ERR_6651
@ CUSTOM_ERR_6653
@ CUSTOM_ERR_6652
@ EngineSniffer
efitick_t efidur_t
brain_pin_e pin
Definition stm32_adc.cpp:15