STM32:实现ping命令(lwip)

发布于:2024-12-08 ⋅ 阅读:(153) ⋅ 点赞:(0)

1.实现步骤

在STM32上使用LwIP库实现ping功能涉及几个步骤。LwIP(Lightweight IP)是一个轻量级的TCP/IP协议栈,它被设计为可以在资源有限的系统中运行。为了在STM32上实现ping功能,你需要确保以下几点:

  1. 配置和初始化LwIP:
    •确保你已经在你的STM32项目中正确地集成了LwIP库。
    •配置网络接口(例如以太网或Wi-Fi),包括MAC地址、IP地址、子网掩码和默认网关。
    •初始化LwIP堆栈。
  2. 设置网络接口:
    •如果你使用的是以太网,需要配置并启用以太网外设。
    •如果是无线网络,则需要配置Wi-Fi模块,并连接到一个可用的无线网络。
  3. 创建Ping线程或任务:
    •在FreeRTOS环境中,你可以创建一个新的任务来处理Ping请求。
    •如果没有操作系统,你可以将Ping代码放在主循环中的适当位置。
  4. 编写Ping函数:
    •使用LwIP提供的API来发送ICMP Echo请求(即Ping请求)。这通常涉及到调用icmp_ping_send函数或类似的功能。
    •你可以通过ping命令行工具或者自己实现一个简单的用户界面来触发Ping操作。
  5. 处理响应:
    •LwIP会自动处理接收到的ICMP Echo回复,并调用相应的回调函数。
    •你需要实现一个回调函数来处理这些回复,比如计算往返时间(RTT)并打印结果。
  6. 测试和调试:
    •连接到你的开发板,并尝试Ping一个已知的IP地址(如8.8.8.8,这是Google的公共DNS服务器之一)。
    •检查输出结果,确认是否成功接收到了回复。

2.源码分析

2.1 初始化函数

设置目标IP地址和本地IP地址,创建并绑定一个新的协议控制块(PCB),以及设置接收回调函数

void Ping_Init(void)
{
    
    IP4_ADDR(&dest_ip,192,168,1,188);
    IP4_ADDR(&local_ip,192,168,1,30);
    /*bind local IP.*/
    LOG_INFO("local IP address:%4d.%4d.%4d.%4d\r\n",ip4_addr1(&local_ip),\
                                                    ip4_addr2(&local_ip),\
                                                    ip4_addr3(&local_ip),\
                                                    ip4_addr4(&local_ip));
    /*bind dest IP.*/
    LOG_INFO("dest IP address:%4d.%4d.%4d.%4d\r\n", ip4_addr1(&dest_ip),\
                                                    ip4_addr2(&dest_ip),\
                                                    ip4_addr3(&dest_ip),\
                                                    ip4_addr4(&dest_ip));    
    /*allocate a new pcb*/
    ping_pcb = raw_new(IP_PROTO_ICMP);//set IP protocol type to ICMP
    if(NULL == ping_pcb) {
   
        LOG_INFO("get n new raw pcb failed.\r\n");
        return;
    }
		
    raw_bind(ping_pcb,&local_ip);//bind local IP to pcb.
    raw_recv(ping_pcb,recv_callback,NULL);
}

2.2 发送函数

函数参数:
1.void *arg:这是一个指向raw_pcb结构体的指针,该结构体代表一个原始协议控制块(PCB),用于处理原始套接字通信。在这个函数中,它被用来发送ICMP Echo请求(即Ping请求)。
2.ip_addr_t dst_ip:这是目标IP地址,表示Ping请求应该发送到的设备。
3.Ping任务状态检查:
首先,函数检查一个全局变量ping_completed,以确定Ping任务是否已经完成。如果已完成,则函数立即返回。
4.发送次数检查:
接着,函数检查已发送的Ping请求数量(ping_count)是否已达到预设的最大值(PING_MAX_COUNT)。如果是,则将ping_completed设置为1,将ping_state设置为PING_STATE_COMPLETED,并记录已收到的回复数量(reply_count),然后返回。
5.获取PCB:
从arg参数中获取raw_pcb结构体的指针。
6.分配pbuf:
使用pbuf_alloc函数为ICMP Echo请求分配内存。请求的内存大小是ICMP头部大小加上一个消息字符串的大小(message),这里假设message是一个在函数外部定义的全局变量或常量字符串。
如果内存分配失败,则记录错误并返回。
7.检查pbuf大小:
确保分配的pbuf足够大,以容纳ICMP头部和消息数据。如果不够大,则释放pbuf并返回。
8.设置ICMP头部:
初始化ICMP Echo请求的头部字段,包括类型(type,设置为Ping请求)、代码(code)、校验和(chksum,这里初始化为0,因为LwIP协议栈在发送前会自动计算并填充正确的校验和)、标识符(id)和序列号(seqno)。
9.添加数据:
将消息数据复制到ICMP Echo请求的数据部分。这里假设message是一个包含要发送数据的字节数组。
10.发送数据包:
使用raw_sendto函数发送ICMP Echo请求。这个函数需要PCB、pbuf和目标IP地址作为参数。
记录发送时间和请求数量:
更新全局变量last_send_time为当前系统时间(使用sys_now函数获取),并增加ping_count的值。
11.释放pbuf:
在发送之后,释放之前为ICMP Echo请求分配的pbuf。

void Ping_Send(void *arg,ip_addr_t dst_ip)
{
   
    struct pbuf *icmp_pbuf = NULL;
    struct raw_pcb  *pcb = NULL;
    struct icmp_echo_hdr *icmp_hdr = NULL;
    u8_t *data_ptr = NULL;
    u8_t i =0;
	
	
	    // 检查Ping任务是否已完成
    if (ping_completed) {
   
        return;
    }

    // 检查是否达到最大发送次数
    if (ping_count >= PING_MAX_COUNT) {
   
        ping_completed = 1;
        ping_state = PING_STATE_COMPLETED;
        LOG_INFO("Ping completed: max count reached, %d replies received.\r\n", reply_count);
        return;
    }

    pcb = (struct raw_pcb*)arg;

    /* IP header(pre allocated) + payload(ICMP header + data)    */
    icmp_pbuf = pbuf_alloc(PBUF_IP,sizeof(struct icmp_echo_hdr) + sizeof(message),PBUF_POOL);//allocate memory;
    if(NULL == icmp_pbuf)
    {
   
        LOG_INFO("pbuf_alloc() failed.\r\n");
        return;
    }
		
		// 确保 pbuf 的长度足够
		if (icmp_pbuf->len < sizeof(struct icmp_echo_hdr) + sizeof(message)) {
   
				LOG_INFO("pbuf too small to hold ICMP header and data.\r\n");
				pbuf_free(icmp_pbuf);
				return;
		}		
		
    icmp_hdr = (struct icmp_echo_hdr*)icmp_pbuf->payload; 

    //set ICMP info.
    icmp_hdr->type = PING_REQUEST;
    icmp_hdr

网站公告

今日签到

点亮在社区的每一天
去签到