using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

// @Name: di_oneshot.cs
// @Author: Smacq
// @Copyright: Smacq
// @Date: 2024/12/25
// @Brief:
// This code focuses on the Di functions of the USB - 3000 device, performing digital input.
// It acquires 100 data points from the Di channel 10 times.
// The DI default suspended is 3.3V HIGH, and 0 - 1.2V is LOW.
// The DI channels vary depending on the module, either 4DI or 8DI.
// The oneshot limit is 110 data points, similar to the acquisition in other functions.
// You can refer to the user manual for more information about functions or device details.
//
// Execution result when only connecting USB for USB - 3000(DI_4):
// 0
// 0
// 0
// 0
// 0
// 0
// 0
// 0
// remain_buffer: 2
// Di_channel 100 data points
//  15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15
//  15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15
//  15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15
//  15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15
//  15 15 15 15
// Last_remain_buffer: 10
// 0
// 0

class Program
{
    static void Main(string[] args)
    {
        // Device index starts from zero
        int DevIndex = 0;

        // Init Di_data_array
        // Usually the array size need >= acquisition data points size.
        // The data points saved to Di_data_array arrange from opened Di channel
        // Data type is uint8, it is not modifiable.
        // Di_channel_4:0~0xF(1111) Di3~DI0, Di_channel_8:0~0xFF(1111 1111) Di7~DI0.
        byte[] Di_data_array = new byte[1000];

        // Di channel sample mode:
        // 0 = Continuous acquisition or 1 = Oneshot, param support 0/1
        byte DiSampleMode = 1;

        // DiOneShotPoints > Num, limit 110 all data point number
        uint DiOneShotPoints = 110;

        // When acquisition amount is 0, just check FIFO return:
        uint Zero = 0;

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

        // Di Sampling period, unit ns, steps 10ns:
        // USB - 3000 is synchronous DI, channel max rate is 10M = 100.
        // sample rate and period:
        // 1M = 1000
        // 100k = 10000
        // 10k = 100000
        // 1k = 1000000
        // 100 = 10000000
        // 10 = 100000000
        // 1 = 1000000000
        uint DiSamplePeriod = 1000000;

        // Di acquisition trig source:
        // 0 = SetUSB3DiSoftTrig(), 1 = Ext_Trig_In, 2~5 = Din_0~3,
        // 6 = with Di, 8 = with DO, 9~12 = with AO~3, 255 = GlobalSoftTrig
        // Supported parameters: 0/1/2/3/4/5/6/8/9/11/12/255
        byte DiTrigSource = 0;

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

        // Timeout unit ms:
        // Suggest Timeout>(Num*Channel_count/Samplerate)*1000
        // Avoid USB3GetDi() 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);

        // Don't need SetUSB3ClrDiTrigger(), set limit 110 data point acquisition
        error_code = USB3000DLL.SetUSB3DiOneShotPoints(DevIndex, DiOneShotPoints);
        Console.WriteLine(error_code);

        // Set Device Di sample mode
        error_code = USB3000DLL.SetUSB3DiSampleMode(DevIndex, DiSampleMode);
        Console.WriteLine(error_code);

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

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

        // Clear Di FIFO
        error_code = USB3000DLL.SetUSB3ClrDiFifo(DevIndex);
        Console.WriteLine(error_code);

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

        // Enable Di software trig acquisition
        error_code = USB3000DLL.SetUSB3DiSoftTrig(DevIndex);
        Console.WriteLine(error_code);

        ulong remain_buffer = (ulong)USB3000DLL.USB3GetDi(DevIndex, Points, Di_data_array, Timeout);
        /*
        remain_buffer range 0~2000000
        USB3GetDi() return the remaining Device FIFO buffer value.
        FIFO buffer 100 data points save to Di_data_array.
        Channel_0 100 data points is Di_data_array[0:100]

        If remain_buffer increase you should run USB3GetDi() more quick, let remain_buffer steady.
        */
        Console.WriteLine("remain_buffer: " + remain_buffer);
        Console.WriteLine("Di_channel 100 data points\n");
        for (int i = 0; i < 100; ++i)
        {
            Console.Write(Di_data_array[i] + " ");
        }
        Console.WriteLine();

        Thread.Sleep(3000);

        // Print and check FIFO remain 10 data point
        remain_buffer = (ulong)USB3000DLL.USB3GetDi(DevIndex, Zero, Di_data_array, Timeout);
        Console.WriteLine("Last_remain_buffer: " + remain_buffer);

        // Clear Di FIFO
        error_code = USB3000DLL.SetUSB3ClrDiFifo(DevIndex);
        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);
        [DllImport("USB3000.dll")]
        public static extern int SetUSB3AoImmediately4Chans(int DevIndex, float Volt0, float Volt1, float Volt2, float Volt3);

        //--------------------------------------------------------------------------
        // 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);
    }

}