コード例 #1
0
        private void FG_SaveWaveformParameters_Click(object sender, RoutedEventArgs e)
        {
            memoryLocationSelected = (string)WaveformList.SelectedItem;    // the data stored in WaveformList will always be strings
            WaveformFile current    = fileDataMap[memoryLocationSelected]; // get the waveformFileStruct from the selected memory location
            double       sampleRate = double.Parse(WaveformSampleRate.Text);

            if (sampleRate == 0)                                         // don't let the user set the sample rate to 0 Hz.
            {
                WaveformSampleRate.Text = current.SampleRate.ToString(); // just have it set back to what is was before if they try to put in 0
            }
            else
            {
                current.SampleRate = sampleRate;                                  // else set the sample rate to what they put in
            }
            double scaleFactor = double.Parse(WaveformAmplitudeScaleFactor.Text); // get the user set scale factor by parsing the textbox text

            if (scaleFactor != current.ScaleFactor)                               // if the scalefactor parsed from the text box doesn't match the one in the WaveformFile
            {
                // then the user has changed the scale factor
                FG_ScaleAmplitude(current, scaleFactor);
                current.ScaleFactor = scaleFactor;  // and then update the scale factor saved in the WaveformFile
            }
            current.IsUploaded = false;
            ListBoxItem item = WaveformList.ItemContainerGenerator.ContainerFromItem(WaveformList.SelectedItem) as ListBoxItem;

            item.Background = Brushes.Gold;  // set the color back to gold to signal that the waveform is saved but is not uploaded.
            // the user will have to click upload again to see changes.
        }
コード例 #2
0
        // Draws the waveform contained in the given WaveformFile on the app's graph canvas
        private void FG_DrawWaveformGraph(WaveformFile wave)
        {
            int length;

            FGWaveformGraphDataLine.Points.Clear();
            if (wave == null || wave.FileName == null)  // if there's nothing actually saved in the current waveform, just draw the reference
                                                        // line for 0V and then return
            {
                FGWaveformGraphZeroLine.Points.Clear();
                FGWaveformGraphZeroLine.Points.Add(new DataPoint(0, 0));
                FGWaveformGraphZeroLine.Points.Add(new DataPoint(FGWaveformPlot.ActualWidth, 0));
                FGWaveformPlot.Model.InvalidatePlot(true);
                return;
            }
            if (wave.Voltages.Length > 1000)
            {
                length = 1000;
            }
            else
            {
                length = wave.Voltages.Length;
            }
            FGWaveformGraphZeroLine.Points.Clear();
            FGWaveformGraphZeroLine.Points.Add(new DataPoint(0, 0));
            FGWaveformGraphZeroLine.Points.Add(new DataPoint(length, 0));
            for (int i = 0; i < length; i++)
            {
                FGWaveformGraphDataLine.Points.Add(new DataPoint(i, wave.Voltages[i]));
            }
            FGWaveformPlot.Model.InvalidatePlot(true);
            if (openingFile)                   // if we're in file opening mode
            {
                WaveformList.IsEnabled = true; // it's best just to wait until the graph is drawn.
            }
        }
コード例 #3
0
 private void FG_LoadWaveformCallback()
 {
     loading = false;                                                       // disable the loading flag
     currentWaveform.ChannelsLoadedTo.Add(functionGeneratorChannelInFocus); // add the current channel to the current waveform's set
                                                                            // of channels it's loaded to
                                                                            // signal the UI thread to update the state of the elements
     Application.Current.Dispatcher.Invoke(() =>
     {
         memoryLocationSelected = (string)WaveformList.SelectedItem;   // the data stored in WaveformList will always be strings
         WaveformFile temp      = fileDataMap[memoryLocationSelected]; // get the waveformFileStruct from the selected memory location
         if (temp.IsUploaded)
         {
             LoadWaveformButton.IsEnabled = true;  // we ungray out the load button once complete
         }
         if (temp.ChannelsLoadedTo.Contains(functionGeneratorChannelInFocus))
         {
             PlayWaveform.IsEnabled = true;  // The loading is complete, so we ungray out the button
         }
         if (temp.FileName != null)
         {
             UploadWaveform.IsEnabled = true;                // re-enable the upload button
         }
         WaveformLoadMessage.Visibility = Visibility.Hidden; // hide the "waveform loading please wait" message
     });
 }
コード例 #4
0
 private void FG_WaveformUploadedCallback()
 {
     // signal the UI thread to update the following UI elements
     Application.Current.Dispatcher.Invoke(() => {
         memoryLocationSelected = (string)WaveformList.SelectedItem;   // the data stored in WaveformList will always be strings
         WaveformFile temp      = fileDataMap[memoryLocationSelected]; // get the waveformFileStruct from the selected memory location
         if (temp.IsUploaded)                                          // this stops the load button from enabling if the user switched waveforms during the upload process
         {
             LoadWaveformButton.IsEnabled = true;                      // only once the uploading is complete do
         }
         // we re-enable the button to load the waveform
         UploadWaveform.IsEnabled                = true;              // and the button to upload another one
         WaveformUploadMessage.Visibility        = Visibility.Hidden; // hide the "uploading waveform please wait" message
         EditWaveformParameterCheckbox.IsEnabled = true;              // enable the edit waveform parameter checkbox
     });
     uploading = false;                                               // turn off the uploading flag
 }
