这是之前用TI的DM642做视频编码器用到的网络协议栈,源码TI官网上有的下载。维基网上也有关于NDK的一些技术文档,都是英文的,看了费劲。
看这个之前我对TCP/IP协议几乎不了解,拿到这个就开始看英文文档,天昏地暗的,边看边整理些东西,没基础真的痛苦,硬着头皮看吧。下面都是我边看边整理的,怕丢了,放到这,以后还有用。
一、NDK中创建任务的方法:
1、用标准的DSP/BIOS API
struct TSK_Attrs ta;
hMyTask = TSK_create( (Fxn)entrypoint, &ta, arg1, arg2, arg3 );
2、用NDK的任务抽象API
hMyTask = TaskCreate( entrypoint, "TaskName", OS_TASKPRINORM, stacksize, arg1, arg2, arg3 );
In both cases, hMyTask is a handle to a DSP/BIOS TSK task thread.
二、内存分配
应用程序在分配内存时最好使用标准的malloc()/free()函数,或者使用DSP/BIOS来分配。
三、NDK初始化和配置
1、必须包含NETCTRL.LIB,NETCTRL模块是协议栈初始化、配置和事件调度的核心。
2、由DSP/BIOS创建的线程是程序的入口点,并且最终成为NETCTRL调度线程。这个控制线程直到协议栈关闭才返回给调用者。
3、在调用其他任何协议栈API之前必须先调用NC_SystemOpen()函数。它初始化协议栈及其所需内存环境。它的两个参数Priority和OpMode分别决定调度任务的优先级和调度器何时开始执行。
4、使用实例:
//
// THIS IS THE FIRST THING DONE IN AN APPLICATION!!
//
rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
if( rc )
{
}
5、系统配置,包括以下参数:
· 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
{
} while( rc > 0 );
As an example of a network start callback, the NetworkStart() function below opens a user SMTP server
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( )
{
}
//
// NetworkStop
//
// This function is called when the network is shutting down
//
static void NetworkStop()
{
}
NetworkIPAddr()函数通常用来同步网络任务,该网络任务需要在执行前设置一个本地IP地址。
void NetIPCb( IPN IPAddr, uint IfIndex, uint fAdd );
//
// 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 )
{
}
6、关闭协议栈的方法:
①手动关闭,NC_NetStop(1)重启网络栈,NC_NetStop(0)关闭网络栈。
②当检测到致命错误时关闭,NC_NetStop(-1)。
7、追踪服务状态
当使用NETTOOLS库时,NETTOOLS状态回调函数被引入,这个回调函数追踪被配置使能的服务的状态。状态回调函数有两级,第一个回调由NETTOOLS服务生成,当服务状态改变时它调用配置服务提供者。然后配置服务提供者增加它自己的状态到报告中,并且调用应用程序回调函数。当应用程序增加服务到系统配置中时,一个指向应用程序回调的指针被提供。
void StatusCallback( uint Item, uint Status, uint Code, HANDLE hCfgEntry )
实例:
//
// 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 )
{
}
以上函数打印的最后一个值是答应通过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
DHCPCODE_IPREMOVE
DHCPCODE_IPRENEW
大部分情况下不必去核对这些状态报告代码,除非以下情况:
当使用DHCP客户端来配置协议栈,DHCP客户端控制CFGTAG_SYSINFO标签空间的前256个入口。这些入口与这256个DHCP操作标签通信。应用程序可以检查DHCPCODE_IPADD或者DHCPCODE_IPRENEW返回代码以便它能够读或者改变通过DHCP客户端获得的信息。
8、不使用DHCP client时,手动配置DNS的IP地址方法如下:
IPN IPTmp;
// Manually add the DNS server "128.114.12.2"
IPTmp = inet_addr("128.114.12.2");
CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
如果以上代码被加到使用DHCP的应用程序中,当DHCP执行状态更新时这个入口将会被清除。
9、使用DHCP client时,手动配置DNS的IP地址方法如下:必须在DHCP配置完成以后再手动增加DNS服务。
//
// 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 )
{
}
四、操作系统配置结构体和NDK配置结构体
以上两个结构体的值可以直接赋值,但是有两个原因说明增加这个参数给系统配置是有用的:
第一,它为所有的网络配置提供了固定的API。
第二,如果使用了配置加载和保存功能,这些配置参数都被保存除了系统配置的其余部分。
以下代码可以改变答应输出的调试信息的级别,例如,不打印出警告信息,而可以打印出调试信息:
// We do not want to see debug messages less than WARNINGS
五、存储和加载配置
1、配置设置好后,存储在非易失性存储器中。
int CfgSave(HANDLE hCfg, int *pSize, UINT8 *pData);
返回值:正确返回被写的字节数,size错误返回0,操作错误返回小于1。
描述:该函数将由hCfg指定的配置内容存储到pData指定的内存块。
int SaveConfig( HANDLE hCfg )
{
}
2、加载配置
实例如下:假设两个函数
MyMemorySize()返回线性buffer中的配置的存储大小
MyMemoryLoad()从flash中加载线性buffer
int NetworkTest()
{