1
votes

I am receiving data from a serial port, placing each line into a queue and then de-queuing the lines, formatting them slightly (removing some leading characters, trimming etc), and then displaying the formatted lines in a listbox.

I am using a Timer to fire the Dequeuing method every 200ms. Everything is working but it seems to be a bit sluggish/slow.

I am considering using a BackgroundWorker to handle the de-queuing and formatting but im getting stuck.

I tried to start the backgroundworker in FormLoad, but quickly realized it would run through the code only once. I tried a label and goto inside the backgroundworker code to create a loop (i know, not good) but that got me high CPU usage and didnt even work.

I also tried using " backgroundWorker1.RunWorkerAsync(); " in my serial received event to run it every time new data comes in but that throws the 'Background worker currently busy" exception

So, I need the background worker to continuously process the queue (dequeue).

Code: heres my data received event, and below that my dequeuing code thats sitting in the backgroundworker. Any help much appreciated.

//  Serial Data Received
private void serialPort1_DataReceived(
    object sender, 
    System.IO.Ports.SerialDataReceivedEventArgs e)
{
    RxString = serialPort1.ReadTo("\u0003");
    q.Enqueue(RxString);
}

Next Code is the dequeue code:

//  Dequeue items, format, then display in listbox
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    if (q.Count == 0)
    {
        // do nothing if q is empty
    }
    else
        do
        {
            output = (q.Dequeue().ToString());
            output = output.TrimStart(new char[] { (char)02 }); 
            output = output.TrimEnd(new char[] { (char)03 });

            if (output.StartsWith("C"))
            {
                ClearAll();
            }
            else if (output.StartsWith("W98"))
            {
                txtTax.Text = (output.Remove(0, 5));
            }
            else if (output.StartsWith("W99"))
            {
                txtTotal.Text = (output.Remove(0, 24));
            }
            else
            {  
                listOrderItems.Items.Add(output.Remove(0, 5));
                listOrderItems.SelectedIndex = listOrderItems.Items.Count - 1;
            }
        } while (q.Count > 0);
}
1
Too many threads. You already got one handed to you on a silver platter: the DataReceived event runs on a threadpool thread. Do the message process there. Then use Control.BeginInvoke to update any UI. - Hans Passant
@Hans: Answers go down there (even short ones) - Allon Guralnek
It doesn't answer the question, users get cranky about that. - Hans Passant
Hans, does your comment mean that the DataReceived event is already running in something that is similar to a BackgroundWorker? If so, does you 'too many threads' comment mean that its not good to create extra threads? how does one determine how many threads are too many? When you say .."do the message process there" do you mean move all the formatting code into the DR event?? If so this begs another question: Do I even need a BgW ? I need this to be responsive. This program doesnt do anything too complicated, but I need it to be fast and stable. - user1062142
i put my formatting code into the DataRec. event handler. it does not work well at all. - user1062142

1 Answers

0
votes

i do not see the point parsing your string in a different thread. it is not a long running procedure, and since your running in the background thread, it seems that you forgot to Invoke to the windows thread. here is my solution,

using System.IO.Ports;    


static void ParseData(ref string data)
{
    data = data.TrimStart(new char[] { (char)02 }); 
    data = data.TrimEnd(new char[] { (char)03 });  
}    

private void UpdateControlsWithData(string data)
{
    Action action;
    if(data.StartsWith("C")
    {
        action = () => ClearAll();
    }
    else if(data.StartsWith("W98"))
    {
        action = () => { txtTax.Text = data.Remove(0, 5); };
    }
    else if(data.StartsWith("W99"))
    {
        action = () => { txtTotal.Text = data.Remove(0, 24); };
    }
    else
    {
        action = () => { 
            listOrderItems.Items.Add(data.Remove(0, 5));
            listOrderItems.SelectedIndex = listOrderItems.Items.Count - 1;
        };
    }
    if(this.InvokeRequired()) this.Invoke(action);
    else action();
}

private void HandleDataReceived()
{
    string data = serialPort1.ReadTo("\u0003");
    ParseData(ref data);
    UpdateControlsWithData(data);
}

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    this.HandleDataReceived();
}