コード例 #5
0
        private void FG_EditWaveformParameterCheckbox_UnChecked(object sender, RoutedEventArgs e)
        {
            WaveformSampleRate.IsReadOnly           = true;
            SaveWaveformParameters.IsEnabled        = false;            // disable the save waveform parameters button
            WaveformSampleRate.IsEnabled            = false;            // disable the input
            WaveformAmplitudeScaleFactor.IsEnabled  = false;
            WaveformAmplitudeScaleFactor.IsReadOnly = true;             // make the scale factor textbox read only
            memoryLocationSelected = (string)WaveformList.SelectedItem; // the data stored in WaveformList will always be strings
            WaveformFile temp = fileDataMap[memoryLocationSelected];    // get the waveformFileStruct from the selected memory location

            WaveformSampleRate.Text           = temp.SampleRate.ToString();
            WaveformAmplitudeScaleFactor.Text = temp.ScaleFactor.ToString();
            if (ScalingErrorLabel.Visibility == Visibility.Visible) // if there was an error when the user unchecks the box
            {
                WaveformAmplitudeScaleFactor.Text = "1";            // just set everything back to 1
                temp.ScaleFactor = 1;
            }
            ScalingErrorLabel.Visibility = Visibility.Hidden;  // then hide the error
        }
コード例 #6
0
        private void FG_UploadWaveform_Click(object sender, RoutedEventArgs e)
        {
            uploading = true;                                      // we can block other UI things from happening. i.e. switching to channel 2 and then back could in some
                                                                   // cases re-activate disabled buttons, and then allow the user to do strange things.
            WaveformUploadMessage.Visibility = Visibility.Visible; // show the "uploading waveform please wait" message
            // UPLOADING WILL BE DONE IN A SEPERATE THREAD
            WaveformFile data = currentWaveform;

            EditWaveformParameterCheckbox.IsEnabled = false; // disable the edit waveform parameter checkbox
            currentWaveform.ChannelsLoadedTo.Clear();        // when a new waveform is uploaded, it won't be loaded to any channel
            PlayWaveform.IsEnabled = false;                  // we know that this is false because we've cleared everything. This just saves us the trouble
                                                             // of forcing an update.
            LoadWaveformButton.IsEnabled = false;
            // these are all non-channel specific, however should probably
            // stop the user from loading a waveform while the waveform is uploading
            // that could result in the user loading the previous waveform stored in that location, and then overwriting it with the
            // parameters of the new one, while keeping the waveform the same. This could result in a DC offset and H2 production.

            UploadWaveform.IsEnabled = false;  // disable the upload waveform button. If the user spam clicks it, then we have a problem
            double[] voltages    = data.Voltages;
            double   SampleRate  = data.SampleRate;
            string   memLocation = string.Copy((string)WaveformList.SelectedItem);

            // on button click, upload the waveform to the function generator
            //ThreadPool.QueueUserWorkItem(ThreadProc);
            ThreadPool.QueueUserWorkItem(lamdaThing => {
                try
                {  // again we can't use lowLevel and highLevel here because of the way that amplitude scaling works.
                    // if all this parallelism causes CPU bottleneck I could store the scaled min and max as well, or just
                    // have it multiply the original high/low levels by the scaling factor.
                    // actually that's not a bad plan.
                    fg.UploadWaveformData(voltages, SampleRate, (data.ScaleFactor * (data.HighLevel + data.LowLevel)) / 2, 0, memLocation);
                }
                finally
                {
                    FG_WaveformUploadedCallback();
                }
            });
            ListBoxItem item = WaveformList.ItemContainerGenerator.ContainerFromItem(WaveformList.SelectedItem) as ListBoxItem;

            item.Background            = Brushes.Green; // set the background so the user knows that the waveform has been uploaded
            currentWaveform.IsUploaded = true;          // stuff uses this flag
        }
コード例 #7
0
        private void FG_ScaleAmplitude(WaveformFile fileToScale, double scaleFactor)
        {
            double[] originalVoltages = fileToScale.OriginalVoltages; // get the unscaled voltage array

            if (scaleFactor.Equals(1))                                // for sanity, using the .Equals() method
            {
                fileToScale.Voltages = fileToScale.OriginalVoltages;  // set the voltage reference in the WaveformFile to be the original
                // voltages if the user sets the scale factor to 1.
                FG_DrawWaveformGraph();                               // draw the graph, can't forget that
                ScalingErrorLabel.Visibility = Visibility.Hidden;
                return;                                               // then we're done.
            }
            // better to do this checking before we start processing rather than having the API throw an error after we've done all of the work.
            if (fileToScale.HighLevel * scaleFactor > maximumAllowedAmplitude / 2)
            {
                ScalingErrorLabel.Visibility = Visibility.Visible;  // show the scaling error label
                return;
            }
            if (fileToScale.LowLevel * scaleFactor < -1 * (maximumAllowedAmplitude / 2))
            {
                // DO UI SIGNALING THAT SOMETHING IS WRONG
                ScalingErrorLabel.Visibility = Visibility.Visible;  // show the scaling error labelG
                return;
            }
            double[] scaledVoltages = fileToScale.ScaledVoltages; // get a reference to the scaled voltages in the WaveformFile
            ScalingErrorLabel.Visibility = Visibility.Hidden;
            if (scaledVoltages == null)                           // we only init the scaled voltages array when needed.
            {
                // dealing with the shifting around of references to counteract stuff is easier than trying to get the array inside that
                // WaveformFile to be passed by reference of reference.
                scaledVoltages = new double[originalVoltages.Length]; // it will (and must) always be
                // the same length as the original Voltage array
                fileToScale.ScaledVoltages = scaledVoltages;          // reference weirdness, pay no mind
            }
            Parallel.For(0, originalVoltages.Length, (i, state) => {
                scaledVoltages[i] = originalVoltages[i] * scaleFactor; // using a parallel for loop, iterate through each of the voltages and
                                                                       // multiply it by the scale factor before placing it in the scaled voltage array.
            });
            FG_RemoveDCOffset(scaledVoltages);                         // remove any DC offset this process created.
            fileToScale.Voltages = scaledVoltages;                     // change the reference to scaled voltages
            FG_DrawWaveformGraph();                                    // and then we redraw the graph so that the changes to the waveform show up immediately
        }
