LCOV - code coverage report
Current view: top level - firmware/development - engine_sniffer.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 87 71.3 %
Date: 2024-12-19 02:33:10 Functions: 11 16 68.8 %

          Line data    Source code
       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
      32             : static 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 '!'
      46             : extern 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             : 
      58             : static char WAVE_LOGGING_BUFFER[WAVE_LOGGING_SIZE] CCM_OPTIONAL;
      59             : 
      60             : int waveChartUsedSize;
      61             : 
      62             : /**
      63             :  * We want to skip some engine cycles to skip what was scheduled before parameters were changed
      64             :  */
      65             : static uint32_t skipUntilEngineCycle = 0;
      66             : 
      67             : #if ! EFI_UNIT_TEST
      68             : extern WaveChart waveChart;
      69             : static void resetNow() {
      70             :         skipUntilEngineCycle = getRevolutionCounter() + 3;
      71             :         waveChart.reset();
      72             : }
      73             : #endif // EFI_UNIT_TEST
      74             : 
      75           1 : WaveChart::WaveChart() : logging("wave chart", WAVE_LOGGING_BUFFER, sizeof(WAVE_LOGGING_BUFFER)) {
      76           1 : }
      77             : 
      78         497 : void WaveChart::init() {
      79         497 :         isInitialized = true;
      80         497 :         reset();
      81         497 : }
      82             : 
      83         497 : void WaveChart::reset() {
      84         497 :         logging.reset();
      85         497 :         counter = 0;
      86         497 :         startTimeNt = 0;
      87         497 :         collectingData = false;
      88         497 :         logging.appendPrintf( "%s%s", PROTOCOL_ENGINE_SNIFFER, LOG_DELIMITER);
      89         497 : }
      90             : 
      91        1342 : void WaveChart::startDataCollection() {
      92        1342 :         collectingData = true;
      93        1342 : }
      94             : 
      95           0 : bool WaveChart::isStartedTooLongAgo() const {
      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           0 :         efidur_t chartDurationNt = getTimeNowNt() - startTimeNt;
     103           0 :         return startTimeNt != 0 && NT2US(chartDurationNt) > engineConfiguration->engineChartSize * 1000000 / 20;
     104             : }
     105             : 
     106       77974 : bool WaveChart::isFull() const {
     107       77974 :         return counter >= engineConfiguration->engineChartSize;
     108             : }
     109             : 
     110           1 : int WaveChart::getSize() {
     111           1 :         return counter;
     112             : }
     113             : 
     114             : #if ! EFI_UNIT_TEST
     115             : static void printStatus() {
     116             :         efiPrintf("engine sniffer: %s", boolToString(getTriggerCentral()->isEngineSnifferEnabled));
     117             :         efiPrintf("engine sniffer size=%lu", engineConfiguration->engineChartSize);
     118             : }
     119             : 
     120             : void setChartSize(int newSize) {
     121             :         if (newSize < 5) {
     122             :                 return;
     123             :         }
     124             :         engineConfiguration->engineChartSize = newSize;
     125             :         printStatus();
     126             : }
     127             : #endif // EFI_UNIT_TEST
     128             : 
     129           0 : void WaveChart::publishIfFull() {
     130           0 :         if (isFull() || isStartedTooLongAgo()) {
     131           0 :                 publish();
     132           0 :                 reset();
     133             :         }
     134           0 : }
     135             : 
     136           0 : void WaveChart::publish() {
     137             : #if EFI_ENGINE_SNIFFER
     138           0 :         logging.appendPrintf( LOG_DELIMITER);
     139           0 :         waveChartUsedSize = logging.loggingSize();
     140             : 
     141           0 :         if (getTriggerCentral()->isEngineSnifferEnabled) {
     142           0 :                 scheduleLogging(&logging);
     143             :         }
     144             : #endif /* EFI_ENGINE_SNIFFER */
     145           0 : }
     146             : 
     147             : /**
     148             :  * @brief       Register an event for digital sniffer
     149             :  */
     150       77974 : void WaveChart::addEvent3(const char *name, const char * msg) {
     151             : #if EFI_TEXT_LOGGING
     152       77974 :         ScopePerf perf(PE::EngineSniffer);
     153       77974 :         efitick_t nowNt = getTimeNowNt();
     154             : 
     155       77974 :         if (nowNt < pauseEngineSnifferUntilNt) {
     156           0 :                 return;
     157             :         }
     158       77974 :         if (!getTriggerCentral()->isEngineSnifferEnabled) {
     159           0 :                 return;
     160             :         }
     161       77974 :         if (skipUntilEngineCycle != 0 && getRevolutionCounter() < skipUntilEngineCycle)
     162           0 :                 return;
     163             : #if EFI_SIMULATOR
     164             :         if (!collectingData) {
     165             :                 return;
     166             :         }
     167             : #endif
     168       77974 :         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       77974 :         efiAssertVoid(ObdCode::CUSTOM_ERR_6653, isInitialized, "chart not initialized");
     175             : 
     176       77974 :         if (isFull()) {
     177       58211 :                 return;
     178             :         }
     179             : 
     180             :         // we have multiple threads writing to the same output buffer
     181             :         chibios_rt::CriticalSectionLocker csl;
     182             : 
     183       19763 :         if (counter == 0) {
     184          93 :                 startTimeNt = nowNt;
     185             :         }
     186       19763 :         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       19763 :         uint32_t diffNt = nowNt - startTimeNt;
     198       19763 :         uint32_t time100 = NT2US(diffNt / ENGINE_SNIFFER_UNIT_US);
     199             : 
     200       19763 :         if (logging.remainingSize() > 35) {
     201             :                 /**
     202             :                  * printf is a heavy method, append is used here as a performance optimization
     203             :                  */
     204       19763 :                 logging.appendFast(name);
     205       19763 :                 logging.appendChar(CHART_DELIMETER);
     206       19763 :                 logging.appendFast(msg);
     207       19763 :                 logging.appendChar(CHART_DELIMETER);
     208             : //              time100 -= startTime100;
     209             : 
     210       19763 :                 itoa10(timeBuffer, time100);
     211       19763 :                 logging.appendFast(timeBuffer);
     212       19763 :                 logging.appendChar(CHART_DELIMETER);
     213       19763 :                 logging.terminate();
     214             :         }
     215             : #endif /* EFI_TEXT_LOGGING */
     216             : }
     217             : 
     218           0 : void initWaveChart(WaveChart *chart) {
     219           0 :         strcpy((char*) shaft_signal_msg_index, "x_");
     220             :         /**
     221             :          * constructor does not work because we need specific initialization order
     222             :          */
     223           0 :         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           0 : }
     236             : 
     237             : #endif /* EFI_ENGINE_SNIFFER */
     238             : 
     239       16253 : void addEngineSnifferOutputPinEvent(NamedOutputPin *pin, FrontDirection frontDirection) {
     240       16253 :         if (!engineConfiguration->engineSnifferFocusOnInputs) {
     241       16253 :                 addEngineSnifferEvent(pin->getShortName(), frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     242             :         }
     243       16253 : }
     244             : 
     245        1342 : void addEngineSnifferTdcEvent(int rpm) {
     246             :         static char rpmBuffer[_MAX_FILLER];
     247        1342 :         itoa10(rpmBuffer, rpm);
     248             : #if EFI_ENGINE_SNIFFER
     249        1342 :         waveChart.startDataCollection();
     250             : #endif
     251        1342 :         addEngineSnifferEvent(TOP_DEAD_CENTER_MESSAGE, (char* ) rpmBuffer);
     252        1342 : }
     253             : 
     254           0 : void addEngineSnifferLogicAnalyzerEvent(int laIndex, FrontDirection frontDirection) {
     255             :         extern const char *laNames[];
     256           0 :         const char *name = laNames[laIndex];
     257             : 
     258           0 :         addEngineSnifferEvent(name, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     259           0 : }
     260             : 
     261       58187 : void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection) {
     262             :         static const char *crankName[2] = { PROTOCOL_CRANK1, PROTOCOL_CRANK2 };
     263             : 
     264       58187 :         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       58187 :         itoa10(&shaft_signal_msg_index[2], triggerEventIndex);
     267             : 
     268       58187 :         addEngineSnifferEvent(crankName[wheelIndex], (char* ) shaft_signal_msg_index);
     269       58187 : }
     270             : 
     271        2192 : void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection) {
     272             :         extern const char *vvtNames[];
     273        2192 :         const char *vvtName = vvtNames[vvtIndex];
     274             : 
     275        2192 :         addEngineSnifferEvent(vvtName, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     276        2192 : }

Generated by: LCOV version 1.14