관리 메뉴

Edward's Labs

WIZnet W5500 Socket Driver 분석 본문

WIZnet Driver 설명/W5500 Socket Driver_Kor

WIZnet W5500 Socket Driver 분석

Eddy 2016.05.31 09:42

안녕하세요.

Edward입니다.

채팅프로그램에 이어서 Wiznet 사에서 배포하여 사용되는 Ethernet Driver 분석을 공유하고자 합니다.

이번은 한글버전이고 다음은 영어버전 그리고 일어 버전을 추가로 업로드 하려고 합니다.

궁금하신부분이 있는 분들은 댓글 남겨주시거나 혹은 http://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
	//플래그 모드 Flow
	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(); // Socket number Check
   CHECK_SOCKMODE(Sn_MR_TCP); // 소켓이 TCP 모드인지 체크
	CHECK_SOCKINIT(); // 소켓생성 이후 Sn_SR가 SOCK_INIT상태가 되었는지 체크
	setSn_CR(sn,Sn_CR_LISTEN); // 커맨드레지스터에 '소켓 대기' 명령
	while(getSn_CR(sn)); // 소켓 대기인지 확인
	 // 에러 Flow (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;
   
   // 나누어져 있는 IP를 묶어서 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 
      setSUBR(0);
   #endif
	setSn_CR(sn,Sn_CR_CONNECT); // 커맨드레지스터에 '소켓 접속' 명령
   while(getSn_CR(sn)); // 소켓 접속 확인
   // Blocking & Nonblocking 설정 
   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);
	/* wait to process the command... */
	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;
}

----------------------------------------------------------------------------------------------

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;
      }
      // SEND_OK, TIME_OUT 둘 다 아닐경우 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 체크
      // 에러 Flow
      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를 전송
   /* wait to process the command... */
   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'
      // 에러 Flow
      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) // Mode Register 체크
   {
      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;
   // 나누어져 있는 IP를 묶어서 IP 체크 (Connect 참고)
   {
      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); // Packet을 보낼 곳의 IP 설정
   setSn_DPORT(sn,port); // Packet을 보낼 곳의 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_WR과 TX_RD간의 차이로 자동 계산됨
	setSn_CR(sn,Sn_CR_SEND); 
	/* wait to process the command... */
	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); // clear 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로 받은 패킷 중 8Byte만 읽음
   			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_); // 1 write mode(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); // Control phase 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); // Control phase 1byte 전송(BSB + R/W + OP)
      // 사용자가 설정한 버퍼에 Ethernet으로 부터 받은 길이 만큼 버퍼에서 읽음
      for(i = 0; i < len; i++,j)
        pBuf[i] = WIZCHIP.IF.SPI._read_byte(); // 1byte read

[/code]


'WIZnet Driver 설명 > W5500 Socket Driver_Kor' 카테고리의 다른 글

WIZnet W5500 Socket Driver 분석  (0) 2016.05.31
0 Comments
댓글쓰기 폼