Read DTC codes OBD2 using arduino - arduino-esp32

I try read dtc codes using a obd device (sparkfun obd based on stn1110) and an arduino. Running this code
uint16_t codes[6];
byte dtcCount = obd.readDTC(codes, 6);
if (dtcCount == 0) {
Serial.println("No DTC");
} else {
Serial.print(dtcCount);
Serial.print(" DTC:");
for (byte n = 0; n < dtcCount; n++) {
Serial.print(' ');
Serial.print(codes[n], HEX);
}
Serial.println();
}
delay(5000);
}
Returns:
2 DTC: 3303 100
How can I interpret those codes? I mean usually I saw error codes are like PXXXX ...
Thanks a lot
L.E.
I scanned same car using a "proffesional" tester and found following codes (see pictures).
What I am doing wrong with my code or how should I interpret my results in order to get same codes as the service scanner?
Basically my code show 2 dtc's but the scanner found 5 in total
Dig further and I think the function used for read dtc is somehow wrong:
this is the function
byte COBD::readDTC(uint16_t codes[], byte maxCodes)
{
byte codesRead = 0;
for (byte n = 0; n < 6; n++) {
char buffer[128];
sprintf_P(buffer, n == 0 ? PSTR("03\r") : PSTR("03%02X\r"), n);
write(buffer);
if (receive(buffer, sizeof(buffer)) > 0) {
Serial.print("received buffer :");
Serial.println(buffer);
if (!strstr_P(buffer, PSTR("NO DATA"))) {
char *p = strstr(buffer, "43");
if (p) {
while (codesRead < maxCodes && *p) {
p += 6;
if (*p == '\r') {
p = strchr(p, ':');
if (!p) break;
p += 2;
}
uint16_t code = hex2uint16(p);
if (code == 0) break;
codes[codesRead++] = code;
}
}
break;
}
}
}
return codesRead;
}
As you see I printed "received buffer" to see what I get from OBD and the result is:
received buffer :43 01 33 03 01 00 00
>
I think is something wrong here, or I miss something in the answer
why i get that">" on a new line?
also according to https://en.wikipedia.org/wiki/OBD-II_PIDs (chapter Service 03 (no PID required))
i delete "43" from my buffer and get "01 33 03 01 00 00"
then "01" means "C - Chassis"
but then nothing match to the decoding description...so I became almost sure that I don t ask / read as it should this thing. I think i get an invalid answer somehow ...
Again any help will be appreciated :)
Thanks
L.E.2 - did another progess step.
According to this document - https://www.elmelectronics.com/wp-content/uploads/2016/07/ELM327DS.pdf , on page 34
first should find out the number of dtc stored and then try to read them.
Sending >0101 to obd return me "41 01 82 07 61 01"
and if I do 82 - 80 => I have 2 trouble codes ?!?! why I have 5 of them on the tester?
From my previous response, also according to that document
"43 01 33 03 01 00 00" means P0133 and P0301
But on the tester, except those 2, I had also - P0303 , P0300 and C1513
How to get to read correctly the dtc codes?
Thanks again

Related

Serial communication : Send a list from Python3 to Arduino

