Giter Club home page Giter Club logo

Comments (26)

Jastreb07 avatar Jastreb07 commented on May 17, 2024 4

Thanks guys, its working now.
I have programmed a Dash Cluster
The result of my work: https://vm.tiktok.com/ZS4XktLp/

from elmduino.

cyberelectronics avatar cyberelectronics commented on May 17, 2024 1

Fortunately, Matthew, who wrote the SafeString library, helped me with this issue.
Just finished a live test, while charging the car for 50 minutes.
No reboot or WiFi and BT connection issues at all.
OBD BT queried once/sec and the datas (in multiple groups) was sent every 2 seconds to Blynk.
So here is the working parser for OBD protocol 6 with multiple dataframes (from 0: 1: 2: to 8: ).
I hope this will help others (maybe @PowerBroker2 will add this to a new release)
Thanks guys!

#include "SafeString.h"

createSafeString(dataFrame0, 14);   // will also add space for the terminating null =>15 sized array
createSafeString(dataFrame1, 14);
createSafeString(dataFrame2, 14);
createSafeString(dataFrame3, 14);
createSafeString(dataFrame4, 14);
createSafeString(dataFrame5, 14);
createSafeString(dataFrame6, 14);
createSafeString(dataFrame7, 14);
createSafeString(dataFrame8, 14);

void clearData() {
                    dataFrame0.clear();
                    dataFrame1.clear();
                    dataFrame2.clear();
                    dataFrame3.clear();
                    dataFrame4.clear();
                    dataFrame5.clear();
                    dataFrame6.clear();
                    dataFrame7.clear();
                    dataFrame8.clear();
  
}

void addToFrame(int frame, char c) {
	switch(frame) {
		case 0:
			dataFrame0 += c;
			break;
		case 1:
			dataFrame1 += c;
			break;
		case 2:
			dataFrame2 += c;
			break;
		case 3:
			dataFrame3 += c;
			break;
		case 4:
			dataFrame4 += c;
			break;
		case 5:
			dataFrame5 += c;
			break;
		case 6:
			dataFrame6 += c;
			break;
		case 7:
			dataFrame7 += c;
			break;
		case 8:
			dataFrame8 += c;
			break;
	}
}

void frameSubstr(SafeString& frame, int m, int n, SafeString& subStr) {
    frame.substring(subStr,m,n);   // SafeString substring is inclusive m to n
}

int convertToInt(SafeString& dataFrame, size_t m, size_t n) {
  // define a local SafeString on the stack for this method
    createSafeString(hexSubString, 14);  // allow for taking entire frame as a substring 
    frameSubstr(dataFrame, m, n, hexSubString);
    return (int)strtol(hexSubString.c_str(), NULL, 16);
}

void parse(char *raw) {
	int frame = -1;
	
	int len = strlen(raw);
	
	for(int i=0; i<len; i++) {
		
		if(raw[i+1] == ':') { //start frame
			frame = (int) raw[i] - '0';
			continue;
		}
		
		if(raw[i] == ':') {
			continue;
		}
		
		if(frame == -1) {
			continue;
		}
		
		if(raw[i] == '>') {
			frame = -1;
			continue;
		}
		
		addToFrame(frame, raw[i]);
	}
	
}

void read_rawdata(){
                       // move data from OBD to Rawdata array
                       char rawData[myELM327.recBytes];
                       int n = 0;
                                                                            
                       DEBUG_PORT.print("Payload received: ");
                       
                       for (int i=0; i<myELM327.recBytes; i++) {
                                                                  rawData[n++] = myELM327.payload[i];  
                                                                  DEBUG_PORT.print(myELM327.payload[i]); // Serial print OBD Rawdata
                                                               }
                       DEBUG_PORT.println(); 
                                                                        
                       parse(rawData);  // parse data received from OBD
                        
  }

