using System;
using System.Runtime.InteropServices;
using System.Threading;

// @Name: ct_count_edge.cs
// @Author: Smacq
// @Copyright: Smacq
// @Date: 2024/12/25
// @Brief:
// This code focuses on the Ct functions of the USB - 3300 device, performing counter acquisition to count rising edges.
// It acquires 100 data points from CT0 10 times, with an interval of 1 second.
// Only USB - 3300 supports counter functions. signel -> Ct0Src
// You can refer to the user manual for more information about functions or device details.
//
// Execution result when only connecting USB for USB - 3300:
// 0
//...
// 0
// ct_remain_buffer: 1550
// ct0 100 data points
// 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
//...
// 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
// 0
// 0
// 0


class Program
{
    static void Main(string[] args)
    {
        // Init Ct_data_array
        // Usually the array size need >= acquisition data points size.
        // Data type is unsigned int, it is not modifiable.
        // The data points saved to ct_data_array arrange from get counter channel
        uint[] ct0_data_array = new uint[100];

        // Device index starts from zero
        int DevIndex = 0;

        // Counter run mode:
        // 0: Counting edge
        // 1: Pulse width measurement
        // 2: Pulse measurement
        // 3: Reserve
        // 4: Frequency measurement
        // 5: Quadrature encoder measurement
        byte CtRunMode = 0;

        // Counter Sample mode:
        // 0: Single spot measurement
        // 1: Sampling clock buffer continuous acquisition
        // 2: Implicit buffer acquisition
        byte CtSampleMode = 1;

        // Ct Sampling period, unit ns, steps 10ns:
        // USB - 3300 Counter is asynchronous, max rate is 100k = 10000.
        // sample rate and period:
        // 10k = 100000
        // 1k = 1000000
        // 100 = 10000000
        // 10 = 100000000
        // 1 = 1000000000
        uint CtSampleRate = 10000000;

        // Acquisition amount of data:
        // Each opened Ai channel will get this amount of data.
        // Suggest value within sampling rate 10%~20%.
        uint Num = 100;

        // Counter trig source
        // 0 = SetCtTrigSource(), 1 = Ext_Trig_In, 2~5 = Din_0~3,
        // 7 = with DI, 8 = with DO, 9~12 = with AO~3, 255 = GlobalSoftTrig
        // Supported parameters: 0/1/2/3/4/5/7/8/9/10/11/12/255
        byte CtTrigSource = 0;

        // Counter acquisition clock source:
        // 0 = SetCtSampleRate(), 1 = Conv_In, 3 = Di, 4 = DO, 5~8 = AO~3
        // Supported parameters: 0/1/3/4/5/6/7/8
        byte CtConvSource = 0;

        // Counter channel
        byte ct_channel_0 = 0;

        // Count start value
        uint CtValue = 0;

        // Set edge level: 1 = Rising edge, 2 = Falling edge
        byte CtCountEdge = 1;

        // Count edge overflow value
        uint CtOverflowValueEdgeCount = 1000;

        // start value of trig overflow
        uint CtReloadValueEdgeCount = 0;

        // Direction: 0 = Decrease, 1 = Increase
        byte CtDirEdgeCount = 1;

        // Src signal: 0 = Internal, 1 = Src signal on external terminal
        byte SrcSel = 1;

        // Timeout unit ms:
        // Suggest Timeout>(Num*Channel_count/Samplerate)*1000
        // Avoid USB3GetAi() func timeout, if timeout return -7.
        int Timeout = 200;

        int error_code;

        // Open specific device and print return value.
        error_code = USB3000DLL.USB3OpenDevice(DevIndex);
        Console.WriteLine(error_code);

        // Set counter run mode
        error_code = USB3000DLL.SetCtRunMode(DevIndex, ct_channel_0, CtRunMode);
        Console.WriteLine(error_code);

        // Set counter sample mode
        error_code = USB3000DLL.SetCtSampleMode(DevIndex, ct_channel_0, CtSampleMode);
        Console.WriteLine(error_code);

        // Set sample rate
        error_code = USB3000DLL.SetCtSampleRate(DevIndex, ct_channel_0, CtSampleRate);
        Console.WriteLine(error_code);

        // Set counter trig source
        error_code = USB3000DLL.SetCtTrigSource(DevIndex, ct_channel_0, CtTrigSource);
        Console.WriteLine(error_code);

        // Set counter clock source
        error_code = USB3000DLL.SetCtConvSource(DevIndex, ct_channel_0, CtConvSource);
        Console.WriteLine(error_code);

        // Set counter single source
        error_code = USB3000DLL.SetCtSrcSel(DevIndex, ct_channel_0, SrcSel);
        Console.WriteLine(error_code);

        // Set edge level
        error_code = USB3000DLL.SetCtCountEdge(DevIndex, ct_channel_0, CtCountEdge);
        Console.WriteLine(error_code);

        // Set the value of start counter
        error_code = USB3000DLL.SetCtValue(DevIndex, ct_channel_0, CtValue);
        Console.WriteLine(error_code);

        // Set count overflow limit value
        error_code = USB3000DLL.SetCtOverflowValueEdgeCount(DevIndex, ct_channel_0, CtOverflowValueEdgeCount);
        Console.WriteLine(error_code);

        // Set start value of trig overflow
        error_code = USB3000DLL.SetCtReloadValueEdgeCount(DevIndex, ct_channel_0, CtReloadValueEdgeCount);
        Console.WriteLine(error_code);

        // Set counter direction Decrease or Increase
        error_code = USB3000DLL.SetCtDirEdgeCount(DevIndex, ct_channel_0, CtDirEdgeCount);
        Console.WriteLine(error_code);

        // clear counter FIFO
        error_code = USB3000DLL.SetCtClrFifo(DevIndex, ct_channel_0);
        Console.WriteLine(error_code);

        // Enable soft Trig, start acquisition counter
        error_code = USB3000DLL.SetCtSoftTrig(DevIndex, ct_channel_0);
        Console.WriteLine(error_code);

        // Continuous execution 10 times GetAiChans()
        for (int i = 0; i < 10; ++i)
        {
            Thread.Sleep(1000);
            ulong ct_remain_buffer = (ulong)USB3000DLL.USB3GetCt(DevIndex, ct_channel_0, Num, ct0_data_array, Timeout);
            /*
            USB3GetCt() return the remaining Device FIFO buffer value.
            FIFO buffer 100 data points save to Ct0_data_array[0:100].
            If remain_buffer increase you should run USB3GetCt() more quick, let remain_buffer steady.
            */
            Console.WriteLine($"ct_remain_buffer: {ct_remain_buffer}");
            Console.WriteLine("ct0 100 data points");
            for (int j = 0; j < 100; ++j)
            {
                Console.Write($"{ct0_data_array[j]} ");
            }
            Console.WriteLine();
        }

        // Disable all trig, clear flag
        error_code = USB3000DLL.SetUSB3ClrTrigger(DevIndex);
        Console.WriteLine(error_code);

        // Clear CT FIFO
        error_code = USB3000DLL.SetCtClrFifo(DevIndex, ct_channel_0);
        Console.WriteLine(error_code);

        // Close Device
        error_code = USB3000DLL.USB3CloseDevice(DevIndex);
        Console.WriteLine(error_code);
    }

