2015-07-10 06:01:56 -07:00
|
|
|
/**
|
2015-07-15 18:01:45 -07:00
|
|
|
* @file engine_sniffer.cpp
|
2019-05-02 14:52:48 -07:00
|
|
|
* @brief rusEfi console wave sniffer logic
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* Here we have our own build-in logic analyzer. The data we aggregate here is sent to the
|
2019-05-02 14:52:48 -07:00
|
|
|
* java UI rusEfi Console so that it can be displayed nicely in the Sniffer tab.
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
2019-12-03 22:11:10 -08:00
|
|
|
* Both external events (see logic_analyzer.cpp) and internal (see signal executors) are supported
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* @date Jun 23, 2013
|
2020-01-07 21:02:40 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2021-08-03 19:05:01 -07:00
|
|
|
#include "pch.h"
|
2022-09-07 12:56:45 -07:00
|
|
|
|
2015-07-15 18:01:45 -07:00
|
|
|
#include "engine_sniffer.h"
|
2016-01-22 23:01:34 -08:00
|
|
|
|
2022-09-10 21:18:08 -07:00
|
|
|
// a bit weird because of conditional compilation
|
|
|
|
static char shaft_signal_msg_index[15];
|
|
|
|
|
2022-10-29 19:33:50 -07:00
|
|
|
#if EFI_ENGINE_SNIFFER
|
|
|
|
#define addEngineSnifferEvent(name, msg) { if (getTriggerCentral()->isEngineSnifferEnabled) { waveChart.addEvent3((name), (msg)); } }
|
|
|
|
#else
|
|
|
|
#define addEngineSnifferEvent(n, msg) {}
|
|
|
|
#endif /* EFI_ENGINE_SNIFFER */
|
|
|
|
|
2019-04-12 19:10:57 -07:00
|
|
|
#if EFI_ENGINE_SNIFFER
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#include "eficonsole.h"
|
|
|
|
#include "status_loop.h"
|
|
|
|
|
|
|
|
#define CHART_DELIMETER '!'
|
2022-09-10 17:25:13 -07:00
|
|
|
extern WaveChart waveChart;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the number of events in the digital chart which would be displayed
|
|
|
|
* on the 'digital sniffer' pane
|
|
|
|
*/
|
|
|
|
#if EFI_PROD_CODE
|
|
|
|
#define WAVE_LOGGING_SIZE 5000
|
|
|
|
#else
|
|
|
|
#define WAVE_LOGGING_SIZE 35000
|
|
|
|
#endif
|
|
|
|
|
2019-05-02 15:42:59 -07:00
|
|
|
static char WAVE_LOGGING_BUFFER[WAVE_LOGGING_SIZE] CCM_OPTIONAL;
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
int waveChartUsedSize;
|
|
|
|
|
|
|
|
//#define DEBUG_WAVE 1
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We want to skip some engine cycles to skip what was scheduled before parameters were changed
|
|
|
|
*/
|
2015-07-14 06:01:29 -07:00
|
|
|
static uint32_t skipUntilEngineCycle = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 19:10:57 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
extern WaveChart waveChart;
|
2021-11-15 04:02:34 -08:00
|
|
|
static void resetNow() {
|
2019-10-14 03:18:08 -07:00
|
|
|
skipUntilEngineCycle = getRevolutionCounter() + 3;
|
2016-01-30 19:03:36 -08:00
|
|
|
waveChart.reset();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2021-04-04 19:01:04 -07:00
|
|
|
#endif // EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-09-13 01:49:25 -07:00
|
|
|
WaveChart::WaveChart() : logging("wave chart", WAVE_LOGGING_BUFFER, sizeof(WAVE_LOGGING_BUFFER)) {
|
2019-05-02 15:42:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaveChart::init() {
|
|
|
|
isInitialized = true;
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
2016-01-30 19:03:36 -08:00
|
|
|
void WaveChart::reset() {
|
2015-07-10 06:01:56 -07:00
|
|
|
#if DEBUG_WAVE
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("reset while at ", counter);
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif /* DEBUG_WAVE */
|
2020-09-13 01:49:25 -07:00
|
|
|
logging.reset();
|
2015-07-10 06:01:56 -07:00
|
|
|
counter = 0;
|
|
|
|
startTimeNt = 0;
|
2019-05-02 15:42:59 -07:00
|
|
|
collectingData = false;
|
2021-11-19 01:01:45 -08:00
|
|
|
logging.appendPrintf( "%s%s", PROTOCOL_ENGINE_SNIFFER, LOG_DELIMITER);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-05-02 15:42:59 -07:00
|
|
|
void WaveChart::startDataCollection() {
|
|
|
|
collectingData = true;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-06-08 06:51:36 -07:00
|
|
|
bool WaveChart::isStartedTooLongAgo() const {
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* Say at 300rpm we should get at least four events per revolution.
|
|
|
|
* That's 300/60*4=20 events per second
|
|
|
|
* engineChartSize/20 is the longest meaningful chart.
|
|
|
|
*
|
|
|
|
*/
|
2019-12-21 18:11:09 -08:00
|
|
|
efitick_t chartDurationNt = getTimeNowNt() - startTimeNt;
|
2015-07-10 06:01:56 -07:00
|
|
|
return startTimeNt != 0 && NT2US(chartDurationNt) > engineConfiguration->engineChartSize * 1000000 / 20;
|
|
|
|
}
|
|
|
|
|
2019-06-08 06:51:36 -07:00
|
|
|
bool WaveChart::isFull() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return counter >= engineConfiguration->engineChartSize;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-04-04 19:48:48 -07:00
|
|
|
int WaveChart::getSize() {
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
2021-04-04 19:01:04 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
2021-11-15 04:02:34 -08:00
|
|
|
static void printStatus() {
|
2022-09-13 23:17:04 -07:00
|
|
|
efiPrintf("engine sniffer: %s", boolToString(getTriggerCentral()->isEngineSnifferEnabled));
|
2022-06-18 11:44:32 -07:00
|
|
|
efiPrintf("engine sniffer size=%d", engineConfiguration->engineChartSize);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void setChartSize(int newSize) {
|
|
|
|
if (newSize < 5) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
engineConfiguration->engineChartSize = newSize;
|
|
|
|
printStatus();
|
|
|
|
}
|
2021-04-04 19:01:04 -07:00
|
|
|
#endif // EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-01-30 19:03:36 -08:00
|
|
|
void WaveChart::publishIfFull() {
|
|
|
|
if (isFull() || isStartedTooLongAgo()) {
|
|
|
|
publish();
|
|
|
|
reset();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-30 19:03:36 -08:00
|
|
|
void WaveChart::publish() {
|
2022-12-17 11:58:10 -08:00
|
|
|
#if EFI_ENGINE_SNIFFER
|
2021-11-19 01:01:45 -08:00
|
|
|
logging.appendPrintf( LOG_DELIMITER);
|
2020-09-13 01:49:25 -07:00
|
|
|
waveChartUsedSize = logging.loggingSize();
|
2015-07-10 06:01:56 -07:00
|
|
|
#if DEBUG_WAVE
|
|
|
|
Logging *l = &chart->logging;
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("IT'S TIME", strlen(l->buffer));
|
2022-12-17 11:58:10 -08:00
|
|
|
#endif // DEBUG_WAVE
|
2022-09-13 23:17:04 -07:00
|
|
|
if (getTriggerCentral()->isEngineSnifferEnabled) {
|
2015-07-10 06:01:56 -07:00
|
|
|
scheduleLogging(&logging);
|
|
|
|
}
|
2022-12-17 11:58:10 -08:00
|
|
|
#endif /* EFI_ENGINE_SNIFFER */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Register an event for digital sniffer
|
|
|
|
*/
|
2016-01-30 19:03:36 -08:00
|
|
|
void WaveChart::addEvent3(const char *name, const char * msg) {
|
2022-06-18 11:17:36 -07:00
|
|
|
#if EFI_TEXT_LOGGING
|
2019-12-23 17:22:17 -08:00
|
|
|
ScopePerf perf(PE::EngineSniffer);
|
2020-05-25 20:38:15 -07:00
|
|
|
efitick_t nowNt = getTimeNowNt();
|
2019-12-23 17:22:17 -08:00
|
|
|
|
2020-05-25 20:38:15 -07:00
|
|
|
if (nowNt < pauseEngineSnifferUntilNt) {
|
2019-12-21 20:27:54 -08:00
|
|
|
return;
|
|
|
|
}
|
2022-09-13 23:17:04 -07:00
|
|
|
if (!getTriggerCentral()->isEngineSnifferEnabled) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2019-10-14 03:18:08 -07:00
|
|
|
if (skipUntilEngineCycle != 0 && getRevolutionCounter() < skipUntilEngineCycle)
|
2017-05-25 20:22:35 -07:00
|
|
|
return;
|
2019-05-02 15:42:59 -07:00
|
|
|
#if EFI_SIMULATOR
|
|
|
|
// todo: add UI control to enable this for firmware if desired
|
2021-11-17 00:54:21 -08:00
|
|
|
// engineConfiguration->alignEngineSnifferAtTDC &&
|
2019-05-02 15:42:59 -07:00
|
|
|
if (!collectingData) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6651, name!=NULL, "WC: NULL name");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#if EFI_PROD_CODE
|
2019-02-23 09:33:49 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6652, getCurrentRemainingStack() > 32, "lowstck#2c");
|
2019-05-02 15:42:59 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6653, isInitialized, "chart not initialized");
|
2015-07-10 06:01:56 -07:00
|
|
|
#if DEBUG_WAVE
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("current", chart->counter);
|
2019-05-02 15:42:59 -07:00
|
|
|
#endif /* DEBUG_WAVE */
|
2016-01-30 19:03:36 -08:00
|
|
|
if (isFull()) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-19 03:56:02 -08:00
|
|
|
// we have multiple threads writing to the same output buffer
|
|
|
|
chibios_rt::CriticalSectionLocker csl;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
if (counter == 0) {
|
|
|
|
startTimeNt = nowNt;
|
|
|
|
}
|
|
|
|
counter++;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We want smaller times within a chart in order to reduce packet size.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* todo: migrate to binary fractions in order to eliminate
|
|
|
|
* this division? I do not like division
|
|
|
|
*
|
|
|
|
* at least that's 32 bit division now
|
|
|
|
*/
|
|
|
|
uint32_t diffNt = nowNt - startTimeNt;
|
2020-05-25 22:08:21 -07:00
|
|
|
uint32_t time100 = NT2US(diffNt / ENGINE_SNIFFER_UNIT_US);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-09-13 01:49:25 -07:00
|
|
|
if (logging.remainingSize() > 35) {
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* printf is a heavy method, append is used here as a performance optimization
|
|
|
|
*/
|
2020-09-13 01:49:25 -07:00
|
|
|
logging.appendFast(name);
|
|
|
|
logging.appendChar(CHART_DELIMETER);
|
|
|
|
logging.appendFast(msg);
|
|
|
|
logging.appendChar(CHART_DELIMETER);
|
2015-07-10 06:01:56 -07:00
|
|
|
// time100 -= startTime100;
|
|
|
|
|
|
|
|
itoa10(timeBuffer, time100);
|
2020-09-13 01:49:25 -07:00
|
|
|
logging.appendFast(timeBuffer);
|
|
|
|
logging.appendChar(CHART_DELIMETER);
|
|
|
|
logging.terminate();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2018-09-16 21:00:19 -07:00
|
|
|
#endif /* EFI_TEXT_LOGGING */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void initWaveChart(WaveChart *chart) {
|
2022-09-10 20:33:37 -07:00
|
|
|
strcpy((char*) shaft_signal_msg_index, "x_");
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* constructor does not work because we need specific initialization order
|
|
|
|
*/
|
|
|
|
chart->init();
|
|
|
|
|
2019-04-12 19:10:57 -07:00
|
|
|
#if EFI_HISTOGRAMS
|
2022-06-18 11:44:32 -07:00
|
|
|
initHistogram(&engineSnifferHisto, "engine sniffer");
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif /* EFI_HISTOGRAMS */
|
|
|
|
|
2021-04-04 19:01:04 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
printStatus();
|
2015-07-10 06:01:56 -07:00
|
|
|
addConsoleActionI("chartsize", setChartSize);
|
2022-06-17 19:10:34 -07:00
|
|
|
// this is used by HW CI
|
2019-12-21 16:59:33 -08:00
|
|
|
addConsoleAction(CMD_RESET_ENGINE_SNIFFER, resetNow);
|
2021-04-04 19:01:04 -07:00
|
|
|
#endif // EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2015-07-15 18:01:45 -07:00
|
|
|
#endif /* EFI_ENGINE_SNIFFER */
|
2022-09-10 21:18:08 -07:00
|
|
|
|
2022-10-29 18:27:49 -07:00
|
|
|
void addEngineSnifferOutputPinEvent(NamedOutputPin *pin, FrontDirection frontDirection) {
|
|
|
|
if (!engineConfiguration->engineSnifferFocusOnInputs) {
|
|
|
|
addEngineSnifferEvent(pin->getShortName(), frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 21:18:08 -07:00
|
|
|
void addEngineSnifferTdcEvent(int rpm) {
|
|
|
|
static char rpmBuffer[_MAX_FILLER];
|
|
|
|
itoa10(rpmBuffer, rpm);
|
|
|
|
#if EFI_ENGINE_SNIFFER
|
|
|
|
waveChart.startDataCollection();
|
|
|
|
#endif
|
|
|
|
addEngineSnifferEvent(TOP_DEAD_CENTER_MESSAGE, (char* ) rpmBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addEngineSnifferLogicAnalyzerEvent(int laIndex, FrontDirection frontDirection) {
|
|
|
|
extern const char *laNames[];
|
|
|
|
const char *name = laNames[laIndex];
|
|
|
|
|
|
|
|
addEngineSnifferEvent(name, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection) {
|
|
|
|
static const char *crankName[2] = { PROTOCOL_CRANK1, PROTOCOL_CRANK2 };
|
|
|
|
|
|
|
|
shaft_signal_msg_index[0] = frontDirection == FrontDirection::UP ? 'u' : 'd';
|
|
|
|
// shaft_signal_msg_index[1] is assigned once and forever in the init method below
|
|
|
|
itoa10(&shaft_signal_msg_index[2], triggerEventIndex);
|
|
|
|
|
|
|
|
addEngineSnifferEvent(crankName[wheelIndex], (char* ) shaft_signal_msg_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection) {
|
|
|
|
extern const char *vvtNames[];
|
|
|
|
const char *vvtName = vvtNames[vvtIndex];
|
|
|
|
|
|
|
|
addEngineSnifferEvent(vvtName, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
|
|
|
|
}
|