首页 > 其他分享 >CH395实现主动ping对端功能(代码及说明)

CH395实现主动ping对端功能(代码及说明)

时间:2023-12-18 15:36:09浏览次数:35  
标签:head socket 对端 CH395 ping None SEND BUF

目录 1.PING原理 1.1简介 1.2协议 1.3通信流程 2.代码解释 3.工程链接

  • PING原理

1.简介

  PING是基于ICMP(Internet Control Message Protocol)协议工作的。ICMP报文是封装在IP包中,工作在网络层。

2.协议

  ICMP包头的类型字段有2类,一类是查询报文,用于检测通信链路是否正常;一类是差错报文,通知出错原因。

  回送消息是用于进行通信的主机间,判断所发的数据包是否已经成功到达对端的一种消息,ping命令就是利用这个消息实现的:可以向对端发送回送请求的消息(request,8),也可以接收对端主机发送回来的应答(reply,0)

Type(8位) Code(8位)
Checksum(16位)
Identifier(16位)
Sequence Number(16位)
选项数据

 

Type(类型):0代表回送应答,8代表回送请求

Code(代码):值为0

Checksum(校验和)

 Identifier(标识符):Unix系统在实现ping程序时,把ICMP报文中的标识符字段设置成发送进程的PID号

Sequence Number(序号):从0开始,每发送一次新的请求就加1

 抓包:

请求包(Response frame:40 表示应答此请求的reply包是N0.40这一包)

 应答包(Request frame:37 表示此包是对N0.37这一请求包的应答)

 3.通信流程

  ①执行ping 192.168.x.x命令后,源主机会先构建一个ICMP请求消息数据包(类型为8)

  ②由ICMP协议将这个数据包连同192.168.x.x这一地址一起交给IP层。IP层将以192.168.x.x作为目的地址,本地ip地址作为源地址,协议字段置为1表示是ICMP协议,再加上一些其他的信息构建成一个IP数据包。

  ③之后,需要加入MAC头,如果在本地ARP映射表中能直接查到192.168.x.x这一地址所对应的MAC地址,则可以直接使用。在获取MAC地址后,由数据链路层构建一个数据帧,其中,目的地址是刚刚找到的MAC地址,源地址是本机的MAC地址。

  ④对端设备收到这个数据帧后,将其中的目的MAC地址和自己的本地MAC地址对比,如果符合则接收,不符合就丢弃。如果MAC地址符合,那么提取出IP数据包,经IP层检查后,再提取出有用的相关信息给ICMP协议。

  ⑤识别出这是一个ping请求帧后,将构建一个ICMP应答包(类型为0),经过同样的流程传给发送请求包的主机。

  • 代码解释(CH395.c)

1.设置395相关网络参数及对端,将ip包协议字段置为1,表示为Internet控制消息 (ICMP)协议类型。

1 /* CH395相关定义 */
2 const  UINT8 CH395IPAddr[4]   = {192,168,1,126};                        /* CH395IP地址 */
3 const  UINT8 CH395GWIPAddr[4] = {192,168,1,1};                         /* CH395网关 */
4 const  UINT8 CH395IPMask[4]   = {255,255,255,0};                       /* CH395子网掩码 */
5 const  UINT8 DestIPAddr[4]    = {192,168,1,23};                       /* 目的IP */
6 const  UINT8  IPRawProto      = 1;                                     /* IP包协议类型 */

 2.初始化395和socket的参数,并将socket设置为ipraw模式。(关于ipraw模式的介绍和使用可以查阅CH395的官方手册)

 1 /**********************************************************************************
 2 * Function Name  : InitCH395InfParam
 3 * Description    : 初始化CH395Inf参数
 4 * Input          : None
 5 * Output         : None
 6 * Return         : None
 7 **********************************************************************************/
 8 void InitCH395InfParam(void)
 9 {
10     memset(&CH395Inf,0,sizeof(CH395Inf));                            /* 将CH395Inf全部清零*/
11     memcpy(CH395Inf.IPAddr,CH395IPAddr,sizeof(CH395IPAddr));         /* 将IP地址写入CH395Inf中 */
12     memcpy(CH395Inf.GWIPAddr,CH395GWIPAddr,sizeof(CH395GWIPAddr));   /* 将网关IP地址写入CH395Inf中 */
13     memcpy(CH395Inf.MASKAddr,CH395IPMask,sizeof(CH395IPMask));       /* 将子网掩码写入CH395Inf中 */
14 }
15 
16 /**********************************************************************************
17 * Function Name  : InitSocketParam
18 * Description    : 初始化socket
19 * Input          : None
20 * Output         : None
21 * Return         : None
22 **********************************************************************************/
23 void InitSocketParam(void)
24 {
25     memset(&SockInf,0,sizeof(SockInf));                              /* 将SockInf[0]全部清零*/
26     memcpy(SockInf.IPAddr,DestIPAddr,sizeof(DestIPAddr));            /* 将目的IP地址写入 */
27     SockInf.ProtoType = PROTO_TYPE_IP_RAW;                           /* IP RAW模式 */
28     SockInf.IPRAWProtoType = IPRawProto;
29 }
30 
31 /**********************************************************************************
32 * Function Name  : CH395SocketInitOpen
33 * Description    : 配置CH395 socket 参数,初始化并打开socket
34 * Input          : None
35 * Output         : None
36 * Return         : None
37 **********************************************************************************/
38 void CH395SocketInitOpen(void)
39 {
40     UINT8 i;
41     /* socket 0为IP RAW模式 */
42     CH395SetSocketDesIP(0,SockInf.IPAddr);                           /* 设置socket 0目标IP地址 */
43     CH395SetSocketProtType(0,SockInf.ProtoType);                     /* 设置socket 0协议类型 */
44     CH395SetSocketIPRAWProto(0,SockInf.IPRAWProtoType);              /* 设置协议字段 */
45 
46     i = CH395OpenSocket(0);                                          /* 打开socket 0 */
47     mStopIfError(i);                                                   /* 检查是否成功 */                                              /* 检查是否成功 */
48 }

 3.在socket的接收中断中,调用 CH395GetRecvLength()函数获取当前缓冲区中的数据长度,在调用CH395GetRecvData()函数读取数据,最后调用 CH395IcmpRecvData()函数对收到的ping包处理和分析。

 1 /**********************************************************************************
 2 * Function Name  : CH395SocketInterrupt
 3 * Description    : CH395 socket 中断,在全局中断中被调用
 4 * Input          : sockindex
 5 * Output         : None
 6 * Return         : None
 7 **********************************************************************************/
 8 void CH395SocketInterrupt(UINT8 sockindex)
 9 {
10    UINT8  sock_int_socket;
11 
12    UINT16 len;
13 
14    sock_int_socket = CH395GetSocketInt(sockindex);                   /* 获取socket 的中断状态 */
15   // printf("SOCK status : %02x\n",sock_int_socket);
16    if(sock_int_socket & SINT_STAT_SENBUF_FREE)                       /* 发送缓冲区空闲,可以继续写入要发送的数据 */
17    {
18    }
19    if(sock_int_socket & SINT_STAT_SEND_OK)                           /* 发送完成中断 */
20    {
21        IcmpSuc++;
22    }
23    if(sock_int_socket & SINT_STAT_RECV)                              /* 接收中断 */
24    {
25        printf("recv back!\r\n");
26        len = CH395GetRecvLength(sockindex);                            /* 获取当前缓冲区内数据长度 */
27        if(len == 0)return;
28        if(len > 512) len = 512;
29        CH395GetRecvData(sockindex,len,MyBuffer);                       /* 读取数据 */
30        CH395IcmpRecvData(len,MyBuffer);
31    }
32    if(sock_int_socket & SINT_STAT_CONNECT)                          /* 连接中断,仅在TCP模式下有效*/
33   {
34 
35   }
36     if(sock_int_socket & SINT_STAT_DISCONNECT)                        /* 断开中断,仅在TCP模式下有效 */
37     {
38     }
39    if(sock_int_socket & SINT_STAT_TIM_OUT)                           /* 超时中断 */
40    {
41    }
42 }

 4.在CH395PINGInit()函数中,进行引脚初始化、复位395、初始化395、初始化socket、打开socket等操作。

调用 CH395EnablePing(1)函数开启ping功能(默认开启)

InitParameter()--- PING参数变量初始化

