⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpip.c

📁 使用MSP430與CS8900開發網頁伺服器
💻 C
📖 第 1 页 / 共 3 页
字号:
/******************************************************************
 *****                                                        *****
 *****  Name: tcpip.c                                         *****
 *****  Ver.: 1.0                                             *****
 *****  Date: November 2001                                   *****
 *****  Auth: Andreas Dannenberg                              *****
 *****  Func: implements the TCP/IP-stack and provides a      *****
 *****        simple API to the user                          *****
 *****                                                        *****
 ******************************************************************/

#include "tcpip.h"

// easyWEB-API function
// initalizes the LAN-controller, reset flags, starts timer-ISR


inline unsigned int SwapBytes(unsigned int Data)
{
  return (Data >> 8) | (Data << 8);
}


void TCPLowLevelInit(void)
{
  BCSCTL1 &= ~DIVA0;                             // ACLK = XT1 / 4 = 2 MHz
  BCSCTL1 |= DIVA1;
  TACTL = ID1 | ID0 | TASSEL0 | TAIE;            // stop timer, use ACLK / 8 = 250 kHz, gen. int.
  TACTL |= MC1;                                  // start timer in continuous up-mode
  _EINT();                                       // enable interrupts
  
  Init8900();
  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();
    }
}

// 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)
{
  unsigned int ActRxEvent;                       // copy of cs8900's RxEvent-Register

  Write8900(ADD_PORT, PP_RxEvent);               // point to RxEvent
  ActRxEvent = Read8900(DATA_PORT);              // read, implied skip the last frame

  if (ActRxEvent & RX_OK)
  {
    if (ActRxEvent & RX_IA) ProcessEthIAFrame();
    if (ActRxEvent & RX_BROADCAST) ProcessEthBroadcastFrame();
  }

  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) | TAR; // 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 NEED a retry-timeout
          LastFrameSent = TCP_FIN_FRAME;                        // time to say goodbye...
          TCPStartRetryTimer();
          TCPStateMachine = LAST_ACK;
        }
      break;
    }
  }

  if (TransmitControl & SEND_FRAME2)
  {
    RequestSend(TxFrame2Size);

    if (Rdy4Tx())                                // NOTE: when using a very fast MCU, maybe
      SendFrame2();                              // the CS8900 isn't ready yet, include
    else {                                       // a kind of timer or counter here
      TCPStateMachine = CLOSED;
      SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
      TCPFlags = 0;                              // clear all flags, stop timers etc.
    }

    TransmitControl &= ~SEND_FRAME2;             // clear tx-flag
  }

  if (TransmitControl & SEND_FRAME1)
  {
    PrepareTCP_DATA_FRAME();                     // build frame w/ actual SEQ, ACK....
    RequestSend(TxFrame1Size);
  
    if (Rdy4Tx())                                // CS8900 ready to accept our frame?
      SendFrame1();                              // (see note above)
    else {
      TCPStateMachine = CLOSED;
      SocketStatus = SOCK_ERR_ETHERNET;          // indicate an error to user
      TCPFlags = 0;                              // clear all flags, stop timers etc.
    }

    TransmitControl &= ~SEND_FRAME1;             // clear tx-flag
  }
}

// easyWEB internal function
// handles an incoming broadcast frame

void ProcessEthBroadcastFrame(void)
{
  unsigned int TargetIP[2];

  // next two words MUST be read with High-Byte 1st (CS8900 AN181 Page 2)
  ReadHB1ST8900(RX_FRAME_PORT);                  // ignore RxStatus Word
  RecdFrameLength = ReadHB1ST8900(RX_FRAME_PORT);// get real length of frame 
    
  DummyReadFrame8900(6);                         // ignore DA (FF-FF-FF-FF-FF-FF)
  CopyFromFrame8900(&RecdFrameMAC, 6);           // store SA (for our answer)

  if (ReadFrameBE8900() == FRAME_ARP)            // get frame type, check for ARP
    if (ReadFrameBE8900() == HARDW_ETH10)        // Ethernet frame
      if (ReadFrameBE8900() == FRAME_IP)         // check protocol
        if (ReadFrameBE8900() == IP_HLEN_PLEN)   // check HLEN, PLEN
          if (ReadFrameBE8900() == OP_ARP_REQUEST)
          {
            DummyReadFrame8900(6);               // ignore sender's hardware address
            CopyFromFrame8900(&RecdFrameIP, 4);  // read sender's protocol address
            DummyReadFrame8900(6);               // ignore target's hardware address
            CopyFromFrame8900(&TargetIP, 4);     // read target's protocol address
            if (!memcmp(&MyIP, &TargetIP, 4))    // is it for us?
              PrepareARP_ANSWER();               // yes->create ARP_ANSWER frame
          }
}

// easyWEB internal function
// handles an incoming frame that passed CS8900's address filter
// (individual addressed = IA)

void ProcessEthIAFrame(void)
{
  unsigned int TargetIP[2];
  unsigned char ProtocolType;

  // next two words MUST be read with High-Byte 1st (CS8900 AN181 Page 2)
  ReadHB1ST8900(RX_FRAME_PORT);                  // ignore RxStatus Word
  RecdFrameLength = ReadHB1ST8900(RX_FRAME_PORT);// get real length of frame 
  
  DummyReadFrame8900(6);                         // ignore DA
  CopyFromFrame8900(&RecdFrameMAC, 6);           // store SA (for our answer)

  switch (ReadFrameBE8900())                     // get frame type
  {
    case FRAME_ARP :                             // check for ARP
    {
      if ((TCPFlags & (TCP_ACTIVE_OPEN | IP_ADDR_RESOLVED)) == TCP_ACTIVE_OPEN)
        if (ReadFrameBE8900() == HARDW_ETH10)         // check for the right prot. etc.
          if (ReadFrameBE8900() == FRAME_IP)
            if (ReadFrameBE8900() == IP_HLEN_PLEN)
              if (ReadFrameBE8900() == OP_ARP_ANSWER)
              {
                TCPStopTimer();                       // OK, now we've the MAC we wanted ;-)
                CopyFromFrame8900(&RemoteMAC, 6);     // extract opponents MAC
                TCPFlags |= IP_ADDR_RESOLVED;
              }
      break;
    }
    case FRAME_IP :                                        // check for IP-type
    {
      if ((ReadFrameBE8900() & 0xFF00 ) == IP_VER_IHL)     // IPv4, IHL=5 (20 Bytes Header)
      {                                                    // ignore Type Of Service
        RecdIPFrameLength = ReadFrameBE8900();             // get IP frame's length
        ReadFrameBE8900();                                 // ignore identification

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -