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