16

I am reading data from serial port. The data comes off the scale. I am now using Readline() and getting data dropped even after I removed DiscardInBuffer().

What is the proper way to read the data from the serial port? There are so few examples online that I feel it's like some holy grail that no one has figured out.

C#, WinCE 5.0, HP thin client, Compact framework 2.0

 private void WeighSample()
    {
        this._processingDone = false;
        this._workerThread = new Thread(CaptureWeight);
        this._workerThread.IsBackground = true;
        this._workerThread.Start();
    } //end of WeighSample()


    private void CaptureWeight()
    {
         globalCounter++;
         string value = "";


          while (!this._processingDone)
          {
              try
              {

                 value = this._sp.ReadLine();

                  if (value != "")
                  {
                      if (value == "ES")
                      {
                          _sp.DiscardInBuffer();
                          value = "";
                      }
                      else
                      {
                          this.Invoke(this.OnDataAcquiredEvent, new object[] { value });
                      }
                  }
              }
              catch (TimeoutException)
              {
                  //catch it but do nothing
              }
              catch
              {
                  //reset the port here?
                  MessageBox.Show("some other than timeout exception thrown while reading serial port");
              }
          }


    } //end of CaptureWeight()

One thing to note about my application is that I start the thread (weighSample) when the cursor jumps onto the textbox. The reason to this is that the weight can also be typed in manually (part of the requirements). So I don't know in advance whether a user is going to press PRINT on the balance or type the weight. In either case after the data is acquired, I exit the worker thread. Also, note that I am not using serial port event DataReceived, since I have been told it's not reliable.

This is my first experience with serial ports.

halfer
  • 19,824
  • 17
  • 99
  • 186
sarsnake
  • 26,667
  • 58
  • 180
  • 286

4 Answers4

12

Depends on what the end-of-line (EOL) character(s) is for your input data. If your data is line oriented then ReadLine is a valid function to use, but you may want to look at the NewLine property and be sure that it is set appropriately for your input data.

For example, if your scale outputs linefeed for EOL then set port.NewLine = "\n";

http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.newline.aspx

joshperry
  • 41,167
  • 16
  • 88
  • 103
  • so does that depend on the device configuration? – sarsnake Mar 11 '09 at 23:57
  • I am reading the data from the scale. Does this value (Newline) have to correspond the scale format in this case? I am now settings it to \r\n which is the standard. – sarsnake Mar 12 '09 at 00:01
  • Thanks a lot. I use the .NewLine set to "\r" because the scanner are sending me that at final and with the .ReadLine() I get exactly what I'm expecting. Excellent solution. – JD - DC TECH Apr 28 '16 at 04:56
  • I was having trouble with ReadLine until I read this answer. I just set port.NewLine to what my printer was sending as EOL (coincidentally "\n") and it worked! Thanks! – João Victor Oliveira Sep 13 '17 at 19:07
8

I have never had luck with ReadLine working. Just do a Read into a local buffer whenever data is available and then use a separate thread to scan the data and find line breaks yourself.

ctacke
  • 66,480
  • 18
  • 94
  • 155
  • quick question - i have polling the scale already running in existing thread. Do I still need a separate thread to scan the data? will post the code when I get to work. – sarsnake Mar 12 '09 at 14:50
  • Generally I fire up a worker thread that does the port reads and puts them in an app buffer. When it puts data into the buffer, it sets an event that signals the parser thread to go an look for data lines and then raise yet another event to the consuming app. You may already have one of these. – ctacke Mar 12 '09 at 17:44
  • so in total you have 2 threads: one main thread and one worker thread? What's the difference between blocking and non-blocking behaviour? Is Read() blocking? – sarsnake Mar 12 '09 at 17:57
  • Yes, I generally have 2 threads. Maybe 3 depening on the exact use case, but the workers are usually in a wait state using very little processor. I would assume Read is blocking and the return is based on the driver CommTimeouts (that's how I implemented it in the OpenNETCF serial library anyway). – ctacke Mar 12 '09 at 18:16
  • 2
    I have read that Read is non-blocking - I am confused , it seems no one really explains HOW it works really. Is it safe to do this: _sp.Read(buffer, 0, _sp.BytesToRead); and buffer is char[] Thanks! i feel overwhelmed by the lack of info about serial ports. – sarsnake Mar 12 '09 at 18:35
  • I can't see how it could be non blocking. When you call Read, it has to return data, so it must block until it either fetches data from the serial driver (or the serial driver times out). Under the hood it's calling the ReadFile API, though it's possible that it has an internal thread that does it – ctacke Mar 12 '09 at 20:47
  • If you want to know exactly what is happening, I'd recommend you look at the OpenNETCF serial library. It's interface compatible with the CF library and that way you can step through the code all the way to the driver call if you want. – ctacke Mar 12 '09 at 20:48
  • do you happen to have any Read working examples? I am afraid I don't have a whole lot of time to step through the library code. I am actually using MS SerialPort not OpenNetCF. All the info I know is from msdn, which can be cryptic. – sarsnake Mar 12 '09 at 22:18
  • @gnomixa, ever get an example? or do you have your own demo project with this working now I could take a look at ? – GONeale May 21 '09 at 04:31
  • Did you ever post this to your blog and could you provide the url? I'm also trying to properly work with the SerialPort class, using a buffer in my serialport wrapper. – Jeff LaFay Aug 17 '11 at 17:11
1
if (serialPort1->IsOpen){
    if (serialPort1->BytesToRead>0){
        this->textBox1->Text += serialPort1->ReadExisting();
    }
}
  • 3
    Please elaborate why you think this code-only answer helps solving the question. – PMF Jul 17 '15 at 14:21
1

I am adding an answer to respond to Elias Santos. There are some gotchas in using the ReadExisting method:

https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readexisting(v=vs.110).aspx

Note that this method can leave trailing lead bytes in the internal buffer, which makes the BytesToRead value greater than zero.

I faced some issues with ReadExisting before and this is because of the unwanted bytes. Using Readline fixed those issues.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • 1
    Note that it's fine to add another answer disputing another as long as you give another suggestion and format it as an answer, which you have done. – AStopher Jun 28 '16 at 09:24