Implementation of Simple Ping of 51 MCU

Publisher:WhisperingLightLatest update time:2012-10-12 Source: 21IC Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Ping (Packet Internet Gopher) uses the "echo" function of the ICMP (Internet Control Message Protocol) protocol to test whether the host/server responds. ICMP provides communication between routers and hosts outside of normal situations. It is an integral part of IP. ICMP includes source station suppression messages that reduce the transmission rate, redirect messages that request the host to change the routing table, and echo request/reply messages that the host can use to determine whether the destination is reachable. ICMP messages are transmitted in the data area of ​​the IP datagram. When the host/server receives an ICMP message with an echo type, it responds with an "echo reply" message. After the local machine receives and confirms the message, it can be considered that the host/server is active, so that the local machine and the remote host/server can be connected and can communicate with each other. I
have implemented a simple ping function based on the ping command under DOS and the current status of 51 single-chip microcomputer resources. Its usage is as follows:
(1) MCU-->PC Use "ping XXX.XXX.XXX.XXX" in Shell. If connected, it will display "Reply from XXX.XXX.XXX.XXX: bytes=32 TTL=XXX", otherwise, it will display "Request timed out.(XXX.XXX.XXX.XXX)".
(2) PC-->MCU Follow the normal operation in DOS
Each ping command repeats the test 8 times, that is, 8 times of information is displayed.
Note that the displayed content is slightly different from that on the PC. This is because ping here works in a multi-task single-window environment. In order to distinguish the source of the response, it is necessary to add the source IP address information. In addition, due to 51 resource limitations, the time parameter (time is the time it takes for the local host to go back and forth with the other host) is cancelled. The specific simplified contents are as follows:
(1) Only the "ping+IP address" command format is supported, and the domain name method and other options are not available
(2) A fixed 32-byte test packet
(3) The round-trip time between the local host and the other host is not calculated, and the test time is 1 to 2 seconds
. In short, the simplified ping can complete the most basic connectivity test function.

0 8 16 31
------------------------------------------------
| Type (8 or 0) | Code (0) | Checksum |
------------------------------------------------
| Identifier | Sequence number |
------------------------------------------------
| Optional data |
------------------------------------------------
| . . . |
------------------------------------------------

Figure 1 ICMP echo request or reply message format

PingCycle
| Scheduled operation
V
PingCmd ---------------- --------------
-------->| PingRequest|----------->| |
Command | | Request | | |
| | |
| A | | B |
| | | |
<--------|PingEcho |<-----------|PingAnswer |
Echo ---------------- Answer --------------

Figure 2 A Ping B process (full-duplex operation, vice versa, the reverse process is not drawn)

Figure 1 shows the ICMP echo request/reply message format (i.e. Ping packet format). After the network card driver is implemented, the implementation of Ping is simplified to filling in the message (see the pseudo code list for details). As shown in Figure 2, I mainly use 4 functions to implement the complete ping process. Ping request (PingRequest), Ping reply (PingAnswer), echo after receiving the reply (PingEcho), and scheduled operation (PingCycle).
PingRequest completes the Ping request. When the Ping command is entered, this function is called to send a request packet.
PingAnswer completes the Ping response. It works in the background and automatically responds whenever it receives a request packet sent to its own IP.
PingEcho displays the response information. Whenever a response is received, the relevant information is immediately displayed.
PingCycle periodically operates the pingbuf record buffer. It scans once per second and changes the state according to the current situation and status.

- ----------------------------------------------------
| | Status (status) | Times (times) | Memory handle (memhandle) |
| ----------------------------------------------------
N | . . . |
| ----------------------------------------------------
| | Status (status) | Times (times) | Memory handle (memhandle) |
- ----------------------------------------------------

N=MaxLenPingBufFigure
3 pingbuf record buffer format

The IP address must be converted into a MAC address before it can be transmitted on the Ethernet. If there is no corresponding item in the ARP cache, it will take a long time to find it (network transmission time relative to CPU time). In order not to block the process, I designed a pingbuf record buffer, as shown in Figure 3. This table is queried once a second and changes its state according to the current situation. It includes three fields: state, number of times, and memory handle. The "number of times" field indicates the remaining number of tests. 0 means that the test is completed, and the state is changed to 0 to indicate that this record item is now idle. The "memory handle" field stores the first address pointer of the ICMP message buffer. The "state" field records the state number, which means as follows:
0---Idle
1---Sent but no response
2---Sent and responded
3---Waiting for ARP
4---First preparation to send (used to synchronize the 1-second clock)
The state transition diagram is shown in Figure 4.

