diff --git a/firmware/console/binary/tunerstudio.cpp b/firmware/console/binary/tunerstudio.cpp index 215af80904..963b6648bd 100644 --- a/firmware/console/binary/tunerstudio.cpp +++ b/firmware/console/binary/tunerstudio.cpp @@ -75,6 +75,7 @@ #include "crc.h" #include "bluetooth.h" #include "tunerstudio_io.h" +#include "tooth_logger.h" #include #include "engine_configuration.h" @@ -448,8 +449,10 @@ static bool isKnownCommand(char command) { || command == TS_IO_TEST_COMMAND || command == TS_GET_STRUCT || command == TS_GET_FILE_RANGE - || command == TS_TOOTH_COMMAND - || command == TS_GET_TEXT || command == TS_CRC_CHECK_COMMAND + || command == TS_SET_LOGGER_MODE + || command == TS_GET_LOGGER_BUFFER + || command == TS_GET_TEXT + || command == TS_CRC_CHECK_COMMAND || command == TS_GET_FIRMWARE_VERSION; } @@ -790,6 +793,29 @@ int tunerStudioHandleCrcCommand(ts_channel_s *tsChannel, char *data, int incomin #endif /* EFI_PROD_CODE */ 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; default: tunerStudioError("ERROR: ignoring unexpected command"); diff --git a/firmware/console/binary/tunerstudio_io.h b/firmware/console/binary/tunerstudio_io.h index 2d9ddb234c..fe50ca6d64 100644 --- a/firmware/console/binary/tunerstudio_io.h +++ b/firmware/console/binary/tunerstudio_io.h @@ -68,7 +68,10 @@ typedef struct { #define TS_PAGE_COMMAND 'P' // 0x50 #define TS_COMMAND_F 'F' // 0x46 #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_CHUNK_WRITE_COMMAND 'C' // 0x43 pageChunkWrite diff --git a/firmware/console/console.mk b/firmware/console/console.mk index f2fc9a7993..d7344a5a28 100644 --- a/firmware/console/console.mk +++ b/firmware/console/console.mk @@ -3,5 +3,6 @@ CONSOLESRC = CONSOLE_SRC_CPP = $(PROJECT_DIR)/console/status_loop.cpp \ $(PROJECT_DIR)/console/console_io.cpp \ - $(PROJECT_DIR)/console/eficonsole.cpp + $(PROJECT_DIR)/console/eficonsole.cpp \ + $(PROJECT_DIR)/console/tooth_logger.cpp diff --git a/firmware/console/tooth_logger.cpp b/firmware/console/tooth_logger.cpp new file mode 100644 index 0000000000..241b64c1e1 --- /dev/null +++ b/firmware/console/tooth_logger.cpp @@ -0,0 +1,72 @@ +#include "tooth_logger.h" + +#include +#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((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(buffer), sizeof(buffer) }; +} diff --git a/firmware/console/tooth_logger.h b/firmware/console/tooth_logger.h new file mode 100644 index 0000000000..8e4d7354fe --- /dev/null +++ b/firmware/console/tooth_logger.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#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(); diff --git a/firmware/controllers/trigger/trigger_central.cpp b/firmware/controllers/trigger/trigger_central.cpp index e42a7d0e58..c209d7853e 100644 --- a/firmware/controllers/trigger/trigger_central.cpp +++ b/firmware/controllers/trigger/trigger_central.cpp @@ -17,6 +17,7 @@ #include "data_buffer.h" #include "histogram.h" #include "pwm_generator_logic.h" +#include "tooth_logger.h" #include "settings.h" #include "engine_math.h" @@ -190,6 +191,11 @@ static bool isInsideTriggerHandler = false; 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, // so we pass them to handleShaftSignal() and defer this test if (!CONFIGB(useNoiselessTriggerDecoder)) { diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index fed76bad3e..1e14019901 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -104,22 +104,20 @@ enable2ndByteCanID = false [LoggerDefinition] - ; valid logger types: composite, tooth, trigger, csv - loggerDef = tooth, "Tooth Logger", tooth - dataReadCommand = "L" - dataReadTimeout = 15000 ; time in ms - dataReadyCondition = { toothLogReady } - dataLength = 256 ; in bytes, including headers, footers and data + loggerDef = compositeLogger, "Primary Trigger Logger", tooth + startCommand = "l\x01" + stopCommand = "l\x02" + dataReadCommand = "L" + dataReadTimeout = 10000 ; time in ms + dataReadyCondition = { toothLogReady } ; 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]