Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KWP Slow init with v1 != v2 #34

Open
tistructor opened this issue Jun 18, 2022 · 4 comments
Open

KWP Slow init with v1 != v2 #34

tistructor opened this issue Jun 18, 2022 · 4 comments

Comments

@tistructor
Copy link

Hi,
I was trying to communicate with ODB2 with my 206 1.1cc auto peugeot which should have the KWB2000 slow protocol.
I built the optoisolated hardware interface and it works properly with perfect signal ascent and descent fronts.
I started testing examples of read_softserial.ino library and modified readerKWP.ino for AltSoftSerial.
The first example with debug enabled has this log :
"
Looping
Before magic 5 baud.
Before setting port.
After setting port.
First read is: 85
read v1: 233
read v2: 143
v1: 233
v2: 143
init_success: 0
"
The problem is that the numbers V1 and V2 are different and initialization fails.

With the second example it fails without log.

I don't understand why V1 values other than V2.

Some suggestions?

@tistructor
Copy link
Author

I did it ;-)
The protocol is KWP2000 slow.
With the initKWP function, initialization was unsuccessful.
So I modified it this way :

bool OBD9141::initKWP(){
    use_kwp_ = true;
    // this function performs the ISO9141 5-baud 'slow' init.
    this->set_port(false); // disable the port.
    this->kline(true);
    
    delay(OBD9141_INIT_IDLE_BUS_BEFORE); // no traffic on bus for 3 seconds.
    OBD9141println("Before magic 5 baud.");
    // next, send the startup 5 baud init..  
    this->kline(false); //digitalWrite(7,LOW); 
    delay(200); // start
        
    this->kline(true); //digitalWrite(7,HIGH); 
    delay(400);  // first two bits
    
    this->kline(false); //digitalWrite(7,LOW);
    delay(400); // second pair
    
    this->kline(true); //digitalWrite(7,HIGH);
    delay(400);  // third pair
    
    this->kline(false); //digitalWrite(7,LOW);
    delay(400); // last pair
    
    this->kline(true); //digitalWrite(7,HIGH);
    delay(200);  // stop bit
    
    // this last 200 ms delay could also be put in the setTimeout below.
    // But the spec says we have a stop bit.

    // done, from now on it the bus can be treated ad a 10400 baud serial port.

    OBD9141println("Before setting port.");
    this->set_port(true);
    OBD9141println("After setting port.");
    uint8_t mess[1];

    this->serial->setTimeout(300+200);
    // wait should be between 20 and 300 ms long

    // read first value into buffer, should be 0x55
    if (this->serial->readBytes(mess, 1)){
        OBD9141print("First read is: "); OBD9141println(mess[0]);
        if (mess[0] != 0x55){
            return false;
        }
    } else {
        OBD9141println("Timeout on read 0x55.");
        return false;
    }
    // we get here after we have passed receiving the first 0x55 from ecu.

    this->serial->setTimeout(20); // w2 and w3 are pauses between 5 and 20 ms

    uint8_t v1=0, v2=0; // sent by car:  (either 0x08 or 0x94)

    // read v1
    if (!this->serial->readBytes(mess, 1)){
        OBD9141println("Timeout on read v1.");
        return false;
    } else {
        v1 = mess[0];
        OBD9141print("read v1: "); OBD9141println(v1);
    }

    // read v2
    if (!this->serial->readBytes(mess, 1)){
        OBD9141println("Timeout on read v2.");
        return false;
    } else {
        v2 = mess[0];
        OBD9141print("read v2: "); OBD9141println(v2);
    }
    
    OBD9141print("v1: "); OBD9141println(v1);
    OBD9141print("v2: "); OBD9141println(v2);

    // these two should be identical according to the spec.
    //if (v1 != v2){
    //    return false;
    //}

    // we obtained w1 and w2, now invert and send it back.
    // tester waits w4 between 25 and 50 ms:
    delay(30);
    this->write(~v2);
    this->serial->setTimeout(50); // w5 is same as w4...  max 50 ms

    // finally, attempt to read 0xCC from the ECU, indicating succesful init.
    if (!this->serial->readBytes(mess, 1)){
        OBD9141println("Timeout on 0xCC read.");
        return false;
    } else {
        OBD9141print("read 0xCC?: "); OBD9141println(mess[0]);
        if ((mess[0] == 0xCC)){ 
            delay(OBD9141_INIT_POST_INIT_DELAY);
            // this delay is not in the spec, but prevents requests immediately
            // after the finishing of the init sequency.
        } else {
            return false;
        }
    }

    this->serial->setTimeout(300+200);
    // wait should be between 20 and 300 ms long

    // startCommunicationRequest message:
    uint8_t message[4] = {0xC1, 0x33, 0xF1, 0x81};
    // checksum (0x66) is calculated by request method.

    // Send this request and read the response
    if (this->requestKWP(&message, 4) == 6) {
        // check positive response service ID, should be 0x7F.
        OBD9141print("read 0x7F?: "); OBD9141println(buffer[3]);
        if (this->buffer[3] == 0x7F) {
            // Not necessary to do anything with this data?
            return true;
        } else {
            return false;
        }
    }
    return false;
}

