LWIP版本:V3.2
最近要使用LWIP协议实现组播,由于此前并不知道这个板卡,对嵌入式也不算熟悉,平时还有其他的任务,前前后后忙了近两个月,后来发现实现过程非常简单,下面介绍我的实现过程。
首先,使用STM32F4时不用完全自己搭建环境的,到官网下载类似于stsw-stm32070.zip的文件包,里面包含了多个典型的Keil uVision工程,配置一下就能用。这个过程改天再写个文档。multicast.h文件的代码为:
#ifndef __MULTICAST__H
#define __MULTICAST__H
#include "stm324xg_eval_sdio_sd.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include "lwip/igmp.h"
/*port */
#define UDP_MULTICASE_RECV_PORT 1178 // multicast port for recive
#define UDP_MULTICASE_SEND_PORT 1180 // multicast port for send
#define LWIP_DEMO_BUF 2048
#endif
multicast.c的代码为:
#include "multicast.h"
struct udp_pcb* udp_server_multi_pcb;//组播PCB控制块
struct ip_addr ipgroup_rev,ipgroup_send;
u16 lwip_demo_buf_len = 0;
u8_t lwip_demo_buf[LWIP_DEMO_BUF];
//UDP发送
void multicast_send_data(unsigned char * data,unsigned short len)
{
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT,len, PBUF_RAM);
memcpy(p->payload, data, len);
udp_sendto(udp_server_multi_pcb, p,(struct ip_addr *) (&ipgroup_send),UDP_MULTICASE_SEND_PORT);//1180
pbuf_free(p);
}
//组播接收,回调函数
void udp_server_rev(void* arg,struct udp_pcb* upcb,struct pbuf* p,struct ip_addr*addr ,u16_t port){
int i,j;
if(p!=NULL){
if((p->tot_len)>=LWIP_DEMO_BUF){ //如果长度过长则额外处理
memcpy(lwip_demo_buf,p->payload,LWIP_DEMO_BUF);
lwip_demo_buf_len = LWIP_DEMO_BUF;
}else{
memcpy(lwip_demo_buf,p->payload,p->tot_len);
lwip_demo_buf_len = p->tot_len;
}
for(i=0;itot_len;i++)//测试组播时,有时候即使没发出去也可能显示收到,因此,我这里将收到的数据加2,以作区分
{
printf("%02x ",lwip_demo_buf[i]);
lwip_demo_buf[i]=lwip_demo_buf[i]+2;
}
printf("\n");
}
}
void Multicast_Config()
{
int i;
IP4_ADDR(&ipgroup_rev, 230,1,1,11);//用于接收组播的地址
IP4_ADDR(&ipgroup_send, 230,12,2,22);//用于发送组播的地址
igmp_joingroup(IP_ADDR_ANY,(struct ip_addr *)(&ipgroup_rev));//只需要将接收地址放入igmp组,发送的不需要
udp_server_multi_pcb = udp_new();
if(udp_server_multi_pcb!=NULL){
udp_bind(udp_server_multi_pcb,IP_ADDR_ANY,UDP_MULTICASE_RECV_PORT);//组播接收地址1178
udp_recv(udp_server_multi_pcb,udp_server_rev,NULL);//
}
}
//测试发送的方法
void UDP_Send()
{
multicast_send_data(lwip_demo_buf,lwip_demo_buf_len);
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if(flash==1)
{
STM_EVAL_LEDOff(LED1);
flash=0;
}
else
{
STM_EVAL_LEDOn(LED1);
flash=1;
}
UDP_Send();
}
}
void lwip_demo(void *pdata)
{
struct netconn *conn;
struct ip_addr local_addr,group_addr,remote_addr;
lwip_init_task();
EnableMacInt();
IP4_ADDR(&local_addr,192,168,1,37);
IP4_ADDR(&group_addr,233,0,0,6);
IP4_ADDR(&remote_addr,192,168,1,78);
conn=netconn_new(NETCONN_UDP);
netconn_bind(conn,NULL,9090);
netconn_join_leave_group(conn,&group_addr,&local_addr,NETCONN_JOIN);
while(1)
{
struct netbuf *inbuf;
inbuf = netconn_recv(conn);
if(inbuf!=NULL)
{
netconn_sendto(conn,inbuf,&remote_addr,8080);
netbuf_delete(inbuf);
}
}
netconn_delete(conn);
}
在无操作系统的环境下使用组播的关键在于前面我们提到的
添加
igmp_tmr()的调用,它能保证板子可以在一定的周期内监听网络上发来的组播流。如果你对嵌入式编程很熟悉,这一点不难理解,如果像我一样习惯了高级编程语言的风格,会一直想不明白。