#include "stdio.h" #include "bsp.h" #include "socket.h" #include "w5500.h" #include "types.h" #include "utils.h" #define W5500_POLL_WAIT static uint32_t local_port; //extern uint16_t sent_ptr; #if 1 /** @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5200 done it. @return 0: ongoing; 1 for sucess; 0xff: error. */ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) { uint8_t ret; static uint32_t sockState=0; if ( ((protocol&0x0F) == Sn_MR_TCP) || ((protocol&0x0F) == Sn_MR_UDP) || ((protocol&0x0F) == Sn_MR_IPRAW) || ((protocol&0x0F) == Sn_MR_MACRAW) || ((protocol&0x0F) == Sn_MR_PPPOE) ) { switch(sockState) { case 0: close(s);//Force to close socket!!! IINCHIP_WRITE(Sn_MR(s) ,protocol | flag); if (port != 0) { IINCHIP_WRITE( Sn_PORT0(s) ,(uint8_t)((port & 0xff00) >> 8)); IINCHIP_WRITE( Sn_PORT1(s) ,(uint8_t)(port & 0x00ff)); } else { local_port++; // if don't set the source port, set local_port number. IINCHIP_WRITE(Sn_PORT0(s) ,(uint8_t)((local_port & 0xff00) >> 8)); IINCHIP_WRITE(Sn_PORT1(s) ,(uint8_t)(local_port & 0x00ff)); } IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_OPEN); // run sockinit Sn_CR sockState=1; case 1: /* wait to process the command... */ if( IINCHIP_READ(Sn_CR(s)) ) { return 0; } sockState=2; case 2: /* ------- */ if(IINCHIP_READ(Sn_SR(s)) != SOCK_INIT ) { return 0; } default: sockState = 0; break; } ret = 1; } else { ret = 0xff; } return ret; } /** @brief This function close the socket and parameter is "s" which represent the socket number @return 0: ongoing; 1 for sucess; 0xff: error. */ uint8_t close(SOCKET s) { static uint32_t closeState=0; switch(closeState) { case 0: IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CLOSE); closeState=1; case 1: /* wait to process the command... */ if( IINCHIP_READ(Sn_CR(s) ) ) { return 0; } default: /* all clear */ IINCHIP_WRITE( Sn_IR(s) , 0xFF); closeState=0; break; } return 1; } /** @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer. @return 0: ongoing; 1 for sucess; 0xff: error. */ uint8_t listen(SOCKET s) { static uint32_t listenState=0; uint8_t ret; // LISTEN command send to Sn_CR, If succeed, set it to 1, otherwise clear it to 0 ret = IINCHIP_READ( Sn_SR(s) ); if (ret == SOCK_INIT) // if init, set it { switch(listenState) { case 0: IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_LISTEN); //MCU sets W5500 into listen mode listenState=1; case 1: if( IINCHIP_READ(Sn_CR(s) ) ) // Configure finished, Sn_CR is cleared automatically { return 0; } default: listenState=0; break; } ret = 1; //ret=1 means: LISTEN command is excuted successfully } else { if(ret == SOCK_LISTEN) { ret = 1; } else { ret = 0xff; // fails } listenState=0; } return ret; } /** @brief This function established the connection for the channel in Active (client) mode. This function waits for the untill the connection is established. @return 1 for success else 0. */ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) { static uint32_t connState=0; uint8_t ret; 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 == 0x0000) ) { return 0xff; } switch( connState) { case 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]); IINCHIP_WRITE( Sn_DPORT0(s), (uint8_t)((port & 0xff00) >> 8)); IINCHIP_WRITE( Sn_DPORT1(s), (uint8_t)(port & 0x00ff)); IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CONNECT); connState=1; case 1: /* wait for completion */ if(IINCHIP_READ(Sn_CR(s))) { return 0; } connState=2; case 2: ret = IINCHIP_READ(Sn_SR(s)); if ( ret != SOCK_SYNSENT )// { if(ret == SOCK_ESTABLISHED) { connState=0; return 1;//success } else if(SOCK_INIT == ret) { connState=0;//reset state return 0; } else if(SOCK_INIT > ret) { connState=0;//reset state setSn_CR(s,Sn_CR_CLOSE); return 0xff; } ret=getSn_IR(s); if( ret & Sn_IR_TIMEOUT) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } if(ret & Sn_IR_DISCON) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_DISCON)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } return 0; } /*if(ret == SOCK_ESTABLISHED) {//connected connState=0; return 1;//success } else if(SOCK_INIT == ret) {//state error connState=0;//reset state return 0; } else if(SOCK_INIT > ret) {//state error connState=0;//reset state setSn_CR(s,Sn_CR_CLOSE); return 0xff; } //else if(SOCK_FIN_WAIT<=ret) //{ // ; //} else if(SOCK_SYNSENT==ret || SOCK_SYNRECV==ret ) {//connecting //return 0; } ret=getSn_IR(s); if( ret & Sn_IR_TIMEOUT) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } if(ret & Sn_IR_DISCON) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_DISCON)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } return 0;*/ /*if ( IINCHIP_READ(Sn_SR(s)) != SOCK_SYNSENT )//?? { ret = IINCHIP_READ(Sn_SR(s)); if(ret == SOCK_ESTABLISHED) { connState=0; return 1;//success } else if(SOCK_CLOSED == ret) { connState=0; return 0xff;//failed } else if(SOCK_INIT == ret) { connState=0;//reset state return 0; } else if(SOCK_INIT >= ret) { connState=0;//reset state setSn_CR(s,Sn_CR_CLOSE); return 0xff; } ret=getSn_IR(s); if( ret & Sn_IR_TIMEOUT) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } if(ret & Sn_IR_DISCON) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_DISCON)); // clear TIMEOUT Interrupt connState=0; return 0xff;//failed } return 0; }*/ default: connState=0; break; } ret=1; return ret; } /** @brief This function used for disconnect the socket and parameter is "s" which represent the socket number @return 1 for success else 0. */ uint8_t disconnect(SOCKET s) { static uint32_t discState=0; switch(discState) { case 0: IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_DISCON); discState=1; case 1: /* wait to process the command... */ if( IINCHIP_READ(Sn_CR(s) ) ) { return 0; } default: discState=1; break; } return 1; } #else /** @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5200 done it. @return 1 for sucess else 0. */ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) { uint8_t ret; if ( ((protocol&0x0F) == Sn_MR_TCP) || ((protocol&0x0F) == Sn_MR_UDP) || ((protocol&0x0F) == Sn_MR_IPRAW) || ((protocol&0x0F) == Sn_MR_MACRAW) || ((protocol&0x0F) == Sn_MR_PPPOE) ) { close(s); IINCHIP_WRITE(Sn_MR(s) ,protocol | flag); if (port != 0) { IINCHIP_WRITE( Sn_PORT0(s) ,(uint8_t)((port & 0xff00) >> 8)); IINCHIP_WRITE( Sn_PORT1(s) ,(uint8_t)(port & 0x00ff)); } else { local_port++; // if don't set the source port, set local_port number. IINCHIP_WRITE(Sn_PORT0(s) ,(uint8_t)((local_port & 0xff00) >> 8)); IINCHIP_WRITE(Sn_PORT1(s) ,(uint8_t)(local_port & 0x00ff)); } IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_OPEN); // run sockinit Sn_CR /* wait to process the command... */ while( IINCHIP_READ(Sn_CR(s)) ) { ; } /* ------- */ while(IINCHIP_READ(Sn_SR(s)) != SOCK_INIT ) { ; } ret = 1; } else { ret = 0; } return ret; } /** @brief This function close the socket and parameter is "s" which represent the socket number */ void close(SOCKET s) { IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CLOSE); /* wait to process the command... */ while( IINCHIP_READ(Sn_CR(s) ) ) { ; } /* ------- */ /* all clear */ IINCHIP_WRITE( Sn_IR(s) , 0xFF); } /** @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer. @return 1 for success else 0. */ uint8_t listen(SOCKET s) { uint8_t ret; if (IINCHIP_READ( Sn_SR(s) ) == SOCK_INIT) // Sn_SR is init { IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_LISTEN); // set W5500 to start listen while( IINCHIP_READ(Sn_CR(s) ) ) // after in listen mode, Sn_CR is cleared automatically { ; } ret = 1; // in LISTEN mode, ret=1 } else { ret = 0; // fails, ret=0 } return ret; } /** @brief This function established the connection for the channel in Active (client) mode. This function waits for the untill the connection is established. @return 1 for success else 0. */ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) { uint8_t ret; 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 == 0x0000) ) { ret = 0; } else { // 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]); IINCHIP_WRITE( Sn_DPORT0(s), (uint8_t)((port & 0xff00) >> 8)); IINCHIP_WRITE( Sn_DPORT1(s), (uint8_t)(port & 0x00ff)); IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CONNECT); /* wait for completion */ while(IINCHIP_READ(Sn_CR(s))) { ; } while ( IINCHIP_READ(Sn_SR(s)) != SOCK_SYNSENT ) { ret = IINCHIP_READ(Sn_SR(s)); if(ret == SOCK_ESTABLISHED) { ret = 1; break; } else if(SOCK_CLOSED == ret) { ret = 0; break; } ret=getSn_IR(s); if( ret & Sn_IR_TIMEOUT) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT)); // clear TIMEOUT Interrupt ret = 0; break; } if(ret & Sn_IR_DISCON) { IINCHIP_WRITE(Sn_IR(s), (Sn_IR_DISCON)); // clear TIMEOUT Interrupt ret = 0; break; } } } return ret; } /** @brief This function used for disconnect the socket and parameter is "s" which represent the socket number @return 1 for success else 0. */ void disconnect(SOCKET s) { IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_DISCON); /* wait to process the command... */ while( IINCHIP_READ(Sn_CR(s) ) ) { ; } /* ------- */ } #endif /** @brief This function used to send the data in TCP mode @return 1 for success else 0. */ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) { uint8_t status=0; uint16_t ret=0; uint16_t freesize=0; if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); else ret = len; do { freesize = getSn_TX_FSR(s); status = IINCHIP_READ(Sn_SR(s)); if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT)) { ret = 0; break; } } while (freesize < ret); send_data_processing(s, (uint8_t *)buf, ret); IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND); while( IINCHIP_READ(Sn_CR(s) ) ); #ifndef W5500_INT_MODE while ( (IINCHIP_READ(Sn_IR(s) ) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK ) { status = IINCHIP_READ(Sn_SR(s)); if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT) ) { printf("SEND_OK Problem!!\r\n"); close(s); return 0; } } IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK); IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK); #endif return ret; } /** @brief This function is an application I/F function which is used to receive the data in TCP mode. It continues to wait for data as much as the application wants to receive. @return received data size for success else -1. */ uint16_t recv(SOCKET s, uint8_t * buf, uint16_t len) { uint16_t ret=0; if ( len > 0 ) { recv_data_processing(s, buf, len); // data recv progress: get recv data from socket recv buffer and store to mcu buffer pointed by *buf IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_RECV); // MCU set Sn_CR to RECV while( IINCHIP_READ(Sn_CR(s) )); // After in recv state, Sn_CR is cleared automatically ret = len; // get the length to ret } return ret; } /** @brief This function is an application I/F function which is used to send the data for other then TCP mode. Unlike TCP transmission, The peer's destination address and the port is needed. @return This function return send data size for success else -1. */ uint8_t Server_MAC[6]={0}; #define Sn_DHAR0(ch) (0x000608 + (ch<<5)) #define Sn_DHAR1(ch) (0x000708 + (ch<<5)) #define Sn_DHAR2(ch) (0x000808 + (ch<<5)) #define Sn_DHAR3(ch) (0x000908 + (ch<<5)) #define Sn_DHAR4(ch) (0x000A08 + (ch<<5)) #define Sn_DHAR5(ch) (0x000B08 + (ch<<5)) uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port) { uint8_t status; uint16_t ret=0; if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size. else ret = len; if( ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || ((port == 0x00)) )//||(ret == 0) ) { /* added return value */ ret = 0; } else { 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]); IINCHIP_WRITE( Sn_DPORT0(s),(uint8_t)((port & 0xff00) >> 8)); IINCHIP_WRITE( Sn_DPORT1(s),(uint8_t)(port & 0x00ff)); // copy data send_data_processing(s, (uint8_t *)buf, ret); IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND); //IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND_MAC); /* wait to process the command... */ /*while( IINCHIP_READ( Sn_CR(s) ) ) ;*/ do { status = IINCHIP_READ( Sn_CR(s)); }while(status); /* ------- */ /*while( (IINCHIP_READ( Sn_IR(s) ) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK ) { if (IINCHIP_READ( Sn_IR(s) ) & Sn_IR_TIMEOUT) { // clear interrupt: SEND_OK & TIMEOUT IINCHIP_WRITE( Sn_IR(s) , (Sn_IR_SEND_OK | Sn_IR_TIMEOUT)); return 0; } }*/ do { status = IINCHIP_READ( Sn_IR(s)); if ( status & Sn_IR_TIMEOUT) {// clear interrupt: SEND_OK & TIMEOUT IINCHIP_WRITE( Sn_IR(s) , (Sn_IR_SEND_OK | Sn_IR_TIMEOUT)); return 0; } } while( (status & Sn_IR_SEND_OK) != Sn_IR_SEND_OK ); IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK); status++; // Server_MAC[0] = IINCHIP_READ(Sn_DHAR0(s)); // Server_MAC[1] = IINCHIP_READ(Sn_DHAR1(s)); // Server_MAC[2] = IINCHIP_READ(Sn_DHAR2(s)); // Server_MAC[3] = IINCHIP_READ(Sn_DHAR3(s)); // Server_MAC[4] = IINCHIP_READ(Sn_DHAR4(s)); // Server_MAC[5] = IINCHIP_READ(Sn_DHAR5(s)); } return ret; } /** @brief This function is an application I/F function which is used to receive the data in other then TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well. @return This function return received data size for success else -1. */ uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port) { uint8_t head[8]; uint16_t data_len=0; uint16_t ptr=0; uint32_t addrbsb =0; if ( len > 0 ) { ptr = IINCHIP_READ(Sn_RX_RD0(s) ); ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_RX_RD1(s)); addrbsb = (uint32_t)(ptr<<8) + (s<<5) + 0x18; switch (IINCHIP_READ(Sn_MR(s) ) & 0x07) { case Sn_MR_UDP : wiz_read_buf(addrbsb, head, 0x08); ptr += 8; // read peer's IP address, port number. 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_len = head[6]; data_len = (data_len << 8) + head[7]; addrbsb = (uint32_t)(ptr<<8) + (s<<5) + 0x18; wiz_read_buf(addrbsb, buf, data_len); ptr += data_len; IINCHIP_WRITE( Sn_RX_RD0(s), (uint8_t)((ptr & 0xff00) >> 8)); IINCHIP_WRITE( Sn_RX_RD1(s), (uint8_t)(ptr & 0x00ff)); break; case Sn_MR_IPRAW : wiz_read_buf(addrbsb, head, 0x06); ptr += 6; addr[0] = head[0]; addr[1] = head[1]; addr[2] = head[2]; addr[3] = head[3]; data_len = head[4]; data_len = (data_len << 8) + head[5]; addrbsb = (uint32_t)(ptr<<8) + (s<<5) + 0x18; wiz_read_buf(addrbsb, buf, data_len); ptr += data_len; IINCHIP_WRITE( Sn_RX_RD0(s), (uint8_t)((ptr & 0xff00) >> 8)); IINCHIP_WRITE( Sn_RX_RD1(s), (uint8_t)(ptr & 0x00ff)); break; case Sn_MR_MACRAW : wiz_read_buf(addrbsb, head, 0x02); ptr+=2; data_len = head[0]; data_len = (data_len<<8) + head[1] - 2; if(data_len > 1514) { printf("data_len over 1514\r\n"); while(1); } addrbsb = (uint32_t)(ptr<<8) + (s<<5) + 0x18; wiz_read_buf(addrbsb, buf, data_len); ptr += data_len; IINCHIP_WRITE( Sn_RX_RD0(s), (uint8_t)((ptr & 0xff00) >> 8)); IINCHIP_WRITE( Sn_RX_RD1(s), (uint8_t)(ptr & 0x00ff)); break; default : break; } IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_RECV); /* wait to process the command... */ while( IINCHIP_READ( Sn_CR(s)) ) ; /* ------- */ } return data_len; } #ifdef __MACRAW__ void macraw_open(void) { uint8_t sock_num; uint16_t dummyPort = 0; uint8_t mFlag = 0; sock_num = 0; close(sock_num); // Close the 0-th socket socket(sock_num, Sn_MR_MACRAW, dummyPort,mFlag); // OPen the 0-th socket with MACRAW mode } uint16_t macraw_send( const uint8_t * buf, uint16_t len ) { uint16_t ret=0; uint8_t sock_num; sock_num =0; if (len > getIINCHIP_TxMAX(sock_num)) ret = getIINCHIP_TxMAX(sock_num); // check size not to exceed MAX size. else ret = len; send_data_processing(sock_num, (uint8_t *)buf, len); //W5500 SEND COMMAND IINCHIP_WRITE(Sn_CR(sock_num),Sn_CR_SEND); while( IINCHIP_READ(Sn_CR(sock_num)) ); while ( (IINCHIP_READ(Sn_IR(sock_num)) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK ); IINCHIP_WRITE(Sn_IR(sock_num), Sn_IR_SEND_OK); return ret; } uint16_t macraw_recv( uint8_t * buf, uint16_t len ) { uint8_t sock_num; uint16_t data_len=0; uint16_t dummyPort = 0; uint16_t ptr = 0; uint8_t mFlag = 0; sock_num = 0; if ( len > 0 ) { data_len = 0; ptr = IINCHIP_READ(Sn_RX_RD0(sock_num)); ptr = (uint16_t)((ptr & 0x00ff) << 8) + IINCHIP_READ( Sn_RX_RD1(sock_num) ); //-- read_data(s, (uint8_t *)ptr, data, len); // read data data_len = IINCHIP_READ_RXBUF(0, ptr); ptr++; data_len = ((data_len<<8) + IINCHIP_READ_RXBUF(0, ptr)) - 2; ptr++; if(data_len > 1514) { printf("data_len over 1514\r\n"); printf("\r\nptr: %X, data_len: %X", ptr, data_len); //while(1); /** recommand : close and open **/ close(sock_num); // Close the 0-th socket socket(sock_num, Sn_MR_MACRAW, dummyPort,mFlag); // OPen the 0-th socket with MACRAW mode return 0; } IINCHIP_READ_RXBUF_BURST(sock_num, ptr, data_len, (uint8_t*)(buf)); ptr += data_len; IINCHIP_WRITE(Sn_RX_RD0(sock_num),(uint8_t)((ptr & 0xff00) >> 8)); IINCHIP_WRITE(Sn_RX_RD1(sock_num),(uint8_t)(ptr & 0x00ff)); IINCHIP_WRITE(Sn_CR(sock_num), Sn_CR_RECV); while( IINCHIP_READ(Sn_CR(sock_num)) ) ; } return data_len; } #endif