Vb.NET, waiting for a character to arrive in the serial port

Thread Starter

cmartinez

Joined Jan 17, 2007
8,220
I've been programming in .NET for years now, and already know how to use background workers and on_comm events when working with serial ports.

There is one thing, however, that I'm sure could be done far more efficiently and elegantly than the way I've been doing it up until now. And that is, wait for a character to arrive at the serial port.
To make a long story short, these are the couple of lines of code that I've been using to accomplish that.

'wait until the controller sends a character to the serial port
While SPort.BytesToRead < 1 : Threading.Thread.Sleep(300) : End While
xx = SPort.ReadByte()

Is there a better way to do this? I'm trying to avoid using the on_comm event for this purpose because doing so requires splitting the code in several segments.

This is what I do not want to do:
  • Set up and activate the on_comm event
  • Once the event is triggered, remove its handler to prevent it from triggering aditional events if more characters arrive
  • Perform several not so easy to understand Invoke instructions from within the event handler so as to execute a procedure and change the state of the form's controls.
  • After this is done re-assign the event handler and exit the event handling routine.
  • Continue the program in a different routine

Doing all of that is not only cumbersome, but also makes the code hard to follow. My technique, however, uses more CPU resources and makes the program run slower and the computer feel jumpy and glitchy.

Is there a simpler, and more fluid way of doing this?
 
Last edited:

wayneh

Joined Sep 9, 2010
17,496
Short answer: I can't help you.

Longer answer: Maybe if I ramble for a minute you'll have an aha! moment.

I've been programming an iPhone app in Swift and Xcode (the IDE). One of the most mysterious functions I've had to learn is how to pause, delay and, wait, and work in parallel. For instance some of the things I'm working on require starting a web session and scraping a piece of information from a website. I need my code to wait patiently for the data to arrive and then handle things ASAP once it does. Thanks to Google and the kindness of strangers, I've had some success with this but pretty much just by brute force and dumb luck.

Probably the most useful technique I've learned is the Grand Central Dispatch. Rather than make you suffer a description from an idiot (me), I've found a fairly decent summary of the concept and how it works. Maybe if you skim it something will jump out, or you'll be able to see some parallel to your own dilemma.
 

hellifino

Joined Jul 2, 2015
19
I haven't messed with VB in awhile, but I can give you a few paths to search down.

Typically there are 2 flavors of I/O reading: blocking and non-blocking. By using BytesToRead(), you're creating your own non-blocking read. I believe the default for most .NET read functions is blocking. The main issue with your loop is that you are always waiting 300ms for the next check. Of course this is trivial in user-related I/O but still.. Anyway you use blocking I/O calls when you want immediate interrupts and you're not doing any buffering etc.

The proper way is to let the OS handle the interrupt for you (unless you want to write that yourself). Something similar to:
while (SPort.Read(&buffer...) == 0){ } // note that read(...) should be blocking execution

Or idk if this works:
short data = -1
do{
try{
data = SPort.ReadByte()
} catch (...) {} // do nothing with the exception
} while (data < 0);


Looks like there's an msdn on this... looks pretty close. Using SerialPort.ReadLine()
https://msdn.microsoft.com/en-us/library/7ya7y41k.aspx


One last point I will mention - I'm not sure if there is a timeout on the serialport.read. There should be, but sometimes with .NET these can be ~30 seconds and is very annoying to wait for when you try to close things. If that's the case, I would dump your read/write into a dedicated thread and have the OS interrupt the thread when you want to break the timeout.
 

Thread Starter

cmartinez

Joined Jan 17, 2007
8,220
Stupid me... all one has to do to accomplish what I wanted is to set the commport.ReadTimeout property as 0 . That way the program will wait for an infinite amount of time before continuing until the expected character arrives. This setting, of course, could cause the program to hang up if the communications line has been severed somehow. So another option would be to set said property to a very high value, and then generate an error if a timeout occurs.
 
Last edited:

Picbuster

Joined Dec 2, 2013
1,047
I do not understand why you have to split up the program.
set RT threshold to 0ne.
On on_com place data or byte in array and set flag disable com input ( when needed).
main loop when flag do what you have to do and enable input.

Picbuster
 
Top