打印
[其他ST产品]

stm32f207实现组播

[复制链接]
261|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
SHOPQQ|  楼主 | 2023-7-26 18:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
背景
第一次使用lwip,在网上看了很多文章,一步步实现了freeRtos与lwip的移植,关于freeRtos与lwip的移植已经有很多可以参考的文章了,就不赘述了。这里主要讲讲我如何实现组播的,因为遇到一些坑,并且如何解决的。

实现组播的流程
第一步、配置LWIP
在lwipopts.h中,将LWIP_IGMP改为1,使能组播代码的编译。

/* ---------- IGMP options ---------- */
#define LWIP_IGMP                       1

第二步、编写组播实现代码

此前没有用过lwip,不会使用netconn。所幸lwip实现了socket接口。socket实现组播,网上有很多文章可以学习,这里和是否使用lwip没关系。…


使用特权

评论回复
沙发
SHOPQQ|  楼主 | 2023-7-26 18:50 | 只看该作者
实现组播接收
#define MULTICAST_ADDR "239.2.1.22"
#define UDP_RCV_PORT 1234

typedef struct{
        int fd;
        struct sockaddr_in sockServer;
        struct sockaddr_in sockClient;
        uint8_t rcvData[1024];
        int rcvLen;
}SocketInfo_ts;

SocketInfo_ts udpClient;
//create a udp socket
int iCreatUdpClient(SocketInfo_ts* udpSock)
{
    struct ip_mreq group;
   
    if((udpSock->fd=socket(AF_INET,SOCK_DGRAM,0))<0)
    {
        return 0;
    }
   
    udpSock->sockClient.sin_family=AF_INET;
    udpSock->sockClient.sin_port=htons(UDP_RCV_PORT);
    udpSock->sockClient.sin_addr.s_addr=htonl(INADDR_ANY);
    if(bind(udpSock->fd,(struct sockaddr*)&udpSock->sockClient,sizeof(struct sockaddr_in))<0)
    {
        return 0;
    }
       
        group.imr_interface.s_addr=htons(INADDR_ANY);
        group.imr_multiaddr.s_addr=inet_addr(MULTICAST_ADDR);
        setsockopt(udpSock->fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&group,sizeof(group));
       
        return 1;
}
void vUdpThread(void* argument)
{
    uint32_t fromSize;
    fd_set fdSockSet;
    struct timeval timeout;
   
    //init udpClient
    iCreatUdpClient(&udpClient);
    for(;;)
    {
                FD_ZERO(&fdSockSet);
                FD_SET(udpClient.fd,&fdSockSet);
               
                timeout.tv_sec=1;
                timeout.tv_usec=0;
                if(select(udpClient.fd+1,&fdSockSet,NULL,NULL,&timeout)>0)
                {
                        if(FD_ISSET(udpClient.fd,&fdSockSet))
                        {
                                fromSize=sizeof(struct sockaddr_in);
                                udpClient.rcvLen=recvfrom(udpClient.fd,udpClient.rcvData,1024,0,(struct sockaddr*)&udpClient.sockServer,&fromSize);
                        }
                }
    }
}

/*-----------------------------------------------------------------------------------*/
void vUdpInit(void)
{
    sys_thread_new("udp_thread", vUdpThread, NULL, DEFAULT_THREAD_STACKSIZE,UDP_THREAD_PRIO );
}

使用特权

评论回复
板凳
SHOPQQ|  楼主 | 2023-7-26 18:51 | 只看该作者
实现组播发送
这里和普通发送差不多,只要将目的地址改为组播地址就行。

第三步、编译验证
编译没什么问题,有问题就改改,然后通过。网络调试助手用起来……
结果当然是失败了,看来没那么简单,啪啪打脸。
接着只能自己一步步查了,程序通过setsockopt(udpSock->fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&group,sizeof(group))实现组播,先查查这个函数,一步步打断点。发现了一个异常igmp.c中,igmp_joingroup函数中igmp_joingroup_netif没有执行,查看了netif->flag这里NETIF_FLAG_IGMP标志没有设置。

使用特权

评论回复
地板
SHOPQQ|  楼主 | 2023-7-26 18:51 | 只看该作者
程序修改点1
修改在ethernetif.c中low_level_init函数添加NETIF_FLAG_IGMP

netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_IGMP | NETIF_FLAG_ETHARP;

