Today I was trying to chart data from project where I recieve it by transmitting from my uC via UART.
The program is just to recieve data in interrupt, process it and display.
When program goes to my ChartData method I'm getting an exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
Additional information: Cross-thread operation not valid: Control 'chart1' accessed from a thread other than the thread it was created on. It is strange for me - I think that I've got one thread in my program.
I have tried charting with pure project where I create data in Form_Load event - everything works fine.
My source code is here - any idea?
public partial class Form1 : Form
{
private List<float> freqList = new List<float>();
private List<float> magList = new List<float>();
private float[] fFrequency = new float[numberOfSamples];
private float[] fMagnitude = new float[numberOfSamples];
public static int counterOfRecBytes = 0;
public static int numberOfSamples = 512;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
GetAvailablePorts();
tb_Rx.Text = "Wprowadź parametry transmisji";
// Default transmission parameters for testing
cb_BaudRate.Text = "9600";
cb_Ports.Text = "COM5";
}
/// <summary>
/// Checks avaiable serialports - for linking my device to other computers
/// </summary>
void GetAvailablePorts()
{
string[] ports = SerialPort.GetPortNames();
cb_Ports.Items.AddRange(ports);
//cb_Ports.SelectedIndex = 0;
}
private void bt_connect_Click(object sender, EventArgs e)
{
if (bt_connect.Text == "Connect")
{
if (cb_Ports.Text == "" || cb_BaudRate.Text == "" || cb_Ports.Text == "")
tb_Rx.Text = "Nie wybrano jednego z parametrów";
else
{
bt_connect.Text = "Disconnect";
SerialP.PortName = cb_Ports.Text;
SerialP.BaudRate = Convert.ToInt32(cb_BaudRate.Text);
SerialP.StopBits = StopBits.One;
SerialP.DataBits = 8;
SerialP.Parity = Parity.None;
SerialP.Handshake = Handshake.None;
SerialP.ReadBufferSize = 8 * numberOfSamples + 4;
SerialP.Open();
pb_connect.Value = 100;
tb_Rx.Clear();
cb_Ports.Enabled = false;
cb_BaudRate.Enabled = false;
}
}
else
{
SerialP.Close();
bt_connect.Text = "Connect";
pb_connect.Value = 0;
bt_connect.Enabled = true;
cb_BaudRate.Enabled = true;
cb_Ports.Enabled = true;
freqList.Clear();
magList.Clear();
pb_connect.Value = 0;
tb_Rx.AppendText(Environment.NewLine + "----Zamknięto połączenie----");
}
}
private void SerialP_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] bArray = new byte[8 * numberOfSamples+4]; // frequencies (512 samples) and magnitudes (512 values) - each is a single precision float so 4 bytes
float[] fArray = new float[2*numberOfSamples];
//bool dataStart = false;
int previouse = counterOfRecBytes;
counterOfRecBytes += sp.BytesToRead;
sp.Read(bArray, previouse, (counterOfRecBytes - previouse));
if (counterOfRecBytes == 8*numberOfSamples+4)
{
for(uint i = 1; i < 2*numberOfSamples+1; i++)
{
// if (freqList.Count == numberOfSamples) freqList.Clear();
// if (magList.Count == numberOfSamples) magList.Clear();
fArray[i-1] = ByteToFloat(bArray, i);
if (i < numberOfSamples+1) freqList.Add(fArray[i]);
else magList.Add(fArray[i-1]);
}
//ListToArray();
ChartData();
// if (counterOfRecBytes >= 8 * numberOfSamples + 4) sp.DiscardInBuffer();
counterOfRecBytes = 0;
}
}
/// <summary>
/// Changes my recieved bArray to single precision floats
/// </summary>
private float ByteToFloat(byte[] input, UInt32 i)
{
byte[] array = new[] { input[4 * i], input[4 * i + 1], input[4 * i + 2], input[4 * i + 3] };
return BitConverter.ToSingle(array, 0);
}
/// <summary>
/// Setting chart data
/// </summary>
private void ChartData()
{
for (int i = 0; i < numberOfSamples; i++)
{
chart1.Series["Widmo"].Points.AddXY(freqList[i], magList[i]);
}
}
}
Problem solved - what I had to do was putting code below in place of just calling ChartData method:
if (InvokeRequired)
{
Invoke(new MethodInvoker(ChartData));
}
else
{
ChartData();
}