I don't manage to deal with my problem even if I have read a lot about it on internet these last few days.
I try to communicate a variable length list from my Python3 program to my Arduino Leonardo.
Actually the length of these lists is variable but there are only three possible length :
first possibility : [0, 0, 1, 176, 1, 0, 0]
second possibility : [0, 1, 11, 255]
third possibility : [0, 2, 0]
(most of the values inside these lists are variables)
My Python3 code :
with Serial(port = port, baudrate=9600, timeout=1, writeTimeout=1) as port_serie :
if port_serie.isOpen() :
for value in Datas_To_Send : #Envoi des données
s = struct.pack('!{0}B'.format(len(Datas_To_Send)), *Datas_To_Send)
port_serie.write(s)
This code sends binary values like this one :
b'\x00\x00\x01\xb0\x01\x00\x00'
(the original list to send was : [0, 0, 1, 176, 1, 0, 0])
The problem is that I absolutely don't know how to find back my original list of values with my Arduino code...
My Arduino code (quite basic) :
void changeSettings() {
if ( Serial.available() > 0 ) {
int byte_read = Serial.read() ;
Serial.println(byte_read, DEC) ;
The output of this code is a pure conversion of each character from the ASCII to the Decimal...
Output (for the binary value I gave as example) :
98
39
92
120
48
48
92
120
48
48
92
120
48
49
92
120
98
48
92
120
48
49
92
120
48
48
92
120
48
48
39
10
Do you have any idea to find the first list back ?
Thank you
It seems you need to transmit either 7, 4 or 3 values, correct?
Are all the values under 256?
So, i would send 1 byte that is either 7, 4 or 3 followed by either 7, 4 or 3 bytes of the list's elements. If any item in your list is greater than 255 and less than 65,536 you'll need to send 2 bytes per element.
Well, I found the solution thanks to #MarkSetchel's and Olmagzar's (Discord user) tips.
Python3 code :
if Datas_To_Send :
long = len(Datas_To_Send)
Datas_To_Send.insert(0, long)
with Serial(port = '/dev/cu.usbmodem14101', baudrate=9600, timeout=1, writeTimeout=1) as port_serie :
if port_serie.isOpen() :
s = struct.pack('!{0}B'.format(len(Datas_To_Send)), *Datas_To_Send)
port_serie.write(s)
port_serie.close()
So I add list length directly at the first position of my list "Datas_To_Send".
Like that I just have to read it first on Arduino's side to know how many items I have to read.
Arduino code :
void changeSettings() {
if (Serial.available() > 0)
{
unsigned char len = Serial.read();
unsigned char Datas[len] ;
for (int i = 0; i < len - 1; i++)
{
unsigned char byte_read = Serial.read();
Datas[i] = byte_read ;
}
}
}

Changing protobuff optional field to oneof

I have the following message:
message Message {
int64 id = 1;
google.protobuf.FloatValue weight = 2;
google.protobuf.FloatValue override_weight = 3;
}
and I wish to change the type of weight and override_weight(optional fields) to google.protobuf.DoubleValue so what I did was the fllowing:
message Message {
int64 id = 1;
oneof weight_oneof {
google.protobuf.FloatValue weight = 2 [deprecated=true];
google.protobuf.DoubleValue double_weight = 4;
}
oneof override_weight_oneof {
google.protobuf.FloatValue override_weight = 3 [deprecated=true];
google.protobuf.DoubleValue double_override_weight = 5;
}
}
My question is, lets assume I have old messages who were compiled by the previous protobuff message compiler for the old message, would I be able to parse them as the new message?
The documentation is very vague about this:
"Move optional fields into or out of a oneof: You may lose some of your information (some fields will be cleared) after the message is serialized and parsed. However, you can safely move a single field into a new oneof and may be able to move multiple fields if it is known that only one is ever set."
Has anyone tried this before? what is the best practice for this situation?
As far as I know fields in an oneof are just serialize using their tag number. The serialized data does not indicate if a field is part of an oneof. This is all handled by the serializer and deserializer. So as long as the tag numbers do not conflict it can be assumed that it will work in both directions, old messages to a new serializer and new messages to an old serializer.
You could test this using an online protobuf deserializer.
Verification:
The code does indeed produce the same byte strings. Below you will find the message definitions and python code I used. The python code will output a byte string you can copy and use in the decoder of Marc Gravell.
syntax = "proto3";
message MessageA {
int64 id = 1;
float weight = 2;
float override_weight = 3;
}
message MessageB {
int64 id = 1;
oneof weight_oneof {
float weight = 2 [deprecated=true];
double double_weight = 4;
}
oneof override_weight_oneof {
float override_weight = 3 [deprecated=true];
double double_override_weight = 5;
}
}
import Example_pb2
# Set some data in the original message
msgA = Example_pb2.MessageA()
msgA.id = 1234
msgA.weight = 3.21
msgA.override_weight = 5.43
# Output the serialized bytes in a pretty format
str = 'msgA = '
for x in msgA.SerializeToString():
str += "{:02x} ".format(x)
print(str)
# Next set the original fields in the new message
msgB = Example_pb2.MessageB()
msgB.id = 1234
msgB.weight = 3.21
msgB.override_weight = 5.43
# Output the serialized bytes in a pretty format
str = 'msgB 1 = '
for x in msgB.SerializeToString():
str += "{:02x} ".format(x)
print(str)
# And finally set the new fields in msgB
msgB.double_weight = 3.21
msgB.double_override_weight = 5.43
# Output the serialized bytes in a pretty format
str = 'msgB 2 = '
for x in msgB.SerializeToString():
str += "{:02x} ".format(x)
print(str)
The output of the python script was:
msgA = 08 d2 09 15 a4 70 4d 40 1d 8f c2 ad 40
msgB 1 = 08 d2 09 15 a4 70 4d 40 1d 8f c2 ad 40
msgB 2 = 08 d2 09 21 ae 47 e1 7a 14 ae 09 40 29 b8 1e 85 eb 51 b8 15 40
As you can see message A and message B yield the same byte string when setting the original fields. Only when you set the new fields you get a different string.

I am trying to loop a number and print it in another method

So the idea is I get a number from the user and this is how many decimals the number will be. I then print out every possible outcome for his many decimal places.
So if the user inputs "2" then it will output 01 02 03 ... 99. I also have to store this number as a string. I am having difficulties getting the number to loop, it will reset after every loop. here is my code.
import java.util.Scanner;
public class Hw2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
diff here = new diff();
String res;
String d = "0";
do {
System.out.println("Enter 1 to enter length of number: ");
System.out.println("q. quit: ");
System.out.print("select:");
res = in.next();
in.nextLine();
switch(res.charAt(0)) {
case '1':
// get n from user
System.out.print("Enter the length of string: ");
int n = in.nextInt();
diff.printDecimal(n, d);
break;
case 'q': case 'Q':
System.out.println("Bye!");
break;
default:
System.out.println("Invalid");
break;
}
} while (res.charAt(0) != 'q' && res.charAt(0) != 'Q');
}
}
class diff {
// print string
static void printDecimal (int n, String d) {
String maxNum = "9";
while( maxNum.length() < n ) {
maxNum += 9;
}
while (d != maxNum) {
System.out.println(inDecimal(n, d));
}
}
// increase string value by 1
static String inDecimal(int n, String d) {
String d2 = "";
int d3 = Integer.parseInt(d);
d3++;
d = Integer.toString(d3);
//d = String.valueOf(d) + 1;
while( d.length() < n ) {
d2 = "0" + d;
d = d2;
}
System.out.println(d);
return d;
}
}
Thank you for all of your help!!
Also just for the record, I would normally go to a tutor with a question like this but they haven't hired tutors yet this semester.
Something like this?
int places = 2;
for (int i = 0; i < Math.pow(10, places); i++) {
System.out.printf("%0" + places + "d\n", i);
}
The string formatting like come out as a zero-padded number with 2 places.
Outputs
00
01
02
03
04
05
06
07
08
09
10
...
99

C++ converting hex number to human readable string representation

I have a char[32] that consist of ASCII characters, some of which may be non printable characters, however, they are all in valid range of 0 to 255.
Let's say, it contains these numbers:
{ 9A 2E 5C 66 26 3D 5A 88 76 26 F1 09 B5 32 DE 10 91 3E 68 2F EA 7B C9 52 66 23 9D 77 16 BB C9 42 }
I'd like to print out or store in std::string as "9A2E5C66263D5A887626F109B532DE10913E682FEA7BC95266239D7716BBC942", however, if I print it out using printf or sprintf, it will yield the ASCII representative of each number, and instead it will print out "ö.\f&=Zàv&Ò µ2fië>h/Í{…Rf#ùwª…B", which is the correct ASCII character representation, since: ö = 9a, . = 2e, ...
How do I reliably get the string representation of the hex numbers? ie: I'd expect a char[64] which contains "9A2E5C66263D5A887626F109B532DE10913E682FEA7BC95266239D7716BBC942" instead.
Thanks!
void bytesToHex(char* dest, char* src, int size) {
for (unsigned int i = 0; i < size; i++) {
sprintf(&dest[i * 2], "%02x", src[i]);
}
}
You'd have to allocate your own memory here.
It would be used like this:
char myBuffer[32]
char result[65];
bytesToHex(result, myBuffer, 32);
result[64] = 0;
// print it
printf(result);
// or store it in an std::string
std::string str = string(result);
I tried:
char szStringRep[64];
for ( int i = 0; i < 32; i++ ) {
sprintf( &szStringRep[i*2], "%x", szHash[i] );
}
it works as intended, but if it encountered a < 0x10 number, it will null terminated as it is printing 0
You can encode your string to another system like Base64, which is widely used when using encryption algorithms.

