EthernetICMP

This sample program uses the ICMP module to ping a remote host. The first example program requires you to enter a numeric IP address. In the second code example, the DNS module is used to resolve a hostname (for example, www.microchip.com) before pinging. Here's what you need to do.

  • Plug a network cable into your board and connect to your network. For example, just plug your Ethernet board into your broadband router, which will act as a DHCP server.
  • Compile and then program the code into your device.
  • Start the Swordfish Serial Communicator plugin, and a connect to your MCUs USART at 115200 baud.
  • Reset the MCU.

If all goes well, something like the following should be displayed in the Serial Communicator window

 Waiting for DHCP...
 Host Name     : SWORDFISH      
 MAC Address   : $00 $04 $A3 $00 $00 $00 
 IP address    : 192.123.223.1
 Mask          : 255.255.255.0
 Gateway       : 192.123.223.254

Now enter a numeric IP address and press enter. For example,

 88.221.127.45

which should return something like

 Ping...40 ms

Sample Code - No DNS

// device and clock - code will work on an 18F452 as well...
Device = 18F4680
Clock = 20

// important configurations...
#option ENC28J60_CS = PORTD.6
#option NET_ICMP = true   // enable ping 
#option NET_DHCP = true   // enable Dynamic Host Configuration Protocol (DHCP)
#option NET_NBNS = true   // enable NETBIOS
Include "NETApp.bas"      // always first!

// TCPIP stack specifics...
Include "NETTypes.bas"
Include "NETUtils.bas"
Include "Tick.bas"
Include "ICMP.bas"

// program helpers...
Include "NETAppDisplay.bas"
Include "usart.bas"
Include "convert.bas"
Include "ISRRX.bas"

// state machine constants...
Const
   SM_HOME = 0,
   SM_GET_RESPONSE = 1,
   SM_FINISHED = 2

// ping variables...   
Dim 
   PingState As Byte,
   PingTimer As TICK
{
****************************************************************************
* Name    : Init                                                           *
* Purpose : Initialise timer and state machine                             *
****************************************************************************
}
Sub Init()
   PingTimer = 0
   PingState = SM_HOME
End Sub
{
****************************************************************************
* Name    : Ping                                                           *
* Purpose : Start a ping                                                   *
****************************************************************************
}
Sub Ping(ByRef pIP As String)
   Dim PingIP As IP_ADDR
   If PingState = SM_HOME Then
	  If ICMPBeginUsage() Then
	     NETUtils.StringToIPAddress(@pIP, PingIP)	     
	     ICMPSendPing(PingIP.Val)
         PingState = SM_GET_RESPONSE
	     PingTimer = TickGet()         
      EndIf 
   EndIf  
End Sub
{
****************************************************************************
* Name    : PingTask                                                       *
* Purpose : Process a ping task                                            *
****************************************************************************
}
Function PingTask() As SHORT
   Result = -2 // do nothing...

   // ping has been started, now wait for ping response...
   If PingState = SM_GET_RESPONSE Then
      Result = ICMPGetReply() 

      // the request timed out...
      If Result <> - 2 Then
         PingState = SM_FINISHED
      EndIf
   EndIf

   // wait at least one second before another ping - remove the ping timer
   // code if you do not need this functionality...
   If PingState = SM_FINISHED And (TickGet() - PingTimer) > 1000 Then
      PingState = SM_HOME
      ICMPEndUsage()
   EndIf
End Function 
{
****************************************************************************
* Name    : OnData                                                         *
* Purpose : The TCPIP stack is a co-operative state machine. Therefore, we *
*         : cannot wait around for USART data and use a buffered interrupt *
*         : instead. When a CR is received, set a ReadyToRead flag to true *
****************************************************************************
}
Dim ReadyToRead As Boolean
Event OnData()
   If ISRRX.DataChar = #13 Then
      ReadyToRead = true
   EndIf 
End Event

// main program variables...
Dim Result As SHORT
Dim StrIP As String(80)

// program start...
SetBaudrate(br115200)
Init()
#if NET_DHCP
Write("Waiting for DHCP...",13,10)
#else
DisplayConfig
#endif

// use interrupt buffered USART...
ReadyToRead = false
USART.ReadTerminator = 13
ISRRX.Initialize(OnData)

// loop forever...
While true

   // This task performs normal stack task including checking for incoming 
   // packet, type of packet and calling appropriate stack entity to process it.
   NETApp.Task

   // If the ready to read flag has been set, read a string from the interrupt
   // buffer and start the ping...
   If ReadyToRead Then
      ReadyToRead = false
      ISRRX.ReadStr(StrIP,13)
      USART.Write("Ping...")
      Ping(StrIP)
   EndIf

   // Process the ping task state machine...
   Result = PingTask()
   If Result >= 0 Then
      USART.Write(DecToStr(Result), " ms", 13,10)
   ElseIf Result = -1 Then
      USART.Write("timed out",13,10)
   EndIf      		 

   // If DHCP is enabled, display configuration when a DHCP event
   // has occurred...
   #if NET_DHCP
   If NETApp.DHCPEvent() Then
      DisplayConfig()
   EndIf
   #endif     
Wend

The next code example is pretty much the same as the above, except it uses the DNS module to resolve a hostname. This means you do not have to enter a numeric IP address. For example,

 www.microchip.com

which should return something like

 Ping...40 ms

