2

Hi I'm trying to program a simple C# WPF that displays time information on a virtual scoreboard in real time from a timing system. I'm fairly new to programming so in depth explanation would be appreciated.

I have created a new thread to handle the incoming data from the COM port and as the app is developed this data will be interpreted. For now I just wanted to display the raw information (in hex) that is coming from the timer into a textbox. This works but not as intended. I am receiving tons of duplicate information, my only explanation is I am reading the data too slowly or its reading the same byte over and over. What I would like to happen is to take out each byte and display them, all controlled by one start/stop button.

Possible solutions include storing the entire buffer in a list or array which I'm not quite sure of yet, I don't want to add so many threads that the program freezes everything up.

Here is my code so far (I'm new to pretty much all the code I have written here, so if anything is bad practice please let me know):

public partial class MainWindow : Window
{
    SerialPort comms;
    Thread commThread;

    bool flag;
    string message;


    public MainWindow()
    {
        InitializeComponent();
        comms = new SerialPort();
    }

    private void PortControl_Click(object sender, RoutedEventArgs e)
    {
        if (!comms.IsOpen)
        {
            PortControl.Content = "Stop";
            comms.PortName = "COM1";
            comms.BaudRate = 9600;
            comms.DataBits = 8;
            comms.StopBits = StopBits.One;
            comms.Parity = Parity.Even;
            comms.ReadTimeout = 500;
            comms.ReceivedBytesThreshold = 1;

            commThread = new Thread(new ThreadStart(Handle));

            comms.Open();

            comms.DataReceived += new SerialDataReceivedEventHandler(ReadIn);
        }
        else
        {
            PortControl.Content = "Start";
            flag = false;
            comms.DataReceived -= ReadIn;

            commThread.Join();
            comms.Close();
        }
    }

    private void ReadIn(object sender, SerialDataReceivedEventArgs e)
    {
        if (!commThread.IsAlive)
        {
            flag = true;
            commThread.Start();
        }
    }

      private void Handle()
      {
          while (flag)
          {
              if (comms.IsOpen)
              {
                  try
                  {
                      message = comms.ReadByte().ToString("X2");

                      Dispatcher.BeginInvoke((Action)(() =>
                      {
                          ConsoleBox.Text += message + " ";
                      }));
                  }
                  catch (Exception ex)
                  {
                      MessageBox.Show(ex.ToString());
                  }
              }
          }
      }


}
pgwri
  • 103
  • 1
  • 4
  • 16
  • Is ConsoleBox a GUI-Control (TextEdit?) Please be aware that Gui-painting, especially updating the text-content like you did __extremely__ slow compared to usual processor tasks. One simple workaround is indeed using a stringbuffer and just displaying this on a separate timer.event. – Enno Jun 01 '13 at 22:16
  • Yes sorry ConsoleBox is a TextBox I don't know why I named it that.. What is this Timer Event does it need to go on another thread? Won't the threads have to swap on a dual core CPU and I lose data? – pgwri Jun 01 '13 at 22:20
  • just use a simple timer-control and set its interval to one second, then during the timer-event write the content of your stringbuffer into the textbox. of course you are right: you have to perform this access threadsafe, for instance with beginInvoke, like you already did in your code above. – Enno Jun 01 '13 at 22:25
  • argh sorry you are in wpf not winforms world! please use DispatcherTimer like shown here: http://stackoverflow.com/questions/5410430/wpf-timer-like-c-sharp-timer – Enno Jun 01 '13 at 22:28
  • I have worked with winforms timers before and it looks like its a similar approach. Thank you for your help! – pgwri Jun 01 '13 at 22:33
  • If you want any kind of decent throughput for this code then you'll have to avoid calling Dispatcher.BeginInvoke() for every single byte. Buffer them so you've got something worth invoking for. – Hans Passant Jun 01 '13 at 23:06
  • Yeah I know about that I just wanted to get the information coming through correctly before I started to gather together bytes for digits and so on. Thanks for the heads up though – pgwri Jun 02 '13 at 00:14

1 Answers1

1

Here is one solution.

The serial port is receiving the data in its own thread, and you should read the incoming bytes in the data received handler.

I propose to read the data and add it to a thread-safe FIFO list in the data received handler and read the data from the list in the main thread.

See my solution in post Serial port reading + Threads or something better?

Community
  • 1
  • 1
user2019047
  • 749
  • 7
  • 10
  • Hi thanks for the response. I attempted to use your idea and it has worked to an extent, I implemented a timer to display the data, however it only displays my data for the first tick, and then when I try to stop it, the application freezes. The hex that I am getting through looks correct though. – pgwri Jun 04 '13 at 12:12
  • When you enter the timer tick handler, stop the timer before calling the routine to empty the queue. When the queue is empty and the routine returns, enable the timer again. That is what I do to make sure the timer tick event is not called too early. – user2019047 Jun 04 '13 at 21:02
  • Thank you! I was able to get it working smoothly by taking everything out of the queue and putting it into another intermediate array to prevent the deadlocking, and then using stringbuilder to display the data. Onto the next step! – pgwri Jun 06 '13 at 13:13
  • Great! I have a timer event every 10 millisecond for an application that receives data from a micro controller. The serial port is set to 9600 baud, and the queue never gets really big, but then I queue a struct with the received characters instead of one character at a time, it makes for more efficient de-queuing. – user2019047 Jun 06 '13 at 15:16