// loop 
void loop(){
             // insert timer/delay (ex. 1sec)
             ...
             myELM327.sendCommand("AT SH 7E4");       // Set Header BMS 
                                                     
             if (myELM327.queryPID("220101")) {      // BMS PID = hex 22 0101 => dec 34, 257
         
                           read_rawdata(); 
                           BATTv = ((convertToInt(dataFrame2, 4, 5)<<8) + convertToInt(dataFrame2, 6, 7))/10;
                           DEBUG_PORT.print("Main Battery Voltage (V): ");
                           DEBUG_PORT.println(BATTv);
                           clearData();
                        }                                                                                   
    }                                                                                                       

Screenshot_20201022-181701_Blynk
20201022_173931
20201022_180720
Screenshot_20201022-172100_Blynk
Screenshot_20201022-180703_Blynk
Screenshot_20201022-181100_Blynk

from elmduino.

KoYoT77 avatar KoYoT77 commented on May 17, 2024 1

Gents,
With Jaukb's help - our sketch works.
The issue was in this line of code:
sprintf(command, SET_HEADER, "7E0");
Elmduino.h const as below:
const char * const SET_HEADER = "AT SH"; // OBD
has been edited to this line
const char * const SET_HEADER = "AT SH %s"; // OBD
finally we have received proper data, same as in the App DPM Monitor.

Thanks to both of you and Jakub too!

from elmduino.

cyberelectronics avatar cyberelectronics commented on May 17, 2024 1

Thanks guys, @PowerBroker2 / Matthew for your library & help!
Here is the almost finished OBD Google TTS project :)
https://youtu.be/mUl9IHsN-ao

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

You can do something like this:

  if (myELM327.queryPID("221E12"))
  {
    int32_t temp = myELM327.findResponse();

    Serial.print("Raw Response: ");
    for (byte i = 0; i < PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      Serial.print("Parsed Response: "); Serial.println(temp);
    }
    else
    {
      Serial.print("ERROR: "); Serial.println(myELM327.status);
    }
  }

from elmduino.

Jastreb07 avatar Jastreb07 commented on May 17, 2024

You can do something like this:

  if (myELM327.queryPID("221E12"))
  {
    int32_t temp = myELM327.findResponse();

    Serial.print("Raw Response: ");
    for (byte i = 0; i < PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      Serial.print("Parsed Response: "); Serial.println(temp);
    }
    else
    {
      Serial.print("ERROR: "); Serial.println(myELM327.status);
    }
  }

'PAYLOAD_LEN' was not declared in this scope

Screenshot: https://prnt.sc/unl6rm

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

Sorry, that was a snippet from old code. Change PAYLOAD_LEN to myELM327.PAYLOAD_LEN

from elmduino.

Jastreb07 avatar Jastreb07 commented on May 17, 2024

Thank its work :)

from elmduino.

Jastreb07 avatar Jastreb07 commented on May 17, 2024

Sorry, that was a snippet from old code. Change PAYLOAD_LEN to myELM327.PAYLOAD_LEN

im get every time "Parsed Response: 0" how i can fix it?
i have testet the PID on "Torque"-APP and it give me value back


Transmission Gear Shifter Position 6.7 –
PID – 221E23– Testing
Long Name (used in menus) – Transmission Shifter Position 6.7L
Short Name (used in gauge display) – Shifter
Min Value – 0.0
Max Value – 100
Scale Factor – x1
Unit Type – PRNDM21
Equation – A
OBD Header –

Park - 70.0
Reverse - 60.0
Neutral - 50.0
Drive - 46.0
Manual - 10.0
2nd Gear - 22.0
1st Gear - 21.0

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

What does the Arduino say for the "Raw Response"?

from elmduino.

Jastreb07 avatar Jastreb07 commented on May 17, 2024

What does the Arduino say for the "Raw Response"?

621E2346

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

Hmm, that should parse to 1646142278 (decimal), I can double check everything and let you know

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

What about this?:

  if (myELM327.queryPID("221E12"))
  {
    uint64_t temp = myELM327.findResponse();

    Serial.print("Raw Response: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      Serial.print("Parsed Response: "); Serial.println(temp);
    }
    else
    {
      Serial.print("ERROR: "); Serial.println(myELM327.status);
    }
  }

