/***************************************************************************
 * Copyright (c) 2009 Digi International Inc., All Rights Reserved
 * 
 * This software contains proprietary and confidential information of Digi
 * International Inc.  By accepting transfer of this copy, Recipient agrees
 * to retain this software in confidence, to prevent disclosure to others,
 * and to make no use of this software other than that for which it was
 * delivered.  This is an unpublished copyrighted work of Digi International
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 * prohibited.
 * 
 * Restricted Rights Legend
 *
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7031 or
 * subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 * Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 ***************************************************************************
 *
 * @Descr: GPIO Class
 *
 * @History:
 *	10/01/09:	aramos      initial version.
 *
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Digi.Common;
using Digi.Imported;
using Digi.Drivers;

/*! \package Digi.Drivers
 */
/// <summary>
/// The Digi.Drivers includes the classes that implement the different Digi Drivers (GPIO, I2C, SPI...)
/// </summary>
namespace Digi.Drivers
{
    /*! \class GPIO
     */
    /// <summary>
    /// General Purpose Input Output class
    /// This class manage the GPIO driver
    /// </summary>
    public abstract class GPIO
    {
        /*! \enum DirectionValue
        */
        /// <summary>
        /// Direction Value enumeration
        /// Enumeration of the possible direcition asigned to a gpio
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// DirectionValue.Input
        /// DirectionValue.Output
        /// DirectionValue.Undefined</code>
        /// </example>
        public enum DirectionValue : uint
        {
            Input,
            Output,
            Undefined
        }

        /*! \enum IrqValue
         */
        /// <summary>
        /// Interrupt Value enumeration
        /// Enumeration of the possible value of a gpio configured as interrupt
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// IrqValue.LowLevel
        /// IrqValue.HighLevel
        /// IrqValue.RisingEdge
        /// IrqValue.FallingEdge
        /// IrqValue.Both</code>
        /// </example> 
        public enum IrqValue : uint
        {
            LowLevel,
            HighLevel,
            RisingEdge,
            FallingEdge
        }

        /*! \enum IoValue
         */
        /// <summary>
        /// Input/Output Value enumeration
        /// Enumeration of the value of a gpio configured as input/output
        /// </summary>        
        /// <example>
        /// <code>
        /// // Use of the constants
        /// IoValue.Low
        /// IoValue.High</code>
        /// </example>  
        public enum IoValue : uint
        {
            Low,
            High
        }

        /*! \fn public public GPIO()
        */
        /// <summary>
        /// Default constructor
        /// </summary> 
        public GPIO()
        {
        }
        /*! \property abstract uint Direction
             */
        /// <summary>
        /// Direction property
        /// </summary>    
        /// <value> Get/Set direction property of the gpio</value>
        public abstract DirectionValue Direction
        {
            set;
            get;
        }
        /*! \property public abstract IrqValue IrqMode
             */
        /// <summary>
        /// IrqMode property
        /// </summary>    
        /// <value> Get/Set interrupt mode property of the gpio</value>
        public abstract IrqValue IrqMode
        {
            set;
            get;
        }
        /*! \property public abstract bool Block
             */
        /// <summary>
        /// Block property
        /// </summary>    
        /// <value> Get/Set block property of the gpio</value>
        public abstract bool Block
        {
            set;
            get;
        }
        /*! \property public abstract uint Value
             */
        /// <summary>
        /// Value property
        /// </summary>    
        /// <value> Get/Set the value of the gpio</value>
        public abstract IoValue Value
        {
            set;
            get;
        }
        /*! \fn public abstract int Wait();
         */
        /// <summary>
        /// Function that wait for the configured interrupt in a gpio configured as interrupt
        /// </summary>        
        /// <returns>
        /// true indicates success, false indicates failure
        /// </returns>              
        public abstract int Wait();

        /*! \fn public abstract bool Poll(IoValue value, uint tries, int sleep);
             */
        /// <summary>
        /// Function that makes a polling of the gpio
        /// </summary>        
        /// <param name=value>Input value to be pooled (use IoValue constants)</param>
        /// <param name=tries>Number of tries to achieve the value</param>  
        /// <param name=sleep>Time to wait between tries</param>
        /// <returns>
        /// true indicates success, false indicates failure
        /// </returns>                 
        public abstract bool Poll(IoValue value, uint tries, int sleep);
    }
    
    /*! \class GPIOIMX51
     */
    /// <summary>
    /// General Purpose Input Output class
    /// This class manage the GPIO driver of the ConnecCore 9M/Wi-9M 2443 platforms 
    /// </summary>
    public class GPIOiMX51 : GPIO
    {
        /*! \enum PullUpDownValue
        */
        /// <summary>
        /// Pull Up/Down Value enumeration
        /// Enumeration of the possible resistor-configuration of the gpio
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// PullUpDownValue.None
        /// PullUpDownValue.Down_100K
        /// PullUpDownValue.Up_100K
        /// PullUpDownValue.Up_22K
        /// PullUpDownValue.Up_47K
        /// PullUpDownValue.Keeper</code>
        /// </example> 
        public enum PullUpDownValue : uint
        {
            None,
            Down_100K,
            Up_100K,
            Up_22K,
            Up_47K,
            Keeper
        }

        /*! \enum WakeUpValue
         */
        /// <summary>
        /// WakeUp Value enumeration
        /// Enumeration of the possible values of the WakeUp configuration
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// WakeUpValue.Disabled
        /// WakeUpValue.Enabled</code>
        /// </example> 
        public enum WakeUpValue : uint
        {
            Disabled,
            Enabled
        }

        /*! \enum Port
         */
        /// <summary>
        /// Port enumeration
        /// Enumeration of the available ports
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// Port.Port1
        /// Port.Port2
        /// Port.Port3
        /// Port.Port4</code>
        /// </example> 
        public enum Port : uint
        {
            Port1,
            Port2,
            Port3,
            Port4
        }

        /*! \enum IrqValue
         */
        /// <summary>
        /// Interrupt Value enumeration
        /// Enumeration of the possible value of a gpio configured as interrupt
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// IrqValue.LowLevel
        /// IrqValue.HighLevel
        /// IrqValue.RisingEdge
        /// IrqValue.FallingEdge
        /// IrqValue.Both</code>
        /// </example> 
        public new enum IrqValue : uint
        {
            LowLevel,
            HighLevel,
            RisingEdge,
            FallingEdge,
            Both
        }

        /*! \enum DriveStregnthValue
         */
        /// <summary>
        /// Drive Stregnth enumeration
        /// Enumeration of the possible value of Drive Stregnth
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// DriveStregnthValue.Normal
        /// DriveStregnthValue.Medium
        /// DriveStregnthValue.High
        /// DriveStregnthValue.Maximum</code>
        /// </example> 
        public enum DriveStrengthValue : uint
        {
            Normal,
            Medium,
            High,
            Maximum
        }

