LCOV - code coverage report
Current view: top level - firmware/console/binary - tooth_logger.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 47 63 74.6 %
Date: 2024-07-27 05:50:15 Functions: 7 10 70.0 %

          Line data    Source code
       1             : /*
       2             :  * @file tooth_logger.cpp
       3             :  *
       4             :  * At least some of the code here is related to xxx.teeth files
       5             :  * See also misc\tooth_log_converter\log_convert.cpp
       6             :  *
       7             :  * @date Jul 7, 2019
       8             :  * @author Matthew Kennedy
       9             :  */
      10             : 
      11             : #include "pch.h"
      12             : 
      13             : #if EFI_TOOTH_LOGGER
      14             : #if !EFI_SHAFT_POSITION_INPUT
      15             :         fail("EFI_SHAFT_POSITION_INPUT required to have EFI_EMULATE_POSITION_SENSORS")
      16             : #endif
      17             : 
      18             : /**
      19             :  * Engine idles around 20Hz and revs up to 140Hz, at 60/2 and 8 cylinders we have about 20Khz events
      20             :  * If we can read buffer at 50Hz we want buffer to be about 400 elements.
      21             :  */
      22             : 
      23             : static_assert(sizeof(composite_logger_s) == COMPOSITE_PACKET_SIZE, "composite packet size");
      24             : 
      25             : static volatile bool ToothLoggerEnabled = false;
      26             : //static uint32_t lastEdgeTimestamp = 0;
      27             : 
      28             : static bool currentTrigger1 = false;
      29             : static bool currentTrigger2 = false;
      30             : static bool currentTdc = false;
      31             : // any coil, all coils thrown together
      32             : static bool currentCoilState = false;
      33             : // same about injectors
      34             : static bool currentInjectorState = false;
      35             : 
      36             : #if EFI_UNIT_TEST
      37             : #include "logicdata.h"
      38             : 
      39             : static std::vector<CompositeEvent> events;
      40             : 
      41         353 : const std::vector<CompositeEvent>& getCompositeEvents() {
      42         353 :         return events;
      43             : }
      44             : 
      45       67407 : void SetNextCompositeEntry(efitick_t timestamp) {
      46       67407 :         CompositeEvent event;
      47             : 
      48       67407 :         event.timestamp = timestamp;
      49       67407 :         event.primaryTrigger = currentTrigger1;
      50       67407 :         event.secondaryTrigger = currentTrigger2;
      51       67407 :         event.isTDC = currentTdc;
      52       67407 :         event.sync = engine->triggerCentral.triggerState.getShaftSynchronized();
      53       67407 :         event.coil = currentCoilState;
      54       67407 :         event.injector = currentInjectorState;
      55             : 
      56       67407 :         events.push_back(event);
      57       67407 : }
      58             : 
      59         437 : void EnableToothLogger() {
      60         437 :         ToothLoggerEnabled = true;
      61         437 :         events.clear();
      62         437 : }
      63             : 
      64           0 : void DisableToothLogger() {
      65           0 :         ToothLoggerEnabled = false;
      66           0 : }
      67             : 
      68             : #else // not EFI_UNIT_TEST
      69             : 
      70             : static constexpr size_t BUFFER_COUNT = BIG_BUFFER_SIZE / sizeof(CompositeBuffer);
      71             : static_assert(BUFFER_COUNT >= 2);
      72             : 
      73             : static CompositeBuffer* buffers = nullptr;
      74             : static chibios_rt::Mailbox<CompositeBuffer*, BUFFER_COUNT> freeBuffers CCM_OPTIONAL;
      75             : static chibios_rt::Mailbox<CompositeBuffer*, BUFFER_COUNT> filledBuffers CCM_OPTIONAL;
      76             : 
      77             : static CompositeBuffer* currentBuffer = nullptr;
      78             : 
      79             : static void setToothLogReady(bool value) {
      80             : #if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
      81             :         engine->outputChannels.toothLogReady = value;
      82             : #endif // EFI_TUNER_STUDIO
      83             : }
      84             : 
      85             : static BigBufferHandle bufferHandle;
      86             : 
      87             : void EnableToothLogger() {
      88             :         chibios_rt::CriticalSectionLocker csl;
      89             : 
      90             :         bufferHandle = getBigBuffer(BigBufferUser::ToothLogger);
      91             :         if (!bufferHandle) {
      92             :                 return;
      93             :         }
      94             : 
      95             :         buffers = bufferHandle.get<CompositeBuffer>();
      96             : 
      97             :         // Reset all buffers
      98             :         for (size_t i = 0; i < BUFFER_COUNT; i++) {
      99             :                 buffers[i].nextIdx = 0;
     100             :         }
     101             : 
     102             :         // Reset state
     103             :         currentBuffer = nullptr;
     104             : 
     105             :         // Empty the filled buffer list
     106             :         CompositeBuffer* dummy;
     107             :         while (MSG_TIMEOUT != filledBuffers.fetchI(&dummy)) ;
     108             : 
     109             :         // Put all buffers in the free list
     110             :         for (size_t i = 0; i < BUFFER_COUNT; i++) {
     111             :                 freeBuffers.postI(&buffers[i]);
     112             :         }
     113             : 
     114             :         // Reset the last edge to now - this prevents the first edge logged from being bogus
     115             :         //lastEdgeTimestamp = getTimeNowUs();
     116             : 
     117             :         // Enable logging of edges as they come
     118             :         ToothLoggerEnabled = true;
     119             : 
     120             :         setToothLogReady(false);
     121             : }
     122             : 
     123             : void DisableToothLogger() {
     124             :         chibios_rt::CriticalSectionLocker csl;
     125             : 
     126             :         ToothLoggerEnabled = false;
     127             :         setToothLogReady(false);
     128             : 
     129             :         // Release the big buffer for another user
     130             :         // C++ magic: here we are calling BigBufferHandle::operator=() with empty instance
     131             :         bufferHandle = {};
     132             :         buffers = nullptr;
     133             : }
     134             : 
     135             : static CompositeBuffer* GetToothLoggerBufferImpl(sysinterval_t timeout) {
     136             :         CompositeBuffer* buffer;
     137             :         msg_t msg = filledBuffers.fetch(&buffer, timeout);
     138             : 
     139             :         if (msg == MSG_TIMEOUT) {
     140             :                 setToothLogReady(false);
     141             :                 return nullptr;
     142             :         }
     143             : 
     144             :         if (msg != MSG_OK) {
     145             :                 // What even happened if we didn't get timeout, but also didn't get OK?
     146             :                 return nullptr;
     147             :         }
     148             : 
     149             :         chibios_rt::CriticalSectionLocker csl;
     150             : 
     151             :         // If the used list is empty, clear the ready flag
     152             :         if (filledBuffers.getUsedCountI() == 0) {
     153             :                 setToothLogReady(false);
     154             :         }
     155             : 
     156             :         return buffer;
     157             : }
     158             : 
     159             : CompositeBuffer* GetToothLoggerBufferNonblocking() {
     160             :         return GetToothLoggerBufferImpl(TIME_IMMEDIATE);
     161             : }
     162             : 
     163             : CompositeBuffer* GetToothLoggerBufferBlocking() {
     164             :         return GetToothLoggerBufferImpl(TIME_INFINITE);
     165             : }
     166             : 
     167             : void ReturnToothLoggerBuffer(CompositeBuffer* buffer) {
     168             :         chibios_rt::CriticalSectionLocker csl;
     169             : 
     170             :         msg_t msg = freeBuffers.postI(buffer);
     171             :         criticalAssertVoid(msg == MSG_OK, "Composite logger post to free buffer fail");
     172             : }
     173             : 
     174             : static CompositeBuffer* findBuffer(efitick_t timestamp) {
     175             :         CompositeBuffer* buffer;
     176             : 
     177             :         if (!currentBuffer) {
     178             :                 // try and find a buffer, if none available, we can't log
     179             :                 if (MSG_OK != freeBuffers.fetchI(&buffer)) {
     180             :                         return nullptr;
     181             :                 }
     182             : 
     183             :                 // Record the time of the last buffer swap so we can force a swap after a minimum period of time
     184             :                 // This ensures the user sees *something* even if they don't have enough trigger events
     185             :                 // to fill the buffer.
     186             :                 buffer->startTime.reset(timestamp);
     187             :                 buffer->nextIdx = 0;
     188             : 
     189             :                 currentBuffer = buffer;
     190             :         }
     191             : 
     192             :         return currentBuffer;
     193             : }
     194             : 
     195             : static void SetNextCompositeEntry(efitick_t timestamp) {
     196             :         // This is called from multiple interrupts/threads, so we need a lock.
     197             :         chibios_rt::CriticalSectionLocker csl;
     198             : 
     199             :         CompositeBuffer* buffer = findBuffer(timestamp);
     200             : 
     201             :         if (!buffer) {
     202             :                 // All buffers are full, nothing to do here.
     203             :                 return;
     204             :         }
     205             : 
     206             :         size_t idx = buffer->nextIdx;
     207             :         auto nextIdx = idx + 1;
     208             :         buffer->nextIdx = nextIdx;
     209             : 
     210             :         if (idx < efi::size(buffer->buffer)) {
     211             :                 composite_logger_s* entry = &buffer->buffer[idx];
     212             : 
     213             :                 uint32_t nowUs = NT2US(timestamp);
     214             : 
     215             :                 // TS uses big endian, grumble
     216             :                 entry->timestamp = SWAP_UINT32(nowUs);
     217             :                 entry->priLevel = currentTrigger1;
     218             :                 entry->secLevel = currentTrigger2;
     219             :                 entry->trigger = currentTdc;
     220             :                 entry->sync = engine->triggerCentral.triggerState.getShaftSynchronized();
     221             :                 entry->coil = currentCoilState;
     222             :                 entry->injector = currentInjectorState;
     223             :         }
     224             : 
     225             :         // if the buffer is full...
     226             :         bool bufferFull = nextIdx >= efi::size(buffer->buffer);
     227             :         // ... or it's been too long since the last flush
     228             :         bool bufferTimedOut = buffer->startTime.hasElapsedSec(5);
     229             : 
     230             :         // Then cycle buffers and set the ready flag.
     231             :         if (bufferFull || bufferTimedOut) {
     232             :                 // Post to the output queue
     233             :                 filledBuffers.postI(buffer);
     234             : 
     235             :                 // Null the current buffer so we get a new one next time
     236             :                 currentBuffer = nullptr;
     237             : 
     238             :                 // Flag that we are ready
     239             :                 setToothLogReady(true);
     240             :         }
     241             : }
     242             : 
     243             : #endif // EFI_UNIT_TEST
     244             : 
     245       64819 : void LogTriggerTooth(trigger_event_e tooth, efitick_t timestamp) {
     246             :     efiAssertVoid(ObdCode::CUSTOM_ERR_6650, hasLotsOfRemainingStack(), "l-t-t");
     247             :         // bail if we aren't enabled
     248       64819 :         if (!ToothLoggerEnabled) {
     249           0 :                 return;
     250             :         }
     251             : 
     252             :         // Don't log at significant engine speed
     253       64819 :         if (!getTriggerCentral()->isEngineSnifferEnabled) {
     254           0 :                 return;
     255             :         }
     256             : 
     257       64819 :         ScopePerf perf(PE::LogTriggerTooth);
     258             : 
     259             : /*
     260             :                 // We currently only support the primary trigger falling edge
     261             :         // (this is the edge that VR sensors are accurate on)
     262             :         // Since VR sensors are the most useful case here, this is okay for now.
     263             :         if (tooth != SHAFT_PRIMARY_FALLING) {
     264             :                 return;
     265             :         }
     266             : 
     267             :         uint32_t nowUs = NT2US(timestamp);
     268             :         // 10us per LSB - this gives plenty of accuracy, yet fits 655.35 ms in to a uint16
     269             :         uint16_t delta = static_cast<uint16_t>((nowUs - lastEdgeTimestamp) / 10);
     270             :         lastEdgeTimestamp = nowUs;
     271             : 
     272             :         SetNextEntry(delta);
     273             : */
     274             : 
     275       64819 :         switch (tooth) {
     276       31080 :         case SHAFT_PRIMARY_FALLING:
     277       31080 :                 currentTrigger1 = false;
     278       31080 :                 break;
     279       31128 :         case SHAFT_PRIMARY_RISING:
     280       31128 :                 currentTrigger1 = true;
     281       31128 :                 break;
     282        1304 :         case SHAFT_SECONDARY_FALLING:
     283        1304 :                 currentTrigger2 = false;
     284        1304 :                 break;
     285        1307 :         case SHAFT_SECONDARY_RISING:
     286        1307 :                 currentTrigger2 = true;
     287        1307 :                 break;
     288           0 :         default:
     289           0 :                 break;
     290             :         }
     291             : 
     292       64819 :         SetNextCompositeEntry(timestamp);
     293             : }
     294             : 
     295        1294 : void LogTriggerTopDeadCenter(efitick_t timestamp) {
     296             :         // bail if we aren't enabled
     297        1294 :         if (!ToothLoggerEnabled) {
     298           0 :                 return;
     299             :         }
     300        1294 :         currentTdc = true;
     301        1294 :         SetNextCompositeEntry(timestamp);
     302        1294 :         currentTdc = false;
     303        1294 :         SetNextCompositeEntry(timestamp + 10);
     304             : }
     305             : 
     306       10227 : void LogTriggerCoilState(efitick_t timestamp, bool state) {
     307       10227 :         if (!ToothLoggerEnabled) {
     308           0 :                 return;
     309             :         }
     310       10227 :         currentCoilState = state;
     311             :         UNUSED(timestamp);
     312             :         //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
     313             : }
     314             : 
     315        4374 : void LogTriggerInjectorState(efitick_t timestamp, bool state) {
     316        4374 :         if (!ToothLoggerEnabled) {
     317           0 :                 return;
     318             :         }
     319        4374 :         currentInjectorState = state;
     320             :         UNUSED(timestamp);
     321             :         //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
     322             : }
     323             : 
     324           0 : void EnableToothLoggerIfNotEnabled() {
     325           0 :         if (!ToothLoggerEnabled) {
     326           0 :                 EnableToothLogger();
     327             :         }
     328           0 : }
     329             : 
     330           0 : bool IsToothLoggerEnabled() {
     331           0 :         return ToothLoggerEnabled;
     332             : }
     333             : 
     334             : #endif /* EFI_TOOTH_LOGGER */

Generated by: LCOV version 1.14