TI DSP TMS320F28335上的TCP/IP协议栈
最近接了学校一个项目,需要在TMS320F28335+RTL8019AS平台上实现一个TCP/IP协议栈,网上找了大半圈,并没有发现相关实现,在嵌入式领域用的比较多的uip和lwip感觉体系太过于庞大,移植工作量较大,而且这两个协议栈目前都适合搭配操作系统使用,且bug不少,对于DSP28335这样性能一般的DSP来说,有点杀鸡用牛刀了。
后来,我找到了ZlIP(详细介绍:http://www.zlmcu.com/project/ZLIP/zlip.htm),一个原来在8051+RTL8019平台实现的一个轻量级TCP/IP协议栈,这个协议栈只实现了TCP/IP的协议,且ICMP协议只实现了echo,以及并不支持UDP和一些常用的应用层协议比如HTTP,不过这些正好不需要,这个实现可以满足项目的需求,又不至于过于庞大,所以就打算将其移植到TMS320F28335平台上。另外好像这个协议栈的0.2版本是开源的,1.0版本已经作为商业用途,说明稳定性应该还可以,至于我,只需要开源版本就可以了。
当然,移植过程并不轻松,在这个过程中,我总算是发现为什么DSP28335上一直没有一个像样的协议栈了,主要原因是28335的总线宽度是16位的,一个char指针指向的是2个字节,一个Int也是2个字节,而且char无法拆开,这就蛋疼了,也就是说,传统协议栈通常会采用结构体的方式去解析TCP数据包,比如像这样:
IP的头部通常是这样定义的:
struct SIPHead { /* Version 4 bits, HeadLength 4 bits. typical value is 0x45 */ BYTE Ver_HeadLen; /* Precedence(priority) 3 bits, Delay, Throughput, Reliability , reserved 2 bits. typical value 0x00 */ BYTE ServeType; WORD TotalLen; /* all size of IP packet inlcude IPHead. 16 bits */ WORD FragmentID; /* 16 bits */ /* Reserved 1 bit, May be fragmented 1 bit, Last fragment 1 bit, Fragment offset 13 bits. typical 0x00 */ #define IP_FRAGMENT_OFFSET_MASK 0x1FFF WORD FragmentFlag_Offset; BYTE LifeLength; /* ttl */ BYTE Protocol; /* eg. IP_PROTOCAL_TCP*/ WORD CheckSum; /* 16 bits */ IP_ADDR IPScr; /* 32 bits */ IP_ADDR IPDest; };
其中的IPSrc和IP_Dest都是4个字节,若直接使用Long指针去转化,他只能包含2个28335总线地址,也就是说,sizeof运算的结果会是这样:
sizeof(char) = 1
sizeof(int) = 1
sizeof(long) = 2
也就是说和我们一般意义上的平台完全不同,因此会造成错乱,无法直接正常运行。于是,最后实在没办法,只好把结构体所有属性全部拆成单字节(也就是说浪费了高8位,2个字节大小的char只使用最低的字节位),所以代码就变成这样了:
struct SIPHead { /* Version 4 bits, HeadLength 4 bits. typical value is 0x45 */ BYTE Ver_HeadLen; /* Precedence(priority) 3 bits, Delay, Throughput, Reliability , reserved 2 bits. typical value 0x00 */ BYTE ServeType; BYTE TotalLenH; /* all size of IP packet inlcude IPHead. 16 bits */ BYTE TotalLenL; BYTE FragmentIDH; /* 16 bits */ BYTE FragmentIDL; /* Reserved 1 bit, May be fragmented 1 bit, Last fragment 1 bit, Fragment offset 13 bits. typical 0x00 */ #define IP_FRAGMENT_OFFSET_MASK 0x1FFF BYTE FragmentFlag_OffsetH; BYTE FragmentFlag_OffsetL; BYTE LifeLength; /* ttl */ BYTE Protocol; /* eg. IP_PROTOCAL_TCP*/ BYTE CheckSumH; /* 16 bits */ BYTE CheckSumL; BYTE IPScrH; /* 32 bits */ BYTE IPScrh; BYTE IPScrl; BYTE IPScrL; BYTE IPDestH; BYTE IPDesth; BYTE IPDestl; BYTE IPDestL; };
我将所有大于1个字节的成员对象,全部拆成H和L各1个字节,其中4个字节的拆成了H h l L这4个,然后,对于取出对象,自己使用了2个merge函数:
Uint32 MergeNetDword(BYTE H,BYTE h,BYTE l,BYTE L) { DWORD out; out = htonl(((DWORD)H<<24)|((DWORD)h<<16)|((DWORD)l<<8)|(DWORD)L); return out; } Uint16 MergeNetWord(BYTE H,BYTE L) { BYTE out; out = htons(((DWORD)H<<8)&0xFF00|(DWORD)L); return out; }
在比较值的时候,再将其中的成员属性合并。最后写的非常蛋疼。不过好在程序还是正常跑起来了,TCP/IP协议也正常工作,当然蛋疼的细节还远不止上面这些。
在移植过程中,还发现了原作者留下的一些bug和坑,ARP协议还是错的,我也是醉,虽然这个不影响正常工作。
如果你对整个协议栈代码感兴趣,代码我已经放在github上以MIT协议开源了,大家可以戳这里:
https://github.com/zjlywjh001/DSP28335_ZlIP_Stack