1

I've made and application using WPF and I have to implement serial communication. Bellow i have the DataReceived function.

The main problem is that the function triggers only sometimes, does anybody have a better solution to DataReceived trigger in WPF?

Below is the connection Connection to ComPort

  public static void connnect(string recPort)
        {
            System.Windows.Threading.DispatcherTimer MyTimer = null;
            bool error = false;
                String serialpname = recPort;
                ComPort = new SerialPort();
                if (ComPort.IsOpen == false)
                {
                ComPort.PortName = serialpname;
                ComPort.BaudRate = 38400;  
                ComPort.Parity = Parity.None; 
                ComPort.DataBits = 8;
                ComPort.StopBits = StopBits.One;
                ComPort.DataReceived += new SerialDataReceivedEventHandler(OnSerialDataReceived);
                System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
                dispatcherTimer.Tick += dispatcherTimer_Tick;
                dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
                try
                {
                    if (ComPort.IsOpen == false)
                    {
                        //Open Port
                        ComPort.Open();
                        dispatcherTimer.Start();
                    }
                }              
                catch (System.IO.IOException) { error = true; }              
            }
        }

Below is the timer that interogates the port

  private static void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                ComPort.Write(eot + "11" + STX + "2170" + ENQ); // get pos 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

The datareceived event


public static void OnSerialDataReceived(object sender,
        SerialDataReceivedEventArgs args)
{           
    bool isString = true;
    try
    {
      Thread.Sleep(100);// this solves the problem
        byte[] readBuffer = new byte[ComPort.ReadBufferSize];

        int readLen = ComPort.Read(readBuffer, 0, readBuffer.Length);

        string readStr = string.Empty;
        if (isString)
        {
            readStr = Encoding.Default.GetString(readBuffer, 0, readLen);
            if(readStr.Length > 10)
            {
                if (readStr.StartsWith("\u0002"))
                {
                    Position = (Mid(readStr, 2, 5));
                    Messenger.Default.Send("NewPos");
                }
                else
                {
                    Position = (Mid(readStr, 31, 4));
                    Messenger.Default.Send("NewPos");
                }
              }
        }
        else
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < readLen; i++)
            {
                stringBuilder.Append(readBuffer[i].ToString("X2") + " ");
            }
            readStr = stringBuilder.ToString();
        }
    }
    catch (Exception ex)
    {
        Trace.TraceError(ex.Message);
        Console.WriteLine(ex);
    }
}
Cristi Wolf
  • 31
  • 1
  • 8
  • 1
    As with most event-based I/O, you probably should get into the habbit of coding what is immediately required and leave the rest for another thread to process. Otherwise if you spend too much time doing compute or other forms of I/O (say `Messenger.Default.Send`) and it takes too long, you could run into _buffer overrun errors_ whereby data is lost. The sender might be running into timeouts too if you take too long. So you could for example, read the COM data and store it and quickly return from the callback –  Feb 02 '20 at 10:35
  • ...or actually use `async` I/O. Even though the `ComPort` class has no explicit `async` support, the port's `BaseStream` does. https://stackoverflow.com/a/32436104/585968. This approach is much nicer than fiddling about with queues :) –  Feb 02 '20 at 10:48
  • Thank you for the answer, i've removed the other I/O and the other I/O forms but the problem with the DataReceived is persisting. From what i have seen, if I put a breakpoint in the function it works as it should. – Cristi Wolf Feb 02 '20 at 10:51
  • Can you please post the code where you setup `ComPort`? Particularly, baud, parity, flow control etc. Also what type of device are you talking to? –  Feb 02 '20 at 10:58
  • Yes, for sure: ComPort.PortName = serialpname; ComPort.BaudRate = 38400; ComPort.Parity = Parity.None; ComPort.DataBits = 8; ComPort.StopBits = StopBits.One; ComPort.DataReceived += new SerialDataReceivedEventHandler(OnSerialDataReceived); It's a controller board for servo motors and pneumatic controls, from which I have to read the position of the motors and different other states. – Cristi Wolf Feb 02 '20 at 11:11
  • 1
    Please [edit](https://stackoverflow.com/posts/60025155/edit) your question to include that info –  Feb 02 '20 at 11:33

1 Answers1

0

Problem solved, i have added a Thread.Sleep(100); in the datareceived function. The buffer was not filled with the incoming data and seems that was the cause. Thank you.

Cristi Wolf
  • 31
  • 1
  • 8