question

MarkusFreitag-0088 avatar image
0 Votes"
MarkusFreitag-0088 asked MarkusFreitag-0088 commented

C# - serial port - RS232 - Timeout

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}");
             }
         }


dotnet-csharp
-message-is-ok.png (7.1 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Markus-Frietag,

I am working on a similar app, where I have to receive data coming from the serial port. However, I don;t have an ending char, like you do.

What I plan on doing is similar to what cheong00 suggests. I am planning on including a timer that I enable once I start receiving data. Every time I receive data, I reset the timer, so while I am receiving data the timer will never fire. If I stop receiving data, the timer eventually fires and takes whatever action is necessary.

Your case is slightly different. When you get the S start flag, you start the timer. When you receive the E end flag you stop the timer. If the E flag is received in time, the timer never fires; however, if getting the E takes too long, the timer event fires and lets the user know that the receive operation timed out.

I hope this help, even if it is basically the same idea that cheong00 proposed. Saga

0 Votes 0 ·
cheong00 avatar image
0 Votes"
cheong00 answered MarkusFreitag-0088 commented

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;
             }

· 9
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Timeout.Infinite

Why is the Infinite not recognized?
How can I write the callback differently? A function? Maybe without lambda

The rest works very well. Thank you very much in advance.


Can you show me please with callback function?


91651--no-infinite08h07m26s.png


91626--withcallbackfunction.png


0 Votes 0 ·
cheong00 avatar image cheong00 MarkusFreitag-0088 ·

This comes from System.Threading.Timeout. If you're unable to find constant for Infinite, use -1 instead.


1 Vote 1 ·

This comes from System.Threading.Timeout. If you're unable to find constant for Infinite, use -1 instead.

I do it.

Can you please still answer, if I would use a custom function TestCallBack, what the code must look like? THANKS.


0 Votes 0 ·
Show more comments

MarkusFreitag,

I found this turial here:

https://owlcation.com/stem/Threading-Timer-In-C-Explained-With-Example\

It creates a simple app using the threading timer, using a callback function like you want. Just curious, why don't you like the solution that Cheong00 proposed for the call back code? :-) Saga

1 Vote 1 ·

ok, thanks

0 Votes 0 ·
cheong00 avatar image
1 Vote"
cheong00 answered MarkusFreitag-0088 commented

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
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

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.

Can you please make a sample? Thanks in advance!

0 Votes 0 ·