rusEFI
The most advanced open source ECU
tooth_logger.cpp
Go to the documentation of this file.
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 const std::vector<CompositeEvent>& getCompositeEvents() {
42  return events;
43 }
44 
45 void SetNextCompositeEntry(efitick_t timestamp) {
46  CompositeEvent event;
47 
48  event.timestamp = timestamp;
49  event.primaryTrigger = currentTrigger1;
50  event.secondaryTrigger = currentTrigger2;
51  event.isTDC = currentTdc;
53  event.coil = currentCoilState;
54  event.injector = currentInjectorState;
55 
56  events.push_back(event);
57 }
58 
60  ToothLoggerEnabled = true;
61  events.clear();
62 }
63 
65  ToothLoggerEnabled = false;
66 }
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)
82 #endif // EFI_TUNER_STUDIO
83 }
84 
86 
87 void EnableToothLogger() {
88  chibios_rt::CriticalSectionLocker csl;
89 
91  if (!bufferHandle) {
92  return;
93  }
94 
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) {
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 
160  return GetToothLoggerBufferImpl(TIME_IMMEDIATE);
161 }
162 
164  return GetToothLoggerBufferImpl(TIME_INFINITE);
165 }
166 
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) {
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 
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;
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 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  if (!ToothLoggerEnabled) {
249  return;
250  }
251 
252  // Don't log at significant engine speed
253  if (!getTriggerCentral()->isEngineSnifferEnabled) {
254  return;
255  }
256 
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  switch (tooth) {
277  currentTrigger1 = false;
278  break;
280  currentTrigger1 = true;
281  break;
283  currentTrigger2 = false;
284  break;
286  currentTrigger2 = true;
287  break;
288  default:
289  break;
290  }
291 
292  SetNextCompositeEntry(timestamp);
293 }
294 
295 void LogTriggerTopDeadCenter(efitick_t timestamp) {
296  // bail if we aren't enabled
297  if (!ToothLoggerEnabled) {
298  return;
299  }
300  currentTdc = true;
301  SetNextCompositeEntry(timestamp);
302  currentTdc = false;
303  SetNextCompositeEntry(timestamp + 10);
304 }
305 
306 void LogTriggerCoilState(efitick_t timestamp, bool state) {
307  if (!ToothLoggerEnabled) {
308  return;
309  }
311  UNUSED(timestamp);
312  //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
313 }
314 
315 void LogTriggerInjectorState(efitick_t timestamp, bool state) {
316  if (!ToothLoggerEnabled) {
317  return;
318  }
320  UNUSED(timestamp);
321  //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
322 }
323 
325  if (!ToothLoggerEnabled) {
327  }
328 }
329 
331  return ToothLoggerEnabled;
332 }
333 
334 #endif /* EFI_TOOTH_LOGGER */
BigBufferHandle getBigBuffer(BigBufferUser user)
Definition: big_buffer.cpp:61
const TBuffer * get() const
Definition: big_buffer.h:34
TriggerCentral triggerCentral
Definition: engine.h:286
TunerStudioOutputChannels outputChannels
Definition: engine.h:99
PrimaryTriggerDecoder triggerState
uint32_t SWAP_UINT32(uint32_t x)
Definition: efilib.h:27
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:589
Engine * engine
UNUSED(samplingTimeSeconds)
static chibios_rt::Mailbox< CanFrameData *, canFrameCount > filledBuffers
Definition: lua_can_rx.cpp:27
static chibios_rt::Mailbox< CanFrameData *, canFrameCount > freeBuffers
Definition: lua_can_rx.cpp:25
@ CUSTOM_ERR_6650
@ LogTriggerTooth
static ScState state
trigger_event_e
@ SHAFT_SECONDARY_RISING
@ SHAFT_SECONDARY_FALLING
@ SHAFT_PRIMARY_FALLING
@ SHAFT_PRIMARY_RISING
void LogTriggerInjectorState(efitick_t timestamp, bool state)
void LogTriggerTooth(trigger_event_e tooth, efitick_t timestamp)
composite packet size
static bool currentTrigger1
void DisableToothLogger()
static bool currentTrigger2
static CompositeBuffer * GetToothLoggerBufferImpl(sysinterval_t timeout)
void LogTriggerTopDeadCenter(efitick_t timestamp)
static volatile bool ToothLoggerEnabled
fail("EFI_SHAFT_POSITION_INPUT required to have EFI_EMULATE_POSITION_SENSORS") static_assert(sizeof(composite_logger_s)
static void setToothLogReady(bool value)
static BigBufferHandle bufferHandle
const std::vector< CompositeEvent > & getCompositeEvents()
static bool currentInjectorState
void EnableToothLogger()
CompositeBuffer * GetToothLoggerBufferBlocking()
void LogTriggerCoilState(efitick_t timestamp, bool state)
static bool currentCoilState
static CompositeBuffer * currentBuffer
static CompositeBuffer * findBuffer(efitick_t timestamp)
static chibios_rt::Mailbox< CompositeBuffer *, BUFFER_COUNT > freeBuffers CCM_OPTIONAL
CompositeBuffer * GetToothLoggerBufferNonblocking()
void ReturnToothLoggerBuffer(CompositeBuffer *buffer)
bool IsToothLoggerEnabled()
static constexpr size_t BUFFER_COUNT
static bool currentTdc
static std::vector< CompositeEvent > events
void EnableToothLoggerIfNotEnabled()
void SetNextCompositeEntry(efitick_t timestamp)
static CompositeBuffer * buffers
composite_logger_s
Definition: tooth_logger.h:48
static BigBufferHandle buffer