コード例 #8
0
ファイル: MainWindow.xaml.cs プロジェクト: uwgridlab/SALT-App
        public MainWindow()
        {
            calibration = false;
            uploading   = false;
            loading     = false;


            openingFile = false;                 // set the uploading flag

            functionGeneratorChannelInFocus = 1; // start with channel 1 in focus
            fileDataMap     = new Dictionary <string, WaveformFile>();
            currentWaveform = new WaveformFile();
            channelsPlaying = new HashSet <int>();
            cancelToken     = new CancellationTokenSource();
            AutoResetEvent autoEvent = new AutoResetEvent(false);

            // Generate configuration file if one does not exist:    (replace this in a future update to be more stable and make more sense)
            if (!File.Exists("config.cfg"))
            {
                File.WriteAllText("config.cfg", "#Replace USB with ENET to use ethernet connectivity, do not include spaces and do not remove this line!\nINTERFACE=USB");
                // a bit sketchy looking, but it works!
            }

            string[] configInput = File.ReadAllLines("config.cfg");
            string   interfaceConfig;

            if (configInput.Length > 0)  // if the file is just empty for some reason, use USB
            {
                interfaceConfig = configInput[1];
                if (interfaceConfig.Equals("INTERFACE=ENET"))  // don't crash on invalid config files (in the future alert the user), just use USB
                {
                    interfaceConfig = "ENET";
                }
                else
                {
                    interfaceConfig = "USB";
                }
            }
            else
            {
                interfaceConfig = "USB";
            }
            if (interfaceConfig.Equals("ENET"))
            {
                Thread.Sleep(1000); // it seems that in some VISA implementations that repeatedly spam-opening the application will cause timeout errors
                ENET_Constructor(); // this is a temporary fix to that. Also don't spam-open the application, wait a second or two before reopening.
                Thread.Sleep(1000);
            }
            else
            {
                USB_Constructor();
            }
            // at the end of both options, scope and fg are set and initialized for I/O operations



            // now we will read in that config file to see whether to use USB connection or over Ethernet, which means bringing up a seperate window



            idealNumScreenPoints    = scope.GetNumPointsPerScreenCapture(); // for graphing purposes
            oscilloscopeNumHorizDiv = scope.GetNumHorizontalDivisions();
            oscilloscopeNumVertDiv  = scope.GetNumVerticalDivisions();
            scope.Run();             // start the scope
            fg.SetAllOutputsOff();   // turn off all the outputs of the function generator
            scopeChannelInFocus = 1; // start with channel 1 in focus for the scope
            InitializeComponent();
            LogoImage.Source = new BitmapImage(new Uri("logo.png", UriKind.Relative));
            WaveformLoadMessage.Visibility   = Visibility.Hidden; // hide the "waveform loading please wait" message
            WaveformUploadMessage.Visibility = Visibility.Hidden; // hide the "uploading waveform please wait" message
                                                                  //  waveformGraph.Background = Brushes.Black;  // set the canvas background to black
            WaveformSampleRate.IsReadOnly           = true;       // make the sample rate textbox read only by default
            WaveformAmplitudeScaleFactor.IsReadOnly = true;       // make the scale factor textbox read only
            cancelFileOpen.Visibility = Visibility.Hidden;        // hide the button for canceling file upload
            UploadWaveform.IsEnabled  = false;                    // disable the button for uploading a waveform
            EditWaveformParameterCheckbox.IsEnabled = false;      // disable the edit waveform parameter checkbox
            LoadWaveformButton.IsEnabled            = false;      // disable the button for loading a waveform into active memory
            WaveformSampleRate.IsEnabled            = false;
            WaveformAmplitudeScaleFactor.IsEnabled  = false;
            OffsetErrorLabel.Visibility             = Visibility.Hidden; // hide the error label
            AmplitudeErrorLabel.Visibility          = Visibility.Hidden; // hide the amplitude error label
            OffsetErrorLabel.Foreground             = Brushes.Red;       // make the error text red
            AmplitudeErrorLabel.Foreground          = Brushes.Red;
            ScalingErrorLabel.Visibility            = Visibility.Hidden;
            ScalingErrorLabel.Foreground            = Brushes.Red;                             // make the error text red
            PlayWaveform.IsEnabled                  = false;                                   // disable the button for playing a waveform
            SaveWaveformParameters.IsEnabled        = false;                                   // disable the save waveform parameters button
            WaveformSaveInstructionLabel.Visibility = Visibility.Hidden;                       // hide the instruction label for saving waveform
            voltageOffsetScaleConstant              = scope.GetYAxisOffsetScaleConstant();
            triggerPositionScaleConstant            = scope.GetTriggerPositionScaleConstant(); // get the graph constants from the scope
            timeOffsetScaleConstant                 = scope.GetXAxisOffsetScaleConstant();
            SavingWaveformCaptureLabel.Visibility   = Visibility.Hidden;                       // hide the "saving waveform please wait" label
            showTriggerLine = false;                                                           // start by not showing the dashed line for the trigger
            double tempYScale = scope.GetYScale();

            VoltageOffsetSlider.Maximum = voltageOffsetScaleConstant * tempYScale;   // set the voltage slider max and min to whatever the max and min
            VoltageOffsetSlider.Minimum = -1 * VoltageOffsetSlider.Maximum;          // are when we boot up the scope
            TriggerSlider.Maximum       = triggerPositionScaleConstant * tempYScale; // trigger slider needs the same range as the offset slider
            TriggerSlider.Minimum       = -1 * TriggerSlider.Maximum;
            numOscilloscopeChannels     = scope.GetNumChannels();
            channelsToDisable           = new HashSet <int>();
            channelsToDraw = new HashSet <int>();                              // if a channel number is contained within this list, draw it
            channelsToDraw.Add(1);                                             // we enable graphing channel 1 by default
            channelGraphs           = new LineSeries[numOscilloscopeChannels]; // init the channelGraphs arrray
            voltageAxes             = new LinearAxis[numOscilloscopeChannels]; // get an axis for each input channel of the scope
            FGWaveformPlot.Model    = new PlotModel();
            FGWaveformGraphDataLine = new LineSeries()
            {
                Color = OxyColor.FromRgb(34, 139, 34)
            };
            FGWaveformGraphZeroLine = new LineSeries()
            {
                Color = OxyColor.FromRgb(0, 0, 0)
            };                                                                                 // zero line is black
            FGWaveformPlot.Model.Series.Add(FGWaveformGraphZeroLine);
            FGWaveformPlot.Model.Series.Add(FGWaveformGraphDataLine);
            channelColors       = new System.Drawing.Color[numOscilloscopeChannels];
            mappedVoltageScales = scope.GetVoltageScalePresets();
            mappedTimeScales    = scope.GetTimeScalePresets();
            for (int i = 0; i < numOscilloscopeChannels; i++)          // this application does not respond to runtime changes in channel color
                                                                       // I have never heard of a scope that does that but just for reference.
            {
                channelColors[i] = scope.GetChannelColor(i + 1);       // we save the channel colors so we don't need to access them again
            }
            foreach (string s in scope.GetVoltageScalePresetStrings()) // add all supported voltage scale presets to the combobox of voltage scales
            {
                VoltageScalePresetComboBox.Items.Add(s);
            }
            foreach (string s in scope.GetTimeScalePresetStrings())  // add all supported time scale presets to the combobox of time scales
            {
                TimeScalePresetComboBox.Items.Add(s);
            }
            MemoryDepthComboBox.Items.Add("AUTO");  // add the auto option first
            int[] tempAllowedMemDepths = scope.GetAllowedMemDepths();
            foreach (int i in tempAllowedMemDepths) // add all supported memory depths to the combobox of memory depths
            {
                MemoryDepthComboBox.Items.Add(i);
            }

            // on startup set the displayed memory depth to be the current selected mem depth for the scope
            for (int i = 1; i <= numOscilloscopeChannels; i++) // add the everything for the different channels into the different stackpanels
            {
                scope.DisableChannel(i);                       // just make sure everything is set to off before we start
                Label channelLabel = new Label()
                {
                    Content = i + "=" + scope.GetYScale(i) + "V", Visibility = Visibility.Hidden
                };
                // get the scale labels for each channel, and then hide them
                CheckBox cb = new CheckBox()
                {
                    Content = "Channel " + i, IsChecked = false
                };
                RadioButton rb = new RadioButton()
                {
                    Content       = "Channel " + i + "   ",
                    IsChecked     = false,
                    FlowDirection = FlowDirection.RightToLeft,
                };
                rb.Checked += (sender, args) =>  // on channel change, switch the displayed scale to the scale for that channel
                {
                    int checkedChannel = (int)(sender as RadioButton).Tag;
                    scopeChannelInFocus = checkedChannel;
                    double offset = scope.GetYAxisOffset(scopeChannelInFocus);  // and set the displayed offset to the offset of that channel
                    VoltageOffsetSlider.Value = offset;
                    previousYScaleFactor      = scope.GetYScale(scopeChannelInFocus);
                    int channelChangedVoltageScaleCheck = Array.IndexOf(mappedVoltageScales, previousYScaleFactor);
                    if (channelChangedVoltageScaleCheck >= 0)
                    {  // use the mapping between names and actual scales to set the initial selected scale to the one
                       // the scope is presently showing for channel 1.
                        VoltageScalePresetComboBox.SelectedIndex = channelChangedVoltageScaleCheck;
                    }
                };
                rb.Unchecked += (sender, args) => { };  // currently no events need to be triggered on an un-check
                rb.Tag        = i;
                OscilloscopeRadioButtonStackPanel.Children.Add(rb);
                cb.Checked += (sender, args) =>
                {
                    int checkedChannel = (int)(sender as CheckBox).Tag;
                    channelsToDraw.Add(checkedChannel);  // enable drawing of the checked channel
                    scope.EnableChannel(checkedChannel);
                    channelsToDisable.Remove(checkedChannel);
                    (OscilloscopeChannelScaleStackPanel.Children[checkedChannel - 1] as Label).Visibility = Visibility.Visible;
                    // when checked/enabled, show the scale for the channel
                    // when a channel is enabled or disabled, we'll need to check if we need to adjust the possible memory depth values
                    MemoryDepthComboBox.Items.Clear();  // first clear out the current iteams
                    MemoryDepthComboBox.Items.Add("AUTO");
                    int[] updatedMemDepths = scope.GetAllowedMemDepths();
                    foreach (int memDepth in updatedMemDepths)
                    {
                        MemoryDepthComboBox.Items.Add(memDepth);  // then add back in the new ones
                    }
                    OScope_CheckMemoryDepth(updatedMemDepths);
                };
                cb.Unchecked += (sender, args) =>
                {
                    int uncheckedChannel = (int)(sender as CheckBox).Tag;
                    channelsToDraw.Remove(uncheckedChannel);                               // disable drawing of the unchecked channel
                    scope.DisableChannel(uncheckedChannel);
                    WaveformPlot.Model.Series.Remove(channelGraphs[uncheckedChannel - 1]); // when the user disables the waveform, clear what remains
                    WaveformPlot.Model.InvalidatePlot(true);
                    channelsToDisable.Add(uncheckedChannel);
                    (OscilloscopeChannelScaleStackPanel.Children[uncheckedChannel - 1] as Label).Visibility = Visibility.Hidden;
                    // when unchecked/disabled, hide the scale for the channel
                    // when a channel is enabled or disabled, we'll need to check if we need to adjust the possible memory depth values
                    MemoryDepthComboBox.Items.Clear();  // first clear out the current iteams

                    MemoryDepthComboBox.Items.Add("AUTO");
                    int[] updatedMemDepths = scope.GetAllowedMemDepths();
                    foreach (int memDepth in updatedMemDepths)
                    {
                        MemoryDepthComboBox.Items.Add(memDepth);  // then add back in the new ones
                    }
                    OScope_CheckMemoryDepth(updatedMemDepths);
                };
                cb.Tag = i;
                OscilloscopeChannelButtonStackPanel.Children.Add(cb);
                OscilloscopeChannelScaleStackPanel.Children.Add(channelLabel);                             // add the channel label to the stackpanel
            }
            (OscilloscopeChannelButtonStackPanel.Children[0] as CheckBox).IsChecked  = true;               // set channel 1 to be checked by default on startup
            (OscilloscopeRadioButtonStackPanel.Children[0] as RadioButton).IsChecked = true;               // set channel 1 to be checked by default on startup
            (OscilloscopeChannelScaleStackPanel.Children[0] as Label).Visibility     = Visibility.Visible; // show channel 1's scale as well.
            scope.EnableChannel(1);
            double currentYScale = scope.GetYScale(1);                                                     // we have tempYScale and currentYScale hmmmm

            previousYScaleFactor = currentYScale;
            int currentVoltageScaleCheck = Array.IndexOf(mappedVoltageScales, currentYScale);

            if (currentVoltageScaleCheck >= 0)
            {  // use the mapping between names and actual scales to set the initial selected scale to the one
                // the scope is presently showing for channel 1.
                VoltageScalePresetComboBox.SelectedIndex = currentVoltageScaleCheck;
            }
            int currentTimeScaleCheck = Array.IndexOf(mappedTimeScales, scope.GetXAxisScale());

            if (currentTimeScaleCheck >= 0)
            {  // use the mapping between names and actual scales to set the initial selected scale to the one
                // the scope is presently showing for channel 1.
                TimeScalePresetComboBox.SelectedIndex = currentTimeScaleCheck;
            }
            OScope_CheckMemoryDepth(tempAllowedMemDepths);
            WaveformPlot.Model = new PlotModel {
                Title = "Oscilloscope Capture"
            };


            foreach (string memoryLocation in fg.GetValidMemoryLocations())
            {
                fileDataMap.Add(memoryLocation, new WaveformFile()); // put placeholder blank waveforms in the fileDataMap
                WaveformList.Items.Add(memoryLocation);              // add each valid memory location to the list box
            }
            for (int i = 1; i <= fg.GetNumChannels(); i++)
            {
                RadioButton rb = new RadioButton()
                {
                    Content = "Channel " + i, IsChecked = i == 0
                };
                rb.Checked += (sender, args) =>
                {
                    int checkedChannel = (int)(sender as RadioButton).Tag;
                    functionGeneratorChannelInFocus = checkedChannel;
                    if (channelsPlaying.Contains(checkedChannel))
                    {
                        PlayWaveform.Content = "Restart Waveform";
                    }
                    else
                    {
                        PlayWaveform.Content = "Play Waveform";
                    }
                    FG_ChannelChanged();
                };
                rb.Unchecked += (sender, args) => { };  // currently no events need to be triggered on an un-check
                rb.Tag        = i;
                FunctionGenChannelButtonStackPanel.Children.Add(rb);
            }
            (FunctionGenChannelButtonStackPanel.Children[0] as RadioButton).IsChecked = true;  // set channel 1 to be checked by default
            if (maximumAllowedAmplitude <= 0 || maximumAllowedAmplitude > fg.GetMaxSupportedVoltage() - fg.GetMinSupportedVoltage())
            // if the maximumAllowedAmplitude setting is below (or equals for sanity checking) 0, OR it's set to something too large then
            // we just set it to be the maximum allowed amplitude of the function generator itself.
            {
                maximumAllowedAmplitude = fg.GetMaxSupportedVoltage() - fg.GetMinSupportedVoltage();
            }
            // these get forced into being symmetrical. That is okay in my opinion. I don't think there are any function generators with
            // non-symmetrical voltage limits

            Color    backgroundColor = (Color)Background.GetValue(SolidColorBrush.ColorProperty);
            OxyColor hiddenColor     = OxyColor.FromArgb(0, backgroundColor.R, backgroundColor.G, backgroundColor.B);

            // This axis is the voltage axis for the FG waveform display
            LinearAxis FGWaveformVoltageAxis = new LinearAxis
            {
                Minimum = -1 * maximumAllowedAmplitude / 2,
                // set the graph's max and min labels to be what the used function generator's max and min supported voltages actually are.
                Maximum       = maximumAllowedAmplitude / 2,
                IsPanEnabled  = false,
                IsZoomEnabled = false,
                Position      = AxisPosition.Left,
                Title         = "Voltage"
            };

            // This axis is just here to make sure that the bottom axis has no ticks or number labels
            LinearAxis FGWaveformBottomAxis = new LinearAxis
            {
                IsPanEnabled  = false,
                IsZoomEnabled = false,
                IsAxisVisible = false,
                TickStyle     = TickStyle.None,
                TextColor     = hiddenColor, // makes it look rectangular at startup while still having no visible numbers on the bottom.
                Position      = AxisPosition.Bottom
            };

            FGWaveformPlot.Model.Axes.Add(FGWaveformVoltageAxis);
            FGWaveformPlot.Model.Axes.Add(FGWaveformBottomAxis);


            // These Axes form the background grid of the oscope display.


            LinearAxis horizGridAxis1 = new LinearAxis      // make horizontal grid lines
            {
                Position               = AxisPosition.Left, // radiate out from center bar to the left
                MajorGridlineStyle     = LineStyle.Solid,
                MinorGridlineStyle     = LineStyle.Dot,
                IsPanEnabled           = false,
                MajorStep              = idealNumScreenPoints / oscilloscopeNumVertDiv,
                IsZoomEnabled          = false,
                Minimum                = -1 * (idealNumScreenPoints / 2), // point 0 is centered, so we have a range of -600 to 600 or similar
                Maximum                = (idealNumScreenPoints / 2),
                AbsoluteMinimum        = -1 * (idealNumScreenPoints / 2),
                AbsoluteMaximum        = (idealNumScreenPoints / 2),
                MinimumPadding         = 0,
                MaximumPadding         = 0,
                TicklineColor          = OxyColor.FromRgb(0, 0, 0),
                PositionAtZeroCrossing = true,
                TextColor              = hiddenColor,
            };
            LinearAxis horizGridAxis2 = new LinearAxis       // make horizontal grid lines
            {
                Position               = AxisPosition.Right, // radiate out of center bar to the right
                MajorGridlineStyle     = LineStyle.Solid,
                MinorGridlineStyle     = LineStyle.Dot,
                IsPanEnabled           = false,
                MajorStep              = idealNumScreenPoints / oscilloscopeNumVertDiv,
                IsZoomEnabled          = false,
                Minimum                = -1 * (idealNumScreenPoints / 2), // point 0 is centered, so we have a range of -600 to 600 or similar
                Maximum                = (idealNumScreenPoints / 2),
                AbsoluteMinimum        = -1 * (idealNumScreenPoints / 2),
                AbsoluteMaximum        = (idealNumScreenPoints / 2),
                IntervalLength         = idealNumScreenPoints / oscilloscopeNumHorizDiv,
                MinimumPadding         = 0,
                MaximumPadding         = 0,
                TicklineColor          = OxyColor.FromRgb(0, 0, 0),
                PositionAtZeroCrossing = true,
                TextColor              = hiddenColor,
                ExtraGridlines         = new double[] { 0 }
            };
            LinearAxis vertGridAxis1 = new LinearAxis
            {
                Position               = AxisPosition.Top,
                MajorGridlineStyle     = LineStyle.Solid,
                MinorGridlineStyle     = LineStyle.Dot,
                MajorStep              = Width / oscilloscopeNumHorizDiv,
                TicklineColor          = OxyColor.FromRgb(0, 0, 0),
                PositionAtZeroCrossing = true,
                MinimumPadding         = 0,
                MaximumPadding         = 0,
                IsZoomEnabled          = false,
                IsPanEnabled           = false,
                TextColor              = hiddenColor,
                ExtraGridlines         = new double[] { 0 }
            };
            LinearAxis vertGridAxis2 = new LinearAxis
            {
                Position               = AxisPosition.Bottom,
                MajorGridlineStyle     = LineStyle.Solid,
                MinorGridlineStyle     = LineStyle.Dot,
                MajorStep              = Width / oscilloscopeNumHorizDiv,
                TicklineColor          = OxyColor.FromRgb(0, 0, 0),
                PositionAtZeroCrossing = true,
                MinimumPadding         = 0,
                MaximumPadding         = 0,
                IsZoomEnabled          = false,
                IsPanEnabled           = false,
                TextColor              = hiddenColor,
            };

            for (int i = 0; i < channelGraphs.Length; i++)
            {
                channelGraphs[i] = new LineSeries(); // then init the objects in it
                voltageAxes[i]   = new LinearAxis
                {                                    // just like on the actual scope display, we need to hide our axes
                    Position      = AxisPosition.Left,
                    TicklineColor = hiddenColor,
                    TextColor     = hiddenColor,
                    IsZoomEnabled = false,
                    IsPanEnabled  = false,
                    Key           = (i + 1).ToString(),         // make the key the channel number (it's fine the text is clear)
                };
                WaveformPlot.Model.Axes.Add(voltageAxes[i]);    // a lot of array accesses here, possibly redo with temp variables?
                channelGraphs[i].YAxisKey = voltageAxes[i].Key; // then use that to associate the axis with the channel graph
            }

            WaveformPlot.Model.Axes.Add(horizGridAxis1); // add the left to right grid line axis to the display
            WaveformPlot.Model.Axes.Add(vertGridAxis1);
            WaveformPlot.Model.Axes.Add(horizGridAxis2);
            WaveformPlot.Model.Axes.Add(vertGridAxis2);
            triggerLine = new LineSeries();
            // the orange trigger set line must be drawn on the graph
            double triggerLineScaled = (scope.GetTriggerLevel() * currentYScale) - (currentYScale / 2);

            WaveformPlot.Model.Series.Add(triggerLine);
            WaveformPlot.Model.InvalidatePlot(true);
        }
