USB-1608G CSharp (C#) Continuous Buffer Read

The example below demonstrates how to read a buffer that is being filled continuously with live data. It uses ALoadQueue(..), AInScan(…) and ScaledWinBufToArray(…), GetStatus(…) to read a group of analog input channels. Data is written to an ASCII text file that can be viewed and verified using Excel, DASYLab, NI LabVIEW, MatLab® and other programs capable of text import.

The functionality is as follows, the acquisition puts data into a continuously looping buffer and the program retrieves it one half buffer at a time. The continuous mode is set using the Scan Options enumeration Background and Continuous. Data is collected by ping-pongs between the lower half then the upper looping fast enough to keep up. Care should be taken that data doesn't come in so fast that the program fails to keep up. When this happens a buffer overrun occurs which is condition where unread data get overwritten.

Although not shown below, a few convenience functions were added such as IsError, GetBoardNum, DisplayData, CreateFileHeader and WaitForKey. To view all the functions download the complete Visual Studio 2008 project by extracting the zip file at the bottom.

The IsError function checks the error number in the ErrorInfo object and if not zero displays the error message. The GetBoardNum function searches for a device matching the identifying string and when found exits returning the board number assigned by InstaCal. The board number is used to get the controlling device object that has AInScan function. The CreateFileHeader writes acquisition information to the beginning of the output file. The Display data writes the data to the file and console screen. And WaitForKey does just that - waits for someone to press the spacebar.

If starting a new project using Visual Studio, you must first add a reference to the MccDaq object before objects and variables. Adding the reference is usually accomplished by right clicking the Project [under the Project Explorer] and selecting Add Reference.

Disclaimer: The attached Code or Example is provided As Is. It has not been tested or validated as a product, for use in a deployed application or system, or for use in hazardous environments. You assume all risks for use of the Code or Example.

using System;
using MccDaq;
using System.IO;
namespace AinScanBackgroundContinuousScan
    class Program
        public const int BLOCKSIZE      = 50;
        public const int CHANCOUNT      = 4;
        public const int FIRSTCHANNEL   = 0;
        public const int LASTCHANNEL    = 3;
        public const int FREQ           = 100;
        public const int BUFFERSIZE     = BLOCKSIZE * CHANCOUNT;
        public const int HALFBUFFSIZE   = BUFFERSIZE / 2;
        public const string DEVICE = "1608G";

        public static StreamWriter fStream;
        static void Main(string[] args)

            MccDaq.ErrorInfo RetVal;

            int     BoardNum        = 0;
            int     DeviceChannels  = 0;
            int     Rate            = FREQ;
            bool    ReadLower       = true;
            BoardNum = GetBoardNum(DEVICE);

            if( BoardNum == -1 )
                Console.WriteLine("No USB-{0} detected!", DEVICE );
                MccBoard daq = new MccDaq.MccBoard( BoardNum );
                daq.BoardConfig.GetNumAdChans(out DeviceChannels);
                if (DeviceChannels > 8)
                    Console.WriteLine( "Single-Ended Channels" );
                    Console.WriteLine( "Differentially-Ended Channels" );

                IntPtr buffer = MccService.ScaledWinBufAllocEx( BUFFERSIZE );

                if( buffer == IntPtr.Zero )
                    Console.WriteLine( "Bad Handle" );

                short[] chArray = new short[CHANCOUNT]; //configuration array for channel numbers
                Range[] chRange = new Range[CHANCOUNT]; //configuration array for input ranges

                chArray[0] = 0;
                chArray[1] = 1;
                chArray[2] = 2;
                chArray[3] = 3;

                chRange[0] = Range.Bip10Volts;
                chRange[1] = Range.Bip10Volts;
                chRange[2] = Range.Bip10Volts;
                chRange[3] = Range.Bip10Volts;

                RetVal = daq.ALoadQueue( chArray, chRange, CHANCOUNT );

                //setup the acquisiton
                RetVal = daq.AInScan(   FIRSTCHANNEL, 
                                        ref Rate, 
                                        ScanOptions.Background | ScanOptions.ScaleData | ScanOptions.Continuous

                fStream = new StreamWriter(@"C:\Users\Public\Documents\DataFile1608G.asc");
                CreateFileHeaders(chArray); //writes basic info to the beginning of the file

                int Count = 0;
                int Index = 0;
                short daqStatus;

                double[] theArray = new double[BUFFERSIZE];

                System.ConsoleKeyInfo cki = new System.ConsoleKeyInfo();

                //Loop until key press
                    RetVal = daq.GetStatus( out daqStatus, out Count, out Index, FunctionType.AiFunction );
                    if ((Index >= HALFBUFFSIZE) & ReadLower) //check for 50% more data
                        //get lower half of buffer - ScaledWinBufToArray returns engineering units
                        RetVal = MccService.ScaledWinBufToArray(buffer, theArray, 0, HALFBUFFSIZE);

                        DisplayData(theArray, HALFBUFFSIZE/CHANCOUNT);
                        ReadLower = false; //flag that controls the next read
                    else if ((Index < HALFBUFFSIZE) & !ReadLower)
                        //get the upper half  - ScaledWinBufToArray returns engineering units
                        RetVal = MccService.ScaledWinBufToArray(buffer, theArray, HALFBUFFSIZE, HALFBUFFSIZE);

                        DisplayData(theArray, HALFBUFFSIZE/CHANCOUNT);
                        ReadLower = true;//flag that controls the next read

                } while (!Console.KeyAvailable);

                cki = Console.ReadKey();

                //flush any buffered data out to disk

                //stop the  acquisition
                RetVal = daq.StopBackground(FunctionType.AiFunction);

                //free up memory