using System.Threading;
using GHI.Pins;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace HWModules
{
    public sealed class MotherBoard
    {
        private static OutputPort DebugLED = new OutputPort(GHI.Pins.G400S.Gpio.PC21, false);
        private static OutputPort MVOpenCommandBit = new OutputPort(GHI.Pins.G400S.Gpio.PD5, false);
        private static InputPort MVOpenedStatusBit = new InputPort(GHI.Pins.G400S.Gpio.PD3, true, Port.ResistorMode.PullUp);
        private static InputPort MVReadyStatusBit = new InputPort(GHI.Pins.G400S.Gpio.PA3, true, Port.ResistorMode.PullUp);
        private static OutputPort I2C_ENA1;
        private static OutputPort I2C_ENA2;
        private static OutputPort I2C_ENA3;
        private static OutputPort I2C_ENA4;
        private static OutputPort I2C_ENA5;
        private static OutputPort I2C_ENA6;
        private static OutputPort V12_RUN;
        private static OutputPort V5_RUN;

        private static InterruptPort CH01_NFLT;
        private static InterruptPort CH02_NFLT;
        private static InterruptPort CH03_NFLT;
        private static InterruptPort CH04_NFLT;
        private static InterruptPort CH05_NFLT;
        private static InterruptPort CH06_NFLT;
        private static InterruptPort CH07_NFLT;
        private static InterruptPort CH08_NFLT;
        private static InterruptPort CH09_NFLT;
        private static InterruptPort CH10_NFLT;
        private static InterruptPort CH11_NFLT;
        private static InterruptPort CH12_NFLT;
        //private static InterruptPort CH13_NFLT; //NOT AVAILABLE
        private static InterruptPort CH14_NFLT;
        private static InterruptPort CH15_NFLT;
        private static InterruptPort CH16_NFLT;
        private static InterruptPort CH17_NFLT; //NOT AVAILABLE
        private static InterruptPort CH18_NFLT;
        private static InterruptPort CH19_NFLT;


        private static InterruptPort CH07_NIRQ;
        private static InterruptPort CH08_NIRQ;
        private static InterruptPort CH09_NIRQ;
        private static InterruptPort CH10_NIRQ;
        private static InterruptPort CH11_NIRQ;
        private static InterruptPort CH12_NIRQ;

        private static InterruptPort LDR0_BUTTON;
        private static InterruptPort LDR1_BUTTON;

        private static OutputPort PUMP_ENA;
        private static InterruptPort PUMP_FLT;

        private static InputPort SD_DETECT;


        //Properties
        public bool Ldr0Pushed { get; set; }
        public bool Ldr1Pushed { get; set; }


        // create the singleton reference
        private static MotherBoard _instance;

        public static MotherBoard Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new MotherBoard();
                return _instance;
            }
        }

        // Initialize all pins and configurations.
        private MotherBoard()
        {
            //DebugLED = new OutputPort(GHI.Pins.G400S.Gpio.PC21, false);
            InitI2cClockLine();

            InitI2CEnableLines();

            InitSlotOutputs();

            InitSlotFaults();

            InitIRQLines();

            InitButtons();

            V12_RUN = new OutputPort(GHI.Pins.G400S.Gpio.PC18, false);
            V5_RUN = new OutputPort(GHI.Pins.G400S.Gpio.PB17, false);

            SD_DETECT = new InputPort(GHI.Pins.G400S.Gpio.PD7, false, Port.ResistorMode.PullUp);

            //InitPumpIO();
        }

        /// <summary>
        /// This Forces the I2c line on the G400S to be high on startup, to fix a low state that persists through
        /// self restarts.
        /// </summary>
        private void InitI2cClockLine()
        {
            var i2CClockOutputPort = new OutputPort(GHI.Pins.G400S.Gpio.PA31, true);
            i2CClockOutputPort = null;
            Debug.GC(true);
            Thread.Sleep(250);
        }

        public enum ChannelNames
        {
            CTDChannel = 1,
            PumpMotorControllerElexChannel,
            BluetoothChannel = 3,
            IridiumChannel,
            MSCChannel = 5,
            OptodeChannel = 6,
            Channel7= 7,
            RadiometerChannel = 8,
            FLBBChannel = 9,
            Channel10 = 10,
            Channel11 = 11,
            Channel12 = 12,
            //PTHSensorChannel = 13,//On by default
            PositionSensorChannel = 14,
            GPSChannel = 15,
            MotorizedValve,
            Spare1I2C,
            Spare2I2C,
            Spare3SPI,
            lastChannel,
        }

        private static OutputPort CH01_PWR;
        private static OutputPort CH02_PWR;
        private static OutputPort CH03_PWR;
        private static OutputPort CH04_PWR;
        private static OutputPort CH05_PWR;
        private static OutputPort CH06_PWR;
        private static OutputPort CH07_PWR;
        private static OutputPort CH08_PWR;
        private static OutputPort CH09_PWR;
        private static OutputPort CH10_PWR;
        private static OutputPort CH11_PWR;
        private static OutputPort CH12_PWR;
        //private static OutputPort CH13_PWR;
        private static OutputPort CH14_PWR;
        private static OutputPort CH15_PWR;
        private static OutputPort CH16_PWR;
        private static OutputPort CH17_PWR;
        private static OutputPort CH18_PWR;
        private static OutputPort CH19_PWR;

        private static void InitSlotOutputs()
        {
            CH01_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC27, false);
            CH02_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC4, false);
            CH03_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PB9, false);
            CH04_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC26, false);
            CH05_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC13, false);
            CH06_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC3, false);
            CH07_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC0, false);
            CH08_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PB10, false);
            CH09_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PB5, false);
            CH10_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PB6, false);
            CH11_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PB18, false);
            CH12_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC1, false);
            //CH13_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PA29, false); CH13 Not available as used by SBE MODE
            CH14_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PD2, false);
            CH15_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PA26, false);
            CH16_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PA2, false);
            CH17_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PC23, false);
            CH18_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PA29, false);
            CH19_PWR = new OutputPort(GHI.Pins.G400S.Gpio.PD0, false);
        }

        public void EnableChannelPower(int channelnum)
        {
            turnChannelPowerOnOff(channelnum, true);
        }

        public void EnableChannelPower(ChannelNames channel)
        {
            turnChannelPowerOnOff((int) channel, true);
        }

        public void EnableChannelPowerAll()
        {
            for (int i = 1; i < (int)ChannelNames.lastChannel; i++)
                EnableChannelPower(i);
        }

        public void DisableChannelPower(int channelnum)
        {
            turnChannelPowerOnOff(channelnum, false);
        }

        public void DisableChannelPower(ChannelNames channel)
        {
            turnChannelPowerOnOff((int) channel, false);
        }

        public void turnChannelPowerOnOff(int channel, bool state)
        {
            switch (channel)
            {
                case 1: CH01_PWR.Write(state); break;
                case 2: CH02_PWR.Write(state); break;
                case 3: CH03_PWR.Write(state); break;
                case 4: CH04_PWR.Write(state); break;
                case 5: CH05_PWR.Write(state); break;
                case 6: CH06_PWR.Write(state); break;
                case 7: CH07_PWR.Write(state); break;
                case 8: CH08_PWR.Write(state); break;
                case 9: CH09_PWR.Write(state); break;
                case 10: CH10_PWR.Write(state); break;
                case 11: CH11_PWR.Write(state); break;
                case 12: CH12_PWR.Write(state); break;
                //case 13: CH13_PWR.Write(state); break;
                case 14: CH14_PWR.Write(state); break;
                case 15: CH15_PWR.Write(state); break;
                case 16: CH16_PWR.Write(state); break;
                case 17: CH17_PWR.Write(state); break;
                case 18: CH18_PWR.Write(state); break;
                case 19: CH19_PWR.Write(state); break;
            }
        }

        public bool QueryChannelPower(int channel)
        {
            switch (channel)
            {
                case 1: return CH01_PWR.Read(); 
                case 2: return CH02_PWR.Read();
                case 3: return CH03_PWR.Read();
                case 4: return CH04_PWR.Read();
                case 5: return CH05_PWR.Read();
                case 6: return CH06_PWR.Read();
                case 7: return CH07_PWR.Read();
                case 8: return CH08_PWR.Read();
                case 9: return CH09_PWR.Read();
                case 10: return CH10_PWR.Read();
                case 11: return CH11_PWR.Read();
                case 12: return CH12_PWR.Read();
                //case 13: return CH13_PWR.Read();
                case 14: return CH14_PWR.Read();
                case 15: return CH15_PWR.Read();
                case 16: return CH16_PWR.Read();
                case 17: return CH17_PWR.Read();
                case 18: return CH18_PWR.Read();
                case 19: return CH19_PWR.Read();
            }

            return false;
        }

        public bool QueryChannelPower(ChannelNames channel)
        {
            return QueryChannelPower((int) channel);
        }

        private void InitIRQLines()
        {
            CH07_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PB7, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            CH08_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PC12, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            CH09_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PC11, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            CH10_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PB0, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            CH11_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PC10, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            CH12_NIRQ = new InterruptPort(GHI.Pins.G400S.Gpio.PB1, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);

            CH07_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
            CH08_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
            CH09_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
            CH10_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
            CH11_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
            CH12_NIRQ.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); });
        }

        private void InitButtons()
        {
            LDR0_BUTTON = new InterruptPort(G400S.Gpio.PA24, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            LDR1_BUTTON = new InterruptPort(G400S.Gpio.PA4, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);

            LDR0_BUTTON.OnInterrupt += new NativeEventHandler((x,y,z) => { 
                ToggleDebugLED();
                EngrLogger.Comment("LDR0 Button Pushed");
                Thread.Sleep(1000); //Debounce
                LDR0_BUTTON.ClearInterrupt();
                Ldr0Pushed = true;
            });

            LDR1_BUTTON.OnInterrupt += new NativeEventHandler((x,y,z) => { 
                ToggleDebugLED();
                EngrLogger.Comment("LDR1 Button Pushed");
                Thread.Sleep(1000); //Debounce
                LDR1_BUTTON.ClearInterrupt();
                Ldr1Pushed = true;
            });
        }
        //TODO IMMEDIATE this is for the motherboard, and changes for the LHE
        //private static void InitPumpIO()
        //{
            //PUMP_ENA = new OutputPort(GHI.Pins.G400S.Gpio.PC19, false);
            //PUMP_FLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC20, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            //PUMP_FLT.OnInterrupt += new NativeEventHandler((x, y, z) => { EngrLogger.Comment("Pump Unit Faulted"); PUMP_FLT.ClearInterrupt(); });
        //}

        private static void InitI2CEnableLines()
        {
            I2C_ENA1 = new OutputPort(GHI.Pins.G400S.Gpio.PB11, true);
            I2C_ENA2 = new OutputPort(GHI.Pins.G400S.Gpio.PB12, true);
            I2C_ENA3 = new OutputPort(GHI.Pins.G400S.Gpio.PB13, true);
            I2C_ENA4 = new OutputPort(GHI.Pins.G400S.Gpio.PB14, true);
            I2C_ENA5 = new OutputPort(GHI.Pins.G400S.Gpio.PB15, true);
            I2C_ENA6 = new OutputPort(GHI.Pins.G400S.Gpio.PB16, true);
        }

        private void InitSlotFaults()
        {
            CH01_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC14, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH02_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PB4, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH03_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC30, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH04_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC31, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLevelLow);
            CH05_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC15, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH06_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC6, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH07_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PB2, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH08_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC24, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH09_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC2, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH10_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC7, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH11_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PB8, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH12_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PB3, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            //CH13_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PD4, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow); //CH13 PWR NOT AVAILABLE
            //This is Eric's original mapping, Brent's digital board needs PA26 to be a regular GPIO
            CH14_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC22, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH15_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PC5, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH16_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PD1, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH17_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PD6, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH18_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PA27, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);
            CH19_NFLT = new InterruptPort(GHI.Pins.G400S.Gpio.PD4, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLevelLow);

            //TODO P2 Remore Clear Interrupt, this should be a registered error with the faultmonitor
            CH01_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 01 FAULTED"); CH01_NFLT.ClearInterrupt(); DisableChannelPower(1);});
            CH02_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 02 FAULTED"); CH02_NFLT.ClearInterrupt(); DisableChannelPower(2);});
            CH03_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 03 FAULTED"); CH03_NFLT.ClearInterrupt(); DisableChannelPower(3);});
            CH04_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 04 FAULTED"); CH04_NFLT.ClearInterrupt(); DisableChannelPower(4);
                Thread.Sleep(100); EnableChannelPower(4);
            });
            CH05_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 05 FAULTED"); CH05_NFLT.ClearInterrupt(); DisableChannelPower(5);});
            CH06_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 06 FAULTED"); CH06_NFLT.ClearInterrupt(); DisableChannelPower(6);});
            CH07_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 07 FAULTED"); CH07_NFLT.ClearInterrupt(); DisableChannelPower(7);});
            CH08_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 08 FAULTED"); CH08_NFLT.ClearInterrupt(); DisableChannelPower(8);});
            CH09_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 09 FAULTED"); CH09_NFLT.ClearInterrupt(); DisableChannelPower(9);});
            CH10_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 10 FAULTED"); CH10_NFLT.ClearInterrupt(); DisableChannelPower(10);});
            CH11_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 11 FAULTED"); CH11_NFLT.ClearInterrupt(); DisableChannelPower(11);});
            CH12_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 12 FAULTED"); CH12_NFLT.ClearInterrupt(); DisableChannelPower(12);});
            //CH13_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 13 FAULTED"); CH13_NFLT.ClearInterrupt(); DisableChannelPower(13);});
            CH14_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 14 FAULTED"); CH14_NFLT.ClearInterrupt(); DisableChannelPower(14);});
            CH15_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 15 FAULTED"); CH15_NFLT.ClearInterrupt(); DisableChannelPower(15);});
            CH16_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 16 FAULTED"); CH16_NFLT.ClearInterrupt(); DisableChannelPower(16);});
            CH17_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 17 FAULTED"); CH17_NFLT.ClearInterrupt(); DisableChannelPower(17);});
            CH18_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 18 FAULTED"); CH18_NFLT.ClearInterrupt(); DisableChannelPower(18);});
            CH19_NFLT.OnInterrupt += new NativeEventHandler((x, y, z) => { ToggleDebugLED(); EngrLogger.Comment("CHANNEL 19 FAULTED"); CH19_NFLT.ClearInterrupt(); DisableChannelPower(19);});
        }

        public bool SDDetected
        {
            get { return !(SD_DETECT.Read()); }
        }

        private int ct;
        public void DitherDebugLED()
        {
            for (ct = 0; ct < 10; ct++)
                ToggleDebugLED();
        }
        public void ToggleDebugLED()
        {
            DebugLED.Write(!DebugLED.Read());
        }

        public void EnableI2CPort(int portnum)
        {
            I2CPORT(portnum, true);
        }

        public void DisableI2CPort(int portnum)
        {
            I2CPORT(portnum, false);
        }

        private void I2CPORT(int portnum, bool state)
        {
            switch (portnum)
            {
                case 1:
                    I2C_ENA1.Write(state);
                    break;
                case 2:
                    I2C_ENA2.Write(state);
                    break;
                case 3:
                    I2C_ENA3.Write(state);
                    break;
                case 4:
                    I2C_ENA4.Write(state);
                    break;
                case 5:
                    I2C_ENA5.Write(state);
                    break;
                case 6:
                    I2C_ENA6.Write(state);
                    break;
            }
        }

        public void Enable12V()
        {
            V12_RUN.Write(true);
        }

        public void Disable12V()
        {
            V12_RUN.Write(false);
        }

        public void Enable5V()
        {
            V5_RUN.Write(true);
        }

        public void Disable5V()
        {
            V5_RUN.Write(false);
        }

        /**
        public void EnablePump()
        {
            PUMP_ENA.Write(true);
        }

        public void DisablePump()
        {
            PUMP_ENA.Write(false);
        }
        */

        /// <summary>
        /// Register a delegate to take action when Interrupt Ports
        /// get triggered.
        /// </summary>
        /// <param name="id">Interrupt port reference</param>
        /// <param name="handler">Delegate to be called, 
        /// and it must clear the IRQ as well, through a call to ClearIRQ()</param>
        public void RegisterInterruptHandler(MbInterrupt id, NativeEventHandler handler)
        {
            switch (id)
            {
                case MbInterrupt.CH07IRQ:
                    CH07_NIRQ.OnInterrupt += handler;
                    break;
                case MbInterrupt.CH08IRQ:
                    CH08_NIRQ.OnInterrupt += handler;
                    break;
                case MbInterrupt.CH09IRQ:
                    CH09_NIRQ.OnInterrupt += handler;
                    break;
                case MbInterrupt.CH10IRQ:
                    CH10_NIRQ.OnInterrupt += handler;
                    break;
                case MbInterrupt.CH11IRQ:
                    CH11_NIRQ.OnInterrupt += handler;
                    break;
                case MbInterrupt.CH12IRQ:
                    CH12_NIRQ.OnInterrupt += handler;
                    break;
            }
        }

        /// <summary>
        /// Clears IRQ on the related interrupt 
        /// </summary>
        /// <param name="id"></param>
        public void ClearInterrupt(MbInterrupt id)
        {
            switch (id)
            {
                case MbInterrupt.CH07IRQ:
                    CH07_NIRQ.ClearInterrupt();
                    break;
                case MbInterrupt.CH08IRQ:
                    CH08_NIRQ.ClearInterrupt();
                    break;
                case MbInterrupt.CH09IRQ:
                    CH09_NIRQ.ClearInterrupt();
                    break;
                case MbInterrupt.CH10IRQ:
                    CH10_NIRQ.ClearInterrupt();
                    break;
                case MbInterrupt.CH11IRQ:
                    CH11_NIRQ.ClearInterrupt();
                    break;
                case MbInterrupt.CH12IRQ:
                    CH12_NIRQ.ClearInterrupt();
                    break;
            }
        }

        public void openMV()
        {
            MVOpenCommandBit.Write(true);
        }

        public void closeMV()
        {
            MVOpenCommandBit.Write(false);
        }

        public bool getMVOpenedStatus()
        {
            return MVOpenedStatusBit.Read();    //MVOpenedStatusBit is active low: false = open
        }

        public bool getMVReadyStatus()
        {
            return MVReadyStatusBit.Read();     //MVReadyStatusBit is active low: false = ready
        }

        public void WaitForLdr0()
        {
            Debug.Print("Press LDR0 Button to Continue... \n");
            while (!Ldr0Pushed)
            {
                ToggleDebugLED();
                Thread.Sleep(333);
            }
                
            //Clear the state
            Ldr0Pushed = false;
        }
    }

    public enum MbInterrupt
    {
        CH07IRQ,
        CH08IRQ,
        CH09IRQ,
        CH10IRQ,
        CH11IRQ,
        CH12IRQ,
    }
}
