Welcome to the MP3Car.com forums.
You are currently viewing our boards as a guest which gives you limited access to view most discussions and access our other features. Registering will also remove advertisements. By joining our free community you will have access to post topics, communicate privately with other members (PM), respond to polls, upload content and access many other special features. Registration is fast, simple and absolutely free so please, join our community today!
If you have any problems with the registration process or your account login, please contact contact us.
|
05-30-2007, 07:06 PM
|
#1
|
|
Newbie
Join Date: May 2007
Location: Las Vegas, NV
Vehicle: 2000 Nissan Frontier Crew Cab
Posts: 20
|
C# Application using OBDPro scantool
I've written a c# app that reads data from my cars OBD port using the OBDPro scantool. My program loops through my "Command" objects and sends commands to a serial port connection object. I'm only sending 4 commands on each loop; Speed, RPM, CoolantTemp and Throttle position. After all four have been sent the application sleeps for 1 seconds and resumes the loop. Meanwhile I have an event listener on the Serial Port object that fires anytime data appears on the serial ports buffer. When it does I read all the characters until I find a carriage return and convert that hex string to a readable integer value and update my windows form. However whenever I send 4 or more commands on each iteration I often get "NO DATA" or ? from the cars OBD port for at least one of the commands. Before talk to the OBD port I first send ate0 and atl0 to suppress echoes and linefeeds. The baud rate is also @ 128000. ScanTool.net doesn't seem to behave this way. Can anyone give some pointers on how to make the responses more reliable? Here are a few snippets of my code:
My control loop:
Code:
private void BeginControlLoopThread()
{
while (true)
{
foreach (OBDCommand obdCommand in mOBDCommandRepository.OBDCommands)
{
mSerialPort.WriteLine(obdCommand.Mode + " " + obdCommand.PID);
mMainWindow.WriteToInputLogDisplay(obdCommand.Mode + " " + obdCommand.PID);
}
Thread.Sleep(1000);
}
}
My event listener:
Code:
private void SerialPort_DataReceived(object sender, EventArgs e)
{
string response = "";
try
{
response = mSerialPort.ReadTo("\r>");
}
catch (Exception exception)
{
// do nothing, exit
// exception.Message.ToString();
return;
}
response = response.Trim();
mMainWindow.WriteToOutputLogDisplay(response);
if (response.StartsWith("4"))
{
string[] translatedResponse = mOBDCommandRepository.TranslateResponse(response);
SendToUI(translatedResponse);
}
}
|
|
|
05-30-2007, 07:13 PM
|
#2
|
|
Newbie
Join Date: May 2007
Location: Las Vegas, NV
Vehicle: 2000 Nissan Frontier Crew Cab
Posts: 20
|
If an admin thinks this is better suited in the Software Development, please move it there. I didn't see an dedicated OBD section over there and I wanted to make sure the people using OBDPro see this.
|
|
|
05-31-2007, 06:55 AM
|
#3
|
|
Variable Bitrate
Join Date: Mar 2006
Posts: 262
|
OrangeSword,
In your control loop thread you should wait for the ">" prompt before sending another command. The OBDPro can buffer serial data while executing a previous OBD Command but ocasionally it will not be able to keep up with buffering serial data and processing the OBD command at the same time.
One way to do this is create a boolean promptSeen. Set this to true when you read a ">" on the serial port handler, and only send a new OBD command when promptSeen == TRUE
hth
Paul
www.obdpros.com
|
|
|
05-31-2007, 11:13 AM
|
#4
|
|
Newbie
Join Date: May 2007
Location: Las Vegas, NV
Vehicle: 2000 Nissan Frontier Crew Cab
Posts: 20
|
I am not getting a "Buffer Full" message back so I don't think the buffer is full.
But anyway following your advice, I've changed the code to this:
Code:
private void BeginControlLoopThread()
{
bool promptFound; ;
bool responseEndFound;
string response;
while (true)
{
foreach (OBDCommand obdCommand in mOBDCommandRepository.OBDCommands)
{
response = "";
promptFound = false;
while (!promptFound)
{
try
{
mSerialPort.ReadTo(">");
mSerialPort.WriteLine(obdCommand.Mode + " " + obdCommand.PID);
mMainWindow.WriteToInputLogDisplay(obdCommand.Mode + " " + obdCommand.PID);
promptFound = true;
}
catch (Exception e)
{
// Prompt was not found, do nothing
}
}
responseEndFound = false;
while (!responseEndFound)
{
try
{
response = mSerialPort.ReadTo("\r");
response = response.Trim();
mMainWindow.WriteToOutputLogDisplay(response);
if (response.StartsWith("4"))
{
string[] translatedResponse = mOBDCommandRepository.TranslateResponse(response);
SendToUI(translatedResponse);
}
responseEndFound = true;
}
catch (Exception e)
{
// Command not finished was not found, do nothing
}
}
}
Thread.Sleep(1000);
}
Potentially I will have a large number of responses to loop through and it might take awhile to finish the loop if I have to wait for every response. Is there a way to get multiple responses back at one time? Like ALL of the data in Mode 01? Am I doing it the most efficient way, is what I am trying to get at.
Last edited by OrangeSword : 05-31-2007 at 11:14 AM.
Reason: typo
|
|
|
05-31-2007, 07:02 PM
|
#5
|
|
Variable Bitrate
Join Date: Mar 2006
Posts: 262
|
Sorry I should have made it a bit more clear....
It's not the OBD buffer that is full, but when getting data from the vehicle bus there are times when the interface needs to shut off processing the serial port interrupts, this means some characters would be dropped...
The ">" char signals the PC that the OBDPro is done executing the command and is now ready to accept additional commands. To make sure you can issue the command immediately when the interface is ready one way would be to send the data right out of the serial data recieved handler. Let me find the code that I use to test the interface and I can send you something as an example...
Paul
www.obdpros.com
|
|
|
05-31-2007, 11:58 PM
|
#6
|
|
Newbie
Join Date: May 2007
Location: Las Vegas, NV
Vehicle: 2000 Nissan Frontier Crew Cab
Posts: 20
|
Thanks. I appreciate it. One other question, is the "NO DATA" and "?" results terminated by a carriage return?
|
|
|
06-19-2007, 09:29 PM
|
#7
|
|
Newbie
Join Date: Aug 2005
Location: Ohio
Vehicle: 2005 Mazda 6s
Posts: 11
|
Keep in mind that if you are reading up to the prompt, you will not be able to use this when looking at streaming data (such as the ATMA mode) since it does not produce a prompt after each line. Using the ReadLine method and keeping line breaks on (ATL1) will solve this. You can always trim the prompt off the front of the response line.
Also, for those looking to use VB.NET you will need to use the Write method and append a carriage return to the command. The WriteLine method does not work with this in VB.NET.
I'll be posting a demo app on obdpros.com forums in a day or so. Just something basic to help beginners get started. My nick on obdpros.com is Deviation....
Quote: Originally Posted by OrangeSword 
Thanks. I appreciate it. One other question, is the "NO DATA" and "?" results terminated by a carriage return?
Yes. If you leave line breaks on.
|
|
|
06-25-2007, 07:41 AM
|
#8
|
|
Newbie
Join Date: Jun 2007
Posts: 1
|
hi have you finished this yet
|
|
|
06-25-2007, 07:02 PM
|
#9
|
|
Newbie
Join Date: May 2007
Location: Las Vegas, NV
Vehicle: 2000 Nissan Frontier Crew Cab
Posts: 20
|
Quote: Originally Posted by aslaughter 
hi have you finished this yet
No not yet. I'm not really building it for distribution, but here is the code I have so far if you are interested in that:
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO.Ports;
using System.Configuration;
namespace OrangeSword.FrontierDash.ObdReader.BusinessLogic
{
/// <summary>
/// Represents a OBD device such as a OBDPro.
/// </summary>
public class ObdDevice
{
private string portName;
private int baudRate;
private SerialPort serialPort;
/// <summary>
/// Initializes a new instance of the <see cref="ObdDevice"/> class.
/// </summary>
public ObdDevice()
{
portName = ConfigurationManager.AppSettings["portName"];
baudRate = Convert.ToInt32(ConfigurationManager.AppSettings["baudRate"]);
Connect();
}
/// <summary>
/// Connects this instance.
/// </summary>
private void Connect()
{
serialPort = new SerialPort(portName, baudRate);
serialPort.Open();
serialPort.ReadTimeout = 1000;
serialPort.NewLine = "\r";
}
/// <summary>
/// Disconnects this instance.
/// </summary>
private void Disconnect()
{
serialPort.Close();
}
/// <summary>
/// Initializes this instance.
/// </summary>
public void Initialize()
{
Reset();
SendAtCommand("ate0");
SendAtCommand("atl0");
}
/// <summary>
/// Sends the obd command.
/// </summary>
/// <param name="obdCommand">The obd command.</param>
/// <returns>The response to the OBD command from the OBD device.</returns>
public string SendObdCommand(ObdCommand obdCommand)
{
string response = "";
bool promptFound = false;
bool responseEndFound = false;
while (!promptFound)
{
try
{
serialPort.ReadTo(">");
serialPort.WriteLine(obdCommand.Mode + " " + obdCommand.PID);
promptFound = true;
}
catch (Exception e)
{
// Prompt was not found
Console.WriteLine("Prompt not found: " + e.Message);
}
}
while (!responseEndFound)
{
try
{
response = serialPort.ReadTo("\r");
response = response.Trim();
if (response.StartsWith("4"))
{
responseEndFound = true;
}
}
catch (Exception e)
{
// Carriage Return not found
Console.WriteLine("Carriage Return not found: " + e.Message);
if (response == "NO DATA")
{
responseEndFound = true;
}
}
}
return response;
}
/// <summary>
/// Sends the AT command.
/// </summary>
/// <param name="atCommand">The AT command.</param>
/// <returns></returns>
public string SendAtCommand(string atCommand)
{
string response = "";
bool promptFound = false;
bool responseEndFound = false;
while (!promptFound)
{
try
{
serialPort.ReadTo(">");
serialPort.WriteLine(atCommand);
promptFound = true;
}
catch (Exception e)
{
// Prompt was not found
Console.WriteLine("Prompt not Found: " + e.Message);
}
}
while (!responseEndFound)
{
try
{
response = serialPort.ReadTo("\r");
response = response.Trim();
responseEndFound = true;
}
catch (Exception e)
{
// Carriage Return not found
Console.WriteLine("Carriage Return not found: " + e.Message);
}
}
return response;
}
/// <summary>
/// Resets this instance.
/// </summary>
public void Reset()
{
serialPort.WriteLine("atz");
}
}
}
|
|
|
08-02-2007, 02:34 PM
|
#10
|
|
Newbie
Join Date: Aug 2007
Location: Houston, TX
Vehicle: 2006 Chevrolet Silverado
Posts: 35
|
Hey guys, new here but been lurking a few weeks. I am about to start a project as well in C#.net, and Orange I think that code is a great start, I had no idea that there's a ports namespace (just looked it up and it looks like it's new to framework 2.0+). upon just a quick msdn read, it looks like the SerialPort class has event handler delegates, so that would seem to be your best bet, rather than waiting for a certain response, you could just use the SerialDataReceivedEventHanlder delegate to invoke a callback function. I'm going to start messing around with this tonight so if I make any progress I'll be sure and post it up here.
|
|
|
08-02-2007, 06:24 PM
|
#11
|
|
Variable Bitrate
Join Date: Mar 2006
Posts: 262
|
Impala,
You have the right approach with the event based setup, I had mentioned to orange that I would throw up some code that I use to test with but it is in such lousy shape that I am afraid to share and just have not had time to clean up.
Since there seems to be some interest I will plan on cleaning it up and posting it if that helps someone
Thanks
Paul
www.obdpros.com
|
|
|
08-02-2007, 09:38 PM
|
#12
|
|
Newbie
Join Date: Aug 2007
Location: Houston, TX
Vehicle: 2006 Chevrolet Silverado
Posts: 35
|
Well it's definitely more fun to look at dirty code than no code
here's a quick file I put together, doesn't quite work but you get the idea. I just got my feet wet with this tonight so hopefully I'll get the hang of it after a while.
Code:
using System;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.IO;
namespace TestObdScanner
{
public class ObdDevice
{
private string PortName;
private int BaudRate;
private int ReadTimeOut;
private SerialPort Port;
public ObdDevice(string portName, int baudRate)
{
PortName = portName;
BaudRate = baudRate;
ReadTimeOut = 1000;
Port = new SerialPort(PortName, BaudRate);
}
public ObdDevice(string portName, int baudRate, int readTimeOut)
{
PortName = portName;
BaudRate = baudRate;
ReadTimeOut = readTimeOut;
Port = new SerialPort(PortName, BaudRate);
}
public bool Connect()
{
if (Port != null)
{
try
{
Port.Open();
Port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived);
}
catch (Exception OpenExcep)
{
Console.WriteLine(OpenExcep.Message);
return false;
}
}
else
{
Console.WriteLine("Error: Tried to connect with a null port");
}
return true;
}
public void TestAllPids()
{
int MaxDecimalPid = 78;
StringBuilder Command = new StringBuilder(6);
for (int i = 1; i <= MaxDecimalPid; i++)
{
Command.AppendFormat("01 {0}", i.ToString("X2"));
Console.WriteLine(Command.ToString());
WriteLogFile(Command.ToString());
Port.WriteLine(Command.ToString());
Thread.Sleep(ReadTimeOut);
Command.Remove(0, Command.Length);
}
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs args)
{
string RawData = Port.ReadExisting();
// Update some publicly accessible data structure to make this useful
Console.WriteLine(RawData);
WriteLogFile(RawData);
}
private void WriteLogFile(string message)
{
StreamWriter sw = new StreamWriter("log.txt", true);
sw.WriteLine(message);
sw.Close();
}
}
}
with the usage of the class like:
Code:
using System;
using TestObdScanner;
namespace ObdConsoleTest
{
class Program
{
static void Main(string[] args)
{
ObdDevice dev = new ObdDevice("COM1", 9600);
if (dev.Connect())
dev.TestAllPids();
}
}
}
the callback is happening, just not seeing the data I'm expecting to see, the log ends up repeating the command sent.
|
|
|
08-03-2007, 10:39 AM
|
#13
|
|
Newbie
Join Date: Aug 2007
Location: Houston, TX
Vehicle: 2006 Chevrolet Silverado
Posts: 35
|
hmm maybe an echo off command will prevent that and make it work... will have to try that when I get home.
|
|
|
08-05-2007, 02:42 AM
|
#14
|
|
Newbie
Join Date: Aug 2007
Posts: 1
|
Keep going
hey guys.. nice great coding  i wish you all the success.I'm a beginner and need some help.im trying to type my own code using a language called Tiger basic but i don't know how to initialize the ISO 9141 protocol if anyone can help me it would be great,my email is (m-samehsabry@peparab.com)
|
|
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 04:06 PM.
|
|