// Called when the x-axis selection is changed. Updates the plotting mapper also
        private void OnXAxisSelectionChanged(object sender, EventArgs e)
        {
            currentXAxis = (ControlEnums.AXISOPTIONS)FindSelectedTextInEnum(XAxisSelectionBox.Text, typeof(ControlEnums.AXISOPTIONS));

            // Populate the unit selection box with available units
            XAxisUnitSelectionBox.Items.Clear();
            foreach (Enum unit in Enum.GetValues(ControlEnums.GetAttribute(currentXAxis).units.GetType()))
            {
                XAxisUnitSelectionBox.Items.Add(ControlEnums.GetAttribute(unit).disp);
            }
            XAxisUnitSelectionBox.SelectedIndex = 0;

            // Update mapper based on selected axis and unit
            if (currentXAxis == ControlEnums.AXISOPTIONS.TIME)
            {
                CalculateTimeUnitConversion(series1Mapper, (ControlEnums.TIMEUNITS)currentXAxisUnit, true);
            }
            else if (currentXAxis == ControlEnums.AXISOPTIONS.VOLTAGE)
            {
                CalculateVoltageUnitConversion(series1Mapper, (ControlEnums.VOLTAGEUNITS)currentXAxisUnit, true);
            }
            else
            {
                CalculateBaseUnitConversion(series1Mapper, currentXAxis, (ControlEnums.BASEUNITS)currentXAxisUnit, true);
            }
            WipeGraph();
        }
 // Searches an enum for a specific display attribute
 private Enum FindSelectedTextInEnum(string text, Type enumType)
 {
     foreach (Enum e in Enum.GetValues(enumType))
     {
         if (text == ControlEnums.GetAttribute(e).disp)
         {
             return(e);
         }
     }
     return(null);
 }
 // Called when the acceleration unit selection is changed
 private void OnAccelerationUnitSelectionChanged(object sender, EventArgs e)
 {
     foreach (ControlEnums.BASEUNITS unit in Enum.GetValues(typeof(ControlEnums.BASEUNITS)))
     {
         if (CurrentAccelerationUnitSelectionBox.Text == ControlEnums.GetAttribute(unit).disp)
         {
             currentAccelerationUnit = unit;
             break;
         }
     }
     WriteMessage("Selected Acceleration Unit updated to " + ControlEnums.GetAttribute(currentAccelerationUnit).disp);
 }
        // Called when the y-axis 2 unit selection changes. Updates the plotting mapper also
        private void OnYAxis2UnitSelectionChanged(object sender, EventArgs e)
        {
            currentYAxis2Unit = FindSelectedTextInEnum(YAxis2UnitSelectionBox.Text, ControlEnums.GetAttribute(currentYAxis2).units.GetType());

            // Update mapper based on selected unit
            if (currentYAxis2 == ControlEnums.AXISOPTIONS.TIME)
            {
                CalculateTimeUnitConversion(series2Mapper, (ControlEnums.TIMEUNITS)currentYAxis2Unit, false);
            }
            else if (currentYAxis2 == ControlEnums.AXISOPTIONS.VOLTAGE)
            {
                CalculateVoltageUnitConversion(series2Mapper, (ControlEnums.VOLTAGEUNITS)currentYAxis2Unit, false);
            }
            else
            {
                CalculateBaseUnitConversion(series2Mapper, currentYAxis2, (ControlEnums.BASEUNITS)currentYAxis2Unit, false);
            }
            WipeGraph();
        }
        /*==================================================== OPERATION MODES ====================================================*/

        // Called when the data mode selection is changed, updates the current data mode
        private void OnDataModeSelectionChanged(object sender, EventArgs e)
        {
            foreach (ControlEnums.DATAMODE dataMode in Enum.GetValues(typeof(ControlEnums.DATAMODE)))
            {
                if (DataModeSelectionBox.Text == ControlEnums.GetAttribute(dataMode).disp)
                {
                    currentDataMode = dataMode;
                    break;
                }
            }
            WriteMessage("Selected data mode updated to " + ControlEnums.GetAttribute(currentDataMode).disp);

            if (currentDataMode == ControlEnums.DATAMODE.MANUAL)
            {
                PositionIntegerUpDown.ReadOnly = false;
            }
            else
            {
                PositionIntegerUpDown.ReadOnly = true;
            }
        }
        // Called when the y-axis 2 selection changes. Updates the plotting mapper also
        private void OnYAxis2SelectionChanged(object sender, EventArgs e)
        {
            currentYAxis2 = (ControlEnums.AXISOPTIONS)FindSelectedTextInEnum(YAxis2SelectionBox.Text, typeof(ControlEnums.AXISOPTIONS));

            // Populate unit selection box with available units
            YAxis2UnitSelectionBox.Items.Clear();
            foreach (Enum unit in Enum.GetValues(ControlEnums.GetAttribute(currentYAxis2).units.GetType()))
            {
                YAxis2UnitSelectionBox.Items.Add(ControlEnums.GetAttribute(unit).disp);
            }
            YAxis2UnitSelectionBox.SelectedIndex = 0;

            // Update mapper based on selected axis and unit
            if (currentYAxis2 == ControlEnums.AXISOPTIONS.TIME)
            {
                CalculateTimeUnitConversion(series2Mapper, (ControlEnums.TIMEUNITS)currentYAxis2Unit, false);
            }
            else if (currentYAxis2 == ControlEnums.AXISOPTIONS.VOLTAGE)
            {
                CalculateVoltageUnitConversion(series2Mapper, (ControlEnums.VOLTAGEUNITS)currentYAxis2Unit, false);
            }
            else
            {
                CalculateBaseUnitConversion(series2Mapper, currentYAxis2, (ControlEnums.BASEUNITS)currentYAxis2Unit, false);
            }

            if (currentYAxis2 == ControlEnums.AXISOPTIONS.ACCELERATION && Series2EnabledCheckbox.Checked)
            {
                Chart.Series.Add(setLine3);
            }
            else if (Chart.Series.Contains(setLine3))
            {
                Chart.Series.Remove(setLine3);
            }
            WipeGraph();
        }
        public GraphingForm()
        {
            InitializeComponent();
            MainInterface.graphingOpen = true;

            // Populate the axes selection boxes
            foreach (ControlEnums.AXISOPTIONS axis in Enum.GetValues(typeof(ControlEnums.AXISOPTIONS)))
            {
                XAxisSelectionBox.Items.Add(ControlEnums.GetAttribute(axis).disp);
                YAxis1SelectionBox.Items.Add(ControlEnums.GetAttribute(axis).disp);
                YAxis2SelectionBox.Items.Add(ControlEnums.GetAttribute(axis).disp);
            }
            XAxisSelectionBox.SelectedIndex  = 0;
            YAxis1SelectionBox.SelectedIndex = 3;
            YAxis2SelectionBox.SelectedIndex = 4;

            // Create the mappers for the 3 series
            series1Mapper = Mappers.Xy <GraphingEntry>().X(entry => entry.uptime / 1000.0).Y(entry => entry.position);
            series2Mapper = Mappers.Xy <GraphingEntry>().X(entry => entry.uptime / 1000.0).Y(entry => entry.velocity);
            lineMapper    = Mappers.Xy <GraphingLine>().X(line => line.uptime / 1000.0).Y(line => line.y);

            series1 = new LineSeries(series1Mapper)
            {
                Values = series1Values, PointGeometrySize = 2, StrokeThickness = 2, Fill = System.Windows.Media.Brushes.Transparent
            };
            series2 = new LineSeries(series2Mapper)
            {
                Values = series2Values, PointGeometrySize = 2, StrokeThickness = 2, Fill = System.Windows.Media.Brushes.Transparent
            };
            setLine1 = new LineSeries(lineMapper)
            {
                Values = setLine1Values, PointGeometrySize = 2, StrokeThickness = 2, Fill = System.Windows.Media.Brushes.Transparent,
                Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 33, 149, 242)), StrokeDashArray = new System.Windows.Media.DoubleCollection {
                    2
                }
            };
            setLine2 = new LineSeries(lineMapper)
            {
                Values = setLine2Values, PointGeometrySize = 2, StrokeThickness = 2, Fill = System.Windows.Media.Brushes.Transparent,
                Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 243, 67, 54)), StrokeDashArray = new System.Windows.Media.DoubleCollection {
                    2
                }
            };
            setLine3 = new LineSeries(lineMapper)
            {
                Values = setLine3Values, PointGeometrySize = 2, StrokeThickness = 2, Fill = System.Windows.Media.Brushes.Transparent,
                Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 243, 67, 54)), StrokeDashArray = new System.Windows.Media.DoubleCollection {
                    2
                }
            };

            // Create the chart series
            Chart.Series = new SeriesCollection {
                series1, series2, setLine1, setLine2
            };

            // Chart option setup
            Chart.DisableAnimations = true;
            //Chart.Hoverable = false;
            Chart.DataTooltip = null;
            series1Values.WithQuality(Quality.Medium);
            series2Values.WithQuality(Quality.Medium);
            setLine1Values.WithQuality(Quality.Low);
            setLine2Values.WithQuality(Quality.Low);
            setLine3Values.WithQuality(Quality.Low);

            pictureBox1.BackColor   = Color.FromArgb(255, 33, 149, 242);
            pictureBox2.BackColor   = Color.FromArgb(255, 243, 67, 54);
            GraphPeriodTextBox.Text = (double)(DataPointsUpDown.Value * (MainInterface.instance.ProgramLoopTimer.Interval / 1000.0m)) + " s";
        }
        // Interface intiialization method
        public MainInterface()
        {
            Debug.WriteLine("Servo Motor Driver Starting Up...");
            InitializeComponent();
            instance = this;

            /* Start the uptime stopwatch, which records system uptime */
            uptimeSW.Start();

            /*==================================================== THREADS ====================================================*/
            // Start the communication thread to communicate with the arduino at a specified rate
            commsThread = new Thread(new ThreadStart(Communicate));
            commsThread.Start();

            /*==================================================== COMBO-BOXES ====================================================*/
            // Add the DATAMODE enums to the dropdown data mode selection box
            foreach (ControlEnums.DATAMODE dataMode in Enum.GetValues(typeof(ControlEnums.DATAMODE)))
            {
                DataModeSelectionBox.Items.Add(ControlEnums.GetAttribute(dataMode).disp);
            }
            DataModeSelectionBox.SelectedIndex = 0;
            WriteMessage("Added Data Mode Selection Options");

            // Add the POSITIONUNITS enums to the dropdown position unit selection box
            foreach (ControlEnums.BASEUNITS unit in Enum.GetValues(typeof(ControlEnums.BASEUNITS)))
            {
                CurrentPositionUnitSelectionBox.Items.Add(ControlEnums.GetAttribute(unit).disp);
            }
            CurrentPositionUnitSelectionBox.SelectedIndex = 0;
            WriteMessage("Added Position Unit Selection Options");

            // Add the VELOCITYUNTIS enums to the dropdown velocity unit selection box
            foreach (ControlEnums.BASEUNITS unit in Enum.GetValues(typeof(ControlEnums.BASEUNITS)))
            {
                CurrentVelocityUnitSelectionBox.Items.Add(ControlEnums.GetAttribute(unit).disp);
            }
            CurrentVelocityUnitSelectionBox.SelectedIndex = 0;
            WriteMessage("Added Velocity Unit Selection Options");

            // Add the ACCELERATIONUNITS enums to the dropdown acceleration unit selection box
            foreach (ControlEnums.BASEUNITS unit in Enum.GetValues(typeof(ControlEnums.BASEUNITS)))
            {
                CurrentAccelerationUnitSelectionBox.Items.Add(ControlEnums.GetAttribute(unit).disp);
            }
            CurrentAccelerationUnitSelectionBox.SelectedIndex = 0;
            WriteMessage("Added Acceleration Unit Selection Options");

            // Add available COM ports to the dropdown port selection box
            COMPortSelectionBox.DataSource = SerialPort.GetPortNames();
            WriteMessage("Added COM Port Selection Options");

            /*==================================================== INITIAL VALUES ====================================================*/
            // Set NumericUpDown Bounds
            VoltageControlUpDown.Maximum = CalculateVoltageFromBinary(binaryMax);
            VoltageControlUpDown.Minimum = CalculateVoltageFromBinary(binaryMin);
            BinaryControlUpDown.Value    = CalculateBinaryFromVoltage(0m);

            OutputsGroupBox.Font = new Font("Microsoft Sans-Serif", 12, FontStyle.Bold);

            // Add Circle plot stuff
            InitializeCirclePlot();
        }