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

namespace DIO_CSharp
{
    class Program
    {
        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_open", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr mxdgio_open();

        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_get_input_signal", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int mxdgio_get_input_signal
        (
            IntPtr fd,
            int port
        );

        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_get_output_signal", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int mxdgio_get_output_signal
        (
            IntPtr fd,
            int port
        );

        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_set_output_signal_high", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int mxdgio_set_output_signal_high
        (
            IntPtr fd,
            uint port
        );

        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_set_output_signal_low", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int mxdgio_set_output_signal_low
        (
            IntPtr fd,
            uint port
        );



        [DllImport("mxdgio.dll", EntryPoint = "mxdgio_close", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern void mxdgio_close(IntPtr fd);

        static uint MAX_DIO_NUMBER = 4;

        public static void Main(string[] args)
        {
            string line;
            int functionNumber;

            Console.WriteLine("DIO Test Program");
            Console.WriteLine("(0) Exit Program");
            Console.WriteLine("(1) Set DOUT value");
            Console.WriteLine("(2) Display both DIN and DOUT");
            Console.WriteLine("(3) Test Program");

            do
            {
                line = Console.ReadLine();
                functionNumber = int.Parse(line);
                switch (functionNumber)
                {
                    default:
                        break;
                    case 0: break;
                    case 1:
                        SetDOUTValue();
                        break;
                    case 2:
                        DisplayDIO();
                        break;
                    case 3:
                        TestDIOFunction();
                        break;
                }
                
            } while (functionNumber != 0);
        }

        static void SetDOUTValue()
        {
            IntPtr hDIO;
            uint port_no;
            int data;
            int intDout;
            int nDout = 0;
            int[] portout = new int[4];

            hDIO = mxdgio_open();
            Console.WriteLine(string.Format("Input the Port Number (0 ~ {0}) = ", MAX_DIO_NUMBER - 1));
            string line = Console.ReadLine();
            port_no = uint.Parse(line);

            Console.WriteLine("Input the value (0 or 1) = ");
            line = Console.ReadLine();
            data = int.Parse(line);

            //Get DOUT Value
            for (int i = 0; i < MAX_DIO_NUMBER; i++)
            {
                intDout = mxdgio_get_output_signal(hDIO, i);
                portout[i] = intDout;
            }
            for (uint i = 0; i < MAX_DIO_NUMBER; i++)
            {
                if (i == port_no)
                {
                    //Set DOUT
                    if (data == 1)
                    {
                        nDout = mxdgio_set_output_signal_high(hDIO, port_no);
                    }
                    else
                    {
                        nDout = mxdgio_set_output_signal_low(hDIO, port_no);
                    }
                }
                else
                {
                    //Save the original value
                    if (portout[i] == 0)
                        mxdgio_set_output_signal_low(hDIO, i);
                    else if (portout[i] == 1)
                        mxdgio_set_output_signal_high(hDIO, i);
                }
            }
            if (nDout == -1)
            {
                Console.WriteLine("Set digital output fail!");
            }
            else
            {
                Console.WriteLine("Set digital output success!");
            }

            //Close DIO
            mxdgio_close(hDIO);
        }

        static void DisplayDIO()
        {
            IntPtr hDIO;
            int port_no;
            int intDout, intDin;
            int[] portout = new int[4];

            hDIO = mxdgio_open();

            for (int i = 0; i < MAX_DIO_NUMBER; i++)
            {
                //Get digital input
                port_no = i;
                intDin = mxdgio_get_input_signal(hDIO, port_no);
                intDout = mxdgio_get_output_signal(hDIO, port_no);
                Console.WriteLine(string.Format("Din{0} = {1}, Dout{0} = {2}", port_no, intDin, intDout));
            }

            //Close DIO
            mxdgio_close(hDIO);
        }

        static void TestDIOFunction()
        {
            IntPtr hDIO;
            uint port_no;
            int intDout;
            int nDout = 0;
            int nSuccessDO = 0, nSuccessDIO = 0;
            int nFailDO = 0, nFailDIO = 0;
            int[] portout = new int[4];
            int testNumber;


            //Open dio
            hDIO = mxdgio_open();

            //Get the number of the test
            Console.WriteLine("Input the number of the test = ");
            string line = Console.ReadLine();
            testNumber = int.Parse(line);
            

            for (int i = 0; i < testNumber; i++)
            {
                //Get DOUT Value
                for (int j = 0; j < MAX_DIO_NUMBER; j++)
                {
                    intDout = mxdgio_get_output_signal(hDIO, j);
                    portout[j] = intDout;
                }

                Random crandom = new Random();
                port_no = (uint)crandom.Next() % 4;

                for (int k = 0; k < MAX_DIO_NUMBER; k++)
                {
                    if (k == port_no)
                    {
                        //Set DOUT
                        if (portout[port_no] == 0)
                        {
                            nDout = mxdgio_set_output_signal_high(hDIO, port_no);
                        }
                        else
                        {
                            nDout = mxdgio_set_output_signal_low(hDIO, port_no);
                        }
                    }
                    else
                    {
                        //Save the original value
                        if (portout[k] == 0)
                            mxdgio_set_output_signal_low(hDIO, (uint)k);
                        else if (portout[k] == 1)
                            mxdgio_set_output_signal_high(hDIO, (uint)k);
                    }
                }

                for (int l = 0; l < MAX_DIO_NUMBER; l++)
                {
                    if (l == port_no)
                    {
                        //DOUT checking
                        if (portout[port_no] != mxdgio_get_output_signal(hDIO, l))
                            nSuccessDO++;
                        else
                        {
                            nFailDO++;
                            Console.WriteLine(string.Format("DOUT {0} error", l));
                        }
                    }
                    else
                    {
                        if (portout[l] == mxdgio_get_output_signal(hDIO, l))
                            nSuccessDO++;
                        else
                        {
                            nFailDO++;
                            Console.WriteLine(string.Format("DOUT {0} error", l));
                        }
                    }

                    //DIO checking
                    if (mxdgio_get_output_signal(hDIO, l) == mxdgio_get_input_signal(hDIO, l))
                        nSuccessDIO++;
                    else
                    {
                        nFailDIO++;
                        Console.WriteLine(string.Format("DIO {0} error\n", l));
                    }
                }
            }

            //Show the results of DO checking
            Console.WriteLine(string.Format("DOUT Success:{0}", nSuccessDO));
            Console.WriteLine(string.Format("DOUT Fail:{0}", nFailDO));

            //Show the results of DIO checking
            Console.WriteLine(string.Format("DIO Success:{0}", nSuccessDIO));
            Console.WriteLine(string.Format("DIO Fail:{0}", nFailDIO));

            nSuccessDO = 0;
            nSuccessDIO = 0;
            nFailDO = 0;
            nFailDIO = 0;

            //Close DIO
            mxdgio_close(hDIO);
        }
    }
}
