/******************************************************************
***** *****
***** Name: tcpip.c *****
***** Ver.: 1.0 *****
***** Date: 07/05/2001 *****
***** Auth: Andreas Dannenberg *****
***** HTWK Leipzig *****
***** university of applied sciences *****
***** Germany *****
***** Func: implements the TCP/IP-stack and provides a *****
***** simple API to the user *****
***** *****
******************************************************************/
#include "tcpip.h"
#include "EMAC.h" // Keil: Line added
#include <string.h> // Keil: Line added
#include "LPC24xx.h" // Keil: Register definition file for LPC2468
const unsigned char MyMAC[6] = // "M1-M2-M3-M4-M5-M6"
{
MYMAC_1, MYMAC_2, MYMAC_3,
MYMAC_4, MYMAC_5, MYMAC_6
};
// easyWEB-API function
// initalizes the LAN-controller, reset flags, starts timer-ISR
void TCPLowLevelInit(void)
{
// Keil: Timer 0 is used for TCP retransmission control
T0MR0 = 3144000; // 262mSec
T0MCR = 3; // Interrupt and Reset on MR0
T0TCR = 1; // Timer0 Enable
VICVectAddr4 = (unsigned int)TCPClockHandler;// set interrupt vector in 4
VICIntEnable = 0x00000010; // Enable Timer0 Interrupt
PCONP |= (1<<12); // Deliver clock to AD
PINSEL1 = 0x00014000; // Enable AD0 and AD1 inputs
Init_EMAC();
TransmitControl = 0;
TCPFlags = 0;
TCPStateMachine = CLOSED;
SocketStatus = 0;
}
// easyWEB-API function
// does a passive open (listen on 'MyIP:TCPLocalPort' for an incoming
// connection)
void TCPPassiveOpen(void)
{
if (TCPStateMachine == CLOSED)
{
TCPFlags &= ~TCP_ACTIVE_OPEN; // let's do a passive open!
TCPStateMachine = LISTENING;
SocketStatus = SOCK_ACTIVE; // reset, socket now active
}
}
// easyWEB-API function
// does an active open (tries to establish a connection between
// 'MyIP:TCPLocalPort' and 'RemoteIP:TCPRemotePort')
void TCPActiveOpen(void)
{
if ((TCPStateMachine == CLOSED) || (TCPStateMachine == LISTENING))
{
TCPFlags |= TCP_ACTIVE_OPEN; // let's do an active open!
TCPFlags &= ~IP_ADDR_RESOLVED; // we haven't opponents MAC yet
PrepareARP_REQUEST(); // ask for MAC by sending a broadcast
LastFrameSent = ARP_REQUEST;
TCPStartRetryTimer();
SocketStatus = SOCK_ACTIVE; // reset, socket now active
}
}
// easyWEB-API function
// closes an open connection
void TCPClose(void)
{
switch (TCPStateMachine)
{
case LISTENING :
case SYN_SENT :
{
TCPStateMachine = CLOSED;
TCPFlags = 0;
SocketStatus = 0;
break;
}
case SYN_RECD :
case ESTABLISHED :
{
TCPFlags |= TCP_CLOSE_REQUESTED;
break;
}
}
}
// easyWEB-API function
// releases the receive-buffer and allows easyWEB to store new data
// NOTE: rx-buffer MUST be released periodically, else the other TCP
// get no ACKs for the data it sent
void TCPReleaseRxBuffer(void)
{
SocketStatus &= ~SOCK_DATA_AVAILABLE;
}
// easyWEB-API function
// transmitts data stored in 'TCP_TX_BUF'
// NOTE: * number of bytes to transmit must have been written to 'TCPTxDataCount'
// * data-count MUST NOT exceed 'MAX_TCP_TX_DATA_SIZE'
void TCPTransmitTxBuffer(void)
{
if ((TCPStateMachine == ESTABLISHED) || (TCPStateMachine == CLOSE_WAIT))
if (SocketStatus & SOCK_TX_BUF_RELEASED)
{
SocketStatus &= ~SOCK_TX_BUF_RELEASED; // occupy tx-buffer
TCPUNASeqNr += TCPTxDataCount; // advance UNA
TxFrame1Size = ETH_HEADER_SIZE + IP_HEADER_SIZE + TCP_HEADER_SIZE + TCPTxDataCount;
TransmitControl |= SEND_FRAME1;
LastFrameSent = TCP_DATA_FRAME;
TCPStartRetryTimer();
}
}
// Reads the length of the received ethernet frame and checks if the
// destination address is a broadcast message or not
unsigned int IsBroadcast(void) {
unsigned short RecdDestMAC[3]; // 48 bit MAC
RecdFrameLength = StartReadFrame();
CopyFromFrame_EMAC(&RecdDestMAC, 6); // receive DA to see if it was a broadcast
CopyFromFrame_EMAC(&RecdFrameMAC, 6); // store SA (for our answer)
if ((RecdDestMAC[0] == 0xFFFF) &&
(RecdDestMAC[1] == 0xFFFF) &&
(RecdDestMAC[2] == 0xFFFF)) {
return(1);
} else {
return (0);
}
}
// easyWEB's 'main()'-function
// must be called from user program periodically (the often - the better)
// handles network, TCP/IP-stack and user events
void DoNetworkStuff(void)
{
if (CheckFrameReceived()) // Packet received
{
if (IsBroadcast()) {
ProcessEthBroadcastFrame();
} else {
ProcessEthIAFrame();
}
EndReadFrame(); // release buffer in ethernet controller
}
if (TCPFlags & TCP_TIMER_RUNNING)
if (TCPFlags & TIMER_TYPE_RETRY)
{
if (TCPTimer > RETRY_TIMEOUT)
{
TCPRestartTimer(); // set a new timeout
if (RetryCounter)
{
TCPHandleRetransmission(); // resend last frame
RetryCounter--;
}
else
{
TCPStopTimer();
TCPHandleTimeout();
}
}
}
else if (TCPTimer > FIN_TIMEOUT)
{
TCPStateMachine = CLOSED;
TCPFlags = 0; // reset all flags, stop retransmission...
SocketStatus &= SOCK_DATA_AVAILABLE; // clear all flags but data available
}
switch (TCPStateMachine)
{
case CLOSED :
case LISTENING :
{
if (TCPFlags & TCP_ACTIVE_OPEN) // stack has to open a connection?
if (TCPFlags & IP_ADDR_RESOLVED) // IP resolved?
if (!(TransmitControl & SEND_FRAME2)) // buffer free?
{
TCPSeqNr = ((unsigned long)ISNGenHigh << 16) | (T0TC & 0xFFFF); // Keil: changed from TAR to T0TC;
// set local ISN
TCPUNASeqNr = TCPSeqNr;
TCPAckNr = 0; // we don't know what to ACK!
TCPUNASeqNr++; // count SYN as a byte
PrepareTCP_FRAME(TCP_CODE_SYN); // send SYN frame
LastFrameSent = TCP_SYN_FRAME;
TCPStartRetryTimer(); // we NEED a retry-timeout
TCPStateMachine = SYN_SENT;
}
break;
}
case SYN_RECD :
case ESTABLISHED :
{
if (TCPFlags & TCP_CLOSE_REQUESTED) // user has user initated a close?
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free?
if (TCPSeqNr == TCPUNASeqNr) // all data ACKed?
{
TCPUNASeqNr++;
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK);
LastFrameSent = TCP_FIN_FRAME;
TCPStartRetryTimer();
TCPStateMachine = FIN_WAIT_1;
}
break;
}
case CLOSE_WAIT :
{
if (!(TransmitControl & (SEND_FRAME2 | SEND_FRAME1))) // buffers free?
if (TCPSeqNr == TCPUNASeqNr) // all data ACKed?
{
TCPUNASeqNr++; // count FIN as a byte
PrepareTCP_FRAME(TCP_CODE_FIN | TCP_CODE_ACK); // we