コード例 #1
0
        /****************************************************************************
        *  SetTrigger
        *  this function sets all the required trigger parameters, and calls the
        *  triggering functions
        ****************************************************************************/
        short SetTrigger(Scope.TriggerChannelProperties[] channelProperties,
                         short nChannelProperties,
                         Scope.TriggerConditions[] triggerConditions,
                         short nTriggerConditions,
                         Scope.ThresholdDirection[] directions,
                         Pwq pwq,
                         uint delay,
                         short auxOutputEnabled,
                         int autoTriggerMs)
        {
            short status;

            if (
                (status =
                     Scope.SetTriggerChannelProperties(_handle, channelProperties, nChannelProperties, auxOutputEnabled,
                                                       autoTriggerMs)) != 0)
            {
                return(status);
            }

            if ((status = Scope.SetTriggerChannelConditions(_handle, triggerConditions, nTriggerConditions)) != 0)
            {
                return(status);
            }

            if (directions == null)
            {
                directions = new Scope.ThresholdDirection[] { Scope.ThresholdDirection.None,
                                                              Scope.ThresholdDirection.None, Scope.ThresholdDirection.None, Scope.ThresholdDirection.None,
                                                              Scope.ThresholdDirection.None, Scope.ThresholdDirection.None }
            }
            ;

            if ((status = Scope.SetTriggerChannelDirections(_handle,
                                                            directions[(int)Scope.Channel.ChannelA],
                                                            directions[(int)Scope.Channel.ChannelB],
                                                            directions[(int)Scope.Channel.ChannelC],
                                                            directions[(int)Scope.Channel.ChannelD],
                                                            directions[(int)Scope.Channel.External],
                                                            directions[(int)Scope.Channel.Aux])) != 0)
            {
                return(status);
            }

            if ((status = Scope.SetTriggerDelay(_handle, delay)) != 0)
            {
                return(status);
            }

            if (pwq == null)
            {
                pwq = new Pwq(null, 0, Scope.ThresholdDirection.None, 0, 0, Scope.PulseWidthType.None);
            }

            status = Scope.SetPulseWidthQualifier(_handle, pwq.conditions,
                                                  pwq.nConditions, pwq.direction,
                                                  pwq.lower, pwq.upper, pwq.type);

            return(status);
        }

        //********************************************************************************
        //Function to acquire data to array                                              *
        //********************************************************************************

        int BlockDataAcquisition(uint sampleCount, uint timebase, short oversampling, int pretrigger)
        {
            //Time in ms the measurement will consume
            int timeIndisposed;
            int pretrig;
            int posttrig;

            //Create structured Array for measurement results of all 4channels
            //MaxPinned will contain the measurement values or the maximum values in aggregated mode
            //MinPinned will contain minimum values´in aggregated mode otherwise 0

            for (int i = 0; i < 4; i++)
            {
                short[] minBuffers = new short[sampleCount];
                short[] maxBuffers = new short[sampleCount];
                minPinned[i] = new PinnedArray <short>(minBuffers);
                maxPinned[i] = new PinnedArray <short>(maxBuffers);
                int status = Scope.SetDataBuffers(_handle, (Scope.Channel)i, maxBuffers, minBuffers, (int)sampleCount);
            }

            //Start collecting Data and create ready=true callback to acknowledge when acquisition is finished
            _ready            = false;
            _callbackDelegate = BlockCallback;
            pretrig           = (int)(sampleCount * pretrigger / 100);
            posttrig          = (int)(sampleCount * (100 - pretrigger) / 100);

            //Start acquisition
            Scope.RunBlock(_handle, pretrig, posttrig, timebase, oversampling, out timeIndisposed, 0, _callbackDelegate, IntPtr.Zero);

            //If a linearitytest is performed wait buffer to fill and start axis
            if (linearitytest == true)
            {
                //Wait for pretrigger buffer to fill with data
                Thread.Sleep(800);

                //Start axis movement
                serialPortTester.WriteLine("$AL3");
            }

            //Wait for measurement finished
            while (!_ready)
            {
                Thread.Sleep(10);
            }

            //Stop scope after data has been acquired
            Scope.Stop(_handle);

            //If acquisiton was successfully finished get values
            if (_ready)
            {
                short overflow;
                Scope.GetValues(_handle, 0, ref sampleCount, 1, Scope.DownSamplingMode.None, 0, out overflow);
            }
            else
            {
            }

            return(timeIndisposed);
        }

        int StartDataAcquisition(uint sampleCount, uint timebase, short oversampling, int pretrigger)
        {
            //Time in ms the measurement will consume
            int timeIndisposed;
            int pretrig;
            int posttrig;

            //Create structured Array for measurement results of all 4channels
            //MaxPinned will contain the measurement values or the maximum values in aggregated mode
            //MinPinned will contain minimum values´in aggregated mode otherwise 0

            for (int i = 0; i < 4; i++)
            {
                short[] minBuffers = new short[sampleCount];
                short[] maxBuffers = new short[sampleCount];
                minPinned[i] = new PinnedArray <short>(minBuffers);
                maxPinned[i] = new PinnedArray <short>(maxBuffers);
                int status = Scope.SetDataBuffers(_handle, (Scope.Channel)i, maxBuffers, minBuffers, (int)sampleCount);
            }

            //Start collecting Data and create ready=true callback to acknowledge when acquisition is finished
            _ready            = false;
            _callbackDelegate = BlockCallback;
            pretrig           = (int)(sampleCount * pretrigger / 100);
            posttrig          = (int)(sampleCount * (100 - pretrigger) / 100);

            //Start acquisition
            Scope.RunBlock(_handle, pretrig, posttrig, timebase, oversampling, out timeIndisposed, 0, _callbackDelegate, IntPtr.Zero);

            return(timeIndisposed);
        }

        int FinishDataAcquisition(uint sampleCount, uint timebase, short oversampling, int pretrigger)
        {
            //Wait for measurement finished
            while (!_ready)
            {
                Thread.Sleep(10);
            }

            //Scope.ReportedTimeUnits reported_time_units_A, reported_time_units_B;
            //long time_A, time_B;
            //int time_ah, time_bh, time_al, time_bl;


            //Stop scope after data has been acquired
            Scope.Stop(_handle);

            //If acquisiton was successfully finished get values
            if (_ready)
            {
                short overflow;
                Scope.GetValues(_handle, 0, ref sampleCount, 1, Scope.DownSamplingMode.None, 0, out overflow);
            }
            else
            {
            }

            return(0);
        }

        int EvaluateDataAcquisition(uint sampleCount, uint numAvg, out double avgA, out double avgB, out double avgC, out double avgD)
        {
            long sum_a = 0, sum_b = 0, sum_c = 0, sum_d = 0;

            for (uint i = sampleCount / 2; i != sampleCount / 2 + numAvg; i++)
            {
                sum_a += maxPinned[0].Target[i];
                sum_b += maxPinned[1].Target[i];
                sum_c += maxPinned[2].Target[i];
                sum_d += maxPinned[3].Target[i];
            }

            avgA = sum_a / numAvg;
            avgB = sum_b / numAvg;
            avgC = sum_c / numAvg;
            avgD = sum_d / numAvg;

            return(0);
        }
    }
