1

My application connects to a Bluetooth module that is transmitting numbers. I want to grab this data and plot it in realtime point by point on a zedgraph window. I am using threads to make my UI more faster. When it comes to plotting the points, I receive the following error, "thread operation not valid: Control 'hScrollBar1' accessed from a thread other than the thread it was created on." I understand that I cannot access this control if it was not created on the same thread but I just do not know how to implement the BackgroundWorker or other solutions to fix this problem. See below for the code:

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.Globalization;
using System.Threading;
using ZedGraph;
using System.IO;
using InTheHand;
using InTheHand.Net.Bluetooth;
//using InTheHand.Net.Bluetooth.AttributeIds;
using InTheHand.Net.Ports;
using InTheHand.Net.Sockets;
using InTheHand.Net;
using InTheHand.Windows.Forms;

namespace MPS430_Serial_Data
{
    public partial class frmMain : Form
    {
    int tickStart = 0;
    string initText = "waiting...";
    const string ID_TEMP = "C";
    const string UNIT_TEMP = " lb";

    GraphPane myPane1;
    GraphPane myPaneBT;
    private static UInt32 cnt_Temp = 0;
    private static UInt32 cnt_All = 0;
    const int XAXIS_SCALE = 60;             //sets the number of seconds unit on the x-axis
    const int YAXIS_MINVALUE = 0;        //sets the minimum value of the y-axis
    const int YAXIS_MAXVALUE = 3000;         //sets the maximum value of the y-axis

    IPointListEdit listBT;//list to store the data and timestamp

    LineItem curveBT;
    List<string> items;
    BluetoothDeviceInfo[] devices;
    byte[] received;

