LCOV - code coverage report
Current view: top level - firmware/development - engine_sniffer.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 63 87 72.4 %
Date: 2024-04-25 02:23:43 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             : //#define DEBUG_WAVE 1
      63             : 
      64             : /**
      65             :  * We want to skip some engine cycles to skip what was scheduled before parameters were changed
      66             :  */
      67             : static uint32_t skipUntilEngineCycle = 0;
      68             : 
      69             : #if ! EFI_UNIT_TEST
      70             : extern WaveChart waveChart;
      71             : static void resetNow() {
      72             :         skipUntilEngineCycle = getRevolutionCounter() + 3;
      73             :         waveChart.reset();
      74             : }
      75             : #endif // EFI_UNIT_TEST
      76             : 
      77           1 : WaveChart::WaveChart() : logging("wave chart", WAVE_LOGGING_BUFFER, sizeof(WAVE_LOGGING_BUFFER)) {
      78           1 : }
      79             : 
      80         306 : void WaveChart::init() {
      81         306 :         isInitialized = true;
      82         306 :         reset();
      83         306 : }
      84             : 
      85         306 : void WaveChart::reset() {
      86             : #if DEBUG_WAVE
      87             :         efiPrintf("reset while at ", counter);
      88             : #endif /* DEBUG_WAVE */
      89         306 :         logging.reset();
      90         306 :         counter = 0;
      91         306 :         startTimeNt = 0;
      92         306 :         collectingData = false;
      93         306 :         logging.appendPrintf( "%s%s", PROTOCOL_ENGINE_SNIFFER, LOG_DELIMITER);
      94         306 : }
      95             : 
      96         936 : void WaveChart::startDataCollection() {
      97         936 :         collectingData = true;
      98         936 : }
      99             : 
     100           0 : bool WaveChart::isStartedTooLongAgo() const {
     101             :         /**
     102             :          * Say at 300rpm we should get at least four events per revolution.
     103             :          * That's 300/60*4=20 events per second
     104             :          * engineChartSize/20 is the longest meaningful chart.
     105             :          *
     106             :          */
     107           0 :         efitick_t chartDurationNt = getTimeNowNt() - startTimeNt;
     108           0 :         return startTimeNt != 0 && NT2US(chartDurationNt) > engineConfiguration->engineChartSize * 1000000 / 20;
     109             : }
     110             : 
     111       62573 : bool WaveChart::isFull() const {
     112       62573 :         return counter >= engineConfiguration->engineChartSize;
     113             : }
     114             : 
     115           1 : int WaveChart::getSize() {
     116           1 :         return counter;
     117             : }
     118             : 
     119             : #if ! EFI_UNIT_TEST
     120             : static void printStatus() {
     121             :         efiPrintf("engine sniffer: %s", boolToString(getTriggerCentral()->isEngineSnifferEnabled));
     122             :         efiPrintf("engine sniffer size=%d", engineConfiguration->engineChartSize);
     123             : }
     124             : 
     125             : void setChartSize(int newSize) {
     126             :         if (newSize < 5) {
     127             :                 return;
     128             :         }
     129             :         engineConfiguration->engineChartSize = newSize;
     130             :         printStatus();
     131             : }
     132             : #endif // EFI_UNIT_TEST
     133             : 
     134           0 : void WaveChart::publishIfFull() {
     135           0 :         if (isFull() || isStartedTooLongAgo()) {
     136           0 :                 publish();
     137           0 :                 reset();
     138             :         }
     139           0 : }
     140             : 
     141           0 : void WaveChart::publish() {
     142             : #if EFI_ENGINE_SNIFFER
     143           0 :         logging.appendPrintf( LOG_DELIMITER);
     144           0 :         waveChartUsedSize = logging.loggingSize();
     145             : #if DEBUG_WAVE
     146             :         Logging *l = &chart->logging;
     147             :         efiPrintf("IT'S TIME", strlen(l->buffer));
     148             : #endif // DEBUG_WAVE
     149           0 :         if (getTriggerCentral()->isEngineSnifferEnabled) {
     150           0 :                 scheduleLogging(&logging);
     151             :         }
     152             : #endif /* EFI_ENGINE_SNIFFER */
     153           0 : }
     154             : 
     155             : /**
     156             :  * @brief       Register an event for digital sniffer
     157             :  */
     158       62577 : void WaveChart::addEvent3(const char *name, const char * msg) {
     159             : #if EFI_TEXT_LOGGING
     160       62577 :         ScopePerf perf(PE::EngineSniffer);
     161       62577 :         efitick_t nowNt = getTimeNowNt();
     162             : 
     163       62577 :         if (nowNt < pauseEngineSnifferUntilNt) {
     164           4 :                 return;
     165             :         }
     166       62573 :         if (!getTriggerCentral()->isEngineSnifferEnabled) {
     167           0 :                 return;
     168             :         }
     169       62573 :         if (skipUntilEngineCycle != 0 && getRevolutionCounter() < skipUntilEngineCycle)
     170           0 :                 return;
     171             : #if EFI_SIMULATOR
     172             :         if (!collectingData) {
     173             :                 return;
     174             :         }
     175             : #endif
     176       62573 :         efiAssertVoid(ObdCode::CUSTOM_ERR_6651, name!=NULL, "WC: NULL name");
     177             : 
     178             : #if EFI_PROD_CODE
     179             :         efiAssertVoid(ObdCode::CUSTOM_ERR_6652, getCurrentRemainingStack() > 32, "lowstck#2c");
     180             : #endif /* EFI_PROD_CODE */
     181             : 
     182       62573 :         efiAssertVoid(ObdCode::CUSTOM_ERR_6653, isInitialized, "chart not initialized");
     183             : #if DEBUG_WAVE
     184             :         efiPrintf("current", chart->counter);
     185             : #endif /* DEBUG_WAVE */
     186       62573 :         if (isFull()) {
     187       46848 :                 return;
     188             :         }
     189             : 
     190             :         // we have multiple threads writing to the same output buffer
     191             :         chibios_rt::CriticalSectionLocker csl;
     192             : 
     193       15725 :         if (counter == 0) {
     194          80 :                 startTimeNt = nowNt;
     195             :         }
     196       15725 :         counter++;
     197             : 
     198             :         /**
     199             :          * We want smaller times within a chart in order to reduce packet size.
     200             :          */
     201             :         /**
     202             :          * todo: migrate to binary fractions in order to eliminate
     203             :          * this division? I do not like division
     204             :          *
     205             :          * at least that's 32 bit division now
     206             :          */
     207       15725 :         uint32_t diffNt = nowNt - startTimeNt;
     208       15725 :         uint32_t time100 = NT2US(diffNt / ENGINE_SNIFFER_UNIT_US);
     209             : 
     210       15725 :         if (logging.remainingSize() > 35) {
     211             :                 /**
     212             :                  * printf is a heavy method, append is used here as a performance optimization
     213             :                  */
     214       15725 :                 logging.appendFast(name);
     215       15725 :                 logging.appendChar(CHART_DELIMETER);
     216       15725 :                 logging.appendFast(msg);
     217       15725 :                 logging.appendChar(CHART_DELIMETER);
     218             : //              time100 -= startTime100;
     219             : 
     220       15725 :                 itoa10(timeBuffer, time100);
     221       15725 :                 logging.appendFast(timeBuffer);
     222       15725 :                 logging.appendChar(CHART_DELIMETER);
     223       15725 :                 logging.terminate();
     224             :         }
     225             : #endif /* EFI_TEXT_LOGGING */
     226             : }
     227             : 
     228           0 : void initWaveChart(WaveChart *chart) {
     229           0 :         strcpy((char*) shaft_signal_msg_index, "x_");
     230             :         /**
     231             :          * constructor does not work because we need specific initialization order
     232             :          */
     233           0 :         chart->init();
     234             : 
     235             : #if EFI_HISTOGRAMS
     236             :         initHistogram(&engineSnifferHisto, "engine sniffer");
     237             : #endif /* EFI_HISTOGRAMS */
     238             : 
     239             : #if ! EFI_UNIT_TEST
     240             :         printStatus();
     241             :         addConsoleActionI("chartsize", setChartSize);
     242             :         // this is used by HW CI
     243             :         addConsoleAction(CMD_RESET_ENGINE_SNIFFER, resetNow);
     244             : #endif // EFI_UNIT_TEST
     245           0 : }
     246             : 
     247             : #endif /* EFI_ENGINE_SNIFFER */
     248             : 
     249       11756 : void addEngineSnifferOutputPinEvent(NamedOutputPin *pin, FrontDirection frontDirection) {
     250       11756 :         if (!engineConfiguration->engineSnifferFocusOnInputs) {
     251       11756 :                 addEngineSnifferEvent(pin->getShortName(), frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     252             :         }
     253       11756 : }
     254             : 
     255         936 : void addEngineSnifferTdcEvent(int rpm) {
     256             :         static char rpmBuffer[_MAX_FILLER];
     257         936 :         itoa10(rpmBuffer, rpm);
     258             : #if EFI_ENGINE_SNIFFER
     259         936 :         waveChart.startDataCollection();
     260             : #endif
     261         936 :         addEngineSnifferEvent(TOP_DEAD_CENTER_MESSAGE, (char* ) rpmBuffer);
     262         936 : }
     263             : 
     264           0 : void addEngineSnifferLogicAnalyzerEvent(int laIndex, FrontDirection frontDirection) {
     265             :         extern const char *laNames[];
     266           0 :         const char *name = laNames[laIndex];
     267             : 
     268           0 :         addEngineSnifferEvent(name, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     269           0 : }
     270             : 
     271       47693 : void addEngineSnifferCrankEvent(int wheelIndex, int triggerEventIndex, FrontDirection frontDirection) {
     272             :         static const char *crankName[2] = { PROTOCOL_CRANK1, PROTOCOL_CRANK2 };
     273             : 
     274       47693 :         shaft_signal_msg_index[0] = frontDirection == FrontDirection::UP ? 'u' : 'd';
     275             :         // shaft_signal_msg_index[1] is assigned once and forever in the init method below
     276       47693 :         itoa10(&shaft_signal_msg_index[2], triggerEventIndex);
     277             : 
     278       47693 :         addEngineSnifferEvent(crankName[wheelIndex], (char* ) shaft_signal_msg_index);
     279       47693 : }
     280             : 
     281        2192 : void addEngineSnifferVvtEvent(int vvtIndex, FrontDirection frontDirection) {
     282             :         extern const char *vvtNames[];
     283        2192 :         const char *vvtName = vvtNames[vvtIndex];
     284             : 
     285        2192 :         addEngineSnifferEvent(vvtName, frontDirection == FrontDirection::UP ? PROTOCOL_ES_UP : PROTOCOL_ES_DOWN);
     286        2192 : }

Generated by: LCOV version 1.14