internal ClosedLoopOut(NRTask CLE, int fs, DataSrv DatSrv, StimSrv StimSrv, Task buffLoadTask, Logger Debugger, string NRFilePath, bool NRRecording, NeuroRighter NR)
 {
     this.CLE = CLE;
     this.outputSampFreq = fs;
     this.DatSrv = DatSrv;
     this.StimSrv = StimSrv;
     this.useManStimWave = false;
     this.buffLoadTask = buffLoadTask;
     this.Debugger = Debugger;
     this.NRFilePath = NRFilePath;
     this.NRRecording = NRRecording;
     this.NR = NR;
 }
        // Method to set up the recording side of neurorighter
        private bool NRAcquisitionSetup()
        {
            lock (this)
            {
                if (!taskRunning)
                {
                    try
                    {

                        this.Cursor = Cursors.WaitCursor;
                       if (switch_record.Value)
                        {
                            // Create file name
                            if (filenameBase == null) //user hasn't specified a file
                                button_BrowseOutputFile_Click(null, null); //call file selection routine
                            if (filenameBase == null) //this happens if the user pressed cancel for the dialog
                            {
                                MessageBox.Show("An output file must be selected before recording."); //display an error message
                                this.Cursor = Cursors.Default;
                                return true;
                            }

                            // If the user is just doing repeated recordings
                            if (checkbox_repeatRecord.Checked || Properties.Settings.Default.useFidTimeStamp)
                            {
                                DateTime nowDate = DateTime.Now;//Get current time (local to computer);
                                string datePrefix = nowDate.ToString("'-'yyyy'-'MM'-'dd'-'HH'-'mm'-'ss");
                                filenameBase = originalNameBase + datePrefix;
                            }

                            // Look for old files with same name
                            string[] matchFiles;
                            try
                            {
                                matchFiles = Directory.GetFiles(currentSaveDir, currentSaveFile + "*");
                            }
                            catch
                            {
                                matchFiles = new string[0];
                            }

                            if (matchFiles.Length > 0)
                            {
                                DialogResult dr = MessageBox.Show("File " + filenameBase + " exists. Overwrite?",
                                    "NeuroRighter Warning", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);

                                if (dr == DialogResult.No)
                                    button_BrowseOutputFile_Click(null, null); //call file selection routine
                                else if (dr == DialogResult.Cancel)
                                {
                                    this.Cursor = Cursors.Default;
                                    return true;
                                }
                            }

                            // Set file base name + number of channels
                            recordingSettings.SetFID(filenameBase);
                            recordingSettings.SetNumElectrodes(numChannels);
                        }

                        // Find out how many devs and channels/dev we are going to need
                        int numDevices = (numChannels > 32 ? Properties.Settings.Default.AnalogInDevice.Count : 1);
                        numChannelsPerDev = (numChannels < 32 ? numChannels : 32);

                        // Set spike buffer lengths
                        spikeBufferLength = Convert.ToInt32(Properties.Settings.Default.ADCPollingPeriodSec * Properties.Settings.Default.RawSampleFrequency);
                        lfpBufferLength = Convert.ToInt32(Properties.Settings.Default.ADCPollingPeriodSec * Properties.Settings.Default.LFPSampleFrequency);

                        // Create spike aquisition task list
                        spikeTask = new List<Task>(numDevices);
                        Properties.Settings.Default.numSpikeTasks = numDevices;
                        NRAIChannelCollection spikeAqSet = new NRAIChannelCollection(numDevices, numChannelsPerDev);
                        spikeAqSet.SetupSpikeCollection(ref spikeTask);

                        // Check audio and video properties
                        if (Properties.Settings.Default.UseSingleChannelPlayback)
                            spikeOutTask = new Task("spikeOutTask"); //For audio output
                        if (checkBox_video.Checked) //NB: This can't be checked unless video is enabled (no need to check properties)
                            triggerTask = new Task("triggerTask");

                        // Set MUA sample rate
                        double muaSamplingRate = spikeSamplingRate / MUA_DOWNSAMPLE_FACTOR;

                        //Add LFP channels, if configured
                        if (Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs)
                        {
                            lfpTask = new Task("lfpTask");
                            for (int i = 0; i < Properties.Settings.Default.NumChannels; ++i)
                                lfpTask.AIChannels.CreateVoltageChannel(Properties.Settings.Default.LFPDevice + "/ai" + i.ToString(), "",
                                    AITerminalConfiguration.Nrse, -10.0, 10.0, AIVoltageUnits.Volts);
                            setGain(lfpTask, Properties.Settings.Default.LFPgain);
                            lfpTask.Control(TaskAction.Verify);
                        }

                        //Add EEG channels, if configured
                        if (Properties.Settings.Default.UseEEG)
                        {

                            eegTask = new Task("eegTask");
                            for (int i = 0; i < Properties.Settings.Default.EEGNumChannels; ++i)
                                eegTask.AIChannels.CreateVoltageChannel(Properties.Settings.Default.EEGDevice + "/ai" +
                                    (i).ToString(), "", AITerminalConfiguration.Nrse, -10.0, 10.0, AIVoltageUnits.Volts);
                            setGain(eegTask, (double)Properties.Settings.Default.EEGGain);
                            eegTask.Control(TaskAction.Verify);
                            eegSamplingRate = Properties.Settings.Default.EEGSamplingRate;
                        }

                        //Add channel to control Cineplex, if configured
                        if (checkBox_video.Checked)
                            triggerTask.DOChannels.CreateChannel(Properties.Settings.Default.CineplexDevice + "/Port0/line0:7", "",
                                ChannelLineGrouping.OneChannelForAllLines);

                        //Change gain based on comboBox values (1-100)
                        for (int i = 0; i < spikeTask.Count; ++i)
                            setGain(spikeTask[i], Properties.Settings.Default.A2Dgain);

                        //Verify the Tasks
                        for (int i = 0; i < spikeTask.Count; ++i)
                            spikeTask[i].Control(TaskAction.Verify);
                        //if (Properties.Settings.Default.UseSingleChannelPlayback)
                        //    spikeOutTask.Control(TaskAction.Verify);

                        //Get sampling rates, set to private variables
                        spikeSamplingRate = Properties.Settings.Default.RawSampleFrequency;
                        lfpSamplingRate = Properties.Settings.Default.LFPSampleFrequency;

                        //Version with videoTask as master clock
                        if (Properties.Settings.Default.UseCineplex)
                        {
                            for (int i = 0; i < spikeTask.Count; ++i)
                            {
                                spikeTask[i].Timing.ReferenceClockSource = videoTask.Timing.ReferenceClockSource;
                                spikeTask[i].Timing.ReferenceClockRate = videoTask.Timing.ReferenceClockRate;
                            }
                        }
                        else
                        {
                            string masterclock = "/" + Properties.Settings.Default.AnalogInDevice[0].ToString() + "/10MhzRefClock";//"OnboardClock";//
                            if (!Properties.Settings.Default.UseStimulator)
                            {
                                //Deal with non M-series devices (these can't use "ReferenceClockSource"
                                Device analogInDevice = DaqSystem.Local.LoadDevice(Properties.Settings.Default.AnalogInDevice[0]);

                                if (analogInDevice.ProductCategory == ProductCategory.MSeriesDaq || analogInDevice.ProductCategory == ProductCategory.XSeriesDaq)
                                    spikeTask[0].Timing.ReferenceClockSource = masterclock; //This will be the master clock
                            }
                            else
                            {

                                spikeTask[0].Timing.ReferenceClockSource = masterclock;//stimPulseTask.Timing.ReferenceClockSource;
                                spikeTask[0].Timing.ReferenceClockRate = 10000000.0; //stimPulseTask.Timing.ReferenceClockRate;
                            }
                            for (int i = 1; i < spikeTask.Count; ++i) //Set other analog in tasks to master clock
                            {
                                spikeTask[i].Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource;
                                spikeTask[i].Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate;
                            }
                        }
                        spikeTask[0].Timing.ConfigureSampleClock("", spikeSamplingRate,
                                SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.RawSampleFrequency / 2));
                        for (int i = 1; i < spikeTask.Count; ++i)
                        {
                            //Pipe ai dev0's sample clock to slave devices
                            spikeTask[i].Timing.ConfigureSampleClock("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/SampleClock", spikeSamplingRate,
                                SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.RawSampleFrequency / 2));

                            //Trigger off of ai dev0's trigger
                            spikeTask[i].Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" + Properties.Settings.Default.AnalogInDevice[0] +
                                "/ai/StartTrigger", DigitalEdgeStartTriggerEdge.Rising);

                            // Manually allocate buffer memory
                            //spikeTask[i].Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;
                        }

                        if (Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs)
                        {
                            lfpTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource;
                            lfpTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate;
                            lfpTask.Timing.ConfigureSampleClock("", lfpSamplingRate,
                                SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.LFPSampleFrequency / 2));

                            // Manually allocate buffer memory
                            //lfpTask.Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;
                        }
                        else
                        {
                            Properties.Settings.Default.numLFPTasks = Properties.Settings.Default.numSpikeTasks;
                        }

                        if (Properties.Settings.Default.UseEEG)
                        {
                            eegTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource;
                            eegTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate;
                            eegTask.Timing.ConfigureSampleClock("", eegSamplingRate,
                                SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Convert.ToDouble(Properties.Settings.Default.EEGSamplingRate) / 2));

                            // Manually allocate buffer memory
                            //eegTask.Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;
                        }

                        if (Properties.Settings.Default.UseCineplex)
                        {
                            if (checkBox_video.Checked)
                            {
                                triggerTask.Timing.ConfigureSampleClock("/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/SampleClock",
                                    spikeSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples,
                                    3);
                            }
                            if (Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs)
                            {
                                lfpTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" +
                                    Properties.Settings.Default.AnalogInDevice[0] + "/ai/StartTrigger",
                                    DigitalEdgeStartTriggerEdge.Rising);
                            }
                            if (Properties.Settings.Default.UseEEG)
                            {
                                eegTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" +
                                    Properties.Settings.Default.AnalogInDevice[0] + "/ai/StartTrigger",
                                    DigitalEdgeStartTriggerEdge.Rising);
                            }
                        }

                        if (Properties.Settings.Default.UseStimulator && Properties.Settings.Default.RecordStimTimes)
                        {
                            try
                            {

                                numStimReads = new List<int>(numDevices);
                                for (int i = 0; i < spikeTask.Count; ++i)
                                    numStimReads.Add(0);
                                stimTimeTask = new Task("stimTimeTask");
                                stimTimeTask.AIChannels.CreateVoltageChannel(Properties.Settings.Default.StimInfoDevice + "/ai16", "",
                                    AITerminalConfiguration.Nrse, -10.0, 10.0, AIVoltageUnits.Volts);
                                stimTimeTask.AIChannels.CreateVoltageChannel(Properties.Settings.Default.StimInfoDevice + "/ai0", "", AITerminalConfiguration.Nrse,
                                    -10.0, 10.0, AIVoltageUnits.Volts); //For triggers

                                // Pipe the spikeTasks sample clock to PFI14 on the stim board
                                DaqSystem.Local.ConnectTerminals(spikeTask[0].Timing.ReferenceClockSource,
                                    "/" + Properties.Settings.Default.StimulatorDevice.ToString() + "/PFI0");

                                if (isNormalRecording)
                                    stimTimeTask.Timing.ReferenceClockSource = "/" + Properties.Settings.Default.StimulatorDevice.ToString() + "/PFI0";
                                else
                                    stimTimeTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource;
                                stimTimeTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate;
                                stimTimeTask.Timing.ConfigureSampleClock("", spikeSamplingRate,
                                    SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.RawSampleFrequency / 2));
                                stimTimeTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(
                                    "/" + Properties.Settings.Default.AnalogInDevice[0] + "/ai/StartTrigger", DigitalEdgeStartTriggerEdge.Rising);
                                stimTimeTask.Control(TaskAction.Verify);

                                // stim Timing Channel settings object
                                StringCollection stimTimePhysChan = new StringCollection();
                                for (int i = 0; i < stimTimeTask.AIChannels.Count; ++i)
                                {
                                    stimTimePhysChan.Add(stimTimeTask.AIChannels[i].PhysicalName);
                                }

                                // Write down the indicies corresponding to the portion of this task that will
                                // actually record stimulus infromation instead of aux analog input
                                stimTimeChanSet = new NRAIChannelCollection(stimTimePhysChan);
                                int[] stimTimeChannels = new int[] { 0, 1 };
                                stimTimeChanSet.SetupNumericalChannelOnly(stimTimeChannels);

                                // Manually allocate buffer memory
                                //stimTimeTask.Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;

                                Console.WriteLine("NRAcquisitionSetup complete");
                            }
                            catch (Exception e)
                            {
                                MessageBox.Show(e.Message);
                            }
                        }

                        //Setup scaling coefficients (to convert digital values to voltages)
                        scalingCoeffsSpikes = new List<double[]>(spikeTask.Count);
                        for (int i = 0; i < spikeTask.Count; ++i)
                            scalingCoeffsSpikes.Add(spikeTask[0].AIChannels[0].DeviceScalingCoefficients);
                        if (Properties.Settings.Default.SeparateLFPBoard)
                            scalingCoeffsLFPs = lfpTask.AIChannels[0].DeviceScalingCoefficients;
                        if (Properties.Settings.Default.UseEEG)
                            scalingCoeffsEEG = eegTask.AIChannels[0].DeviceScalingCoefficients;

                        // Setup auxiliary recording tasks
                        if (Properties.Settings.Default.useAuxAnalogInput)
                        {
                            // Set up the aux channel set
                            auxChanSet = new NRAIChannelCollection(Properties.Settings.Default.auxAnalogInChan);

                            if (Properties.Settings.Default.auxAnalogInDev == Properties.Settings.Default.StimInfoDevice
                                && Properties.Settings.Default.RecordStimTimes)
                            {
                                // In this case we are recording both stimulus times and aux analog input times on the same
                                // DAQ, so we need to just make the auxAnInTask reference the stimulus timing task
                                twoAITasksOnSingleBoard = true;
                                auxAnInTask = stimTimeTask;
                                auxChanSet.SetupAuxCollection(ref auxAnInTask);
                            }
                            else
                            {
                                // In this case there is no conflict for AI, so we can create a dedicated task for aux analog input
                                twoAITasksOnSingleBoard = false;
                                auxAnInTask = new Task("AuxiliaryAnalogInput");
                                auxChanSet.SetupAuxCollection(ref auxAnInTask);

                                auxAnInTask.Timing.ReferenceClockSource = spikeTask[0].Timing.ReferenceClockSource;
                                auxAnInTask.Timing.ReferenceClockRate = spikeTask[0].Timing.ReferenceClockRate;

                                //Pipe ai dev0's sample clock to slave devices
                                auxAnInTask.Timing.ConfigureSampleClock("", spikeSamplingRate,
                                    SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.RawSampleFrequency / 2));
                                auxAnInTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/Dev1/ai/StartTrigger", DigitalEdgeStartTriggerEdge.Rising);

                                // Manually allocate buffer memory
                                // auxAnInTask.Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;

                                // Create space for the buffer
                                auxAnData = new double[auxChanSet.numericalChannels.Length, spikeBufferLength];

                            }

                        }

                        if (Properties.Settings.Default.useAuxDigitalInput)
                        {
                            auxDigInTask = new Task("AuxiliaryDigitalInput");
                            auxDigInTask.DIChannels.CreateChannel(Properties.Settings.Default.auxDigitalInPort,
                                "Auxiliary Digitial In", ChannelLineGrouping.OneChannelForAllLines);

                            auxDigInTask.Timing.ConfigureSampleClock("", spikeSamplingRate,
                                SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, Convert.ToInt32(Properties.Settings.Default.RawSampleFrequency / 2));
                            auxDigInTask.Timing.SampleClockSource = spikeTask[0].Timing.SampleClockTerminal;

                            // Manually allocate buffer memory
                            // auxDigInTask.Stream.Buffer.InputBufferSize = DAQ_BUFFER_SIZE_SAMPLES;
                        }

                        #region Setup_Plotting

                        numSnipsDisplayed = (int)numericUpDown_NumSnipsDisplayed.Value;

                        #region PlotData_Buffers
                        //***********************
                        //Make PlotData buffers
                        //***********************
                        int downsample, numRows, numCols;
                        const double spikeplotlength = 0.25; //in seconds
                        switch (Properties.Settings.Default.NumChannels)
                        {
                            case 16:
                                numRows = numCols = 4;
                                downsample = 10;
                                break;
                            case 32:
                                numRows = numCols = 6;
                                downsample = 15;
                                break;
                            case 64:
                                numRows = numCols = 8;
                                downsample = 20; //if this gets really small, LFP data won't plot
                                break;
                            default:
                                numRows = numCols = 4;
                                downsample = 5;
                                break;
                        }

                        //Create plot colormap
                        NRBrainbow = (64).GenerateBrainbow();
                        NRSnipBrainbow = (64).GenerateSnipBrainbow();
                        NRUnitBrainbow = (64).GenerateUnitBrainbow();

                        //Initialize graphs
                        if (spikeGraph != null) { spikeGraph.Dispose(); spikeGraph = null; }
                        spikeGraph = new GridGraph();
                        int samplesPerPlot = (int)(Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * spikeSamplingRate / downsample) * (spikeplotlength / Properties.Settings.Default.ADCPollingPeriodSec));
                        spikeGraph.setup(numRows, numCols, samplesPerPlot, false, 1 / 4.0, spikeTask[0].AIChannels.All.RangeHigh * 2.0);
                        spikeGraph.setMinMax(0, (float)(samplesPerPlot * numCols) - 1,
                            (float)(spikeTask[0].AIChannels.All.RangeLow * (numRows * 2 - 1)), (float)(spikeTask[0].AIChannels.All.RangeHigh));
                        spikeGraph.Dock = DockStyle.Fill;
                        spikeGraph.Parent = tabPage_spikes;

                        if (Properties.Settings.Default.UseLFPs)
                        {
                            if (lfpGraph != null) { lfpGraph.Dispose(); lfpGraph = null; }
                            lfpGraph = new RowGraph();
                            lfpGraph.setup(numChannels, (int)((Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * lfpSamplingRate / downsample) * (5 / Properties.Settings.Default.ADCPollingPeriodSec))),
                                5.0, spikeTask[0].AIChannels.All.RangeHigh * 2.0);
                            if (Properties.Settings.Default.SeparateLFPBoard)
                                lfpGraph.setMinMax(0, 5 * (int)(Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * lfpSamplingRate / downsample) / Properties.Settings.Default.ADCPollingPeriodSec) - 1,
                                    (float)(lfpTask.AIChannels.All.RangeLow * (numChannels * 2 - 1)), (float)(lfpTask.AIChannels.All.RangeHigh));
                            else
                                lfpGraph.setMinMax(0, 5 * (int)(Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * lfpSamplingRate / downsample) / Properties.Settings.Default.ADCPollingPeriodSec) - 1,
                                    (float)(spikeTask[0].AIChannels.All.RangeLow * (numChannels * 2 - 1)), (float)(spikeTask[0].AIChannels.All.RangeHigh));
                            lfpGraph.Dock = DockStyle.Fill;
                            lfpGraph.Parent = tabPage_LFPs;
                        }

                        if (Properties.Settings.Default.ProcessMUA)
                        {
                            if (muaGraph != null) { muaGraph.Dispose(); muaGraph = null; }
                            muaGraph = new RowGraph();
                            muaGraph.setup(numChannels, (int)((Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * muaSamplingRate / downsample) * (5 / Properties.Settings.Default.ADCPollingPeriodSec))),
                                5.0, spikeTask[0].AIChannels.All.RangeHigh * 2.0);
                            muaGraph.setMinMax(0, 5 * (int)(Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * muaSamplingRate / downsample) / Properties.Settings.Default.ADCPollingPeriodSec) - 1,
                                    (float)(spikeTask[0].AIChannels.All.RangeLow * (numChannels * 2 - 1)), (float)(spikeTask[0].AIChannels.All.RangeHigh));
                            muaGraph.Dock = DockStyle.Fill;
                            muaGraph.Parent = tabPage_MUA;

                            muaPlotData = new PlotDataRows(numChannels, downsample, (int)(muaSamplingRate * 5), muaSamplingRate,
                                    (float)spikeTask[0].AIChannels.All.RangeHigh * 2F, 0.5, 5, Properties.Settings.Default.ADCPollingPeriodSec);
                            //muaPlotData.setGain(Properties.Settings.Default.LFPDisplayGain);

                            //muaGraph.setDisplayGain(Properties.Settings.Default.LFPDisplayGain);
                            muaPlotData.dataAcquired += new PlotData.dataAcquiredHandler(muaPlotData_dataAcquired);
                        }

                        if (Properties.Settings.Default.UseEEG)
                        {
                            if (eegGraph != null) { eegGraph.Dispose(); eegGraph = null; }
                            eegGraph = new RowGraph();
                            eegGraph.setup(Properties.Settings.Default.EEGNumChannels, (int)((Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * eegSamplingRate / downsample) * (5 / Properties.Settings.Default.ADCPollingPeriodSec))),
                                5.0, eegTask.AIChannels.All.RangeHigh * 2.0);
                            eegGraph.setMinMax(0, 5 * (int)(Math.Ceiling(Properties.Settings.Default.ADCPollingPeriodSec * eegSamplingRate / downsample) / Properties.Settings.Default.ADCPollingPeriodSec) - 1,
                                    (float)(eegTask.AIChannels.All.RangeLow * (Properties.Settings.Default.EEGNumChannels * 2 - 1)), (float)(eegTask.AIChannels.All.RangeHigh));
                            eegGraph.Dock = DockStyle.Fill;
                            eegGraph.Parent = tabPage_EEG;
                        }

                        resetSpkWfm(); //Take care of spike waveform graph

                        double ampdec = (1 / Properties.Settings.Default.PreAmpGain);

                        spikePlotData = new PlotDataGrid(numChannels, downsample, (int)(spikeSamplingRate), spikeSamplingRate,
                            (float)(spikeTask[0].AIChannels.All.RangeHigh * 2.0), numRows, numCols, spikeplotlength,
                            Properties.Settings.Default.ChannelMapping, Properties.Settings.Default.ADCPollingPeriodSec);
                        spikePlotData.dataAcquired += new PlotData.dataAcquiredHandler(spikePlotData_dataAcquired);
                        spikePlotData.setGain(Properties.Settings.Default.SpikeDisplayGain);
                        spikeGraph.setDisplayGain(Properties.Settings.Default.SpikeDisplayGain);

                        if (Properties.Settings.Default.UseLFPs)
                        {
                            if (Properties.Settings.Default.SeparateLFPBoard)
                                lfpPlotData = new PlotDataRows(numChannels, downsample, (int)(lfpSamplingRate * 5), lfpSamplingRate,
                                    (float)lfpTask.AIChannels.All.RangeHigh * 2F, 0.5, 5, Properties.Settings.Default.ADCPollingPeriodSec);
                            else lfpPlotData = new PlotDataRows(numChannels, downsample, (int)(lfpSamplingRate * 5), lfpSamplingRate,
                                    (float)spikeTask[0].AIChannels.All.RangeHigh * 2F, 0.5, 5, Properties.Settings.Default.ADCPollingPeriodSec);
                            lfpPlotData.setGain(Properties.Settings.Default.LFPDisplayGain);

                            lfpGraph.setDisplayGain(Properties.Settings.Default.LFPDisplayGain);
                            lfpPlotData.dataAcquired += new PlotData.dataAcquiredHandler(lfpPlotData_dataAcquired);
                        }

                        waveformPlotData = new EventPlotData(numChannels, spikeDet.NumPre + spikeDet.NumPost + 1, (float)(spikeTask[0].AIChannels.All.RangeHigh * 2F),
                            numRows, numCols, numSnipsDisplayed, Properties.Settings.Default.ChannelMapping);
                        waveformPlotData.setGain(Properties.Settings.Default.SpkWfmDisplayGain);
                        spkWfmGraph.setDisplayGain(Properties.Settings.Default.SpkWfmDisplayGain);
                        waveformPlotData.dataAcquired += new EventPlotData.dataAcquiredHandler(waveformPlotData_dataAcquired);
                        waveformPlotData.start();
                        #endregion

                        if (Properties.Settings.Default.UseEEG)
                        {
                            eegPlotData = new PlotDataRows(Properties.Settings.Default.EEGNumChannels, downsample, (int)(eegSamplingRate * 5), eegSamplingRate,
                                    (float)eegTask.AIChannels.All.RangeHigh * 2F, 0.5, 5, Properties.Settings.Default.ADCPollingPeriodSec);
                            eegPlotData.setGain(Properties.Settings.Default.EEGDisplayGain);

                            eegGraph.setDisplayGain(Properties.Settings.Default.EEGDisplayGain);
                            eegPlotData.dataAcquired += new PlotData.dataAcquiredHandler(eegPlotData_dataAcquired);
                        }

                        if (Properties.Settings.Default.useAuxAnalogInput)
                        {
                            // Remove existing plots
                            for (int i = scatterGraph_AuxAnalogData.Plots.Count-1; i > 0; --i)
                            {
                                scatterGraph_AuxAnalogData.Plots.RemoveAt(i);
                            }
                            // Initialize the aux data scatter graph with a plot for each aux Analog channel
                            for (int i = 0; i < Properties.Settings.Default.auxAnalogInChan.Count-1; ++i)
                            {
                                ScatterPlot p = new ScatterPlot();
                                scatterGraph_AuxAnalogData.Plots.Add(p);
                            }

                            // Initialize the controller
                            auxInputGraphController = new ScatterGraphController(ref scatterGraph_AuxAnalogData);

                            // Make history selector reflect current limits on input
                            //slide_AnalogDispMaxVoltage.Range = new Range(0.05, 10);
                            //slide_AnalogDispWidth.Range = new Range(2*Properties.Settings.Default.ADCPollingPeriodSec, Properties.Settings.Default.datSrvBufferSizeSec);

                        }
                        #endregion

                        #region Setup_Filters
                        //Setup filters, based on user's input
                        resetSpikeFilter();
                        if (Properties.Settings.Default.UseLFPs) resetLFPFilter();
                        resetEEGFilter();

                        muaFilter = new Filters.MUAFilter(
                            numChannels, spikeSamplingRate, spikeBufferLength,
                            Properties.Settings.Default.MUAHighCutHz,
                            Properties.Settings.Default.MUAFilterOrder,
                            MUA_DOWNSAMPLE_FACTOR,
                            Properties.Settings.Default.ADCPollingPeriodSec);

                        #endregion

                        #region Setup_DataStorage
                        //Initialize data storing matrices
                      //  numChannels = Properties.Settings.Default.NumChannels;

                        numSpikeReads = new int[spikeTask.Count];

                        filtSpikeData = new rawType[numChannels][];

                        if (Properties.Settings.Default.UseLFPs)
                        {
                            filtLFPData = new rawType[numChannels][];
                            finalLFPData = new rawType[numChannels][];
                            for (int i = 0; i < filtSpikeData.GetLength(0); ++i)
                            {
                                if (Properties.Settings.Default.SeparateLFPBoard)
                                    filtLFPData[i] = new rawType[lfpBufferLength];
                                else
                                    filtLFPData[i] = new rawType[spikeBufferLength];
                            }
                        }

                        if (Properties.Settings.Default.ProcessMUA)
                        {
                            muaData = new double[numChannels][];
                            for (int c = 0; c < numChannels; ++c)
                                muaData[c] = new double[spikeBufferLength / MUA_DOWNSAMPLE_FACTOR];
                        }

                        if (Properties.Settings.Default.UseEEG)
                        {

                            filtEEGData = new double[Properties.Settings.Default.EEGNumChannels][];
                            for (int i = 0; i < filtEEGData.GetLength(0); ++i)
                            {
                                filtEEGData[i] = new double[eegBufferLength];
                            }
                        }

                        for (int i = 0; i < filtSpikeData.GetLength(0); ++i)
                        {
                            filtSpikeData[i] = new rawType[spikeBufferLength];
                            if (Properties.Settings.Default.UseLFPs)
                                finalLFPData[i] = new rawType[lfpBufferLength];
                        }

                        if (Properties.Settings.Default.UseStimulator)
                        {
                            stimDataBuffer = new double[STIM_BUFFER_LENGTH];
                            stimJump = (double)spikeSamplingRate * 0.0001; //num. indices in 100 us of data
                        }

                        stimIndices = new List<StimTick>(5);
                        //if devices refresh rate is reset, need to reset SALPA
                        if (checkBox_SALPA.Checked)
                            resetSALPA();
                        if (spikeDet != null && isNormalRecording)
                            setSpikeDetector();
                        if (spikeDet.spikeDetector == null)
                            setSpikeDetector();

                        #endregion

                        #region Verify Tasks
                        if (Properties.Settings.Default.UseStimulator && Properties.Settings.Default.RecordStimTimes)
                            stimTimeTask.Control(TaskAction.Verify);
                        if (Properties.Settings.Default.UseEEG)
                            eegTask.Control(TaskAction.Verify);
                        if (Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs)
                            lfpTask.Control(TaskAction.Verify);
                        if (checkBox_video.Checked)
                            triggerTask.Control(TaskAction.Verify);
                        for (int i = 0; i < spikeTask.Count; ++i)
                            spikeTask[i].Control(TaskAction.Verify);
                        if (Properties.Settings.Default.useAuxAnalogInput)
                            auxAnInTask.Control(TaskAction.Verify);
                        if (Properties.Settings.Default.useAuxDigitalInput)
                            auxDigInTask.Control(TaskAction.Verify);
                        #endregion

                        SetupFileWriting();

                        //Set callbacks for data acq.
                        spikeReader = new List<AnalogMultiChannelReader>(spikeTask.Count);
                        for (int i = 0; i < spikeTask.Count; ++i)
                        {
                            spikeReader.Add(new AnalogMultiChannelReader(spikeTask[i].Stream));
                            spikeReader[i].SynchronizeCallbacks = true;
                        }
                        //if (Properties.Settings.Default.UseSingleChannelPlayback)
                        //    spikeOutWriter = new AnalogSingleChannelWriter(spikeOutTask.Stream);
                        if (checkBox_video.Checked)
                            triggerWriter = new DigitalSingleChannelWriter(triggerTask.Stream);

                        //if (Properties.Settings.Default.UseSingleChannelPlayback)
                        //    spikeOutWriter.SynchronizeCallbacks = false; //These don't use UI, so they don't need to be synched

                        spikeCallback = new AsyncCallback(AnalogInCallback_spikes);

                        if (Properties.Settings.Default.UseStimulator && Properties.Settings.Default.RecordStimTimes)
                        {
                            stimTimeReader = new AnalogMultiChannelReader(stimTimeTask.Stream);
                        }

                        if (Properties.Settings.Default.SeparateLFPBoard && Properties.Settings.Default.UseLFPs)
                        {
                            lfpReader = new AnalogUnscaledReader(lfpTask.Stream);
                            lfpReader.SynchronizeCallbacks = true;
                            lfpCallback = new AsyncCallback(AnalogInCallback_LFPs);
                        }
                        if (Properties.Settings.Default.UseEEG)
                        {
                            eegReader = new AnalogUnscaledReader(eegTask.Stream);
                            eegReader.SynchronizeCallbacks = true;
                            eegCallback = new AsyncCallback(AnalogInCallback_EEG);
                        }

                        if (Properties.Settings.Default.useAuxAnalogInput)
                        {
                            auxAnReader = new AnalogMultiChannelReader(auxAnInTask.Stream);
                            auxAnReader.SynchronizeCallbacks = true;
                            auxAnCallback = new AsyncCallback(AnalogInCallback_AuxAn);
                        }

                        if (Properties.Settings.Default.useAuxDigitalInput)
                        {
                            auxDigReader = new DigitalSingleChannelReader(auxDigInTask.Stream);
                            auxDigReader.SynchronizeCallbacks = true;
                            auxDigCallback = new AsyncCallback(AnalogInCallback_AuxDig);
                        }

                        //Setup background workers for data processing
                        bwSpikes = new List<BackgroundWorker>(spikeTask.Count);
                        bwIsRunning = new bool[spikeTask.Count];
                        for (int i = 0; i < spikeTask.Count; ++i)
                        {
                            bwSpikes.Add(new BackgroundWorker());
                            bwSpikes[i].DoWork += new DoWorkEventHandler(bwSpikes_DoWork);
                            bwSpikes[i].RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwSpikes_RunWorkerCompleted);
                            bwSpikes[i].WorkerSupportsCancellation = true;
                        }

                        //Make persistent buffers for spikeData
                        spikeData = new List<AnalogWaveform<double>[]>(spikeReader.Count);
                        for (int i = 0; i < spikeReader.Count; ++i)
                        {
                            spikeData.Add(new AnalogWaveform<double>[numChannelsPerDev]);
                            for (int j = 0; j < numChannelsPerDev; ++j)
                                spikeData[i][j] = new AnalogWaveform<double>(spikeBufferLength);
                        }

                        //Make channel playback task
                        if (Properties.Settings.Default.UseSingleChannelPlayback)
                            BNCOutput = new ChannelOutput(spikeSamplingRate, 0.1, Properties.Settings.Default.ADCPollingPeriodSec, spikeTask[0],
                                Properties.Settings.Default.SingleChannelPlaybackDevice, 0);

                    }
                    catch (Exception exception)
                    {
                        //Display Errors
                        this.Cursor = Cursors.Default;
                        MessageBox.Show(exception.Message);
                        reset();
                    }

                    // Set up the DataSrv object. This is an object that publishes a nice large data history
                    // for use in closed loop control and other things
                    if (datSrv != null)
                        datSrv = null;

                    datSrv = new DataSrv(
                        Properties.Settings.Default.datSrvBufferSizeSec,
                        checkBox_SALPA.Checked,
                        SALPA_WIDTH,
                        checkBox_spikesFilter.Checked,
                        spikeDet.spikeDetectionLag
                        );

                    // Set the number of units if appropriate
                    if (spikeDet.spikeSorter != null)
                        datSrv.SetNumberOfUnits(spikeDet.spikeSorter.totalNumberOfUnits, spikeDet.spikeSorter.unit2Channel);

                    Debugger = new Logger();
                    Debugger.GrabTimer(spikeTask[0]);

                    //Send debug output to the user's application data folder
                    Debugger.SetPath(Path.Combine(Properties.Settings.Default.neurorighterAppDataPath, "neurorighter-log.txt"));

                    //Tell neuroRighter that the tasks now exist
                    taskRunning = true;
                }
                else
                {
                    Console.WriteLine("NRAcquisitionSetup was called while a task was running, and therefore setup did not execute.  Perhaps this should have thrown an error");
                }
            }

            //update gui at the end
            // Modify the UI, so user doesn't try running multiple instances of tasks

            spikeDet.numPreSamples.Enabled = false;
            spikeDet.numPostSamples.Enabled = false;
            settingsToolStripMenuItem.Enabled = false;

            button_Train.Enabled = false;
            button_SetRecordingStreams.Enabled = false;
            switch_record.Enabled = false;
            //processingSettingsToolStripMenuItem.Enabled = false;

            button_startStimFromFile.Enabled = false;
            button_startClosedLoopStim.Enabled = false;
            checkBox_SALPA.Enabled = false;

            //numericUpDown_NumSnipsDisplayed.Enabled = false;
            button_startClosedLoopStim.Enabled = false;
            button_scaleUp.Enabled = true;
            button_scaleDown.Enabled = true;
            button_scaleReset.Enabled = true;

            // Disable spike detector saving while running
            spikeDet.DisableFileMenu();
            Console.WriteLine("NRAcquisitionSetup successfully executed");
            this.Cursor = Cursors.Default;
            return false;
        }
 internal ClosedLoopOut(NRTask CLE, int fs, DataSrv DatSrv, StimSrv StimSrv, Task buffLoadTask, Logger Debugger, string NRFilePath, bool NRRecording, NeuroRighter NR, double[] standardWave)
     : this(CLE, fs, DatSrv, StimSrv, buffLoadTask,Debugger,NRFilePath, NRRecording, NR)
 {
     this.guiWave = standardWave;
     this.useManStimWave = true;
 }
 internal void Grab(DataSrv DatSrv, StimSrv StimSrv, Logger Debugger, string NRFilePath, bool NRRecording, NeuroRighter NR)
 {
     this.NRDataSrv = DatSrv;
     this.NRStimSrv = StimSrv;
     this.debugger = Debugger;
     this.nrFilePath = NRFilePath;
     this.nrRecording = NRRecording;
     this.NR = NR;//we need a reference back to NR to initiate the stop sequence
 }