dashboard: add passive CAN capture markers
This commit is contained in:
@@ -40,6 +40,20 @@ static constexpr uint32_t OBD_REQUEST_ID = 0x7DF;
|
||||
static constexpr uint32_t OBD_RESPONSE_ID_MIN = 0x7E8;
|
||||
static constexpr uint32_t OBD_RESPONSE_ID_MAX = 0x7EF;
|
||||
static constexpr uint8_t OBD_PID_COOLANT_TEMP = 0x05;
|
||||
static constexpr size_t CAN_TRACKED_ID_COUNT = 96;
|
||||
static constexpr unsigned long CAN_LOG_MIN_INTERVAL_MS = 100;
|
||||
|
||||
struct CanTrackedFrame {
|
||||
bool used = false;
|
||||
bool extended = false;
|
||||
uint32_t identifier = 0;
|
||||
uint8_t dlc = 0;
|
||||
uint8_t data[8] = {};
|
||||
unsigned long last_log_ms = 0;
|
||||
};
|
||||
|
||||
static CanTrackedFrame can_tracked_frames[CAN_TRACKED_ID_COUNT];
|
||||
static String can_serial_command;
|
||||
|
||||
static bool obd_can_ready = false;
|
||||
static bool obd_can_started = false;
|
||||
@@ -444,9 +458,9 @@ static bool init_obd_can()
|
||||
return true;
|
||||
}
|
||||
|
||||
twai_general_config_t general_config = TWAI_GENERAL_CONFIG_DEFAULT(OBD_CAN_TX_PIN, OBD_CAN_RX_PIN, TWAI_MODE_NORMAL);
|
||||
general_config.tx_queue_len = 5;
|
||||
general_config.rx_queue_len = 20;
|
||||
twai_general_config_t general_config = TWAI_GENERAL_CONFIG_DEFAULT(OBD_CAN_TX_PIN, OBD_CAN_RX_PIN, TWAI_MODE_LISTEN_ONLY);
|
||||
general_config.tx_queue_len = 0;
|
||||
general_config.rx_queue_len = 64;
|
||||
|
||||
twai_timing_config_t timing_config = TWAI_TIMING_CONFIG_500KBITS();
|
||||
twai_filter_config_t filter_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
@@ -471,37 +485,12 @@ static bool init_obd_can()
|
||||
|
||||
obd_can_started = true;
|
||||
obd_last_error = "started";
|
||||
Serial.println("OBD CAN: TWAI started on TX GPIO15 / RX GPIO16 at 500 kbps");
|
||||
Serial.println("OBD CAN: passive logger started on RX GPIO16 at 500 kbps");
|
||||
Serial.println("CAN CSV: CAN,ms,id,format,dlc,b0,b1,b2,b3,b4,b5,b6,b7");
|
||||
Serial.println("Enter TEMP,<degrees F> when recording a scan-tool coolant reading.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void send_obd_coolant_request()
|
||||
{
|
||||
twai_message_t message = {};
|
||||
message.identifier = OBD_REQUEST_ID;
|
||||
message.extd = 0;
|
||||
message.rtr = 0;
|
||||
message.data_length_code = 8;
|
||||
message.data[0] = 0x02;
|
||||
message.data[1] = 0x01;
|
||||
message.data[2] = OBD_PID_COOLANT_TEMP;
|
||||
message.data[3] = 0x55;
|
||||
message.data[4] = 0x55;
|
||||
message.data[5] = 0x55;
|
||||
message.data[6] = 0x55;
|
||||
message.data[7] = 0x55;
|
||||
|
||||
esp_err_t result = twai_transmit(&message, 0);
|
||||
if (result == ESP_OK) {
|
||||
obd_tx_count++;
|
||||
last_obd_tx_ms = millis();
|
||||
obd_last_error = "coolant request sent";
|
||||
} else {
|
||||
obd_tx_fail_count++;
|
||||
obd_last_error = "tx failed: " + String((int)result);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_obd_can_message(const twai_message_t &message)
|
||||
{
|
||||
if (message.extd || message.rtr) {
|
||||
@@ -533,16 +522,97 @@ static void handle_obd_can_message(const twai_message_t &message)
|
||||
}
|
||||
}
|
||||
|
||||
static CanTrackedFrame *find_can_tracked_frame(const twai_message_t &message)
|
||||
{
|
||||
CanTrackedFrame *free_slot = nullptr;
|
||||
for (size_t i = 0; i < CAN_TRACKED_ID_COUNT; i++) {
|
||||
CanTrackedFrame &tracked = can_tracked_frames[i];
|
||||
if (tracked.used && tracked.identifier == message.identifier && tracked.extended == message.extd) {
|
||||
return &tracked;
|
||||
}
|
||||
if (!tracked.used && free_slot == nullptr) free_slot = &tracked;
|
||||
}
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
static void log_changed_can_frame(const twai_message_t &message)
|
||||
{
|
||||
if (message.rtr) return;
|
||||
|
||||
CanTrackedFrame *tracked = find_can_tracked_frame(message);
|
||||
if (tracked == nullptr) return;
|
||||
|
||||
bool changed = !tracked->used || tracked->dlc != message.data_length_code;
|
||||
for (uint8_t i = 0; i < message.data_length_code && i < 8; i++) {
|
||||
changed = changed || tracked->data[i] != message.data[i];
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
bool should_log = changed && (!tracked->used || now - tracked->last_log_ms >= CAN_LOG_MIN_INTERVAL_MS);
|
||||
tracked->used = true;
|
||||
tracked->extended = message.extd;
|
||||
tracked->identifier = message.identifier;
|
||||
tracked->dlc = message.data_length_code;
|
||||
memcpy(tracked->data, message.data, sizeof(tracked->data));
|
||||
|
||||
if (!should_log) return;
|
||||
|
||||
tracked->last_log_ms = now;
|
||||
Serial.print("CAN,");
|
||||
Serial.print(now);
|
||||
Serial.print(",");
|
||||
Serial.print(message.identifier, HEX);
|
||||
Serial.print(message.extd ? ",EXT," : ",STD,");
|
||||
Serial.print(message.data_length_code);
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
Serial.print(",");
|
||||
if (i < message.data_length_code) {
|
||||
if (message.data[i] < 0x10) Serial.print("0");
|
||||
Serial.print(message.data[i], HEX);
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
static void process_can_serial_commands()
|
||||
{
|
||||
while (Serial.available() > 0) {
|
||||
char value = (char)Serial.read();
|
||||
if (value == '\r') continue;
|
||||
if (value != '\n') {
|
||||
if (can_serial_command.length() < 48) can_serial_command += value;
|
||||
continue;
|
||||
}
|
||||
|
||||
can_serial_command.trim();
|
||||
if (can_serial_command.startsWith("TEMP,")) {
|
||||
String temperature = can_serial_command.substring(5);
|
||||
temperature.trim();
|
||||
Serial.print("TEMP,");
|
||||
Serial.print(millis());
|
||||
Serial.print(",");
|
||||
Serial.println(temperature);
|
||||
} else if (can_serial_command.startsWith("MARK,")) {
|
||||
String label = can_serial_command.substring(5);
|
||||
label.trim();
|
||||
Serial.print("MARK,");
|
||||
Serial.print(millis());
|
||||
Serial.print(",");
|
||||
Serial.println(label);
|
||||
} else if (can_serial_command.length() > 0) {
|
||||
Serial.println("ERROR,expected TEMP,<degrees F> or MARK,<label>");
|
||||
}
|
||||
can_serial_command = "";
|
||||
}
|
||||
}
|
||||
|
||||
static void process_obd_can()
|
||||
{
|
||||
if (!init_obd_can()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (millis() - last_obd_poll_ms >= 1000) {
|
||||
last_obd_poll_ms = millis();
|
||||
send_obd_coolant_request();
|
||||
}
|
||||
process_can_serial_commands();
|
||||
|
||||
twai_message_t message = {};
|
||||
while (twai_receive(&message, 0) == ESP_OK) {
|
||||
@@ -552,6 +622,7 @@ static void process_obd_can()
|
||||
obd_last_rx_extended = message.extd;
|
||||
last_obd_raw_rx_ms = millis();
|
||||
|
||||
log_changed_can_frame(message);
|
||||
handle_obd_can_message(message);
|
||||
}
|
||||
|
||||
@@ -635,23 +706,14 @@ static void update_diagnostics_overlay()
|
||||
text += String(status_model.cell_delta_mv);
|
||||
text += " mV";
|
||||
|
||||
text += "\n\nOBD-II / CAN\n";
|
||||
text += "\n\nPassive CAN Logger\n";
|
||||
text += " TWAI: ";
|
||||
text += obd_can_started ? "started" : "offline";
|
||||
text += " @ 500 kbps";
|
||||
text += "\n Pins: TX GPIO15 / RX GPIO16";
|
||||
text += "\n Coolant: ";
|
||||
text += obd_coolant_temp_f > -100 ? String(obd_coolant_temp_f) + "°F" : String("--");
|
||||
|
||||
text += "\n Requests OK/fail: ";
|
||||
text += String(obd_tx_count);
|
||||
text += "/";
|
||||
text += String(obd_tx_fail_count);
|
||||
|
||||
text += "\n Raw RX/coolant RX: ";
|
||||
text += "\n Mode: listen-only (no transmit)";
|
||||
text += "\n Raw RX: ";
|
||||
text += String(obd_raw_rx_count);
|
||||
text += "/";
|
||||
text += String(obd_rx_count);
|
||||
|
||||
text += "\n Last frame: ";
|
||||
if (obd_raw_rx_count > 0) {
|
||||
|
||||
Reference in New Issue
Block a user