#include <stdio.h>
 
#include <string.h>
 
#include "socket.h"
 
#include "w5300.h"
 
 
 
#define SWAP16(A)               ((((A << 8 ) & 0xFF00)) | ((A >> 8)& 0x00FF))
 
 
 
uint16   iinchip_source_port;
 
uint8    check_sendok_flag[MAX_SOCK_NUM];
 
 
 
uint8 socket(SOCKET s, uint8 protocol, uint16 port, uint16 flag)
 
{
 
        IINCHIP_WRITE(Sn_MR0(s), (uint8)((protocol | flag) >> 8));
 
        IINCHIP_WRITE(Sn_MR1(s), (uint8)((protocol | flag) & 0xff));
 
        if (port != 0) 
 
        {
 
                IINCHIP_WRITE(Sn_PORTR0(s),(uint8)((port & 0xff00) >> 8));
 
                IINCHIP_WRITE(Sn_PORTR1(s),(uint8)(port & 0x00ff));
 
        }
 
        else 
 
        {
 
                iinchip_source_port++;     // if don't set the source port, set local_port number.
 
                IINCHIP_WRITE(Sn_PORTR0(s),(uint8)((iinchip_source_port & 0xff00) >> 8));
 
                IINCHIP_WRITE((Sn_PORTR1(s)),(uint8)(iinchip_source_port & 0x00ff));
 
        }
 
        setSn_CR(s, Sn_CR_OPEN);      // open s-th SOCKET 
 
 
 
        check_sendok_flag[s] = 1;     // initialize the sendok flag.
 
 
 
        #ifdef __DEF_IINCHIP_DBG__
 
                printf("%d : Sn_MR=0x%04x,Sn_PORTR=0x%04x(%04d),Sn_SSR=%04x\r\n",s
,IINCHIP_READ
(Sn_MR
(s
)),(uint16)((IINCHIP_READ
(Sn_PORTR0
(s
)) << 8) + IINCHIP_READ
(Sn_PORTR1
(s
))),(uint16)((IINCHIP_READ
(Sn_PORTR0
(s
)) << 8) + IINCHIP_READ
(Sn_PORTR1
(s
))),getSn_SSR
(s
));  
        #endif
 
        return 1;   
 
}
 
 
 
void     close(SOCKET s)
 
{
 
        // M_08082008 : It is fixed the problem that Sn_SSR cannot be changed a undefined value to the defined value.
 
        //              Refer to Errata of W5300
 
        //Check if the transmit data is remained or not.
 
        if( ((getSn_MR(s)& 0x0F) == Sn_MR_TCP) && (getSn_TX_FSR(s) != getIINCHIP_TxMAX(s)) ) 
 
        { 
 
                uint16 loop_cnt =0;
 
                while(getSn_TX_FSR(s) != getIINCHIP_TxMAX(s))
 
                {
 
                        if(loop_cnt++ > 10)
 
                        {
 
                                uint8 destip[4];
 
                                // M_11252008 : modify dest ip address
 
                                //getSIPR(destip);
 
                                destip[0] = 0;destip[1] = 0;destip[2] = 0;destip[3] = 1;
 
                                socket(s,Sn_MR_UDP,0x3000,0);
 
                                sendto(s,(uint8*)"x",1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1).
 
                                break; // M_11252008 : added break statement
 
                        }
 
                wait_10ms(10);
 
                }
 
        };
 
        setSn_IR(s ,0x00FF);          // Clear the remained interrupt bits.
 
        setSn_CR(s ,Sn_CR_CLOSE);     // Close s-th SOCKET     
 
}
 
 
 
 
 
uint8    connect(SOCKET s, uint8 * addr, uint16 port)
 
{
 
        if
 
        (
 
                ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
 
                ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
 
                (port == 0x00) 
 
        )
 
        {
 
                #ifdef __DEF_IINCHIP_DBG__
 
                        printf("%d : Fail[invalid ip,port]\r\n",s
);  
                #endif
 
                return 0;
 
        }
 
 
 
        // set destination IP 
 
        IINCHIP_WRITE(Sn_DIPR0(s),addr[0]);
 
        IINCHIP_WRITE(Sn_DIPR1(s),addr[1]);
 
        IINCHIP_WRITE(Sn_DIPR2(s),addr[2]);
 
        IINCHIP_WRITE(Sn_DIPR3(s),addr[3]);
 
        // set destination port number
 
        IINCHIP_WRITE(Sn_DPORTR0(s),(((uint8)(port >> 8))));
 
        IINCHIP_WRITE(Sn_DPORTR1(s),(((uint8)port & 0xff)));
 
        // Connect
 
        ApplySubnet();
 
        setSn_CR(s,Sn_CR_CONNECT);
 
        
 
        
 
        while( IINCHIP_READ(Sn_SSR(s)) != SOCK_SYNSENT )
 
        {
 
                if(IINCHIP_READ(Sn_SSR(s)) == SOCK_ESTABLISHED)
 
                {
 
                        break;
 
                }
 
                if(getSn_IR(s) & Sn_IR_TIMEOUT)
 
                {
 
                        setSn_IR(s,(Sn_IR_TIMEOUT));
 
                        break;
 
                }
 
        }
 
        
 
                
 
        ClearSubnet();
 
 
 
        return 1;   
 
}
 
 
 
void     disconnect(SOCKET s)
 
{
 
        setSn_CR(s,Sn_CR_DISCON);     // Disconnect
 
}
 
 
 
uint8    listen(SOCKET s)
 
{
 
        if (getSn_SSR(s) != SOCK_INIT)
 
        {
 
                #ifdef __DEF_IINCHIP_DBG__
 
                        printf("%d : SOCKET is not created!\r\n",s
);  
                #endif
 
                return 0;
 
        }
 
        setSn_CR(s,Sn_CR_LISTEN);     // listen
 
 
 
        return 1;
 
}  
 
 
 
uint32   send(SOCKET s, uint8 * buf, uint32 len)
 
{
 
        uint8 status=0;
 
        uint32 ret=0;
 
        uint32 freesize=0;
 
        #ifdef __DEF_IINCHIP_DBG__
 
                uint32 loopcnt = 0;
 
 
 
        #endif
 
 
 
        ret = len;
 
        if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
 
 
 
   
 
 
 
        /*
 
        * \note if you want to use non blocking function, <b>"do{}while(freesize < ret)"</b> code block 
 
        * can be replaced with the below code. \n
 
        * \code 
 
        *       while((freesize = getSn_TX_FSR(s))==0); 
 
        *       ret = freesize;
 
        * \endcode
 
        */
 
        // -----------------------
 
        // NOTE : CODE BLOCK START
 
        do                                   
 
        {
 
                freesize = getSn_TX_FSR(s);
 
                status = getSn_SSR(s);
 
                #ifdef __DEF_IINCHIP_DBG__
 
                        printf("%d : freesize=%ld\r\n",s
,freesize
);  
                if(loopcnt++ > 0x0010000)
 
                { 
 
                        printf("%d : freesize=%ld,status=%04x\r\n",s
,freesize
,status
);  
                        printf("%d:Send Size=%08lx(%d)\r\n",s
,ret
,ret
);  
                        printf("MR=%04x\r\n",*((vuint16
*)MR
));  
                        loopcnt = 0;
 
                }
 
                #endif
 
                if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT)) return 0;
 
        } while (freesize < ret);
 
        // NOTE : CODE BLOCK END
 
        // ---------------------
 
   
 
        if(ret & 0x01) wiz_write_buf(s, buf, (ret+1));
 
        else wiz_write_buf(s,buf,ret);                   // copy data
 
 
 
        #ifdef __DEF_IINCHIP_DBG__
 
                loopcnt=0;
 
        #endif   
 
 
 
        if(!check_sendok_flag[s])                 // if first send, skip.
 
        {
 
                while (!(getSn_IR(s) & Sn_IR_SENDOK))  // wait previous SEND command completion.
 
                {
 
                #ifdef __DEF_IINCHIP_DBG__
 
 
 
                if(loopcnt++ > 0x010000)
 
                {
 
                        printf("%d:Sn_SSR(%02x)\r\n",s
,status
);  
                        printf("%d:Send Size=%08lx(%d)\r\n",s
,ret
,ret
);  
                        printf("MR=%02x%02x\r\n",*((vuint8
*)MR0
),*((vuint8
*)MR1
));  
                        loopcnt = 0;
 
                }
 
                #endif
 
                if (getSn_SSR(s) == SOCK_CLOSED)    // check timeout or abnormal closed.
 
                {
 
                        #ifdef __DEF_IINCHIP_DBG__
 
                                printf("%d : Send Fail. SOCK_CLOSED.\r\n",s
);  
                        #endif
 
                        
 
                        return 0;
 
                }
 
                }
 
                setSn_IR(s, Sn_IR_SENDOK);             // clear Sn_IR_SENDOK      
 
        }
 
        else check_sendok_flag[s] = 0;
 
 
 
        // send
 
        setSn_TX_WRSR(s,ret);   
 
        setSn_CR(s,Sn_CR_SEND);
 
   
 
        return ret;
 
}
 
 
 
uint32   recv(SOCKET s, uint8 * buf, uint32 len)
 
{
 
        uint16 pack_size=0;
 
        vint16 mr = getMR();
 
 
 
        #ifdef __DEF_IINCHIP_DBG__
 
        #endif
 
 
 
        if(IINCHIP_READ(Sn_MR0(s)) & Sn_MR_ALIGN) 
 
        {
 
                wiz_read_buf(s, buf, len);
 
                setSn_CR(s,Sn_CR_RECV);
 
                return len;
 
        }
 
 
 
        wiz_read_buf(s,(uint8*)&pack_size,2);        // extract the PACKET-INFO(DATA packet length)
 
 
 
        #ifdef LITTLE_ENDIAN
 
                if(mr & MR_FS) pack_size = pack_size;
 
                else pack_size = SWAP16(pack_size);
 
        #else
 
                if(mr & MR_FS) pack_size = SWAP16(pack_size);
 
                else pack_size = pack_size;
 
        #endif
 
 
 
        #ifdef __DEF_IINCHIP_DBG__   
 
                printf("%d:pack_size=%d\r\n",s
,pack_size
);  
        #endif
 
 
 
        len = pack_size;
 
        if(pack_size & 0x01) len += 1;
 
 
 
        wiz_read_buf(s, buf, len);     // copy data   
 
 
 
        setSn_CR(s,Sn_CR_RECV);                      // recv
 
 
 
   /*
 
   * \warning  send a packet for updating window size. This code block must be only used when W5300 do only receiving data.
 
   */
 
   // ------------------------
 
   // WARNING CODE BLOCK START 
 
   
 
   // M_15052008 : Replace Sn_CR_SEND with Sn_CR_SEND_KEEP.
 
   //if(!(getSn_IR(s) & Sn_IR_SENDOK))
 
   //{
 
   //   setSn_TX_WRSR(s,0);                    // size = 0
 
   //   setSn_CR(s,Sn_CR_SEND);                // send
 
   //   while(!(getSn_IR(s) & Sn_IR_SENDOK));  // wait SEND command completion
 
   //   setSn_IR(s,Sn_IR_SENDOK);              // clear Sn_IR_SENDOK bit
 
   //}
 
   
 
   // M_04072008 : Replace Sn_CR_SEND_KEEP with Sn_CR_SEND.
 
   //if(getSn_RX_RSR(s) == 0)                     // send the window-update packet when the window size is full
 
   //{
 
   //   uint8 keep_time = 0;
 
   //   if((keep_time=getSn_KPALVTR(s)) != 0x00) setSn_KPALVTR(s,0x00); // disables the auto-keep-alive-process
 
   //   setSn_CR(s,Sn_CR_SEND_KEEP);              // send a keep-alive packet by command
 
   //   setSn_KPALVTR(s,keep_time);               // restore the previous keep-alive-timer value
 
   //}
 
 
 
 
 
//   if(getSn_RX_RSR(s) == 0)                     // check if the window size is full or not
 
//   { /* Sn_RX_RSR can be compared with another value instead of ??0??,
 
//      according to the host performance of receiving data */
 
//      setSn_TX_WRSR(s,1);                       // size : 1 byte dummy size
 
//      IINCHIP_WRITE(Sn_TX_FIFOR0(s),0x00);     // write dummy data into tx memory
 
//      IINCHIP_WRITE(Sn_TX_FIFOR1(s),0x00);
 
//      setSn_CR(s,Sn_CR_SEND);                   // send                         
 
//      while(!(getSn_IR(s) & Sn_IR_SENDOK));     // wait SEND command completion 
 
//      setSn_IR(s,Sn_IR_SENDOK);                 // clear Sn_IR_SENDOK bit       
 
//   }                                                                         
 
 
 
 
 
   // WARNING CODE BLOCK END
 
   // ----------------------
 
   
 
   return (uint32)pack_size;
 
}
 
 
 
uint32   sendto(SOCKET s, uint8 * buf, uint32 len, uint8 * addr, uint16 port)
 
{
 
        uint8 status=0;
 
        uint8 isr=0;
 
        uint32 ret=0;
 
 
 
        #ifdef __DEF_IINCHIP_DBG__
 
                printf("%d : sendto():%d.%d.%d.%d(%d), len=%d\r\n",s
, addr
[0], addr
[1], addr
[2], addr
[3] , port
, len
);  
        #endif
 
 
 
        if
 
        (
 
          ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
 
          ((port == 0x00)) ||(len == 0)
 
        ) 
 
        {
 
                #ifdef __DEF_IINCHIP_DBG__
 
                         printf("%d : Fail[%d.%d.%d.%d, %.d, %d]\r\n",s
, addr
[0], addr
[1], addr
[2], addr
[3] , port
, len
);  
                #endif
 
                return 0;
 
        }
 
   
 
   
 
        if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
 
        else ret = len;
 
 
 
        // set destination IP address
 
        IINCHIP_WRITE(Sn_DIPR0(s),addr[0]);
 
        IINCHIP_WRITE(Sn_DIPR1(s),addr[1]);
 
        IINCHIP_WRITE(Sn_DIPR2(s),addr[2]);
 
        IINCHIP_WRITE(Sn_DIPR3(s),addr[3]);
 
        // set destination port number
 
        IINCHIP_WRITE(Sn_DPORTR0(s),((uint8)(port >> 8)));
 
        IINCHIP_WRITE(Sn_DPORTR1(s),((uint8)(port & 0xff)));
 
 
 
        wiz_write_buf(s, buf, ret+(ret & 0x01));                               // copy data
 
        // send
 
        setSn_TX_WRSR(s,ret);
 
        ApplySubnet();
 
        setSn_CR(s, Sn_CR_SEND);
 
 
 
        while (!((isr = getSn_IR(s)) & Sn_IR_SENDOK))            // wait SEND command completion
 
        {
 
                status = getSn_SSR(s);                                // warning ---------------------------------------
 
                if ((status == SOCK_CLOSED) || (isr & Sn_IR_TIMEOUT)) // Sn_IR_TIMEOUT causes the decrement of Sn_TX_FSR
 
                {                                                     // -----------------------------------------------
 
                        #ifdef __DEF_IINCHIP_DBG__
 
                                printf("%d: send fail.status=0x%02x,isr=%02x\r\n",s
,status
,isr
);  
                        #endif
 
                        setSn_IR(s,Sn_IR_TIMEOUT);
 
                        return 0;
 
                }
 
        }
 
 
 
        setSn_IR(s, Sn_IR_SENDOK); // Clear Sn_IR_SENDOK
 
        ClearSubnet();
 
   
 
        #ifdef __DEF_IINCHIP_DBG__           
 
                printf("%d : send()end\r\n",s
);  
        #endif       
 
 
 
        return ret;   
 
}
 
 
 
uint32   recvfrom(SOCKET s, uint8 * buf, uint32 len, uint8 * addr, uint16  *port)
 
{
 
        uint8 head[8];
 
        uint16 data_len=0;
 
        uint16 crc[2];
 
        vint16 mr = getMR();
 
 
 
        #ifdef __DEF_IINCHIP_DBG__
 
        #endif
 
 
 
        if ( len > 0 )
 
        {
 
 
 
                switch (IINCHIP_READ(Sn_MR1(s)) & 0x07)                 // check the mode of s-th SOCKET
 
                {                                                       // -----------------------------
 
                case Sn_MR_UDP :                                        // UDP mode 
 
 
 
                        wiz_read_buf(s, head, 8);                       // extract the PACKET-INFO
 
                        // read peer's IP address, port number.
 
 
 
                        if(mr & MR_FS)
 
                        {
 
                                addr[0] = head[1];                      // destination IP address
 
                                addr[1] = head[0];
 
                                addr[2] = head[3];
 
                                addr[3] = head[2];
 
                        }
 
                        else
 
                        {
 
                                addr[0] = head[0];
 
                                addr[1] = head[1];
 
                                addr[2] = head[2];
 
                                addr[3] = head[3];
 
                        }
 
                        #ifdef LITTLE_ENDIAN
 
                                if(mr & MR_FS)
 
                                {
 
                                        *port = head[5];                                // destination port number
 
                                        *port = (*port << 8) + head[4];
 
                                        data_len = (uint16)head[7];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[6];
 
                                }
 
                                else
 
                                {
 
                                        *port = head[4];                                // destination port number
 
                                        *port = (*port << 8) + head[5];
 
                                        data_len = (uint16)head[6];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[7];
 
                                }
 
                        #else
 
                                if(mr & MR_FS)
 
                                {
 
                                        *port = head[4];
 
                                        *port = (*port << 8) + head[5];
 
                                        data_len = (uint16)head[6];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[7];
 
                                }
 
                                else
 
                                {
 
                                        *port = head[5];
 
                                        *port = (*port << 8) + head[4];
 
                                        data_len = (uint16)head[7];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[6];
 
                                }
 
                        #endif
 
 
 
                        #ifdef __DEF_IINCHIP_DBG__
 
                                printf("UDP msg arrived:%d(0x%04x)\r\n",data_len
,data_len
);  
                                printf("source Port : %d\r\n", *port
);  
                                printf("source IP : %d.%d.%d.%d\r\n", addr
[0], addr
[1], addr
[2], addr
[3]);  
                        #endif
 
 
 
                        wiz_read_buf(s, buf, data_len + (data_len & 0x01) );        // data copy.
 
                        break;
 
 
 
                                                                                        // -----------------------
 
                case Sn_MR_IPRAW :                                                      // IPRAW mode
 
                        wiz_read_buf(s, (uint8*)head, 6);                               // extract the PACKET-INFO 
 
                        if((*(vint8*)MR0) & MR_FS)
 
                        {
 
                                addr[0] = head[1];                                      // destination IP address
 
                                addr[1] = head[0];
 
                                addr[2] = head[3];
 
                                addr[3] = head[2];
 
                        }
 
                        else
 
                        {
 
                                addr[0] = head[0];                                      // destination IP address
 
                                addr[1] = head[1];
 
                                addr[2] = head[2];
 
                                addr[3] = head[3];
 
                        }
 
 
 
                        #ifdef LITTLE_ENDIAN
 
                                if((*(vint8*)MR0) & MR_FS)
 
                                {
 
                                        data_len = (uint16)head[5];                      // DATA packet length
 
                                        data_len = (data_len << 8) + head[4];
 
                                }
 
                                else
 
                                {
 
                                        data_len = (uint16)head[4];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[5];
 
                                }
 
                        #else
 
                                if((*(vint8*)MR0) & MR_FS)
 
                                {
 
                                        data_len = (uint16)head[4];
 
                                        data_len = (data_len << 8) + head[5];
 
                                }
 
                                else
 
                                {
 
                                        data_len = (uint16)head[5];
 
                                        data_len = (data_len << 8) + head[4];
 
                                }
 
                        #endif
 
 
 
                        #ifndef __DEF_IINCHIP_DBG__
 
                                printf("IP RAW msg arrived\r\n");  
                                printf("source IP : %d.%d.%d.%d\r\n", addr
[0], addr
[1], addr
[2], addr
[3]);  
                        #endif
 
 
 
                        wiz_read_buf(s, buf, data_len+(data_len & 0x01));               // data copy.
 
                        break;                                 
 
                
 
                                                                                        // -----------------------
 
                case Sn_MR_MACRAW :                                                     // MACRAW mode
 
                        wiz_read_buf(s,(uint8*)head,2);                                 // extract the PACKET-INFO
 
                        #ifdef LITTLE_ENDIAN
 
                                if((*(vint8*)MR0) & MR_FS)
 
                                {
 
                                        data_len = (uint16)head[1];                     // DATA packet length
 
                                        data_len = (data_len << 8) + head[0];
 
                                }
 
                                else
 
                                {
 
                                        data_len = (uint16)head[0];
 
                                        data_len = (data_len << 8) + head[1];
 
                                }
 
                        #else
 
                                if((*(vint8*)MR0) & MR_FS)
 
                                {
 
                                        data_len = (uint16)head[0];
 
                                        data_len = (data_len << 8) + head[1];
 
                                }
 
                                else
 
                                {
 
                                        data_len = (uint16)head[1];
 
                                        data_len = (data_len << 8) + head[0];
 
                                }
 
                        #endif
 
 
 
                        wiz_read_buf(s, buf, data_len + (data_len & 0x01));        // data copy.
 
                        wiz_read_buf(s,(uint8*)crc, 4);        // extract CRC data and ignore it.
 
 
 
                        break;
 
                default :
 
                        break;
 
                }
 
                setSn_CR(s,Sn_CR_RECV);                      // recv
 
        }
 
        #ifdef __DEF_IINCHIP_DBG__
 
                printf("recvfrom() end ..\r\n");  
        #endif
 
   
 
        return data_len;   
 
}