        /*! \enum OpenDrainValue
         */
        /// <summary>
        /// Open Drain enumeration
        /// Enumeration of the possible value of Open Drain
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// OpenDrainValue.Disable
        /// OpenDrainValue.Enable/code>
        /// </example> 
        public enum OpenDrainValue : uint
        {
            Disable,
            Enable
        }

        /*! \enum HysteresisValue
         */
        /// <summary>
        /// Hysteresis enumeration
        /// Enumeration of the possible value of Hysteresis
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// HysteresisValue.Disable
        /// HysteresisValue.Enable/code>
        /// </example> 
        public enum HysteresisValue : uint
        {
            Disable,
            Enable
        }

        /*! \enum SlewRateValue
         */
        /// <summary>
        /// Slew Rate enumeration
        /// Enumeration of the possible value of Slew Rate
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// SlewRateValue.Slow
        /// SlewRateValue.Fast/code>
        /// </example> 
        public enum SlewRateValue : uint
        {
            Slow,
            Fast
        }

        /*! \enum OutVoltageValue
         */
        /// <summary>
        /// Out Voltage enumeration
        /// Enumeration of the possible value of Out Voltage
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// OutVoltageValue.Low
        /// OutVoltageValue.High/code>
        /// </example> 
        public enum OutVoltageValue : uint
        {
            Low,
            High
        }

        /*! \enum InMode
         */
        /// <summary>
        /// In Mode enumeration
        /// Enumeration of the possible value of In Mode
        /// </summary>
        /// <example>
        /// <code>
        /// // Use of the constants
        /// InMode.CMOS
        /// InMode.DDR/code>
        /// </example> 
        public enum InModeValue : uint
        {
            CMOS,
            DDR
        }

        // GPIO configuration Flags

        //interrupt
        private const uint FLAG_INTR_LEVEL = 0x00000001;		// Interrupt is level sensitive, if not: Edge detect
        private const uint FLAG_INTR_INVER = 0x00000002;		// Interrupt is Active low (or low edge), if not: Active high (or high edge)
        private const uint FLAG_INTR_BOTH = 0x00000010;	// Interrupt both edges
        //Pull Up/Down      
        private const uint FLAG_PULL_UP = 0x00000004;	// Set Pin Pull-Up (PULL_UP_100K)
        private const uint FLAG_PULL_DOWN = 0x00000008;	// Set Pin Pull-Down (PULL_DOWN_100K)
        private const uint FLAG_PULL_KEEPER = 0x00000020;	//
        private const uint FLAG_PULL_NONE = 0x00000040;	//
        private const uint FLAG_PULL_UP_47K = 0x00000080;	//
        private const uint FLAG_PULL_UP_22K = 0x00000100;	//
        private const uint MASK_PULLUPDOWN = ~(FLAG_PULL_UP | FLAG_PULL_DOWN | FLAG_PULL_KEEPER | FLAG_PULL_NONE | FLAG_PULL_UP_47K | FLAG_PULL_UP_22K);
        //Drive Strength
        private const uint FLAG_DRIVE_NORMAL = 0x00000200;	// GPO output drive
        private const uint FLAG_DRIVE_MEDIUM = 0x00000400;	// 
        private const uint FLAG_DRIVE_HIGH = 0x00000800;	// 
        private const uint FLAG_DRIVE_MAX = 0x00001000;	// 
        private const uint MASK_DRIVESTRENGTH = ~(FLAG_DRIVE_NORMAL | FLAG_DRIVE_MEDIUM | FLAG_DRIVE_HIGH | FLAG_DRIVE_MAX);
        //Open Drain
        private const uint FLAG_OPENDRAIN_DISABLE = 0x00002000;	//
        private const uint FLAG_OPENDRAIN_ENABLE = 0x00004000;	//
        private const uint MASK_OPENDRAIN = ~(FLAG_OPENDRAIN_ENABLE | FLAG_OPENDRAIN_DISABLE);	//
        //Slew Rate
        private const uint FLAG_SLEW_RATE_SLOW = 0x00008000;	// GPIO slew rate slow
        private const uint FLAG_SLEW_RATE_FAST = 0x00010000;	// GPIO slew rate fast
        private const uint MASK_SLEW_RATE = ~(FLAG_SLEW_RATE_SLOW | FLAG_SLEW_RATE_FAST);	// 
        //Hysteresis
        private const uint FLAG_HYSTERESIS_DISABLE = 0x00020000;	//
        private const uint FLAG_HYSTERESIS_ENABLE = 0x00040000;	//
        private const uint MASK_HYSTERESIS = ~(FLAG_HYSTERESIS_ENABLE | FLAG_HYSTERESIS_DISABLE);	//
        //In Mode
        private const uint FLAG_INMODE_CMOS = 0x00080000;	//
        private const uint FLAG_INMODE_DDR = 0x00100000;	//
        private const uint MASK_INMODE = ~(FLAG_INMODE_CMOS | FLAG_INMODE_DDR);	//
        //Out Voltage
        private const uint FLAG_OUTVOLT_LOW = 0x00200000;	//
        private const uint FLAG_OUTVOLT_HIGH = 0x00400000;	//
        private const uint MASK_OUTVOLT = ~(FLAG_OUTVOLT_LOW | FLAG_OUTVOLT_HIGH);	//
        //GPIO commands
        private const uint GPIO_UNCONFIG = 0;
        private const uint GPIO_INPUT = 1;
        private const uint GPIO_OUTPUT = 2;
        private const uint GPIO_IRQ = 3;
        private const uint GPIO_OTHER = 4;
        private const uint GPIO_USED =5;
        private const uint GPIO_NOT_EXIST =6;

        /// <summary>
        /// Internal structure, not accesible to the user
        /// </summary>
        private struct GPIOMessageMx51
        {
            public uint uiPin;
            public uint uiPort;
            public uint mode;
            public bool Block;
            public uint ulFlags; 
            public uint unValue;
            public uint uiIrqTimeout;
        }
        
        //Handle
        private static DriverIO hGPIO = new DriverIO();

        //Internal GPIO Message
        private GPIOiMX51.GPIOMessageMx51 gpioM;

