Implement TS tooth logger (#873)
* FW changes * config changes * whitespace * comment * simplify
This commit is contained in:
parent
1fce0201a5
commit
d708f3e038
|
@ -75,6 +75,7 @@
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "bluetooth.h"
|
#include "bluetooth.h"
|
||||||
#include "tunerstudio_io.h"
|
#include "tunerstudio_io.h"
|
||||||
|
#include "tooth_logger.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "engine_configuration.h"
|
#include "engine_configuration.h"
|
||||||
|
@ -448,8 +449,10 @@ static bool isKnownCommand(char command) {
|
||||||
|| command == TS_IO_TEST_COMMAND
|
|| command == TS_IO_TEST_COMMAND
|
||||||
|| command == TS_GET_STRUCT
|
|| command == TS_GET_STRUCT
|
||||||
|| command == TS_GET_FILE_RANGE
|
|| command == TS_GET_FILE_RANGE
|
||||||
|| command == TS_TOOTH_COMMAND
|
|| command == TS_SET_LOGGER_MODE
|
||||||
|| command == TS_GET_TEXT || command == TS_CRC_CHECK_COMMAND
|
|| command == TS_GET_LOGGER_BUFFER
|
||||||
|
|| command == TS_GET_TEXT
|
||||||
|
|| command == TS_CRC_CHECK_COMMAND
|
||||||
|| command == TS_GET_FIRMWARE_VERSION;
|
|| command == TS_GET_FIRMWARE_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,6 +793,29 @@ int tunerStudioHandleCrcCommand(ts_channel_s *tsChannel, char *data, int incomin
|
||||||
#endif /* EFI_PROD_CODE */
|
#endif /* EFI_PROD_CODE */
|
||||||
sendOkResponse(tsChannel, TS_CRC);
|
sendOkResponse(tsChannel, TS_CRC);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case TS_SET_LOGGER_MODE:
|
||||||
|
switch(data[0]) {
|
||||||
|
case 0x01:
|
||||||
|
EnableToothLogger();
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
DisableToothLogger();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// dunno what that was, send NAK
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendOkResponse(tsChannel, TS_CRC);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TS_GET_LOGGER_BUFFER:
|
||||||
|
{
|
||||||
|
auto toothBuffer = GetToothLoggerBuffer();
|
||||||
|
sr5SendResponse(tsChannel, TS_CRC, toothBuffer.Buffer, toothBuffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tunerStudioError("ERROR: ignoring unexpected command");
|
tunerStudioError("ERROR: ignoring unexpected command");
|
||||||
|
|
|
@ -68,7 +68,10 @@ typedef struct {
|
||||||
#define TS_PAGE_COMMAND 'P' // 0x50
|
#define TS_PAGE_COMMAND 'P' // 0x50
|
||||||
#define TS_COMMAND_F 'F' // 0x46
|
#define TS_COMMAND_F 'F' // 0x46
|
||||||
#define TS_GET_FIRMWARE_VERSION 'V' // versionInfo
|
#define TS_GET_FIRMWARE_VERSION 'V' // versionInfo
|
||||||
#define TS_TOOTH_COMMAND 'L' // 0x4C
|
|
||||||
|
// High speed logger commands
|
||||||
|
#define TS_SET_LOGGER_MODE 'l'
|
||||||
|
#define TS_GET_LOGGER_BUFFER 'L'
|
||||||
|
|
||||||
#define TS_SINGLE_WRITE_COMMAND 'W' // 0x57 pageValueWrite
|
#define TS_SINGLE_WRITE_COMMAND 'W' // 0x57 pageValueWrite
|
||||||
#define TS_CHUNK_WRITE_COMMAND 'C' // 0x43 pageChunkWrite
|
#define TS_CHUNK_WRITE_COMMAND 'C' // 0x43 pageChunkWrite
|
||||||
|
|
|
@ -3,5 +3,6 @@ CONSOLESRC =
|
||||||
|
|
||||||
CONSOLE_SRC_CPP = $(PROJECT_DIR)/console/status_loop.cpp \
|
CONSOLE_SRC_CPP = $(PROJECT_DIR)/console/status_loop.cpp \
|
||||||
$(PROJECT_DIR)/console/console_io.cpp \
|
$(PROJECT_DIR)/console/console_io.cpp \
|
||||||
$(PROJECT_DIR)/console/eficonsole.cpp
|
$(PROJECT_DIR)/console/eficonsole.cpp \
|
||||||
|
$(PROJECT_DIR)/console/tooth_logger.cpp
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#include "tooth_logger.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include "efitime.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "efilib.h"
|
||||||
|
#include "tunerstudio_configuration.h"
|
||||||
|
|
||||||
|
extern TunerStudioOutputChannels tsOutputChannels;
|
||||||
|
|
||||||
|
static uint16_t buffer[1000] CCM_OPTIONAL;
|
||||||
|
static size_t NextIdx = 0;
|
||||||
|
static volatile bool ToothLoggerEnabled = false;
|
||||||
|
|
||||||
|
static uint32_t lastEdgeTimestamp = 0;
|
||||||
|
|
||||||
|
void SetNextEntry(uint16_t entry) {
|
||||||
|
// TS uses big endian, grumble
|
||||||
|
buffer[NextIdx] = SWAP_UINT16(entry);
|
||||||
|
NextIdx++;
|
||||||
|
|
||||||
|
// If we hit the end, loop
|
||||||
|
if (NextIdx >= sizeof(buffer) / sizeof(buffer[0])) {
|
||||||
|
NextIdx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogTriggerTooth(trigger_event_e tooth) {
|
||||||
|
// bail if we aren't enabled
|
||||||
|
if (!ToothLoggerEnabled) return;
|
||||||
|
|
||||||
|
// We currently only support the primary trigger falling edge
|
||||||
|
// (this is the edge that VR sensors are accurate on)
|
||||||
|
// Since VR senors are the most useful case here, this is okay for now.
|
||||||
|
if (tooth != SHAFT_PRIMARY_FALLING) return;
|
||||||
|
|
||||||
|
uint32_t nowUs = NT2US(getTimeNowNt());
|
||||||
|
// 10us per LSB - this gives plenty of accuracy, yet fits 655.35 ms in to a uint16
|
||||||
|
uint16_t delta = static_cast<uint16_t>((nowUs - lastEdgeTimestamp) / 10);
|
||||||
|
lastEdgeTimestamp = nowUs;
|
||||||
|
|
||||||
|
SetNextEntry(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableToothLogger() {
|
||||||
|
// Clear the buffer
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
// Reset the last edge to now - this prevents the first edge logged from being bogus
|
||||||
|
lastEdgeTimestamp = NT2US(getTimeNowNt());
|
||||||
|
|
||||||
|
// Reset write index
|
||||||
|
NextIdx = 0;
|
||||||
|
|
||||||
|
// Enable logging of edges as they come
|
||||||
|
ToothLoggerEnabled = true;
|
||||||
|
|
||||||
|
// Tell TS that we're ready for it to read out the log
|
||||||
|
// nb: this is a lie, as we may not have written anything
|
||||||
|
// yet. However, we can let it continuously read out the buffer
|
||||||
|
// as we update it, which looks pretty nice.
|
||||||
|
tsOutputChannels.toothLogReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisableToothLogger() {
|
||||||
|
ToothLoggerEnabled = false;
|
||||||
|
tsOutputChannels.toothLogReady = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToothLoggerBuffer GetToothLoggerBuffer() {
|
||||||
|
return { reinterpret_cast<uint8_t*>(buffer), sizeof(buffer) };
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include "rusefi_enums.h"
|
||||||
|
|
||||||
|
// Enable the tooth logger - this clears the buffer starts logging
|
||||||
|
void EnableToothLogger();
|
||||||
|
|
||||||
|
// Stop logging - leave buffer intact
|
||||||
|
void DisableToothLogger();
|
||||||
|
|
||||||
|
// A new tooth has arrived! Log to the buffer if enabled.
|
||||||
|
void LogTriggerTooth(trigger_event_e tooth);
|
||||||
|
|
||||||
|
struct ToothLoggerBuffer
|
||||||
|
{
|
||||||
|
const uint8_t* const Buffer;
|
||||||
|
const size_t Length;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get a reference to the buffer
|
||||||
|
ToothLoggerBuffer GetToothLoggerBuffer();
|
|
@ -17,6 +17,7 @@
|
||||||
#include "data_buffer.h"
|
#include "data_buffer.h"
|
||||||
#include "histogram.h"
|
#include "histogram.h"
|
||||||
#include "pwm_generator_logic.h"
|
#include "pwm_generator_logic.h"
|
||||||
|
#include "tooth_logger.h"
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "engine_math.h"
|
#include "engine_math.h"
|
||||||
|
@ -190,6 +191,11 @@ static bool isInsideTriggerHandler = false;
|
||||||
|
|
||||||
|
|
||||||
void hwHandleShaftSignal(trigger_event_e signal) {
|
void hwHandleShaftSignal(trigger_event_e signal) {
|
||||||
|
// Log to the Tunerstudio tooth logger
|
||||||
|
// We want to do this before anything else as we
|
||||||
|
// actually want to capture any noise/jitter that may be occuring
|
||||||
|
LogTriggerTooth(signal);
|
||||||
|
|
||||||
// for effective noise filtering, we need both signal edges,
|
// for effective noise filtering, we need both signal edges,
|
||||||
// so we pass them to handleShaftSignal() and defer this test
|
// so we pass them to handleShaftSignal() and defer this test
|
||||||
if (!CONFIGB(useNoiselessTriggerDecoder)) {
|
if (!CONFIGB(useNoiselessTriggerDecoder)) {
|
||||||
|
|
|
@ -104,22 +104,20 @@ enable2ndByteCanID = false
|
||||||
|
|
||||||
|
|
||||||
[LoggerDefinition]
|
[LoggerDefinition]
|
||||||
|
|
||||||
; valid logger types: composite, tooth, trigger, csv
|
; valid logger types: composite, tooth, trigger, csv
|
||||||
loggerDef = tooth, "Tooth Logger", tooth
|
loggerDef = compositeLogger, "Primary Trigger Logger", tooth
|
||||||
dataReadCommand = "L"
|
startCommand = "l\x01"
|
||||||
dataReadTimeout = 15000 ; time in ms
|
stopCommand = "l\x02"
|
||||||
dataReadyCondition = { toothLogReady }
|
dataReadCommand = "L"
|
||||||
dataLength = 256 ; in bytes, including headers, footers and data
|
dataReadTimeout = 10000 ; time in ms
|
||||||
|
dataReadyCondition = { toothLogReady }
|
||||||
|
|
||||||
; recordDef = headerLen, footerLen, recordLen
|
; recordDef = headerLen, footerLen, recordLen
|
||||||
recordDef = 0, 0, 4; in bytes, the recordLen is for each record, currently limited to 4 bytes
|
recordDef = 0, 0, 2; in bytes, the recordLen is for each record, currently limited to 4 bytes
|
||||||
|
|
||||||
|
; uint16 that stores 1/100 second
|
||||||
|
recordField = toothTime, "tooth", 0, 16, 0.01, "ms"
|
||||||
|
|
||||||
recordField = PA3, "Inj D", 3, 1, 1, ""
|
|
||||||
recordField = PA2, "Inj C", 2, 1, 1, ""
|
|
||||||
recordField = PA1, "Inj B", 1, 1, 1, ""
|
|
||||||
recordField = PA0, "Inj A", 0, 1, 1, ""
|
|
||||||
|
|
||||||
[VeAnalyze]
|
[VeAnalyze]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue