1050 lines
27 KiB
C
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);
|
|
}
|
|
}
|
|
}
|