flexPTP-demo-TM4C1294/Drivers/eth_client_lwip.c
2025-06-08 22:33:35 +02:00

1050 lines
27 KiB
C

//*****************************************************************************
//
// eth_client.c - This is the portion of the ethernet client.
//
// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
// This is part of revision 2.1.0.12573 of the EK-TM4C1294XL Firmware Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/flash.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "eth_client_lwip.h"
#include "utils/lwiplib.h"
#include "lwip/dns.h"
#include "lwipopts.h"
#include "lwip/tcp.h"
#include "lwip/ip.h"
#if RTOS_FREERTOS
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#endif
//*****************************************************************************
//
// Flag indexes for g_sEnet.ui32Flags
//
//*****************************************************************************
#define FLAG_TIMER_DHCP_EN 0
#define FLAG_TIMER_DNS_EN 1
#define FLAG_TIMER_TCP_EN 2
#define FLAG_DHCP_STARTED 3
#define FLAG_DNS_ADDRFOUND 4
//*****************************************************************************
//
// The current state of the Ethernet connection.
//
//*****************************************************************************
struct
{
volatile uint32_t ui32Flags;
//
// Array to hold the MAC addresses.
//
uint8_t pui8MACAddr[8];
//
// Global define of the TCP structure used.
//
struct tcp_pcb *psTCP;
//
// Global IP structure to hold a copy of the IP address.
//
struct ip4_addr sIPAddr;
//
// Global IP structure to hold a copy of the DNS resolved address.
//
struct ip4_addr sResolvedIP;
//
// The saved proxy name as a text string.
//
const char *pcProxyName;
//
// The port number for the proxy server.
//
uint16_t ui16ProxyPort;
//
// The saved host name as a text string.
//
const char *pcHostName;
//
// The port number on the host.
//
uint16_t ui16HostPort;
//
// The number of bytes to be sent.
//
uint32_t ui32SendSize;
//
// The index into the send buffer.
//
uint32_t ui32SendIndex;
//
// Event handler.
//
tEventFunction pfnEvent;
//
// States.
//
volatile enum
{
iEthNoConnection,
iEthDHCPWait,
iEthDNSWait,
iEthTCPOpen,
iEthTCPWait,
iEthSend,
iEthIdle
} eState;
}
g_sEnet;
//*****************************************************************************
//
// Maximum size of a request.
//
//*****************************************************************************
#define MAX_REQUEST 256
//*****************************************************************************
//
// Send buffer config.
//
//*****************************************************************************
uint8_t g_pui8SendBuff[SEND_BUFFER_SIZE];
//*****************************************************************************
//
// Reset the state to a non-connected state to restart dhcp and dns.
//
//*****************************************************************************
static void
ResetConnection(void)
{
//
// Nothing to do if already not connected.
//
if(g_sEnet.eState != iEthNoConnection)
{
//
// No longer have a link.
//
g_sEnet.eState = iEthNoConnection;
//
// Reset the flags to just enable the lwIP timer.
//
g_sEnet.ui32Flags = (1 << FLAG_TIMER_DHCP_EN);
}
//
// Deallocate the TCP structure if it was already allocated.
//
if(g_sEnet.psTCP)
{
//
// Clear out all of the TCP callbacks.
//
tcp_sent(g_sEnet.psTCP, NULL);
tcp_recv(g_sEnet.psTCP, NULL);
tcp_err(g_sEnet.psTCP, NULL);
//
// Close the TCP connection.
//
tcp_close(g_sEnet.psTCP);
g_sEnet.psTCP = 0;
}
}
//*****************************************************************************
//
// Handler function when the DNS server gets a response or times out.
//
// \param pcName is DNS server name.
// \param psIPAddr is the DNS server's IP address.
// \param vpArg is the configurable argument.
//
// This function is called when the DNS server resolves an IP or times out.
// If the DNS server returns an IP structure that is not NULL, add the IP to
// to the g_sEnet.sResolvedIP IP structure.
//
// \return None.
//
//*****************************************************************************
static void
DNSServerFound(const char *pcName, const ip_addr_t *psIPAddr, void *vpArg)
{
//
// Check if a valid DNS server address was found.
//
if((psIPAddr) && (psIPAddr->addr))
{
//
// Copy the returned IP address into a global IP address.
//
g_sEnet.sResolvedIP = *psIPAddr;
//
// Tell the main program that a DNS address was found.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND) = 1;
}
else
{
//
// Disable the DNS timer.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
}
}
//*****************************************************************************
//
//! Handles lwIP TCP/IP errors.
//!
//! \param vPArg is the state data for this connection.
//! \param iErr is the error that was detected.
//!
//! This function is called when the lwIP TCP/IP stack has detected an error.
//! The connection is no longer valid.
//!
//! \return None.
//
//*****************************************************************************
void
TCPError(void *vPArg, err_t iErr)
{
//
// Signal event handler that there was an error.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_ERROR, 0, (uint32_t)iErr);
}
//*****************************************************************************
//
//! Finalizes the TCP connection in client mode.
//!
//! \param pvArg is the state data for this connection.
//! \param psPcb is the pointer to the TCP control structure.
//! \param psBuf
//! \param iErr is not used in this implementation.
//!
//! This function is called when the lwIP TCP/IP stack has completed a TCP
//! connection.
//!
//! \return This function will return an lwIP defined error code.
//
//*****************************************************************************
err_t
TCPReceived(void *pvArg, struct tcp_pcb *psPcb, struct pbuf *psBuf, err_t iErr)
{
struct pbuf *psBufCur;
//
// Signal event handler that data is available.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_RECEIVE, (void *)psBuf->payload,
(uint32_t)psBuf->len);
//
// Indicate that you have received and processed this set of TCP data.
//
tcp_recved(psPcb, psBuf->len);
//
// Initialize the linked list pointer to parse.
//
psBufCur = psBuf;
//
// Free the buffers used since they have been processed.
//
while(psBufCur->len != 0)
{
//
// Indicate that you have received and processed this set of TCP data.
//
tcp_recved(psPcb, psBufCur->len);
//
// Go to the next buffer.
//
psBufCur = psBufCur->next;
//
// Terminate if there are no more buffers.
//
if(psBufCur == 0)
{
break;
}
}
//
// Free the memory space allocated for this receive.
//
pbuf_free(psBuf);
//
// Return.
//
return(ERR_OK);
}
//*****************************************************************************
//
//! Handles acknowledgment of data transmitted via Ethernet.
//!
//! \param pvArg is the state data for this connection.
//! \param psPcb is the pointer to the TCP control structure.
//! \param ui16Len is the length of the data transmitted.
//!
//! This function is called when the lwIP TCP/IP stack has received an
//! acknowledgment for data that has been transmitted.
//!
//! \return This function will return an lwIP defined error code.
//
//*****************************************************************************
err_t
TCPSent(void *pvArg, struct tcp_pcb *psPcb, u16_t ui16Len)
{
//
// Signal the event handler that data was sent.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_SEND, 0, (uint32_t)ui16Len);
//
// Return OK.
//
return (ERR_OK);
}
//*****************************************************************************
//
//! Finalizes the TCP connection in client mode.
//!
//! \param pvArg is the state data for this connection.
//! \param psPcb is the pointer to the TCP control structure.
//! \param iErr is not used in this implementation.
//!
//! This function is called when the lwIP TCP/IP stack has completed a TCP
//! connection.
//!
//! \return This function will return an lwIP defined error code.
//
//*****************************************************************************
err_t
TCPConnected(void *pvArg, struct tcp_pcb *psPcb, err_t iErr)
{
//
// Check if there was a TCP error.
//
if(iErr != ERR_OK)
{
//
// Clear out all of the TCP callbacks.
//
tcp_sent(psPcb, NULL);
tcp_recv(psPcb, NULL);
tcp_err(psPcb, NULL);
//
// Close the TCP connection.
//
tcp_close(psPcb);
if(psPcb == g_sEnet.psTCP)
{
g_sEnet.psTCP = 0;
}
//
// And return.
//
return(ERR_CONN);
}
//
// Setup the TCP receive function.
//
tcp_recv(psPcb, TCPReceived);
//
// Setup the TCP error function.
//
tcp_err(psPcb, TCPError);
//
// Setup the TCP sent callback function.
//
tcp_sent(psPcb, TCPSent);
//
// Signal event handler that connection is established.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_CONNECT, 0, 0);
//
// Return a success code.
//
return(ERR_OK);
}
//*****************************************************************************
//
//! TCP connect
//!
//! This function attempts to connect to a TCP endpoint.
//!
//! \return None.
//
//*****************************************************************************
int32_t
EthClientTCPConnect(void)
{
err_t eTCPReturnCode;
//
// Enable the TCP timer function calls.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN) = 1;
if(g_sEnet.psTCP)
{
//
// Initially clear out all of the TCP callbacks.
//
tcp_sent(g_sEnet.psTCP, NULL);
tcp_recv(g_sEnet.psTCP, NULL);
tcp_err(g_sEnet.psTCP, NULL);
//
// Make sure there is no lingering TCP connection.
//
tcp_close(g_sEnet.psTCP);
}
//
// Create a new TCP socket.
//
g_sEnet.psTCP = tcp_new();
//
// Check if you need to go through a proxy.
//
if(g_sEnet.pcProxyName != 0)
{
//
// Attempt to connect through the proxy server.
//
eTCPReturnCode = tcp_connect(g_sEnet.psTCP, &g_sEnet.sResolvedIP,
g_sEnet.ui16ProxyPort, TCPConnected);
}
else
{
//
// Attempt to connect to the server directly.
//
eTCPReturnCode = tcp_connect(g_sEnet.psTCP, &g_sEnet.sResolvedIP,
g_sEnet.ui16HostPort, TCPConnected);
}
if((eTCPReturnCode == ERR_OK) || (eTCPReturnCode == ERR_INPROGRESS))
{
return(0);
}
else
{
return(1);
}
}
//*****************************************************************************
//
//! TCP discconnect
//!
//! This function attempts to disconnect a TCP endpoint.
//!
//! \return None.
//
//*****************************************************************************
void
EthClientTCPDisconnect(void)
{
g_sEnet.eState = iEthIdle;
//
// Reset connection.
//
ResetConnection();
//
// Disable the TCP timer function calls.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN) = 0;
}
//*****************************************************************************
//
//! Send a request to the server
//!
//! \param pi8Request request to be sent
//! \param ui32Size length of the request to be sent. This is usually the size
//! of the request minus the termination character.
//!
//! This function will send the request to the connected server
//!
//! \return the lwIP error code.
//
//*****************************************************************************
int32_t
EthClientSend(int8_t *pi8Request, uint32_t ui32Size)
{
uint32_t ui32Index, ui32SendSize, ui32CurrentState;
//
// Save off the current number of bytes used in the buffer and the current
// state.
//
ui32SendSize = g_sEnet.ui32SendSize;
ui32CurrentState = g_sEnet.eState;
//
// Check that we have room in the buffer.
//
if (ui32SendSize + ui32Size <= SEND_BUFFER_SIZE)
{
//
// Fill the send buffer.
//
for (ui32Index = 0; ui32Index < ui32Size; ui32Index++)
{
g_pui8SendBuff[ui32SendSize + ui32Index] =
pi8Request[ui32Index];
}
//
// Increment the number of bytes we have to send.
//
g_sEnet.ui32SendSize += ui32Size;
//
// Check if we have already sent some data in the buffer.
// This is determined by checking the number of bytes left to be sent
// and the current state. If we have then we need to update the index
// into the buffer.
//
if (g_sEnet.ui32SendSize != ui32SendSize &&
g_sEnet.eState != ui32CurrentState &&
ui32CurrentState == iEthSend)
{
g_sEnet.ui32SendIndex = ui32SendSize;
}
else
{
g_sEnet.ui32SendIndex = 0;
}
//
// Set the state to Send and send on the next Tick.
//
g_sEnet.eState = iEthSend;
return(ERR_OK);
}
else
{
//
// Tell the app we dont have enough memory.
//
return(ERR_MEM);
}
}
//*****************************************************************************
//
//! DHCP connect
//!
//! This function obtains the MAC address from the User registers, starts the
//! DHCP timer and blocks until an IP address is obtained.
//!
//! \return None.
//
//*****************************************************************************
err_t
EthClientDHCPConnect(void)
{
//
// Check if the DHCP has already been started.
//
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) == 0)
{
//
// Set the DCHP started flag.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) = 1;
}
else
{
//
// If DHCP has already been started, we need to clear the IPs and
// switch to static. This forces the LWIP to get new IP address
// and retry the DHCP connection.
//
lwIPNetworkConfigChange(0, 0, 0, IPADDR_USE_STATIC);
//
// Restart the DHCP connection.
//
lwIPNetworkConfigChange(0, 0, 0, IPADDR_USE_DHCP);
}
return ERR_OK;
}
//*****************************************************************************
//
//! Handler function when the DNS server gets a response or times out.
//!
//! This function is called when the DNS server resolves an IP or times out.
//! If the DNS server returns an IP structure that is not NULL, add the IP to
//! to the g_sEnet.sResolvedIP IP structure.
//!
//! \return None.
//
//*****************************************************************************
int32_t
EthClientDNSResolve(void)
{
err_t iRet;
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN))
{
return(ERR_INPROGRESS);
}
//
// Set DNS config timer to true.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 1;
//
// Initialize the host name IP address found flag to false.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND) = 0;
//
// Set state.
//
g_sEnet.eState = iEthDNSWait;
//
// Resolve host name.
//
if(g_sEnet.pcProxyName != 0)
{
iRet = dns_gethostbyname(g_sEnet.pcProxyName, &g_sEnet.sResolvedIP,
DNSServerFound, 0);
}
else
{
iRet = dns_gethostbyname(g_sEnet.pcHostName, &g_sEnet.sResolvedIP,
DNSServerFound, 0);
}
//
// If ERR_OK is returned, the local DNS table resolved the host name. If
// ERR_INPROGRESS is returned, the DNS request has been queued and will be
// sent to the DNS server.
//
if(iRet == ERR_OK)
{
//
// Stop calling the DNS timer function.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
}
//
// Return host name not found.
//
return(iRet);
}
//*****************************************************************************
//
// Returns the weather server IP address for this interface.
//
// This function will read and return the server IP address that is currently
// in use. This could be the proxy server if the Internet proxy is enabled.
//
// \return Returns the weather server IP address for this interface.
//
//*****************************************************************************
uint32_t
EthClientServerAddrGet(void)
{
//
// Return IP.
//
return((uint32_t)g_sEnet.sResolvedIP.addr);
}
//*****************************************************************************
//
//! Returns the IP address for this interface.
//!
//! This function will read and return the currently assigned IP address for
//! the Tiva Ethernet interface.
//!
//! \return Returns the assigned IP address for this interface.
//
//*****************************************************************************
uint32_t
EthClientAddrGet(void)
{
//
// Return IP.
//
return(lwIPLocalIPAddrGet());
}
//*****************************************************************************
//
// Returns the MAC address for the Tiva Ethernet controller.
//
// \param pui8MACAddr is the 6 byte MAC address assigned to the Ethernet
// controller.
//
// This function will read and return the MAC address for the Ethernet
// controller.
//
// \return Returns the weather server IP address for this interface.
//
//*****************************************************************************
void
EthClientMACAddrGet(uint8_t *pui8MACAddr)
{
int32_t iIdx;
for(iIdx = 0; iIdx < 6; iIdx++)
{
pui8MACAddr[iIdx] = g_sEnet.pui8MACAddr[iIdx];
}
}
//*****************************************************************************
//
// Set the proxy string for the Ethernet connection.
//
// \param pi8ProxyName is the string used as the proxy server name.
//
// This function sets the current proxy used by the Ethernet connection. The
// \e pi8ProxyName value can be 0 to indicate that no proxy is in use or it can
// be a pointer to a string that holds the name of the proxy server to use.
// The content of the pointer passed to \e pi8ProxyName should not be changed
// after this call as this function only stores the pointer and does not copy
// the data from this pointer.
//
// \return None.
//
//*****************************************************************************
void
EthClientProxySet(const char *pcProxyName, uint16_t ui16Port)
{
//
// Save the new proxy string.
//
g_sEnet.pcProxyName = pcProxyName;
g_sEnet.ui16ProxyPort = ui16Port;
//
// Reset the connection on any change to the proxy.
//
ResetConnection();
}
void
EthClientHostSet(const char *pcHostName, uint16_t ui16Port)
{
//
// Save the new host setting.
//
g_sEnet.pcHostName = pcHostName;
g_sEnet.ui16HostPort = ui16Port;
//
// Reset the connection on any change to the host.
//
ResetConnection();
}
//*****************************************************************************
//
// Initialize the Ethernet client
//
// This function initializes all the Ethernet components to not configured.
// This tells the SysTick interrupt which timer modules to call.
//
// \return None.
//
//*****************************************************************************
void
EthClientInit(uint32_t ui32SysClock, tEventFunction pfnEvent)
{
uint32_t ui32User0, ui32User1;
//
// Initialize all the Ethernet components to not configured. This tells
// the SysTick interrupt which timer modules to call.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN) = 0;
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN) = 0;
g_sEnet.eState = iEthNoConnection;
g_sEnet.pfnEvent = pfnEvent;
g_sEnet.pcProxyName = 0;
//
// Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
// address needed to program the hardware registers, then program the MAC
// address into the Ethernet Controller registers.
//
FlashUserGet(&ui32User0, &ui32User1);
g_sEnet.pui8MACAddr[0] = ((ui32User0 >> 0) & 0xff);
g_sEnet.pui8MACAddr[1] = ((ui32User0 >> 8) & 0xff);
g_sEnet.pui8MACAddr[2] = ((ui32User0 >> 16) & 0xff);
g_sEnet.pui8MACAddr[3] = ((ui32User1 >> 0) & 0xff);
g_sEnet.pui8MACAddr[4] = ((ui32User1 >> 8) & 0xff);
g_sEnet.pui8MACAddr[5] = ((ui32User1 >> 16) & 0xff);
//
// Initialize lwIP with the system clock, MAC and use DHCP.
//
lwIPInit(ui32SysClock, g_sEnet.pui8MACAddr, 0, 0, 0, IPADDR_USE_DHCP);
//
// Start lwIP tick interrupt.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN) = 1;
}
//*****************************************************************************
//
// Periodic Tick for the Ethernet client
//
// This function is the needed periodic tick for the Ethernet client. It needs
// to be called periodically through the use of a timer or systick.
//
// \return None.
//
//*****************************************************************************
#if NO_SYS
void
EthClientTick(uint32_t ui32TickMS)
{
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DHCP_EN))
{
lwIPTimer(ui32TickMS);
}
}
#endif // #if NO_SYS
//*****************************************************************************
//
// Required by lwIP library to support any host-related timer functions.
//
//*****************************************************************************
void
lwIPHostTimerHandler(void)
{
uint32_t ui32IPAddr;
err_t eError;
#if NO_SYS
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN))
{
dns_tmr();
}
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_TCP_EN))
{
tcp_tmr();
}
#endif // #if NO_SYS
//
// Check if we need to send.
//
if(g_sEnet.eState == iEthSend)
{
//
// Queue the send.
//
eError = tcp_write(g_sEnet.psTCP,
g_pui8SendBuff + g_sEnet.ui32SendIndex,
g_sEnet.ui32SendSize, TCP_WRITE_FLAG_COPY);
//
// Write data for sending (but does not send it immediately).
//
if(eError == ERR_OK)
{
//
// Find out what we can send and send it.
//
tcp_output(g_sEnet.psTCP);
//
// No more data to send.
//
g_sEnet.ui32SendSize = 0;
}
//
// Set state to Idle
//
g_sEnet.eState = iEthIdle;
}
//
// Check for loss of link.
//
else if((g_sEnet.eState != iEthNoConnection) &&
(lwIPLocalIPAddrGet() == 0xffffffff))
{
//
// Reset the connection due to a loss of link.
//
ResetConnection();
//
// Signal a disconnect event.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_DISCONNECT, 0, 0);
}
else if(g_sEnet.eState == iEthNoConnection)
{
//
// Once link is detected start DHCP.
//
if(lwIPLocalIPAddrGet() != 0xffffffff)
{
EthClientDHCPConnect();
g_sEnet.eState = iEthDHCPWait;
}
}
else if(g_sEnet.eState == iEthDHCPWait)
{
//
// Get IP address.
//
ui32IPAddr = lwIPLocalIPAddrGet();
//
// If IP Address has not yet been assigned, update the display
// accordingly.
//
if((ui32IPAddr != 0xffffffff) && (ui32IPAddr != 0))
{
//
// Update the DHCP IP address.
//
g_sEnet.sIPAddr.addr = ui32IPAddr;
g_sEnet.eState = iEthIdle;
//
// Stop DHCP timer since an address has been provided.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_DHCP_STARTED) = 0;
//
// Signal a connect event.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_DHCP, &g_sEnet.sIPAddr.addr, 4);
}
}
else if(g_sEnet.eState == iEthDNSWait)
{
//
// Check to see if the DNS timer has been turned off, which signals
// that the DNS lookup has failed.
//
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) == 0)
{
//
// Go back to idle.
//
g_sEnet.eState = iEthIdle;
//
// Signal failure.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_DNS, 0, 0);
}
//
// Check if the host name was resolved.
//
if(HWREGBITW(&g_sEnet.ui32Flags, FLAG_DNS_ADDRFOUND))
{
//
// Stop calling the DNS timer function.
//
HWREGBITW(&g_sEnet.ui32Flags, FLAG_TIMER_DNS_EN) = 0;
//
// Go back to idle.
//
g_sEnet.eState = iEthIdle;
//
// Notify the main routine of the new Ethernet connection.
//
g_sEnet.pfnEvent(ETH_CLIENT_EVENT_DNS, &g_sEnet.sResolvedIP.addr,
4);
}
}
}