Files
2023-02-01 14:19:13 +08:00

318 lines
9.2 KiB
C

/********************************** (C) COPYRIGHT *******************************
* File Name : PING.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/11
* Description : ping related functions.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "PING.h"
u8 sendErrCnt;
u8 unreachCnt;
u8 timeoutCnt;
u8 sucRecCnt;
u8 sendBuf[100];
u8 ICMPCnt = 0;
u8 ICMPSeq = 0;
u8 ICMPSuc = 0;
u8 ICMPTmpVal = 0;
u32 timeCnt;
extern u8 SocketId;
/*********************************************************************
* @fn InitParameter
*
* @brief Initializes parameters.
*
* @return none
*/
void InitParameter(void)
{
unreachCnt = 0;
timeoutCnt = 0;
sucRecCnt = 0;
ICMPSuc = ICMP_KEEP_NO;
}
/*********************************************************************
* @fn InitPING
*
* @brief Initializes PING.
*
* @return none
*/
void InitPING(void)
{
IcmpHeader head;
u32 check_sum = 0;
u8 i;
ICMPCnt++;
ICMPSeq += 1;
head.i_type = ICMP_HEAD_TYPE;
head.i_code = ICMP_HEAD_CODE;
head.i_id = ICMP_HEAD_ID;
head.i_seq = ICMP_HEAD_SEQ + ICMPSeq;
memset(head.i_data, 0, sizeof(head.i_data));
for(i = 0; i < ICMP_DATA_BYTES; i++) {
if(i < 26)
head.i_data[i] = i + 'a';
else
head.i_data[i] = i + 'a' - 26;
if(i % 2 == 0)
check_sum += head.i_data[i] << 8;
else
check_sum += head.i_data[i];
}
check_sum += head.i_type << 8;
check_sum += head.i_code;
check_sum += head.i_id;
check_sum += head.i_seq;
head.i_cksum = check_sum >> 16;
head.i_cksum += check_sum & 0xffff;
head.i_cksum = 0xffff - head.i_cksum;
memset(sendBuf, 0, sizeof(sendBuf));
memcpy(sendBuf, &head, sizeof(head));
sendBuf[2] = head.i_cksum >> 8;
sendBuf[3] = head.i_cksum & 0xff;
sendBuf[4] = head.i_id >> 8;
sendBuf[5] = head.i_id & 0xff;
sendBuf[6] = head.i_seq >> 8;
sendBuf[7] = head.i_seq & 0xff;
}
/*********************************************************************
* @fn Respond_PING
*
* @brief Respond to PING request.
*
* @param pDat - ACK data.
*
* @return none
*/
void Respond_PING(u8 *pDat)
{
IcmpHeader head;
u32 check_sum = 0;
u8 i;
head.i_type = ICMP_HEAD_REPLY;
head.i_code = pDat[1];
head.i_id = (pDat[4] << 8) + pDat[5];
head.i_seq = (pDat[6] << 8) + pDat[7];
check_sum += head.i_type << 8;
check_sum += head.i_code;
check_sum += head.i_id;
check_sum += head.i_seq;
for (i = 0; i < 32; i++) {
head.i_data[i] = pDat[i + 8];
if (i % 2 == 0)
check_sum += head.i_data[i] << 8;
else
check_sum += head.i_data[i];
}
head.i_cksum = check_sum >> 16;
head.i_cksum += check_sum & 0xffff;
head.i_cksum = 0xffff - head.i_cksum;
memset(sendBuf, 0, sizeof(sendBuf));
memcpy(sendBuf, &head, sizeof(head));
sendBuf[2] = head.i_cksum >> 8;
sendBuf[3] = head.i_cksum & 0xff;
sendBuf[4] = head.i_id >> 8;
sendBuf[5] = head.i_id & 0xff;
sendBuf[6] = head.i_seq >> 8;
sendBuf[7] = head.i_seq & 0xff;
}
/*********************************************************************
* @fn WCHNET_ICMPRecvData
*
* @brief receive and parse data.
*
* @param len - data length.
* pDat - data buff
*
* @return none
*/
void WCHNET_ICMPRecvData(u32 len, u8 *pDat)
{
u16 tmp = 0;
ICMPTmpVal = ICMPSuc;
ICMPSuc = 3;
if (len == 40) {
if (pDat[0] == ICMP_HEAD_REPLY) {
if (pDat[1] == ICMP_HEAD_CODE) {
tmp = pDat[4];
tmp = tmp << 8;
tmp += pDat[5];
if (tmp == ICMP_HEAD_ID) {
tmp = pDat[6];
tmp = (tmp << 8);
tmp += pDat[7] - ICMPSeq;
if (tmp == ICMP_HEAD_SEQ) {
ICMPSuc = ICMP_RECV_SUC;
}
}
}
}
if (pDat[0] == ICMP_HEAD_TYPE) {
if (pDat[1] == ICMP_HEAD_CODE) {
Respond_PING(pDat);
ICMPSuc = ICMP_REPLY;
}
}
} else {
if (pDat[0] == 3) {
if (pDat[1] == 1) {
ICMPSuc = ICMP_UNRECH;
}
}
}
}
/*********************************************************************
* @fn WCHNET_PINGSendData
*
* @brief send PING command.
*
* @param PSend - data buff.
* Len - data length
* id - socket id
*
* @return none
*/
void WCHNET_PINGSendData( u8 *PSend, u32 Len,u8 id )
{
u32 length;
u8 i,count=0;
length = Len;
count = 0;
while(1){
Len = length;
i = WCHNET_SocketSend(id,PSend,&Len);
mStopIfError(i);
if(Len == 0){
count++;
if(count>2){
return;
}
}
length -= Len;
PSend += Len; //offset buffer pointer
if(length)continue; //If the data is not sent, continue to send
break;
}
ICMPSuc++;
}
/*********************************************************************
* @fn WCHNET_PINGCmd
*
* @brief Query status and execute corresponding commands.
*
* @return none
*/
void WCHNET_PINGCmd(void)
{
if (ICMPSuc < ICMP_KEEP_NO) {
switch (ICMPSuc) {
case ICMP_SOKE_CON:
ICMPSuc = 1;
timeCnt = 0;
WCHNET_PINGSendData(sendBuf, 40, SocketId);
printf("Ping %d.%d.%d.%d with %d bytes of data.\r\n",
(u16) DESIP[0], (u16) DESIP[1], (u16) DESIP[2],
(u16) DESIP[3], (u16) ICMP_DATA_BYTES);
break;
case ICMP_SEND_ERR:
if (sendErrCnt > 10) {
ICMPSuc = ICMP_KEEP_NO;
sendErrCnt = 0;
}
if (timeCnt > 250) {
printf("send data fail!\n");
timeCnt = 0;
sendErrCnt++;
WCHNET_PINGSendData(sendBuf, 40, SocketId);
}
break;
case ICMP_SEND_SUC:
if (timeCnt > 100) {
printf("Request timeout.\n");
timeoutCnt++;
if (ICMPCnt < PING_SEND_CNT) {
ICMPSuc = 1;
InitPING();
timeCnt = 0;
WCHNET_PINGSendData(sendBuf, 40, SocketId);
} else {
printf("PING end!\r\n");
printf("send = %d Received = %d", PING_SEND_CNT, sucRecCnt);
ICMPSuc = ICMP_KEEP_NO;
}
}
break;
case ICMP_RECV_ERR: // error unknown
printf("receive unknown data.\r\n");
ICMPSuc = ICMP_KEEP_NO;
break;
case ICMP_RECV_SUC: // success
printf("Reply from %d.%d.%d.%d: bytes=%d time<4ms\r\n",
(u16) DESIP[0], (u16) DESIP[1], (u16) DESIP[2],
(u16) DESIP[3], (u16) ICMP_DATA_BYTES);
sucRecCnt++;
if (ICMPCnt < PING_SEND_CNT) {
ICMPSuc = 1;
InitPING();
timeCnt = 0;
WCHNET_PINGSendData(sendBuf, 40, SocketId);
} else {
printf(
"Ping statistics for %d.%d.%d.%d:\r\nPackets: Sent = %d,Received = %d,Lost = %d<%d%% loss>.\r\n",
(u16) DESIP[0], (u16) DESIP[1], (u16) DESIP[2],
(u16) DESIP[3], PING_SEND_CNT, (u16) sucRecCnt,
(u16) (PING_SEND_CNT - sucRecCnt),
(u16) ((PING_SEND_CNT - sucRecCnt) * 100 / PING_SEND_CNT));
ICMPSuc = ICMP_KEEP_NO;
}
break;
case ICMP_UNRECH: // unreachable
printf("Reply from %d.%d.%d.%d: Destination host unreachable.\r\n",
(u16) DESIP[0], (u16) DESIP[1], (u16) DESIP[2],
(u16) DESIP[3]);
unreachCnt++;
if (ICMPCnt < PING_SEND_CNT) {
ICMPSuc = 1;
InitPING();
timeCnt = 0;
WCHNET_PINGSendData(sendBuf, 40, SocketId);
} else {
printf("PING end!\r\n");
printf("send = %d Received = %d", PING_SEND_CNT, sucRecCnt);
ICMPSuc = ICMP_KEEP_NO;
}
break;
case ICMP_REPLY:
WCHNET_PINGSendData(sendBuf, 40, SocketId);
break;
case ICMP_REPLY_SUC:
printf("Reply ping.\r\n");
ICMPSuc = ICMPTmpVal;
break;
case ICMP_KEEP_NO:
break;
default:
break;
}
}
}
/*********************************** endfile **********************************/