/// <summary>
        /// Gets the Stim parameters for a Group
        /// </summary>
        /// <param name="theSummit">SummitSystem for making the api call to INS</param>
        /// <param name="group">Group number to get the data</param>
        /// <returns>StimParameterModel that contains stim amp, stim rate and pulse width</returns>
        public Tuple <bool, string, TherapyGroup> GetTherapyDataForGroup(SummitSystem theSummit, GroupNumber group)
        {
            TherapyGroup insStateGroup = null;

            if (theSummit == null || theSummit.IsDisposed)
            {
                return(Tuple.Create(false, "Summit Disposed", insStateGroup));
            }

            try
            {
                //Get the data from the api
                bufferInfo = theSummit.ReadStimGroup(group, out insStateGroup);
                if (bufferInfo.RejectCode != 0 || insStateGroup == null)
                {
                    _log.Warn("Could not read stim group from Medtronic api call");
                    return(Tuple.Create(false, "Could not read stim group from Medtronic api call", insStateGroup));
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
                return(Tuple.Create(false, "Error reading stim group.", insStateGroup));
            }
            return(Tuple.Create(true, "Success", insStateGroup));
        }
 /// <summary>
 /// Constructor to set values for stimulation data for pulse width, stim rate and stim amp
 /// </summary>
 /// <param name="pulsewidth">Sets the pulseWidth value</param>
 /// <param name="stimrate">Sets the stimRate value</param>
 /// <param name="stimamp">Sets the stimAmp value</param>
 /// <param name="electrodesStim">Sets the electrode that is stimming</param>
 /// <param name="therapyElectrodes">Therapy electrodes</param>
 /// <param name="therapyGroup">Therapy group with all settings</param>
 public StimParameterModel(string pulsewidth, string stimrate, string stimamp, string electrodesStim, TherapyElectrodes therapyElectrodes, TherapyGroup therapyGroup)
 {
     PulseWidth        = pulsewidth;
     StimRate          = stimrate;
     StimAmp           = stimamp;
     StimElectrodes    = electrodesStim;
     TherapyElectrodes = therapyElectrodes;
     TherapyGroup      = therapyGroup;
 }
 /// <summary>
 /// Constructor to set values for stimulation data for pulse width, stim rate and stim amp
 /// </summary>
 /// <param name="pulsewidth">Sets the pulseWidth value</param>
 /// <param name="stimrate">Sets the stimRate value</param>
 /// <param name="stimamp">Sets the stimAmp value</param>
 /// <param name="electrodesStim">Sets the electrode that is stimming</param>
 /// <param name="therapyElectrodes">Therapy electrodes</param>
 /// <param name="therapyGroup">Therapy group with all settings</param>
 /// <param name="ampLimits">Amp Limits</param>
 /// <param name="rateValue">Rate value as double</param>
 /// <param name="ampValue">Amp value as double</param>
 /// <param name="pwValue">Pulse width value as double</param>
 public StimParameterModel(string pulsewidth, string stimrate, string stimamp, string electrodesStim, TherapyElectrodes therapyElectrodes, TherapyGroup therapyGroup, AmplitudeLimits ampLimits, double rateValue, double ampValue, int pwValue)
 {
     PulseWidth        = pulsewidth;
     StimRate          = stimrate;
     StimAmp           = stimamp;
     StimElectrodes    = electrodesStim;
     TherapyElectrodes = therapyElectrodes;
     TherapyGroup      = therapyGroup;
     AmpLimits         = ampLimits;
     StimAmpValue      = ampValue;
     StimRateValue     = rateValue;
     PulseWidthValue   = pwValue;
 }
        /// <summary>
        /// Finds the electrodes that are stimming
        /// </summary>
        /// <param name="therapyGroup">therapy group from the ins call</param>
        /// <param name="program">program number 0-3</param>
        /// <returns>Returns the contacts that are stimming along with anode or cathode</returns>
        public string FindStimElectrodes(TherapyGroup therapyGroup, int program)
        {
            string electrodesStimming = "";

            if (therapyGroup.Valid)
            {
                if (therapyGroup.Programs[program].Valid)
                {
                    for (int i = 0; i < 17; i++)
                    {
                        if (!therapyGroup.Programs[program].Electrodes[i].IsOff)
                        {
                            //Case is 16 so it gets a C. Otherwise give the number
                            if (i == 16)
                            {
                                electrodesStimming += "C";
                            }
                            else
                            {
                                electrodesStimming += i.ToString();
                            }
                            // What type of electrode is it?
                            switch (therapyGroup.Programs[program].Electrodes[i].ElectrodeType)
                            {
                            case ElectrodeTypes.Cathode:
                                electrodesStimming += "-";
                                break;

                            case ElectrodeTypes.Anode:
                                electrodesStimming += "+";
                                break;

                            default:
                                break;
                            }
                        }
                    }
                }
            }
            return(electrodesStimming);
        }
        /// <summary>
        /// Sweep through all the indicated stimulation amplitudes, pulse widths, and frequencies. If stimulation engine failure flag is raised, or if user
        /// pushes quit button, the sweep is aborted.
        /// </summary>
        public bool Sweep()
        {
            bool sweepAborted = false;

            //go through each parameter, put thier number of values, stim stop, and pause durations in the right order
            List <int> numValues = new List <int>()
            {
                0, 0, 0
            };
            List <int> pauseDurations = new List <int>()
            {
                0, 0, 0
            };

            List <int> maxIters = new List <int>(2);

            for (int iLevel = 0; iLevel < m_sweepParameters.paramOrder.Count; iLevel++)
            {
                numValues[m_sweepParameters.paramOrder[iLevel]]      = m_sweepParameters.paramNumValues[iLevel];
                pauseDurations[m_sweepParameters.paramOrder[iLevel]] = m_sweepParameters.paramPauseDurationMilliSeconds[iLevel];
            }

            //initialize current values
            if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
            {
                sweepAborted = true;
                return(sweepAborted);
            }

            //bring pulse width and freq to starting values:
            if (m_currentAmp != 0)
            {
                //amp should be 0 so there will be no stimulation when setting pw and freq. Set to 0 if it's not.
                Console.WriteLine(String.Format("Sweep initialzation amplitude should be 0, but it's {0}! Cannot do stim sweep", m_currentAmp));
                return(sweepAborted = true);
            }

            m_summitInfo = m_summit.StimChangeTherapyOn();
            // Reset POR if set
            if (m_summitInfo.RejectCodeType == typeof(MasterRejectCode) &&
                (MasterRejectCode)m_summitInfo.RejectCode == MasterRejectCode.ChangeTherapyPor)
            {
                // Inform user
                Console.WriteLine("POR set, resetting...");
                // Reset POR
                m_summitInfo = SummitUtils.resetPOR(m_summit);
            }
            Thread.Sleep(1000);
            try
            {
                ResetSweep();
            }
            catch
            {
                sweepAborted = true;
                return(sweepAborted);
            }

            //initialize a counter to 0's for the number of values we've already sweeped across for each parameter
            List <int> iterCounter = new List <int> {
                0, 0, 0
            };
            int iParameter, iAmp = 0, iPW = 0, iFreq = 0;

            //make a listener thread to check for terminations
            Thread stopListenerThread = new Thread(StopSweepListener);

            //start stimulation by bringing amp to first value
            m_sweepFinished = false;
            m_summitInfo    = m_summit.StimChangeStepAmp(0, m_sweepParameters.ampValues[0], out m_currentAmp);
            if (m_summitInfo.RejectCode != 0)
            {
                Console.WriteLine("Error when increasing stimulation amplitude to " + m_sweepParameters.ampValues[iAmp] + "mA. Error descriptor:" + m_summitInfo.Descriptor);
                if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                {
                    sweepAborted = true;
                    return(sweepAborted);
                }
            }
            Console.WriteLine("Sweep started at: " + m_currentAmp
                              + "mA , " + m_currentPulseWidth
                              + "us pulse width, and " + m_currentFreq + " Hz");
            stopListenerThread.Start();

            Thread.Sleep(m_sweepParameters.permutationDuration);

            //now do iteration by increasing the counter for each parameter (until all the parameter's value's have all been iterated across)
            while (iterCounter[0] < (numValues[0] - 1) || iterCounter[1] < (numValues[1] - 1) || iterCounter[2] < (numValues[2] - 1))
            {
                //First do check here to see if the sweep has been stopped (either quit key has been pressed or stim engine out of range flag has been set)
                if (m_stopSweep)
                {
                    Console.WriteLine("Stimulation Sweep Aborted");
                    sweepAborted = true;
                    break;
                }

                if (iterCounter[0] < (numValues[0] - 1))
                {
                    try
                    {
                        //we're at innermost parameter
                        IntraSweepPause(pauseDurations[0]);
                        iterCounter[0]++;
                        iParameter = 0;
                    }
                    catch
                    {
                        sweepAborted = true;
                        return(sweepAborted);
                    }
                }
                else if (iterCounter[1] < (numValues[1] - 1))
                {
                    //we're at the middle parameter
                    try
                    {
                        IntraSweepPause(pauseDurations[1]);
                        iterCounter[1]++;
                        iParameter = 1;

                        //reset innermost parameter
                        ResetParameter(0, ref iAmp, ref iPW, ref iFreq);
                        iterCounter[0] = 0;
                    }
                    catch
                    {
                        sweepAborted = true;
                        return(sweepAborted);
                    }
                    Console.WriteLine();
                }
                else
                {
                    try
                    {
                        //we're at the outermost parameter
                        IntraSweepPause(pauseDurations[2]);
                        iterCounter[2]++;
                        iParameter = 2;

                        //reset innermost and middle parameter
                        ResetParameter(0, ref iAmp, ref iPW, ref iFreq);
                        ResetParameter(1, ref iAmp, ref iPW, ref iFreq);
                        iterCounter[0] = 0;
                        iterCounter[1] = 0;
                    }
                    catch
                    {
                        sweepAborted = true;
                        return(sweepAborted);
                    }
                    Console.WriteLine();
                }


                // increment the parameter we're at in the sweep
                if (iParameter == m_sweepParameters.ampOrder)
                {
                    //increase stim amp
                    iAmp++;

                    m_summitInfo = m_summit.StimChangeStepAmp(0, Math.Round(m_sweepParameters.ampValues[iAmp] - m_currentAmp.Value, 1), out m_currentAmp);
                    if (m_summitInfo.RejectCode != 0)
                    {
                        Console.WriteLine("Error when increasing stimulation amplitude to " + m_sweepParameters.ampValues[iAmp] + "mA. Error descriptor:" + m_summitInfo.Descriptor);
                        if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                        {
                            sweepAborted = true;
                            return(sweepAborted);
                        }
                    }

                    Console.WriteLine("Increased amplitude to " + m_currentAmp + "mA");

                    m_stimPaused = false;
                    Thread.Sleep(m_sweepParameters.permutationDuration);
                }
                else if (iParameter == m_sweepParameters.pulseWidthOrder)
                {
                    //increase pulse duration
                    iPW++;
                    m_summitInfo = m_summit.StimChangeStepPW(0, m_sweepParameters.pulseWidthValues[iPW] - m_currentPulseWidth.Value, out m_currentPulseWidth);

                    if (m_summitInfo.RejectCode != 0)
                    {
                        Console.WriteLine("Error when increasing stimulation pulse width to " + m_sweepParameters.pulseWidthValues[iPW] + "us. Error descriptor:" + m_summitInfo.Descriptor);
                        if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                        {
                            sweepAborted = true;
                            return(sweepAborted);
                        }
                    }

                    Console.WriteLine("Increased pulse width to " + m_currentPulseWidth + "us");

                    //bring stimulation back, if it was turned off for pause
                    if (m_stimPaused)
                    {
                        m_summitInfo = m_summit.StimChangeStepAmp(0, m_prePauseAmp, out m_currentAmp);

                        if (m_summitInfo.RejectCode != 0)
                        {
                            Console.WriteLine("Error when increasing stimulation amplitude back after pulse width increase. Error descriptor:" + m_summitInfo.Descriptor);
                            if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                            {
                                sweepAborted = true;
                                return(sweepAborted);
                            }
                        }

                        m_stimPaused = false;
                    }
                    Thread.Sleep(m_sweepParameters.permutationDuration);
                }
                else if (iParameter == m_sweepParameters.freqOrder)
                {
                    //increase frequency
                    iFreq++;

                    m_summitInfo = m_summit.StimChangeStepFrequency(Math.Round(m_sweepParameters.freqValues[iFreq] - m_currentFreq.Value, 1), false, out m_currentFreq);

                    if (m_summitInfo.RejectCode != 0)
                    {
                        Console.WriteLine("Error when increasing stimulation frequency to " + m_sweepParameters.freqValues[iFreq] + "Hz. Error descriptor:" + m_summitInfo.Descriptor);
                        if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                        {
                            sweepAborted = true;
                            return(sweepAborted);
                        }
                    }

                    Console.WriteLine("Increased frequency to " + m_currentFreq + "Hz");

                    //bring stimulation back, if it was turned off for pause
                    if (m_stimPaused)
                    {
                        m_summitInfo = m_summit.StimChangeStepAmp(0, m_prePauseAmp, out m_currentAmp);

                        if (m_summitInfo.RejectCode != 0)
                        {
                            Console.WriteLine("Error when increasing stimulation amplitude back after frequency increase. Error descriptor:" + m_summitInfo.Descriptor);
                            if (!SummitUtils.CheckCurrentStimParameters(m_summit, m_groupNum, 0, out m_currentAmp, out m_currentPulseWidth, out m_currentFreq))
                            {
                                sweepAborted = true;
                                return(sweepAborted);
                            }
                        }

                        m_stimPaused = false;
                    }
                    Thread.Sleep(m_sweepParameters.permutationDuration);
                }

                //just call some function to interragate INS to allow any OOR info to arrive (add 100 ms sleep to all time for setting the abort flags)
                TherapyGroup groupInfo = new TherapyGroup();
                m_summit.ReadStimGroup(m_groupNum, out groupInfo);
                Thread.Sleep(100);
            }

            //ok sweep finished, reset all parametrs and flags, and join listener thread
            m_stimOutOfRangeFlag = false;
            try
            {
                ResetSweep();
            }
            catch
            {
                sweepAborted = true;
                return(sweepAborted);
            }

            //turn therapy off
            m_summit.StimChangeTherapyOff(false);
            m_sweepFinished = true;
            stopListenerThread.Join();
            m_stopSweep = false;
            return(sweepAborted);
        }
        /// <summary>
        /// Gets the stim parameters based on group from the actual API
        /// </summary>
        /// <param name="theSummit">SummitSystem for making the API call to INS</param>
        /// <param name="groupNumber">Group number corresponding to which group we want to get stim parameters from such as Group0, Group1, etc</param>
        /// <returns>StimParameterModel that contains stim amp, stim rate and pulse width</returns>
        private StimParameterModel GetStimParameterModel(SummitSystem theSummit, GroupNumber groupNumber, int program)
        {
            if (theSummit == null || theSummit.IsDisposed)
            {
                return(null);
            }
            TherapyGroup    insStateGroup = null;
            AmplitudeLimits ampLimits     = null;

            try
            {
                int counter = 5;
                do
                {
                    bufferInfo = theSummit.ReadStimGroup(groupNumber, out insStateGroup);
                    counter--;
                } while ((insStateGroup == null || bufferInfo.RejectCode != 0) && counter > 0);
                if (bufferInfo.RejectCode != 0 && counter == 0)
                {
                    _log.Warn("Could not read stim group from Medtronic api call");
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            try
            {
                int counter = 5;
                do
                {
                    bufferInfo = theSummit.ReadStimAmplitudeLimits(groupNumber, out ampLimits);
                    counter--;
                } while ((insStateGroup == null || bufferInfo.RejectCode != 0) && counter > 0);
                if (bufferInfo.RejectCode != 0 && counter == 0)
                {
                    _log.Warn("Could not read amp limits from Medtronic api call");
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            int    pulseWidthValue = -1;
            double rateValue       = -1;
            double ampValue        = -1;

            try
            {
                //parse the data to get the pulsewidth
                if (insStateGroup != null)
                {
                    pulseWidth      = insStateGroup.Programs[program].PulseWidthInMicroseconds.ToString();
                    stimRate        = insStateGroup.RateInHz.ToString();
                    stimAmp         = insStateGroup.Programs[program].AmplitudeInMilliamps.ToString();
                    stimElectrode   = FindStimElectrodes(insStateGroup, program);
                    electrodes      = insStateGroup?.Programs[program]?.Electrodes;
                    pulseWidthValue = insStateGroup.Programs[program].PulseWidthInMicroseconds;
                    rateValue       = insStateGroup.RateInHz;
                    ampValue        = insStateGroup.Programs[program].AmplitudeInMilliamps;
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            //Set the Model with these values and return model
            if (rateValue == -1 || ampValue == -1 || pulseWidthValue == -1)
            {
                StimParameterModel StimParameterModel = new StimParameterModel(pulseWidth, stimRate, stimAmp, stimElectrode, electrodes, insStateGroup, ampLimits);
                return(StimParameterModel);
            }
            else
            {
                StimParameterModel StimParameterModel = new StimParameterModel(pulseWidth, stimRate, stimAmp, stimElectrode, electrodes, insStateGroup, ampLimits, rateValue, ampValue, pulseWidthValue);
                return(StimParameterModel);
            }
        }