Add compile_commands.json for build configuration and update .gitignore to exclude .cache. Modify main.cpp to enhance CAN Bus Sniffer functionality with new ID definitions and optional scanning mode for improved data output.

This commit is contained in:
2026-03-01 10:44:17 +01:00
parent 02ed1d3bad
commit 78056f97ac
3 changed files with 349 additions and 54 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
.cache

290
compile_commands.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,8 @@
/** /**
* CAN Bus Sniffer for Renault Clio 3 2012 * CAN Bus Sniffer for Renault Clio 3 2012
* Reads all CAN packets via OBD2 pins 6 (CAN_H) and 14 (CAN_L) * IDs/formulas from x0r.fr reverse-engineering: https://x0r.fr/blog/39
* Target: odometer and RPM (not available via OBD2 PIDs)
*/ */
#define SCAN 0
#include <Arduino.h> #include <Arduino.h>
#include <ESP32-TWAI-CAN.hpp> #include <ESP32-TWAI-CAN.hpp>
@@ -19,6 +19,10 @@ void setup() {
delay(1000); delay(1000);
Serial.println("CAN Bus Sniffer - Renault Clio 3"); Serial.println("CAN Bus Sniffer - Renault Clio 3");
Serial.println("-------------------------------"); Serial.println("-------------------------------");
#if SCAN
Serial.println("SCAN: printing ALL frames. Run while idling, then at steady 50km/h.");
Serial.println("Share output to find correct RPM/speed IDs and byte positions.");
#endif
// Initialize TWAI with 500 kbps, RX=GPIO32, TX=GPIO33 // Initialize TWAI with 500 kbps, RX=GPIO32, TX=GPIO33
if (ESP32Can.begin(ESP32Can.convertSpeed(CAN_SPEED_KBPS), CAN_TX_GPIO, CAN_RX_GPIO, 10, 20)) { if (ESP32Can.begin(ESP32Can.convertSpeed(CAN_SPEED_KBPS), CAN_TX_GPIO, CAN_RX_GPIO, 10, 20)) {
@@ -33,84 +37,84 @@ void loop() {
// Non-blocking read (timeout 0) // Non-blocking read (timeout 0)
if (ESP32Can.readFrame(rxFrame, 0)) { if (ESP32Can.readFrame(rxFrame, 0)) {
// candump-style output: ID:0xXXX LEN:X DATA:XX XX XX XX XX XX XX XX #if SCAN
Serial.print("ID:0x"); Serial.printf("ID:0x%03X LEN:%d ", rxFrame.identifier, rxFrame.data_length_code);
Serial.print(rxFrame.identifier, HEX);
Serial.print(" LEN:");
Serial.print(rxFrame.data_length_code);
Serial.print(" DATA:");
for (int i = 0; i < rxFrame.data_length_code && i < 8; i++) { for (int i = 0; i < rxFrame.data_length_code && i < 8; i++) {
if (rxFrame.data[i] < 0x10) Serial.print("0"); Serial.printf("%02X ", rxFrame.data[i]);
Serial.print(rxFrame.data[i], HEX);
if (i < rxFrame.data_length_code - 1) Serial.print(" ");
} }
Serial.println(); Serial.println();
#else
// Optional: decode known Renault IDs (add as reverse-engineered)
decode_renault(rxFrame); decode_renault(rxFrame);
#endif
} }
} }
// Known Renault CAN IDs (Megane 3 RS / Clio 3 platform) // Renault Clio 3 - from x0r.fr/blog/39
#define ID_WHEEL_SPEED_FRONT 0x29A // 666 - FL, FR #define ID_ENGINE_RPM 0x1F9 // bytes 2-3 BE, raw/8 = RPM
#define ID_WHEEL_SPEED_REAR 0x29C // 668 - RL, RR #define ID_VEHICLE_SPEED 0x354 // bytes 0-1 BE, raw*0.01 = km/h
#define ID_ENGINE_RPM 0x230 // Common Renault/PSA engine broadcast (verify on your car) #define ID_SPEED_2 0x645 // bytes 3-4 BE, raw*0.01 = km/h (dashboard backlight msg)
#define ID_VEHICLE_SPEED 0x2D4 // Possible speed/odometer (verify on your car) #define ID_ODOMETER 0x5FD // bytes 2-4 BE, raw/13.0856 = km (cal: 114513)
#define ID_ODOMETER 0x5D7 // Renault Megane 3 / Clio 3 - bytes 2-5, (raw>>4)/100 = km
static uint16_t lastRpm = 0xFFFF;
static uint16_t lastSpeed = 0xFFFF;
static uint32_t lastOdo = 0xFFFFFFFF;
static uint32_t lastPrintMs = 0;
#define DEBOUNCE_MS 300
// Decoder for Renault Clio 3 - outputs human-readable values // Decoder for Renault Clio 3 - outputs human-readable values
void decode_renault(const CanFrame& frame) { void decode_renault(const CanFrame& frame) {
const uint8_t* d = frame.data; const uint8_t* d = frame.data;
uint8_t len = frame.data_length_code; uint8_t len = frame.data_length_code;
uint32_t now = millis();
switch (frame.identifier) { switch (frame.identifier) {
case ID_WHEEL_SPEED_FRONT: case ID_ENGINE_RPM: // 0x1F9 bytes 2-3 BE, raw/8 (x0r: "Régime moteur")
if (len >= 4) { if (len >= 4) {
uint16_t fr = (uint16_t)(d[1] << 8) | d[0]; uint16_t raw = (uint16_t)(d[2] << 8) | d[3];
uint16_t fl = (uint16_t)(d[3] << 8) | d[2]; uint16_t rpm = raw / 8;
float fr_kmh = fr * 0.005f; if (rpm >= 100 && rpm <= 7000 && (rpm != lastRpm || now - lastPrintMs > DEBOUNCE_MS)) {
float fl_kmh = fl * 0.005f; lastRpm = rpm;
Serial.printf(" -> [WheelSpeed Front] FL:%.1f km/h FR:%.1f km/h\n", fl_kmh, fr_kmh); lastPrintMs = now;
Serial.printf("RPM: %u\n", rpm);
}
} }
break; break;
case ID_WHEEL_SPEED_REAR: case ID_VEHICLE_SPEED: // 0x354 bytes 0-1 BE, raw*0.01 = km/h
if (len >= 4) {
uint16_t rr = (uint16_t)(d[1] << 8) | d[0];
uint16_t rl = (uint16_t)(d[3] << 8) | d[2];
float rr_kmh = rr * 0.005f;
float rl_kmh = rl * 0.005f;
Serial.printf(" -> [WheelSpeed Rear] RL:%.1f km/h RR:%.1f km/h\n", rl_kmh, rr_kmh);
}
break;
case ID_ENGINE_RPM:
if (len >= 4) {
uint16_t raw = (uint16_t)(d[3] << 8) | d[2];
uint16_t rpm = raw / 4;
if (rpm < 10000) Serial.printf(" -> [Engine] RPM: %u\n", rpm);
}
break;
case ID_VEHICLE_SPEED:
if (len >= 2) { if (len >= 2) {
uint16_t raw = (uint16_t)(d[1] << 8) | d[0]; uint16_t raw = (uint16_t)(d[0] << 8) | d[1];
float kmh = raw * 0.01f; float kmh = raw * 0.01f;
if (kmh < 300) Serial.printf(" -> [Speed] %.1f km/h\n", kmh); if (kmh < 250 && (raw != lastSpeed || now - lastPrintMs > DEBOUNCE_MS)) {
lastSpeed = raw;
lastPrintMs = now;
Serial.printf("Speed: %.1f km/h\n", kmh);
}
} }
break; break;
case ID_ODOMETER: case ID_SPEED_2: // 0x645 bytes 3-4 BE, raw*0.01 = km/h (x0r)
if (len >= 6) { if (len >= 5) {
// Renault Megane 3 / Clio 3: bytes 2-5, (raw>>4)/100 = km (from car-reminder project) uint16_t raw = (uint16_t)(d[3] << 8) | d[4];
uint32_t raw = (uint32_t)d[2] << 24 | (uint32_t)d[3] << 16 | float kmh = raw * 0.01f;
(uint32_t)d[4] << 8 | d[5]; if (kmh < 250 && (raw != lastSpeed || now - lastPrintMs > DEBOUNCE_MS)) {
uint32_t km = (raw >> 4) / 100; lastSpeed = raw;
if (km < 999999) Serial.printf(" -> [Odometer] %lu km\n", (unsigned long)km); lastPrintMs = now;
Serial.printf("Speed: %.1f km/h\n", kmh);
}
} }
break; break;
default: case ID_ODOMETER: // 0x5FD x0r: bytes 0-2 = km. This car uses bytes 2-4.
if (len >= 5) {
uint32_t raw = (uint32_t)d[2] << 16 | (uint32_t)d[3] << 8 | d[4];
uint32_t km = (uint32_t)(raw / 13.0834f); // cal: 114513
if (km < 999999 && (km != lastOdo || now - lastPrintMs > DEBOUNCE_MS)) {
lastOdo = km;
lastPrintMs = now;
Serial.printf("Odometer: %lu km\n", (unsigned long)km);
}
}
break; break;
} }
} }