from elmduino.

Jastreb07 avatar Jastreb07 commented on May 17, 2024
if (myELM327.queryPID("221E12"))
  {
    uint64_t temp = myELM327.findResponse();

    Serial.print("Raw Response: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      Serial.print("Parsed Response: "); Serial.println(temp);
    }
    else
    {
      Serial.print("ERROR: "); Serial.println(myELM327.status);
    }
  }

Arduino_hardware_serial_test.ino

call of overloaded 'println(uint64_t&)' is ambiguous

https://prnt.sc/uommak

PID "221E23" (shifter Gear) --> https://prnt.sc/uompf8
PID "221E12" (Current Gear) respons too "0"

from elmduino.

KoYoT77 avatar KoYoT77 commented on May 17, 2024

im get every time "Parsed Response: 0" how i can fix it?
i have testet the PID on "Torque"-APP and it give me value back

I have same problem, all the time response is equal "0".
So I'm curious about solution. Looking forward.

PowerBroker2 -> I have tried to contact you on Arduino.cc forum in private message.

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

Please post exactly what you're trying to do along with your entire sketch in tags along with a description of your physical setup and experiment parameters (i.e. car make/model, is the car on and running, etc). Also, make sure all other bluetooth devices are either disabled or turned off. Testing with different bauds also clears some people's issues.

from elmduino.

KoYoT77 avatar KoYoT77 commented on May 17, 2024

Project: Retrive information about DPF,
Physical setup: Arduino Nano + BlueTooth HC-05 -> iCar2Pro(ELM327)+Opel Insignia; engine A20DTH.
Code below

/*
Code base on PowerBroker2 & miguelos6 - Github https://github.com/PowerBroker2/ELMduino/issues/4
HEADER for Engine parameters Jakub Dziworski  - http://jakubdziworski.github.io/
Car: Vauxhal/OPEL; model: Insignia; Engine: A20DTH
Communication->Arduino > BT HC-05 > ELM V-Link ICAR2Pro
Results printed on LCD 16x2
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include <ELMduino.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
SoftwareSerial mySerial(10, 7); // RX, TX for BlueTooth HC-05
#define ELM_PORT mySerial
ELM327 myELM327;

/*//////////////CONST &  VARIABLE DEFINITION///////////////// */
const long debugRate = 115200;
const long mySerialRate = 38400; //one working BT BOUND 34800,0,0
int32_t dirtLevel = -1;
int32_t burn = -1;
int32_t regenStatus = -1;
int32_t kmsSinceDpf = -1;
  

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("...CONNECTING...");
  lcd.setCursor(0,1);  
  lcd.print("BT HC05 > V-LINK");
  Serial.begin(debugRate);
  Serial.println("Serial Monitor - START");
  ELM_PORT.begin(mySerialRate);
  Serial.println("...Connecting to ELM327...");  

/*//////////////CHECK BT CONNECTION///////////////// */
  if (!myELM327.begin(ELM_PORT))
  {
    Serial.println("V-LINK - NOT CONNECTED");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("..NOT CONNECTED.");
    lcd.setCursor(0,1);  
    lcd.print("BT HC05 > V-LINK"); 
    while (1);
  }
  Serial.println("V-LINK - CONNECTED SUCCESFUL");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("BT HC05 > V-LINK");
    lcd.setCursor(0,1);  
    lcd.print("....CONNECTED...");

/*//////////////CONFIRM BY FLASHING BUILT LED///////////////// */
flashLEDx5();

/*//////////////SET HEADER FOR ENGINE///////////////// */
  myELM327.sendCommand(PRINTING_SPACES_ON);
  char command[20] = { '\0' };
  sprintf(command, SET_HEADER, "7E0");
 
  if (myELM327.sendCommand(command) != ELM_SUCCESS)
  {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("UNABLE TO SET ");
    lcd.setCursor(0,1);
    lcd.print("...HEADER 7E0...");
    Serial.println("UNABLE TO SET AT SH 7E0");
  }
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("...HEADER 7E0...");
    lcd.setCursor(0,1);
    lcd.print("  HAS BEEN SET  ");  
    Serial.println("AT SH 7E0 - SUCCESS!!!");

