基于个人兴趣,决定实现一个和方案公司提供的uboot收发广播的功能。记录笔记如下。
SDK版本:Hi3518E_V100R001C01SPC081
1. 由于我手头的板子的Phy是RMII模式,因此先按这篇帖子进行将uboot默认的网络驱动改为RMII模式。
http://blog.csdn.net/skdkjzz/article/details/39931915
2. 然后设置好Phy的CONFIG_PHY_ADDR_U和CONFIG_PHY_ADDR_D,这个我不太懂是为什么,估计和硬件有关,各位看官可能这里不能完全照抄,我有空翻一翻Phy的规格书。编辑 u-boot-2010.06\include\configs\hi3518e.h
3. 在common目录下新建文件cmd_udp.c,新建一个uboot cmd
1 #include <common.h> 2 #include <command.h> 3 #include <net.h> 4 5 char _ctoi(char c) 6 { 7 if(c>=‘0‘&&c<=‘9‘)return c-‘0‘; 8 if(c>=‘a‘&&c<=‘f‘)return c-‘a‘+10; 9 return 0; 10 } 11 12 int _atoi(char* s) 13 { 14 unsigned int a=0; 15 unsigned int b=0; 16 int i=0; 17 while(s[i]){ 18 a*=10; 19 a+=_ctoi(s[i]); 20 i++; 21 } 22 return a; 23 } 24 25 int _atox(char* s) 26 { 27 unsigned int a=0; 28 unsigned int b=0; 29 int i=0; 30 while(s[i]){ 31 a<<=4; 32 a|=_ctoi(s[i]); 33 i++; 34 if(i>=8)break; 35 } 36 return a; 37 } 38 39 int _strlen(char*s) 40 { 41 int i=0; 42 while(s[i]){ 43 i++; 44 } 45 return i; 46 } 47 48 void _getmac(char* s,char* eth) 49 { 50 unsigned char a=0; 51 int i=0; 52 while(s[i]){ 53 a<<=4; 54 a|=_ctoi(s[i]); 55 if((i&1)==1){ 56 eth[i>>1]=a; 57 a=0; 58 } 59 i++; 60 } 61 } 62 63 int do_udp_broadcast(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 64 { 65 uchar eth[6]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 66 char* UdpServerIP="255.255.255.255"; 67 int dest_port = 25500, src_port =25300; 68 uchar *str; 69 int len; 70 71 switch(argc){ 72 case 1: 73 puts("Params error, try again\nusage: [udp_b] [string] or [udp_b] [dest_port] [src_port] [string]\n"); 74 return 1; 75 break; 76 case 2: 77 str = argv[1]; 78 len = strlen(str); 79 break; 80 case 4: 81 dest_port = _atoi(argv[1]); 82 src_port = _atoi(argv[2]); 83 str = argv[3]; 84 len = strlen(argv[3]); 85 break; 86 default: 87 return 1; 88 break; 89 } 90 91 printf("len=%d\n",len); 92 show_boot_progress(80); 93 if(NetLoop_UDP(eth,UdpServerIP,dest_port,src_port,str,len)<0){ 94 show_boot_progress(-81); 95 return 1; 96 } 97 98 return 0; 99 } 100 101 U_BOOT_CMD( 102 udp_b, 4, 1, do_udp_broadcast, 103 "Send or receive UDP broadcast to/from server using UDP protocol", 104 "[udp_b] [string] or [udp_b] [dest_port] [src_port] [string]" 105 );
4. 给common目录的makefile添加
COBJS-$(CONFIG_CMD_UDP) += cmd_udp.o
5. 在net目录新建文件udp处理函数,udp.c和udp.h
udp.c
1 #include <common.h> 2 #include <watchdog.h> 3 #include <command.h> 4 #include <net.h> 5 #include <miiphy.h> 6 #include "udp.h" 7 8 void 9 UdpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) //这个函数是处理包,先放下,有空再写 10 { 11 //printf("handler udp packet\n"); 12 printf("Receive udp packet: %s\n",pkt); 13 } 14 15 void 16 udpSend(void) 17 { 18 uchar *pkt; 19 pkt = (uchar *)NetTxPacket; 20 pkt += NetSetEther(pkt, UdpServerEther, PROT_IP); 21 NetSetIP (pkt, UdpServerIP, UdpServerPort, UdpOurPort, data_len); 22 pkt += IP_HDR_SIZE; 23 memcpy(pkt, pkt_data, data_len); 24 (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + data_len); 25 } 26 27 void 28 UdpStart(const uchar *remoteeth, char *remoteip, int remoteport,int thisport, const char *data, int datalength) 29 { 30 UdpServerEther = remoteeth; 31 UdpServerIP = string_to_ip(remoteip); 32 UdpServerPort = remoteport; 33 UdpOurPort = thisport; 34 pkt_data = data; 35 data_len = datalength; 36 37 udpSend(); 38 printf("Send,ready to receive...\n"); 39 }
udp.h
1 #ifndef __UDP_H__ 2 #define __UDP_H__ 3 4 static uchar *UdpServerEther; 5 static IPaddr_t UdpServerIP; 6 static int UdpServerPort;/* The UDP port at their end 7 */ 8 static int UdpOurPort;/* The UDP port at our end 9 */ 10 static uchar *pkt_data; 11 static int data_len; 12 13 void UdpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len); 14 15 #endif
5. 修改net目录的net.c,在最下面加入NetLoop_UDP函数,并添加udp.h头文件引用 #include "udp.h"
1 int 2 NetLoop_UDP(const uchar* remorteth, char* remoteip, int remoteport, int thisport, const char* data, int datalength) 3 { 4 bd_t *bd = gd->bd; 5 6 /* XXX problem with bss workaround */ 7 NetTxPacket = NULL; 8 9 if (!NetTxPacket){ 10 int i; 11 /* 12 * Setup packet buffers, aligned correctly. 13 */ 14 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); 15 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; 16 for (i = 0; i < PKTBUFSRX; i++) { 17 NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN; 18 } 19 } 20 21 eth_halt(); 22 if (eth_init(bd) < 0) { 23 eth_halt(); 24 return(-1); 25 } 26 27 restart: 28 eth_getenv_enetaddr("ethaddr", NetOurEther); 29 /* 30 * Start the ball rolling with the given start function. From 31 * here on, this code is a state machine driven by received 32 * packets and timer events. 33 */ 34 NetInitLoop(TFTP); 35 36 switch (net_check_prereq (TFTP)) { 37 case 1: 38 /* network not configured */ 39 eth_halt(); 40 return (-1); 41 42 case 0: 43 NetSetHandler(UdpHandler); 44 UdpStart(remorteth,remoteip, remoteport, thisport, data, datalength); 45 break; 46 } 47 48 /* 49 * Main packet reception loop. Loop receiving packets until 50 * someone sets `NetState‘ to a state that terminates. 51 */ 52 for (;;) { 53 /* 54 * Check the ethernet for a new packet. The ethernet 55 * receive routine will process it. 56 */ 57 eth_rx(); 58 NetSetHandler(UdpHandler); 59 60 /* 61 * Abort if ctrl-c was pressed. 62 */ 63 if (ctrlc()) { 64 eth_halt(); 65 puts ("\nAbort by Ctrl+C\n"); 66 return (-1); 67 } 68 } 69 }
6. 修改net目录下的makefile,添加
COBJS-$(CONFIG_CMD_NET) += udp.o
7. 这样操作后可以通过udp_b命令发送和接收UDP广播了。实际跑在板子上能发送UDP广播,但接收不到UDP广播包。
经过查看芯片规格书之后,发现有寄存器可以屏蔽广播包,我们查看uboot网络驱动源码之后发现确实默认将UDP广播包屏蔽了。
那么我们修改\drivers\net\hisfv300下的glb.c
将 hieth_writel_bits(ld, 0, GLB_MACTCTRL, BITS_BROAD2CPU_UP); 修改为 hieth_writel_bits(ld, 1, GLB_MACTCTRL, BITS_BROAD2CPU_UP);
8. 修改部分到此结束,现在我们进行测试。我采用的测试工具是我自己用c#写的udp收发小工具,源码就不发了,很简单的小工具。
参考链接:
http://blog.csdn.net/skdkjzz/article/details/39931915
https://segmentfault.com/a/1190000005273491
http://www.ithao123.cn/content-10639610.html