InitPing()--- PING初始化,生成ping查询报文

 1 /**********************************************************************************
 2 * Function Name  : main
 3 * Description    : main主函数
 4 * Input          : None
 5 * Output         : None
 6 * Return         : None
 7 **********************************************************************************/
 8 void CH395PINGInit(void)
 9 {
10     UINT8 i;
11     Delay_Ms(100);
12     printf("CH395EVT Test Demo\n");
13     CH395_PORT_INIT();
14     CH395CMDReset();                                                 /* 复位CH395芯片 */
15     Delay_Ms(1000);                                                  /* 延时1000毫秒,要分开写,否则无效 */
16 
17     i = CH395CMDGetVer();                                            /*获取芯片以及固件版本号 */
18     printf("固件版本号:%02x\n",i);
19     InitCH395InfParam();                                             /* 初始化CH395相关变量 */
20     i = CH395Init();                                                 /* 初始化CH395芯片 */
21     printf("CH395Init:%02x\n",i);
22     mStopIfError(i);
23 
24     while(1)
25     {                                                                /* 等待以太网连接成功*/
26        if(CH395CMDGetPHYStatus() == PHY_DISCONN)                     /* 查询CH395是否连接 */
27        {
28            printf("CH395 DISCONN\n");
29            Delay_Ms(200);                                            /* 未连接则等待200MS后再次查询 */
30        }
31        else
32        {
33            printf("CH395 Connect Ethernet\n");                       /* CH395芯片连接到以太网,此时会产生中断 */
34            break;
35        }
36     }
37     InitSocketParam();         //                                      /* 初始化socket相关变量 */
38     CH395SocketInitOpen();//
39 
40     //CH395EnablePing(1);//默认开启
41     InitParameter();
42     InitPing();
43     printf("!!\r\n");
44 //    TIM2_Init();
45 //    Intervalometer_4ms();
46 }
 1 /**********************************************************************************
 2 * Function Name  : InitParameter
 3 * Description    : Ping参数初始化
 4 * Input          : None
 5 * Output         : None
 6 * Return         : None
 7 **********************************************************************************/
 8 void InitParameter( void )
 9 {
10     UNREACH_COUNT=0;
11     TIMOUT_COUNT=0;
12     SUCRECV_COUNT=0;
13     IcmpCont=0;
14     IcmpSeq=0;
15     IcmpSuc=0;///
16     icmp_tmp=0;
17     CH395GetIPInf(CH395INF_BUF);
18 }
19 
20 /**********************************************************************************
21 * Function Name  : InitPing
22 * Description    : Ping初始化
23 * Input          : None
24 * Output         : None
25 * Return         : None
26 **********************************************************************************/
27 void InitPing( void )
28 {
29   IcmpHeader head;
30   UINT32 check_sum=0;
31   UINT8 i;
32 
33   IcmpCont++;
34   IcmpSeq += 1;
35   head.i_type = ICMP_HEAD_TYPE;//8
36   head.i_code = ICMP_HEAD_CODE;//0
37   head.i_id   = ICMP_HEAD_ID;//512
38   head.i_seq  = ICMP_HEAD_SEQ+IcmpSeq;//100+
39   memset(head.i_data,0,sizeof(head.i_data));
40 
41   for( i=0;i<ICMP_DATA_BYTES;i++ ){//32
42     if(i<26)
43         head.i_data[i] = i + 'a';
44     else
45         head.i_data[i] = i + 'a' - 26;
46     if(i%2==0)
47         check_sum += head.i_data[i]<<8;
48     else
49         check_sum += head.i_data[i];
50   }
51   check_sum += head.i_type<<8;
52   check_sum += head.i_code;
53   check_sum += head.i_id;
54   check_sum += head.i_seq;
55   head.i_cksum = check_sum>>16;
56   head.i_cksum += check_sum&0xffff;
57   head.i_cksum = 0xffff - head.i_cksum;
58   memset(SEND_BUF,0,sizeof(SEND_BUF));
59   memcpy(SEND_BUF,&head,sizeof(head));
60 
61   SEND_BUF[2] = head.i_cksum >> 8;
62   SEND_BUF[3] = head.i_cksum & 0xff;
63   SEND_BUF[4] = head.i_id >> 8;
64   SEND_BUF[5] = head.i_id & 0xff;
65   SEND_BUF[6] = head.i_seq >> 8;
66   SEND_BUF[7] = head.i_seq & 0xff;
67 }

 5.在main函数中,通过 CH395SendData()函数发送 InitPing()函数生成的40字节的数据,简单实现按键按一下发送一次ping请求包。

 1 /**********************************************************************************
 2 * Function Name  : main
 3 * Description    : main主函数
 4 * Input          : None
 5 * Output         : None
 6 * Return         : None
 7 **********************************************************************************/
 8 int main(void)
 9 {
10 
11     Delay_Init();
12     USART_Printf_Init(115200);
13     Delay_Ms(100);
14     /* 延时100毫秒 */
15     GPIO_Toggle_INIT_C();
16     CH395PINGInit();
17 //
18 //Delay_Ms(2000);
19 //CH395SendData(0,MyBuffer1,2);
20 //Delay_Ms(20);
21 //            CH395SendData( 0,SEND_BUF,40 );
22 //            Delay_Ms(20);
23 //            CH395SendData( 0,SEND_BUF,40 );
24 //
25 //            Delay_Ms(20);
26 //            CH395SendData( 0,SEND_BUF,40 );
27 //            Delay_Ms(20);
28 //            CH395SendData( 0,SEND_BUF,40 );
29     while(1)
30     {
31         if(CH395_INT_WIRE == 0)
32         {
33             CH395GlobalInterrupt();
34         }
35         if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET)
36         {
37             Delay_Ms(2);
38             if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET)
39             {
40                 printf("PING %d times\r\n",++t);
41                 CH395SendData( 0,SEND_BUF,40 );
42                 while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET);
43             }
44         }
45 //    CH395SendData( 0,SEND_BUF,40 );
46 //      Delay_Ms(1500);
47       /*查询状态执行相应命令*/
48 //      CH395_PINGCmd();
49      // InitPing();
50     }
51 }