/*//////////////CONFIRM BY FLASHING BUILT LED///////////////// */
flashLEDx5();
}

/*//////////////RETRIEVING DATA///////////////// 
0x22, 0x3274 = 34,12916 - regeneration status
0x22, 0x3277 = 34,12919 - km's since last DPF clean
0x22, 0x3275 = 34,12917 - DPF dirt level
*/
void loop()
{
/*
  ////////////////////REGENERATION STATUS//////////////////
  int32_t getRegenerationStatus() {return queryVgate(0x22, 0x3274);}
*/
  if (myELM327.queryPID(34, 12916))
  {
    int32_t tempregenStatus = myELM327.findResponse();

    Serial.print("Payload received for soot: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      regenStatus = tempregenStatus;
      Serial.print("RegenStat: "); Serial.println(regenStatus);
    }
    else
      printError();
  }
/*
  ////////////////////KMs SINCE DPF//////////////////
  int32_t getKmsSinceDpf() {return queryVgate(0x22, 0x3277);}
*/
  if (myELM327.queryPID(34, 12919))
  {
    int32_t tempkmsSinceDpf = myELM327.findResponse();

    Serial.print("Payload received for soot: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      kmsSinceDpf = tempkmsSinceDpf;
      Serial.print("Km since DPF: "); Serial.println(kmsSinceDpf);
    }
    else
      printError();
  }
/*
  ////////////////////DPF Dirt Level//////////////////
int32_t getDpfDirtLevel() {return queryVgate(0x22, 0x3275);}
*/
  if (myELM327.queryPID(34, 12917))
  {
    int32_t tempdirtLevel = myELM327.findResponse();

    Serial.print("Payload received for dirtLevel: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();
    
    if (myELM327.status == ELM_SUCCESS)
    {
      dirtLevel = tempdirtLevel;
      Serial.print("DPF dirt level: "); Serial.println(dirtLevel);
    }
    else
      printError();
  }
/*//////////////CONFIRM BY FLASHING BUILT LED///////////////// */
flashLEDx5();

/*//////////////CHECK REGENERATING IS IN PROGRESS OR NOT///////////////// 

> */

 if(burn > 0) {
    printRegenerating(regenStatus);
   return;
 }
/*//////////////PRINT STATUS OF PARAMETERS///////////////// */
 printDpfStatus();

/*//////////////WAIT 1s BEFORE ASK AGAIN///////////////// */ 
delay(1000);
  
}

/*//////////////CHECK ELM327 - ANSWER///////////////// */ 
void printError()
{
  if (myELM327.status == ELM_SUCCESS)
    Serial.println(F("\tELM_SUCCESS"));
  else if (myELM327.status == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.status == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.status == ELM_GARBAGE)
    Serial.println(F("\tERROR: ELM_GARBAGE"));
  else if (myELM327.status == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.status == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.status == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.status == ELM_GENERAL_ERROR)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));
  delay(500);  
  }

/*//////////////FLASHING BUILT LED - LOOP///////////////// */
void flashLEDx5()
{
  for (int a = 0; a < 5; ++a)
  {
    digitalWrite(LED_BUILTIN,HIGH); delay(100);
    digitalWrite(LED_BUILTIN,LOW); delay(100); 
  }
  
}
/*//////////////JAKUB's FUNCTIONS TO DETERMINE LEVEL OF SOOT AND STATUS///////////////// */
void printDpfStatus() {
  lcd.clear();
  lcd.setCursor(0,0);
  String message = "LAST: ";
  message = message + kmsSinceDpf + "KM";
  Serial.println(message);
  lcd.print(message);
  lcd.setCursor(0,1);
  message = "FILL: ";
  message = message + dirtLevel + "%";
  lcd.print(message);
}