コード例 #2
0
        /****************************************************************************
        *  SetTrigger
        *  this function sets all the required trigger parameters, and calls the
        *  triggering functions
        ****************************************************************************/
        short SetTrigger(Scope.TriggerChannelProperties[] channelProperties, short nChannelProperties, Scope.TriggerConditions[] triggerConditions, short nTriggerConditions, Scope.ThresholdDirection[] directions, Pwq pwq, uint delay, short auxOutputEnabled, int autoTriggerMs)
        {
            short status;

            if (
                (status =
                     Scope.SetTriggerChannelProperties(_handle, channelProperties, nChannelProperties, auxOutputEnabled,
                                                       autoTriggerMs)) != 0)
            {
                return(status);
            }

            if ((status = Scope.SetTriggerChannelConditions(_handle, triggerConditions, nTriggerConditions)) != 0)
            {
                return(status);
            }

            if (directions == null)
            {
                directions = new Scope.ThresholdDirection[] { Scope.ThresholdDirection.None,
                                                              Scope.ThresholdDirection.None, Scope.ThresholdDirection.None, Scope.ThresholdDirection.None,
                                                              Scope.ThresholdDirection.None, Scope.ThresholdDirection.None }
            }
            ;

            if ((status = Scope.SetTriggerChannelDirections(_handle,
                                                            directions[(int)Scope.Channel.ChannelA],
                                                            directions[(int)Scope.Channel.ChannelB],
                                                            directions[(int)Scope.Channel.ChannelC],
                                                            directions[(int)Scope.Channel.ChannelD],
                                                            directions[(int)Scope.Channel.External],
                                                            directions[(int)Scope.Channel.Aux])) != 0)
            {
                return(status);
            }

            if ((status = Scope.SetTriggerDelay(_handle, delay)) != 0)
            {
                return(status);
            }

            if (pwq == null)
            {
                pwq = new Pwq(null, 0, Scope.ThresholdDirection.None, 0, 0, Scope.PulseWidthType.None);
            }

            status = Scope.SetPulseWidthQualifier(_handle, pwq.conditions,
                                                  pwq.nConditions, pwq.direction,
                                                  pwq.lower, pwq.upper, pwq.type);

            return(status);
        }

        /****************************************************************************
        * CollectBlockImmediate
        *  this function demonstrates how to collect a single block of data
        *  from the unit (start collecting immediately)
        ****************************************************************************/
        void CollectBlockImmediate()
        {
            Console.WriteLine("Collect block immediate...");
            Console.WriteLine("Press a key to start");
            WaitForKey();

            SetDefaults();

            /* Trigger disabled	*/
            SetTrigger(null, 0, null, 0, null, null, 0, 0, 0);

            BlockDataHandler("First 10 readings", 0);
        }

        /****************************************************************************
        *  CollectBlockRapid
        *  this function demonstrates how to collect blocks of data
        * using the RapidCapture function
        ****************************************************************************/
        void CollectBlockRapid()
        {
            ushort numRapidCaptures = 1;
            bool   valid            = false;

            Console.WriteLine("Collect rapid block...");
            Console.WriteLine("Specify number of captures:");

            do
            {
                try
                {
                    numRapidCaptures = ushort.Parse(Console.ReadLine());
                    valid            = true;
                }
                catch
                {
                    valid = false;
                    Console.WriteLine("\nEnter numeric values only");
                }
            } while (Scope.SetNoOfRapidCaptures(_handle, numRapidCaptures) > 0 || !valid);

            int maxSamples;

            Scope.MemorySegments(_handle, numRapidCaptures, out maxSamples);

            Console.WriteLine("Collecting {0} rapid blocks. Press a key to start", numRapidCaptures);

            WaitForKey();

            SetDefaults();

            /* Trigger is optional, disable it for now	*/
            SetTrigger(null, 0, null, 0, null, null, 0, 0, 0);

            RapidBlockDataHandler(numRapidCaptures);
        }

        /****************************************************************************
        * CollectBlockTriggered
        *  this function demonstrates how to collect a single block of data from the
        *  unit, when a trigger event occurs.
        ****************************************************************************/
        void CollectBlockTriggered()
        {
            short triggerVoltage = mv_to_adc(1000, (short)_channelSettings[(int)Scope.Channel.ChannelA].range); // ChannelInfo stores ADC counts

            Scope.TriggerChannelProperties[] sourceDetails = new Scope.TriggerChannelProperties[] {
                new Scope.TriggerChannelProperties(triggerVoltage,
                                                   256 * 10,
                                                   triggerVoltage,
                                                   256 * 10,
                                                   Scope.Channel.ChannelA,
                                                   Scope.ThresholdMode.Level)
            };

            Scope.TriggerConditions[] conditions = new Scope.TriggerConditions[] {
                new Scope.TriggerConditions(Scope.TriggerState.True,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare)
            };

            Scope.ThresholdDirection[] directions = new Scope.ThresholdDirection[]
            { Scope.ThresholdDirection.Rising,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None };

            Console.WriteLine("Collect block triggered...");


            Console.Write("Collects when value rises past {0}", (_scaleVoltages) ?
                          adc_to_mv(sourceDetails[0].ThresholdMajor,
                                    (int)_channelSettings[(int)Scope.Channel.ChannelA].range)
                                    : sourceDetails[0].ThresholdMajor);
            Console.WriteLine("{0}", (_scaleVoltages) ? ("mV") : ("ADC Counts"));

            Console.WriteLine("Press a key to start...");
            WaitForKey();

            SetDefaults();

            /* Trigger enabled
             * Rising edge
             * Threshold = 1000mV */
            SetTrigger(sourceDetails, 1, conditions, 1, directions, null, 0, 0, 0);

            BlockDataHandler("Ten readings after trigger", 0);
        }

        /****************************************************************************
        * Initialise unit' structure with Variant specific defaults
        ****************************************************************************/
        void GetDeviceInfo()
        {
            int variant = 0;

            string[] description =
            {
                "Driver Version    ",
                "USB Version       ",
                "Hardware Version  ",
                "Variant Info      ",
                "Serial            ",
                "Cal Date          ",
                "Kernel Ver        "
            };
            System.Text.StringBuilder line = new System.Text.StringBuilder(80);

            if (_handle >= 0)
            {
                for (int i = 0; i < 7; i++)
                {
                    short requiredSize;
                    Scope.GetUnitInfo(_handle, line, 80, out requiredSize, i);
                    if (i == 3)
                    {
                        line.Length = 4;
                        variant     = Convert.ToInt16(line.ToString());
                    }
                    Console.WriteLine("{0}: {1}", description[i], line);
                }

                switch (variant)
                {
                case (int)Scope.Model.PS4223:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_100V;
                    _channelCount = DUAL_SCOPE;
                    break;

                case (int)Scope.Model.PS4224:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_20V;
                    _channelCount = DUAL_SCOPE;
                    break;

                case (int)Scope.Model.PS4423:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_100V;
                    _channelCount = QUAD_SCOPE;
                    break;

                case (int)Scope.Model.PS4424:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_20V;
                    _channelCount = QUAD_SCOPE;
                    break;

                case (int)Scope.Model.PS4226:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_20V;
                    _channelCount = DUAL_SCOPE;
                    break;

                case (int)Scope.Model.PS4227:
                    _firstRange   = Scope.Range.Range_50MV;
                    _lastRange    = Scope.Range.Range_20V;
                    _channelCount = DUAL_SCOPE;
                    break;

                case (int)Scope.Model.PS4262:
                    _firstRange   = Scope.Range.Range_10MV;
                    _lastRange    = Scope.Range.Range_20V;
                    _channelCount = DUAL_SCOPE;
                    break;
                }
            }
        }

        /****************************************************************************
        * Select input voltage ranges for channels A and B
        ****************************************************************************/
        void SetVoltages()
        {
            bool valid = false;

            /* See what ranges are available... */
            for (int i = (int)_firstRange; i <= (int)_lastRange; i++)
            {
                Console.WriteLine("{0} . {1} mV", i, inputRanges[i]);
            }

            /* Ask the user to select a range */
            Console.WriteLine("Specify voltage range ({0}..{1})", _firstRange, _lastRange);
            Console.WriteLine("99 - switches channel off");
            for (int ch = 0; ch < _channelCount; ch++)
            {
                Console.WriteLine("");
                uint range = 8;

                do
                {
                    try
                    {
                        Console.WriteLine("Channel: {0}", (char)('A' + ch));
                        range = uint.Parse(Console.ReadLine());
                        valid = true;
                    }
                    catch
                    {
                        valid = false;
                        Console.WriteLine("\nEnter numeric values only");
                    }
                } while ((range != 99 && (range < (uint)_firstRange || range > (uint)_lastRange) || !valid));


                if (range != 99)
                {
                    _channelSettings[ch].range = (Scope.Range)range;
                    Console.WriteLine(" = {0} mV", inputRanges[range]);
                    _channelSettings[ch].enabled = true;
                }
                else
                {
                    Console.WriteLine("Channel Switched off");
                    _channelSettings[ch].enabled = false;
                }
            }
            SetDefaults();  // Set defaults now, so that if all but 1 channels get switched off, timebase updates to timebase 0 will work
        }

        /****************************************************************************
        *
        * Select _timebase, set _oversample to on and time units as nano seconds
        *
        ****************************************************************************/
        void SetTimebase()
        {
            int  timeInterval;
            int  maxSamples;
            bool valid = false;

            Console.WriteLine("Specify timebase");

            do
            {
                try
                {
                    _timebase = uint.Parse(Console.ReadLine());
                    valid     = true;
                }
                catch
                {
                    valid = false;
                    Console.WriteLine("\nEnter numeric values only");
                }
            } while (!valid);

            while (Scope.GetTimebase(_handle, _timebase, BUFFER_SIZE, out timeInterval, 1, out maxSamples, 0) != 0)
            {
                Console.WriteLine("Selected timebase {0} could not be used", _timebase);
                _timebase++;
            }

            Console.WriteLine("Timebase {0} - {1} ns", _timebase, timeInterval);
            _oversample = 1;
        }

        /****************************************************************************
         * Stream Data Handler
         * - Used by the two stream data examples - untriggered and triggered
         * Inputs:
         * - preTrigger - the number of samples in the pre-trigger phase
         *					(0 if no trigger has been set)
         ***************************************************************************/
        void StreamDataHandler(uint preTrigger)
        {
            uint sampleCount = BUFFER_SIZE * 10; /*  *10 is to make sure buffer large enough */

            short[][]             minBuffers = new short[_channelCount][];
            short[][]             maxBuffers = new short[_channelCount][];
            PinnedArray <short>[] minPinned  = new PinnedArray <short> [_channelCount];
            PinnedArray <short>[] maxPinned  = new PinnedArray <short> [_channelCount];
            uint  totalsamples = 0;
            uint  triggeredAt  = 0;
            short status;

            uint sampleInterval = 1;

            for (int i = 0; i < _channelCount; i++) // create data buffers
            {
                minBuffers[i] = new short[sampleCount];
                maxBuffers[i] = new short[sampleCount];
                minPinned[i]  = new PinnedArray <short>(minBuffers[i]);
                maxPinned[i]  = new PinnedArray <short>(maxBuffers[i]);
                status        = Scope.SetDataBuffers(_handle, (Scope.Channel)i, minBuffers[i], maxBuffers[i], (int)sampleCount);
            }

            Console.WriteLine("Waiting for trigger...Press a key to abort");
            _autoStop = false;
            status    = Scope.RunStreaming(_handle, ref sampleInterval, Scope.ReportedTimeUnits.MicroSeconds,
                                           preTrigger, 1000000 - preTrigger, true, 1000, sampleCount);
            Console.WriteLine("Run Streaming : {0} ", status);

            Console.WriteLine("Streaming data...Press a key to abort");

            TextWriter writer = new StreamWriter("stream.txt", false);

            writer.Write("For each of the {0} Channels, results shown are....", _channelCount);
            writer.WriteLine();
            writer.WriteLine("Maximum Aggregated value ADC Count & mV, Minimum Aggregated value ADC Count & mV");
            writer.WriteLine();

            for (int i = 0; i < _channelCount; i++)
            {
                writer.Write("Ch  Max ADC    Max mV   Min ADC    Min mV   ");
            }
            writer.WriteLine();

            while (!_autoStop && !Console.KeyAvailable)
            {
                /* Poll until data is received. Until then, GetStreamingLatestValues wont call the callback */
                Thread.Sleep(100);
                _ready = false;
                Scope.GetStreamingLatestValues(_handle, StreamingCallback, IntPtr.Zero);

                if (_ready && _sampleCount > 0) /* can be ready and have no data, if autoStop has fired */
                {
                    if (_trig > 0)
                    {
                        triggeredAt = totalsamples + _trigAt;
                    }
                    totalsamples += (uint)_sampleCount;

                    Console.Write("\nCollected {0,4} samples, index = {1,5} Total = {2,5}", _sampleCount, _startIndex, totalsamples);

                    if (_trig > 0)
                    {
                        Console.Write("\tTrig at Index {0}", triggeredAt);
                    }

                    for (uint i = _startIndex; i < (_startIndex + _sampleCount); i++)
                    {
                        for (int ch = 0; ch < _channelCount; ch++)
                        {
                            if (_channelSettings[ch].enabled)
                            {
                                writer.Write("Ch{0} {1,7}   {2,7}   {3,7}   {4,7}   ",
                                             (char)('A' + ch),
                                             minPinned[ch].Target[i],
                                             adc_to_mv(minPinned[ch].Target[i], (int)_channelSettings[(int)(Scope.Channel.ChannelA + ch)].range),
                                             maxPinned[ch].Target[i],
                                             adc_to_mv(maxPinned[ch].Target[i], (int)_channelSettings[(int)(Scope.Channel.ChannelA + ch)].range));
                            }
                        }
                        writer.WriteLine();
                    }
                }
            }
            if (Console.KeyAvailable)
            {
                Console.ReadKey(true);                       // clear the key
            }
            Scope.Stop(_handle);
            writer.Close();

            if (!_autoStop)
            {
                Console.WriteLine("\ndata collection aborted");
            }


            foreach (PinnedArray <short> p in minPinned)
            {
                if (p != null)
                {
                    p.Dispose();
                }
            }
            foreach (PinnedArray <short> p in maxPinned)
            {
                if (p != null)
                {
                    p.Dispose();
                }
            }
        }

        /****************************************************************************
         * CollectStreamingImmediate
         *  this function demonstrates how to collect a stream of data
         *  from the unit (start collecting immediately)
         ***************************************************************************/
        void CollectStreamingImmediate()
        {
            SetDefaults();

            Console.WriteLine("Collect streaming...");
            Console.WriteLine("Data is written to disk file (stream.txt)");
            Console.WriteLine("Press a key to start");
            WaitForKey();

            /* Trigger disabled	*/
            SetTrigger(null, 0, null, 0, null, null, 0, 0, 0);

            StreamDataHandler(0);
        }

        /****************************************************************************
         * CollectStreamingTriggered
         *  this function demonstrates how to collect a stream of data
         *  from the unit (start collecting on trigger)
         ***************************************************************************/
        void CollectStreamingTriggered()
        {
            short triggerVoltage = mv_to_adc(1000, (short)_channelSettings[(int)Scope.Channel.ChannelA].range); // ChannelInfo stores ADC counts

            Scope.TriggerChannelProperties[] sourceDetails = new Scope.TriggerChannelProperties[] {
                new Scope.TriggerChannelProperties(triggerVoltage,
                                                   256 * 10,
                                                   triggerVoltage,
                                                   256 * 10,
                                                   Scope.Channel.ChannelA,
                                                   Scope.ThresholdMode.Level)
            };

            Scope.TriggerConditions[] conditions = new Scope.TriggerConditions[] {
                new Scope.TriggerConditions(Scope.TriggerState.True,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare,
                                            Scope.TriggerState.DontCare)
            };

            Scope.ThresholdDirection[] directions = new Scope.ThresholdDirection[]
            { Scope.ThresholdDirection.Rising,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None,
              Scope.ThresholdDirection.None };

            Console.WriteLine("Collect streaming triggered...");
            Console.WriteLine("Data is written to disk file (stream.txt)");
            Console.WriteLine("Press a key to start");
            WaitForKey();
            SetDefaults();

            /* Trigger enabled
             * Rising edge
             * Threshold = 1000mV */

            SetTrigger(sourceDetails, 1, conditions, 1, directions, null, 0, 0, 0);

            StreamDataHandler(100000);
        }

        /****************************************************************************
         * DisplaySettings
         * Displays information about the user configurable settings in this example
         ***************************************************************************/
        void DisplaySettings()
        {
            int ch;
            int voltage;

            Console.WriteLine("\n\nReadings will be scaled in {0}", (_scaleVoltages) ? ("mV") : ("ADC counts"));

            for (ch = 0; ch < _channelCount; ch++)
            {
                voltage = inputRanges[(int)_channelSettings[ch].range];
                Console.Write("Channel {0} Voltage Range = ", (char)('A' + ch));

                if (voltage < 1000)
                {
                    Console.WriteLine("{0}mV", voltage);
                }
                else
                {
                    Console.WriteLine("{0}V", voltage / 1000);
                }
            }
            Console.WriteLine();
        }