    class USB3000DLL
    {
        [DllImport("USB3000.dll")]
        public static extern int FindUSB3DAQ();
        [DllImport("USB3000.dll")]
        public static extern int USB3OpenDevice(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int USB3CloseDevice(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int USB3ReadDevcieSN(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int USB3ReadDevcieModel(int DevIndex);

        //--------------------------------------------------------------------------
        // Ananlog Input Configuration

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiSampleRate(int DevIndex, uint SamplePeriod);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiSampleMode(int DevIndex, byte AiSampleMode);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiConnectType(int DevIndex, byte AiConnectType);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiRange(int DevIndex, byte Chan, float AiRange);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiChanSel(int DevIndex, byte Chan, byte Sel);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiTrigSource(int DevIndex, byte AiTrigSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiConvSource(int DevIndex, byte AiConvSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiPreTrigPoints(int DevIndex, uint AiPreTrigPoints);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiOneShotPoints(int DevIndex, uint AiOneShotPoints);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrAiFifo(int DevIndex);

        //--------------------------------------------------------------------------
        // Digital I/O Configuration

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiSampleRate(int DevIndex, uint SamplePeriod);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiSampleMode(int DevIndex, byte DiSampleMode);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiTrigSource(int DevIndex, byte DiTrigSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiConvSource(int DevIndex, byte DiConvSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiPreTrigPoints(int DevIndex, uint DiPreTrigPoints);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiOneShotPoints(int DevIndex, uint DiOneShotPoints);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrDiFifo(int DevIndex);

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoSampleRate(int DevIndex, uint SamplePeriod);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoSampleMode(int DevIndex, byte DoSampleMode);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoTrigSource(int DevIndex, byte DoTrigSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoConvSource(int DevIndex, byte DoConvSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoCycle(int DevIndex, uint DoCycle);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoDataFifo(int DevIndex, uint[] Value, uint Len);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrDoFifo(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoWaveCtrl(int DevIndex, uint Chan);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoImmediately(int DevIndex, uint Chan, uint Value);

        //--------------------------------------------------------------------------
        // Ananlog Output Configuration

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoSampleRate(int DevIndex, byte Chan, uint SamplePeriod);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoSampleMode(int DevIndex, byte Chan, byte AoSampleMode);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoTrigSource(int DevIndex, byte Chan, byte AoTrigSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoConvSource(int DevIndex, byte Chan, byte AoConvSource);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoCycle(int DevIndex, byte Chan, byte AoCycle);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoDataFifo(int DevIndex, byte Chan, float[] Voltage, uint Len);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrAoFifo(int DevIndex, byte Chan);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoSync(int DevIndex, byte Chans);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoImmediately(int DevIndex, byte Chan, float Voltage);

        //--------------------------------------------------------------------------
        // Timer/Counter Configuration
        [DllImport("USB3000.dll")]
        public static extern int SetCtRunMode(int DevIndex, byte Chan, byte CtRunMode);
        [DllImport("USB3000.dll")]
        public static extern int SetCtSampleMode(int DevIndex, byte Chan, byte CtSampleMode);
        [DllImport("USB3000.dll")]
        public static extern int SetCtSampleRate(int DevIndex, byte Chan, uint SamplePeriod);
        [DllImport("USB3000.dll")]
        public static extern int SetCtTrigSource(int DevIndex, byte Chan, byte CtTrigSource);
        [DllImport("USB3000.dll")]
        public static extern int SetCtConvSource(int DevIndex, byte Chan, byte CtConvSource);
        [DllImport("USB3000.dll")]
        public static extern int SetCtCountEdge(int DevIndex, byte Chan, byte CtCountEdge);
        [DllImport("USB3000.dll")]
        public static extern int SetCtValue(int DevIndex, byte Chan, uint Value);
        [DllImport("USB3000.dll")]
        public static extern int SetCtOverflowValueEdgeCount(int DevIndex, byte Chan, uint OverflowValue);
        [DllImport("USB3000.dll")]
        public static extern int SetCtFrontPartValueEdgeCount(int DevIndex, byte Chan, uint FrontPartValue);
        [DllImport("USB3000.dll")]
        public static extern int SetCtReloadValueEdgeCount(int DevIndex, byte Chan, uint ReloadValue);
        [DllImport("USB3000.dll")]
        public static extern int SetCtDirEdgeCount(int DevIndex, byte Chan, byte Dir);
        [DllImport("USB3000.dll")]
        public static extern int SetCtPulseWidthStartEdge(int DevIndex, byte Chan, byte StartEdge);
        [DllImport("USB3000.dll")]
        public static extern int SetCtInternalSrcPeriod(int DevIndex, byte Chan, uint Period);
        [DllImport("USB3000.dll")]
        public static extern int SetCtSrcSel(int DevIndex, byte Chan, byte SrcSel);
        [DllImport("USB3000.dll")]
        public static extern int SetCtEncodeMode(int DevIndex, byte Chan, byte EncodeMode);
        [DllImport("USB3000.dll")]
        public static extern int SetCtZPhase(int DevIndex, byte Chan, byte ALev, byte BLev);
        [DllImport("USB3000.dll")]
        public static extern int SetCtZValue(int DevIndex, byte Chan, uint Value);
        [DllImport("USB3000.dll")]
        public static extern int SetCtZEnable(int DevIndex, byte Chan, byte Enable);
        [DllImport("USB3000.dll")]
        public static extern int SetCtSoftTrig(int DevIndex, byte Chan);
        [DllImport("USB3000.dll")]
        public static extern int SetCtClrFifo(int DevIndex, byte Chan);

        //--------------------------------------------------------------------------
        // Trig Control

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AiSoftTrig(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DiSoftTrig(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3DoSoftTrig(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoSoftTrig(int DevIndex, byte Chan);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3GlobalSoftTrig(int DevIndex);

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrTrigger(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrAiTrigger(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrDiTrigger(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrDoTrigger(int DevIndex);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrAoTrigger(int DevIndex, byte Chan);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ClrGlobalSoftTrig(int DevIndex);

        //--------------------------------------------------------------------------
        // Sync Configuration

        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ExtTrigOutSource(int DevIndex, byte Source);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3ExtConvOutSource(int DevIndex, byte Source);

        //--------------------------------------------------------------------------
        // Get Data Acquired

        [DllImport("USB3000.dll")]
        public static extern int USB3GetAi(int DevIndex, uint Points, float[] Ai, int TimeOut);
        [DllImport("USB3000.dll")]
        public static extern int USB3GetDi(int DevIndex, uint Points, byte[] Di, int TimeOut);
        [DllImport("USB3000.dll")]
        public static extern int USB3GetCt(int DevIndex, byte Chan, uint Points, uint[] Ct, int TimeOut);
        [DllImport("USB3000.dll")]
        public static extern int GetLatestCtValue(int DevIndex, byte Chan, ref uint Ct, int TimeOut);
    }
}