void printRegenerating(int32_t regenStatus) {
  int32_t percentRegenerated = map(regenStatus, 0, 255, 0, 100);
  String statusMessage = "      ";
  statusMessage = statusMessage + percentRegenerated + "%      ";
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("!!REGENERATING!!");
  lcd.setCursor(0,1);
  lcd.print(statusMessage);
  lcd.noBacklight();
  delay(200);
  lcd.backlight();
  delay(200);
}

With sketch above the answer for LCD is always 0.
Answer visible in Serial Monitor of Arduino IDE and it doesn't matter engine is running or not.
https://www.dropbox.com/s/djp31qyjkiw51df/silnik%20zgaszony%20i%20odpalony.jpg?dl=0

20:54:41.253 -> AT SH 7E0 - SUCCESS!!!
20:54:42.334 -> Payload received for soot: SEARCHING...7F2222
20:54:50.129 -> Payload received for soot: 7F2222
20:54:42.334 -> Payload received for soot: SEARCHING...7F2222
20:54:42.334 -> RegenStat: 0
20:54:42.674 -> Payload received for soot: 7F2222
20:54:42.674 -> Km since DPF: 0
20:54:43.002 -> Payload received for dirtLevel: 7F2222
20:54:43.002 -> DPF dirt level: 0
20:54:45.024 -> LAST: 0KM

When I used code provided by you:

void loop()
{
  if(DEBUG_PORT.available())
  {
    char c = DEBUG_PORT.read();
    DEBUG_PORT.write(c);
    ELM_PORT.write(c);
  }
  if(ELM_PORT.available())
  {
    char c = ELM_PORT.read();
    if(c == '>')
      DEBUG_PORT.println();
    DEBUG_PORT.write(c);
  }
}

And sent request thru the serial monitor like below:

20:00:24.528 -> ATZ
ELM327 v2.2
>AT SH 7E0
OK
>223275
62 32 75 4E 

the recived value 4E converted to decimal gave me same result as DPF Monitor App.

I'm begginer at programing so if you could support me I will appriciate that.
Let me know if there is lack of needed information.

I have also tried code below

if (myELM327.queryPID("221E12"))
  {
    uint64_t temp = myELM327.findResponse();

    Serial.print("Raw Response: ");
    for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
      Serial.write(myELM327.payload[i]);
    Serial.println();

    if (myELM327.status == ELM_SUCCESS)
    {
      Serial.print("Parsed Response: "); Serial.println(temp);
    }
    else
    {
      Serial.print("ERROR: "); Serial.println(myELM327.status);
    }
  }

and I got result during verifiying of sketch same as Jastreb07

overloaded 'println(uint64_t&)' is ambiguous

So, i'm waiting your feedback.
Thank you in advance
KoYoT77

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

You can typecast temp into a normal int for printing in your case. Also, what exactly is going wrong in your case? Also, can you edit the lib files to print the exact command bytes sent to the ELM327 the next time you test?

from elmduino.

cyberelectronics avatar cyberelectronics commented on May 17, 2024

In my case (Hyundai Kona EV), when the car is turned OFF, the OBD adapter sends something like this (Rawdata, OBD protocol 6):
03E0:620101FFF7E7

But when it is ON, "7F2212" frames appears (random length, before or after the first actual dataframe 0:620101FFF7E7, where 0: is the indicator for DataFrame 0. Can send even 8 similar dataframes. Each dataframe contains 7bytes, except 0:, which contains only 6bytes).
7F22127F22127F22127F22127F221203E0:620101FFF7E71:FF8A00000000802:00000ED91814133:141713000011C2
Need to modify the 'payloadlen' value to 200 for 8 dataframes in elmduino.h :
bool begin(Stream& stream, char protocol='0', uint16_t payloadLen = 200);

So your actual data will be after this 7Fxxx bytes.

from elmduino.

KoYoT77 avatar KoYoT77 commented on May 17, 2024

You can typecast temp into a normal int for printing in your case. Also, what exactly is going wrong in your case? Also, can you edit the lib files to print the exact command bytes sent to the ELM327 the next time you test?

