HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::Dispose___VOID__BOOLEAN( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);
        CLR_RT_HeapBlock_NativeEventDispatcher* port;
        TINYCLR_CHECK_HRESULT(Library_spot_hardware_native_Microsoft_SPOT_Hardware_NativeEventDispatcher::GetEventDispatcher( stack, port ));
        // Check if HW port was not closed.  - 
        if ( ( pThis[ FIELD__m_flags ].NumericByRefConst().s4 & GPIO_PortParams::c_Disposed ) == 0 )   
        {
            CLR_UINT32 portID = pThis[ FIELD__m_portId ].NumericByRefConst().u4;
            
            // Cleanup the HAL queue from the instance of assiciated CLR_RT_HeapBlock_NativeEventDispatcher 
            port->RemoveFromHALQueue();
            
            // Set flag in managed object that port is closed.
            pThis[ FIELD__m_flags ].NumericByRef().s4 |= GPIO_PortParams::c_Disposed;

            // Set pin to input state so the pin is in "weak" state and does not drain power. 
            ::CPU_GPIO_EnableInputPin2( portID,
                                        false,
                                        NULL,
                                        0,
                                        GPIO_INT_NONE,
                                        RESISTOR_PULLUP
                                      );
            // Releases the pin
            ::CPU_GPIO_ReservePin( portID, FALSE );
            
        }
    }
    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_NativeEventDispatcher::Dispose___VOID__BOOLEAN( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
        
    CLR_RT_HeapBlock_NativeEventDispatcher *pNativeDisp = NULL;
    
    CLR_RT_HeapBlock*  pThis = stack.This();  FAULT_ON_NULL(pThis);
    
    TINYCLR_CHECK_HRESULT(GetEventDispatcher( stack, pNativeDisp ));
    
    // Cleanup the HAL queue from the instance of assiciated CLR_RT_HeapBlock_NativeEventDispatcher 
    pNativeDisp->RemoveFromHALQueue();
    
    // Calls driver to de-initilaze hardware.
    TINYCLR_CHECK_HRESULT(pNativeDisp->m_DriverMethods->m_CleanupProc( pNativeDisp )); 
    
    TINYCLR_NOCLEANUP();
}
HRESULT CLR_HW_Hardware::SpawnDispatcher()
{
    NATIVE_PROFILE_CLR_HARDWARE();
    TINYCLR_HEADER();

    CLR_RT_ApplicationInterrupt* interrupt;
    CLR_RT_HeapBlock_NativeEventDispatcher* ioPort;
    CLR_RT_HeapBlock_NativeEventDispatcher ::InterruptPortInterrupt *interruptData;

    // if reboot is in progress, just bail out
    if(CLR_EE_DBG_IS( RebootPending )) 
    {
        return S_OK;
    }

    interrupt = (CLR_RT_ApplicationInterrupt*)m_interruptData.m_applicationQueue.FirstValidNode();

    if((interrupt == NULL) || !g_CLR_RT_ExecutionEngine.EnsureSystemThread( g_CLR_RT_ExecutionEngine.m_interruptThread, ThreadPriority::System_Highest ))
    {
        return S_OK;
    }

    interrupt->Unlink();

    interruptData = &interrupt->m_interruptPortInterrupt;
    ioPort = interruptData->m_context;

    CLR_RT_ProtectFromGC gc1 ( *ioPort );
                    
    TINYCLR_SET_AND_LEAVE(ioPort->StartDispatch( interrupt, g_CLR_RT_ExecutionEngine.m_interruptThread ));
            
    TINYCLR_CLEANUP();

    if(FAILED(hr))
    {
        ioPort->ThreadTerminationCallback( interrupt );
    }

    --m_interruptData.m_queuedInterrupts;

    TINYCLR_CLEANUP_END();    
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_NativeEventDispatcher::Dispose___VOID__BOOLEAN( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
        
    CLR_RT_HeapBlock_NativeEventDispatcher *pNativeDisp = NULL;
    
    CLR_RT_HeapBlock*  pThis = stack.This();  FAULT_ON_NULL(pThis);
    
    TINYCLR_CHECK_HRESULT(GetEventDispatcher( stack, pNativeDisp ));
    
    // Cleanup the HAL queue from the instance of assiciated CLR_RT_HeapBlock_NativeEventDispatcher 
    pNativeDisp->RemoveFromHALQueue();
    
    // Calls driver to enable interrupts.  Consider that there could be no driver 
    // associated to this object so check that the driver methods are set 
    // we will be tolerant in this case and not throw any exception
    if(pNativeDisp->m_DriverMethods != NULL)
    {
        TINYCLR_CHECK_HRESULT(pNativeDisp->m_DriverMethods->m_CleanupProc( pNativeDisp )); 
    }
    
    TINYCLR_NOCLEANUP();
}
void Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::IsrProcedure( GPIO_PIN pin, BOOL pinState, void* context )
{
    { 
        ASSERT_IRQ_MUST_BE_OFF();

        // If context parameter is NULL, then there is no way to dispatch data managed thread.
        CLR_RT_HeapBlock_NativeEventDispatcher* port = (CLR_RT_HeapBlock_NativeEventDispatcher*)context;
        if ( port == NULL )
        {    
            return;
        }
        
        // Retrieve managed object correspoinding to instance of CLR_RT_HeapBlock.
        // Managed object keeps all the data associated with port.
        CLR_RT_HeapBlock* pManagedPortObj = NULL;
        port->RecoverManagedObject( pManagedPortObj );
        if ( pManagedPortObj == NULL )
        {
            return;
        }

        CLR_INT32 &flags              = pManagedPortObj[ Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::FIELD__m_flags             ].NumericByRef().s4;
        CLR_UINT32  portID            = pManagedPortObj[ Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::FIELD__m_portId            ].NumericByRefConst().u4;
        GPIO_INT_EDGE  interruptMode  = (GPIO_INT_EDGE)pManagedPortObj[ Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::FIELD__m_interruptMode ].NumericByRefConst().s4;
        GPIO_RESISTOR  resistorMode   = (GPIO_RESISTOR)pManagedPortObj[ Library_spot_hardware_native_Microsoft_SPOT_Hardware_Port::FIELD__m_resistorMode  ].NumericByRefConst().s4;

        
        // Discard the call if flags show that interrupt is disabled for this port. 
        if ( flags & GPIO_PortParams::c_InterruptDisabled )
        {
            return;
        }

        // For the level interrupt we disable it once the level was reached.
        // Application needs to enable it back. It is used to protect agains multiple callbacks as result of reaching the level. 
        if ( interruptMode == GPIO_INT_LEVEL_HIGH || interruptMode == GPIO_INT_LEVEL_LOW )
        {   
           
            if ( flags & GPIO_PortParams::c_Disposed )
            {
                return;
            }

            // Disable interrupts for port if not disabled. 
            if(( flags & GPIO_PortParams::c_InterruptDisabled ) == 0)
            {
                // Disable level interrupt.
                flags |= GPIO_PortParams::c_InterruptDisabled;
                ::CPU_GPIO_EnableInputPin2(
                                             portID, // data1 is portId for GPIO case.
                                             false, 
                                             NULL,
                                             0,
                                             GPIO_INT_NONE,
                                             resistorMode
                                          );
            }
        }

        // To calling SaveToHALQueue saves data to 128 slot HAL queue and finally causes dispatch to managed callback. 
        port->SaveToHALQueue( pin, pinState );
    }
}