        //GPIO IOCTLs
        private static uint IOCTL_GPIO_CONFIG
        {
            get
            {
                return WINIOCTL_H.CTL_CODE(DeviceType.GpioPort, 0x802, MethodType.Buffered, AccessType.Any);
            }
        }
        private static uint IOCTL_GPIO_WAIT_FOR_IRQ
        {
            get
            {
                return WINIOCTL_H.CTL_CODE(DeviceType.GpioPort, 0x803, MethodType.Buffered, AccessType.Any);
            }
        }
        private static uint IOCTL_GPIO_RELEASE
        {
            get
            {
                return WINIOCTL_H.CTL_CODE(DeviceType.GpioPort, 0x804, MethodType.Buffered, AccessType.Any);
            }
        }
        private static uint IOCTL_GPIO_BLOCK
        {
            get
            {
                return WINIOCTL_H.CTL_CODE(DeviceType.GpioPort, 0x805, MethodType.Buffered, AccessType.Any);
            }
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber)
         */
        /// <summary>
        /// Constructor, need port and pin
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param>          
        /// <example>
        /// <code>
        /// // define a gpio using port and pin
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11);</code>
        /// </example>    
        public GPIOiMX51(Port PortNumber, uint PinNumber)
        {
            ConfigIO((uint)PortNumber, PinNumber, GPIO_OUTPUT, (uint)IoValue.Low, (uint)PullUpDownValue.None);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection)
        */
        /// <summary>
        /// Constructor, need port, pin and direction
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param>      
        /// <param name="PinDirection">Direction of the gpio (use DirectionValue constants)</param>          
        /// <example>
        /// <code>
        /// // define a gpio using port, pin and direction
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11, DirectionValue.Output);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection)
        {
            ConfigIO((uint)PortNumber, PinNumber, (uint)PinDirection, (uint)IoValue.Low, (uint)PullUpDownValue.None);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, IoValue PinValue) 
         */
        /// <summary>
        /// Constructor, need port, pin, direction and value
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param>   
        /// <param name="PinDirection">Direction of the gpio (use DirectionValue constants)</param> 
        /// <param name="PinValue">Value of the gpio (use IoValue constants)</param>          
        /// <example>
        /// <code>
        /// // define a gpio using port, pin, direction and value
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11, DirectionValue.Output, IoValue.Low);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, IoValue PinValue)
        {
            ConfigIO((uint)PortNumber, PinNumber, (uint)PinDirection, (uint)PinValue, (uint)PullUpDownValue.None);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, IrqValue IrqMode) 
         */
        /// <summary>
        /// Constructor, need port and pin and interrupt mode
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param> 
        /// <param name="IrqMode">Interrupt mode of the gpio (use IrqValue constants)</param>         
        /// <example>
        /// <code>
        /// // define a gpio using port and pin and interrupt mode
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 14, IrqValue.LowLevel);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, IrqValue IrqMode)
        {
            ConfigIrq((uint)PortNumber, PinNumber, (uint)IrqMode, (uint)PullUpDownValue.None);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, PullUpDownValue PullUpDown)
         */
        /// <summary>
        /// Constructor, need port, pin and PullUp/Down configuration
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param>     
        /// <param name="PullUpDown">Pull-up or pull-down configuration of the gpio (use PullUpDownValue constants)</param>          
        /// <example>
        /// <code>
        /// // define a gpio using port, pin and PullUp/Down configuration
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11, PullUpDownValue.Up);</code>
        /// </example>  
        public GPIOiMX51(Port PortNumber, uint PinNumber, PullUpDownValue PullUpDown)
        {
            ConfigIO((uint)PortNumber, PinNumber, GPIO_OUTPUT, (uint)IoValue.Low, (uint)PullUpDown);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, PullUpDownValue PullUpDown)
        */
        /// <summary>
        /// Constructor, need port, pin, direction and PullUp/Down configuration
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param>    
        /// <param name="PinDirection">Direction of the gpio (use DirectionValue constants)</param>   
        /// <param name="PullUpDown">Pull-up or pull-down configuration of the gpio (use PullUpDownValue constants)</param>        
        /// <example>
        /// <code>
        /// // define a gpio using port, pin, direction and PullUp/Down configuration
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11, DirectionValue.Output, PullUpDownValue.Up);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, PullUpDownValue PullUpDown)
        {
            ConfigIO((uint)PortNumber, PinNumber, (uint)PinDirection, (uint)IoValue.Low, (uint)PullUpDown);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, IoValue PinValue, PullUpDownValue PullUpDown) 
         */
        /// <summary>
        /// Constructor, need port, pin, direction, value and PullUp/Down configuration
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param> 
        /// <param name="PinDirection">Direction of the gpio (use DirectionValue constants)</param> 
        /// <param name="PinValue">Value of the gpio (use IoValue constants)</param>    
        /// <param name="PullUpDown">Pull-up or pull-down configuration of the gpio (use PullUpDownValue constants)</param>              
        /// <example>
        /// <code>
        /// // define a gpio using port, pin, direction, value and PullUp/Down configuration
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 11, DirectionValue.Output, IoValue.Low, PullUpDownValue.Up);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, DirectionValue PinDirection, IoValue PinValue, PullUpDownValue PullUpDown)
        {
            ConfigIO((uint)PortNumber, PinNumber, (uint)PinDirection, (uint)PinValue, (uint)PullUpDown);
        }

        /*! \fn public GPIOIMX51(Port PortNumber, uint PinNumber, IrqValue IrqMode, PullUpDownValue PullUpDown) 
         */
        /// <summary>
        /// Constructor, need port and pin, interrupt mode and PullUp/Down configuration
        /// </summary>    
        /// <param name="PortNumber">Port of the gpio (use Port constants)</param>
        /// <param name="PinNumber">Pin number in the port</param> 
        /// <param name="IrqMode">Interrupt mode of the gpio (use IrqValue constants)</param> 
        /// <param name="PullUpDown">Pull-up or pull-down configuration of the gpio (use PullUpDownValue constants)</param>         
        /// <example>
        /// <code>
        /// // define a gpio using port and pin, interrupt mode and PullUp/Down configuration
        /// GPIOIMX51 mygpio = new GPIOIMX51(Port.L, 14, IrqValue.LowLevel, PullUpDownValue.Up);</code>
        /// </example> 
        public GPIOiMX51(Port PortNumber, uint PinNumber, IrqValue IrqMode, PullUpDownValue PullUpDown)
        {
            ConfigIrq((uint)PortNumber, PinNumber, (uint)IrqMode, (uint)PullUpDown);
        }

        // ConfigIO internal funcion that configures a gpio as input or output
        void ConfigIO(uint PortNumber, uint PinNumber, uint PinDirection, uint PinValue, uint PullUpDown)
        {
            GPIOMessageMx51 gpioM_intern = gpioM;
            if (GPIOiMX51.hGPIO.FileHandle == (IntPtr)(-1))
            {
                if (!(hGPIO.CreateFile("PIO1:", GenericAccessRights.ReadWrite, 0, CreationDisposition.OpenExisting, 0)))
                    throw new Exception("[GPIO]CreateFile failed");
            }

            gpioM_intern.uiPin = PinNumber;
            gpioM_intern.uiPort = (uint)PortNumber;
            if ((PinValue == 0) || (PinValue == 1))
                gpioM_intern.unValue = PinValue;
            else
                throw new ArgumentException();
            if (PinDirection == (uint)DirectionValue.Input)
                gpioM_intern.mode = GPIO_INPUT;
            else if (PinDirection == (uint)DirectionValue.Output)
                gpioM_intern.mode = GPIO_OUTPUT;
            else
                throw new ArgumentException();
            gpioM_intern.Block = false;
            gpioM_intern.ulFlags = 0;
            if (PullUpDown == (uint)PullUpDownValue.Down_100K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_DOWN;
            else if (PullUpDown == (uint)PullUpDownValue.Keeper)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_KEEPER;
            else if (PullUpDown == (uint)PullUpDownValue.None)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_NONE;
            else if (PullUpDown == (uint)PullUpDownValue.Up_100K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP;
            else if (PullUpDown == (uint)PullUpDownValue.Up_22K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_22K;
            else if (PullUpDown == (uint)PullUpDownValue.Up_47K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_47K;
            else
                throw new ArgumentException();
            byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
            if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
            if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
            gpioM = gpioM_intern;
        }

        // ConfigIO internal funcion that configures a gpio as interrupt
        void ConfigIrq(uint PortNumber, uint PinNumber, uint IrqMode, uint PullUpDown)
        {
            GPIOMessageMx51 gpioM_intern = gpioM;
            if (hGPIO.FileHandle == (IntPtr)(-1))
            {
                if (!(hGPIO.CreateFile("PIO1:", GenericAccessRights.ReadWrite, 0, CreationDisposition.OpenExisting, 0)))
                    throw new Exception("[GPIO]CreateFile failed");
            }
            gpioM_intern.uiPin = PinNumber;
            gpioM_intern.uiPort = (uint)PortNumber;
            gpioM_intern.Block = false;
            gpioM_intern.ulFlags = 0;
            gpioM_intern.unValue = 0;
            gpioM_intern.mode = GPIO_IRQ;
            if (IrqMode == (uint)IrqValue.FallingEdge)
                gpioM_intern.ulFlags |= ~FLAG_INTR_LEVEL | FLAG_INTR_INVER;
            else if (IrqMode == (uint)IrqValue.RisingEdge)
                gpioM_intern.ulFlags |= ~(FLAG_INTR_LEVEL | FLAG_INTR_INVER);
            else if (IrqMode == (uint)IrqValue.LowLevel)
                gpioM_intern.ulFlags |= FLAG_INTR_LEVEL | FLAG_INTR_INVER;
            else if (IrqMode == (uint)IrqValue.HighLevel)
                gpioM_intern.ulFlags |= FLAG_INTR_LEVEL & ~FLAG_INTR_INVER;
            else if (IrqMode == (uint)IrqValue.Both)
                gpioM_intern.ulFlags |= FLAG_INTR_BOTH;
            else
                throw new ArgumentException();
            if (PullUpDown == (uint)PullUpDownValue.Down_100K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_DOWN;
            else if (PullUpDown == (uint)PullUpDownValue.Keeper)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_KEEPER;
            else if (PullUpDown == (uint)PullUpDownValue.None)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_NONE;
            else if (PullUpDown == (uint)PullUpDownValue.Up_100K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP;
            else if (PullUpDown == (uint)PullUpDownValue.Up_22K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_22K;
            else if (PullUpDown == (uint)PullUpDownValue.Up_47K)
                gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_47K;
            else
                throw new ArgumentException();
            byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
            if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
            if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
            gpioM = gpioM_intern;
        }

        //Private function that converts a GPIOMessage structure in a byte array
        private byte[] ConvertGpioMtoBuffer(GPIOMessageMx51 gpioM)
        {
            StructBuilder SBgpioM = new StructBuilder(28);
            byte[] SBgpioMPin = new byte[4];
            byte[] SBgpioMPort = new byte[4];
            byte[] SBgpioMMode = new byte[4];
            byte[] SBgpioMBlock = new byte[4];
            byte[] SBgpioMFlags = new byte[4];
            byte[] SBgpioMValue = new byte[4];
            byte[] SBgpioMIrqTimeout = new byte[4];

            DigiMath.UintToBuff(SBgpioMPin, 0, gpioM.uiPin, true);
            SBgpioM.Set(0, SBgpioMPin, 4);
            DigiMath.UintToBuff(SBgpioMPort, 0, gpioM.uiPort, true);
            SBgpioM.Set(4, SBgpioMPort, 4);
            DigiMath.UintToBuff(SBgpioMMode, 0, gpioM.mode, true);
            SBgpioM.Set(8, SBgpioMMode, 4);
            if (gpioM.Block == false)
                DigiMath.UintToBuff(SBgpioMBlock, 0, 0, true);
            else
                DigiMath.UintToBuff(SBgpioMBlock, 0, 1, true);
            SBgpioM.Set(12, SBgpioMBlock, 4);
            DigiMath.UintToBuff(SBgpioMFlags, 0, gpioM.ulFlags, true);
            SBgpioM.Set(16, SBgpioMFlags, 4);
            DigiMath.UintToBuff(SBgpioMValue, 0, gpioM.unValue, true);
            SBgpioM.Set(20, SBgpioMValue, 4);
            DigiMath.UintToBuff(SBgpioMIrqTimeout, 0, gpioM.uiIrqTimeout, true);
            SBgpioM.Set(24, SBgpioMIrqTimeout, 4);

            byte[] buff = new byte[SBgpioM.GetSize()];
            SBgpioM.Get(0, ref buff);
            return buff;
        }

        //Private function that converts a byte array in a GPIOMessage structure
        private GPIOMessageMx51 ConvertBuffertoGpioM(byte[] buffer)
        {
            GPIOMessageMx51 gpioM_intern;
            gpioM_intern.uiPin = DigiMath.BuffToUint(buffer, 0, true);
            gpioM_intern.uiPort = DigiMath.BuffToUint(buffer, 4, true);
            gpioM_intern.mode = DigiMath.BuffToUint(buffer, 8, true);
            uint Block_value = DigiMath.BuffToUint(buffer, 12, true);
            if (Block_value == 1) gpioM_intern.Block = true;
            else gpioM_intern.Block = false;
            gpioM_intern.ulFlags = DigiMath.BuffToUint(buffer, 16, true);
            gpioM_intern.unValue = DigiMath.BuffToUint(buffer, 20, true);
            gpioM_intern.uiIrqTimeout = DigiMath.BuffToUint(buffer, 24, true);
            return gpioM_intern;
        }

        private uint direction;
        /*! \property public override DirectionValue Direction
         */
        /// <summary>
        /// Get/Set direction property of the gpio (use DirectionValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use DirectionValue constants (DirectionValue.Input / DirectionValue.Output)
        /// mygpio.Direction = DirectionValue.Input; 
        /// DirectionValue Value = mygpio.Direction;</code>
        /// </example> 
        public override DirectionValue Direction
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (gpioM_intern.mode == GPIO_INPUT)
                    return (DirectionValue.Input);
                else if (gpioM_intern.mode == GPIO_OUTPUT)
                    return (DirectionValue.Output);
                else
                    return DirectionValue.Undefined;
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                direction = (uint)value;
                if (direction == (uint)DirectionValue.Input)
                    gpioM_intern.mode = GPIO_INPUT;
                else if (direction == (uint)DirectionValue.Output)
                    gpioM_intern.mode = GPIO_OUTPUT;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, ref buffer)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }
        private uint irqmode;
        /*! \property public GPIOIMX51.IrqValue IrqModeIXM51
         */
        /// <summary>
        /// Get/Set interrupt mode property of the gpio (use IrqValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use IrqValue constants (IrqValue.LowLevel / IrqValue.HighLevel / IrqValue.FallingEdge / IrqValue.RisingEdge / IrqValue.Both)
        /// mygpio.IrqModeIXM51 = GPIOIMX51.IrqValue.LowLevel;
        /// GPIOIMX51.IrqValue Value = mygpio.IrqModeIXM51;</code>
        /// </example> 
        public GPIOiMX51.IrqValue IrqModeIXM51
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_INTR_BOTH == (gpioM_intern.ulFlags & FLAG_INTR_BOTH))
                    return (IrqValue.Both);
                else if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_LEVEL))
                {
                    if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_INVER))
                        return (IrqValue.LowLevel);
                    else
                        return (IrqValue.HighLevel);
                }
                else
                {
                    if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_INVER))
                        return (IrqValue.FallingEdge);
                    else
                        return (IrqValue.RisingEdge);
                }
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                irqmode = (uint)value;
                if (irqmode == (uint)IrqValue.FallingEdge)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER | FLAG_INTR_BOTH))) | FLAG_INTR_INVER;
                else if (irqmode == (uint)IrqValue.RisingEdge)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER | FLAG_INTR_BOTH)));
                else if (irqmode == (uint)IrqValue.LowLevel)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER | FLAG_INTR_BOTH))) | (FLAG_INTR_LEVEL | FLAG_INTR_INVER);
                else if (irqmode == (uint)IrqValue.HighLevel)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER | FLAG_INTR_BOTH))) | FLAG_INTR_LEVEL;
                else if (irqmode == (uint)IrqValue.Both)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER | FLAG_INTR_BOTH))) | FLAG_INTR_BOTH;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public override IrqValue IrqMode
         */
        /// <summary>
        /// Get/Set interrupt mode property of the gpio (use IrqValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use IrqValue constants (IrqValue.LowLevel / IrqValue.HighLevel / IrqValue.FallingEdge / IrqValue.RisingEdge)
        /// mygpio.IrqMode = GPIO.IrqValue.LowLevel;
        /// GPIO.IrqValue Value = mygpio.IrqMode;</code>
        /// </example> 
        public override GPIO.IrqValue IrqMode
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_LEVEL))
                {
                    if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_INVER))
                        return (GPIO.IrqValue.LowLevel);
                    else
                        return (GPIO.IrqValue.HighLevel);
                }
                else
                {
                    if (FLAG_INTR_LEVEL == (gpioM_intern.ulFlags & FLAG_INTR_INVER))
                        return (GPIO.IrqValue.FallingEdge);
                    else
                        return (GPIO.IrqValue.RisingEdge);
                }
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                irqmode = (uint)value;
                if (irqmode == (uint)IrqValue.FallingEdge)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER))) | FLAG_INTR_INVER;
                else if (irqmode == (uint)IrqValue.RisingEdge)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER)));
                else if (irqmode == (uint)IrqValue.LowLevel)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER))) | (FLAG_INTR_LEVEL | FLAG_INTR_INVER);
                else if (irqmode == (uint)IrqValue.HighLevel)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & (~(FLAG_INTR_LEVEL | FLAG_INTR_INVER))) | FLAG_INTR_LEVEL;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }
        private uint pullupdown;
        /*! \property public PullUpDownValue PullUpDown
         */
        /// <summary>
        /// Get/Set Pull Up/Down property of the gpio (use PullUpDownValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use PullUpDownValue constants (PullUpDownValue.Down / PullUpDownValue.Up / PullUpDownValue.None)
        /// mygpio.PullUpDown = PullUpDownValue.Down;
        /// PullUpDownValue Value = mygpio.PullUpDown;</code>
        /// </example> 
        public PullUpDownValue PullUpDown
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_PULL_DOWN == (gpioM_intern.ulFlags & FLAG_PULL_DOWN))
                    return (PullUpDownValue.Down_100K);
                else if (FLAG_PULL_UP == (gpioM_intern.ulFlags & FLAG_PULL_KEEPER))
                    return (PullUpDownValue.Keeper);
                else if (FLAG_PULL_UP == (gpioM_intern.ulFlags & FLAG_PULL_NONE))
                    return (PullUpDownValue.None);
                else if (FLAG_PULL_UP == (gpioM_intern.ulFlags & FLAG_PULL_UP))
                    return (PullUpDownValue.Up_100K);
                else if (FLAG_PULL_UP == (gpioM_intern.ulFlags & FLAG_PULL_UP_22K))
                    return (PullUpDownValue.Up_22K);
                else if (FLAG_PULL_UP == (gpioM_intern.ulFlags & FLAG_PULL_UP_47K))
                    return (PullUpDownValue.Up_47K);
                else
                    return (PullUpDownValue.None);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                pullupdown = (uint)value;
                if (pullupdown == (uint)PullUpDownValue.Down_100K)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_DOWN;
                else if (pullupdown == (uint)PullUpDownValue.Keeper)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_KEEPER;
                else if (pullupdown == (uint)PullUpDownValue.None)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_NONE;
                else if (pullupdown == (uint)PullUpDownValue.Up_100K)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP;
                else if (pullupdown == (uint)PullUpDownValue.Up_22K)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_22K;
                else if (pullupdown == (uint)PullUpDownValue.Up_47K)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_PULLUPDOWN) | FLAG_PULL_UP_47K;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public DriveStrengthValue DriveStrength
         */
        /// <summary>
        /// Get/Set Drive Strength property of the gpio (use DriveStrengthValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use DriveStrengthValue constants (DriveStrengthValue.High / DriveStrengthValue.Maximum / DriveStrengthValue.Medium / DriveStrengthValue.Norma)
        /// mygpio.DriveStrength = DriveStrengthValue.High;
        /// DriveStrengthValue Value = mygpio.DriveStrength;</code>
        /// </example> 
        public DriveStrengthValue DriveStrength
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_DRIVE_HIGH == (gpioM_intern.ulFlags & FLAG_DRIVE_HIGH))
                    return (DriveStrengthValue.High);
                else if (FLAG_DRIVE_MAX == (gpioM_intern.ulFlags & FLAG_DRIVE_MAX))
                    return (DriveStrengthValue.Maximum);
                else if (FLAG_DRIVE_MEDIUM == (gpioM_intern.ulFlags & FLAG_DRIVE_MEDIUM))
                    return (DriveStrengthValue.Medium);
                else 
                    return (DriveStrengthValue.Normal);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == DriveStrengthValue.High)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_DRIVESTRENGTH) | FLAG_DRIVE_HIGH;
                else if (value == DriveStrengthValue.Maximum)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_DRIVESTRENGTH) | FLAG_DRIVE_MAX;
                else if (value == DriveStrengthValue.Medium)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_DRIVESTRENGTH) | FLAG_DRIVE_MEDIUM;
                else if (value == DriveStrengthValue.Normal)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_DRIVESTRENGTH) | FLAG_DRIVE_NORMAL;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public HysteresisValue Hysteresis
         */
        /// <summary>
        /// Get/Set Hysteresis property of the gpio (use HysteresisValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use HysteresisValue constants (HysteresisValue.Enable / HysteresisValue.Disable )
        /// mygpio.DriveStrength = HysteresisValue.Enable;
        /// HysteresisValue Value = mygpio.DriveStrength;</code>
        /// </example> 
        public HysteresisValue Hysteresis
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_HYSTERESIS_DISABLE == (gpioM_intern.ulFlags & FLAG_HYSTERESIS_DISABLE))
                    return (HysteresisValue.Disable);
                else
                    return (HysteresisValue.Enable);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == HysteresisValue.Disable)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_HYSTERESIS) | FLAG_HYSTERESIS_DISABLE;
                else if (value == HysteresisValue.Enable)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_HYSTERESIS) | FLAG_HYSTERESIS_ENABLE;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public OpenDrainValue Hysteresis
         */
        /// <summary>
        /// Get/Set Open Drain property of the gpio (use OpenDrainValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use OpenDrainValue constants (OpenDrainValue.Enable / OpenDrainValue.Disable )
        /// mygpio.OpenDrain = OpenDrainValue.Enable;
        /// OpenDrainValue Value = mygpio.OpenDrain;</code>
        /// </example> 
        public OpenDrainValue OpenDrain
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_OPENDRAIN_DISABLE == (gpioM_intern.ulFlags & FLAG_OPENDRAIN_DISABLE))
                    return (OpenDrainValue.Disable);
                else
                    return (OpenDrainValue.Enable);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == OpenDrainValue.Disable)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_OPENDRAIN) | FLAG_OPENDRAIN_DISABLE;
                else if (value == OpenDrainValue.Enable)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_OPENDRAIN) | FLAG_OPENDRAIN_ENABLE;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public SlewRateValue SlewRate
         */
        /// <summary>
        /// Get/Set Slew Rate property of the gpio (use SlewRateValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use OpenDrainValue constants (SlewRateValue.Fast / SlewRateValue.Slow )
        /// mygpio.SlewRate = SlewRateValue.Enable;
        /// SlewRateValue Value = mygpio.SlewRate;</code>
        /// </example> 
        public SlewRateValue SlewRate
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_SLEW_RATE_FAST == (gpioM_intern.ulFlags & FLAG_SLEW_RATE_FAST))
                    return (SlewRateValue.Fast);
                else
                    return (SlewRateValue.Slow);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == SlewRateValue.Fast)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_SLEW_RATE) | FLAG_SLEW_RATE_FAST;
                else if (value == SlewRateValue.Slow)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_SLEW_RATE) | FLAG_SLEW_RATE_SLOW;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public OutVoltageValue OutVoltage
         */
        /// <summary>
        /// Get/Set Out Voltage property of the gpio (use OutVoltageValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use OpenDrainValue constants (OutVoltageValue.High / OutVoltageValue.Low )
        /// mygpio.OutVoltage = OutVoltageValue.Enable;
        /// OutVoltageValue Value = mygpio.OutVoltage;</code>
        /// </example> 
        public OutVoltageValue OutVoltage
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_OUTVOLT_HIGH == (gpioM_intern.ulFlags & FLAG_OUTVOLT_HIGH))
                    return (OutVoltageValue.High);
                else
                    return (OutVoltageValue.Low);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == OutVoltageValue.High)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_OUTVOLT) | FLAG_OUTVOLT_HIGH;
                else if (value == OutVoltageValue.Low)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_OUTVOLT) | FLAG_OUTVOLT_LOW;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public InModeValue OutVoltage
         */
        /// <summary>
        /// Get/Set In Mode property of the gpio (use InModeValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use OpenDrainValue constants (InModeValue.CMOS / InModeValue.DDR )
        /// mygpio.InMode = InModeValue.CMOS;
        /// InModeValue Value = mygpio.InMode;</code>
        /// </example> 
        public  InModeValue InMode
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (FLAG_INMODE_CMOS == (gpioM_intern.ulFlags & FLAG_INMODE_CMOS))
                    return (InModeValue.CMOS);
                else
                    return (InModeValue.DDR);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == InModeValue.CMOS)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_INMODE) | FLAG_INMODE_CMOS;
                else if (value == InModeValue.DDR)
                    gpioM_intern.ulFlags = (gpioM_intern.ulFlags & MASK_INMODE) | FLAG_INMODE_DDR;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }
        /*! \property public override bool Block
         */
        /// <summary>
        /// Get/Set block property of the gpio (use true/false)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use boolean values (true / false)
        /// mygpio.Block = true;
        /// bool Value = mygpio.Block;</code>
        /// </example> 
        public override bool Block
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (gpioM_intern.Block == false)
                    return (false);
                else
                    return (true);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == true)
                    gpioM_intern.Block = true;
                else if (value == false)
                    gpioM_intern.Block = false;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
                if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");
                gpioM = gpioM_intern;
            }
        }

        /*! \property public override IoValue Value
         */
        /// <summary>
        /// Get/Set the value of the gpio (use IoValue constants)
        /// </summary>    
        /// <example>
        /// <code>
        /// //use IoValue constants (IoValue.High / IoValue.Low)
        /// mygpio.Value = IoValue.High;
        /// IoValue Value = mygpio.Value;</code>
        /// </example> 
        public override IoValue Value
        {
            get
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer, buffer.Length)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (gpioM_intern.unValue == (uint)IoValue.High)
                    return (IoValue.High);
                else
                    return (IoValue.Low);
            }
            set
            {
                GPIOMessageMx51 gpioM_intern = gpioM;
                if (value == IoValue.High)
                    gpioM_intern.unValue = (uint)IoValue.High;
                else if (value == IoValue.Low)
                    gpioM_intern.unValue = (uint)IoValue.Low;
                else
                    throw new ArgumentException();
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.WriteFile(buffer,buffer.Length) == -1))
                    throw new Exception("[GPIO]WriteFile failed");
            /*    if ((hGPIO.DeviceIOControl(IOCTL_GPIO_CONFIG, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                    throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_CONFIG failed");*/
                gpioM = gpioM_intern;
            }
        }
        /*! \fn public override int Wait()
         */
        /// <summary>
        /// Function that wait for the configured interrupt in a gpio configured as interrupt
        /// </summary>        
        /// <returns>
        /// true indicates success, false indicates failure
        /// </returns>              
        /// <example>
        /// <code>
        /// // Wait for an interrupt configured in a irq gpio
        /// if(mygpio.Wait())
        ///     MessageBox.Show("Interrupt achieved"); 
        /// else
        ///     MessageBox.Show("Interrupt not achieved");</code>
        /// </example> 
        public override int Wait()
        {
            GPIOMessageMx51 gpioM_intern = gpioM;
            byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
            return (hGPIO.DeviceIOControl(IOCTL_GPIO_WAIT_FOR_IRQ, ref buffer, ref buffer));
        }
        /*! \fn public override bool Poll(IoValue value, uint tries, int sleep)
             */
        /// <summary>
        /// Function that makes a polling of the gpio
        /// </summary>        
        /// <param name=value>Input value to be pooled (use IoValue constants)</param>
        /// <param name=tries>Number of tries to achieve the value</param>  
        /// <param name=sleep>Time to wait between tries</param>
        /// <returns>
        /// true indicates success, false indicates failure
        /// </returns>                 
        /// <example>
        /// <code>
        /// // Wait for a specific value in the gpio configured as input
        /// if(mygpio.Poll(IoValue.Low,100,1))
        ///     MessageBox.Show("poll achieved"); 
        /// else
        ///     MessageBox.Show("poll not achieved");</code> 
        /// </example>
        public override bool Poll(IoValue value, uint tries, int sleep)
        {
            GPIOMessageMx51 gpioM_intern = gpioM;
            int i;
            for (i = 0; i < tries; i++)
            {
                byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
                if ((hGPIO.ReadFile(buffer)) == -1)
                    throw new Exception("[GPIO]ReadFile failed");
                gpioM_intern = ConvertBuffertoGpioM(buffer);
                gpioM = gpioM_intern;
                if (gpioM_intern.unValue == (uint)value)
                    return (true);
                Thread.Sleep(sleep);
            }
            return (false);
        }
        /*! \fn public bool Release()
             */
        /// <summary>
        /// Function that releases the gpio
        /// </summary>        
        /// <returns>
        /// true indicates success, otherwise indicates failure
        /// </returns>                 
        /// <example>
        /// <code>
        /// // Release a specific gpio
        /// mygpio.Release();</code> 
        /// </example>
        public bool Release()
        {
            GPIOMessageMx51 gpioM_intern = gpioM;
            byte[] buffer = ConvertGpioMtoBuffer(gpioM_intern);
            if ((hGPIO.DeviceIOControl(IOCTL_GPIO_RELEASE, ref buffer, buffer.Length, ref buffer, 0)) == -1)
                throw new Exception("[GPIO]DeviceIOControl IOCTL_GPIO_RELEASE failed");
            return (true);
        }
    }
}