效果如下,按下按键发送一次ping请求包,对端reply一包数据。(一共发了3次ping_request,成功进入socket接收中断接收处理回包)


 

工程代码及抓包:https://files.cnblogs.com/files/blogs/808422/CH395_%E4%B8%BB%E5%8A%A8ping.zip?t=1702869711&download=true

标签:head,socket,对端,CH395,ping,None,SEND,BUF
From: https://www.cnblogs.com/wchwchlq/p/17910432.html

相关文章

  • streamlit 网络批量ping和snmp检查
    importtimeimportnetaddrfromnetaddrimport*importpandasaspdimportstreamlitasstfromconcurrent.futuresimportThreadPoolExecutorimportsubprocessimportshlexfromthreadingimportLockimportreclasscompute(object):def__init__(self):s......
  • 在 Windows 11 中为 WSL2 启用 Systemd 以及修复ping不通和DNS无法解析等的问题
    前言今天使用WSL2(Ubuntu22.04.1LTS)的时候,遇到了ping不通的问题,提示:ping:connect:Networkisunreachable以及执行sudoaptupdate命令出现错误:Failedtofetchhttp://archive.ubuntu.com/ubuntu/dists/focal/InReleaseTemporaryfailureresolving'archive.ubunt......
  • offline RL | Pessimistic Bootstrapping (PBRL):在 Q 更新中惩罚 uncertainty,拉低 OOD
    论文题目:PessimisticBootstrappingforUncertainty-DrivenOfflineReinforcementLearning,ICLR2022,6688spotlight。pdf版本:https://arxiv.org/abs/2202.11566html版本:https://ar5iv.labs.arxiv.org/html/2202.11566openreview:https://openreview.net/forum?id=Y4c......
  • 最新Spring 6手写实现Sping IOC保姆级教程
    Java全能学习+面试指南:https://javaxiaobear.cn我们都知道,Spring框架的IOC是基于Java反射机制实现的,下面我们先回顾一下java反射。1、回顾Java反射Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种......
  • 在Python的类型提示中,你不能直接使用​​or​​​来表示一个参数可以是多种类型中的一
    在Python的类型提示中,你不能直接使用or来表示一个参数可以是多种类型中的一种。你应该使用typing.Union来表示这种情况¹²。所以,你的函数应该这样写:fromtypingimportUnion,Listdefquery_coilNum(self,coilNum:Union[str,List[str]]):pass在这个例子中,Union[str,Li......
  • python之typing
    typing介绍Python是一门动态语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果,就不得不去阅读代码的具体内容,降低了阅读的速度,typing模块可以很......
  • 在思岚A1上复现gmapping
    文章目录软硬件条件laser_scan_matcher通过源码安装rplidar_ros通过源码安装设置参数启动效果预览软硬件条件软件:Ubuntu20.04,ROSnoetic硬件:RPLidarA1.laser_scan_matcher通过源码安装mkdir-p~/catkin_ws/srccd~/catkin_ws/srcgitclonehttps://github.com/ccny-ros-pk......
  • day21 atm项目 shopping_car
    shopping_car()fromatm.lib_common.file_handleimport*fromatm.core.shoppingimportgoods_showfromatm.lib_common.money_enquiryimport*defcompute_money_total(username):"""计算购物车总价返回购物车总价和购物车字典"""......
  • 分析网络路由的工具 pathping 和 mtr
    结合了ping和tracert/traceroute的工具有PathPing(Windows)和MTR(MyTraceroute,在Unix/Linux上)PathPing(Windows)PathPing:这个工具结合了ping和tracert的功能,它会发送多个数据包到每个跳点,并统计丢包率和延迟。这对于识别链路中的问题节点非常有用。如何使用PathPing打开......
  • TypingLearn解决了我在学习英语中的一大痛点
    上一次在博客园发贴还是在上一次(2021年),那个时候博客园就遇到了危机(被罚款)。彼时在疫情期间,我个人生活也受到了影响,先后去了多个城市,最终在上海找到了.NETWeb开发的岗位,还是比较幸运的,因为这就是我感兴趣的。TypingLearn解决了我在学习英语中的一大痛点一些背景我是一个开......