PowerBroker2
What is going wrong
In my case id doesn't matter what I asked:
myELM327.queryPID(34, 12916)
myELM327.queryPID(34, 12919)
myELM327.queryPID(34, 12917)
answer is all the time the same

Payload received for soot: 7F2222

change of uint64_t to int
still gave me same answer.
Same for engine running & not.

I suppose somewhere in my code there is a bug, but I'm really newbie in programming.
So if you be so kind please check it.

from elmduino.

KoYoT77 avatar KoYoT77 commented on May 17, 2024

In my case (Hyundai Kona EV), when the car is turned OFF, the OBD adapter sends something like this (Rawdata, OBD protocol 6):
03E0:620101FFF7E7

But when it is ON, "7F2212" frames appears (random length, before or after the first actual dataframe 0:620101FFF7E7, where 0: is the indicator for DataFrame 0. Can send even 8 similar dataframes. Each dataframe contains 7bytes, except 0:, which contains only 6bytes).
7F22127F22127F22127F22127F221203E0:620101FFF7E71:FF8A00000000802:00000ED91814133:141713000011C2
Need to modify the 'payloadlen' value to 200 for 8 dataframes in elmduino.h :
bool begin(Stream& stream, char protocol='0', uint16_t payloadLen = 200);

So your actual data will be after this 7Fxxx bytes.

I have tried what you suggest, Elmduino.h opened, I look for payloadLen in my lib its value is set to 40.
But there are two declaration of variables:
uint16_t PAYLOAD_LEN; called in my sketch for iteration
for (byte i = 0; i < myELM327.PAYLOAD_LEN; i++)
and
uint16_t payloadLen = 40 used in begin function of the lib.
But please be forgiving to the beginner if I said something stupid.
Regards

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

payloadLen is used by the begin() member function to set the value of PAYLOAD_LEN (or myELM327.PAYLOAD_LEN in the sketch). By default that value is 40, but you can change it to another value, i.e. 200.

from elmduino.

cyberelectronics avatar cyberelectronics commented on May 17, 2024