/*! \class GPIO_IOEXPANSORiMX51
*/
/// <summary>
/// General Purpose Input Output class
/// This class manage the GPIO expansor on the DevBoard using the I2C driver
/// </summary>
public class GPIO_IOEXPANSORiMX51 : GPIO
{
    //Handel to I2C driver
    I2CiMX51 I2CFunctions = new I2CiMX51(I2CiMX51.I2CPort.I2C2);
    private byte IO_PinNumber;

    //I2C constans
    private const byte CFG_I2C_GPIO_EXP_ADDR = 0x20;       //PCA9554 address (Slave address will be shifted << 1) 
    private const uint CFG_I2C_GPIO_EXP_ADDR_LEN = 1;      //1 address bytes 

    //I2C commands
    private const byte I2C_READ_INPUT = 0;
    private const byte I2C_RW_OUTPUT = 1;
    private const byte I2C_RW_POL_INVERT = 2;
    private const byte I2C_RW_CONFIG = 3;

    /*! \fn public GPIO_IOEXPANSOR(uint PinNumber)
     */
    /// <summary>
    /// Constructor, need pin number
    /// </summary>
    /// <param name="PinNumber">Pin number to be open</param>
    public GPIO_IOEXPANSORiMX51(uint PinNumber)
    {
        ConfigIO(PinNumber, (uint)DirectionValue.Output, (uint)IoValue.Low);
    }