コード例 #9
0
        // a single click on one of the memory locations in the list
        private void FG_WaveformList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            OffsetErrorLabel.Visibility    = Visibility.Hidden;                 // hide the offset error label if it's showing
            AmplitudeErrorLabel.Visibility = Visibility.Hidden;                 // hide the amplitude one too
            memoryLocationSelected         = (string)WaveformList.SelectedItem; // the data stored in WaveformList will always be strings
            WaveformFile current = fileDataMap[memoryLocationSelected];         // get the waveformFileStruct from the selected memory location

            if (current.FileName == null)                                       // if the waveform selected still has its default values, just let the user know and then return
            {
                WaveformName.Content              = "No data in requested location";
                WaveformMemoryLocation.Content    = memoryLocationSelected;          // show the memory location
                WaveformSampleRate.Text           = "No data in requested location";
                WaveformAmplitudeScaleFactor.Text = "No data in requested location"; // show the scaling factor

                FG_DrawWaveformGraph(current);                                       // draw an empty graph, with just the 0V reference line

                UploadWaveform.IsEnabled = false;                                    // try just disabling the button instead of hiding it
                EditWaveformParameterCheckbox.IsEnabled = false;                     // disable the edit waveform parameter checkbox
                LoadWaveformButton.IsEnabled            = false;                     // if there's nothing in the memory location, we definitely can't load it
                PlayWaveform.IsEnabled = false;                                      // we definitely can't play it if there's nothing there
                return;
            }
            else
            {
                if (!openingFile)
                {
                    currentWaveform = current;
                }
                // UploadWaveform.IsEnabled = true;  // try just enabling the button instead of showing it
                EditWaveformParameterCheckbox.IsEnabled = true; // enable the edit waveform parameter checkbox
                if (currentWaveform.IsUploaded)                 // if the waveform in the memory location is uploaded to the generator
                {
                    if (!(uploading || loading))                // as long as no operation is in progress
                    {
                        LoadWaveformButton.IsEnabled = true;    // we can enable the button to load the waveform into active memory
                        UploadWaveform.IsEnabled     = true;
                    }
                    if (currentWaveform.ChannelsLoadedTo.Contains(functionGeneratorChannelInFocus)) // if the waveform is loaded into the
                                                                                                    //selected channel's active memory.
                    {
                        if (!loading)                                                               // if we're not currently loading a waveform
                        {
                            PlayWaveform.IsEnabled = true;                                          // enable the playwaveform button
                        }
                    }
                    else
                    {
                        PlayWaveform.IsEnabled = false;  // just in case
                    }
                }
                else
                {
                    if (!(uploading || loading))
                    {
                        UploadWaveform.IsEnabled = true;
                    }
                    LoadWaveformButton.IsEnabled = false;  // just in case
                    PlayWaveform.IsEnabled       = false;
                }
                // if the waveform selected has set values, display them for the user.
                WaveformName.Content              = current.FileName;               // show the displayed name
                WaveformMemoryLocation.Content    = memoryLocationSelected;         // show the memory location
                WaveformSampleRate.Text           = current.SampleRate.ToString();  // show the sample rate
                WaveformAmplitudeScaleFactor.Text = current.ScaleFactor.ToString(); // show the scaling factor
                FG_DrawWaveformGraph(current);                                      // draw the waveform on the app's graph
            }
        }
