TI的TCP/IP协议栈---NDK
1、用标准的DSP/BIOS API
struct TSK_Attrs ta;
ta = TSK_ATTRS;
ta.priority = OS_TASKPRINORM;
ta.stack = 0;
ta.stacksize = stacksize;
ta.stackseg = 0;
ta.environ = 0;
ta.name = "TaskName";
ta.exitflag = 0;
hMyTask = TSK_create( (Fxn)entrypoint, &ta, arg1, arg2, arg3 );
hMyTask = TaskCreate( entrypoint, "TaskName", OS_TASKPRINORM, stacksize, arg1, arg2, arg3 );
应用程序在分配内存时最好使用标准的malloc()/free()函数,或者使用DSP/BIOS来分配。
1、必须包含NETCTRL.LIB,NETCTRL模块是协议栈初始化、配置和事件调度的核心。
2、由DSP/BIOS创建的线程是程序的入口点,并且最终成为NETCTRL调度线程。这个控制线程直到协议栈关闭才返回给调用者。
3、在调用其他任何协议栈API之前必须先调用NC_SystemOpen()函数。它初始化协议栈及其所需内存环境。它的两个参数Priority和OpMode分别决定调度任务的优先级和调度器何时开始执行。
Priority包括NC_PRIORITY_LOW 和 NC_PRIORITY_HIGH两种,
OpMode包括NC_OPMODE_POLLING 和 NC_OPMODE_INTERRUPT两种,大部分情况使用interrupt模式,而polling模式会持续运行,当使用polling模式时,优先级必须设为低(NC_PRIORITY_LOW)。
4、使用实例:
//
// THIS IS THE FIRST THING DONE IN AN APPLICATION!!
//
rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
if( rc )
{
printf("NC_SystemOpen Failed (%d)\n",rc);
for(;;);
}
· Network Hostname
· IP Address and Subnet Mask
· IP Address of Default Routes
· Services to be Executed (DHCP, DNS, HTTP, etc.)
· IP Address of name servers
· Stack Properties (IP routing, socket buffer size, ARP timeouts, etc.)
系统配置开始时调用CfgNew()来创建配置句柄。
配置好之后调用NC_NetStart()函数,该函数有4个参数,配置句柄,指向开始回调函数的指针,指向结束函数的指针,指向IP地址事件的函数。开始和结束函数都只被调用一次。开始函数在初始化结束准备执行网络应用程序时调用,结束函数在系统完全关闭时调用,意味着协议栈将不能执行网路应用。IP地址事件函数能够多次被调用。
NC_NetStart()到系统关闭才返回一个关闭代码。
//
// Boot the system using our configuration
//
// We keep booting until the function returns 0. This allows
// us to have a "reboot" command.
//
do
{
rc = NC_NetStart( hCfg, NetworkStart, NetworkStop, NetworkIPAddr );
} while( rc > 0 );
application by calling an open function to create the main application thread.
//
// NetworkStart
//
// This function is called after the configuration has booted
//
static SMTP_Handle hSMTP;
static void NetworkStart( )
{
// Create an SMTP server
task hSMTP = SMTP_open( );
}
// NetworkStop
//
// This function is called when the network is shutting down
//
static void NetworkStop()
{
// Close our SMTP server task
SMTP_close( hSMTP );
}
void NetIPCb( IPN IPAddr, uint IfIndex, uint fAdd );
IPAddr 增加或者移除的IP地址
IfIndex 外设接口获取或者移除IP地址的标识
fAdd 增加一个IP地址时设为1,移除IP地址时设为0
//
// NetworkIPAddr
//
// This function is called whenever an IP address binding is
// added or removed from the system.
//
static void NetworkIPAddr( IPN IPAddr, uint IfIdx, uint fAdd )
{
IPN IPTmp;
if( fAdd )
printf("Network Added: ");
else
printf("Network Removed: ");
// Print a message
IPTmp = ntohl( IPAddr );
printf("If-%d:%d.%d.%d.%d\n", IfIdx,
(UINT8)(IPTmp>>24) & 0xFF,
(UINT8)(IPTmp>>16) & 0xFF,
(UINT8)(IPTmp>>8) & 0xFF,
(UINT8) IPTmp & 0xFF );
}
①手动关闭,NC_NetStop(1)重启网络栈,NC_NetStop(0)关闭网络栈。
②当检测到致命错误时关闭,NC_NetStop(-1)。
// We do not want the stack to abort on any error禁止错误引起的关闭
uint rc = DBG_NONE;
CfgAddEntry( hCfg, CFGTAG_OS, CFGITEM_OS_DBGABORTLEVEL,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
7、追踪服务状态
当使用NETTOOLS库时,NETTOOLS状态回调函数被引入,这个回调函数追踪被配置使能的服务的状态。状态回调函数有两级,第一个回调由NETTOOLS服务生成,当服务状态改变时它调用配置服务提供者。然后配置服务提供者增加它自己的状态到报告中,并且调用应用程序回调函数。当应用程序增加服务到系统配置中时,一个指向应用程序回调的指针被提供。
Item Item value of entry changed被更改的入口的项目值
Status New status新状态
Code Report code (if any)报告代码
hCfgEntry Non-Referenced HANDLE to entry with status change不引用
实例:
//
// Service Status Reports
//
static char *TaskName[] = { "Telnet","HTTP","NAT","DHCPS","DHCPC","DNS" }; //不能改变,在netcfg.h中定义
static char *ReportStr[] = { "","Running","Updated","Complete","Fault" }; //不能改变,在nettools.h中定义
static char *StatusStr[] = { "Disabled", "Waiting", "IPTerm", "Failed", "Enabled" }
static void ServiceReport( uint Item, uint Status, uint Report, HANDLE h )
{
printf( "Service Status: %-9s: %-9s: %-9s: %03d\n",
TaskName[Item-1], StatusStr[Status],
ReportStr[Report/256], Report&0xFF );
}
以上函数打印的最后一个值是答应通过Report传递的低8位的值,这个值是固定的,大部分情况下这个值不需要。通常,如果服务成功,它报告Complete,失败,他报告Fault。对于那些不会结束的服务(例如,当IP分配启动时,DHCP客户端会持续运行),Report的高位字节意味着Running,而服务特定的低字节必须被用来指定当前状态。
For example, the status codes returned in the 8 least significant bits of Report when using the DHCP
client service are:
DHCPCODE_IPADD Client has added an IP address
DHCPCODE_IPREMOVE IP address removed and CFG erased
DHCPCODE_IPRENEW IP renewed, DHCP config space reset
大部分情况下不必去核对这些状态报告代码,除非以下情况:
当使用DHCP客户端来配置协议栈,DHCP客户端控制CFGTAG_SYSINFO标签空间的前256个入口。这些入口与这256个DHCP操作标签通信。应用程序可以检查DHCPCODE_IPADD或者DHCPCODE_IPRENEW返回代码以便它能够读或者改变通过DHCP客户端获得的信息。
IPN IPTmp;
IPTmp = inet_addr("128.114.12.2");
0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
如果以上代码被加到使用DHCP的应用程序中,当DHCP执行状态更新时这个入口将会被清除。
//
// Service Status Reports
//
static char *TaskName[] = { "Telnet","HTTP","NAT","DHCPS","DHCPC","DNS" };
static char *ReportStr[] = { "","Running","Updated","Complete","Fault" };
static char *StatusStr[] = { "Disabled","Waiting","IPTerm", "Failed","Enabled" };
static void ServiceReport( uint Item, uint Status, uint Report, HANDLE h )
{
printf( "Service Status: %-9s: %-9s: %-9s: %03d\n",
TaskName[Item-1], StatusStr[Status],
ReportStr[Report/256], Report&0xFF );
// Example of adding to the DHCP configuration space
//
// When using the DHCP client, the client has full control over access
// to the first 256 entries in the CFGTAG_SYSINFO space. Here, we want
// to manually add a DNS server to the configuration, but we can only
// do it once DHCP has finished its programming.
//
if( Item == CFGITEM_SERVICE_DHCPCLIENT &&
Status == CIS_SRV_STATUS_ENABLED &&
(Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW)) )
{
IPN IPTmp;
// Manually add the DNS server when specified. If the address
// string reads "0.0.0.0", IPTmp will be set to zero.
IPTmp = inet_addr(DNSServer);
if( IPTmp )
CfgAddEntry( 0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
}
}
以上两个结构体的值可以直接赋值,但是有两个原因说明增加这个参数给系统配置是有用的:
第一,它为所有的网络配置提供了固定的API。
第二,如果使用了配置加载和保存功能,这些配置参数都被保存除了系统配置的其余部分。
以下代码可以改变答应输出的调试信息的级别,例如,不打印出警告信息,而可以打印出调试信息:
// We do not want to see debug messages less than WARNINGS
rc = DBG_WARN;
CfgAddEntry( hCfg, CFGTAG_OS, CFGITEM_OS_DBGPRINTLEVEL,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8 *)&rc, 0 );
1、配置设置好后,存储在非易失性存储器中。
int CfgSave(HANDLE hCfg, int *pSize, UINT8 *pData);
返回值:正确返回被写的字节数,size错误返回0,操作错误返回小于1。
描述:该函数将由hCfg指定的配置内容存储到pData指定的内存块。
数据缓冲区的大小最初由pSize指定,如果这个指针指向的size值为0(pSize本身不能为NULL指针),这个函数不会试图存储配置,相反地,会计算需要的大小并且将这个值写到由pSize指定的位置。事实上,在任何时候pSize处的值都比存储配置所需的值要小,函数返回0值并且pSize处的值被用来设置存储数据所需的大小。参数pData指向接收配置信息的数据缓冲区。
int SaveConfig( HANDLE hCfg )
{
UINT8 *pBuf;
int size;
// Get the required size to save the configuration
CfgSave( hCfg, &size, 0 ); //计算存储所需的大小并存储到pSize
if( size && (pBuf = malloc(size) ) )
{
CfgSave( hCfg, &size, pBuf );
MyMemorySave( pBuf, size ); //假设这个函数是将线性缓冲区存储到非易失性存储器
Free( pBuf );
return(1);
}
return(0);
}
实例如下:假设两个函数
MyMemorySize()返回线性buffer中的配置的存储大小
MyMemoryLoad()从flash中加载线性buffer
{
int rc;
HANDLE hCfg;
UINT8 *pBuf;
Int size;
//
// 在应用程序中,这绝对是第一个必须被完成的!
//
rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
if( rc )
{
printf("NC_SystemOpen Failed (%d)\n",rc);
for(;;);
}
//
// 首先加载装有配置信息的线性存储块
//
size = MyMemorySize();
if( !size )
goto main_exit;
if( !pBuf )
goto main_exit;
MyMemoryLoad( pBuf, size );
// 创建新配置并且加载配置信息
//
hCfg = CfgNew();
{
printf("Unable to create configuration\n");
free( pBuf );
goto main_exit;
}
CfgLoad( hCfg, size, pBuf );
// 用这个配置来启动这个系统
//
// We keep booting until the function returns less than 1. This allows
// us to have a "reboot" command.
//
do
{
rc = NC_NetStart( hCfg, NetworkStart, NetworkStop, NetworkIPAddr );
} while( rc > 0 );
CfgFree( hCfg );
main_exit:
NC_SystemmClose();
return(0);
}
uint tmp = 65500;
CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_IPREASMMAXSIZE,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8*) &tmp, 0);
1、NDK配置操作:
CFGITEM_IP_SOCKUDPRXLIMIT
CFGITEM_IP_IPREASMMAXSIZE
2、socket操作:
SO_SNDBUF
SO_RCVBUF
3、操作系统适配层定义:
MMALLOC_MAXSIZE
MMALLOC_MAXSIZE
例如:为了配置发送和接收的UDP数据包能达到65500字节的大小,一下代码必须被执行
1、uint tmp = 65500;
CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_IPREASMMAXSIZE,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8*) &tmp, 0);
CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_SOCKUDPRXLIMIT,
CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8*) &tmp, 0);
2、在"pbm.c"文件中修改MMALLOC_MAXSIZE参数,在"mem.c"文件中修改RAW_PAGE_SIZE参数,并且重新建立OSAL库。
3、uint tmp = 65500;
setsockopt(s, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(int) );
setsockopt(s, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(int) );
NDK允许应用程序更新UDP数据包的有效载荷。常用的方法是更新数据包的时间戳信息。这样,发送端和接收端能更精确地调整依赖于改变系统特有的运行时间的传递延时。
1、在传输端:
在每个socket上,通过使用"setsockopt"函数,应用程序可以注册一个唤起函数。
将数据包插入驱动的传输队列之前,协议栈调用这个唤起函数。
在头部,唤起函数要更新UDP校验和信息。
以下代码示意了怎样控制它:
void myTxTimestampFxn(UINT8 *pIpHdr) {
...
}
setsockopt(s, SOL_SOCKET, SO_TXTIMESTAMP, (void*) myTxTimestampFxn, sizeof(void*));
2、在接收端:
在每个接口基础上,通过使用"EtherConfig"函数,应用程序可以注册一个唤起函数。EtherConfig函数在"netctrl.c"文件中的NC_NetStart()函数中设置。
这个唤起函数仅仅在处理包之前协议栈调度器调用。
在头部,唤起函数要更新UDP校验和信息。
以下代码示意了怎样控制它:
void myRcvTimestampFxn(UINT8 *pIpHdr) {
...
}
EtherConfig( hEther[i], 1518, 14, 0, 6, 12, 4, myRcvTimestampFxn);
包括DBG_INFO,DBG_WARN,DBG_ERROR。使用这些等级有两个目的:
1,决定调试信息是否会被打印。
2,决定调试信息是否会引起NDK关闭。
DBG_ERROR这一层的信息会引起栈的关闭。可以通过系统配置和使用操作系统配置结构来调整这个行为。
当诊断NDK调试信息时,字存储器出错会频繁发生。这是因为对于缓冲设备很容易造成存储器出错。包含在NDK中的大部分示例程序都是用全L2缓冲模式。在这种模式下,任何对CPU内部存储边界的读写访问都会引起缓冲区出错,从而引起存储器出错。因为内部存储(L2)边界从地址0x00000000开始,当使用全缓冲时,一个空指针会导致问题。
当L2使用cache+RAM模式时,对于地址0x00000000的读写不会引起缓冲错误。
大部分程序死锁都是由于任务堆栈空间不足引起的。例如,当我们写一个HTTP CGI函数时,CGI函数的任务线程可能总共只需要5000字节的任务堆栈空间。因此,使用过大的堆栈是不被推荐的。
一般来说,不使用下面的源码:
myTask()
{
char TempBuffer[2000];
myFun( TempBuffer );
}
而是这样使用:
myTask()
{
char *pTempBuf;
pTempBuf = MEM_alloc( 0, 2000, 0);
if( pTempBuf != MEM_ILLEGAL )
{
myFun( pTempBuf );
MEM_free( pTempBuf, 2000 );
}
}
如果调用一个内存分配函数速度太快,可以考虑使用外部buffer。这仅仅是个例子,几乎不要事先考虑就能排除所有可能的堆栈溢出情况,并且消除可能的程序死锁。
mmAlloc()和mmFree():分配/释放小的内存块
mmBulkAlloc()和mmBulkFree():分配/释放较大(不受限制的,通常在3000bytes以上)内存块
(21504/46080 mmAlloc: 61347036/0/61346947, mmBulk: 25/0/17)
mmAlloc: 61347036/0/61346947 :调用了mmAlloc()函数61347036次,失败了0次,调用mmFree()函数61346947次。在任何时候,调用mmAlloc()的次数 + 失败的次数 = 调用mmFree()的次数 + 应该分配而未分配的次数。假如在最终的报告中有 mmAlloc:n1/n2/n3,n1+n2应该等于n3,如果不等,就有内存泄露。
NC_NetStart()
{
设备初始化;
创建配置启动线程;
网络调度器(NetScheduler(););
关闭设备;
}
TI的TCP/IP协议栈---NDK相关推荐
- TI C6000DSP上TCP/IP协议栈的实现
摘要:针对TIC6000系列DSP网络开发工具NDK进行研究,结合TMS320DM642芯片详细描述了NDK的结构,讲述了利用NDK开发DSP网络应用程序的一般过程和实际应用中要注意的问题,并给出了N ...
- 基于TI C6000的TCP/IP协议栈的研究与实现
本文来自:东北大学信息学院 李松 吴建华 <TI C6000DSP上TCP/IP协议栈的实现> 有适当删减. 摘要:针对TIC6000系列DSP网络开发工具NDK进行研究,结合TMS32 ...
- TCP/IP协议栈在MSP430单片机上的实现
引言 随着信息技术的不断发展,以及人们对日常生活舒适度.方便度要求的提高,信息家电.智能仪表等产品越来越频繁的出现在我们的生活当中:人们也越来越热衷于把家电.仪表等设备连接到Internet 中,从而 ...
- TCP/IP 协议栈4层结构及3次握手4次挥手
TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...
- OSI七层 TCP/IP四层 TCP/IP协议栈: 不同的通信协议的大集合
应用层: 网络服务与最终用户的一个接口. 协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP 表示层: 数据的表示.安全.压缩.(在五层模型里 ...
- TCP/IP 协议栈及 OSI 参考模型详解--云平台技术栈04
导读:之前发布了云平台技术栈(ps:点击可查看),本文主要说一下其中的tcp/ip和网络! 来源:王东裕 http://wangdy.blog.51cto.com/3845563/1588379 OS ...
- C1000k 新思路:用户态 TCP/IP 协议栈
转自:http://blog.csdn.net/solstice/article/details/26363901 C1000k 新思路:用户态 TCP/IP 协议栈 现在的服务器支撑上百万个并发 T ...
- 渣渣小本求职复习之路每天一博客系列——TCP/IP协议栈(5)
前情回顾:一篇短短的博客明显不能满足TCP和UDP这两个饥渴的汉子,而且还被应用协议占了一小半的篇幅.在昨天结束之后,相信大家都基本对TCP/IP协议栈的轮廓有一个大概的印象了,能够对整体有所把握. ...
- 几种开源的TCP/IP协议栈分析
1.BSD TCP/IP协议栈 BSD栈历史上是其他商业栈的起点,大多数专业TCP/IP栈(VxWorks内嵌的TCP/IP栈)是BSD栈派生的.这是因为BSD栈在BSD许可协 议下提供了这些专业栈的 ...
最新文章
- 鸿蒙系统支持最低处理器,这四款华为手机可升级到鸿蒙系统,老机型居多,最低只需千元!...
- 波束管理 Beam Management
- java查看jdk源码_Java-如何查看JDK源码
- 公开课 | 知识图谱构建与应用概述
- ipv6网络使用scp,并解决No route to host与no matches found报错
- java 面向对象 1
- 搜狗词库合集分享_Rime小狼毫
- 计算机桌面桌面设置动态视频,电脑壁纸 篇一:电脑设置动态视频桌面图文教程...
- Android 极光各厂商配置
- kali Linux 系统安装教程
- 11年艺术学习“转投”数学,他出版首本TensorFlow中文教材,成为蚂蚁金服技术大军一员...
- android10.0(Q) MTK 系统相机打开 USBCamera
- Python生成器教程
- matlab ga函数详解,matlab遗传算法ga函数
- android手机固件升级原理,为什么常说Android手机千万别频繁的系统升级,背后的真实原因?...
- 安卓流畅度测试方法二:FPS Meter测试安卓帧数
- jvm.option是什么,它是如何加载的
- 串口通信(unity,VS通用)
- LTE 各频段对应频点以及频率,频点号与频率之间的转换关系
- [基于harbor部署私有仓库] 4 推送镜像到harbor
热门文章
- Http 与 Socket 区别
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2- “Tab”标签新增可“最大化”显示功能...
- BarTender安装常见问题集结
- GetResponse() 基础连接已经关闭:服务器关闭了本应保持活动状态的连接
- Amazon DynamoDB 入门2:工作原理、API和数据类型介绍
- Install Mysql with SELinux on
- Mysql数据库误删除数据恢复成功
- linq TO XML 基础
- Objective-C中的@property使用[五]
- linux(gentoo)安装配置conky