MCP2200 linux settings

Im want to control MCP2200 in linux.
I found Text Link and set everything.
For example:
I type in console
GP3-1
It will sets pin 3 to 1. But i dont know what to type in console
for controlling the mcp2200 you will need a program doing the stuff for you.
The USBtoUART didn't work for me, maybe you'll have to do some coding yourself - but you can use it to understand how to connect to the mcp2200 hid.
For controlling the IOs, just set up a 16-byte array, filled with the data described here:
http://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf
If you want to control some more stuff but gpios, you'll have to do some more - it is possible to control more than just the gpios of the mcp2200 from linux.
I did a little usb trace of the communication of the windows config tool, extracted some informations and - tadaah, there you go with your own pID/vID, Manufacturer and Product strings.
Note: you'll probably need the HIDAPI MikeF was talking about.
First of all, some definitions:
// NOTE: max. string length for manufacturer / product string is 63 bytes!!
// from usb trace of mcp2200 config tool
#define MCP2200_SECRET_CONFIGURE 0x01
#define MCP2200_CFG_PID_VID 0x00
#define MCP2200_CFG_MANU 0x01
#define MCP2200_CFG_PROD 0x02
... and some variables:
unsigned char **mcp2200_manu_string;
unsigned char **mcp2200_prod_string;
The output message for manufacturer string looks like
/* configure manufacturer string (16 x 16 bytes):
* output buffer:
* #0: [01 01 00 16 03 58 00 4B 00 72 00 FF FF FF FF FF]
* | | | | | | | | | | | +-----------+--> Always FF
* | | | | | | +-----+-----+-----------------> Always 00
* | | | | | +-----+-----+--------------------> First 3 Chars of Manufacturer Name / Product Name
* | | | | +-----------------------------------> In #0: 0x03, After #0: 0x00
* | | | +--------------------------------------> (Length (Manufacturer Name) * 2) + 2 (after #0: chars of manufacturer name)
* | | +-----------------------------------------> Counter 0x00 .. 0x0F
* | +--------------------------------------------> MCP2200 Config Bit (MCP2200_CFG_MANU / PROD / VID_PID)
* +-----------------------------------------------> MCP2200_SECRET_CONFIGURE from usb trace
*/
if you put all this in a function, it could look like this:
void prepare_cfg_strings (char* manu, char* prod) {
char manuStr[64];
char prodStr[64];
unsigned int i, k = 0;
unsigned char tmp = 0;
memset (manuStr, 0x00, sizeof(manuStr));
memset (prodStr, 0x00, sizeof(prodStr));
// allocate mcp2200_{manu,prod}_string buffer, 2-dim array with 16 x 16 chars
if (( mcp2200_manu_string = ( unsigned char** )malloc( 16*sizeof( unsigned char* ))) == NULL ) {
// error
}
if (( mcp2200_prod_string = ( unsigned char** )malloc( 16*sizeof( unsigned char* ))) == NULL ) {
// error
}
for ( i = 0; i < 16; i++ )
{
if (( mcp2200_manu_string[i] = ( unsigned char* )malloc( 16 )) == NULL ) {
/* error */
}
if (( mcp2200_prod_string[i] = ( unsigned char* )malloc( 16 )) == NULL ) {
/* error */
}
/* init the rows here */
memset (mcp2200_manu_string[i], 0x00, sizeof(&mcp2200_manu_string[i]));
memset (mcp2200_prod_string[i], 0x00, sizeof(&mcp2200_prod_string[i]));
}
// manuStr holds (strlen(manuStr) * 2) + 2 in byte[0] and manufacturer string from byte[1] on
strcpy (&manuStr[1], manu);
manuStr[0] = ((strlen (&manuStr[1]) * 2) + 2);
// prodStr holds (strlen(prodStr) * 2) + 2 in byte[0] and product string from byte[1] on
strcpy (&prodStr[1], prod);
prodStr[0] = ((strlen (&prodStr[1]) * 2) + 2);
// build manufacturer / product strings
for (i=0, k=0; i<16; i++, k+=4) {
if (i==0) {
tmp = 0x03;
} else {
tmp = 0x00;
}
// manufacturer string
mcp2200_manu_string[i][0] = MCP2200_SECRET_CONFIGURE;
mcp2200_manu_string[i][1] = MCP2200_CFG_MANU;
mcp2200_manu_string[i][2] = i;
mcp2200_manu_string[i][3] = manuStr[k];
mcp2200_manu_string[i][4] = tmp;
mcp2200_manu_string[i][5] = manuStr[k+1];
mcp2200_manu_string[i][6] = 0x00;
mcp2200_manu_string[i][7] = manuStr[k+2];
mcp2200_manu_string[i][8] = 0x00;
mcp2200_manu_string[i][9] = manuStr[k+3];
mcp2200_manu_string[i][10] = 0x00;
mcp2200_manu_string[i][11] = 0xff;
mcp2200_manu_string[i][12] = 0xff;
mcp2200_manu_string[i][13] = 0xff;
mcp2200_manu_string[i][14] = 0xff;
mcp2200_manu_string[i][15] = 0xff;
// product string
mcp2200_prod_string[i][0] = MCP2200_SECRET_CONFIGURE;
mcp2200_prod_string[i][1] = MCP2200_CFG_PROD;
mcp2200_prod_string[i][2] = i;
mcp2200_prod_string[i][3] = prodStr[k];
mcp2200_prod_string[i][4] = tmp;
mcp2200_prod_string[i][5] = prodStr[k+1];
mcp2200_prod_string[i][6] = 0x00;
mcp2200_prod_string[i][7] = prodStr[k+2];
mcp2200_prod_string[i][8] = 0x00;
mcp2200_prod_string[i][9] = prodStr[k+3];
mcp2200_prod_string[i][10] = 0x00;
mcp2200_prod_string[i][11] = 0xff;
mcp2200_prod_string[i][12] = 0xff;
mcp2200_prod_string[i][13] = 0xff;
mcp2200_prod_string[i][14] = 0xff;
mcp2200_prod_string[i][15] = 0xff;
}
}
Call this function in your main loop:
prepare_cfg_strings ("MyManufacturerName, "MyProductName");
Open a hid handle to your mcp2200 and put this stuff on the bus:
// write manufacturer string configuration to usb device
for (i=0; i<16; i++) {
hid_write (handle, mcp2200_manu_string[i], 16);
}
// write product string configuration to usb device
for (i=0; i<16; i++) {
hid_write (handle, mcp2200_prod_string[i], 16);
}
If you want to flash the mcp2200 with your own VendorID / ProductID configure your message:
// Microchip VID: 0x04d8
// MCP2200 PID: 0x00df
mcp2200_pid_vid_cfg[] = 01 00 D8 04 DF 00 00 00 00 00 00 00 00 00 00 00
| | +---+ +---+--------------------------------> Product ID (bytes swapped)
| | +--------------------------------------> Vendor ID (bytes swapped)
| +--------------------------------------------> MCP2200 Config Bit (MCP2200_CFG_VID_PID)
+-----------------------------------------------> MCP2200_SECRET_CONFIGURE from usb trace
and put it on the bus:
hid_write (handle, mcp2200_pid_vid_cfg, 16);
Have Fun!
n.
You will not be able to control the GPIO ports from the console/terminal via USB tty...
The USB to serial/UART converter is one of the features of MCP2200, to control the GPIO, you need to send commands via USB & HID driver. to achieve this, you will need the following.
HIDAPI:
https://github.com/signal11/hidapi
USBtoUART:
https://github.com/Miceuz/USBtoUART
USBtoUART requires hid.o from the HIDAPI package.... so start with HIDAPI first...
good luck!
MikeF
ps: I made a few modifications to the code, to accept binary format for controlling the GPIO ports, etc... it has been compiled fine on x86 and ARM ( Raspberry Pi )

Resources