Send request, wait for response from the serial port

Markus Freitag 3,791 Reputation points
2024-02-15T19:58:16.6066667+00:00

Hello, It does almost everything as expected, how can I trigger a **timeout exception? **

I coming not inside the TimeoutException.

public void Test_Timeout()
{
	var port = new SerialPort("COM4");
	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)
		{
			Trace.WriteLine("Got response: {0}", buffer.ToString());

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


	var commandsToSend = new string[] { "AT1", "AT2", "AT3" };
	var responseTimeout = TimeSpan.FromSeconds(10);

	foreach (var command in commandsToSend)
	{
		try
		{
			Trace.WriteLine($"Write '{command}' to {port.PortName}");
			port.WriteLine(command);

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

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

Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. Pinaki Ghatak 5,600 Reputation points Microsoft Employee Volunteer Moderator
    2024-02-16T08:48:48.8633333+00:00

    Hello @Markus Freitag In your current code, the TimeoutException is not being triggered because you’re using an AutoResetEvent to wait for a response from the serial port. The AutoResetEvent’s WaitOne method will return false if no signal is received within the specified timeout, but it will not throw a TimeoutException.

    If you want to trigger a TimeoutException, you could use the ReadLine method of the SerialPort class with a ReadTimeout set. Here’s an example:

    public void Test_Timeout()
    {
        var port = new SerialPort("COM4");
        port.Open();
        port.ReadTimeout = 10000; // Set the timeout to 10 seconds
    
        var commandsToSend = new string[] { "AT1", "AT2", "AT3" };
    
        foreach (var command in commandsToSend)
        {
            try
            {
                Trace.WriteLine($"Write '{command}' to {port.PortName}");
                port.WriteLine(command);
    
                Trace.WriteLine("Waiting for response...");
    
                // This will throw a TimeoutException if no data is received within the timeout
                string response = port.ReadLine();
    
                Trace.WriteLine($"Got response: {response}");
            }
            catch (TimeoutException)
            {
                Console.WriteLine("Read took longer than expected");
            }
            catch
            {
                Trace.WriteLine("Failed to write to port");
            }
        }    
    }
    

    In this modified code, the ReadLine method will block until a line is received or the timeout expires. If the timeout expires, a TimeoutException will be thrown. Please note that this will only work if the data you’re expecting ends with a newline character, as ReadLine reads up to the next newline.

    If your data doesn’t end with a newline, you might need to use the Read or ReadExisting methods and implement your own timeout logic.

    Also, remember to close the port when you’re done with it to free up the resource.

    If this information provided here helps solve your issue, please tag this as answered, so it helps further community readers, who may have similar questions.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Michael Taylor 60,326 Reputation points
    2024-02-15T20:05:58.9166667+00:00

    WaitOne won't throw a TimeoutException so that use case will never happen in the code block you gave. If the wait elapsed, based upon the timeout you gave, then the method returns false. If you want to trigger an exception if that situation occurs then throw the exception yourself.

    try
    {
       ...
       if (!mre.WaitOne(responseTimeout))
       {
          ...
          throw new TimeoutException("Timed out waiting for response"));
       };   
    } catch (TimeoutException)
    {
       ...
    }
    

    However note that your existing code would then catch the exception and log yet another message which is wasteful. If you aren't going to do something with the raised exception then don't handle it.

    try
    {
       ...
       if (!mre.WaitOne(responseTimeout))
       {
          ...
          throw new TimeoutException("Timed out waiting for response"));
       };   
    } catch (TimeoutException)
    {
       //Do nothing and rethrow
       throw;
    }
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.