C# - serial port - RS232 - Timeout

Markus Freitag 3,791 Reputation points
2021-04-23T09:57:42.12+00:00

Hello,

I am looking for a good way to query the serial port.

Inputstring
90708--message-is-ok.png
When I receive S and E, the message is complete.
If I receive S and E does not come after n time, timeout message to the operator.

How can I reach the goal, how do I solve the timeout?
When S comes I have to start.
If timeout I have to empty the buffer.

The string, I can receive the message. That is good. The timeout is the problem.
How can I set an existing array to default to 0, like memset in C++?

My trials

public byte BreakCondition { get; }     Byte 13, can be also Byte 5  
  
ASerialPort = new SerialPort(ConfigRS232.PortName, this.ConfigRS232.BaudRate, ConfigRS232.Parity, ConfigRS232.DataBits, ConfigRS232.StopBits);  
  ASerialPort.Handshake = ConfigRS232.Handshake;  
  ASerialPort.DataReceived += ReadDataFromSerialPort;  
  ASerialPort.Open();  




private void ReadDataFromSerialPort(object sender, SerialDataReceivedEventArgs e)  
        {  
            try  
            {  
                DataToReceive += ASerialPort.ReadExisting();  
  
                byte[] bytesReceived = Encoding.ASCII.GetBytes(DataToReceive);  
  
                byte[] bytesDestination = new byte[DataToReceive.Length];  
  
                int i = 0;  
                int iStart = 0;  
                bool startCharacter = false;  
                bool endCharacter = false;  
                foreach (var item in bytesReceived)  
                {  
                    i++;  
  
                    if (startCharacter == false)  
                    {  
                        if (Convert.ToChar(item) == 'P')  
                        {  
                            startCharacter = true;  
                            iStart = i;  
                        }  
                        continue;  
                    }  
  
                    if (item == BreakCondition)  
                    {  
                        endCharacter = true;  
                        break;  
                    }  
                }  
  
                if (endCharacter)  
                {  
                    Buffer.BlockCopy(bytesReceived, iStart, bytesDestination, 0, i - iStart);  
             
                    string program = Encoding.UTF8.GetString(bytesDestination, 0, i - iStart);  
  
                    EvHaContentReceivedTrigger?.Invoke(this, program );  
                    DataToReceive = "";  
                    //EvNewMessageReceived.Set();  
                    ASerialPort?.DiscardInBuffer();  
                    ASerialPort?.DiscardOutBuffer();  
  
                }  
  
            }  
            catch (Exception ex)  
            {  
                throw new ArgumentException($"COM port 'ReadDataFromSerialPort'  {ex.Message + ex.StackTrace}");  
            }  
        }  
Developer technologies C#
{count} votes

Accepted answer
  1. cheong00 3,486 Reputation points Volunteer Moderator
    2021-04-27T02:20:30.083+00:00

    Here I only will briefly list out relevant parts of code:

    First, you add a variable declaration of timer on your class: (Add using System.Threading; at the top if not done already)

    Timer timeoutTimer = null;
    

    Then, at the part you detected startCharacter, you do the following:

            timeoutTimer = new Timer((o) =>
            {
                //do whatever you want here, including cleanup of buffer or prompt alert to user
                timeoutTimer.Dispose();
                timeoutTimer = null;
            }, null, 2000, Timeout.Infinite);
    

    2000 means to wait 2000 milliseconds = 2 seconds, multiply the seconds you wish to wait by 1000 to get the duration that you want.

    Finally, on the part you detected endCharacter, add the following to cancel it:

                if (timeoutTimer != null)
                {
                    timeoutTimer.Dispose();
                    timeoutTimer = null;
                }
    

1 additional answer

Sort by: Most helpful
  1. cheong00 3,486 Reputation points Volunteer Moderator
    2021-04-26T04:20:08.873+00:00

    Create a Thread Timer when received "S"(period set to Infinite because you're making one-time-invoke here only). On the callback, throw your timeout exception. When "E" is received, call timer.Dispose() to destroy the timer and prevent the timeout exception be throw.

    For your second question, the C# specification requires all elements in array be initialized to their type default value. So just declare array with specified length and all elements will be initialized to default of int type, which is 0.

    1 person found this answer helpful.

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.