    //Initializes values for controls on the main form
    public frmMain()
    {
        items = new List<string>();
        string[] myPort = SerialPort.GetPortNames();
        InitializeComponent();
        //When our form loads, auto detect all serial ports in the system and populate the cmbPort Combo box.
        foreach (string port in myPort)
        {
            cmbPort.Items.Add(port);
        }
        //Populate the cmbBaud Combo box to common baud rates used
        //cmbBaud.Items.Add(2400);
        cmbBaud.Items.Add(9600);
        cmbModel.Items.Add("41000-200");
        cmbModel.Items.Add("41000-300");
        cmbModel.Items.Add("41000-400");
        cmbModel.Items.Add("41000-500");

        //Checks if the load monitor is connected to the PC using a USB cable
        try
        {
            cmbPort.SelectedIndex = 0;      //Set cmbPort text to the first COM port detected
        }
        catch (ArgumentOutOfRangeException)
        {
            MessageBox.Show("Please connect USB cable", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
        }
        cmbBaud.SelectedIndex = 0;      //Set cmbBaud text to the first Baud rate on the list  
        cmbModel.SelectedIndex = 0;      //Set cmbModel text to the first model on the list    
        btnDisconnect.Enabled = false;
        textTemp.Text = initText;
        tabPage1.Text = "USB Connection";
        tabPage3.Text = "Bluetooth Connection";

    }

    //Initializes the graph and timer when the form loads
    private void frmMain_Load(object sender, EventArgs e)
    {                  
        myPaneBT = zgControlBT.GraphPane;
        myPaneBT.Chart.Fill = new Fill(Color.White, Color.SteelBlue, 45.0F);
        myPaneBT.Title.Text = "Dynamic Display of Load Cell Values";
        myPaneBT.XAxis.Title.Text = "Time (Seconds)";
        myPaneBT.YAxis.Title.Text = "Load (lb)";
        LineItem curveBT = myPaneBT.AddCurve("Load", listBT, Color.Black, SymbolType.Circle);         
        timer1.Interval = 1;
        timer1.Enabled = true;
        timer1.Start();
    }

    //Plots the received data on the graph versus the instantaneous time 
    private void Display_Data(String sTemp, LineItem curve, IPointListEdit list, ZedGraphControl zgControl)
    {
        double currentForce = 0;
        double maxForce = 0;
        if (zgControl.GraphPane.CurveList.Count <= 0)                    //Make sure that the curvelist has at least one curve
            return;
        curve = zgControl.GraphPane.CurveList[0] as LineItem;            //Get the first CurveItem in the graph
        if (curve == null)
            return;
        list = curve.Points as IPointListEdit;                                  //Get the PointPairList
        if (list == null)                                                       //If this is null, it means the reference at curve.Points does not
            return;                                                             //support IPointListEdit, so we won't be able to modify it
        double time = (Environment.TickCount - tickStart) / 1000.0;             //Time is measured in seconds
        DateTime now = new DateTime();                                          //Get current time        
        now = DateTime.Now;
        double timestamp = now.ToOADate();
        list.Add(timestamp, Convert.ToDouble(sTemp));
        currentForce = Convert.ToDouble(sTemp);
        if (currentForce > maxForce)                                            //Compares the current force with the highest force
            maxForce = currentForce;
        //txtMaxForce.Text = maxForce.ToString();                                 //Displays the maximum force
        XDate dateTime = curve[0].X;                                            //Converts the date and time to a readable format
        //txtStartTime.Text = dateTime.DateTime.ToString();                       //Displays the starting time  
        zgControl.IsShowHScrollBar = true;
        zgControl.ScrollGrace = 0.1;                                     //Add 10% to scale range
        zgControl.IsEnableHPan = false;                                  //Horizontal pan and zoom not allowed
        zgControl.IsEnableHZoom = false;
        zgControl.IsEnableVPan = false;                                  //Vertical pan and zoom not allowed
        zgControl.IsEnableVZoom = false;
        zgControl.IsAutoScrollRange = true;                              //the scrollbars on the x-axis will scroll automatically
        zgControl.AxisChange();                                          //changes the x-axis  
        zgControl.Invalidate();                                          //Force a redraw
    }



    //Sets the size of the user interface
    private void Form1_Resize(object sender, EventArgs e)
    {
        SetSize(zgControlBT);
    }

    // Set the size and location of the ZedGraphControl
    private void SetSize(ZedGraphControl zgControl)
    {
        Rectangle formRect = this.ClientRectangle;
        formRect.Inflate(-10, -10);                   // Control is always 10 pixels inset from the client rectangle of the form
        if (zgControl.Size != formRect.Size)
        {
            zgControl.Location = formRect.Location;
            zgControl.Size = formRect.Size;
        }
    }

    //Sets the axis and scales of the real-time graph
    private void setGraphAxis(GraphPane myPane, ZedGraphControl zgControl)
    {
        myPane.XAxis.Type = AxisType.Date;                                          //sets the date on the x-axis
        myPane.XAxis.MinorGrid.IsVisible = true;                                    //displays gridlines
        myPane.XAxis.MajorGrid.IsVisible = true;
        myPane.YAxis.MajorGrid.IsVisible = true;
        myPane.XAxis.Scale.Min = new XDate(DateTime.Now);                           //sets the current time as the min value on the x-axis scale
        myPane.XAxis.Scale.Max = new XDate(DateTime.Now.AddSeconds(XAXIS_SCALE));   //adds 120 seconds (5 minutes) to the current value 
        //to get the max value on the x-axis scale  
        myPane.YAxis.Scale.Min = YAXIS_MINVALUE;                                    //sets the min value on the y-axis scale
        myPane.YAxis.Scale.Max = YAXIS_MAXVALUE;                                    //sets the max value on the y-axis scale        
        myPane.XAxis.Scale.Format = "HH:mm:ss \n MMM dd yyyy";                      //sets the date format for the x-axis
        myPane.XAxis.Scale.MinorUnit = DateUnit.Second;                             //sets the minimum x unit to time/seconds
        myPane.XAxis.Scale.MajorUnit = DateUnit.Second;                             //sets the maximum x unit to time/minutes
        zgControl.AxisChange();                                              //Scale the axes
    }

    //Sets the axis and scale for the graph when data is retrieved from the data logger
    private void setDataLoggerGraphAxis(GraphPane myPane)
    {
        myPane.XAxis.Type = AxisType.Date;                                          //sets the date on the x-axis
        myPane.XAxis.MinorGrid.IsVisible = true;                                    //displays gridlines
        myPane.XAxis.MajorGrid.IsVisible = true;
        myPane.YAxis.MajorGrid.IsVisible = true;
        myPane.XAxis.Scale.Min = 0;
        myPane.XAxis.Scale.Max = 30;
        myPane.YAxis.Scale.Min = YAXIS_MINVALUE;                                    //sets the min value on the y-axis scale
        myPane.YAxis.Scale.Max = YAXIS_MAXVALUE;                                    //sets the max value on the y-axis scale        
        myPane.XAxis.Scale.Format = "HH:mm:ss \n MMM dd yyyy";                      //sets the date format for the x-axis
        myPane.XAxis.Scale.MinorUnit = DateUnit.Second;                             //sets the minimum x unit to time/seconds
        myPane.XAxis.Scale.MajorUnit = DateUnit.Second;                             //sets the maximum x unit to time/minutes
        zgControlUSB.AxisChange();                                              //Scale the axes  
    }


    //Guid mUUID = new Guid("643F6826-1EC5-4509-BBC4-0CC795C576F4");
    Guid mUUID = BluetoothService.SerialPort;
    private void btnFindDevice_Click(object sender, EventArgs e)
    {
        startScan();
    }

    private void startScan()
    {
        listBox1.DataSource = null;
        listBox1.Items.Clear();
        items.Clear();
        Thread bluetoothScanThread = new Thread(new ThreadStart(scan));
        bluetoothScanThread.Start();
    }

    private void scan()
    {

        BluetoothClient client = new BluetoothClient();
        devices = client.DiscoverDevicesInRange();
        foreach (BluetoothDeviceInfo d in devices)
        {
            items.Add(d.DeviceName);
            updateDeviceList(); 
        }

    }

    private void updateDeviceList()
    {
        Func<int> del = delegate()
        {
            cbDevices.DataSource = items;
            listBox1.DataSource = items;
            txtDevice.Text = items[0].ToString();
            return 0;
        };
        Invoke(del);
    }


    private void ClientConnect()
    {
        BluetoothClient client = new BluetoothClient();
        client.BeginConnect(deviceInfo.DeviceAddress, mUUID, this.BluetoothClientConnectCallback, client);

    }


    void BluetoothClientConnectCallback(IAsyncResult result)
    {
        BluetoothClient client = (BluetoothClient)result.AsyncState;
        received = new byte[1024];
        client.EndConnect(result);
        string btValue = "";
        byte[] temp = new byte[1024];
        byte[] receivedValue = new byte[1024];
        int i = 0;  
        Thread.Sleep(10000);
        Stream btstream = client.GetStream();
        btstream.ReadTimeout = 1000;

        while (true)
        {
            // while (!ready) ;

            Array.Clear(received, 0, received.Length);
            try
            {
                byte btByte;
                btstream.Read(received, 0, received.Length);
                // MessageBox.Show(btstream.Length.ToString());
                foreach (Byte b in received)
                {
                    //MessageBox.Show(b.ToString());
                    temp[i] = b;
                    if (b == 10)
                    {
                        break;
                    }
                    i++;
                }
                i = 0;
                MessageBox.Show(Encoding.ASCII.GetString(temp));
                Display_Data(Encoding.ASCII.GetString(temp), curveBT, listBT, zgControlBT);
                Array.Clear(temp, 0, temp.Length);
            }
            catch (IOException e)
            {
            }
            //finally { }
            //index++;
        }
        btstream.Flush();
        btstream.Close();
        client.Close();
    }

    string myPin = "1234";
    private bool pairDevice()
    {
        if (!deviceInfo.Authenticated)
        {
            if (!BluetoothSecurity.PairRequest(deviceInfo.DeviceAddress, myPin))
            {
                return false;
            }
        }
        return true;
    }



    private void btnBTConnect_Click(object sender, EventArgs e)
    {
        deviceInfo = devices.ElementAt(listBox1.SelectedIndex);

        if (pairDevice())
        {
            ClientConnect();

        }
        else
        {
            //updateUI("Pair failed");
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        //put the important, processor-intensive stuff
        Thread.Sleep(1000); //one second
        /**********************************************************************************
         * e.Argument is used to get the parameter reference received by RunWorkerAsync
         * or gets a value that represents the argument of an asynchronous operation
         * ***********************************************************************************/

        /************************************************************************
         * e.Result is used to see what the BackgroundWorker processing did
         * or gets or sets a value that represents the result of an asynchronous operation
         * *************************************************************************************/

        /**************************************************************************************
         * backgroundWorker1.RunWorkerAsync is called to start a process on the worker thread
         * or starts execution of a background operation
         * **************************************************************************************/


    }
}

}

I receive the error at this line in the code: zgControl.IsShowHScrollBar = true;

Any help is appreciated. Thanks in advance!

0 Answers0