W5500EVB Pings Other Device

“Ping” is an important function in Networking. It is a function to see if the connectivity is alright, which is an essential tool for debugging. It is under Internet Control Management Protocol (ICMP), no wonder why it is important for debugging. 

For “Ping”, or to “ping” a device, it technically means sending a message to a desired device/place and getting an echo(message with exactly the same data being sent), making sure the data is transferable and the connection is good to use. If the “Ping” process can not be completed, you may need to check the connectivity to see what actually happened in the route. Here we are not going deep into how to analyse the connectivity.

Other than most of the protocol, it neither bases on TCP or UDP, but ICMP, we may go further about the packet format below.



Before burning the bin file into your EVB:

      1. Connect W5500 EVB to the router/NAT that you are using, or any other device that allows you to connect to the internet
      2. Manually change the Network configuration:
          • Go to the definition of function “set_default()” (Should be inside device.c), make sure the subnet mask, local IP address, gateway and DNS are set according to the internet setting you are using with your router/NAT
      3. Rebuild the sample code and burn it into W5500EVB
      4. Change your PC’s IP address to a static IP if you are not using router


Code Explanation

The sample code are basically divided into four states: Initialized, Established, To Be Closed, Closed. 

int main(void)
{


As usual, W5500EVB does the initialization about the network setting and communication setting and stuff. It then goes into do_ping(). Please notice that there is no while loop in main(), which means the do_ping() only does once and W5500EVB does nothing afterwards.

  systick_init(72);
  USART1_Config();
  i2c_CfgGpio();
  gpio_for_w5500_config();
  reset_w5500();
  set_w5500_mac();
  set_w5500_ip();
	
  socket_buf_init(txsize, rxsize);
	
  printf("\r\n------------Start Ping Test!-----------------------\r\n\r\n");
	
  do_ping();
}
/******************





 These are all the necessary
 initialization





********************/






do_ping() is a function which leads you to the ping_count() function, the main function of this example.

Like when you ping other devices using your computer(command-line on windows), a total of four “ping” would be done consequently. It depends on what parameter you input, 4 “ping”s would be done by default if you do not make any changes.

void do_ping(void)
{	 
  ping_count(SOCK_PING,4,remote_ip);
}



ping_count()

It first goes into a for-loop (loop 4 times by default). It goes to the switch statement.

