Page 1 of 2 12 LastLast
Results 1 to 10 of 18

Thread: C# Application using OBDPro scantool

  1. #1
    Newbie OrangeSword's Avatar
    Join Date
    May 2007
    Location
    Las Vegas, NV
    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);
          }     
          
        }

  2. #2
    Newbie OrangeSword's Avatar
    Join Date
    May 2007
    Location
    Las Vegas, NV
    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.

  3. #3
    VENDOR - OBDPros
    Join Date
    Mar 2006
    Posts
    359
    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

  4. #4
    Newbie OrangeSword's Avatar
    Join Date
    May 2007
    Location
    Las Vegas, NV
    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.

  5. #5
    VENDOR - OBDPros
    Join Date
    Mar 2006
    Posts
    359
    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

  6. #6
    Newbie OrangeSword's Avatar
    Join Date
    May 2007
    Location
    Las Vegas, NV
    Posts
    20
    Thanks. I appreciate it. One other question, is the "NO DATA" and "?" results terminated by a carriage return?

  7. #7
    Newbie
    Join Date
    Aug 2005
    Location
    Ohio
    Posts
    12
    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 View Post
    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.
    2006 Nissan Maxima SE
    2002 GMC Envoy SLT
    Digital Deviation

  8. #8
    Newbie
    Join Date
    Jun 2007
    Posts
    2
    hi have you finished this yet

  9. #9
    Newbie OrangeSword's Avatar
    Join Date
    May 2007
    Location
    Las Vegas, NV
    Posts
    20
    Quote Originally Posted by aslaughter View Post
    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");
        }
      }
    }

  10. #10
    Newbie impala454's Avatar
    Join Date
    Aug 2007
    Location
    Houston, TX
    Posts
    34
    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.

Page 1 of 2 12 LastLast

Similar Threads

  1. Replies: 0
    Last Post: 09-23-2006, 08:38 PM
  2. Notifying child application of Hibernation wakeup
    By mullaly in forum Road Runner
    Replies: 2
    Last Post: 04-24-2006, 03:44 AM
  3. How to embbed any Application in RR ?
    By guino in forum RR FAQ
    Replies: 0
    Last Post: 03-20-2005, 12:35 PM
  4. Beta-Testing External Application Code
    By CarComp in forum Media Engine
    Replies: 2
    Last Post: 02-17-2005, 10:42 PM
  5. embedded GPS application problem
    By Bokky in forum Centrafuse
    Replies: 4
    Last Post: 01-23-2005, 12:44 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •