stm32 重置ip地址(udp单播)

实现了利用udp通信去重新设置mcu的ip地址、子网掩码、网关
udp使用的是静态的ip
默认已经用cubemx配好ETH、lwip已经配好并能进行udp通信

关于udp的配置可看这位大佬
用cubemx配置生成udp代码

1、ip信息结构体

  • 为了方便使用,需要自定义
  • 不同的lwip驱动ip4_addr_t可能不同
struct IP_INFO{
	uint8_t ip_addr[4];
	uint8_t netmask_addr[4];
	uint8_t gateway_addr[4];
	ip4_addr_t ip;//地址
	ip4_addr_t nm;//掩码
	ip4_addr_t gw;//网关
};

struct IP_INFO ip_info;

2、修改ip的核心函数

  • 一般cubemx生成的代码在lwip.c中会有NET_set_addr
  • 只需要将绑定好的ip地址、掩码、网关传给NET_set_addr就行
  • 需要用这个函数:IP4_ADDR 来绑定你的ip地址、网关等
/*
使用示例
IP4_ADDR(&ip_info.ip,192,168,2,100);//掩码和网关也是这样绑
......
NET_set_addr(&ip_info.ip, &ip_info.nm,&ip_info.gw);
*/
void NET_set_addr(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
    const ip4_addr_t *gw)
{
  if (ip4_addr_isany(ipaddr)) {
    /* when removing an address, we have to remove it *before* changing netmask/gw
       to ensure that tcp RST segment can be sent correctly */
    netif_set_ipaddr(&gnetif, ipaddr);
    netif_set_netmask(&gnetif, netmask);
    netif_set_gw(&gnetif, gw);
  } else {
    netif_set_netmask(&gnetif, netmask);
    netif_set_gw(&gnetif, gw);
    /* set ipaddr last to ensure netmask/gw have been set when status callback is called */
    netif_set_ipaddr(&gnetif, ipaddr);
  }
}

3、从消息里获取ip信息

  • 需要一个全局变量struct IP_INFO ip_info;
  • 命令格式(前面可自定义 只需修改函数中i的初始值)
    $setip<xxx.xxx.xxx.xxx><xxx.xxx.xxx.xxx><xxx.xxx.xxx.xxx>
    最好做个判断决定是否要进入消息解析函数
  • 加入了输入语法检测,即保证拿到的是12个数字
    无法保证这12个数字是否合法
/*用于从消息中获取要设置的ip地址等信息*/
struct ip_tmp_udp{
	uint8_t tmp[3];
	int8_t count;
};
/*********************************************************************
功  能:将字符串转换数字
示例
   str.tmp[0] = 1
   str.tmp[1] = 9
   str.tmp[2] = 2
   转化后
   dest = 192
*********************************************************************/
void udp_string_to_num(struct ip_tmp_udp str,uint8_t *dest){
	
	uint8_t num = 0;
/*
	这段有问题,会传出奇怪的值
	int i = 0;
	str.count--;
	while(1){
	 if(tr.count < 0){
	  break;
	 }
	 num = num + str.tmp[i]*10^str.count;
	 i++;
	 str.count--;
	}
*/
	if(str.count == 3){
		num = str.tmp[0]*100+str.tmp[1]*10+str.tmp[2];
	}
	else if(str.count == 2){
		num = str.tmp[0]*10+str.tmp[1];	
	}
	else{
		num = str.tmp[0];		
	}
	
	*dest = num;
}

/*********************************************************************
功  能:从数据中获取ip地址,子网掩码,网关等信息
					ip                掩码           网关
命令:$setip<xxx.xxx.xxx.xxx><xxx.xxx.xxx.xxx><xxx.xxx.xxx.xxx>
循环1:解析xxx,由于xxx的位数不确定(可能为3,2,1位)  
循环2:解析<...>
循环3:解析<><><>
*********************************************************************/
void udp_GetIp_AND_Reset(char *recv_msg){
	
	char send_data[128] = {0};
	uint8_t left = 0;//计数<
	uint8_t right = 0;//计数>
	uint8_t i = 6;//遍历recv_msg;
	uint8_t j = 4;//计数“.”

	uint8_t check = 1;//检测输入合法性 1合法,0不合法
	
	struct IP_INFO ip_info_tmp;
	struct ip_tmp_udp str;//暂存xxx

	//读到$setip进入本循环
	while(check)//循环3
	{

		if(i > 57 || right > 4 || j <4)//异常结束循环
		{	
			sprintf(send_data,"(1)fail to setip : %d\r\n",i);				
			check = 0;
		}
		else if(right == 3 && right == left)//正常结束所有循环
		{
			break;
		}
					
		if(recv_msg[i] == '<')
		{
			i++;  //recv_msg[i] == '<' 所以要i+1;
			
			j = 0;//“.”计数置0
			while(recv_msg[i-1] != '>' && check)//循环2
			{
				str.count = 0;
				/* <xxx.xxx.xxx.xxx> <>*/
				while(recv_msg[i] != '.' && recv_msg[i] != '>' && check)//循环1
				{
					
					/* xxx每一位合理的范围是 0 ~ 9 */
					if(recv_msg[i]>57 || recv_msg[i]<48)
					{
		        sprintf(send_data,"(2)fail to setip : %d\r\n",i);							
						check = 0;
						break;						
					}
					str.tmp[str.count] = recv_msg[i]-48;//逐位复制xxx
					str.count++;//xxx 计数+1
					
					/* xxx合理位数为1~3,<xxxx.xx*/
					if(str.count >3)
					{
						sprintf(send_data,"(3)fail to setip : %d\r\n",i);
						check = 0;
						break;
					}
					
					i++;
				}
				
				/* xxx合理位数为1~3,<xxx..xxx提醒出错的位数 */
				if(str.count == 0)
				{
					sprintf(send_data,"(4)fail to setip : %d\r\n",i);
					check = 0;
					break;
				}
				
				
				if(check)
				{
					if(left == 0)
					{
						udp_string_to_num(str,&ip_info_tmp.ip_addr[j]);
					}
					else if(left == 1)
					{
						udp_string_to_num(str,&ip_info_tmp.netmask_addr[j]);
					}
					else
					{
						udp_string_to_num(str,&ip_info_tmp.gateway_addr[j]);
					}						
				}

				j++;//“.”计数+1
			
				if(j > 4)
				{
					sprintf(send_data,"(5)fail to setip : %d\r\n",i);						
					check = 0;
					break;
				}
				
				i++;
				
			}
		 left++;
	 }
			
	right++;
		 
 }

	if(check)
	{
		for(i = 0;i<4;i++){
			ip_info.ip_addr[i] = ip_info_tmp.ip_addr[i];
			ip_info.netmask_addr[i] = ip_info_tmp.netmask_addr[i];
			ip_info.gateway_addr[i] = ip_info_tmp.gateway_addr[i]; 
		}
		sprintf(send_data,"step1 of setip is complete\r\n");
		
		
		if(1) //ip 掩码 网关 合法性检测(未完成)
		{
			udp_ResetIp();//重置ip
		}

	}
		
//	udp_app_send(send_data,strlen(send_data));//消息回传到指定地址	
	
}

4、接收回调函数

  • 我是先解析一次消息再调用的上面的函数
static void udp_receive_callback(void *arg, struct udp_pcb *pcb,
	 struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
	char udp_msg[512] = {0};
	
	if(p!=NULL){
		
		pbuf_copy_partial(p,(void *)udp_msg,p->len,0);//这样复制不会有乱码
		
		udp_app_sendto(udp_msg,strlen(udp_msg),*addr,port);//消息回传,并重置udp发送端口
		
		udp_parse_cmd(udp_msg);//命令解析
	
		pbuf_free(p);
	} 
}

5、运行截图

  • 修改测试

在这里插入图片描述

  • 语法检测(仅能检测 $setip后面)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值