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

// @Name: ao_waveform_pc_infinite.cs
// @Author: Smacq
// @Copyright: Smacq
// @Date: 2024/12/25
// @Brief:
// This code focuses on the Ao functions of the USB - 3000 device, performing waveform output.
// It outputs a -1V ~ 1V sine wave and a -5V ~ +5V square wave on Ao channel 0.
// The device's AO analog voltage range is -10V ~ +10V.
// The Ao channels vary depending on the module, either Ao_4 or NONE.
// You can refer to the user manual for more information about functions or device details.
//
// Execution result when only connecting USB for USB - 3000(Ao_4):
// 0
//...
// 0
// Ao0 outputting -1V and 1V sine wave, Please Enter to next wave.
// 0
// 0
// 0
// 0
// Ao0 outputting -1V and 1V square wave, Please Enter to stop output.
// 0 AOChannel_0 is 0V
// 0
// 0
// 0

class Program
{
    static void Main(string[] args)
    {
        // init -1 ~ 1V sine wave to Ao_data_array
        float[] Ao_data_array_sine = new float[1000];
        // init -1V and 1V square wave 200 data point to Ao_data_array
        float[] Ao_data_array_square = new float[200];

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

        // Ao channel, Ao channel 0 to Ao channel 3
        byte AOChannel_0 = 0;
        byte AOChannel_1 = 1;
        byte AOChannel_2 = 2;
        byte AOChannel_3 = 3;

        // voltage value, range is -10 to +10
        float voltage_0 = 0.0f;

        // Ao channel sample mode:
        // 0 = continuous non - loop output to computer buffer
        // 1 = FIFO output loop determined by SetUSB3AoCycle()
        byte AoSampleMode = 1;

        // Ao Sampling period, unit ns, steps 10ns:
        // USB - 3000 is synchronous Ao, max rate is 100k = 10000.
        // sample rate and period:
        // 10k = 100000
        // 1k = 1000000
        // 100 = 10000000
        // 10 = 100000000
        // 1 = 1000000000
        uint AoSampleRate = 10000000;

        // Ao acquisition trig source:
        // 0 = SetUSB3AoSoftTrig(), 1 = Ext_Trig_In, 2~5 = Din_0~3,
        // 6 = with Ai, 7 = with Di, 7 = with Do, 9~12 = with AO~3, 255 = GlobalSoftTrig
        // Supported parameters: 0/1/2/3/4/5/6/7/8/9/10/11/12/255
        byte AoTrigSource = 0;

        // Ao acquisition clock source:
        // 0 = SetUSB3AoSampleRate(), 1 = Conv_In, 2 = Ai, 3 = Di, 5~8 = AO~3
        // Supported parameters: 0/1/2/3/5/6/7/8
        byte AoConvSource = 0;

        // Set waveform output cycle
        // 0 = infinite loop output
        // 1 = 1 time, 2 = 2 times and so on.
        // Supported parameters: 0 ~ 4294967295
        byte AoCycle = 0;

        // Download to Ao FIFO data number for sine wave
        uint Num_sine = 1000;
        // Download to Ao FIFO data number for square wave
        uint Num_square = 200;

        // Function to initialize sine wave data array
        void initSineWave(float[] array)
        {
            for (int i = 0; i < 1000; i++)
            {
                double x = -2 * Math.PI + (4 * Math.PI * i) / 999;
                array[i] = (float)Math.Sin(x);
            }
        }

        // Function to initialize square wave data array
        void initSquareWave(float[] array)
        {
            for (int i = 0; i < 100; i++)
            {
                array[i] = 1.0f;
            }
            for (int i = 100; i < 200; i++)
            {
                array[i] = -1.0f;
            }
        }

        
        int error_code;

        initSineWave(Ao_data_array_sine);

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

        // Disable Ao software trig, clear flag
        error_code = USB3000DLL.SetUSB3ClrAoTrigger(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        // Clear FIFO
        error_code = USB3000DLL.SetUSB3ClrAoFifo(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        // Set Device Ao sample mode
        error_code = USB3000DLL.SetUSB3AoSampleMode(DevIndex, AOChannel_0, AoSampleMode);
        Console.WriteLine(error_code);

        // Set Device sample rate
        error_code = USB3000DLL.SetUSB3AoSampleRate(DevIndex, AOChannel_0, AoSampleRate);
        Console.WriteLine(error_code);

        // Set Device trig source
        error_code = USB3000DLL.SetUSB3AoTrigSource(DevIndex, AOChannel_0, AoTrigSource);
        Console.WriteLine(error_code);

        // Set Device clock source
        error_code = USB3000DLL.SetUSB3AoConvSource(DevIndex, AOChannel_0, AoConvSource);
        Console.WriteLine(error_code);

        // Set digital output cycle 2 times
        error_code = USB3000DLL.SetUSB3AoCycle(DevIndex, AOChannel_0, AoCycle);
        Console.WriteLine(error_code);

        // Download array data to Ao FIFO for sine wave
        error_code = USB3000DLL.SetUSB3AoDataFifo(DevIndex, AOChannel_0, Ao_data_array_sine, Num_sine);
        Console.WriteLine(error_code);

        // Enable Ao software trig start Ao output wave
        error_code = USB3000DLL.SetUSB3AoSoftTrig(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        Console.WriteLine("Ao0 outputting -1V and 1V sine wave, Please Enter to next wave.");
        Console.ReadLine();

        // Disable Ao software trig, clear flag
        error_code = USB3000DLL.SetUSB3ClrAoTrigger(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        // Clear FIFO
        error_code = USB3000DLL.SetUSB3ClrAoFifo(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        initSquareWave(Ao_data_array_square);

    // Download array data to Ao FIFO for square wave
    error_code = USB3000DLL.SetUSB3AoDataFifo(DevIndex, AOChannel_0, Ao_data_array_square, Num_square);
        Console.WriteLine(error_code);

        // Enable Ao software trig start Ao output wave
        error_code = USB3000DLL.SetUSB3AoSoftTrig(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        Console.WriteLine("Ao0 outputting -1V and 1V square wave, Please Enter to stop output.");
        Console.ReadLine();

        error_code = USB3000DLL.SetUSB3AoImmediately(DevIndex, AOChannel_0, voltage_0);
        Console.WriteLine(error_code + " AOChannel_0 is 0V");

        // Disable Ao software trig, clear flag
        error_code = USB3000DLL.SetUSB3ClrAoTrigger(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        // Clear FIFO
        error_code = USB3000DLL.SetUSB3ClrAoFifo(DevIndex, AOChannel_0);
        Console.WriteLine(error_code);

        // Close Device and stop Ao wave output
        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);
    }
}