views:

60

answers:

3

I am pretty new to serial comms, but would like advise on how to best achieve a robust application which speak to and listens to a serial device.

I have managed to make use of System.IO.SerialPort, and successfully connected to, sent data to and recieved from my device. The way things work is this.

My application connects to the Com Port and opens the port.... I then connect my device to the com port, and it detects a connection to the PC, so sends a bit of text. it's really just copyright info, as well as the version of the firmware. I don't do anything with that, except display it in my 'activity' window.

The device then waits.

I can then query information, but sending a command such as 'QUERY PARAMETER1'. It then replies with something like:

'QUERY PARAMETER1\r\n\r\n76767\r\n\r\n'

I then process that. I can then update it by sending 'SET PARAMETER1 12345', and it will reply with 'QUERY PARAMETER1\r\n\r\n12345\r\n\r\n'.

All pretty basic.

So, what I have done is created a Communication Class. this call is called in it's own thread, and sends data back to the main form... and also allows me to send messages to it.

Sending data is easy. Recieving is a bit more tricky. I have employed the use of the datarecieved event, and when ever data comes in, I echo that to my screen. My problem is this:

When I send a command, I feel I am being very dodgy in my handling. What I am doing is, lets say I am sending 'QUERY PARAMETER1'. I send the command to the device, I then put 'PARAMETER1' into a global variable, and I do a Thread.Sleep(100).

On the data received, I then have a bit of logic that checks the incoming data, and sees if the string CONTAINS the value in the global variable. As the reply may be 'QUERY PARAMETER1\r\n\r\n76767\r\n\r\n', it sees that it contains my parameter, parses the string, and returns the value I am looking for, but placing it into another global variable.

My sending method was sleeping for 100ms. It then wakes, and checks the returned global variable. If it has data... then I'm happy, and I process the data. Problem is... if the sleep is too short.. it will fail. And I feel it's flaky.. putting stuff into variables.. then waiting...

The other option is to use ReadLine instead, but that's very blocking. So I remove the data received method, and instead... just send the data... then call ReadLine(). That may give me better results. There's no time, except when we connect initially, that data comes from the device, without me requesting it. So, maybe ReadLine will be simpler and safer? Is this known as 'Blocking' reads? Also, can I set a timeout?

Hopefully someone can guide me.

A: 

If you do all of your reads on a background thread, then I don't see any problem with using ReadLine. It's the simplest and most robust solution.

You can use the ReadTimeout property to set the timeout for read operations.

Dean Harding
+1  A: 

Well, Thread.Sleep() is blocking too. Much worse, actually, because you'd have to specify a sleep time that is always safe, even if the machine is under heavy load. Using ReadLine() is always better, it will be quicker and it cannot fail.

Note that your example doesn't require the client code to wait for a response. It can simply assume that the command was effective. All you need is an Error event to signal that something went wrong.

If there is a command that requires the client code to get the response that you should offer the option to wait as well as get the result asynchronously. That gives the client code options: waiting is slow but easy, async is difficult to program. It is a very common pattern in the .NET framework, the asynchronous method name starts with "Begin". Check the MSDN Library article about it.

You also should consider delivering asynchronous notifications on the thread that the client code prefers. The SynchronizingObject property is a good pattern for that.

Hans Passant
A: 

You may want to read this Serial Port

dbasnett