using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices; // For the DllImport of AIOWDM Driver API

namespace AIOWDMNet
{
	public class AIOWDM
	{
		// Prototype AIOWDM.dll data and functions in managed C# for Dot Net
		// Using C# data types and default marshaling of unmanaged code

		// Predefined constants for device index:
		public const UInt32 diNone  = 0xFFFFFFFF; // "-1"
		public const UInt32 diFirst = 0xFFFFFFFE; // "-2" First board
		public const UInt32 diOnly  = 0xFFFFFFFD; // "-3" One and only board

		public const UInt32 TIME_METHOD_NOW = 0;
		public const UInt32 TIME_METHOD_WAIT_INPUT_ENABLE = 86;
		public const UInt32 TIME_METHOD_NOW_AND_ABORT = 5;
		public const UInt32 TIME_METHOD_WHEN_INPUT_ENABLE = 1;

		// Watchdog function constants:
		public const UInt32 WDG_ACTION_IGNORE = 0;
		public const UInt32 WDG_ACTION_DISABLE = 1;
		public const UInt32 WDG_ACTION_SOFT_RESTART = 2;
		public const UInt32 WDG_ACTION_MOSTLY_SOFT_RESTART = 4;
		public const Double PCI_WDG_CSM_RATE = 2.08333;
		public const Double P104_WDG_CSM_RATE = 2.08333;
		public const Double ISA_WDG_CSM_RATE = 0.894886;

		public const byte BAR0 = 0x80;
		public const byte BAR1 = 0x81;
		public const byte BAR2 = 0x82;
		public const byte BAR3 = 0x83;
		public const byte BAR4 = 0x84;
        public const byte BAR5 = 0x85;

        public const UInt32 bRestricted = 1;
        public const UInt32 bSimultaneous = 1;
        public const UInt32 bUpdate = 1;

        public enum Range : UInt32
        {
            NoChange = 0xFFFFFFFF,
            Unipolar10 = 0x30313055, // FourCC("U010");
            Unipolar5 = 0x35303055, // FourCC("U005");
            Bipolar10 = 0x3031E142, // FourCC("B±10");
            Bipolar5 = 0x3530E142, // FourCC("B±05");
            Bipolar2_5 = 0xBD32E142, // FourCC("B±2½");
            Current420 = 0x30323449, // FourCC("I420"); // 4-20mA
            Current020 = 0x30323049,
            Current024 = 0x34323049,
            Code0 = 0,
            Code1 = 1,
            Code2 = 2,
            Code3 = 3,
            Code4 = 4,
            Code5 = 5,
            Code6 = 6,
            Code7 = 7,
        }


        [DllImport("kernel32.dll")]
		public static extern uint GetLastError();

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern Int32 GetNumCards();