    /*! \fn public GPIO_IOEXPANSOR(uint PinNumber, DirectionValue PinDirection)
     */
    /// <summary>
    /// Constructor, need pin number and direction
    /// </summary>
    /// <param name="PinNumber">Pin number to be open</param>
    /// <param name="PinDirection">Direction of the pin (use DirectionValue constants)</param> 
    public GPIO_IOEXPANSORiMX51(uint PinNumber, DirectionValue PinDirection)
    {
        ConfigIO(PinNumber, (uint)PinDirection, (uint)IoValue.Low);
    }
    /*! \fn public  GPIO_IOEXPANSOR(uint PinNumber, DirectionValue PinDirection, IoValue PinValue)
     */
    /// <summary>
    /// Constructor, need pin number, direction and pin value
    /// </summary>
    /// <param name="PinNumber">Pin number to be open</param>
    /// <param name="PinDirection">Direction of the pin (use DirectionValue constants)</param> 
    /// <param name="PinValue">Value of the pin (use IoValue constants)</param>
    public GPIO_IOEXPANSORiMX51(uint PinNumber, DirectionValue PinDirection, IoValue PinValue)
    {
        ConfigIO(PinNumber, (uint)PinDirection, (uint)PinValue);
    }

    /***********************************************************************
    * @Function: ConfigIO
    * @Return: void
    * @Descr: configure a gpio as input or output 
    ***********************************************************************/
    void ConfigIO(uint PinNumber, uint PinDirection, uint PinValue)
    {
        byte[] buffer = new byte[2];

        if ((PinNumber > 7) || (PinNumber < 0))
            throw new ArgumentException();

        IO_PinNumber = (byte)(0x1 << (byte)PinNumber);

        I2CFunctions.Addr = CFG_I2C_GPIO_EXP_ADDR;
        buffer[0] =  I2C_RW_CONFIG;
        I2CFunctions.Write(ref buffer, 1);
        I2CFunctions.Read(ref buffer, 1);

        if (PinDirection == (uint)DirectionValue.Input)
        {
            buffer[0] = (byte)(buffer[0] | (byte)IO_PinNumber);
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_CONFIG;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
        }
        else if (PinDirection == (uint)DirectionValue.Output)
        {
            buffer[0] = (byte)(buffer[0] & ~IO_PinNumber);
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_CONFIG;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            buffer[1] = buffer[0];
            buffer[0] = I2C_READ_INPUT;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            if (!I2CFunctions.Read(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if (PinValue == 0)
                buffer[0] = (byte)(buffer[0] & ~IO_PinNumber);
            else if (PinValue == 1)
                buffer[0] = (byte)(buffer[0] | IO_PinNumber);
            else
                throw new ArgumentException();
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_OUTPUT;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
        }
        else
            throw new ArgumentException();
    }

    private uint direction;
    /*! \property public override DirectionValue Direction
     */
    /// <summary>
    /// Get/Set direction property of the gpio (use DirectionValue constants)
    /// </summary>    
    /// <example>
    /// <code>
    /// //use DirectionValue constants (DirectionValue.Input / DirectionValue.Output)
    /// mygpio.Direction = DirectionValue.Input; 
    /// DirectionValue Value = mygpio.Direction;</code>
    /// </example> 
    public override DirectionValue Direction
    {
        get
        {
            byte[] buffer = new byte[1];
            buffer[0] = I2C_RW_CONFIG;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if (!I2CFunctions.Read(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if ((buffer[0] & IO_PinNumber) == IO_PinNumber)
                return (DirectionValue.Input);
            else
                return (DirectionValue.Output);
        }
        set
        {
            byte[] buffer = new byte[2];
            direction = (uint)value;
            buffer[0] = I2C_RW_CONFIG;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            I2CFunctions.Read(ref buffer, 1);
            if (direction == (uint)DirectionValue.Input)
                buffer[0] = (byte)(buffer[0] | IO_PinNumber);
            else if (direction == (uint)DirectionValue.Output)
                buffer[0] = (byte)(buffer[0] & ~IO_PinNumber);
            else
                throw new ArgumentException();
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_CONFIG;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
        }
    }

    /*! \property public override IrqValue IrqMode
     */
    /// <summary>
    /// Not supported
    /// </summary>    
    public override IrqValue IrqMode
    {
        get
        {
            throw new Exception("[GPIO_I2CiMX51]Irq not supported");
        }
        set
        {
            throw new Exception("[GPIO_I2CiMX51]Irq not supported");
        }
    }
    /*! \property public override bool Block
     */
    /// <summary>
    /// Not supported
    /// </summary>    
    public override bool Block
    {
        get
        {
            throw new Exception("[GPIO_I2CiMX51]Block not supported");
        }
        set
        {
            throw new Exception("[GPIO_I2CiMX51]Block not supported");
        }
    }

    /*! \property public override IoValue Value
     */
    /// <summary>
    /// Get/Set the value of the gpio (use IoValue constants)
    /// </summary>    
    /// <example>
    /// <code>
    /// //use IoValue constants (IoValue.High / IoValue.Low)
    /// mygpio.Value = IoValue.High;
    /// IoValue Value = mygpio.Value;</code>
    /// </example> 
    public override IoValue Value
    {
        get
        {
            byte[] buffer = new byte[1];
            buffer[0] = I2C_READ_INPUT;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            if (!I2CFunctions.Read(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if ((buffer[0] & IO_PinNumber) == IO_PinNumber)
                return (IoValue.High);
            else
                return (IoValue.Low);
        }
        set
        {
            byte[] buffer = new byte[2];
            buffer[0] = I2C_READ_INPUT;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            I2CFunctions.Read(ref buffer, 1);
            if (value == IoValue.Low)
                buffer[0] = (byte)(buffer[0] & ~IO_PinNumber);
            else if (value == IoValue.High)
                buffer[0] = (byte)(buffer[0] | IO_PinNumber);
            else
                throw new ArgumentException();
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_OUTPUT;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
        }
    }

    /*! \property public bool Invert
     */
    /// <summary>
    /// Get/Set Invert property of the gpio (use true/false values)
    /// </summary>    
    /// <example>
    /// <code>
    /// //use boolean values (true/false)
    /// mygpio.Invert = true;
    /// bool Value = Invert.Value;</code>
    /// </example> 
    public bool Invert
    {
        get
        {
            byte[] buffer = new byte[1];
            buffer[0] = I2C_RW_POL_INVERT;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            if (!I2CFunctions.Read(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if ((buffer[0] & IO_PinNumber) == IO_PinNumber)
                return (true);
            else
                return (false);
        }
        set
        {
            byte[] buffer = new byte[2];
            buffer[0] = I2C_RW_POL_INVERT;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            I2CFunctions.Read(ref buffer, 1);
            if (value)
                buffer[0] = (byte)(buffer[0] | IO_PinNumber);
            else
                buffer[0] = (byte)(buffer[0] & ~IO_PinNumber);
            buffer[1] = buffer[0];
            buffer[0] = I2C_RW_POL_INVERT;
            if (!I2CFunctions.Write(ref buffer, 2))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
        }
    }
    /***********************************************************************
    * @Method: Wait
    * @Descr: Not supported  
    ***********************************************************************/
    /*! \fn public override int Wait()
     */
    /// <summary>
    /// Not supported
    /// </summary>  
    public override int Wait()
    {
        throw new Exception("[GPIO_I2CiMX51]Wait method not supported");
    }

    /*! \fn public override bool Poll(IoValue value, uint tries, int sleep)
         */
    /// <summary>
    /// Function that makes a polling of the pin
    /// </summary>        
    /// <param name=value>Input value to be pooled (use IoValue constants)</param>
    /// <param name=tries>Number of tries to achieve the value</param>  
    /// <param name=sleep>Time to wait between tries</param>
    /// <returns>
    /// true indicates success, false indicates failure
    /// </returns>                 
    /// <example>
    /// <code>
    /// // Wait for a specific value in the gpio configured as input
    /// if(mygpio.Poll(IoValue.Low,100,1))
    ///     MessageBox.Show("poll achieved"); 
    /// else
    ///     MessageBox.Show("poll not achieved");</code> 
    /// </example>
    public override bool Poll(IoValue value, uint tries, int sleep)
    {
        byte[] buffer = new byte[1];
        int i;
        for (i = 0; i < tries; i++)
        {
            buffer[0] = I2C_READ_INPUT;
            if (!I2CFunctions.Write(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Write failed");
            if (!I2CFunctions.Read(ref buffer, 1))
                throw new Exception("[GPIO_I2CiMX51]Read failed");
            if ((buffer[0] & IO_PinNumber) == IO_PinNumber)
            {
                if (value == IoValue.High)
                    return (true);
            }
            else
            {
                if (value == IoValue.Low)
                    return (true);
            }
            Thread.Sleep(sleep);
        }
        return (false);
    }
}