修改后,还是不能接收数据,看来还有问题啊。单播通信是可以的。发现网络调试助手发送组播后,网卡对应的中断都没有触发。
网卡初始化程序是抄的(参考)是st官方demo。查看了STM32技术手册,发现里面有组播/广播以及过滤器的说明。抱着疑惑的态度将网卡初始化代码看了。在结构体ETH_MACInitTypeDef中发现一个成员变量ReceiveAll设置是ETH_RECEIVEAll_DISABLE,将其改为ETH_RECEIVEALL_ENABLE试试。还有个成员变量MulticastFramesFilter注释说明该变量与组播有关,也可以改改。经测试,这里两种更改都可行。这里很多东西包括如何配置过滤器,都可以去看官方的文档。

使用特权

评论回复
5
SHOPQQ|  楼主 | 2023-7-26 18:51 | 只看该作者
程序更改点2
更改方式1
修改stm32f2xx_hal_eth.c中函数ETH_MACDMAConfig,接收所有数据包,如下
/*************************************************/
  macinit.ReceiveAll = ETH_RECEIVEALL_ENABLE;
/****************************************************/

使用特权

评论回复
6
SHOPQQ|  楼主 | 2023-7-26 18:51 | 只看该作者
更改方式2
也是函数ETH_MACDMAConfig中,取消针对组播的过滤
/********************************************************/
macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_NONE;
/*******************************************************/

使用特权

评论回复
7
SHOPQQ|  楼主 | 2023-7-26 18:51 | 只看该作者
可以接收组播数据了。
只是电脑和pcb板一对一连接也不需要什么组播。用路由器、交换机,多个网络主机、多个开发板组个局域网,也能收发,可惜好景不长,接收了没多久,就收不到数据。
网口接收中断也不触发,然后抓包,发现交换机没有给板子发数据了(而使用路由器可以)。当时想交换机有bug啊,都不发数据了。但是用其他板子,可以正常收到数据,就stm32的不行,打电话问过交换机厂家,也不清楚具体原因。
看了只能自己好好了解下组播的机制,继续看文档。发现组播协议有自己的membership query与membership reports。

使用特权

评论回复
8
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
补充说明,市面上部分路由器、交换机并没有去实现组播,而是采用广播的方式。将组播数据直接转发出去,没有根据query与report建立对应的组播表,根据表实现转发。具体内容可以参考其他文章

使用特权

评论回复
9
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
抓包发现,板子就最初发送过membership reports,后面就没有发送了。查看了lwip里关于组播的api,这里有个igmp_report_groups,调用定时发送membership report。这个函数并不会report组播地址出来。调用igmp_lookfor_group,组播地址有加入netif里面。查看实现report代码。有如下语句,通过注释了解到是要跳过224.0.0.1这个地址。

使用特权

评论回复
10
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
        /* Do not send messages on the all systems group address! */
     /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
        if (groupref != NULL) {
                 groupref = groupref->next;
        }

使用特权

评论回复
11
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
每次会跳过第一个组播地址(实际该地址是通过socket的配置组播地址),又查看了igmp_lookup_group实现组播地址的添加,这里通过链表实现,224.0.0.1这个地址放在最后的,不应该跳过第一个地址。

使用特权

评论回复
12
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
程序更改点3
igmp.c中把如下代码注释掉就行。在igmp_delaying_member中判断地址不等于224.0.0.1。

使用特权

评论回复
13
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
  /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
//  if (group != NULL) {
//    group = group->next;
//  }

使用特权

评论回复
14
SHOPQQ|  楼主 | 2023-7-26 18:52 | 只看该作者
每次会跳过第一个组播地址(实际该地址是通过socket的配置组播地址),又查看了igmp_lookup_group实现组播地址的添加,这里通过链表实现,224.0.0.1这个地址放在最后的,不应该跳过第一个地址。

使用特权

评论回复
15
SHOPQQ|  楼主 | 2023-7-26 18:53 | 只看该作者
程序更改点3
igmp.c中把如下代码注释掉就行。在igmp_delaying_member中判断地址不等于224.0.0.1。
  /* Skip the first group in the list, it is always the allsystems group added in igmp_start() */
//  if (group != NULL) {
//    group = group->next;
//  }

使用特权

评论回复
16
SHOPQQ|  楼主 | 2023-7-26 18:53 | 只看该作者
本打算去lwip上提交更改意见,但查看了后面的版本,该问题已经修复了。这里建议使用较新的lwip,新版本修复了许多问题,也添加了如mqtt等新功能。

结束语
这里网口芯片最初使用的是LAN8742A,后续开发板使用了DP83848,也是可以使用的。**的本文能给大家一点参考。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

183

帖子

0

粉丝