1

Do we have in .NET 4.0 the opportunity to wait for a response and then to return the response?

Currently I'm doing it like this but it isn't really nice and I don't like it:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        byte[] options = new byte[]{1,1,0};
        COMManager mgr = new COMManager("COM1");

        byte[] result = mgr.GetResponse(options);
    }
}

And my COM Manager Class (I have to do the operation in a seperate class (dll)):

public class COMManager
    {
        SerialPort sp = null;
        byte[] result = null;
        bool completed = false;

        public COMManager(string comport)
        {
            sp = new SerialPort(comport);
            sp.DataReceived +=new SerialDataReceivedEventHandler(sp_DataReceived);
        }

        public byte[] GetResponse(byte[] option)
        {
            sp.Write(option, 0, option.Length);
            //I don't like the way...
            while (!completed) { }
            completed = false;
            return result;
        }

        void  sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            result = new byte[sp.BytesToRead];
            sp.Read(result, 0, sp.BytesToRead);
            completed = true;
        }
    }

In .NET 4.5 we may have the opportunity to use the "await" statement. But for the current project we only are allowed to use .NET 4.0. Any ideas?

user1011394
  • 1,656
  • 6
  • 28
  • 41

3 Answers3

4

There's no point in using the DataReceived event if you don't want to read asynchronously. Simply call the Read() method directly in GetResponse().

Beware that you cannot assume you will get a complete response, you cannot ignore the return value of Read(). It usually returns a couple of bytes only, serial ports are pretty slow. So be sure to keep calling Read() until you got the entire response.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Hi Hans Passant, it is an asynchronously call. First I have to write bytes (send it to the device) and second, the device will interpret it and send me an individual response. – user1011394 Aug 02 '12 at 16:59
2

The clean way would be to wait on an AutoResetEvent and for for the receive callback to signal it.

By creating a wrapper with this method, you can effectivly await in every version of .Net.

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
2

For your original question, to block the executing thread you can use a ManualResetEvent or AutoResetEvent which will get Set when your response has been obtained. There's a fairly good explanation on the page.

For threading, the rule of thumb is that if you're not extremely clear on what you're doing, don't do it.

Synchronous blocking when you have access to events seems like a waste. Considering that the data is a stream, this might end up being a hard to maintain abstraction.

There's a longer explanation of the above idea with an example over here.

You can also do this in async with TaskCompletionSource. Instead of set, you can call SetResult, and you await the .Task, but the idea is pretty much the same.

Asti
  • 12,447
  • 29
  • 38
  • Hi Asti. Thanks for your reply. I never used ManualResetEvents before. So i add"private static ManualResetEvent mre = new ManualResetEvent(false);" to my COMManager class and "mre.Reset()" will replace my while loop. And on dp_DataReceived instead of completed = true i set mre.Set() right? – user1011394 Aug 02 '12 at 16:55
  • @user1011394 Yes, basically. Don't declare it as static though. – Asti Aug 02 '12 at 17:08
  • You can also use AutoResetEvent which gets automatically reset after you set it, so you won't have to called Reset if you so desire. – Asti Aug 02 '12 at 17:10
  • @Asti can you help in this:https://stackoverflow.com/questions/55026042/wait-for-response-from-the-serial-port-and-then-send-next-data – Prashant Pimpale Mar 11 '19 at 07:27
  • 1
    @PrashantPimpale oops, just saw your message now. Wrote you an answer. – Asti Mar 14 '19 at 06:27