1

I'm writing a program that reads every second data from a serialPort and save it in a textfile/show it on GUI. The reading starts and end with an buttonclick.

I tried some different timers to solve this but every timer brings some trouble(see below).

My tryouts:

serialPort1.ReadTimeout = 2000;

System.Timers.Timer:

    private void timer1_Tick(object sender, EventArgs e) 
    {
        if (!serialPort1.isOpen) 
        {
            serialPort1.Open();
        }

        serialPort1.WriteLine("INFO"); //Send data command
        string data = serialPort1.ReadLine();

        serialPort.Close();
        editData(data); //Method for GUI update and textfile log
    }

Can easily started and stopped with timer1.Start() and timer1.Stop(). The problem is, System.Timers.Timer runs on GUI Threard and freezes the GUI while serialPort.read and serialPort.Close() is called.


Backgroundworker:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        while (backgroundWorker1.CancellationPending == false)
        {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
        }
    }  

Runs asynchronlly. I need to run the programm ~every second.


System.Timers.Timer calls Backgroundworker:

    private void timer1_Tick(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
    }  

This works fine until the data reading process takes longer or a serialPort.readTimeout occur. Backgroundworker can only run once. So I think this isn't an option.


System.Threading.Timers:

        System.Threading.Timer timer;
        timer = new System.Threading.Timer(_ => readSerialPort(), null, 0, 950);

        private void readSerialPort()
        {
            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }

            serialPort1.WriteLine("INFO");
            string data = serialPort1.ReadLine();

            serialPort.Close();
            Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
        }

This works fine but the problem is, I can't stop and restart the reading.


Do anyone have an idea which timer I should use in this case?

5
  • Well, you've outlined your options, and added the reasoning for each of those. What exactly are you expecting as an answer here? :) Commented Sep 30, 2016 at 11:03
  • 1
    System.Timers.Timer is not running on UI thread by default by the way, only if you set SynchronizingObject. Commented Sep 30, 2016 at 11:06
  • @Luaan I'm looking for an option where I can start and stop the data reading and the GUI shouldn't freeze while serialPort.Close(), / SerialPort.ReadLine() Commented Sep 30, 2016 at 11:07
  • 1
    Another option would be to not use any timer but a simple background thread that handles start/stop and does proper looping to do regular reading from the port. Commented Sep 30, 2016 at 11:07
  • 1
    You can stop and restart System.Threading.Timer - just use Timer.Change(). Thus, I would recommend that you use this timer. Commented Sep 30, 2016 at 11:16

2 Answers 2

1

About System.Threading.Timer

var timer = new System.Threading.Timer(cb, null, 1000, 1000); // init   
timer.Change(Timeout.Infinite, Timeout.Infinite); // stop   
timer.Change(0, 1000); // start

P.S. Dont forget to dispose timer

Sign up to request clarification or add additional context in comments.

Comments

1

You can implement this logic using a thread. A meta code is below:

        var stopEvent = new ManualResetEvent(false);
        var thread = new Thread(() => {

            if (!serialPort1.isOpen)
            {
                serialPort1.Open();
            }
            try
            {

                while (!stopEvent.WaitOne(0))
                {
                    try
                    {
                        serialPort1.WriteLine("INFO");
                        string data = serialPort1.ReadLine();
                        Invoke((MethodInvoker)(() => editData(data)));

                    }
                    catch (Exception)
                    {

                        // Handle exception, e.g. a reading timeout
                    }

                    stopEvent.WaitOne(1000); //Thread.Sleep(1000);
                }
            } finally
            {
                serialPort.Close();
            }


        });
        thread.Start();

        //call it to stop the loop.
        stopEvent.Set();
    }

You can implement more complex logic like stopping and resuming readings. Just use more events. If you are not familiar with events you can use just use boolean variables but define that they are volatile.

1 Comment

This is a good idea for working without timers. I will try it, thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.