none
System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.' RRS feed

  • Question

  • Hello everyone,

    I try to develop an application that communicate with HID device I got System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.' error. Here is my codes:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using CyUSB;
    using System.Threading;
    
    namespace EGI
    {
        public partial class EGI_Main : Form
        {
            // *********************** START OF PROGRAM MAIN ****************************** //
    
            USBDeviceList usbDevices = null;            // Pointer to list of USB devices
            CyHidDevice myHidDevice = null;             // Handle of USB device
    
            int VID = 0x04B4;                           // Cypress Vendor ID
            int PID = 0xE177;                           // Example Project Product ID
    
            bool communicate = false;                   // Communication status
    
            byte que = 00;                              // Command Byte
            byte PGAValue = 02;                         // PGA
            byte[] receivedDatas = new byte[128];       // Byte array to store 128 bytes of received data from device
    
            /**********************************************************************
            * NAME: EGI - Ekin Generic HID Communication Interface
            *
            * DESCRIPTION: Main function called initially upon the starting of the
            * application. Used to un-initialized variables, the GUI application, register
            * the event handlers, and check for a connected device.
            *
            ***********************************************************************/
    
            public EGI_Main()
            {
                CheckForIllegalCrossThreadCalls = false;
                InitializeComponent();
                // Create a list of CYUSB devices for this application
                usbDevices = new USBDeviceList(CyConst.DEVICES_HID);
                //Add event handlers for device attachment and device removal
                usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
                usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);
                //Connect to the USB device
                GetDevice();
            }
    
            /**********************************************************************
            * NAME: EGI_Main_Load
            *
            * DESCRIPTION: Loads and sets necessary companents and settings on start.
            *
            ***********************************************************************/
    
            private void EGI_Main_Load(object sender, EventArgs e)
            {
                // Real data graph settings
                chartResult.ChartAreas[0].AxisX.ScaleView.Zoom(0, 127);
                chartResult.ChartAreas[0].AxisY.ScaleView.Zoom(0, 255);
                chartResult.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
                chartResult.Series[0].Color = Color.Black;
                chartResult.Series[0].BorderWidth = 3;
    
                // On line average result graph settings
                chartResult.Series.Add("onLineAvg");
                chartResult.Series["onLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
                chartResult.Series["onLineAvg"].Color = Color.Red;
                chartResult.Series["onLineAvg"].BorderWidth = 3;
    
                // Multipline with on line average result graph settings
                chartResult.Series.Add("multOnLineAvg");
                chartResult.Series["multOnLineAvg"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
                chartResult.Series["multOnLineAvg"].Color = Color.Navy;
                chartResult.Series["multOnLineAvg"].BorderWidth = 3;
    
                // Exceed point(s) graph settings
                chartResult.Series.Add("exceed");
                chartResult.Series["exceed"].Color = Color.Brown;
                chartResult.Series["exceed"].BorderWidth = 3;
    
                for(int i = 0; i < 128; i++)
                {
                    chartResult.Series[0].Points.AddXY(i, 0);
                    chartResult.Series["onLineAvg"].Points.AddXY(i, 0);
                    chartResult.Series["multOnLineAvg"].Points.AddXY(i, 0);
                }
            }
    
            /**********************************************************************
            * NAME: usbDevices_DeviceRemoved
            *
            * DESCRIPTION: Event handler for the removal of a USB device. When the removal
            * of a USB device is detected, this function will be called which will check to
            * see if the device removed was the device we were using. If so, then reset
            * device handler (myHidDevice), disable the timer, and update the GUI.
            *
            ***********************************************************************/
    
            public void usbDevices_DeviceRemoved(object sender, EventArgs e)
            {
                USBEventArgs usbEvent = e as USBEventArgs;
                if ((usbEvent.ProductID == PID) && (usbEvent.VendorID == VID))
                {
                    InputTimer.Enabled = false; // Disable interrupts for polling HID
                    myHidDevice = null;
                    GetDevice(); // Process device status
                }
            }
    
            /**********************************************************************
            * NAME: usbDevices_DeviceAttached
            *
            * DESCRIPTION: Event handler for the attachment of a USB device. The function
            * first checks to see if a matching device is already connected by seeing
            * if the handler (myHidDevice) is null. If no device is previously attached,
            * the function will call GetDevice to check and see if a matching device was
            * attached.
            *
            ***********************************************************************/
    
            public void usbDevices_DeviceAttached(object sender, EventArgs e)
            {
                if (myHidDevice == null)
                {
                    GetDevice(); // Process device status
                }
            }
    
            /**********************************************************************
            * NAME: GetDevice
            *
            * DESCRIPTION: Function checks to see if a matching USB device is attached
            * based on the VID and PID provided in the application. When a device is
            * found, it is assigned a handler (myHidDevice) and the GUI is updated to
            * reflect the connection. Additionally, if the device is not connected,
            * the function will update the GUI to reflect the disconnection.
            *
            ***********************************************************************/
            public void GetDevice()
            {
                //Look for device matching VID/PID
                myHidDevice = usbDevices[VID, PID] as CyHidDevice;
                if (myHidDevice != null) //Check to see if device is already connected
                {
                    Status.Text = "Connected";
                    Status.ForeColor = Color.Green;
                    InputTimer.Enabled = true; //Enable background timer
                }
                else
                {
                    Status.Text = "Disconnected";
                    Status.ForeColor = Color.Red;
                }
            }
            
            /**********************************************************************
            * NAME: Set_VidPid_Click
            *
            * DESCRIPTION: Updates the applications Vendor ID and Product ID based on
            * user input when the “Set” button is clicked. This will cause the default VID
            * and PID of 0x04B4 and 0xE177 to be overwritten. The function will then
            * call GetDevice() to check for matching USB device.
            *
            ***********************************************************************/
            private void Set_VidPid_Click(object sender, EventArgs e)
            {
                //Respond to update of VID and PID value by pressing the “Set” button
                VID = Convert.ToInt32(VidTextBox.Text, 16);
                PID = Convert.ToInt32(PidTextBox.Text, 16);
                GetDevice();
            }
    
            /**********************************************************************
            * NAME: receive_Click
            *
            * DESCRIPTION: Starts and stops communication with device.
            *
            ***********************************************************************/
    
            private void receive_Click(object sender, EventArgs e)
            {
                if (communicate)
                {
                    communicate = false;
                    receive.Text = "Communicate";
                    receive.BackColor = Color.White;
                    receive.ForeColor = Color.Black;
                }
                else
                {
                    communicate = true;
                    receive.Text = "Stop";
                    receive.BackColor = Color.Red;
                    receive.ForeColor = Color.White;
                    que = 00;
                    backgroundWorkerGetAndProcessData.RunWorkerAsync();
                }
            }
    
            /**********************************************************************
            * NAME: communicateNow
            *
            * DESCRIPTION:Sends commands to device.
            *
            ***********************************************************************/
    
            private void communicateNow()
            {
                if (communicate)
                {
                    // Load data into Output Buffer
                    myHidDevice.Outputs.DataBuf[0] = 00;                                    // Report ID
                    myHidDevice.Outputs.DataBuf[1] = (byte)numericUpDownThreshold.Value;    // Threshold
                    myHidDevice.Outputs.DataBuf[2] = (byte)numericUpDownPB.Value;           // PB
                    myHidDevice.Outputs.DataBuf[3] = PGAValue;                              // PGA
                    myHidDevice.Outputs.DataBuf[4] = 87;                                    // W/R
                    myHidDevice.Outputs.DataBuf[5] = que;                                   // Command byte
                    myHidDevice.Outputs.DataBuf[6] = 00;
                    myHidDevice.Outputs.DataBuf[7] = 00;
                    myHidDevice.Outputs.DataBuf[8] = 00;
                    myHidDevice.Outputs.DataBuf[9] = 00;
    
                    // Function call to send data to device
                    myHidDevice.WriteOutput();
                    // Function call to receive data from device
                    myHidDevice.ReadInput();
    
                    byte[] tempData = myHidDevice.Inputs.DataBuf;
    
                    for (int i = 2; i < myHidDevice.Inputs.DataBuf.Length - 1; i++)
                    {
                        if (que == 0)
                            receivedDatas[i - 2] = tempData[i];
                        else if (que == 1)
                            receivedDatas[32 + i - 2] = tempData[i];
                        else if (que == 2)
                            receivedDatas[64 + i - 2] = tempData[i];
                        else if (que == 3)
                            receivedDatas[96 + i - 2] = tempData[i];
                    }
    
                    if (que < 03)
                    {
                        que++;
                        communicateNow();
                    }
                    else
                    {
                        que = 00;
                    }
                }
            }
            
    
            /**********************************************************************
            * NAME: dataProcess
            *
            * DESCRIPTION: Regroup the datas, writes them to specific textboxes and
            * calls calculateAndDrawGraph to calculate and draw graph.
            *
            ***********************************************************************/
    
            private void dataProcess()
            {
                byte[] realDatas = receivedDatas;
                bool highLightPower = false;
                bool lowLightPower = false;
    
                // Clear textboxes
                receivedData_00.Text = null;
                receivedData_01.Text = null;
                receivedData_02.Text = null;
                receivedData_03.Text = null;
    
                // Count datas to separate to textboxes
                int countOfDatas = 0;
    
                // Write all datas to specified textboxes
                for(int i = 0; i < realDatas.Length; i++)
                {
                    if (countOfDatas < 32)
                        receivedData_00.AppendText(realDatas[i] + " - ");
                    else if (countOfDatas < 64)
                        receivedData_01.AppendText(realDatas[i] + " - ");
                    else if (countOfDatas < 96)
                        receivedData_02.AppendText(realDatas[i] + " - ");
                    else if (countOfDatas < 128)
                        receivedData_03.AppendText(realDatas[i] + " - ");
    
                    // Check whether light power is high or low.
                    if (realDatas[i] >= 190)
                        highLightPower = true;
                    else if (realDatas[i] <= 25)
                        lowLightPower = true;
    
                    countOfDatas++;
                }
    
                if (highLightPower)
                {
                    labelLightPower.BackColor = Color.Red;
                    labelLightPower.ForeColor = Color.White;
                    labelLightPower.Text = "Decrease";
                }
                else if (lowLightPower)
                {
                    labelLightPower.BackColor = Color.Yellow;
                    labelLightPower.ForeColor = Color.Black;
                    labelLightPower.Text = "Increase";
                }
                else
                {
                    labelLightPower.BackColor = Color.Green;
                    labelLightPower.ForeColor = Color.White;
                    labelLightPower.Text = "";
                }
    
            }
    
            /**********************************************************************
            * NAME: calculateAndDrawGraph
            *
            * DESCRIPTION: Calculates averages and draws their graphs. Recall 
            * communicateNow() to receive new datas.
            *
            ***********************************************************************/
    
            private void calculateAndDrawGraph()
            {
                byte[] realDatas = receivedDatas;
                byte[] onLineAvg = new byte[128];
                byte[] multOnLineAvg = new byte[128];
                int onLineAvgMidPoint = (int)SampleCount.Value / 2;
                int multOnLineAvgMidPoint = (int)(SampleCount.Value * multUD.Value) / 2;
    
                // Clear graph
                chartResult.Series[0].Points.Clear();
                chartResult.Series["onLineAvg"].Points.Clear();
                chartResult.Series["multOnLineAvg"].Points.Clear();
    
                for(int i = 0; i < (127 - SampleCount.Value); i++)
                {
                    for (int j = i; j < (i + (SampleCount.Value)); j++)
                    {
                        onLineAvg[onLineAvgMidPoint] += Convert.ToByte(realDatas[j] / (int)(SampleCount.Value));
                    }
                    if(i<(127 - SampleCount.Value * multUD.Value))
                    {
                        for (int j = i; j < (i + (SampleCount.Value * multUD.Value)); j++)
                        {
                            multOnLineAvg[multOnLineAvgMidPoint] += Convert.ToByte(realDatas[j] / (int)(SampleCount.Value * multUD.Value));
                        }
                    }
                    onLineAvgMidPoint++;
                    multOnLineAvgMidPoint++;
                }
    
                for (int i = 0; i < 128; i++)
                {
                    chartResult.Series[0].Points.AddXY(i, realDatas[i]);
                    chartResult.Series["onLineAvg"].Points.AddXY(i, onLineAvg[i]);
                    chartResult.Series["multOnLineAvg"].Points.AddXY(i, multOnLineAvg[i]);
                }
    
                Thread.Sleep(900);
            }
    
            /**********************************************************************
            * NAME: radioButton_CheckedChanged
            *
            * DESCRIPTION: Sets PGAValue.
            *
            ***********************************************************************/
    
            private void radioButton_CheckedChanged(object sender, EventArgs e)
            {
                if (radioButton1.Checked)
                    PGAValue = 01;
                else if (radioButton2.Checked)
                    PGAValue = 02;
                else if (radioButton4.Checked)
                    PGAValue = 04;
                else if (radioButton8.Checked)
                    PGAValue = 08;
            }
    
            /**********************************************************************
            * NAME: backgroundWorkerGetAndProcessData_DoWork
            *
            * DESCRIPTION: Starts background worker to get data and process them.
            *
            ***********************************************************************/
    
            private void backgroundWorkerGetAndProcessData_DoWork(object sender, DoWorkEventArgs e)
            {
                Thread communicate = new Thread(new ThreadStart(communicateNow));
                communicate.Start();
                communicate.Join(10);
                Thread dataPro = new Thread(new ThreadStart(dataProcess));
                dataPro.Start();
                dataPro.Join(20);
                Thread calcAndDrawGraph = new Thread(new ThreadStart(calculateAndDrawGraph));
                calcAndDrawGraph.Start();
                calcAndDrawGraph.Join(30);
            }
    
            /**********************************************************************
            * NAME: backgroundWorkerGetAndProcessData_RunWorkerCompleted
            *
            * DESCRIPTION: Recalls background worker to get data and process them.
            *
            ***********************************************************************/
    
            private void backgroundWorkerGetAndProcessData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                backgroundWorkerGetAndProcessData.RunWorkerAsync();
            }
        }
    }
    

    Could anyone helps?

    Thursday, January 4, 2018 1:34 PM

All replies

  • Hi Ali Dayan,

    Thank you for posting here.

    For your question, I try to test your code. I could not reproduce your exception. If it is possible, please upload your project on OneDrive for us to test.

    Which line you get the exception? Please provide more details.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, January 8, 2018 8:40 AM
    Moderator