W5100S+树莓派RP2040快速入门之PING篇(十)

2023-10-09 08:20

本文主要是介绍W5100S+树莓派RP2040快速入门之PING篇(十),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

        上一章节我们用我们开发板在UDP组播模式下进行数据回环测试,本章我们用开发板去主动ping主机IP地址来检测与该主机之间网络的连通性。

什么是PING?

        PING是一种命令, 是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机。ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。可以理解为ping命令是ICMP的一种形式,而ICMP属于网络层协议,因而ping也工作在网络层。

连接方式

  • 开发板直连主机
  • 开发板和主机都接在路由器LAN口

PING测试

        我们的W5100S以太网芯片,既可以通过一个socket端口开启IPRAW模式自己组包(ICMP报文)对目标IP进行ping测试,从而在软件上实现ping功能,也可以通过配置SOCKET-less命令相关寄存器,通过SOCKET-less命令直接在硬件上实现ping功能,省去了在软件上组包、解析数据包的烦恼,而且不占用socket端口,非常方便和易于实现。下面我们通过这两种方式分别进行ping测试:

1. 相关代码

1. 通过IPRAW模式实现(软件)

        我们打开库文件PING文件夹里的ping.c文件,我们主要用到这几个函数:ping_auto()、ping_request()、ping_reply()、do_ping()等,ping_request()和ping_reply()主要是ping请求的组包和收到ping回复的数据包解析,用到的数据转换和处理大家自行查看,这里我们主要看下ping_auto()函数,它通过在一个循环里构建一个状态机来对socket状态进行轮询,做出对应处理,如果端口关闭状态,就设置对应端口协议为ICMP协议,然后以IPRAW模式打开;进入IPRAW模式后,发送ping请求,然后判断是否收到或超时,收到就进行解析,之后跳出,超时则跳出,当请求数和回复数相等且为4次时结束大循环,然后将它再封装成do_ping()方便直接调用,如下所示:

/* Ping the Internet automatically. */
void ping_auto(uint8_t sn, uint8_t *addr)
{int32_t len = 0;uint8_t cnt = 0;uint8_t i;for (i = 0; i < 10; i++){if (req == rep && req == 4)break;switch (getSn_SR(sn)){case SOCK_IPRAW:ping_request(sn, addr);req++;while (1){if ((len = getSn_RX_RSR(sn)) > 0){ping_reply(sn, addr, len);sleep_ms(50);rep++;break;}else if (cnt > 200){printf("Request Time out.\r\n");cnt = 0;break;}else{cnt++;sleep_ms(50);}}break;case SOCK_CLOSED:close(sn);setSn_PROTO(sn, IPPROTO_ICMP);if (socket(sn, Sn_MR_IPRAW, 3000, 0) != 0){}while (getSn_SR(sn) != SOCK_IPRAW);sleep_ms(2000);default:break;}
#ifdef PING_DEBUGif (rep != 0){printf(" Ping Request = %d, PING_Reply = %d\r\n", req, rep);if (rep == req)printf(" PING SUCCESS\r\n ");elseprintf(" REPLY_ERROR\r\n ");}
#endif// if(rep==4)break;}
}/* ping response. */
uint8_t ping_request(uint8_t sn, uint8_t *addr)
{uint16_t i;int32_t t;ping_reply_received = 0;PingRequest.Type = PING_REQUEST;    /*Ping-Request*/PingRequest.Code = CODE_ZERO;       /*总是 '0'*/PingRequest.ID = htons(RandomID++); /*设置ping响应ID为随机的整型变量*/PingRequest.SeqNum = htons(RandomSeqNum++);for (i = 0; i < BUF_LEN; i++){PingRequest.Data[i] = (i) % 8;}PingRequest.CheckSum = 0;PingRequest.CheckSum = htons(checksum((uint8_t *)&PingRequest, sizeof(PingRequest)));t = sendto(sn, (uint8_t *)&PingRequest, sizeof(PingRequest), addr, 3000);if (t == 0){printf("\r\n Fail to send ping-reply packet  r\n");}else{printf(" 正在 Ping: %d.%d.%d.%d  \r\n", (addr[0]), (addr[1]), (addr[2]), (addr[3]));}return 0;
}/* Resolving ping reply. */
uint8_t ping_reply(uint8_t s, uint8_t *addr, uint16_t rlen)
{uint16_t tmp_checksum;uint16_t len;uint16_t i;uint8_t data_buf[128];uint16_t port = 3000;PINGMSGR PingReply;len = recvfrom(s, (uint8_t *)data_buf, rlen, addr, &port); /*从目的端接收数据*/if (data_buf[0] == PING_REPLY){PingReply.Type = data_buf[0];PingReply.Code = data_buf[1];PingReply.CheckSum = (data_buf[3] << 8) + data_buf[2];PingReply.ID = (data_buf[5] << 8) + data_buf[4];PingReply.SeqNum = (data_buf[7] << 8) + data_buf[6];for (i = 0; i < len - 8; i++){PingReply.Data[i] = data_buf[8 + i];}tmp_checksum = ~checksum(data_buf, len); /*检查ping回复的次数*/if (tmp_checksum != 0xffff)printf("tmp_checksum = %x\r\n", tmp_checksum);else{printf(" 来自 %d.%d.%d.%d 的回复: ID=%x 字节=%d \r\n",(addr[0]), (addr[1]), (addr[2]), (addr[3]), htons(PingReply.ID), (rlen + 6));ping_reply_received = 1; /*当退出ping回复循环时,设置ping回复标志为1*/}}else if (data_buf[0] == PING_REQUEST){PingReply.Code = data_buf[1];PingReply.Type = data_buf[2];PingReply.CheckSum = (data_buf[3] << 8) + data_buf[2];PingReply.ID = (data_buf[5] << 8) + data_buf[4];PingReply.SeqNum = (data_buf[7] << 8) + data_buf[6];for (i = 0; i < len - 8; i++){PingReply.Data[i] = data_buf[8 + i];}tmp_checksum = PingReply.CheckSum; /*检查ping回复次数*/PingReply.CheckSum = 0;if (tmp_checksum != PingReply.CheckSum){printf(" \n CheckSum is in correct %x shold be %x \n", (tmp_checksum), htons(PingReply.CheckSum));}else{}printf("  Request from %d.%d.%d.%d  ID:%x SeqNum:%x  :data size %d bytes\r\n",(addr[0]), (addr[1]), (addr[2]), (addr[3]), (PingReply.ID), (PingReply.SeqNum), (rlen + 6));ping_reply_received = 1; /* 当退出ping回复循环时,设置ping回复标志为1  */}else{printf(" Unkonwn msg. \n");}return 0;
}void do_ping(uint8_t sn, uint8_t *ip)
{if (req < 4){printf("------------------PING test start-----------------------\r\n");sleep_ms(1000);ping_auto(sn, ip);}else if (req == 4)close(sn);
}

2. 通过SOCKET-less命令实现(硬件)

我们找到SLping()函数,它需要我们传入两个参数:ping测试远程IP地址和ping测试次数,然后我们配置相应的SOCKET-less重传时间、重传次数、远程IP地址、中断屏蔽寄存器,然后根据传入的参数值设置ping次数,传入的值为0则将其设置为数据类型的最大值;接着在for循环里面,设置ping序列号和ID,并开启ping请求发送命令,用Switch状态机轮询中断寄存器,根据中断置位情况进行相应处理,这里分为超时和收到ping应答两个状态(情况),最后统计请求和应答成功、失败数后,进入阻塞;如下所示:

/*** socket-less ping* remote_ip:  ping ip address* ping_count: ping times, if its 0,always request to the max :65535 times.*/
void SLping(uint8_t *remote_ip, uint16_t ping_count)
{uint16_t i;static uint16_t succ_count = 0;setSLRTR(5000); // 5000 * 100us = 500mssetSLRCR(2);setSLPIPR(remote_ip);setSLIMR(0x05);if (ping_count == 0)ping_count = 65535;for (i = 0; i < ping_count; i++){printf("Ping the %d.%d.%d.%d \r\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]);setPINGSEQR(RandomSeqNum);setPINGIDR(RandomID);setSLCR(0X01);  // pingsleep_ms(2000); // waitswitch (getSLIR() & 0x07){case PING_INT:printf("Reply from %d.%d.%d.%d : ID: %x SeqNum: %x.\r\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3], getPINGIDR(), getPINGSEQR());succ_count++;break;case TIMEOUT_INT:printf("Request timeout\r\n");default:break;}RandomID++;RandomSeqNum++;}printf("Ping request: %d, Succ: %d, Fail: %d.\r\n", ping_count, succ_count, (ping_count - succ_count));while (1);
}

主程序只需要初始化相关对应信息后,传入主函数循环调用即可,这里我们要进行ping测试的主机IP为我们开发板同一网段的电脑IP,如下所示:

#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)void network_init(void);wiz_NetInfo net_info = {.mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},.ip = {192, 168, 1, 11},.sn = {255, 255, 255, 0},.gw = {192, 168, 1, 1},.dns = {8, 8, 8, 8},.dhcp = NETINFO_STATIC};
wiz_NetInfo get_info;
static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint8_t remote_ip[4] = {192, 168, 1, 2};int main()                                                          
{   stdio_init_all();sleep_ms(2000);network_init();while(true){do_ping(SOCKET_ID, remote_ip);// SLping(remote_ip, 4);sleep_ms(500);}
}void network_init(void)
{uint8_t temp;wizchip_initialize();printf("W5100s udp client example.\r\n");sleep_ms(2000);wizchip_setnetinfo(&net_info);print_network_information(get_info);sleep_ms(2000);   
}

2. 测试现象

编译烧录后,打开串行监视器,打开wireshark输入过滤条件<icmp>然后开启监听,可以看到在串口打印的配置信息,以及ping测试情况,wireshark的抓包情况,这里是通过软件实现的测试,硬件实现大家自行尝试;测试结果如下图所示:

相关链接

本章例程链接icon-default.png?t=N7T8https://gitee.com/wiznet-hk/w5100s-evb-pico-routine.git

这篇关于W5100S+树莓派RP2040快速入门之PING篇(十)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/171544

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者