@KoYoT77 I think we have similar issues.
Your data is there, after 7F.... bytes, but probable the parser stops after a few bytes.
One of my friends sent me a parser, which worked great for ~15seconds :) , after this the ESP32 module crashed (picture attached at the end, where you can see where is the issue, but I don't know how to fix it and he is busy now).
Here is the code for parsing:

void clearData() {
  dataFrame0 = "";
  dataFrame1 = "";
  dataFrame2 = "";
  dataFrame3 = "";
  dataFrame4 = "";
  dataFrame5 = "";
  dataFrame6 = "";
  dataFrame7 = "";
  dataFrame8 = "";

}

char* appendCharToCharArray(char* array, char c) {
  int len = strlen(array);

  char ret[len + 2];

  strcpy(ret, array);
  ret[len] = c;
  ret[len + 1] = '\0';

  return strdup(ret);
}

void addToFrame(int frame, char c) {
  switch (frame) {
    case 0:
      dataFrame0 = appendCharToCharArray(dataFrame0, c);
      break;
    case 1:
      dataFrame1 = appendCharToCharArray(dataFrame1, c);
      break;
    case 2:
      dataFrame2 = appendCharToCharArray(dataFrame2, c);
      break;
    case 3:
      dataFrame3 = appendCharToCharArray(dataFrame3, c);
      break;
    case 4:
      dataFrame4 = appendCharToCharArray(dataFrame4, c);
      break;
    case 5:
      dataFrame5 = appendCharToCharArray(dataFrame5, c);
      break;
    case 6:
      dataFrame6 = appendCharToCharArray(dataFrame6, c);
      break;
    case 7:
      dataFrame7 = appendCharToCharArray(dataFrame7, c);
      break;
    case 8:
      dataFrame8 = appendCharToCharArray(dataFrame8, c);
      break;
  }
}


// get substring between m and n (excluding n)
char* substr(const char *src, int m, int n) {
  n += 1;
  int len = n - m;

  char *dest = (char*)malloc(sizeof(char) * (len + 1));

  for (int i = m; i < n && (*(src + i) != '\0'); i++)
  {
    *dest = *(src + i);
    dest++;
  }

  *dest = '\0';

  return dest - len;
}

void parse(char *raw) {
  int frame = -1;

  int len = strlen(raw);

  for (int i = 0; i < len; i++) {

    if (raw[i + 1] == ':') { //start frame
      frame = (int) raw[i] - '0';
      continue;
    }

    if (raw[i] == ':') {
      continue;
    }

    if (frame == -1) {
      continue;
    }

    if (raw[i] == '>') {
      frame = -1;
      continue;
    }

    addToFrame(frame, raw[i]);
  }

}

int convertToInt(char *hexStr) {
  return (int)strtol(hexStr, NULL, 16);

}

And here is how to use it in the loop(), with some delay/timer (in my case, this will return/print battery voltage):

myELM327.sendCommand("AT SH 7E4");      // Set Header BMS (Battery Management System)

if (myELM327.queryPID("220101")) {      // BMS PID
  read_rawdata();

  BATTv = ((convertToInt(substr(dataFrame2, 4, 5)) << 8) + convertToInt(substr(dataFrame2, 6, 7))) / 10;
  DEBUG_PORT.print("Main Battery Voltage (V): ");
  DEBUG_PORT.println(BATTv);
  clearData();
}

Read_rawdata function looks like this (will print the rawdata coming from OBD, then will parse it):

void read_rawdata() {
  // move data from OBD to Rawdata array
  char rawData[myELM327.recBytes];
  int n = 0;

  DEBUG_PORT.print("Payload received: ");

  for (int i = 0; i < myELM327.recBytes; i++) {
    rawData[n++] = myELM327.payload[i];
    DEBUG_PORT.print(myELM327.payload[i]);
  }
  DEBUG_PORT.println();

  parse(rawData);  // parse data received from OBD
}

Rawdata from OBD:
Payload received: 7F22127F22127F22127F22127F221203E0:620101FFF7E71:FF8A00000000832:00240ED71713133:141713000010C14:22C12800008B005:00450B0000434B6:000019A80000187:1200200EE70D018:7B0000000003E8

Parse(rawData), will look for dataframes, which begins with 0: 1: 2: 3: etc... then I can select any byte in any dataframe:
Ex.:
Dataframe2 >>>>>>>>>>> 2:00240ED7171313

convertToInt(substr(dataFrame2, 4, 5)) >>>> will return a single byte on location 4 and 5 (from 0) in dataframe 2.
convertToInt(substr(dataFrame2, 6, 7)) >>>> will return a single byte on location 6 and 7 (from 0) in dataframe 2.

Result >>>
0E =14;
D7 = 215;
Formula for Battery voltage = (14 * 256 + 215) / 10.0 = 379.9V

Now the problem is the parser will crash (possible memory leak) after 10-15seconds, until the crash, the parser works great.

Maybe @PowerBroker2 can help both of us, with this parser :) .
As I know we should not use malloc() at all (or use it with free() ).

exception

from elmduino.

PowerBroker2 avatar PowerBroker2 commented on May 17, 2024

This is dope! I'll take a closer look later and see if/how I can incorporate it.

However, @cyberelectronics, feel free to fork and PR if you want to do it yourself. Either way, thanks!

from elmduino.

cyberelectronics avatar cyberelectronics commented on May 17, 2024

Thanks, but I don't know how to use github :D .
Also if you can, please add/modify the code for other cases, where the dataframe delimiters are missing (no 0: , when all datas are in a single frame package) like in @KoYoT77 example.
Ex. PID >223275
Response: 62 32 75 4E
Skip any 7F... bytes at the beginning sent by OBD adapter, and Search/Compare for the first byte of PID 22hex + 40hex = 623275hex >>> 4E..... hex data bytes (dataframe).

from elmduino.

nices0325 avatar nices0325 commented on May 17, 2024

what should I do I wanna use service22 and service01 both?
should I set header to 7E4 to get bms system data and set filter off to get data from service01 and set header to 7E4 again in loop??

from elmduino.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.