Figure 4 is omitted. For details, see the pseudo code list PingCycle. Please draw the state diagram yourself.

This implementation also uses auxiliary programs such as ping command processing, IP address conversion, and checksum calculation. For details, see the pseudo code list. The IP protocol uses a unified CheckSum algorithm to calculate and verify the header checksum of the datagram. The header is regarded as a 16-bit integer sequence, and the checksum is defined as the binary complement of the sum of all 16-bit integers in the header. Similarly, the sum and complement are also defined to use the binary complement algorithm. All TCP/IP protocol checksum calculations and data packet verification are completed by the CheckSum subroutine. However, it should be noted that the TCP and UDP checksums require a pseudo header. The packets that require header checksum calculation and verification are: IP, ICMP, UDP, TCP. The only difference between them is that the sum data is different, and the algorithm uses CheckSum. See the source program listing for details. (Hint: The IP header consists of 20 bytes from the version number, header length, service type to the destination IP address (if it does not contain IP options); the ICMP checksum only covers the ICMP message. Comparing the similarities between the UDP, TCP pseudo header and the IP header, it is not necessary to allocate a separate pseudo header buffer, but to directly use the IP buffer to calculate the checksum. By observing the adjacent data of the IP header, direct calculation can be achieved by taking certain measures. That is, first clear the IP lifetime field to 0, assign the corresponding value to the protocol field, assign the checksum to the UDP/TCP packet length value, and add 12 to indicate the 3-word length of the pseudo header. After the calculation is completed, add the correct lifetime and checksum value to the IP packet header, as shown in Figure 5.)

0 8 16 31 0 8 16 31
---------------------------- ---------------------------
| Lifetime | Protocol | Header checksum | | Source IP address |
---------------------------- ---------------------------
| Source IP address | | Destination IP address |
---------------------------- ---------------------------
| Destination IP address | | Zero | Protocol | UDP/TCP length |
---------------------------- ---------------------------
| Data | | UDP/TCP packet data |
---------------------------- ---------------------------
IP packet format (partial) UDP, TCP pseudo header + data format
Figure 5 Comparison of IP packet format (partial) and UDP, TCP pseudo header format

Pseudocode listing:

PingRequest(IP address) //Ping request
{
//Apply for small memory
pICMP=OSMemGet();

//Fill in Ethernet frame
Destination MAC address=physical address obtained after parsing the IP address passed in by the ping command
Source MAC address=MAC address of this node
Type=0x0800 //IP packet

//Fill in IP frame
Version number & header length=0x45
Service type=0
Total length=60
Identifier=GlobalID++ //Global variable 16-bit GlobalID plus 1
flag & fragment offset=0x0000
Lifetime=0x80
Protocol=0x0001 //icmp
header checksum=0x0000
Source IP address=IP address
of this node Destination IP address=IP address passed in by the ping command
Header checksum=CheckSum(IP header and length) //Calculate the IP packet header checksum

//Fill in ICMP frame
Type=8 //8 Request 0
Response code = 0
checksum = 0x0
identifier = 0x0300
sequence number = GlobalID
checksum = CheckSum (ICMP header and length) //Calculate the ICMP packet header checksum

//Register the ICMP packet in PingBuf
for(i=0;i if(PingBuf[i].status==0){
PingBuf[i].times=0x8; //Test 8 times
PingBuf[i].ip=IP address passed in by ping command;
PingBuf[i].memhandle=memory handle;
PingBuf[i].status=4; //First preparation for sending (used to synchronize 1 second clock)
break;
}
}
if(i==MaxLenPingBuf) release memory;
}

PingAnswer(*input packet buffer first address pBUF) //Ping response
{
//Rewrite Ethernet frame
Destination MAC address = source MAC address
Source MAC address = local node MAC address

//Rewrite IP frame
Lifetime = life-1
Destination IP address = source IP address
Source IP address = local node IP address
Header checksum = 0x0000
Header checksum = CheckSum (IP header and length) //Calculate IP packet header checksum

//Rewrite ICMP frame
Type = 0 //8 request 0 response
Checksum = 0x0
Checksum = CheckSum (ICMP header and length) //Calculate ICMP packet header checksum

//Directly send ICMP packet to TxQFIFO buffer
OSQSend(QID,*pBUF);
}[page]

