diff --git a/examples/Car Specific/Honda/Honda.ino b/examples/Car Specific/Honda/Honda.ino index 591c492..77603b2 100644 --- a/examples/Car Specific/Honda/Honda.ino +++ b/examples/Car Specific/Honda/Honda.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + //KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + //KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + //KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + //KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("Honda Code."); } @@ -29,19 +34,19 @@ void loop() { void Honda_Simulator() { if (KLine.readData()) { - if (KLine.compareData(hondaEngine, sizeof(hondaEngine))) KLine.writeRawData(hondaEngine_Response, sizeof(hondaEngine_Response), 0); - else if (KLine.compareData(hondaEngine2, sizeof(hondaEngine2))) KLine.writeRawData(hondaEngine_Response, sizeof(hondaEngine_Response), 0); - else if (KLine.compareData(hondaEngine_LiveData1, sizeof(hondaEngine_LiveData1))) KLine.writeRawData(hondaEngine_LiveData1_R, sizeof(hondaEngine_LiveData1_R), 0); - else if (KLine.compareData(hondaEngine_LiveData2, sizeof(hondaEngine_LiveData2))) KLine.writeRawData(hondaEngine_LiveData2_R, sizeof(hondaEngine_LiveData2_R), 3); - else if (KLine.compareData(hondaEngine_LiveData3, sizeof(hondaEngine_LiveData3))) KLine.writeRawData(hondaEngine_LiveData3_R, sizeof(hondaEngine_LiveData3_R), 0); - else if (KLine.compareData(hondaEngine_LiveData4, sizeof(hondaEngine_LiveData4))) KLine.writeRawData(hondaEngine_LiveData4_R, sizeof(hondaEngine_LiveData4_R), 0); - else if (KLine.compareData(hondaEngine_LiveData5, sizeof(hondaEngine_LiveData5))) KLine.writeRawData(hondaEngine_LiveData5_R, sizeof(hondaEngine_LiveData5_R), 0); - else if (KLine.compareData(hondaEngine_LiveData6, sizeof(hondaEngine_LiveData6))) KLine.writeRawData(hondaEngine_LiveData6_R, sizeof(hondaEngine_LiveData6_R), 0); - else if (KLine.compareData(hondaEngine_LiveData7, sizeof(hondaEngine_LiveData7))) KLine.writeRawData(hondaEngine_LiveData7_R, sizeof(hondaEngine_LiveData7_R), 0); - else if (KLine.compareData(hondaEngine_LiveData8, sizeof(hondaEngine_LiveData8))) KLine.writeRawData(hondaEngine_LiveData8_R, sizeof(hondaEngine_LiveData8_R), 0); - else if (KLine.compareData(hondaEngine_LiveData9, sizeof(hondaEngine_LiveData9))) KLine.writeRawData(hondaEngine_LiveData9_R, sizeof(hondaEngine_LiveData9_R), 0); - else if (KLine.compareData(hondaEngine_ReadDTCs, sizeof(hondaEngine_ReadDTCs))) KLine.writeRawData(hondaEngine_ReadDTCs_R, sizeof(hondaEngine_ReadDTCs_R), 0); - else if (KLine.compareData(hondaEngine_ClearDTCs, sizeof(hondaEngine_ClearDTCs))) KLine.writeRawData(hondaEngine_ClearDTCs_R, sizeof(hondaEngine_ClearDTCs_R), 0); - //else if (KLine.compareData(hondaABS, sizeof(hondaABS))) KLine.writeRawData(hondaABS_Response, sizeof(hondaABS_Response), false); + if (KLine.compareData(hondaEngine)) KLine.writeRawData(hondaEngine_Response, 0); + else if (KLine.compareData(hondaEngine2)) KLine.writeRawData(hondaEngine_Response, 0); + else if (KLine.compareData(hondaEngine_LiveData1)) KLine.writeRawData(hondaEngine_LiveData1_R, 0); + else if (KLine.compareData(hondaEngine_LiveData2)) KLine.writeRawData(hondaEngine_LiveData2_R, 3); + else if (KLine.compareData(hondaEngine_LiveData3)) KLine.writeRawData(hondaEngine_LiveData3_R, 0); + else if (KLine.compareData(hondaEngine_LiveData4)) KLine.writeRawData(hondaEngine_LiveData4_R, 0); + else if (KLine.compareData(hondaEngine_LiveData5)) KLine.writeRawData(hondaEngine_LiveData5_R, 0); + else if (KLine.compareData(hondaEngine_LiveData6)) KLine.writeRawData(hondaEngine_LiveData6_R, 0); + else if (KLine.compareData(hondaEngine_LiveData7)) KLine.writeRawData(hondaEngine_LiveData7_R, 0); + else if (KLine.compareData(hondaEngine_LiveData8)) KLine.writeRawData(hondaEngine_LiveData8_R, 0); + else if (KLine.compareData(hondaEngine_LiveData9)) KLine.writeRawData(hondaEngine_LiveData9_R, 0); + else if (KLine.compareData(hondaEngine_ReadDTCs)) KLine.writeRawData(hondaEngine_ReadDTCs_R, 0); + else if (KLine.compareData(hondaEngine_ClearDTCs)) KLine.writeRawData(hondaEngine_ClearDTCs_R, 0); + //else if (KLine.compareData(hondaABS)) KLine.writeRawData(hondaABS_Response, false); } } diff --git a/examples/Car Specific/Opel/Opel.ino b/examples/Car Specific/Opel/Opel.ino index ccecab1..3afaa80 100644 --- a/examples/Car Specific/Opel/Opel.ino +++ b/examples/Car Specific/Opel/Opel.ino @@ -17,33 +17,38 @@ int kw81_Stage = 0; void setup() { Serial.begin(115200); // Start the default serial (for logging/debugging) - KLine.setDebug(Serial); // Optional: outputs debug messages to the selected serial port - //KLine.setProtocol("ISO14230_Fast"); // Optional: communication protocol (default: Automatic; supported: ISO9141, ISO14230_Slow, ISO14230_Fast, Automatic) - KLine.setByteWriteInterval(5); // Optional: delay (ms) between bytes when writing - KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data - KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setDebug(Serial); // Optional: outputs debug messages to the selected serial port + KLine.setProtocol("ISO14230_Fast"); // Optional: communication protocol (default: Automatic; supported: ISO9141, ISO14230_Slow, ISO14230_Fast, Automatic) + KLine.setByteWriteInterval(5); // Optional: delay (ms) between bytes when writing + KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data + KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + + //KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + //KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0x80, 0x11, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + //KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. Serial.println("Opel Code."); } void loop() { - //Opel_Vectra_Test1(); + //KLine.read5baud(); + Opel_Vectra_Test1(); //Opel_Vectra_Test2(); - Opel_Vectra_Simulator1(); + //Opel_Vectra_Simulator1(); //Engine and Immobilizer //Opel_Vectra_Simulator2(); //Instrument Cluster Simulator (Select 4800 Baud) } void Opel_Vectra_Test1() { if (KLine.initOBD2()) { - KLine.writeRawData(imoKeepalive, sizeof(imoKeepalive), 2), KLine.readData(); - KLine.writeRawData(imoReadLiveData, sizeof(imoReadLiveData), 2), KLine.readData(); - - KLine.writeRawData(imoKeepalive, sizeof(imoKeepalive), 2), KLine.readData(); - KLine.writeRawData(imoReadDTCs, sizeof(imoReadDTCs), 2), KLine.readData(); + KLine.writeRawData(engineReadLiveData1, 2), KLine.readData(); + KLine.writeRawData(engineReadLiveData2, 2), KLine.readData(); + KLine.writeRawData(engineReadLiveData3, 2), KLine.readData(); - KLine.writeRawData(imoKeepalive, sizeof(imoKeepalive), 2), KLine.readData(); - KLine.writeRawData(imoClearDTCs, sizeof(imoClearDTCs), 2), KLine.readData(); + // KLine.writeRawData(imoReadLiveData, 2), KLine.readData(); + // KLine.writeRawData(imoReadDTCs, 2), KLine.readData(); + // KLine.writeRawData(imoClearDTCs, 2), KLine.readData(); } } @@ -56,17 +61,17 @@ void Opel_Vectra_Test2() { void Opel_Vectra_Simulator1() { if (KLine.readData()) { - if (KLine.compareData(engineInit0, sizeof(engineInit0)) || KLine.compareData(engineInit, sizeof(engineInit))) KLine.writeRawData(engineInit_Response, sizeof(engineInit_Response), 2); - else if (KLine.compareData(engineCheckConnection, sizeof(engineCheckConnection))) KLine.writeRawData(engineCheckConnection_Response, sizeof(engineCheckConnection_Response), 2); - else if (KLine.compareData(engineReadLiveData1, sizeof(engineReadLiveData1))) KLine.writeRawData(engineReadLiveData1_Response, sizeof(engineReadLiveData1_Response), 2); - else if (KLine.compareData(engineReadLiveData2, sizeof(engineReadLiveData2))) KLine.writeRawData(engineReadLiveData2_Response, sizeof(engineReadLiveData2_Response), 2); - else if (KLine.compareData(engineReadLiveData3, sizeof(engineReadLiveData3))) KLine.writeRawData(engineReadLiveData3_Response, sizeof(engineReadLiveData3_Response), 2); - - if (KLine.compareData(imoInit0, sizeof(imoInit0))) KLine.writeRawData(imoInit_Response, sizeof(imoInit_Response), 2); - else if (KLine.compareData(imoKeepalive, sizeof(imoKeepalive))) KLine.writeRawData(imoKeepalive_Response, sizeof(imoKeepalive_Response), 2); - else if (KLine.compareData(imoReadLiveData, sizeof(imoReadLiveData))) KLine.writeRawData(imoReadLiveData_Response, sizeof(imoReadLiveData_Response), 2); - else if (KLine.compareData(imoReadDTCs, sizeof(imoReadDTCs))) KLine.writeRawData(imoReadDTCs_Response, sizeof(imoReadDTCs_Response), 2); - else if (KLine.compareData(imoClearDTCs, sizeof(imoClearDTCs))) KLine.writeRawData(imoClearDTCs_Response2, sizeof(imoClearDTCs_Response2), 2); + if (KLine.compareData(engineInit0) || KLine.compareData(engineInit)) KLine.writeRawData(engineInit_Response, 2); + else if (KLine.compareData(engineCheckConnection)) KLine.writeRawData(engineCheckConnection_Response, 2); + else if (KLine.compareData(engineReadLiveData1)) KLine.writeRawData(engineReadLiveData1_Response, 2); + else if (KLine.compareData(engineReadLiveData2)) KLine.writeRawData(engineReadLiveData2_Response, 2); + else if (KLine.compareData(engineReadLiveData3)) KLine.writeRawData(engineReadLiveData3_Response, 2); + + if (KLine.compareData(imoInit0)) KLine.writeRawData(imoInit_Response, 2); + else if (KLine.compareData(imoKeepalive)) KLine.writeRawData(imoKeepalive_Response, 2); + else if (KLine.compareData(imoReadLiveData)) KLine.writeRawData(imoReadLiveData_Response, 2); + else if (KLine.compareData(imoReadDTCs)) KLine.writeRawData(imoReadDTCs_Response, 2); + else if (KLine.compareData(imoClearDTCs)) KLine.writeRawData(imoClearDTCs_Response2, 2); } } @@ -74,17 +79,17 @@ void Opel_Vectra_Simulator2() { if (connectionStatus == false) { if (KLine.read5baud() == 0x60) { connectionStatus = true; - KLine.writeRawData(instumentClusterInit_Response, sizeof(instumentClusterInit_Response), 0); + KLine.writeRawData(instumentClusterInit_Response, 0); } } if (connectionStatus == true) { - if (kw81_Stage == 0) KLine.writeRawData(instumentClusterECUID_Response, sizeof(instumentClusterECUID_Response), 0); - else if (kw81_Stage == 1) KLine.writeRawData(instumentClusterLiveData_Response, sizeof(instumentClusterLiveData_Response), 0); + if (kw81_Stage == 0) KLine.writeRawData(instumentClusterECUID_Response, 0); + else if (kw81_Stage == 1) KLine.writeRawData(instumentClusterLiveData_Response, 0); else if (kw81_Stage == 2) {} if (KLine.readData()) { - if (KLine.compareData(instumentClusterLiveData, sizeof(instumentClusterLiveData))) kw81_Stage = 1; - else if (KLine.compareData(instumentClusterClearDTC, sizeof(instumentClusterClearDTC))) kw81_Stage = 2; + if (KLine.compareData(instumentClusterLiveData)) kw81_Stage = 1; + else if (KLine.compareData(instumentClusterClearDTC)) kw81_Stage = 2; } } } diff --git a/examples/OBD2 Standard/ClearDTC/ClearDTC.ino b/examples/OBD2 Standard/ClearDTC/ClearDTC.ino index 939dd78..931e895 100644 --- a/examples/OBD2 Standard/ClearDTC/ClearDTC.ino +++ b/examples/OBD2 Standard/ClearDTC/ClearDTC.ino @@ -20,13 +20,18 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } void loop() { // Attempt to initialize OBD2 communication if (KLine.initOBD2()) { - KLine.clearDTCs(); // Clear Diagnostic Trouble Codes (DTCs) + KLine.clearDTCs(); // Clear Diagnostic Trouble Codes (DTCs) delay(1000); } } diff --git a/examples/OBD2 Standard/GetFreezeFrame/GetFreezeFrame.ino b/examples/OBD2 Standard/GetFreezeFrame/GetFreezeFrame.ino index b390cc9..823f673 100644 --- a/examples/OBD2 Standard/GetFreezeFrame/GetFreezeFrame.ino +++ b/examples/OBD2 Standard/GetFreezeFrame/GetFreezeFrame.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } diff --git a/examples/OBD2 Standard/GetLiveData/GetLiveData.ino b/examples/OBD2 Standard/GetLiveData/GetLiveData.ino index 86974b7..e6737e3 100644 --- a/examples/OBD2 Standard/GetLiveData/GetLiveData.ino +++ b/examples/OBD2 Standard/GetLiveData/GetLiveData.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } diff --git a/examples/OBD2 Standard/GetSupportedPIDs/GetSupportedPIDs.ino b/examples/OBD2 Standard/GetSupportedPIDs/GetSupportedPIDs.ino index e8176a5..663673e 100644 --- a/examples/OBD2 Standard/GetSupportedPIDs/GetSupportedPIDs.ino +++ b/examples/OBD2 Standard/GetSupportedPIDs/GetSupportedPIDs.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } diff --git a/examples/OBD2 Standard/GetVehicleInfo/GetVehicleInfo.ino b/examples/OBD2 Standard/GetVehicleInfo/GetVehicleInfo.ino index 7b46665..82194de 100644 --- a/examples/OBD2 Standard/GetVehicleInfo/GetVehicleInfo.ino +++ b/examples/OBD2 Standard/GetVehicleInfo/GetVehicleInfo.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } diff --git a/examples/OBD2 Standard/ReadDTC/ReadDTC.ino b/examples/OBD2 Standard/ReadDTC/ReadDTC.ino index 09a5eef..9a8df41 100644 --- a/examples/OBD2 Standard/ReadDTC/ReadDTC.ino +++ b/examples/OBD2 Standard/ReadDTC/ReadDTC.ino @@ -20,6 +20,11 @@ void setup() { KLine.setInterByteTimeout(60); // Optional: sets the maximum inter-byte timeout (ms) while receiving data KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + Serial.println("OBD2 Starting."); } diff --git a/examples/OBD2 Standard/Sniffer/Sniffer.ino b/examples/OBD2 Standard/Sniffer/Sniffer.ino new file mode 100644 index 0000000..e51f8c8 --- /dev/null +++ b/examples/OBD2 Standard/Sniffer/Sniffer.ino @@ -0,0 +1,34 @@ +#include "OBD2_KLine.h" // Include the library for OBD2 K-Line communication + +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega2560__) +#include +AltSoftSerial Alt_Serial; +OBD2_KLine KLine(Alt_Serial, 10400, 8, 9); // Uses AltSoftSerial at 10400 baud, with RX on pin 8 and TX on pin 9. +#elif defined(ESP32) +OBD2_KLine KLine(Serial1, 9600, 10, 11); // Uses Hardware Serial (Serial1) at 10400 baud, with RX on pin 10 and TX on pin 11. +#else +#error "Unsupported board! This library currently supports Arduino Uno, Nano, Mega, and ESP32. Please select a compatible board in your IDE." +#endif + +void setup() { + Serial.begin(115200); // Start the default serial (for logging/debugging) + Serial.println("OBD2 K-Line Sniffing Example"); + + KLine.setDebug(Serial); // Optional: outputs debug messages to the selected serial port + KLine.setByteWriteInterval(5); // Optional: delay (ms) between bytes when writing + KLine.setInterByteTimeout(20); // Optional: sets the maximum inter-byte timeout (ms) while receiving data + KLine.setReadTimeout(1000); // Optional: maximum time (ms) to wait for a response after sending a request + + KLine.setInitAddress(0x33); // Optional: Sets the target ECU address used during the 5-baud Slow Init sequence. + KLine.setISO9141Header(0x68, 0x6A, 0xF1); // Optional: Configures the 3-byte header (Priority, Receiver, Transmitter) for ISO9141. + KLine.setISO14230Header(0xC0, 0x33, 0xF1); // Optional: Configures the 3-byte header (Format, Receiver, Transmitter) for KWP2000. + KLine.setLengthMode(true); // Optional: Defines if data length is embedded in the header or sent as a separate byte. + + Serial.println("OBD2 Starting."); +} + +void loop() { + // int result = KLine.read5baud(); + // if (result < 0) KLine.readData(); + KLine.readData(); +} diff --git a/src/OBD2_KLine.cpp b/src/OBD2_KLine.cpp index e583dbe..3303735 100644 --- a/src/OBD2_KLine.cpp +++ b/src/OBD2_KLine.cpp @@ -1,6 +1,6 @@ #include "OBD2_KLine.h" -OBD2_KLine::OBD2_KLine(SerialType &serialPort, uint32_t baudRate, uint8_t rxPin, uint8_t txPin) +OBD2_KLine::OBD2_KLine(SerialType& serialPort, uint32_t baudRate, uint8_t rxPin, uint8_t txPin) : _serial(&serialPort), _rxPin(rxPin), _txPin(txPin), _baudRate(baudRate) { // Start serial setSerial(true); @@ -47,7 +47,7 @@ bool OBD2_KLine::trySlowInit() { setSerial(false); delay(5500); - send5baud(slowInitByte); + send5baud(defaultInitAddress); setSerial(true); setInterByteTimeout(30); @@ -81,6 +81,8 @@ bool OBD2_KLine::trySlowInit() { } bool OBD2_KLine::tryFastInit() { + // example Request: C1 33 F1 81 66 + // example Response: 83 F1 11 C1 EF 8F C4 debugPrintln(F("🔁 Trying ISO14230_Fast")); setSerial(false); @@ -92,7 +94,7 @@ bool OBD2_KLine::tryFastInit() { delay(25); setSerial(true); - writeRawData(initMsg, sizeof(initMsg), 2); + writeData((uint8_t[]){0x81}); if (!readData()) return false; @@ -109,7 +111,7 @@ bool OBD2_KLine::tryFastInit() { // ----------------------------------- Basic Read/Write functions ----------------------------------- -void OBD2_KLine::writeRawData(const uint8_t *dataArray, uint8_t length, uint8_t checksumType) { +void OBD2_KLine::writeRawData(const uint8_t* dataArray, uint8_t length, uint8_t checksumType) { uint8_t totalLength = length; // default no checksum uint8_t checksum = 0; @@ -149,52 +151,52 @@ void OBD2_KLine::writeRawData(const uint8_t *dataArray, uint8_t length, uint8_t for (size_t i = 0; i < totalLength; i++) { _serial->write(sendData[i]); - delay(_byteWriteInterval); + if (i < totalLength - 1) delay(_byteWriteInterval); } clearEcho(totalLength); } -void OBD2_KLine::writeData(uint8_t mode, uint8_t pid) { - uint8_t message[7] = {0}; - size_t length = (mode == read_FreezeFrame || mode == test_OxygenSensors) ? 7 : - (mode == read_storedDTCs || mode == clear_DTCs || mode == read_pendingDTCs) ? 5 : - 6; +void OBD2_KLine::writeData(const uint8_t* data, uint8_t dataLength) { + uint8_t headerLength = 3; + uint8_t actualLengthByteCount = useLengthInHeader ? 0 : 1; + uint8_t fullDataLength = headerLength + actualLengthByteCount + dataLength + 1; // +1 for checksum + uint8_t message[fullDataLength]; if (connectedProtocol == "ISO9141") { - message[0] = (mode == read_FreezeFrame || mode == test_OxygenSensors) ? 0x69 : 0x68; - message[1] = 0x6A; - } else if (connectedProtocol == "ISO14230_Fast" || connectedProtocol == "ISO14230_Slow") { - message[0] = (mode == read_FreezeFrame || mode == test_OxygenSensors) ? 0xC3 : - (mode == read_storedDTCs || mode == clear_DTCs || mode == read_pendingDTCs) ? 0xC1 : - 0xC2; - message[1] = 0x33; + memcpy(message, header_ISO9141, headerLength); + } else if (connectedProtocol == "ISO14230_Fast" || connectedProtocol == "ISO14230_Slow" || connectionStatus == false) { + memcpy(message, header_ISO14230_Fast, headerLength); + + if (useLengthInHeader) { + message[0] += dataLength; + } else { + message[3] = dataLength; + } } - message[2] = 0xF1; - message[3] = mode; - if (length > 5) message[4] = pid; - if (length == 7) message[5] = 0x00; + uint8_t dataStartOffset = headerLength + actualLengthByteCount; + memcpy(&message[dataStartOffset], data, dataLength); - message[length - 1] = checksum8_Modulo256(message, length - 1); + message[fullDataLength - 1] = checksum8_Modulo256(message, fullDataLength - 1); debugPrint(F("\n➡️ Sending Data: ")); - for (size_t i = 0; i < length; i++) { + for (size_t i = 0; i < fullDataLength; i++) { debugPrintHex(message[i]); debugPrint(F(" ")); } debugPrintln(F("")); - for (size_t i = 0; i < length; i++) { + for (size_t i = 0; i < fullDataLength; i++) { _serial->write(message[i]); - delay(_byteWriteInterval); + if (i < fullDataLength - 1) delay(_byteWriteInterval); } - clearEcho(length); + clearEcho(fullDataLength); } uint8_t OBD2_KLine::readData() { - debugPrintln(F("Reading...")); + debugPrint(F("Reading Data ... ")); unsigned long startMillis = millis(); int bytesRead = 0; @@ -222,7 +224,8 @@ uint8_t OBD2_KLine::readData() { } } - debugPrintln(F("\n✅ Data reception completed.")); + debugPrintln(F("")); + // debugPrintln(F("\n✅ Data reception completed.")); return bytesRead; } } @@ -233,23 +236,43 @@ uint8_t OBD2_KLine::readData() { return 0; } -void OBD2_KLine::clearEcho(int length) { - int result = _serial->available(); - if (result > 0) { - debugPrint(F("🗑️ Cleared Echo Data: ")); - for (int i = 0; i < length; i++) { - uint8_t readedByte = _serial->read(); - debugPrintHex(readedByte); - debugPrint(F(" ")); +void OBD2_KLine::clearEcho(uint8_t length) { + const unsigned long byteTimeoutMs = 100; + + // Wait for the first byte + unsigned long startTime = millis(); + while (_serial->available() == 0) { + if (millis() - startTime >= byteTimeoutMs) { + debugPrintln(F("❌ Echo not received")); + return; } - debugPrintln(F("")); - // debugPrintln(F("Echo Data Cleared")); - } else { - debugPrintln(F("❌ Not Received Echo Data")); + delayMicroseconds(100); + } + + // First byte received, now read the rest + debugPrint(F("🗑️ Cleared Echo Data: ")); + + uint8_t readedByte; + for (size_t readCount = 0; readCount < length; readCount++) { + startTime = millis(); + + while (_serial->available() == 0) { + if (millis() - startTime >= byteTimeoutMs) { + debugPrintln(F("\n❌ Echo incomplete")); + return; + } + delayMicroseconds(100); + } + + readedByte = _serial->read(); + debugPrintHex(readedByte); + debugPrint(F(" ")); } + + debugPrintln(F("")); } -bool OBD2_KLine::compareData(const uint8_t *dataArray, uint8_t length) { +bool OBD2_KLine::compareData(const uint8_t* dataArray, uint8_t length) { for (size_t i = 0; i < length; i++) { if (dataArray[i] != resultBuffer[i]) { return false; @@ -269,7 +292,14 @@ float OBD2_KLine::getFreezeFrame(uint8_t pid) { } float OBD2_KLine::getPID(uint8_t mode, uint8_t pid) { - writeData(mode, pid); + // example Request: C2 33 F1 01 0C F3 + // example Response: 84 F1 11 41 0C 0D 58 38 + if (mode == read_LiveData) { + writeData((uint8_t[]){mode, pid}); + } else if (mode == read_FreezeFrame) { + writeData((uint8_t[]){mode, pid, 0x00}); + } + int len = readData(); if (len <= 0) return -1; // Data not received @@ -457,7 +487,7 @@ uint8_t OBD2_KLine::readDTCs(uint8_t mode) { // example Response: 87 F1 11 43 01 70 01 34 00 00 72 // example Response: 87 F1 11 43 00 00 CC int dtcCount = 0; - String *targetArray = nullptr; + String* targetArray = nullptr; if (mode == read_storedDTCs) { targetArray = storedDTCBuffer; @@ -467,7 +497,7 @@ uint8_t OBD2_KLine::readDTCs(uint8_t mode) { return -1; // Invalid mode } - writeData(mode, 0x00); + writeData((uint8_t[]){mode}); int len = readData(); if (len >= 3) { @@ -495,7 +525,7 @@ String OBD2_KLine::getPendingDTC(uint8_t index) { } bool OBD2_KLine::clearDTCs() { - writeData(clear_DTCs, 0x00); + writeData((uint8_t[]){clear_DTCs}); int len = readData(); if (len >= 3) { if (resultBuffer[3] == 0x44) { @@ -525,9 +555,9 @@ String OBD2_KLine::getVehicleInfo(uint8_t pid) { messageCount = 5; } else if (pid == 0x04 || pid == 0x06) { if (pid == 0x04) { - writeData(read_VehicleInfo, read_ID_Length); + writeData((uint8_t[]){read_VehicleInfo, read_ID_Length}); } else if (pid == 0x06) { - writeData(read_VehicleInfo, read_ID_Num_Length); + writeData((uint8_t[]){read_VehicleInfo, read_ID_Num_Length}); } else { return ""; } @@ -539,7 +569,7 @@ String OBD2_KLine::getVehicleInfo(uint8_t pid) { } } - writeData(read_VehicleInfo, pid); + writeData((uint8_t[]){read_VehicleInfo, pid}); if (readData()) { for (int j = 0; j < messageCount; j++) { @@ -592,7 +622,7 @@ uint8_t OBD2_KLine::readSupportedData(uint8_t mode) { int pidIndex = 0; int startByte = 0; int arraySize = 32; // Size of supported data arrays - uint8_t *targetArray = nullptr; + uint8_t* targetArray = nullptr; if (mode == read_LiveData) { // Mode 01 startByte = 5; @@ -622,7 +652,7 @@ uint8_t OBD2_KLine::readSupportedData(uint8_t mode) { // Group 0 is always processed, others must be checked if (n != 0 && !isInArray(targetArray, 32, pidCmds[n])) break; - writeData(mode, pidCmds[n]); + writeData((uint8_t[]){mode, pidCmds[n]}); if (readData() && resultBuffer[3] == 0x40 + mode) { for (int i = 0; i < 4; i++) { uint8_t value = resultBuffer[i + startByte]; @@ -689,70 +719,95 @@ void OBD2_KLine::setReadTimeout(uint16_t timeoutMs) { _readTimeout = timeoutMs; } -void OBD2_KLine::setProtocol(const String &protocolName) { +void OBD2_KLine::setProtocol(const String& protocolName) { selectedProtocol = protocolName; connectionStatus = false; // Reset connection status connectedProtocol = ""; // Reset connected protocol - debugPrintln(("Protocol set to: " + selectedProtocol).c_str()); + debugPrint(F("Protocol set to: ")); + debugPrintln((selectedProtocol).c_str()); } -// 5 Baud 7O1 (1 start, 7 data, 1 parity, 1 stop) -uint8_t OBD2_KLine::read5baud() { - unsigned long t0 = millis(); - while (digitalRead(_rxPin) == HIGH) { - if (millis() - t0 > 2000) return -1; - } +void OBD2_KLine::setConnectionStatus(bool status) { + connectionStatus = status; +} - setSerial(false); // Disable serial to read 5 baud data +// 5 Baud 7O1 (1 start, 7 data, 1 parity, 1 stop) +int OBD2_KLine::read5baud() { + // debugPrintln(F("Waiting for 5-baud init...")); + setSerial(false); + const unsigned long THRESHOLD = 100000; - uint8_t bits[10]; - uint8_t data = 0; - int ones = 0; - delayMicroseconds(100000); + // HIGH -> LOW (start bit decrease) + while (digitalRead(_rxPin) == HIGH); - for (int i = 0; i < 10; i++) { // bits: 0=start, 1..7=data, 8=parity, 9=stop - bits[i] = digitalRead(_rxPin) ? 1 : 0; + // debugPrintln(F("Transition detected. Measuring start bit... ")); + unsigned long tStart = micros(); - if (i >= 1 && i <= 7) { - data |= (bits[i] << (i - 1)); // save data bits - if (bits[i]) ones++; - } else if (i == 8) { // parity bit - if (bits[i]) ones++; - } else if (i == 9) { // stop bit + while (digitalRead(_rxPin) == LOW) { + if (micros() - tStart > THRESHOLD) { + // debugPrintln(F("✅ LOW > 100ms, 5-baud detected")); break; } + } - delayMicroseconds(200000); + if (digitalRead(_rxPin) == HIGH && (micros() - tStart <= THRESHOLD)) { + // debugPrintln(F("❌ No 5 Baud data detected.")); + setSerial(true); + return -1; } - // Parity control (Odd) - if (ones % 2 == 0) { - debugPrintln(F("Parity error!")); - return -2; + debugPrint(F("✅ Received 5 Baud data - ")); + uint8_t bits[10]; + + delay(200); + for (int i = 1; i < 10; i++) { + bits[i] = digitalRead(_rxPin); + delay(200); } - debugPrint(F("Received 5 Baud Data: ")); - debugPrintln(String(data, HEX).c_str()); + debugPrint(F("Bits: ")); + for (int i = 0; i < 10; i++) { + debugPrint(bits[i] ? "1" : "0"); + } + + uint8_t data = 0; + int ones = 0; + for (int i = 1; i <= 7; i++) { + data |= (bits[i] << (i - 1)); + if (bits[i]) ones++; + } + if (bits[8]) ones++; + + debugPrint(F(", DATA: 0x")); + debugPrintHex(data); + + if ((ones & 1) == 0) + debugPrintln(F(", ❌ Parity ERROR (odd expected)")); + else + debugPrintln(F(", ✅ Parity OK")); + // debugPrintln(); + setSerial(true); - setSerial(true); // Re-enable serial after reading 5 baud data return data; } // 5 Baud 7O1 (1 start, 7 data, 1 parity, 1 stop) void OBD2_KLine::send5baud(uint8_t data) { - uint8_t even = 1; // for calculating parity bit uint8_t bits[10]; - bits[0] = 0; // start bit bits[9] = 1; // stop bit - // 7-bit data and parity calculation - for (int i = 1; i <= 7; i++) { - bits[i] = (data >> (i - 1)) & 1; - even ^= bits[i]; + // 7-bit data + for (int i = 0; i < 7; i++) { + bits[i + 1] = (data >> i) & 1; } - bits[8] = (even == 0) ? 1 : 0; // parity bit + // Odd parity calculation + uint8_t ones = 0; + for (int i = 1; i <= 7; i++) { + if (bits[i]) ones++; + } + bits[8] = (ones % 2 == 0) ? 1 : 0; // parity bit debugPrint(F("➡️ 5 Baud Init for Module 0x")); debugPrintHex(data); @@ -770,7 +825,7 @@ void OBD2_KLine::send5baud(uint8_t data) { debugPrintln(F("")); } -uint8_t OBD2_KLine::checksum8_XOR(const uint8_t *dataArray, int length) { +uint8_t OBD2_KLine::checksum8_XOR(const uint8_t* dataArray, int length) { uint8_t checksum = 0; for (int i = 0; i < length; i++) { checksum ^= dataArray[i]; // XOR operation @@ -778,15 +833,15 @@ uint8_t OBD2_KLine::checksum8_XOR(const uint8_t *dataArray, int length) { return checksum; } -uint8_t OBD2_KLine::checksum8_Modulo256(const uint8_t *dataArray, int length) { +uint8_t OBD2_KLine::checksum8_Modulo256(const uint8_t* dataArray, int length) { unsigned int sum = 0; for (int i = 0; i < length; i++) { sum += dataArray[i]; } - return (byte)(sum % 256); // veya (byte)sum; çünkü uint8_t overflow da mod 256 etkisi verir + return (byte)(sum % 256); // or (byte)sum; because uint8_t overflow also gives a mod 256 effect. } -uint8_t OBD2_KLine::checksum8_TwosComplement(const uint8_t *dataArray, int length) { +uint8_t OBD2_KLine::checksum8_TwosComplement(const uint8_t* dataArray, int length) { unsigned int sum = 0; for (int i = 0; i < length; i++) { sum += dataArray[i]; @@ -809,7 +864,7 @@ String OBD2_KLine::decodeDTC(uint8_t input_byte1, uint8_t input_byte2) { return ErrorCode; } -bool OBD2_KLine::isInArray(const uint8_t *dataArray, uint8_t length, uint8_t value) { +bool OBD2_KLine::isInArray(const uint8_t* dataArray, uint8_t length, uint8_t value) { for (int i = 0; i < length; i++) { if (dataArray[i] == value) { return true; @@ -818,7 +873,7 @@ bool OBD2_KLine::isInArray(const uint8_t *dataArray, uint8_t length, uint8_t val return false; } -String OBD2_KLine::convertHexToAscii(const uint8_t *dataArray, uint8_t length) { +String OBD2_KLine::convertHexToAscii(const uint8_t* dataArray, uint8_t length) { String asciiString = ""; for (int i = 0; i < length; i++) { uint8_t b = dataArray[i]; @@ -829,7 +884,7 @@ String OBD2_KLine::convertHexToAscii(const uint8_t *dataArray, uint8_t length) { return asciiString; } -String OBD2_KLine::convertBytesToHexString(const uint8_t *dataArray, uint8_t length) { +String OBD2_KLine::convertBytesToHexString(const uint8_t* dataArray, uint8_t length) { String hexString = ""; for (int i = 0; i < length; i++) { if (dataArray[i] < 0x10) hexString += "0"; // Pad leading zero @@ -841,23 +896,23 @@ String OBD2_KLine::convertBytesToHexString(const uint8_t *dataArray, uint8_t len // ----------------------------------- Debug Functions ----------------------------------- -void OBD2_KLine::setDebug(Stream &serial) { +void OBD2_KLine::setDebug(Stream& serial) { _debugSerial = &serial; } -void OBD2_KLine::debugPrint(const char *msg) { +void OBD2_KLine::debugPrint(const char* msg) { if (_debugSerial) _debugSerial->print(msg); } -void OBD2_KLine::debugPrint(const __FlashStringHelper *msg) { +void OBD2_KLine::debugPrint(const __FlashStringHelper* msg) { if (_debugSerial) _debugSerial->print(msg); } -void OBD2_KLine::debugPrintln(const char *msg) { +void OBD2_KLine::debugPrintln(const char* msg) { if (_debugSerial) _debugSerial->println(msg); } -void OBD2_KLine::debugPrintln(const __FlashStringHelper *msg) { +void OBD2_KLine::debugPrintln(const __FlashStringHelper* msg) { if (_debugSerial) _debugSerial->println(msg); } @@ -873,4 +928,31 @@ void OBD2_KLine::debugPrintHexln(uint8_t val) { debugPrintHex(val); _debugSerial->println(); } +} + +void OBD2_KLine::setInitAddress(uint8_t address) { + defaultInitAddress = address; + // ISO14230 Header'ındaki hedef adresini de otomatik güncellemek isteyebilirsiniz: + header_ISO14230_Fast[1] = address; + debugPrint(F("✅ New Init Address set to: ")); + debugPrintHex(address); + debugPrintln(F("")); +} + +void OBD2_KLine::setISO9141Header(uint8_t h1, uint8_t h2, uint8_t h3) { + header_ISO9141[0] = h1; + header_ISO9141[1] = h2; + header_ISO9141[2] = h3; + debugPrintln(F("✅ ISO9141 Header Updated.")); +} + +void OBD2_KLine::setISO14230Header(uint8_t h1, uint8_t h2, uint8_t h3) { + header_ISO14230_Fast[0] = h1; + header_ISO14230_Fast[1] = h2; + header_ISO14230_Fast[2] = h3; + debugPrintln(F("✅ ISO14230 Header Updated.")); +} + +void OBD2_KLine::setLengthMode(bool inHeader) { + useLengthInHeader = inHeader; } \ No newline at end of file diff --git a/src/OBD2_KLine.h b/src/OBD2_KLine.h index 49324be..d5b4d74 100644 --- a/src/OBD2_KLine.h +++ b/src/OBD2_KLine.h @@ -35,22 +35,37 @@ const uint8_t read_ID = 0x04; // Read Calibration ID const uint8_t read_ID_Num_Length = 0x05; // Read Calibration ID Number Length const uint8_t read_ID_Num = 0x06; // Read Calibration ID Number - class OBD2_KLine { public: - OBD2_KLine(SerialType &serialStream, uint32_t baudRate, uint8_t rxPin, uint8_t txPin); + OBD2_KLine(SerialType& serialStream, uint32_t baudRate, uint8_t rxPin, uint8_t txPin); - void setDebug(Stream &serial); + void setDebug(Stream& serial); void setSerial(bool enabled); bool initOBD2(); bool trySlowInit(); bool tryFastInit(); - void writeData(uint8_t mode, uint8_t pid); - void writeRawData(const uint8_t *dataArray, uint8_t length, uint8_t checksumType); + void writeRawData(const uint8_t* dataArray, uint8_t length, uint8_t checksumType); + void writeData(const uint8_t* data, uint8_t length); + + template + void writeData(const uint8_t (&dataArray)[N]) { + writeData(dataArray, N); + } + + template + void writeRawData(const uint8_t (&dataArray)[N], uint8_t checksumType) { + writeRawData(dataArray, N, checksumType); + } + + template + bool compareData(const uint8_t (&dataArray)[N]) { + return compareData(dataArray, N); + } + uint8_t readData(); - bool compareData(const uint8_t *dataArray, uint8_t length); + bool compareData(const uint8_t* dataArray, uint8_t length); void send5baud(uint8_t data); - uint8_t read5baud(); + int read5baud(); float getPID(uint8_t mode, uint8_t pid); float getLiveData(uint8_t pid); @@ -78,18 +93,26 @@ class OBD2_KLine { void setByteWriteInterval(uint16_t interval); void setInterByteTimeout(uint16_t interval); void setReadTimeout(uint16_t timeoutMs); - void setProtocol(const String &protocolName); + void setProtocol(const String& protocolName); void updateConnectionStatus(bool messageReceived); + void setConnectionStatus(bool status); - uint8_t initMsg[4] = {0xC1, 0x33, 0xF1, 0x81}; // ISO14230-Fast init message - uint8_t slowInitByte = 0x33; // ISO9141/ISO14230-Slow init byte + void setInitAddress(uint8_t address); + void setISO9141Header(uint8_t h1, uint8_t h2, uint8_t h3); + void setISO14230Header(uint8_t h1, uint8_t h2, uint8_t h3); + void setLengthMode(bool inHeader); private: - SerialType *_serial; + SerialType* _serial; uint32_t _baudRate; uint8_t _rxPin; uint8_t _txPin; - Stream *_debugSerial = nullptr; // Debug serial port + Stream* _debugSerial = nullptr; // Debug serial port + + uint8_t defaultInitAddress = 0x33; + uint8_t header_ISO9141[3] = {0x68, 0x6A, 0xF1}; + uint8_t header_ISO14230_Fast[3] = {0xC0, 0x33, 0xF1}; + bool useLengthInHeader = true; uint8_t resultBuffer[160] = {0}; uint8_t unreceivedDataCount = 0; @@ -110,19 +133,19 @@ class OBD2_KLine { uint8_t supportedControlComponents[32]; uint8_t supportedVehicleInfo[32]; - uint8_t checksum8_XOR(const uint8_t *dataArray, int length); - uint8_t checksum8_Modulo256(const uint8_t *dataArray, int length); - uint8_t checksum8_TwosComplement(const uint8_t *dataArray, int length); + uint8_t checksum8_XOR(const uint8_t* dataArray, int length); + uint8_t checksum8_Modulo256(const uint8_t* dataArray, int length); + uint8_t checksum8_TwosComplement(const uint8_t* dataArray, int length); String decodeDTC(uint8_t input_byte1, uint8_t input_byte2); - bool isInArray(const uint8_t *dataArray, uint8_t length, uint8_t value); - String convertBytesToHexString(const uint8_t *dataArray, uint8_t length); - String convertHexToAscii(const uint8_t *dataArray, uint8_t length); - void clearEcho(int length); - void debugPrint(const char *msg); - void debugPrint(const __FlashStringHelper *msg); - void debugPrintln(const char *msg); - void debugPrintln(const __FlashStringHelper *msg); + bool isInArray(const uint8_t* dataArray, uint8_t length, uint8_t value); + String convertBytesToHexString(const uint8_t* dataArray, uint8_t length); + String convertHexToAscii(const uint8_t* dataArray, uint8_t length); + void clearEcho(uint8_t length); + void debugPrint(const char* msg); + void debugPrint(const __FlashStringHelper* msg); + void debugPrintln(const char* msg); + void debugPrintln(const __FlashStringHelper* msg); void debugPrintHex(uint8_t val); // Hexadecimal output void debugPrintHexln(uint8_t val); // Hexadecimal + newline };