コード例 #10
0
        // a double click on one of the memory locations in the list
        private void FG_WaveformList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            memoryLocationSelected = (string)WaveformList.SelectedItem;                               // the data stored in WaveformList will always be strings
            WaveformFile current = fileDataMap[memoryLocationSelected];                               // get the waveformFileStruct from the selected memory location

            OffsetErrorLabel.Visibility    = Visibility.Hidden;                                       // hide the offset error label if it's showing
            AmplitudeErrorLabel.Visibility = Visibility.Hidden;                                       // hide the amplitude error one too
            if (openingFile)
            {                                                                                         // if we are currently in opening file mode
                if (current.FileName == null)                                                         // if the memory location that was clicked on is empty, just save the data there.
                {
                    fileDataMap[memoryLocationSelected] = currentWaveform;                            // save the data
                    openingFile = false;                                                              // set opening file to false
                    WaveformSaveInstructionLabel.Visibility = Visibility.Hidden;                      // hide the instruction label
                    cancelFileOpen.Visibility               = Visibility.Hidden;                      // hide the cancel button again.
                    WaveformName.Content                    = currentWaveform.FileName;               // show the displayed name
                    WaveformMemoryLocation.Content          = memoryLocationSelected;                 // show the memory location
                    WaveformSampleRate.Text                 = currentWaveform.SampleRate.ToString();  // show the sample rate
                    WaveformAmplitudeScaleFactor.Text       = currentWaveform.ScaleFactor.ToString(); // show the scaling factor
                    EditWaveformParameterCheckbox.IsEnabled = true;                                   // enable the edit waveform parameter checkbox
                    ListBoxItem item = WaveformList.ItemContainerGenerator.ContainerFromItem(WaveformList.SelectedItem) as ListBoxItem;
                    item.Background = Brushes.Gold;
                    // set the color to gold to signal that the waveform is saved but
                    // not uploaded
                    if (!(uploading || loading))
                    {
                        UploadWaveform.IsEnabled = true; // enable the upload button
                    }
                    FG_DrawWaveformGraph();              // draw the graph

                    return;                              // then just return.
                }
                else // if the memory location that was clicked on isn't empty, ask the user if they are okay with overwriting the data that
                     // is already there
                {
                    if (MessageBox.Show("Overwrite Waveform in " + memoryLocationSelected, "Overwrite Waveform?",
                                        MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                    {
                        fileDataMap[memoryLocationSelected] = currentWaveform;                      // they said it was okay to overwrite
                        openingFile = false;                                                        // set opening file to false
                        cancelFileOpen.Visibility = Visibility.Hidden;                              // hide the cancel button again.
                        WaveformSaveInstructionLabel.Visibility = Visibility.Hidden;                // hide the instruction label
                        WaveformName.Content              = currentWaveform.FileName;               // show the displayed name
                        WaveformMemoryLocation.Content    = memoryLocationSelected;                 // show the memory location
                        WaveformSampleRate.Text           = currentWaveform.SampleRate.ToString();  // show the sample rate
                        WaveformAmplitudeScaleFactor.Text = currentWaveform.ScaleFactor.ToString(); // show the scaling factor
                        FG_DrawWaveformGraph();                                                     // draw the graph
                        if (!(uploading || loading))
                        {
                            UploadWaveform.IsEnabled = true;  // enable the upload button
                        }
                        ListBoxItem item = WaveformList.ItemContainerGenerator.ContainerFromItem(WaveformList.SelectedItem) as ListBoxItem;
                        EditWaveformParameterCheckbox.IsEnabled = true; // enable the edit waveform parameter checkbox
                        item.Background = Brushes.Gold;                 // set the color to gold to signal that the waveform is saved but
                        // not uploaded
                        return;                                         // then just return.
                    }
                    else
                    {
                        // we don't set opening file to false because the user may have clicked on the wrong waveform or something
                        // the empty else branch is left here as a placeholder.
                        return;  // just return
                    }
                }
            }
            else  // if the user is not opening a file, and just double clicks on the memory location, load the waveform there into current
            {
                current = fileDataMap[memoryLocationSelected];  // reload current value
                                                                // if the waveform selected has set values, display them for the user.
                                               // (Then also like load the file into the graph but that's for later)
                currentWaveform = current;
                if (current.FileName == null)  // if there isn't any data saved there, keep the original "no data" messages
                {
                    WaveformName.Content                    = "No data in requested location";
                    WaveformMemoryLocation.Content          = memoryLocationSelected;          // show the memory location
                    WaveformSampleRate.Text                 = "No data in requested location";
                    WaveformAmplitudeScaleFactor.Text       = "No data in requested location"; // show the scaling factor
                    EditWaveformParameterCheckbox.IsEnabled = false;                           // disable the edit waveform parameter checkbox
                    FG_DrawWaveformGraph();                                                    // draw an empty graph
                    UploadWaveform.IsEnabled = false;                                          // disable the upload button
                    return;
                }  // if it's not null, just show it's data
                WaveformName.Content                    = current.FileName;                       // show the displayed name
                WaveformMemoryLocation.Content          = memoryLocationSelected;                 // show the memory location
                WaveformSampleRate.Text                 = current.SampleRate.ToString();          // show the sample rate
                WaveformAmplitudeScaleFactor.Text       = currentWaveform.ScaleFactor.ToString(); // show the scaling factor
                EditWaveformParameterCheckbox.IsEnabled = true;                                   // enable the edit waveform parameter checkbox
                if (!(uploading || loading))
                {
                    UploadWaveform.IsEnabled = true; // enable the upload button
                }
                FG_DrawWaveformGraph();              // draw the graph with the data saved in the memory location
            }
        }
コード例 #11
0
        private void FG_ParseFile(string filePath)
        {
            double sampleRate = 844;  // default samplerate
            string fileName   = System.IO.Path.GetFileName(filePath);
            IEnumerable <string> fileLines = File.ReadLines(filePath);

            if (fileLines.First().StartsWith("samplerate="))
            {
                sampleRate = double.Parse(fileLines.First().Substring(11)); // parse the sampleRate
                fileLines  = fileLines.Skip(1);                             // and then we have to skip the first one.
            }
            double[] voltageArray = fileLines.AsParallel().AsOrdered().Select(line => double.Parse(line)).ToArray();
            // parse to an IEnumerable of doubles, using Parallel processing, but preserving the order
            if (voltageArray.AsParallel().Max() - voltageArray.AsParallel().Min() > maximumAllowedAmplitude)  // amplitude is too high
            {
                // signal the UI thread to display the error/warning
                Application.Current.Dispatcher.Invoke(() => {
                    AmplitudeErrorLabel.Visibility = Visibility.Visible;
                });
                double absMax = Math.Max(Math.Abs(voltageArray.AsParallel().Max()), Math.Abs(voltageArray.AsParallel().Min()));
                // get the maximum absolute value from the waveform.
                // now we can't just use the ScaleWaveform() function for this because then it would set the original
                // values to ones that were beyond the max/min.
                double scalingFactor = absMax / (maximumAllowedAmplitude / 2);  // get the scaling factor
                Parallel.For(0, voltageArray.Length, (i, state) =>
                {
                    voltageArray[i] = voltageArray[i] / scalingFactor;  // then we multiply every value in the waveform by the scaling factor.
                });
                // and then we just move on
            }
            int returnedValue = FG_RemoveDCOffset(voltageArray); // remove the DC offset from the waveform if there is one.

            if (returnedValue == -1)                             // then there was an error removing the DC offset
            {
                // signal the UI thread to show the DC offset removal error and clean up the opening file process
                Application.Current.Dispatcher.Invoke(() => {
                    OffsetErrorLabel.Visibility             = Visibility.Visible;
                    cancelFileOpen.Visibility               = Visibility.Hidden; // hide the cancel file open button
                    WaveformSaveInstructionLabel.Visibility = Visibility.Hidden; // hide the save file instructions
                    WaveformList.IsEnabled = true;                               // also reenable the list
                });
                openingFile = false;                                             // set opening file to false
                return;                                                          // then just give up without actually saving the waveform or anything.
            }

            // for safety reasons, we will only be putting in a maximum amplitude of 1Vpp into our bucket.
            // However, checking for this does make the code less flexible, so here are the lines of code that cause this.
            // 1Vpp checking code:
            // should we check this before or after DC offset removal. Before is faster, but after is better. So after.

            // okay so we need to automatically scale the amplitude down to fit the maximum allowed amplitude.



            WaveformFile fileStruct = new WaveformFile(sampleRate, voltageArray.Length, fileName, voltageArray, filePath);

            // create a new WaveformFileStruct to contain the info about this waveform file

            currentWaveform = fileStruct;                                // then set the waveform data for the currently selected memory address
            Application.Current.Dispatcher.Invoke(FG_DrawWaveformGraph); // attempt to signal the UI thread to update the graph as soon
            // as we are done doing the parsing
        }