The readKWP.ino file modified for arduino one :

#include "Arduino.h"
#include "AltSoftSerial.h"
#include "OBD9141.h"

#define TXL_PIN 7     // connect to transceiver TxL
#define RX_PIN 8
#define TX_PIN 9
#define EN_PIN 2

AltSoftSerial altSerial;
OBD9141 obd;


void setup(){
    Serial.begin(9600);
    delay(2000);

    pinMode(EN_PIN, OUTPUT);
    digitalWrite(EN_PIN, HIGH);

    obd.begin(altSerial, RX_PIN, TX_PIN);

}
    
void loop(){
    Serial.println("Looping");

    // only change from reader is the init method here.
    uint8_t init_success =  obd.initKWP();
    Serial.print("init_success:");
    Serial.println(init_success);
    delay(50);

    //init_success = true;
    // Uncomment this line if you use the simulator to force the init to be
    // interpreted as successful. With an actual ECU; be sure that the init is 
    // succesful before trying to request PID's.

    if (init_success){
        bool res;
        while(1){
            res = obd.getCurrentPID(0x11, 1);
            if (res){
                Serial.print("Result 0x11 (throttle): ");
                Serial.println(obd.readUint8());
            }
            delay(50);
            
            res = obd.getCurrentPID(0x0C, 2);
            if (res){
                Serial.print("Result 0x0C (RPM): ");
                Serial.println(obd.readUint16()/4);
            }
            delay(50);


            res = obd.getCurrentPID(0x0D, 1);
            if (res){
                Serial.print("Result 0x0D (speed): ");
                Serial.println(obd.readUint8());
            }
            Serial.println();

            delay(200);
        }
        delay(200);
    }
    delay(3000);
}

TXL didn't help me.
In the hardware interface I also made the L-Line, but it is not needed with my car.

Serial Monitor:

Looping
Before magic 5 baud.
Before setting port.
After setting port.
First read is: 85
read v1: 233
read v2: 143
v1: 233
v2: 143
read 0xCC?: 204
Rem: 6
ret_len: 7
R: 131 241 16 127 129 17 149 0 
calc cs: 149
buf cs: 149
ok
6
read 0x7F?: 127
init_success:1

With car on but stopped:

Result 0x11 (throttle): 63
Rem: 7
ret_len: 8
R: 132 241 16 65 12 22 108 84 0 
calc cs: 84
buf cs: 84
ok
7
Result 0x0C (RPM): 1435
Rem: 6
ret_len: 7
R: 131 241 16 65 13 0 210 0 
calc cs: 210
buf cs: 210
ok
6
Result 0x0D (speed): 0

Optoisolated interface scheme :
Schermata a 2022-06-18 17-25-29
Schermata a 2022-06-18 17-27-25

@iwanders
Copy link
Owner

iwanders commented Jun 18, 2022

Hey,

Hmm, I've never seen v1 and v2 not being identical, I think the spec says they should be... The values you get (233 and 143) as not even bitwise inverts of each other or something that could perhaps make sense... What is good to see is that your updated initialization code still sends ~v2 and then we get the 0xCC back from the ECU that confirms the initialization succeeded. So you still get the confirmation the ECU is turned on and responding to your requests.

I wonder if the slow part of your initKWP function is somehow just acting as a wakeup signal or something and the end of the KWP init still takes care of the actual initialization 🤔 Regardless, it is working, that's what matters!

I'm glad you got it working :) Thanks for reporting the problem you encountered and the resolution. (Edit; I changed the title of this issue to better capture the issue encountered, hopefully others can find your resolution this way!)

@iwanders iwanders changed the title V1 other than V2! KWP Slow init with v1 != v2 Jun 18, 2022
@tistructor
Copy link
Author

tistructor commented Jun 19, 2022

I read this information to initialize odb2 kwp2000 :
https://m0agx.eu/2018/01/02/reading-obd2-data-without-elm327-part-2-k-line/

@iwanders
Copy link
Owner

iwanders commented Oct 3, 2022

I never got back to this, nor did I read the link you sent. But when answering on #41, I realised that the 233 and 143 looked familiar and looked this issue back up.

I've just filed #42 which implements the same discoveries we had in #41 as you had to make this work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants