ioLibrary 100% 활용하기 (4)


앞서 살펴 본 ioLibrary의 가장 큰 특징은 다음과 같다.

  • 모든 함수의 Success & Fail 처리 : SOCKET ERROR 시 상황 코드
  • Blocked & Non-Blocked I/O function
  • Datagram Data의 Flexible 처리

각 특징들이 어떻게 활용되는지 하나씩 알아보자


Datagram Data의 Flexible 처리

UDP와 같은 Connection-less Datagram 통신은 1:N 통신이 가능하여 WIZnet chip들은 Data Packet외에 IP, Port number와 같은 추가 정보를 Data packet 앞에 추가된다. 따라서 수신한 Data 처리를 Packet단위로 하지 못할 경우 Packet 정보를 제대로 분석할 수 없어 통신에 에러가 발생하게 된다.

ioLibrary에서는 Packet에 대한 정보를 ioLibrary가 내부적으로 관리하여 Packet 처리 오류를 해결하였다.
ioLibrary의 Datagram Flexible 처리는 하나의 Packet을 저장할 메모리가 부족한 시스템에서 아주 유용하게 사용될 수 있다. 즉 하나의 Packet을 원하는 크기대로 나누어 수신하고 분석함으로써 Memory usage를 최소화할 수 있다.
물론, Code는 복잡도가 높아지기 때문에 Code 크기는 증가된다는 단점이 있다.

W5300에서의 TCP Data의 Flexible 처리

W5300에서 Sn_TX_FIFOR/Sn_RX_FIFOR Register는 16bit Access를 기본으로 하므로, 데이타크기가 Even number가 아닌 경우 UDP와 같이 Data 길이에 대한 정보가 추가된다. 이전 API에서는 UDP와 마찬가지로 Packet 단위로 처리해야되며 또한 반드시 FIFO register를 16bit 단위로 처리해야하는 부담이 있었다.

ioLibray에서는 이 모든 문제를 해결하여, Pakcet 크기의 Odd, Even Number에 상관없이 원하는 크기대로 Data를 처리할 수 있다.

How to Usage Example

uint8_t    gDATABUF[TX_RX_MAX_BUF_SIZE];
uint16_t test_size[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
uint16_t test_idx1 = 0;


int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port)
{
       int32_t  ret;
       uint16_t size, sentsize;
       static uint8_t  destip[4];
    static uint16_t destport;
    switch(getSn_SR(sn))
    {
          case SOCK_UDP :
             if((size = getSn_RX_RSR(sn)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur.
            {
                if(size > TX_RX_MAX_BUF_SIZE) size = TX_RX_MAX_BUF_SIZE;
                ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
                //ret = recvfrom(sn,buf,test_size[test_idx1 & 0x0F],destip,(uint16_t*)&destport);
                if(ret <= 0)   // check SOCKERR_BUSY & SOCKERR_XXX. For showing the occurrence of SOCKERR_BUSY.
                {
                    printf("%d: recvfrom error. %ld\r\n",sn,ret);
                    return ret;
                }
                printf("RX_RSR=%u, RECVFROM %d = ", size, ret);
                printf("%d.%d.%d.%d ",destip[0],destip[1],destip[2],destip[3]);
                printf(" (%u)\r\n", destport);
                size = (uint16_t) ret;
                sentsize = 0;
                while(sentsize != size)
                {
                       ret = sendto(sn,buf+sentsize,size-sentsize,destip,destport);
                       if(ret < 0)
                       {
                          printf("%d: sendto error. %ld\r\n",sn,ret);
                          return ret;
                       }
                       sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
                }
                test_idx1++;
             }
             break;
          case SOCK_CLOSED:
            printf("%d:LBUStart\r\n",sn);
             if((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
                    return ret;
             printf("%d:Opened\r\n",sn);
             test_idx1 = 0;
             break;
          default :
             break;
       }
       return 1;
}

void main(void)
{
    int32_t ret = 0;
    //
    // Initialize system & ioLibrary
    //
    while(1)
    {
        if((ret = loopback_udp(0, gDATABUF,ip, 3000)) < 0)
        {
            printf("ERROR : ErrCode = %d\r\n", ret);
            while(1);
        }
    }
}

recvfrom()에 전달되어지는 ip와 port는 전역변수나 static 변수를 사용해야 한다. 이는 packet이 완전히 처리될 때까지 Peer의 정보를 유지하기 위함이다.

Tip

  • int8_t getsockopt(uint8_t sn, sockopt_type sotype, void arg);
    : sotype에 따라 현 Socket의 Optional 정보를 구할 수 있다. 성공시 결과는
    arg 값으로 확인가능하다.
    • sotype
      • SO_REMAINSIZE : 현 Packet의 남은 크기를 알려준다.
      • SO_PACKINFO : 현 Packet에 대한 정보 (PACK_FIRST, PACK_REMAINED, PACK_COMPLETED)를 알려준다.

마치며

총 4편으로 구성 ioLibrary 100% 활용하기 를 마치며, 끝까지 읽어 주신 분들에게 우선 감사드리며, 작은 도움이나마 되길 바란다. 앞으로 W5XXX 시리즈 뿐만 아니라, ioLibrary가 지속적으로 개선 발전해 나가길 바란다.

블로그 이미지

MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

,