Search code examples
c#visual-studio-2010serial-portbackgroundworkerserial-communication

Reading Serial Communication Visual Studios


I need some help with Background worker. I am trying to read data from a serial port (works fine with a button) the problem is that I need to continuously read from the serial port, until someone presses a button (Close button) on the form to stop reading. I tried doing this by adding a loop, but it just ran infinitely and froze up the form. I have the following code, whenever I press the button to read, a file is created, but when I press the close port button,it says

The I/O operation has been aborted because of either a thread exit or an application request

Any ideas on how to fix this?

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.IO;

    namespace SerialCommunication
{
   public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        GetAvaliablePortNames();
    }

    bool indicator;
    StreamWriter sw = new StreamWriter(@"C:\Users\slahiri\Desktop\Data\jumbo.txt");

    void GetAvaliablePortNames()
    {
        string[] Ports = SerialPort.GetPortNames();
        cmbPort.Items.AddRange(Ports);
    }

    private void btnOpen_Click(object sender, EventArgs e)
    {
        try
        {
            if (cmbPort.Text == "" || cmbBaud.Text == "")
            {
                MessageBox.Show("Please select the Port and Baud Rates");
            }
            else
            {
                serialPort1.PortName = cmbPort.Text;
                serialPort1.BaudRate = Convert.ToInt32(cmbBaud.Text);
                serialPort1.Open();
                progressBar1.Value = 100;

                groupBox2.Enabled = true;
                btnRead.Enabled = true;

                btnOpen.Enabled = false;
                btnClose.Enabled = true;
            }
        }
        catch (UnauthorizedAccessException)
        {
            txtRead.Text = "Unauthorized Acess";
        }
    }

    private void btnClose_Click(object sender, EventArgs e)
    {
        serialPort1.Close();
        progressBar1.Value = 0;
        btnClose.Enabled = false;
        btnRead.Enabled = false;

        btnOpen.Enabled = true;
        indicator = true;


    }



    private void btnRead_Click(object sender, EventArgs e)
    {
        if (btnRead.Text == "Read")
        {

            btnRead.Text = "Stop and Close Port";
            progressBar1.Maximum = 1000;
            progressBar1.Value = 0;
            backgroundWorker1.RunWorkerAsync(progressBar1.Maximum);
            indicator = false;
        }
        else
        {

            backgroundWorker1.WorkerSupportsCancellation = true; 
            backgroundWorker1.CancelAsync();

        }
    }


    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            int max = (int)e.Argument;
            int n = 0;
            indicator = false;
            do
            {
                //write to serial writer
                sw.WriteLine(serialPort1.ReadLine());
                if (backgroundWorker1.CancellationPending)
                {
                    sw.Flush();
                    sw.Close();
                    e.Cancel = true;
                    break;
                }
               // backgroundWorker1.ReportProgress(n++);
            }

            while (indicator ==false);
        }
        catch (TimeoutException)
        {
            //Close Serial Writer & Messagebox
            //txtRead.Text = "Time Out!";
            MessageBox.Show("TimeOut Exception");
        }

    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //progressBar1.Value = e.ProgressPercentage;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
         btnRead.Text = "Read";
        //close serial writer
    }

}

}


Solution

  • Since you have a do-while construct you evaluate the condition at the END! So when you hit the Close button and close the SerialPort the backgroundworker is still active and running in the background trying to read from the SerialPort. It enters the do compartment and tries to read from a closed port, which is like running agains a closed door :) this leads to the exception.

    You could solve it by

    1) putting the while-evaluation on top and get rid of the do statement (making it a simple while-loop). This way the serialPort.ReadLine will not be executed anymore, because you set indicator = true; when hitting the close button.

    May be in this case you should put the setting of indicator as the first line before closing the port:

    private void btnClose_Click(object sender, EventArgs e)
    {
        try
        {
            indicator = true;
            serialPort1.Close();
    

    Or

    2) put an extra if clause that makes sure to read only if the port is open!

    if (serialPort1.IsOpen)
    {
        sw.WriteLine(serialPort1.ReadLine());
    }