rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
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
23static_assert(sizeof(composite_logger_s) == COMPOSITE_PACKET_SIZE, "composite packet size");
24
25static volatile bool ToothLoggerEnabled = false;
26//static uint32_t lastEdgeTimestamp = 0;
27
28static bool currentTrigger1 = false;
29static bool currentTrigger2 = false;
30static bool currentTdc = false;
31// any coil, all coils thrown together
32static bool currentCoilState = false;
33// same about injectors
34static bool currentInjectorState = false;
35
36#if EFI_UNIT_TEST
37
38void jsonTraceEntry(const char* name, int pid, bool isEnter, efitick_t timestamp) {
39extern FILE *jsonTrace;
40 if (jsonTrace != nullptr) {
41 fprintf(jsonTrace, ",\n");
42 fprintf(jsonTrace, "{\"name\":\"%s\",\"ph\":\"%s\",\"tid\":0,\"pid\":%d,\"ts\":%f}",
43 name,
44 isEnter ? "B" : "E",
45 pid,
46 timestamp / 1000.0);
47 }
48}
49
50#include "logicdata.h"
51
52static std::vector<CompositeEvent> events;
53
54const std::vector<CompositeEvent>& getCompositeEvents() {
55 return events;
56}
57
58void SetNextCompositeEntry(efitick_t timestamp) {
59 CompositeEvent event;
60
61 event.timestamp = timestamp;
62 event.primaryTrigger = currentTrigger1;
63 event.secondaryTrigger = currentTrigger2;
64 event.isTDC = currentTdc;
66 event.coil = currentCoilState;
67 event.injector = currentInjectorState;
68
69 events.push_back(event);
70}
71
73 ToothLoggerEnabled = true;
74 events.clear();
75}
76
78 ToothLoggerEnabled = false;
79}
80
81#else // not EFI_UNIT_TEST
82
83static constexpr size_t BUFFER_COUNT = BIG_BUFFER_SIZE / sizeof(CompositeBuffer);
84static_assert(BUFFER_COUNT >= 2);
85
86static CompositeBuffer* buffers = nullptr;
87static chibios_rt::Mailbox<CompositeBuffer*, BUFFER_COUNT> freeBuffers CCM_OPTIONAL;
88static chibios_rt::Mailbox<CompositeBuffer*, BUFFER_COUNT> filledBuffers CCM_OPTIONAL;
89
91
92static void setToothLogReady(bool value) {
93#if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
95#endif // EFI_TUNER_STUDIO
96}
97
99
100void EnableToothLogger() {
101 chibios_rt::CriticalSectionLocker csl;
102
104 if (!bufferHandle) {
105 return;
106 }
107
109
110 // Reset all buffers
111 for (size_t i = 0; i < BUFFER_COUNT; i++) {
112 buffers[i].nextIdx = 0;
113 }
114
115 // Reset state
116 currentBuffer = nullptr;
117
118 // Empty the filled buffer list
119 CompositeBuffer* dummy;
120 while (MSG_TIMEOUT != filledBuffers.fetchI(&dummy)) ;
121
122 // Put all buffers in the free list
123 for (size_t i = 0; i < BUFFER_COUNT; i++) {
124 freeBuffers.postI(&buffers[i]);
125 }
126
127 // Reset the last edge to now - this prevents the first edge logged from being bogus
128 //lastEdgeTimestamp = getTimeNowUs();
129
130 // Enable logging of edges as they come
131 ToothLoggerEnabled = true;
132
133 setToothLogReady(false);
134}
135
136void DisableToothLogger() {
137 chibios_rt::CriticalSectionLocker csl;
138
139 ToothLoggerEnabled = false;
140 setToothLogReady(false);
141
142 // Release the big buffer for another user
143 // C++ magic: here we are calling BigBufferHandle::operator=() with empty instance
144 bufferHandle = {};
145 buffers = nullptr;
146}
147
148static CompositeBuffer* GetToothLoggerBufferImpl(sysinterval_t timeout) {
150 msg_t msg = filledBuffers.fetch(&buffer, timeout);
151
152 if (msg == MSG_TIMEOUT) {
153 setToothLogReady(false);
154 return nullptr;
155 }
156
157 if (msg != MSG_OK) {
158 // What even happened if we didn't get timeout, but also didn't get OK?
159 return nullptr;
160 }
161
162 chibios_rt::CriticalSectionLocker csl;
163
164 // If the used list is empty, clear the ready flag
165 if (filledBuffers.getUsedCountI() == 0) {
166 setToothLogReady(false);
167 }
168
169 return buffer;
170}
171
175
179
181 chibios_rt::CriticalSectionLocker csl;
182
183 msg_t msg = freeBuffers.postI(buffer);
184 criticalAssertVoid(msg == MSG_OK, "Composite logger post to free buffer fail");
185}
186
187static CompositeBuffer* findBuffer(efitick_t timestamp) {
189
190 if (!currentBuffer) {
191 // try and find a buffer, if none available, we can't log
192 if (MSG_OK != freeBuffers.fetchI(&buffer)) {
193 return nullptr;
194 }
195
196 // Record the time of the last buffer swap so we can force a swap after a minimum period of time
197 // This ensures the user sees *something* even if they don't have enough trigger events
198 // to fill the buffer.
199 buffer->startTime.reset(timestamp);
200 buffer->nextIdx = 0;
201
203 }
204
205 return currentBuffer;
206}
207
208static void SetNextCompositeEntry(efitick_t timestamp) {
209 // This is called from multiple interrupts/threads, so we need a lock.
210 chibios_rt::CriticalSectionLocker csl;
211
212 CompositeBuffer* buffer = findBuffer(timestamp);
213
214 if (!buffer) {
215 // All buffers are full, nothing to do here.
216 return;
217 }
218
219 size_t idx = buffer->nextIdx;
220 auto nextIdx = idx + 1;
221 buffer->nextIdx = nextIdx;
222
223 if (idx < efi::size(buffer->buffer)) {
224 composite_logger_s* entry = &buffer->buffer[idx];
225
226 uint32_t nowUs = NT2US(timestamp);
227
228 // TS uses big endian, grumble
229 entry->timestamp = SWAP_UINT32(nowUs);
230 entry->priLevel = currentTrigger1;
231 entry->secLevel = currentTrigger2;
232 entry->trigger = currentTdc;
234 entry->coil = currentCoilState;
235 entry->injector = currentInjectorState;
236 }
237
238 // if the buffer is full...
239 bool bufferFull = nextIdx >= efi::size(buffer->buffer);
240 // ... or it's been too long since the last flush
241 bool bufferTimedOut = buffer->startTime.hasElapsedSec(5);
242
243 // Then cycle buffers and set the ready flag.
244 if (bufferFull || bufferTimedOut) {
245 // Post to the output queue
246 filledBuffers.postI(buffer);
247
248 // Null the current buffer so we get a new one next time
249 currentBuffer = nullptr;
250
251 // Flag that we are ready
252 setToothLogReady(true);
253 }
254}
255
256#endif // not EFI_UNIT_TEST
257
258#define JSON_TRG_PID 4
259#define JSON_CAM_PID 10
260
261void LogTriggerSync(bool isSync, efitick_t timestamp) {
262#if EFI_UNIT_TEST
263 jsonTraceEntry("sync", 3, /*isEnter*/isSync, timestamp);
264#else
265#endif
266}
267
268void LogTriggerCamTooth(bool isRising, efitick_t timestamp, int index) {
269#if EFI_UNIT_TEST
270 jsonTraceEntry("cam", JSON_CAM_PID + index, /*isEnter*/isRising, timestamp);
271#else
272#endif
273}
274
275void LogTriggerTooth(trigger_event_e tooth, efitick_t timestamp) {
276
277#if EFI_UNIT_TEST
278 if (tooth == SHAFT_PRIMARY_RISING) {
279 jsonTraceEntry("trg0", JSON_TRG_PID, /*isEnter*/true, timestamp);
280 } else if (tooth == SHAFT_PRIMARY_FALLING) {
281 jsonTraceEntry("trg0", JSON_TRG_PID, /*isEnter*/false, timestamp);
282 }
283#endif // EFI_UNIT_TEST
284
285 efiAssertVoid(ObdCode::CUSTOM_ERR_6650, hasLotsOfRemainingStack(), "l-t-t");
286 // bail if we aren't enabled
287 if (!ToothLoggerEnabled) {
288 return;
289 }
290
291 // Don't log at significant engine speed
292 if (!getTriggerCentral()->isEngineSnifferEnabled) {
293 return;
294 }
295
297
298/*
299 // We currently only support the primary trigger falling edge
300 // (this is the edge that VR sensors are accurate on)
301 // Since VR sensors are the most useful case here, this is okay for now.
302 if (tooth != SHAFT_PRIMARY_FALLING) {
303 return;
304 }
305
306 uint32_t nowUs = NT2US(timestamp);
307 // 10us per LSB - this gives plenty of accuracy, yet fits 655.35 ms in to a uint16
308 uint16_t delta = static_cast<uint16_t>((nowUs - lastEdgeTimestamp) / 10);
309 lastEdgeTimestamp = nowUs;
310
311 SetNextEntry(delta);
312*/
313
314 switch (tooth) {
316 currentTrigger1 = false;
317 break;
319 currentTrigger1 = true;
320 break;
322 currentTrigger2 = false;
323 break;
325 currentTrigger2 = true;
326 break;
327 default:
328 break;
329 }
330
331 SetNextCompositeEntry(timestamp);
332}
333
334void LogTriggerTopDeadCenter(efitick_t timestamp) {
335 // bail if we aren't enabled
336 if (!ToothLoggerEnabled) {
337 return;
338 }
339 currentTdc = true;
340 SetNextCompositeEntry(timestamp);
341 currentTdc = false;
342 SetNextCompositeEntry(timestamp + 10);
343}
344
345void LogTriggerCoilState(efitick_t timestamp, size_t index, bool state) {
346#if EFI_UNIT_TEST
347 jsonTraceEntry("coil", 20 + index, state, timestamp);
348#endif // EFI_UNIT_TEST
349 if (!ToothLoggerEnabled) {
350 return;
351 }
353 UNUSED(timestamp);
354 //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
355}
356
357void LogTriggerInjectorState(efitick_t timestamp, size_t index, bool state) {
358#if EFI_UNIT_TEST
359 jsonTraceEntry("inj", 30 + index, state, timestamp);
360#endif // EFI_UNIT_TEST
361 if (!ToothLoggerEnabled) {
362 return;
363 }
365 UNUSED(timestamp);
366 //SetNextCompositeEntry(timestamp, trigger1, trigger2, trigger);
367}
368
374
376 return ToothLoggerEnabled;
377}
378
379#endif /* EFI_TOOTH_LOGGER */
BigBufferHandle getBigBuffer(BigBufferUser user)
const TBuffer * get() const
Definition big_buffer.h:34
TriggerCentral triggerCentral
Definition engine.h:301
TunerStudioOutputChannels outputChannels
Definition engine.h:104
PrimaryTriggerDecoder triggerState
uint32_t SWAP_UINT32(uint32_t x)
Definition efilib.h:27
TriggerCentral * getTriggerCentral()
Definition engine.cpp:588
static Engine *const engine
Definition engine.h:386
UNUSED(samplingTimeSeconds)
static chibios_rt::Mailbox< CanFrameData *, canFrameCount > filledBuffers
static chibios_rt::Mailbox< CanFrameData *, canFrameCount > freeBuffers
@ CUSTOM_ERR_6650
@ LogTriggerTooth
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1739, 1.0, -1.0, -1.0, "")
trigger_event_e
@ SHAFT_SECONDARY_RISING
@ SHAFT_SECONDARY_FALLING
@ SHAFT_PRIMARY_FALLING
@ SHAFT_PRIMARY_RISING
static bool currentTrigger1
void jsonTraceEntry(const char *name, int pid, bool isEnter, efitick_t timestamp)
void DisableToothLogger()
static CompositeBuffer * GetToothLoggerBufferImpl(sysinterval_t timeout)
static bool currentTrigger2
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
static bool currentInjectorState
void EnableToothLogger()
void LogTriggerInjectorState(efitick_t timestamp, size_t index, bool state)
void LogTriggerCoilState(efitick_t timestamp, size_t index, bool state)
static bool currentCoilState
static CompositeBuffer * currentBuffer
void LogTriggerCamTooth(bool isRising, efitick_t timestamp, int index)
const std::vector< CompositeEvent > & getCompositeEvents()
static chibios_rt::Mailbox< CompositeBuffer *, BUFFER_COUNT > freeBuffers CCM_OPTIONAL
void LogTriggerSync(bool isSync, efitick_t timestamp)
CompositeBuffer * GetToothLoggerBufferNonblocking()
void ReturnToothLoggerBuffer(CompositeBuffer *buffer)
bool IsToothLoggerEnabled()
static CompositeBuffer * findBuffer(efitick_t timestamp)
static constexpr size_t BUFFER_COUNT
static bool currentTdc
CompositeBuffer * GetToothLoggerBufferBlocking()
static std::vector< CompositeEvent > events
void EnableToothLoggerIfNotEnabled()
void SetNextCompositeEntry(efitick_t timestamp)
static CompositeBuffer * buffers
composite_logger_s
static BigBufferHandle buffer