		// QueryDeviceInfo() Array of char Name version :
		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 QueryCardInfo(Int32 CardNum, out UInt32 pDeviceID, out UInt32 pBase, [In, Out] UInt32 pNameSize, [In, Out] Char[] Name);
        // QueryDeviceInfo() StringBuilder Name version :
        [DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 QueryCardInfo(Int32 CardNum, out UInt32 pDeviceID, out UInt32 pBase, ref UInt32 pNameSize, StringBuilder Name);

        // QueryDeviceInformation() C# String Name version :
        public static UInt32 QueryCardInformation(Int32 CardNum, out UInt32 pDeviceID, out UInt32 pBase, out String Name)
        {
            UInt32 Status;
            UInt32 NameSize = 256; // Initial size of the string buffer.

            // Allocate a StringBuilder with the same size as NameSize.
            StringBuilder sbName = new StringBuilder((int)NameSize);

            // Call the DLL method.
            Status = QueryCardInfo(CardNum, out pDeviceID, out pBase, ref NameSize, sbName);

            // Set the output Name to the StringBuilder contents.
            Name = sbName.ToString();

            return Status;
        }


        // We need SetLastError = true for the two wait functions so they are "allowed" to set it.
        // Its not neccesarily an error it is used like a thread return value for already pending wait or intentional abort
        // This actually tels the CLR to call GetLastError immediatly after a call and save the value dont overwrite it.
        [DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 QueryBARBase(Int32 CardNum, UInt32 BARIndex, out UInt32 pBase);

		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WaitForIRQ(Int32 CardNum);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 AbortRequest(Int32 CardNum);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 CloseCard(Int32 CardNum);
		//[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		//public static extern UInt32 COSWaitForIRQ(Int64 CardNum, UInt32 PPIs, void* pData); // ref Void ???
		// uses a void pointer to an array of 3 unsigned char or UInt16

		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 COSWaitForIRQ(Int32 CardNum, UInt32 PPIs, [In, Out] UInt16[] pData); // ref Void ???

		// Byte version: COS boards will only have 1 or 2 PPIs so 3 or 6 bytes for chan ABC
		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 COSWaitForIRQ(Int32 CardNum, UInt32 PPIs, [In, Out] Byte[] pData); // ref Void ???

		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 SetCOSScheme(long CardNum, UInt64 COSScheme);

		[DllImport("AIOWDM.DLL", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 PollForIRQ(long CardNum);



		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGInit(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGHandleIRQ(Int32 CardNum, UInt32 Action);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern Double WDGSetTimeout(Int32 CardNum, Double Milliseconds, Double MHzClockRate);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern Double WDGSetResetDuration(Int32 CardNum, Double Milliseconds, Double MHzClockRate);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGPet(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern Double WDGReadTemp(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGReadStatus(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGStart(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 WDGStop(Int32 CardNum);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 EmergencyReboot();



		// We use an 8 bit byte here but return/pass a 16 bit byte to accomidate possible AA55 error return for value:
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 InPortB(UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 OutPortB(UInt32 Port, Byte Value);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 InPort(UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 OutPort(UInt32 Port, UInt16 Value);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 InPortL(UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 OutPortL(UInt32 Port, UInt32 Value);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 InPortDWord(UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 OutPortDWord(UInt32 Port, UInt32 Value);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelInPortB(Int32 CardNum, UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelOutPortB(Int32 CardNum, UInt32 Port, Byte Value);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelInPort(Int32 CardNum, UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelOutPort(Int32 CardNum, UInt32 Port, UInt16 Value);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 RelInPortL(Int32 CardNum, UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelOutPortL(Int32 CardNum, UInt32 Port, UInt32 Value);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 RelInPortDWord(Int32 CardNum, UInt32 Port);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt16 RelOutPortDWord(Int32 CardNum, UInt32 Port, UInt32 Value);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 OutBAR32(Int32 CardNum, byte BAR, UInt32 Port, UInt32 Value);
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern UInt32 InBAR32(Int32 CardNum, byte BAR, UInt32 Port);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 OutBAR8(long CardNum, byte BAR, UInt32 Offset, byte Value);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 InBAR8(long CardNum, byte BAR, UInt32 Offset);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt16 InBAR16(long CardNum, byte BAR, UInt32 Offset);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt16 OutBAR16(long CardNum, byte BAR, UInt32 Offset, UInt16 Value);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 RelINSB(long CardNum, UInt32 Offset, UInt32 Count, byte[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 RelINSW(long CardNum, UInt32 Offset, UInt32 Count, UInt16[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 RelINSL(long CardNum, UInt32 Offset, UInt32 Count, UInt32[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 INSB(UInt32 Addr, UInt32 Count, byte[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 INSW(UInt32 Addr, UInt32 Count, UInt16[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 INSL(UInt32 Addr, UInt32 Count, UInt32[] pBuf);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt16 OutBAR32(long CardNum, byte BAR, UInt32 Port, UInt32 Value);
        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern UInt32 InBAR32(long CardNum, byte BAR, UInt32 Offset);

        // DAC Functions
		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern uint DAC_GetNumDacs(long CardNum, out UInt16 numDacs);

		[DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
		public static extern uint DAC_GetMaxCounts(long CardNum, out UInt32 maxCounts);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_Output(long CardNum, ushort iDac, double Value);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_Outputs(long CardNum, ushort NumValues, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] Values);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_SetRange(long CardNum, ushort iDac, UInt32 RangeCode);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_SetRanges(long CardNum, ushort numRangeCodes, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] UInt32[] RangeCodes);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_GetRange(long CardNum, ushort iDac, ref uint RangeCode);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_GetRanges(long CardNum, ref ushort pNumRangeCodes, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] UInt32[] RangeCodes);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_ValueFromCounts(long CardNum, ushort iDac, uint Counts, ref double Value);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_OutputCount(long CardNum, ushort iDac, uint Counts);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_OutputCounts(long CardNum, ushort numCounts, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] uint[] Counts);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_ReloadCalibrationData(long CardNum);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_EnableCalibration(long CardNum, ushort Enable /* 1 | 0 */);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_GetCalibrationData(long CardNum, ref ushort pBufLength, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] pBuf);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_WriteCalibrationData(long CardNum, ref ushort pBufLength, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pBuf, ushort bToEEPROM);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern uint DAC_ConfigureSimultaneousMode(long CardNum, long bSimultaneous, long bUpdate);

        [DllImport("AIOWDM.DLL", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DAC_ConfigureVoltageRestrictMode(long CardNum, long bRestricted);

	// Digital Integration Features API
	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_ConfigurePulseClock(uint cardNum, ref double clockHz);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_Measure(uint cardNum, uint iBit, ref double loSide, ref double hiSide, ref double dutyCycle, ref double frequency);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_Generate(uint cardNum, uint iBit, double activeSide, double inactiveSide, ushort pulseCount);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_ConfigureGeneration(uint cardNum, uint iBit, double activeSide, double inactiveSide, ushort pulseCount);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_ConfigureCounting(uint cardNum, uint iBit, bool countFalling, bool countRising);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_Count(uint cardNum, uint iBit, ref uint count);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_CountOverflowIRQEnable(uint cardNum, uint iBit, bool enabled);

	[DllImport("AIOWDM.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
	public static extern uint DIF_IRQEdgeEnable(uint cardNum, uint iBit, bool fallingIRQ, bool risingIRQ);

	}
}