PingEcho(*input packet buffer first address pBUF) //Echo after receiving the response
{
//Print ping response, because the 51 timer is slow, the time parameter is omitted (time is the time taken for the local machine to go back and forth with the other host).
PrintStr(" \\tReply from IP=");
PrintStr(input packet source IP address); PrintStr
(": bytes=32");
PrintStr(" TTL=");
PrintByte(input packet TTL);
PrintStr(" ");

//Process PingBuf recordsfor
(i=0;i if(PingBuf[i].status==1){
if(PingBuf[i].ip==pBUF.ipframe.ip){
PingBuf[i].status=2; //Sent and respondedbreak
;
}
}
}
}

PingCycle() //Timed operation, put in the 1 second loop task
{
for(;;){
taskDelay(1 second);
for(i=0;i switch(PingBuf[i].status)
case 0: //Idle
break;

{
case 1: //Sent but no response

//Print timeout informationPrintStr
(" \\tRequest timed out.(");
PrintStr(PingBuf[i].ip);
PrintStr(") ");

case 2: //Sent and responded

//State transitionPingBuf
[i].times=PingBuf[i].times-1;
if(PingBuf[i].times==0)
​​PingBuf[i].status=0;
else{

case 4: //First preparation to send (used to synchronize the 1 second clock)

//Check the ARP cacheif
(ARP cache has a corresponding item){

//Directly send ICMP packet to TxQFIFO
bufferOSQSend(QID,*pBUF);

PingBuf[i].status=1; //Sent but no response
}
else PingBuf[i].status=3; //Wait for ARP
}
break;
}
case 3: //Wait for ARP
{
//Check ARP cache
if(ARP cache has corresponding item){
//Directly send ICMP packet to TxQFIFO buffer
OSQSend(QID,*pBUF);
}
PingBuf[i].status=1; //Sent but no response
}
default: //Other status, error
PingBuf[i].status=0;
}
}
}

void PingCommand(WORDTABLE *WordTable)//PING command processing
{
if(WordTable->Num==1)
PrintStr(" Please input IP address! ");
else{
if(IPadrToHEX(WordTable->wt[1].Str, &ping_ip_address)==0){
PrintStr(" IP address error! ");return;
}
else
PingRequest(ping_ip_address);
}
}

INT16U CheckSum(INT16U *buf,INT16U length) //Checksum calculation
{
INT16U len;
INT32U sum;

len=length>>1;
for(sum=0;len>0;len--)
sum+=*buf++;
if (length&1)
sum+=(*buf&0xFF00);
sum=(sum>>16)+(sum&0xFFFF);
sum+=(sum>>16);

return(~sum);
}

union ip_address_type{ //IP address data structure
unsigned long dwords;
unsigned int words[2];
unsigned char bytes[4];
};

bit IPadrToHEX(unsigned char *Str,union ip_address_type *ip) //Convert IP string to IP address value
{
unsigned char i,j,ch,x;

ch=*Str++;

for(j=0;j<3;j++){
x=0;
for(i=0;i<4;i++){
if(ch==\'.\') {ch=*Str++;break;}
else if(i==3) return 0;
else if(ch<0&&ch>9) return 0;
else
x=10*x+(ch-\'0\');
ch=*Str++;
}
ip->bytes[ j]=x;
}

x=0;
for(i=0;i<4;i++){
if(ch==\'\\0\') {ch=*Str++;break;}
else if(i==3) return 0;
else if(ch<0&&ch>9) return 0;
else
x=10*x+(ch-\'0\');
ch=*Str++;
}
ip->bytes[3]=x;
return 1;
}

void HEXToIPadr(unsigned char *Str,union ip_address_type *ip) //Convert IP address value to IP string
{
unsigned char i;
unsigned char x,y;

for(i=0;i<4;i++){
x=ip->bytes[i];
if(x>99){
y=x/100;*Str++=y+\'0\';
x=x- 100*y;y=x/10;*Str++=y+\'0\';
x=x-10*y;*Str++=x+\'0\';
if(i==3) *Str++=\' \\0\';
else *Str++=\'.\';
}
else if(x>9){
y=x/10;*Str++=y+\'0\';
x=x-10*y;* Str++=x+\'0\';
if(i==3) *Str++=\'\\0\';
else *Str++=\'.\';
}
else{
*Str++=x+\'0\';
if(i==3) *Str++=\'\\0\';
else *Str++=\'.\';
}
}
}


References:
1. "Internetworking with TCP/IP" (3rd edition)

Reference address:Implementation of Simple Ping of 51 MCU

Previous article:51 MCU ARP protocol implementation principle
Next article:51 MCU general assembly delay subroutine

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号