HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetSerialPins___VOID__I4__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbrxPin;
    CLR_RT_HeapBlock  hbtxPin;
    CLR_RT_HeapBlock  hbctsPin;
    CLR_RT_HeapBlock  hbrtsPin;

    CLR_UINT32 port, rxPin, txPin, ctsPin, rtsPin;

    port = stack.Arg1().NumericByRef().u4;

    rxPin  = (CLR_UINT32)-1; // GPIO_NONE
    txPin  = (CLR_UINT32)-1; // GPIO_NONE
    ctsPin = (CLR_UINT32)-1; // GPIO_NONE
    rtsPin = (CLR_UINT32)-1; // GPIO_NONE
    
    // COM ports are numbered from 0 up
    if(port >= CPU_USART_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    
    ::CPU_USART_GetPins( port, rxPin, txPin, ctsPin, rtsPin );

    hbrxPin.SetInteger ( (CLR_INT32)rxPin  ); TINYCLR_CHECK_HRESULT(hbrxPin.StoreToReference ( stack.Arg2(),  0 ));
    hbtxPin.SetInteger ( (CLR_INT32)txPin  ); TINYCLR_CHECK_HRESULT(hbtxPin.StoreToReference ( stack.Arg3(),  0 ));
    hbctsPin.SetInteger( (CLR_INT32)ctsPin ); TINYCLR_CHECK_HRESULT(hbctsPin.StoreToReference( stack.Arg4(),  0 ));
    hbrtsPin.SetInteger( (CLR_INT32)rtsPin ); TINYCLR_CHECK_HRESULT(hbrtsPin.StoreToReference( stack.ArgN(5), 0 ));
    

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetLCDMetrics___VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();


    CLR_RT_HeapBlock  hbLength;
    CLR_RT_HeapBlock  hbWidth;
    CLR_RT_HeapBlock  hbBitPP;
    CLR_RT_HeapBlock  hbOrientation;

    CLR_UINT32        length, width, bitPP, orientation;

    width  = LCD_SCREEN_WIDTH;
    length = LCD_SCREEN_HEIGHT;
    bitPP  = LCD_SCREEN_BPP;
    orientation = LCD_SCREEN_ORIENTATION;

    hbLength.SetInteger( (CLR_INT32)length );TINYCLR_CHECK_HRESULT(hbLength.StoreToReference( stack.Arg1(), 0 ));
    hbWidth.SetInteger (( CLR_INT32)width  );TINYCLR_CHECK_HRESULT(hbWidth.StoreToReference ( stack.Arg2(), 0 ));

    hbBitPP.SetInteger( (CLR_INT32)bitPP );             TINYCLR_CHECK_HRESULT(hbBitPP.StoreToReference( stack.Arg3(), 0 ));
    hbOrientation.SetInteger( (CLR_INT32)orientation ); TINYCLR_CHECK_HRESULT(hbOrientation.StoreToReference( stack.Arg4(), 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetBaudRateBoundary___VOID__I4__BYREF_U4__BYREF_U4( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbmaxBR;
    CLR_RT_HeapBlock  hbminBR;

    CLR_UINT32 port, maxBR, minBR;

    port = stack.Arg1().NumericByRef().u4;

    maxBR = (CLR_UINT32)0; 
    minBR = (CLR_UINT32)0; 
    
    // COM ports are numbered from 0 up
    if(port >= CPU_USART_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }

    ::CPU_USART_GetBaudrateBoundary( port, maxBR, minBR );

    hbmaxBR.SetInteger( (CLR_INT32)maxBR ); TINYCLR_CHECK_HRESULT(hbmaxBR.StoreToReference( stack.Arg2(), 0 ));
    hbminBR.SetInteger( (CLR_INT32)minBR ); TINYCLR_CHECK_HRESULT(hbminBR.StoreToReference( stack.Arg3(), 0 ));
  

    TINYCLR_NOCLEANUP();


}
//--// SPI
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetSpiPins___VOID__MicrosoftSPOTHardwareSPISPImodule__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbmsk;
    CLR_RT_HeapBlock  hbmiso;
    CLR_RT_HeapBlock  hbmosi;
    
    CLR_UINT32        port, msk, miso, mosi;

    msk  = (CLR_UINT32)-1; // GPIO_NONE
    miso = (CLR_UINT32)-1; // GPIO_NONE
    mosi = (CLR_UINT32)-1; // GPIO_NONE
    
    port = stack.Arg1().NumericByRef().u4;

    // SPI ports are numbered from 0 up
    if(port >= CPU_SPI_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    
    ::CPU_SPI_GetPins( port, msk, miso, mosi );

    hbmsk.SetInteger ( (CLR_INT32)msk  ); TINYCLR_CHECK_HRESULT(hbmsk .StoreToReference( stack.Arg2(), 0 ));
    hbmiso.SetInteger( (CLR_INT32)miso ); TINYCLR_CHECK_HRESULT(hbmiso.StoreToReference( stack.Arg3(), 0 ));
    hbmosi.SetInteger( (CLR_INT32)mosi ); TINYCLR_CHECK_HRESULT(hbmosi.StoreToReference( stack.Arg4(), 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_native_Microsoft_SPOT_Hardware_SystemInfo::GetSystemVersion___STATIC__VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock hbMajor;
        CLR_RT_HeapBlock hbMinor;
        CLR_RT_HeapBlock hbBuild;
        CLR_RT_HeapBlock hbRevision;

        MfReleaseInfo releaseInfo;

        Solution_GetReleaseInfo( releaseInfo );

        hbMajor.SetInteger( releaseInfo.version.usMajor );
        TINYCLR_CHECK_HRESULT(hbMajor.StoreToReference( stack.Arg0(), 0 ));

        hbMinor.SetInteger( releaseInfo.version.usMinor );
        TINYCLR_CHECK_HRESULT(hbMinor.StoreToReference( stack.Arg1(), 0 ));

        hbBuild.SetInteger( releaseInfo.version.usBuild );
        TINYCLR_CHECK_HRESULT(hbBuild.StoreToReference( stack.Arg2(), 0 ));

        hbRevision.SetInteger( releaseInfo.version.usRevision );
        TINYCLR_CHECK_HRESULT(hbRevision.StoreToReference( stack.Arg3(), 0 ));
    }
    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::SecureConnect___STATIC__VOID__I4__STRING__OBJECT( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_INT32 sslContext     = stack.Arg0().NumericByRef().s4;
    CLR_RT_HeapBlock* hb     = stack.Arg1().DereferenceString();
    CLR_RT_HeapBlock* socket = stack.Arg2().Dereference();
    CLR_INT32         timeout_ms = -1; // wait forever
    CLR_RT_HeapBlock  hbTimeout;
    
    int        result;    
    LPCSTR     szName;
    CLR_INT32  handle;
    bool       fRes = true;
    CLR_INT64 *timeout;

    FAULT_ON_NULL(socket);

    handle = socket[ Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::FIELD__m_Handle ].NumericByRef().s4;

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    FAULT_ON_NULL_ARG(hb);

    szName = hb->StringText();

    hbTimeout.SetInteger( timeout_ms );
        
    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    while(true)
    {
        result = SSL_Connect( handle, szName, sslContext );

        if(result == SOCK_EWOULDBLOCK || result == SOCK_TRY_AGAIN)
        {
            // non-blocking - allow other threads to run while we wait for socket activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));

            if(result < 0) break;
        }
        else
        {
            break;
        }
    }

    stack.PopValue();       // Timeout

    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));

    TINYCLR_NOCLEANUP();
}
//--// I2C
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetI2CPins___VOID__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
    CLR_RT_HeapBlock  hbscl;
    CLR_RT_HeapBlock  hbsda;
    CLR_UINT32        scl, sda;

    scl = (CLR_UINT32)-1; // GPIO_NONE
    sda = (CLR_UINT32)-1; // GPIO_NONE

    ::I2C_Internal_GetPins( scl, sda );

    hbscl.SetInteger( (CLR_INT32)scl ); TINYCLR_CHECK_HRESULT(hbscl.StoreToReference( stack.Arg1(), 0 ));
    hbsda.SetInteger( (CLR_INT32)sda ); TINYCLR_CHECK_HRESULT(hbsda.StoreToReference( stack.Arg2(), 0 ));

    TINYCLR_NOCLEANUP();

}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::poll___STATIC__BOOLEAN__OBJECT__I4__I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock* socket = stack.Arg0().Dereference();
    CLR_INT32 handle;
    CLR_INT32 mode       = stack.Arg1().NumericByRef().s4;    
    CLR_INT32 timeout_us = stack.Arg2().NumericByRef().s4;
    
    CLR_RT_HeapBlock hbTimeout;
    CLR_INT32 timeout_ms;

    CLR_INT32 res = 0;
    bool fRes     = true;

    CLR_INT64* timeout;

    FAULT_ON_NULL(socket);
    handle = socket[ FIELD__m_Handle ].NumericByRef().s4;

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE (CLR_E_PROCESS_EXCEPTION);
    }


    if(timeout_us < 0) timeout_ms = -1;
    else               timeout_ms = timeout_us / 1000;

    hbTimeout.SetInteger( timeout_ms );

    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    while(fRes)
    {
        res = Helper__SelectSocket( handle, mode );

        if(res != 0) break;

        TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));
    }

    stack.PopValue(); //timer

    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, res ));

    stack.SetResult_Boolean( res == 1 );   

    TINYCLR_NOCLEANUP();
}
HRESULT Library_corlib_native_System_AppDomain::Unload___STATIC__VOID__SystemAppDomain( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();

    CLR_RT_AppDomain* appDomainSav;
    CLR_RT_AppDomain* appDomain;
    CLR_RT_HeapBlock  hbTimeout;
    CLR_INT64*        timeout;
    bool              fRes;
    
    TINYCLR_CHECK_HRESULT(GetAppDomain( stack.ThisRef(), appDomain, appDomainSav, false ));

    hbTimeout.SetInteger( 5 * 1000 );
    
    if(stack.m_customState == 0)
    {        
        //Attempt to unload the AppDomain only once
        TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.UnloadAppDomain( appDomain, stack.m_owningThread ));            
    }

    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    fRes = true;
    while(fRes)
    {
        //Check to make sure this AppDomain is the one that caused the event to fire
        if(appDomain->m_state == CLR_RT_AppDomain::AppDomainState_Unloaded) break;

        _ASSERTE(CLR_EE_IS(UnloadingAppDomain));

        TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_AppDomain, fRes ));
    }

    if(!fRes) TINYCLR_SET_AND_LEAVE(CLR_E_TIMEOUT);

    appDomain->DestroyInstance();

    stack.PopValue();
    
    TINYCLR_CLEANUP();

    g_CLR_RT_ExecutionEngine.SetCurrentAppDomain( appDomainSav );    

    TINYCLR_CLEANUP_END();
}
HRESULT Library_corlib_native_System_TimeSpan::Compare___STATIC__I4__SystemTimeSpan__SystemTimeSpan( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();

    CLR_INT64*       pLeft;
    CLR_INT64*       pRight;
    CLR_RT_HeapBlock resLeft;
    CLR_RT_HeapBlock resRight;

    pLeft  = Library_corlib_native_System_TimeSpan::GetValuePtr( stack        ); FAULT_ON_NULL(pLeft);
    pRight = Library_corlib_native_System_TimeSpan::GetValuePtr( stack.Arg1() ); FAULT_ON_NULL(pRight);

    resLeft .SetInteger( *pLeft  );
    resRight.SetInteger( *pRight );

    stack.SetResult_I4( CLR_RT_HeapBlock::Compare_Signed_Values( resLeft, resRight ) );

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeIsSupportedBaudRate___BOOLEAN__I4__BYREF_U4( CLR_RT_StackFrame& stack )
{
	TINYCLR_HEADER();
    CLR_RT_HeapBlock  hbBR;
    CLR_UINT32        port;
   
    CLR_UINT32        SupportedBaudrate;

    port              = stack.Arg1().NumericByRef().u4;

    TINYCLR_CHECK_HRESULT(hbBR.LoadFromReference( stack.Arg2() ));
    SupportedBaudrate = hbBR.NumericByRef().u4;

    if (CPU_USART_IsBaudrateSupported(port,SupportedBaudrate) == TRUE)
        stack.SetResult_Boolean( true );
    else
        stack.SetResult_Boolean( false );

    hbBR.SetInteger( (CLR_UINT32)SupportedBaudrate );
    TINYCLR_CHECK_HRESULT(hbBR.StoreToReference( stack.Arg2(), 0 ));        

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::ReadWriteHelper( CLR_RT_StackFrame& stack, bool isWrite )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock*       socket     = stack.Arg0().Dereference();
    CLR_RT_HeapBlock_Array* arrData    = stack.Arg1().DereferenceArray(); 
    CLR_INT32               offset     = stack.Arg2().NumericByRef().s4;
    CLR_INT32               count      = stack.Arg3().NumericByRef().s4;
    CLR_INT32               timeout_ms = stack.Arg4().NumericByRef().s4;
    CLR_UINT8*              buffer;
    CLR_RT_HeapBlock        hbTimeout;

    CLR_INT32  totReadWrite;
    bool       fRes = true;
    CLR_INT64 *timeout;
    int        result = 0;
    CLR_INT32 handle;

    if(count == 0) 
    {
        stack.SetResult_I4( 0 );
        TINYCLR_SET_AND_LEAVE(S_OK);
    }

    FAULT_ON_NULL(socket);

    handle = socket[ Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::FIELD__m_Handle ].NumericByRef().s4;

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }


    FAULT_ON_NULL(arrData);

    hbTimeout.SetInteger( timeout_ms );
        
    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    //
    // Push "totReadWrite" onto the eval stack.
    //
    if(stack.m_customState == 1)
    {
        stack.PushValueI4( 0 );

        stack.m_customState = 2;
    }

    totReadWrite = stack.m_evalStack[ 1 ].NumericByRef().s4;

    buffer = arrData->GetElement( offset + totReadWrite );
    count -= totReadWrite;

    if((offset + count + totReadWrite) > (int)arrData->m_numOfElements) TINYCLR_SET_AND_LEAVE(CLR_E_INDEX_OUT_OF_RANGE);    

    while(count > 0)
    {
        // first make sure we have data to read or ability to write
        while(fRes)
        {
            if(!isWrite)
            {
                // check SSL_DataAvailable() in case SSL has already read and buffered socket data
                result = SSL_DataAvailable(handle);

                if((result > 0) || ((result < 0) && (SOCK_getlasterror() != SOCK_EWOULDBLOCK)))
                {
                    break;
                }
            }

            result = Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::Helper__SelectSocket( handle, isWrite ? 1 : 0 );

            if((result > 0) || ((result < 0) && (SOCK_getlasterror() != SOCK_EWOULDBLOCK)))
            {
                break;
            }

            // non-blocking - allow other threads to run while we wait for socket activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));

            // timeout expired 
            if(!fRes)
            {
                result = SOCK_SOCKET_ERROR;
                
                ThrowError(stack, SOCK_ETIMEDOUT);
            
                TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION );
            }
        }

        // socket is in the excepted state, so let's bail out
        if(SOCK_SOCKET_ERROR == result)
        {
            break;
        }

        if(isWrite)
        {
            result = SSL_Write( handle, (const char*)buffer, count );
        }
        else
        {
            result = SSL_Read( handle, (char*)buffer, count );

            if(result == SSL_RESULT__WOULD_BLOCK)
            {
                continue;
            }
        }

        // ThrowOnError expects anything other than 0 to be a failure - so return 0 if we don't have an error
        if(result <= 0)
        {
            break;
        }

        buffer       += result;
        totReadWrite += result;
        count        -= result;


        // read is non-blocking if we have any data
        if(!isWrite && (totReadWrite > 0))
        {
            break;
        }

        stack.m_evalStack[ 1 ].NumericByRef().s4 = totReadWrite;        
    }

    stack.PopValue();       // totReadWrite
    stack.PopValue();       // Timeout

    if(result < 0)
    {
        TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));
    }

    stack.SetResult_I4( totReadWrite );
    
    TINYCLR_NOCLEANUP();
    
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::getaddrinfo___STATIC__VOID__STRING__BYREF_STRING__BYREF_SZARRAY_SZARRAY_U1( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    LPCSTR szName = stack.Arg0().RecoverString();
    struct SOCK_addrinfo hints;
    struct SOCK_addrinfo* addr = NULL;
    struct SOCK_addrinfo* addrT;
    CLR_UINT32        cAddresses = 0;
    CLR_RT_HeapBlock* pAddress;
    CLR_INT32         timeout_ms = 30000;
    CLR_RT_HeapBlock  hbTimeout;
    CLR_INT32         ret;
    bool              fRes = true;
    CLR_INT64*        timeout;

    hbTimeout.SetInteger( timeout_ms );

    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    do
    {
        memset( &hints, 0, sizeof(hints) );

        ret = SOCK_getaddrinfo( szName, NULL, &hints, &addr );

        if(ret == SOCK_SOCKET_ERROR)
        {
            if(SOCK_getlasterror() == SOCK_EWOULDBLOCK)
            {
                // non-blocking - allow other threads to run while we wait for handle activity
                TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    while(fRes);
    
    // timeout expired
    if(!fRes)
    {
        ret = SOCK_SOCKET_ERROR;
        
        ThrowError( stack, SOCK_ETIMEDOUT );
    
        TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION );
    }

    // getaddrinfo returns a winsock error code rather than SOCK_SOCKET_ERROR, so pass this on to the exception handling
    if(ret != 0)
    {
        ThrowError( stack, ret );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    {
        CLR_RT_HeapBlock  hbCanonicalName;
        CLR_RT_HeapBlock  hbAddresses;
        
        hbCanonicalName.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc( hbCanonicalName );

        hbAddresses.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc2( hbAddresses );

        for(int pass = 0; pass < 2; pass++)
        {                                    
            cAddresses = 0;

            for(addrT = addr; addrT != NULL; addrT = addrT->ai_next)
            {
                if(pass == 1)
                {
                    if(addrT->ai_canonname && addrT->ai_canonname[ 0 ])
                    {
                        //allocate return string
                        TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbCanonicalName, addrT->ai_canonname ));
                        TINYCLR_CHECK_HRESULT(hbCanonicalName.StoreToReference( stack.Arg1(), 0 ));
                    }

                    //allocate address and store into array
                    pAddress = (CLR_RT_HeapBlock*)hbAddresses.DereferenceArray()->GetElement( cAddresses );

                    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( *pAddress, (CLR_UINT32)addrT->ai_addrlen, g_CLR_RT_WellKnownTypes.m_UInt8 ));

                    //copy address.
                    memcpy( pAddress->DereferenceArray()->GetFirstElement(), addrT->ai_addr, addrT->ai_addrlen );
                }
                                
                cAddresses++;
            }
                            
            if(pass == 0)
            {
                //allocate array of byte arrays
                CLR_RT_ReflectionDef_Index idx;

                idx.m_kind               = REFLECTION_TYPE;
                idx.m_levels             = 2;
                idx.m_data.m_type.m_data = g_CLR_RT_WellKnownTypes.m_UInt8.m_data;

                TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( hbAddresses, cAddresses, idx ));

                TINYCLR_CHECK_HRESULT(hbAddresses.StoreToReference( stack.Arg2(), 0 ));                
            }
        }    
    }

    stack.PopValue();       // Timeout
    
    TINYCLR_CLEANUP();

    if( addr ) SOCK_freeaddrinfo( addr );

    TINYCLR_CLEANUP_END();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::SendRecvHelper( CLR_RT_StackFrame& stack, bool fSend, bool fAddress )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock*       socket    = stack.Arg0().Dereference();
    CLR_INT32               handle;
    CLR_RT_HeapBlock_Array* arrData   = stack.Arg1().DereferenceArray(); 
    CLR_UINT32              offset    = stack.Arg2().NumericByRef().u4;
    CLR_UINT32              count     = stack.Arg3().NumericByRef().u4;
    CLR_INT32               flags     = stack.Arg4().NumericByRef().s4;
    CLR_INT32               timeout_ms = stack.ArgN(5).NumericByRef().s4;
    CLR_RT_HeapBlock        hbTimeout;

    CLR_INT64* timeout;
    CLR_UINT8* buf;
    bool       fRes = true;
    CLR_INT32  totReadWrite;
    CLR_INT32  ret = 0;

    FAULT_ON_NULL(socket);
    handle = socket[ FIELD__m_Handle ].NumericByRef().s4;

    FAULT_ON_NULL(arrData);
    
    if(offset + count > arrData->m_numOfElements) TINYCLR_SET_AND_LEAVE(CLR_E_INDEX_OUT_OF_RANGE);    

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE (CLR_E_PROCESS_EXCEPTION);
    }

    hbTimeout.SetInteger( timeout_ms );
        
    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    //
    // Push "totReadWrite" onto the eval stack.
    //
    if(stack.m_customState == 1)
    {
        stack.PushValueI4( 0 );
        
        stack.m_customState = 2;
    }

    totReadWrite = stack.m_evalStack[ 1 ].NumericByRef().s4;

    buf    = arrData->GetElement( offset + totReadWrite );
    count -= totReadWrite;

    while(count > 0)
    {
        CLR_INT32 bytes = 0;

        // first make sure we have data to read or ability to write
        while(fRes)
        {
            ret = Helper__SelectSocket( handle, fSend ? 1 : 0 );

            if(ret != 0) break;

            // non-blocking - allow other threads to run while we wait for handle activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));
        }

        // timeout expired
        if(!fRes)
        {
            ret = SOCK_SOCKET_ERROR;
            
            ThrowError( stack, SOCK_ETIMEDOUT );

            TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION );
        }

        // socket is in the excepted state, so let's bail out
        if(SOCK_SOCKET_ERROR == ret)
        {
            break;
        }

        if(fAddress)
        {
            struct SOCK_sockaddr addr;
            CLR_UINT32 addrLen = sizeof(addr);
            CLR_RT_HeapBlock& blkAddr = stack.ArgN( 6 );

            if(fSend)
            {
                TINYCLR_CHECK_HRESULT(MarshalSockAddress( &addr, addrLen, blkAddr ));
                
                bytes = SOCK_sendto( handle, (const char*)buf, count, flags, &addr, addrLen );
            }
            else
            {
                CLR_RT_HeapBlock* pBlkAddr = blkAddr.Dereference();
                
                TINYCLR_CHECK_HRESULT(MarshalSockAddress( &addr, addrLen, *pBlkAddr ));

                bytes = SOCK_recvfrom( handle, (char*)buf, count, flags, &addr, (int*)&addrLen );

                if(bytes != SOCK_SOCKET_ERROR)
                {
                    TINYCLR_CHECK_HRESULT(MarshalSockAddress( blkAddr, &addr, addrLen ));
                }
            }
        }
        else
        {
            if(fSend)
            {
                bytes = SOCK_send( handle, (const char*)buf, count, flags );
            }
            else
            {
                bytes = SOCK_recv( handle, (char*)buf, count, flags );
            }
        }

        // send/recv/sendto/recvfrom failed
        if(bytes == SOCK_SOCKET_ERROR)
        {
            CLR_INT32 err = SOCK_getlasterror();
            
            if(err != SOCK_EWOULDBLOCK)
            {
                ret = SOCK_SOCKET_ERROR;
                break;
            }
            
            continue;
        }
                // zero recv bytes indicates the handle has been closed.
        else if(!fSend && (bytes == 0)) 
        {
            break;
        }
        
        buf          += bytes;
        totReadWrite += bytes;
        count        -= bytes;

        stack.m_evalStack[ 1 ].NumericByRef().s4 = totReadWrite;        

        // receive returns immediately after receiving bytes.
        if(!fSend && (totReadWrite > 0))
        {
            break;
        }

    }

    stack.PopValue();       // totReadWrite
    stack.PopValue();       // Timeout
    
    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, ret ));

    stack.SetResult_I4( totReadWrite );

    TINYCLR_NOCLEANUP();
}