본문 바로가기

WIZnet Driver 설명/W5500 Socket Driver_Japan

W5500 イーサネット Source 分析 Japanese

こんにちは。皆さん

エドワードと呼ばれます。

韓国の名前はアンジンフイです。

よろしくお願いします。

以下のコードは、TCP / IPチップのW5500 iolibraryソースです。

このコードは、韓国バージョンと英語バージョン、そして日本バージョンがあります。参照してください。

WIZnet社のW5500イーサネットソースコードをより簡単に説明しました。

ご覧になって気になる部分があればjinhee.ahn@wiznet.co.krまたは

wizwiki.net/forumにお問い合わせください。

ありがとうございます。

[code language="c"]
//*****************************************************************************
//
//! \file socket.c
//! \brief SOCKET APIs Implements file.
//! \details SOCKET APIs like as Berkeley Socket APIs. 
//! \version 1.0.3
//! \date 2013/10/21
//! \par  Revision history
//!       <2014/05/01> V1.0.3. Refer to M20140501
//!         1. Implicit type casting -> Explicit type casting.
//!         2. replace 0x01 with PACK_REMAINED in recvfrom()
//!         3. Validation a destination ip in connect() & sendto(): 
//!            It occurs a fatal error on converting unint32 address if uint8* addr parameter is not aligned by 4byte address.
//!            Copy 4 byte addr value into temporary uint32 variable and then compares it.
//!       <2013/12/20> V1.0.2 Refer to M20131220
//!                    Remove Warning.
//!       <2013/11/04> V1.0.1 2nd Release. Refer to "20131104".
//!                    In sendto(), Add to clear timeout interrupt status (Sn_IR_TIMEOUT)
//!       <2013/10/21> 1st Release
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c)  2013, WIZnet Co., LTD.
//! All rights reserved.
//! 
//! Redistribution and use in source and binary forms, with or without 
//! modification, are permitted provided that the following conditions 
//! are met: 
//! 
//!     * Redistributions of source code must retain the above copyright 
//! notice, this list of conditions and the following disclaimer. 
//!     * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution. 
//!     * Neither the name of the <ORGANIZATION> nor the names of its 
//! contributors may be used to endorse or promote products derived 
//! from this software without specific prior written permission. 
//! 
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#include "socket.h"
 
#define SOCK_ANY_PORT_NUM  0xC000;
 
static uint16_t sock_any_port = SOCK_ANY_PORT_NUM;
static uint16_t sock_io_mode = 0;
static uint16_t sock_is_sending = 0;
static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = {0,0,};
static uint8_t  sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,};
 
#if _WIZCHIP_ == 5200
   static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] ={0,};
#endif
 
#define CHECK_SOCKNUM()   \
   do{                    \
      if(sn > _WIZCHIP_SOCK_NUM_) return SOCKERR_SOCKNUM;   \
   }while(0);             \
 
#define CHECK_SOCKMODE(mode)  \
   do{                     \
      if((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE;  \
   }while(0);              \
 
#define CHECK_SOCKINIT()   \
   do{                     \
      if((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \
   }while(0);              \
 
#define CHECK_SOCKDATA()   \
   do{                     \
      if(len == 0) return SOCKERR_DATALEN;   \
   }while(0);              \
 
----------------------------------------------------------------------------------------------
 
int8_t socket(uint8_t sn, uint8_t
        protocol, uint16_t port, uint8_t flag)
{
    CHECK_SOCKNUM(); // ソケット番号チェック
    switch(protocol)
    {
      case Sn_MR_TCP : // 0x01('0001')
      case Sn_MR_UDP : // 0x02('0010')
      case Sn_MR_MACRAW : // 0x04('0100')
         break;
   #if ( _WIZCHIP_ < 5200 )
      case Sn_MR_IPRAW :
      case Sn_MR_PPPoE :
         break;
   #endif
      default :
         return SOCKERR_SOCKMODE;
    }
 
    if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG; // same not to the Flag zero(0) is return Error Flag(Invalid)
#if _WIZCHIP_ == 5200
   if(flag & 0x10) return SOCKERR_SOCKFLAG;
#endif
    //フラグモードフラグ
    if(flag != 0)
    {
    switch(protocol)
    {
       case Sn_MR_TCP:
          if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK))==0) return SOCKERR_SOCKFLAG; ///< Invalid socket flag
          break;
       case Sn_MR_UDP:
          if(flag & SF_IGMP_VER2)
          {
             if((flag & SF_MULTI_ENABLE)==0) return SOCKERR_SOCKFLAG;
          }
          #if _WIZCHIP_ == 5500
              if(flag & SF_UNI_BLOCK)
              {
                 if((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG;
              }
          #endif
          break;
       default:
          break;
    }
   }
    close(sn); // ソケットを閉じる
    //モードレジスタ設定
    setSn_MR(sn, (protocol | (flag & 0xF0)));
    if(!port)
    {
       port = sock_any_port++;
       if(sock_any_port == 0xFFF0) sock_any_port = SOCK_ANY_PORT_NUM;
    }
   setSn_PORT(sn,port);
   setSn_CR(sn,Sn_CR_OPEN); // コマンドレジスタに「ソケットオ?プン」 セット
   while(getSn_CR(sn)); // ソケットオ?プンを確認
    sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn); // 0
   sock_is_sending &= ~(1<<sn); // 0
   sock_remained_size[sn] = 0; // 0
   sock_pack_info[sn] = 0; // 0
   while(getSn_SR(sn) == SOCK_CLOSED);
   return (int8_t)sn;
}
 
----------------------------------------------------------------------------------------------
 
int8_t close(uint8_t sn)
{
    CHECK_SOCKNUM();
     
    setSn_CR(sn,Sn_CR_CLOSE); // コマンド セット (Hostから W5500まで)
   /* コマンド プロセッサ 処理 待つ... */
    while( getSn_CR(sn) );
    /* ソケットのすべての割り込み初期化 */
    setSn_IR(sn, 0xFF);
    sock_is_sending &= ~(1<<sn);
    sock_remained_size[sn] = 0;
    sock_pack_info[sn] = 0;
    while(getSn_SR(sn) != SOCK_CLOSED);
    return SOCK_OK;
}
 
----------------------------------------------------------------------------------------------
 
int8_t listen(uint8_t sn)
{
    CHECK_SOCKNUM(); // ソケットナンバーチェック
   CHECK_SOCKMODE(Sn_MR_TCP); // ソケットがTCPモードであるかチェック
    CHECK_SOCKINIT(); // ソケットの作成いがいSn_SRがSOCK_INIT状態がいるかチェックし
    setSn_CR(sn,Sn_CR_LISTEN); // コマンドレジスタに「ソケット待機」セット
    while(getSn_CR(sn)); // ソケット待機確認
     // エラーフロー(Sn_SRがListen状態でなければエラー)
   while(getSn_SR(sn) != SOCK_LISTEN)
   {
      if(getSn_CR(sn) == SOCK_CLOSED)
      {
         close(sn);
         return SOCKERR_SOCKCLOSED;
      }
   }
   return SOCK_OK; // Sn_IR(0x10) -> 通常動作と完了したこと割り込み
}
 
----------------------------------------------------------------------------------------------
 
int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port)
{
   CHECK_SOCKNUM();
   CHECK_SOCKMODE(Sn_MR_TCP);
   CHECK_SOCKINIT();
    
   //M20140501 : For avoiding fatal error on memory align mismatched
   //if( *((uint32_t*)addr) == 0xFFFFFFFF || *((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
    
   // 4 Byte IPを2進数に変換してまとめてIPチェック
   {
      //IPチェック変数
      uint32_t taddr;
      //入力されたIPを計算して変数に入れてチェック
      taddr = ((uint32_t)addr[0] & 0x000000FF);
      taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
      taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
      taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
      //込められているIPアドレスが255.255.255.255 or 0.0.0.0であればエラー
      if( taddr == 0xFFFFFFFF || taddr == 0) return SOCKERR_IPINVALID;
   }
   
    if(port == 0) return SOCKERR_PORTZERO; // ポートが0の場合、エラー
    setSn_DIPR(sn,addr); // 接続したサーバのIP設定
    setSn_DPORT(sn,port); // 接続サーバーPORT設定
   #if _WIZCHIP_ == 5200   // for W5200 ARP errata (これはW5200用)
      setSUBR(0);
   #endif
    setSn_CR(sn,Sn_CR_CONNECT); // コマンドレジスタに「ソケット接続」セット
   while(getSn_CR(sn)); // ソケット接続確認
   // ブロッキング及びノンブロッキング設定 
   if(sock_io_mode & (1<<sn)) return SOCK_BUSY;
   // エラーフロー
   while(getSn_SR(sn) != SOCK_ESTABLISHED)
   {   
        if (getSn_IR(sn) & Sn_IR_TIMEOUT)
        {
            setSn_IR(sn, Sn_IR_TIMEOUT);
         #if _WIZCHIP_ == 5200   // for W5200 ARP errata 
            setSUBR((uint8_t*)"\x00\x00\x00\x00");
         #endif
         return SOCKERR_TIMEOUT;
        }
    }
   #if _WIZCHIP_ == 5200   // for W5200 ARP errata 
      setSUBR((uint8_t*)"\x00\x00\x00\x00");
   #endif
    
   return SOCK_OK;
}
 
int8_t disconnect(uint8_t sn)
{
   CHECK_SOCKNUM();
   CHECK_SOCKMODE(Sn_MR_TCP);
    setSn_CR(sn,Sn_CR_DISCON);
    /* コマンドの処理を待っている。... */
    while(getSn_CR(sn));
    sock_is_sending &= ~(1<<sn);
   if(sock_io_mode & (1<<sn)) return SOCK_BUSY;
    while(getSn_SR(sn) != SOCK_CLOSED)
    {
       if(getSn_IR(sn) & Sn_IR_TIMEOUT)
       {
          close(sn);
          return SOCKERR_TIMEOUT;
       }
    }
    return SOCK_OK;
}
 
----------------------------------------------------------------------------------------------

/*TCPがデータからの重要な部分*/
int32_t send(uint8_t sn, uint8_t * buf, uint16_t len)
{
   uint8_t tmp=0;
   uint16_t freesize=0;
    
   CHECK_SOCKNUM();
   CHECK_SOCKMODE(Sn_MR_TCP);
   CHECK_SOCKDATA(); // コマンドの処理を待っている。
   tmp = getSn_SR(sn); // ソケットの状態を変数に保存
   // 保存した変数の2つの状態と比較
   if(tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT) return SOCKERR_SOCKSTATUS;
     
   // 直前データあり/なしをチェック
   if( sock_is_sending & (1<<sn) ) // sock_is_sending フラグ「1」であれば
   {
      tmp = getSn_IR(sn);
      if(tmp & Sn_IR_SENDOK) // データ転送が終了したら、SEND_OKフラグを「1」に設定(0x10)
      {
         setSn_IR(sn, Sn_IR_SENDOK); // 割り込みレジスタの初期化
         #if _WIZCHIP_ == 5200
            if(getSn_TX_RD(sn) != sock_next_rd[sn])
            {
               setSn_CR(sn,Sn_CR_SEND);
               while(getSn_CR(sn));
               return SOCKERR_BUSY;
            }
         #endif
         sock_is_sending &= ~(1<<sn); // sock_is_sending フラグ「0」設定
      }
      else if(tmp & Sn_IR_TIMEOUT) // 0x08
      {
         close(sn);
         return SOCKERR_TIMEOUT;
      }
      // SENDOK、TIMEOUT両方ない場合SOCK_BUSYになる。
      else return SOCK_BUSY; // まだdata処理が取れない (0x00)
   }
    
   // W5500は、初期設定Default 2Kbyte、MAX 16Kbyteすることができる。
   // Sn_TX_FSR(Free Size Register)は、空いているスペースを示す。
   freesize = getSn_TxMAX(sn); // TX_buffer_size 読む
   // ユーザーが送信したDataがTx Bufferよりも大きい場合Tx Buffer分だけ送信
   if (len > freesize) len = freesize;
     // 残っている容量をチェック
   while(1)
   {
      freesize = getSn_TX_FSR(sn); // 残りのsizeチェック
      // エラーフロー
      tmp = getSn_SR(sn);
      if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT)) // compare to socket n state
      {
         close(sn);
         return SOCKERR_SOCKSTATUS;
      }
      // もう一度エラーチェック(安全性の要求)
      if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY; // nonblocking
      // データがTx Bufferに入ってくると構文の脱出
      if(len <= freesize) break;
   }
   // SPI転送
   wiz_send_data(sn, buf, len);
    
   #if _WIZCHIP_ == 5200
      sock_next_rd[sn] = getSn_TX_RD(sn) + len;
   #endif
    
   setSn_CR(sn,Sn_CR_SEND); // 更新された長さだけDataを送信
   /* コマンドの処理を待っている。... */
   while(getSn_CR(sn)); // Sn_CRが「0」に設定されていることを確認(正常動作していることを確認)
   sock_is_sending |= (1 << sn); // sock_is_sending フラグ「1」に設定
   return len;
}
 
----------------------------------------------------------------------------------------------
 
int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)
{
   uint8_t  tmp = 0;
   uint16_t recvsize = 0;
   CHECK_SOCKNUM();
   CHECK_SOCKMODE(Sn_MR_TCP);
   CHECK_SOCKDATA();
    
   // W5500は、初期設定Default 2Kbyte、MAX 16Kbyteすることができる。
   // RX_buffer_sizeレジスタ読む
   recvsize = getSn_RxMAX(sn);
   // Ethernetで受けたDataが初期設定されたRX_buffer_sizeよりも大きい場合、RX_buffer_size分だけ読む。
   if(recvsize < len) len = recvsize;
   //Data あり/なしを判別
   while(1)
   {
      // RX_BUFのSize読む
      recvsize = getSn_RX_RSR(sn); // 'Receive Size Register'
      // エラーフロー
      tmp = getSn_SR(sn);
      if (tmp != SOCK_ESTABLISHED)
      {
         if(tmp == SOCK_CLOSE_WAIT)
         {
            if(recvsize != 0) break; // まだ残っているDataがある場合、再処理
            else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn))
            {
               close(sn);
               return SOCKERR_SOCKSTATUS;
            }
         }
         else // close socket
         {
            close(sn);
            return SOCKERR_SOCKSTATUS;
         }
      }
      // もう一度チェック
      if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
      if(recvsize != 0) break; // RSRにRX bufferの長さを読めば、無限ループの脱出
   };
   if(recvsize < len) len = recvsize;
   wiz_recv_data(sn, buf, len); // SPI 転送
   //元々あったRX_RDポインタの位置から読み取ったデータの長さだけ更新されたポインタの増加を適用
   setSn_CR(sn,Sn_CR_RECV);
   while(getSn_CR(sn)); // Sn_CRが「0」に設定されていることを確認(正常動作していることを確認)
   return len;
    
}
 
----------------------------------------------------------------------------------------------
 
int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
{
   uint8_t tmp = 0;
   uint16_t freesize = 0;
   CHECK_SOCKNUM();
   switch(getSn_MR(sn) & 0x0F) // モードレジスタチェック
   {
      case Sn_MR_UDP: // P[3:0] -> '0010'
      case Sn_MR_MACRAW: // P[3:0] -> '0100'
         break;
      default:
         return SOCKERR_SOCKMODE;
   }
   CHECK_SOCKDATA();
   //M20140501 : For avoiding fatal error on memory align mismatched
   //if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
   // 4 Byte IPを2進数に変換してまとめてIPチェック
   {
      uint32_t taddr;
      taddr = ((uint32_t)addr[0]) & 0x000000FF;
      taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
      taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
      taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
   }
   // IPが0.0.0.0チェック(UDP(Broadcast)は、255.255.255.255チェックしない)
   // 理由は、ブロードキャストの説明を確認
   if(*((uint32_t*)taddr) == 0) return SOCKERR_IPINVALID;  
   if(port == 0)               return SOCKERR_PORTZERO;
   //エラーフロー
   tmp = getSn_SR(sn);
   if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS;
       
   setSn_DIPR(sn,addr); // パケットを送信したところのIP設定
   setSn_DPORT(sn,port); // パケットを送信するところPORT設定
   //TX_buffer_size 読む
   freesize = getSn_TxMAX(sn); 
   if (len > freesize) len = freesize;
   //비어있는 Tx_buffer サイズチェック
   while(1)
   {
      freesize = getSn_TX_FSR(sn);
      // エラーチェック
      if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
      if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;
      // HostからDataが入ってくると構文の脱出
      if(len <= freesize) break;
   };
    wiz_send_data(sn, buf, len); // SPI転送
 
   #if _WIZCHIP_ == 5200   // for W5200 ARP errata 
      setSUBR(0);
   #endif
    
  // コマンドセットが入ってくるどきにTX_WRが増えた分FSRスペースが減る。
  // つまり、TX_ERとTX RDとの間の差で自動計算される
    setSn_CR(sn,Sn_CR_SEND); 
    /* コマンドの処理を待っている... */
    while(getSn_CR(sn)); // コマンド正常動作確認
   #if _WIZCHIP_ == 5200   // for W5200 ARP errata 
      setSUBR((uint8_t*)"\x00\x00\x00\x00");
   #endif
    
   // Data転送判別チェック
   while(1)
   {
      tmp = getSn_IR(sn);
      // UDPであるため、相手からACKこない
      // だからData転送が完了したらSn_IR_SENDOK自動Set
      // そして減ったFSRのスペースがRDが更新され増える。
      if(tmp & Sn_IR_SENDOK) 
      {
         setSn_IR(sn, Sn_IR_SENDOK); // Sn IRクリア
         break;
      }
      //M:20131104
      //else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT;
      else if(tmp & Sn_IR_TIMEOUT)
      {
         setSn_IR(sn, Sn_IR_TIMEOUT);
         return SOCKERR_TIMEOUT;
      }
      ////////////
   }
    return len;
}
 
----------------------------------------------------------------------------------------------
 
int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)
{
   uint8_t  mr;
 
   uint8_t  head[8];
    uint16_t pack_len=0;
 
   CHECK_SOCKNUM();
   //CHECK_SOCKMODE(Sn_MR_UDP);
   switch((mr=getSn_MR(sn)) & 0x0F)
   {
      case Sn_MR_UDP: // '0010', 0x02
      case Sn_MR_MACRAW: // '0100', 0x04
         break;
   #if ( _WIZCHIP_ < 5200 )         
      case Sn_MR_IPRAW:
      case Sn_MR_PPPoE:
         break;
   #endif
      default:
         return SOCKERR_SOCKMODE;
   }
   CHECK_SOCKDATA();
    
   if(sock_remained_size[sn] == 0)
   {
      // Data あり/なしを判別
      while(1)
      {
         // RX buffer size 読む
         pack_len = getSn_RX_RSR(sn);
         // エラーチェック
         if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
         if( (sock_io_mode & (1<<sn)) && (pack_len == 0) ) return SOCK_BUSY;
         // Data 読めば構文脱出
         if(pack_len != 0) break;
      };
   }
   sock_pack_info[sn] = PACK_COMPLETED; // Data 読み取り完了
    
    switch (mr & 0x07)
    {
       case Sn_MR_UDP :
          if(sock_remained_size[sn] == 0)
          {
            wiz_recv_data(sn, head, 8); // UDPで受けたパケットのうち8 Byteのみ読む
            setSn_CR(sn,Sn_CR_RECV);
            while(getSn_CR(sn));
            // read peer's IP address, port number & packet length
            // IP アドレス
            addr[0] = head[0];
            addr[1] = head[1];
            addr[2] = head[2];
            addr[3] = head[3];
            // ポート番号
            *port = head[4];
            *port = (*port << 8) + head[5];
            // 送信されたDataパケットの長さ
            sock_remained_size[sn] = head[6];
            sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[7];
            // UDPでパケット全体(Data)を受けてきた後、定められたHeader(8byte)を別々に持って来る。
            // この状態の時info Flagは下の変数として宣言
            sock_pack_info[sn] = PACK_FIRST; // 0x80
       }
      // UDPで受けたパケットの長さが、ユーザーが設定したバッファの長さよりも大きい場合Rx bufferサイズ分だけ受ける
            if(len < sock_remained_size[sn]) pack_len = len;
            // そうでない場合、受けたパケットの長さだけData受ける
            else pack_len = sock_remained_size[sn];
            //
            // Need to packet length check (default 1472)
            //
            //pack_lenが、実際のdata
        wiz_recv_data(sn, buf, pack_len); // data copy.
            break;
             
       case Sn_MR_MACRAW :
          if(sock_remained_size[sn] == 0)
          {
            wiz_recv_data(sn, head, 2);
            setSn_CR(sn,Sn_CR_RECV);
            while(getSn_CR(sn));
            // read peer's IP address, port number & packet length
                sock_remained_size[sn] = head[0];
            sock_remained_size[sn] = (sock_remained_size[sn] <<8) + head[1];
            if(sock_remained_size[sn] > 1514) 
            {
               close(sn);
               return SOCKFATAL_PACKLEN;
            }
            sock_pack_info[sn] = PACK_FIRST;
       }
            if(len < sock_remained_size[sn]) pack_len = len;
            else pack_len = sock_remained_size[sn];
            wiz_recv_data(sn,buf,pack_len);
           break;
   #if ( _WIZCHIP_ < 5200 )
        case Sn_MR_IPRAW:
           if(sock_remained_size[sn] == 0)
           {
            wiz_recv_data(sn, head, 6);
            setSn_CR(sn,Sn_CR_RECV);
            while(getSn_CR(sn));
            addr[0] = head[0];
            addr[1] = head[1];
            addr[2] = head[2];
            addr[3] = head[3];
            sock_remained_size[sn] = head[4];
            sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5];
            sock_pack_info[sn] = PACK_FIRST;
         }
            //
            // Need to packet length check
            //
            if(len < sock_remained_size[sn]) pack_len = len;
            else pack_len = sock_remained_size[sn];
        wiz_recv_data(sn, buf, pack_len); // data copy.
            break;
   #endif
      default:
         // パケットを受けてい(RX bufferポインタの増加)
         wiz_recv_ignore(sn, pack_len); // data copy.
         // パケット全体をremained変数に入れて、再びループ回したときに読む
         sock_remained_size[sn] = pack_len;
         break;
   }
    setSn_CR(sn,Sn_CR_RECV);
    /* wait to process the command... */
    while(getSn_CR(sn)) ;
    // もし受けたパケットが、ユーザーが設定したバッファサイズよりも大きい場合、その差の数値分抜く。
    // そしてsock_remained_sizeに残ったパケットサイズを保存する。
    sock_remained_size[sn] -= pack_len;
    //M20140501 : replace 0x01 with PACK_REMAINED
    //if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01;
    // パケットがまだW5500バッファに残っている場合info変数をREMAINEDに設定
    // もう一度繰り返し、残りのパケットデータもHostに送る。
    if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= PACK_REMAINED; //0x01
   //
    return pack_len; // 実際のdataパケットのみをHostに送る。
}
 
----------------------------------------------------------------------------------------------
 
// SPI ADDRESS + BSB + R/W , OP(VDM, FDM) 割り当て
void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
   uint16_t ptr = 0;
   uint32_t addrsel = 0;
   if(len == 0)  return;
   //Hostは送信するDataを保存開始Addressであるこの値を読む。
   ptr = getSn_TX_WR(sn); // Tx bufferの書き込みポインタ
   //M20140501 : implict type casting -> explict type casting
   //addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
   //ADDRESS[15:8] + BSB[7:3] 割り当て
   //0b 0000:0000:0000:0XXX
   addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3);
   //Hostは、この値を開始AddressしてdataをSocket n TX Bufferに保存する。
   WIZCHIP_WRITE_BUF(addrsel,wizdata, len);
    
   //元々あったTX_WRポインタの位置からバッファに保存されたdataのサイズだけ合わせてTX_WRの位置の値を更新する。
   ptr += len;
   setSn_TX_WR(sn,ptr); // ポインタ更新
}
 
----------------------------------------------------------------------------------------------
 
// SPI ADDRESS + BSB + R/W , OP(VDM, FDM) 割り当て
void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
   uint16_t ptr = 0;
   uint32_t addrsel = 0;
    
   if(len == 0) return;
   //Hostは送信するDataを保存開始Addressであるこの値を読む。
   ptr = getSn_RX_RD(sn); // RX bufferの読み取りポインタ
   //M20140501 : implict type casting -> explict type casting
   //addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
   //ADDRESS[15:8] + BSB[7:3] 割り当て
   //0b 0000:0000:0000:0XXX
   addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
   //Hostは、この開始Addressからdataを読む。
   WIZCHIP_READ_BUF(addrsel, wizdata, len);
    
   //元々あったRX_RDポインタの位置から読み取ったデータの長さだけポインタ増加
   ptr += len;
   setSn_RX_RD(sn,ptr); // 増加した後、ポインタ更新


}
 
 
void wiz_recv_ignore(uint8_t sn, uint16_t len)
{
   uint16_t ptr = 0;
   ptr = getSn_RX_RD(sn);
   ptr += len;
   setSn_RX_RD(sn,ptr);
}
 
 
----------------------------------------------------------------------------------------------
 
 
void     WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
{
   uint16_t i = 0;
   uint16_t j = 0;
   WIZCHIP_CRITICAL_ENTER();
   WIZCHIP.CS._select(); // CSがLowのとき - > SPI転送を開始する
 
#if( (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_)) // SPIインタフェースモードチェック
 
   #if  ( _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_ ) // VDMモードチェック
      // R/W, OP(VDM,FDM) 割り当て
      // XXXX:XXXX:XXXX:X000
      AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_); // 書き込みモード(MOSI)
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); // Address上位1byte転送
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >>  8); // Address下位1byte転送
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >>  0); // コントロール 位相 1byte 転送(BSB + R/W + OP)
      // ユーザーが設定したバッファにユーザーが入力した長さだけバッファへの書き込み
      for(i = 0; i < len; i++,j) 
         WIZCHIP.IF.SPI._write_byte(pBuf[i]);
 
 
----------------------------------------------------------------------------------------------
 
 
void     WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
{
   uint16_t i = 0;
   uint16_t j = 0;
   WIZCHIP_CRITICAL_ENTER();
   WIZCHIP.CS._select(); // CSがLowのとき - > SPI転送を開始する
 
#if( (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SPI_)) // SPIインタフェースモードチェック
 
   #if  ( _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_ ) // VDMモードチェック
      // R/W, OP(VDM,FDM) 할당
      // XXXX:XXXX:XXXX:X000
      AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_); // 0 read mode(MISO)
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16); // Address上位1byte転送
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >>  8); // Address下位1byte転送
      WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >>  0); // コントロール 位相 1byte 転送(BSB + R/W + OP)
      // ユーザーが設定したバッファにEthernetから受けた長さだけバッファから読む
      for(i = 0; i < len; i++,j)
        pBuf[i] = WIZCHIP.IF.SPI._read_byte(); // 1byte read

[/code]

お疲れ様でした。