void ping_count(uint8 s, uint16 pCount, uint8 *addr)
{
  uint16 rlen, cnt,i;
  cnt = 0;

  for(i=0; i<pCount+1;i++)
  {		
    if(i!=0)
    {
      /* Output count number */
      printf( "No.%d  ",i);
    }
    switch(getSn_SR(s))
      {


Initially no socket is opened, therefore it goes into case “SOCK_CLOSED”and open a socket in “IP RAW” mode. As mentioned above, the socket is opened in “IP RAW” mode rather than UDP or TCP mode since “Ping” is under ICMP.

Make sure the socket is opened in “IP RAW” mode. Do nothing until then.

case SOCK_CLOSED:
  close(s);			
  IINCHIP_WRITE(Sn_PROTO(s), IPPROTO_ICMP);
  if(socket(s,Sn_MR_IPRAW,3000,0)!=0)
  { }
  while(getSn_SR(s)!=SOCK_IPRAW);
		
break;  
/***************
 Make sure the socket is closed initially

 Open the socket with "IP RAW" mode

 Make sure the socket is opened in “IP 
 RAW” mode. Do nothing until then.
****************/


When the socket is opened, it starts sending a Ping request with the function ping_request(), which will be discussed below.

Then it enters a while loop and waits until there is any data going in the RX buffer. If there is data received, it goes into the ping_reply() function to handle the replied message, else no data is detected for a certain amount of time, it sends a message to serial, showing “time out”, and breaks the for loop.

case SOCK_IPRAW:
  ping_request(s, addr);
  req++
  while(1)
  {
    if ( (rlen = getSn_RX_RSR(s) ) > 0)
    {
      ping_reply(s, addr, rlen);
      rep++;
      if (ping_reply_received)  break;			
    }
    if ( (cnt > 1000) )
    {
      printf("Request Time out\r\n\r\n") ;
      cnt = 0;
      break;
    }
    else
    { 
      cnt++;
      delay_ms(1000);
    }
  }
  break;

  default:
  break;
/****************
 Sending a Ping request

 Enters a while loop
 Waits until there is any data going in
 the RX buffer

 Handle the replied message packet



 No data is detected for a certain 
 amount of time

 printf message, showing timeout 











****************/
    if(req>=pCount)
    {	
      printf("Ping Request = %d, Ping Reply = %d, Lost = %d\r\n",req,rep,req-rep);	  
    }
  }
}



ping_request()

This is a function for sending ping request packet to the target device

uint8 ping_request(uint8 s, uint8 *addr)
{


The struct “PingRequest” is used to store the data and construct it into a packet with ping packet format, which would be discussed below.

  uint16 i;
  ping_reply_received = 0;
  PingRequest.Type = PING_REQUEST;
  PingRequest.Code = CODE_ZERO;
  PingRequest.ID = htons(RandomID++);
  PingRequest.SeqNum =htons(RandomSeqNum++);

  for(i = 0 ; i < BUF_LEN; i++)
  {
    PingRequest.Data[i] = (i) % 8;
  }


htons() changes the order of the data to fit the data sequence for data transmission

checksum() helps calculate the checksum of the data packet. Please be reminded that checksum itself, in this example “PingRequest.CheckSum”, should be zero since the calculation of checksum excludes the value of checksum. Otherwise if checksum has value, the function checksum() would include the value and give a wrong checksum value, hence fail to get any reply from the target device.

  PingRequest.CheckSum = 0;


// ************The function for calculating checksum, explanation above************

  PingRequest.CheckSum = htons(checksum((uint8*)&PingRequest,sizeof(PingRequest))); 

// ********************************************************************************



//  Then internal-check to see if the message is sent, and send a message to serial to indicate the result.
  if(sendto(s,(uint8 *)&PingRequest,sizeof(PingRequest),addr,3000)==0)	
  {
    printf("Fail to send ping-reply packet\r\n");
  }
  else
  {
    printf("Ping:%d.%d.%d.%d\r\n",(addr[0]),  (addr[1]),  (addr[2]),  (addr[3]));
  }
  return 0;
} 



ping_reply()

This is a function to check if the received packet is valid.

uint8 ping_reply(uint8 s, uint8 *addr,  uint16 rlen)
{
  uint16 tmp_checksum;
  uint16 len;
  uint16 i;
  uint8 data_buf[136];
 
  uint16 port = 3000;
  PINGMSGR PingReply;
  len = recvfrom(s, data_buf,rlen,addr,&port);


First it checks if the packet is a reply or not. And the struct “PingReply” is used to store the data received, classify and divide it into its corresponding meaning.

//
if(data_buf[0] == PING_REPLY)
{	
  PingReply.Type       = data_buf[0];
  PingReply.Code       = data_buf[1];
  PingReply.CheckSum   = (data_buf[3]<<8) + data_buf[2];
  PingReply.ID         = (data_buf[5]<<8) + data_buf[4];
  PingReply.SeqNum     = (data_buf[7]<<8) + data_buf[6];
			
  for(i=0; i<len-8 ; i++)
  {
    PingReply.Data[i] = data_buf[8+i];
  }
  tmp_checksum = ~checksum(data_buf,len);
  if(tmp_checksum != 0xffff)
  printf("tmp_checksum = %x\r\n",tmp_checksum);
 
/****************
First it checks if the 
packet is a reply or not. 

Classify and divide the
received packet







Check if the checksum of 
the packet is correct

****************/

  else
  {
    printf("Reply from %3d.%3d.%3d.%3d ID=%x Byte=%d\r\n\r\n",(addr[0]),  (addr[1]),  (addr[2]),  (addr[3]),htons(PingReply.ID),(rlen+6));			
    ping_reply_received =1;    // a counter indicating the success of the ping process.
  }
}



Ping Packet Format

The related format of the packet would be as follows:

Type indicates the type of packet you receive. We have a couple of types under ICMP. For ping packets, you will probably see type 0(), type 8(), and type 3 () if unfortunately. 

Code indicates more details about the packet. It should always be 0 for type 0 and type 8.

ICMP Header Checksum is a 16-bit one’s complement of the one’s complement sum of the ICMP message, starting with the ICMP Type field. In this example, it is the packet format you saw above, excluding some information such as sender’s IP address and receiver’s IP address. The following video on YouTube gives a good explanation of how to calculate checksum for internet data transfer: https://youtu.be/EmUuFRMJbss

Identifier is a 4 digit 16 bits hex number for better identification. It can be any number within 16 bits.

Sequence shows the sequence of how much ping packet has already been sent. It can be any hex number within 16 bits.

Data is the content of the message. However in case of pinging, the data is not necessary at all that it can be any value or even null, which would not affect the pinging at all.



Remarks