Skip to content

Commit

Permalink
First attempt at support for variable requests, DTC.
Browse files Browse the repository at this point in the history
  • Loading branch information
iwanders committed Feb 2, 2018
1 parent bb5f4a5 commit 3833cd2
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 1 deletion.
67 changes: 67 additions & 0 deletions examples/readDTC/readDTC.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "Arduino.h"
#define OBD9141_DEBUG 1
#include "OBD9141.h"

#define RX_PIN 0
#define TX_PIN 1
#define EN_PIN 2

/*
This example is untested
*/

OBD9141 obd;


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

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

obd.begin(Serial1, RX_PIN, TX_PIN);

}

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

bool init_success = obd.init();
Serial.print("init_success:");
Serial.println(init_success);

//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.

uint8_t dtc_buf[5];

if (init_success){
uint8_t res;
while(1){
res = obd.readTroubleCodes();
if (res){
Serial.print("Read ");
Serial.print(res);
Serial.print(" codes:");
for (uint8_t index=0; index < res; index++)
{
// convert the DTC bytes from the buffer into readable string
OBD9141::decodeDTC(obd.getTroubleCode(index), dtc_buf);
Serial.write(dtc_buf, 5);
Serial.println();
}
}
Serial.println();

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




103 changes: 103 additions & 0 deletions src/OBD9141.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,72 @@ bool OBD9141::request(void* request, uint8_t request_len, uint8_t ret_len){
}
}

uint8_t OBD9141::request(void* request, uint8_t request_len){
bool success = true;
// wipe the entire buffer to ensure we are in a clean slate.
memset(this->buffer, 0, OBD9141_BUFFER_SIZE);

// create the request with checksum.
uint8_t buf[request_len+1];
memcpy(buf, request, request_len); // copy request
buf[request_len] = this->checksum(&buf, request_len); // add the checksum

// manually write the bytes onto the serial port
// this does NOT read the echoes.
OBD9141print("W: ");
#ifdef OBD9141_DEBUG
for (uint8_t i=0; i < (request_len+1); i++){
OBD9141print(buf[i]);OBD9141print(" ");
};OBD9141println();
#endif
for (uint8_t i=0; i < request_len+1 ; i++){
this->serial->write(reinterpret_cast<uint8_t*>(request)[i]);
delay(OBD9141_INTERSYMBOL_WAIT);
}

// next step, is to read the echo from the serial port.
this->serial->setTimeout(OBD9141_REQUEST_ECHO_MS_PER_BYTE * 1 + OBD9141_WAIT_FOR_ECHO_TIMEOUT);
uint8_t tmp[request_len+1]; // temporary variable to read into.
this->serial->readBytes(tmp, request_len+1);

OBD9141print("E: ");
for (uint8_t i=0; i < request_len+1; i++)
{
#ifdef OBD9141_DEBUG
OBD9141print(tmp[i]);OBD9141print(" ");
#endif
// check if echo is what we wanted to send.
success &= (buf[i] == tmp[i]);
}

// so echo is dealt with now... next is listening to the reply, which is a variable number.
// set the timeout for the first read.
this->serial->setTimeout(OBD9141_REQUEST_ANSWER_MS_PER_BYTE * 1 + OBD9141_WAIT_FOR_REQUEST_ANSWER_TIMEOUT);

uint8_t answer_length = 0;
// while readBytes returns a byte, keep reading.
while (this->serial->readBytes(&(this->buffer[answer_length]), 1))
{
answer_length++;
this->serial->setTimeout(OBD9141_REQUEST_ANSWER_MS_PER_BYTE * 1);
}

OBD9141println();OBD9141print("A: ");
#ifdef OBD9141_DEBUG
for (uint8_t i=0; i < (answer_length); i++){
OBD9141print(his->buffer[i]);OBD9141print(" ");
};OBD9141println();
#endif

// next, calculate the checksum
bool checksum = (this->checksum(&(this->buffer[0]), answer_length-1) == this->buffer[answer_length]);
if (checksum && success)
{
return answer_length - 1;
}
return 0;
}

/*
No header description to be found on the internet?
Expand Down Expand Up @@ -143,6 +209,17 @@ bool OBD9141::clearTroubleCodes(){
return res;
}

uint8_t OBD9141::readTroubleCodes()
{
uint8_t message[4] = {0x68, 0x6A, 0xF1, 0x03};
uint8_t response = this->request(&message, 4);
if (response >= 4)
{
return (response - 4) / 2.0; // every DTC is 2 bytes.
}
return 0;
}

uint8_t OBD9141::readUint8(){
return this->buffer[5];
}
Expand All @@ -155,6 +232,15 @@ uint8_t OBD9141::readUint8(uint8_t index){
return this->buffer[5 + index];
}

uint8_t OBD9141::readBuffer(uint8_t index){
return this->buffer[index];
}

uint8_t* OBD9141::getTroubleCode(uint8_t index)
{
return &(this->buffer[index*2 + 4]);
}

bool OBD9141::init(){
// this function performs the ISO9141 5-baud 'slow' init.
this->set_port(false); // disable the port.
Expand Down Expand Up @@ -249,3 +335,20 @@ bool OBD9141::init(){
}


void OBD9141::decodeDTC(void* input_bytes, uint8_t* output_string){
const uint8_t A = reinterpret_cast<uint8_t*>(input_bytes)[0];
const uint8_t B = reinterpret_cast<uint8_t*>(input_bytes)[1];
const static char type_lookup[4] = {'P', 'C', 'B', 'U'};
const static char digit_lookup[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

// A7-A6 is first dtc character, error type:
output_string[0] = type_lookup[A >> 6];
// A5-A4 is second dtc character
output_string[1] = digit_lookup[(A >> 4) & 0b11];
// A3-A0 is third dtc character.
output_string[2] = digit_lookup[A & 0b1111];
// B7-B4 is fourth dtc character
output_string[3] = digit_lookup[B >> 4];
// B3-B0 is fifth dtc character
output_string[4] = digit_lookup[B & 0b1111];
}
42 changes: 41 additions & 1 deletion src/OBD9141.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,34 @@ class OBD9141{
// length was returned and if the checksum matches.
// User needs to ensure that the ret_len never exceeds the buffer size.


/**
* @brief Send a request with a variable number of return bytes.
* @param request The pointer to read the address from.
* @param request_len the length of the request.
* @return the number of bytes read if checksum matches.
* @note If checksum doesn't match return will be zero, but bytes will
* still be written to the internal buffer.
*/
uint8_t request(void* request, uint8_t request_len);

// The following methods only work to read values from PID mode 0x01
uint8_t readUint8(); // returns right part from the buffer as uint8_t
uint16_t readUint16(); // idem...
uint8_t readUint8(uint8_t index); // returns byte on index.

/**
* @brief This method allows raw access to the buffer, the return header
* is 4 bytes, so data starts on index 4.
*/
uint8_t readBuffer(uint8_t index);

/**
* @brief return the pointer to the trouble code in the buffer by index.
* @param index The index of the trouble code.
* @return point used by decodeDTC.
*/
uint8_t* getTroubleCode(uint8_t index);


void set_port(bool enabled);
// need to disable the port before init.
Expand All @@ -159,7 +182,24 @@ class OBD9141{
// Check engine light.
// Returns whether the request was successful.

/**
* @brief attempts to read the diagnostic trouble codes using the
* variable read method.
* @return The number of trouble codes read.
*/
uint8_t readTroubleCodes();

static uint8_t checksum(void* b, uint8_t len); // public for sim.

/**
* Decodes the two bytes at input_bytes into the diagnostic troublecode,
* written in printable format to output_string.
* @param output_string Writes 5 bytes to this pointer representing the
* human readable DTC string.
* @param input_bytes reads two bytes from this location.
*/
static void decodeDTC(void* input_bytes, uint8_t* output_string);

};


Expand Down

0 comments on commit 3833cd2

Please sign in to comment.