Sample Code with DNS

// device and clock - code will work on an 18F452 as well...
Device = 18F4680
Clock = 20

// important configurations...
#option ENC28J60_CS = PORTD.6
#option NET_ICMP = true   // enable ping 
#option NET_DHCP = true   // enable Dynamic Host Configuration Protocol (DHCP)
#option NET_NBNS = true   // enable NETBIOS
#option NET_DNS = true    // enable Domain Name Service (DNS)
Include "NETApp.bas"      // always first!

// TCPIP stack specifics...
Include "NETTypes.bas"
Include "NETUtils.bas"
Include "Tick.bas"
Include "ICMP.bas"
Include "DNS.bas"

// program helpers...
Include "NETAppDisplay.bas"
Include "usart.bas"
Include "convert.bas"
Include "ISRRX.bas"

// state machine constants...
Const
   SM_HOME = 0,
   SM_RESOLVING = 1,
   SM_PING = 2,
   SM_GET_RESPONSE = 3,
   SM_FINISHED = 4

// ping variables...   
Dim 
   PingState As Byte,
   PingTimer As TICK,
   PingIP As IP_ADDR
{
****************************************************************************
* Name    : Init                                                           *
* Purpose : Initialise timer and state machine                             *
****************************************************************************
}
Sub Init()
   PingTimer = 0
   PingState = SM_HOME
End Sub
{
****************************************************************************
* Name    : Ping                                                           *
* Purpose : Start a ping                                                   *
****************************************************************************
}
Sub Ping(ByRef pHostname As String)
   If PingState = SM_HOME Then
      If DNSBeginUsage() Then
         DNSResolve(@pHostName, DNS_TYPE_A)
         PingState = SM_RESOLVING
      EndIf    
   EndIf     
End Sub
{
****************************************************************************
* Name    : PingTask                                                       *
* Purpose : Process a ping task                                            *
****************************************************************************
}
Function PingTask() As SHORT
   Dim PingResult As SHORT

   // default result is 0
   Result = 0

   // resolve hostname to an IP address...
   If PingState = SM_RESOLVING Then
      PingIP.Val = 0
      If DNSIsResolved(PingIP) Then
         DNSEndUsage

         // resolved, start ping...
         If PingIP.Val <> 0 Then
            PingState = SM_PING

         // unable to resolve, abort...
         Else
            Result = -1
            PingState = SM_HOME
         EndIf
      EndIf
   EndIf 

   // hostname has been resolved, start ping using
   // the IP address obtained from the DNS server...
   If PingState = SM_PING Then
	  If ICMPBeginUsage() Then
	     ICMPSendPing(PingIP.Val)
         PingState = SM_GET_RESPONSE
	     PingTimer = TickGet()         
      EndIf 
   EndIf     

   // ping has been started, now wait for ping response...
   If PingState = SM_GET_RESPONSE Then
      PingResult = ICMPGetReply() 

      // the request timed out...
      If PingResult = -1 Then
         Result = -2
         PingState = SM_FINISHED

      // echo received, time elapsed is stored in result (units of TICK)
      ElseIf PingResult >= 0 Then
		 Result = PingResult
		 PingState = SM_FINISHED
      EndIf
   EndIf

   // wait at least one second before another ping - remove the ping timer
   // code if you do not need this functionality...
   If PingState = SM_FINISHED And (TickGet() - PingTimer) > 1000 Then
      PingState = SM_HOME
      ICMPEndUsage()
   EndIf
End Function 
{
****************************************************************************
* Name    : OnData                                                         *
* Purpose : The TCPIP stack is a co-operative state machine. Therefore, we *
*         : cannot wait around for USART data and use a buffered interrupt *
*         : instead. When a CR is received, set a ReadyToRead flag to true *
****************************************************************************
}
Dim ReadyToRead As Boolean
Event OnData()
   If ISRRX.DataChar = #13 Then
      ReadyToRead = true
   EndIf 
End Event

// main program variables...
Dim Result As SHORT
Dim StrHostname As String(80)

// program start...
SetBaudrate(br115200)
Init()
#if NET_DHCP
Write("Waiting for DHCP...",13,10)
#else
DisplayConfig
#endif

// use interrupt buffered USART...
ReadyToRead = false
USART.ReadTerminator = 13
ISRRX.Initialize(OnData)

// loop forever...
While true

   // This task performs normal stack task including checking for incoming 
   // packet, type of packet and calling appropriate stack entity to process it.
   NETApp.Task

   // If the ready to read flag has been set, read a string from the interrupt
   // buffer and start the ping...
   If ReadyToRead Then
      ReadyToRead = false
      ISRRX.ReadStr(StrHostname,13)
      USART.Write("Ping...")
      Ping(StrHostname)
   EndIf

   // Process the ping task state machine...
   Result = PingTask()
   If Result > 0 Then
      USART.Write(DecToStr(Result), " ms", 13,10)
   ElseIf Result = -1 Then
      USART.Write("Unable to resolve ", StrHostname, 13,10)
   ElseIf Result = -2 Then
      USART.Write("timed out",13,10)
   EndIf      		 

   // If DHCP is enabled, display configuration when a DHCP event
   // has occurred...
   #if NET_DHCP
   If NETApp.DHCPEvent() Then
      DisplayConfig()
   EndIf
   #endif     
Wend