Implement TS tooth logger (#873)

* FW changes

* config changes

* whitespace

* comment

* simplify
This commit is contained in:
Matthew Kennedy 2019-07-06 17:48:58 -07:00 committed by rusefi
parent 1fce0201a5
commit d708f3e038
7 changed files with 144 additions and 15 deletions

View File

@ -75,6 +75,7 @@
#include "crc.h"
#include "bluetooth.h"
#include "tunerstudio_io.h"
#include "tooth_logger.h"
#include <string.h>
#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");

View File

@ -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

View File

@ -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

View File

@ -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) };
}

View File

@ -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();

View File

@ -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)) {

View File

@ -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]