Wait for response from the Serial Port and then send next data

What you need is a way to block the execution of some code, until something else has happened, or – how to get things running on two threads synchronously.
.NET has quite a few classes in the System.Threading namespace for synchronization. We’ll use AutoResetEvent here.

Think of AutoResetEvent as a turnstile.

turnstile

You can’t move forward if the the person on the other side stops.
When you move forward, you call Wait – and it blocks you from moving,
until someone calls Set on it.

Now if we apply that to our problem:
We need to stop sending data until we get an acceptable response.
So call Wait when sending data, and let the response handling code call Set to let it move forward.

Here’s an example which simulates a modem.
You send some AT commands, it responds, but the responses always end with \r\n.

var port = new SerialPort("COM2");
port.Open();

var mre = new AutoResetEvent(false);
var buffer = new StringBuilder();

port.DataReceived += (s, e) =>
{
    buffer.Append(port.ReadExisting());
    if (buffer.ToString().IndexOf("\r\n") >= 0)
    {
        Console.WriteLine("Got response: {0}", buffer);

        mre.Set(); //allow loop to continue
        buffer.Clear();
    }
};


var commandsToSend = new string[] { "AT", "AT", "AT+CSQ" };
var responseTimeout = TimeSpan.FromSeconds(10);

foreach (var command in commandsToSend)
{
    try
    {
        Console.WriteLine("Write '{0}' to {1}", command, port.PortName);
        port.WriteLine(command);

        Console.WriteLine("Waiting for response...");

        //this is where we block
        if (!mre.WaitOne(responseTimeout))
        {
            Console.WriteLine("Did not receive response");
            //do something
        }
    }
    catch (TimeoutException)
    {
        Console.WriteLine("Write took longer than expected");
    }
    catch
    {
        Console.WriteLine("Failed to write to port");
    }
}

Console.ReadLine();

Sample output when tested through virtual serial port:
(I just reply with OK<CR><LF>)

Write 'AT' to COM2
Waiting for response...
Got response: OK

Write 'AT' to COM2
Waiting for response...
Got response: OK

Write 'AT+CSQ' to COM2
Waiting for response...
Did not receive response

Leave a Comment