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

// @Name: ai_ct_coder.cs
// @Author: Translated from Python code
// @Copyright: Smacq
// @Date: 2024/12/25
// @Brief:
// The Ai and Ct functions of USB - 3300 are used for Ai and Counter synchronous acquisition.
// Synchronously acquire 100 data points from Ai0 channel and CT0 of 10 times.
// Only USB - 3300 supports Counter functions.
// You can refer to the user manual for more information about functions or device details.
//
// USB - 3300 only connect USB execution result:
// Device_number: 1
// 0
// Device_Index: 0 Device_SN: 66666666 Device_Model: 3323
// 0
//...
// 0
// ai_remain_buffer: 0
// Ai0 100 data points£º
//  [0.02281528 0.0237529  0.02531559 0.02719082 0.02812843 0.02844097
//...
//   0.02031498 0.02094006 0.02125259 0.02219021]
// ct_remain_buffer: 3
// 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]
// Press Enter to continue...
// 0
// 0
// 0
// 0

class Program
{
    static void Main(string[] args)
    {
        // Init Ai_data_array
        // Usually the array size need >= acquisition data points size.
        // Data type is float32_t, it is not modifiable.
        // The data points saved to Ai_data_array arrange from opened Ai channel
        float[] Ai_data_array = new float[2400];

        // Init Ct_data_array
        // Usually the array size need >= acquisition data points size.
        // Data type is int32_t, it is not modifiable.
        // The data points saved to Ct_data_array arrange from get counter channel
        uint[] ct0_data_array = new uint[1000];

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

        // Ai voltage range
        // 10.24 = -10.24 to +10.24V and so on
        // Voltage range param support 10.24/5.12/2.56/1.28/0.64
        float Range = 10.24f;

        // Ai channel sample mode
        // 0=Continuous acquisition or 1=Oneshot, param support 0/1
        byte AiSampleMode = 0;

        // Ai channel connect type
        // 0=Diff or 1=NRSE, param support 0/1
        byte AiConnectType = 1;

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

        // Configuration values for Ai channels
        // Device model channel number start from 0
        byte Channel = 0;

        // Set channel ON/OFF
        byte Channel_ON = 1;
        byte Channel_OFF = 0;

        // Ai Sampling period, unit ns, steps 10ns
        // USB - 3000 is asynchronous DAQ, single channel max rate is 1M=1000.
        // Multichannel each channel share out samplerate, 1M/channel.
        // sample rate and period:
        // 100k = 10000
        // 10k  = 100000
        // 1k   = 1000000
        // 100  = 10000000
        // 10   = 100000000
        // 1    = 1000000000
        uint AiSamplePeriod = 1000000;

        // Ai acquisition trig source
        // 0=SetUSB3AiSoftTrig(), 1=Ext_Trig_In, 2~5=Din_0~3,
        // 7=with DI, 8=with DO, 9~12=with AO~3, 255=GlobalSoftTrig
        // param support 0/1/2/3/4/5/7/8/9/10/11/12/255
        byte AiTrigSource = 0;

        // Ai acquisition clock source
        // 0=SetUSB3AiSampleRate(), 1=Conv_In, 3=Di, 4=DO, 5~8=AO~3
        // param support 0/1/3/4/5/6/7/8
        byte AiConvSource = 0;

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

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

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

        // 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
        // param support 0/1/2/3/4/5/7/8/9/10/11/12/255
        byte CtTrigSource = 6;

        // counter acquisition clock source
        // 0=SetCtSampleRate(), 1=Conv_In, 2=Ai, 3=Di, 4=DO, 5~8=AO~3
        // param support 0/1/2/3/4/5/6/7/8
        byte CtConvSource = 2;

        // counter encoder mode
        // 0: Quadrature encoder, X1
        // 1: Quadrature encoder, X2
        // 2: Quadrature encoder, X4
        // 3: Two pulse encoder
        byte CtEncoderMode = 0;

        // counter Z init value
        uint CtZValue = 0;

        // For SetCtZPhase() A and B trig Z init(0 is LOW, 1 is HIGH)
        byte CtALev = 0;
        byte CtBLev = 0;

        // 0 is disable, 1 is enable
        byte CtZEnable = 0;

        // counter channel
        byte ct_channel_0 = 0;

        int error_code;

        // Find connected DAQ number
        int Device_number = USB3000DLL.FindUSB3DAQ();
        Console.WriteLine($"Device_number: {Device_number}");

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

        // Get and print Device_SN
        int Device_SN = USB3000DLL.USB3ReadDevcieSN(DevIndex);
        int Device_Model = USB3000DLL.USB3ReadDevcieModel(DevIndex);
        Console.WriteLine($"Device_Index: {DevIndex} Device_SN: {Device_SN} Device_Model: {Device_Model}");


        // Turn OFF Ai channel 0 - 8 (default Ai channel 0 - 8 is ON)
        for (byte channel = 0; channel < 8; channel++)
        {
            error_code = USB3000DLL.SetUSB3AiChanSel(DevIndex, channel, Channel_OFF);
            if (error_code != 0)
            {
                Console.WriteLine(error_code);
            }
        }

        // Turn ON and set input voltage Range for Ai channel 0
        for (byte channel = 0; channel < 1; channel++)
        {
            error_code = USB3000DLL.SetUSB3AiChanSel(DevIndex, channel, Channel_ON);
            Console.WriteLine(error_code);
            error_code = USB3000DLL.SetUSB3AiRange(DevIndex, channel, Range);
            Console.WriteLine(error_code);
        }

        // Set Device Ai sample mode
        error_code = USB3000DLL.SetUSB3AiSampleMode(DevIndex, AiSampleMode);
        Console.WriteLine(error_code);

        // Set Device Ai connect type
        error_code = USB3000DLL.SetUSB3AiConnectType(DevIndex, AiConnectType);
        Console.WriteLine(error_code);

        // Set Device sample rate
        error_code = USB3000DLL.SetUSB3AiSampleRate(DevIndex, AiSamplePeriod);
        Console.WriteLine(error_code);

        // Set Device clock source
        error_code = USB3000DLL.SetUSB3AiConvSource(DevIndex, AiConvSource);
        Console.WriteLine(error_code);

        // Clear AI FIFO
        error_code = USB3000DLL.SetUSB3ClrAiFifo(DevIndex);
        Console.WriteLine(error_code);

        // Set Device trig source
        error_code = USB3000DLL.SetUSB3AiTrigSource(DevIndex, AiTrigSource);
        Console.WriteLine(error_code);

        // Set counter clock source
        error_code = USB3000DLL.SetCtConvSource(DevIndex, ct_channel_0, CtConvSource);
        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 counter trig source together with Ai
        error_code = USB3000DLL.SetCtTrigSource(DevIndex, ct_channel_0, CtTrigSource);
        Console.WriteLine(error_code);

        // Set the starting condition of Z index
        error_code = USB3000DLL.SetCtZPhase(DevIndex, ct_channel_0, CtALev, CtBLev);
        Console.WriteLine(error_code);

        // Set the value after trig Z function
        error_code = USB3000DLL.SetCtZValue(DevIndex, ct_channel_0, CtZValue);
        Console.WriteLine(error_code);

        // Set Z function enable
        error_code = USB3000DLL.SetCtZEnable(DevIndex, ct_channel_0, CtZEnable);
        Console.WriteLine(error_code);

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

        // Enable Ai software trig acquisition
        error_code = USB3000DLL.SetUSB3AiSoftTrig(DevIndex);
        Console.WriteLine(error_code);

        // Continuous execution 10 times USB3GetAi() and  USB3GetCt()
        for (int i = 0; i < 10; i++)
        {
            ulong ai_remain_buffer = (ulong)USB3000DLL.USB3GetAi(DevIndex, Num, Ai_data_array, Timeout);
            Console.WriteLine($"ai_remain_buffer: {ai_remain_buffer}");
            Console.WriteLine("Ai0 100 data points£º");
            for (int j = 0; j < 100; j++)
            {
                Console.WriteLine($"{Ai_data_array[j]} ");
            }
            Console.WriteLine();

            ulong ct_remain_buffer = (ulong)USB3000DLL.USB3GetCt(DevIndex, ct_channel_0, Num, ct0_data_array, Timeout);
            Console.WriteLine($"ct_remain_buffer: {ct_remain_buffer}");
            Console.WriteLine("ct0 100 data points£º");
            for (int j = 0; j < 100; j++)
            {
                Console.WriteLine($"{(int)ct0_data_array[j]} ");
            }
            Console.WriteLine();
        }

        Console.WriteLine("Press Enter to continue...");
        Console.ReadKey();

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

        // Clear AI FIFO
        error_code = USB3000DLL.SetUSB3ClrAiFifo(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);
    }
}