您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 从Cfgdemo项目来分析协议栈的启动
从Cfgdemo项目来分析协议栈的启动项目中静态创建的任务有两个:一个是空闲任务,一个是StackTest任务,main函数是空的。任务StackTest的优先级(5)比空闲任务高。整个程序的初始化部分执行完之后,就会执行StackTest任务,从而执行StackTest()函数。StackTest()函数首先调用了NC_SystemOpen()函数,来完成协议栈系统的初始化工作。必须注意的是:在使用协议栈之前必须最先调用该函数。接下来调用函数CfgNew()来创建一个配置(Configuration)并获得该配置的句柄,接下来的工作就是在配置中增添配置项(ConfigurationEntry),增添配置选项是通过调用CfgAddEntry()函数实现的。该项目中首先增添的配置项为Hostname:从CFGDEMO项目来分析协议栈的启动接着增添的配置项为Telnet服务,那么协议栈系统在启动之后会启动Telnet服务(创建了一个名为telnetd的任务):接着通过调用efs_createfile()创建5个文件,其名字分别为:index.html、tibug.gif、cfgstart.cgi、cfgpass.cgicfgdone.cgi;这5个文件中,前两个文件的数据分别存放在数组DEFAULT[]、TIBUG[]中,而后三个文件实际是cgi程序,这三个cgi程序分别完成来之客户端的命令请求:Viewconfiguration、Changepassword、Submitconfiguration,与之同时,它们动态修改并发送了两个网页并CONFIG、USERMSG。接着增添的配置项为HTTP服务,那么协议栈启动之后会启动Http服务(创建一个名为httpserver的任务)接着的增添的配置项为CFGITEM_OS_DBGPRINTLEVEL,来选择打印的信息内容:接下来调用函数CfgSave()来获取配置的大小并讲配置数据存入一个缓存中去,并释放配置。接下来调用函数NetBoot()来启动协议栈。这个函数是NDK的用户自己写的一个函数,在这个函数中,调用了协议栈启动函数NC_NetStart(),这个函数属于NetworkControlAPI,该函数的源代码可以在\ti\NDK\src\netctrl\netctrl.c中找到。其函数接口如下:NetBoot()在调用NC_NetStart()之前调用CfgNew()来创建一个新的空的配置,然后再调用CfgLoad()来把之前存入缓冲区中的配置好的配置数据载入新的配置中去,并把它作为参数传入NC_NetStart()中去,接着就调用NC_NetStart()启动协议栈。NC_NetStart()函数首先调用了4个硬件抽象层(HAL)的四个初始化函数,由它们来完成底层硬件的初始化(具体细节过程等待进一步研究):接着该函数调用CfgSetDefault()把传入NC_NetStart()函数中构建好的配置设置为默认配置。由于编程方法上的需要,协议栈就使用配置是统一为一个配置句柄指向的配置。这样CfgSetDefault()的本质就是把该配置句柄指向传入NC_NetStart()函数中构建好的配置。接着把传入NC_NetStart()函数的三个函数指针赋值给三个全局变量,以方便后面适当的时候调用:接着调用协议栈的核心API函数ExecOpen()来初始化协议栈的executive(自己意会这个概念)。接着动态创建一个名为ConfigBoot的任务,其优先级为15(最高),其执行的函数是NS_BootTask()。由于DSP/BIOS是占先式实时OS,所以一旦任务高优先级的任务创建,OS内核的调度模块就会自动切换到高优先级的任务执行。很显然,接下来执行的是函数NS_BootTask()。这个函数的源码在\ti\NDK\src\netctrl\netsrv.c中可以找到。NS_BootTask()函数首先调用CfgSetService()来SetServiceCallBackFuntionsforEveryConfigurationTag,其意思是为每个ConfigurationTag设置一个回调函数,其目的是为了在修改完配置之后能及时更新协议栈系统,也就是使协议栈系统随着配置的改变而实时地改变。回调函数的接口定义如下:在NDK的协议栈中,ConfigurationTag共有如下8个:其中需要配置回调函数的有如下几个:CFGTAG_OS、CFGTAG_IP、CFGTAG_SERVICE、CFGTAG_IPNET、CFGTAG_ROUTE,它们的回调函数分别为:SPConfig()、SPConfig()、SPService()、SPIpNet()、SPRoute(),这些回调函数的实现源代码都在\ti\NDK\src\netctrl\netsrv.c可以找到。下面分析以下SPConfig()函数是怎样实现实时更新系统的:SPConfig()函数是作为CFGTAG_OS、CFGTAG_IP的回调函数的,所以它必须负责处理增添CFGTAG_OS、CFGTAG_IP两种类型的ConfigurationEntry时的系统实时更新工作。系统在调CfgAddEntry函数来增添一个CFGTAG_OS、CFGTAG_IP类型的配置项后(注意:CfgAddEntry只把配置数据添加到配置中去),会调用与该种配置类型捆绑的的回调函数SPConfig(CfgSetService函数来完成捆绑工作的),SPConfig函数调用CfgEntryInfo来获取该配置项的数据缓冲区的指针并存放在变量pi中,接着更具ConfigurationTag的类型来获取具体需要修改的系统配置参数结构体;CFGTAG_OSèOSENVCFG_oscfg、oscfgcopy/CFGTAG_IPèIPCONFIG_ipcfg、ipcfgcopy,这两个都是全局变量,它们的数据结构类型如下://ConfigurationStructuretypedefstruct_ipconfig{uintIcmpDoRedirect;//UpdateRtTableonICMPredirect(1=Yes)uintIcmpTtl;//TTLforICMPmessagesRFC1700says64uintIcmpTtlEcho;TTLforICMPechoRFC1700says64uintIpIndex;//IPStartIndexuintIpForwarding;//IPForwarding(1=Enabled)uintIpNatEnable;//IPNATEnable(1=Yes)uintIpFilterEnable;//IPFilteringEnable(1=Yes)uintIpReasmMaxTime;//MaxreassemblytimeinsecondsuintIpReasmMaxSize;//MaxreassemblypacketsizeuintIpDirectedBCast;//LookfordirectedBCastIPaddressesuintTcpReasmMaxPkt;//MaxreasmpktsheldbyTCPsocketuintRtcEnableDebug;//EnableRouteControlMessages(1=On)uintRtcAdvTime;//TimeinsectosendRtAdv(0=don't) uintRtcAdvLife;//LitetimeofrouteinRtAdvintRtcAdvPref;//PreferenceLevel(signed)inRtAdvuintRtArpDownTime;//Time5failedARPskeepRtdown(sec)uintRtKeepaliveTime;//VALIDATEDroutetimeout(sec)uintRtCloneTimeout;//INITIALroutetimeout(sec)uintRtDefaultMTU;//DefaultMTUforinternalroutesuintSockTtlDefault;//DefaultPacketTTLuintSockTosDefault;//DefaultPacketTOSintSockMaxConnect;//MaxSocketConnectionsuintSockTimeConnect;//Maxtimetoconnect(sec)uintSockTimeIo;//DefaultSocketIOtimeout(sec)intSockBufMax; //AbsolutemaxSocketbuffersizeintSockBufMinTx;//MinTxspaceforabletowriteintSockBufMinRx;//MinRxdataforabletoreaduintPipeTimeIo;//DefaultPipeIOtimeout(sec)intPipeBufSize;//PipeinternalbuffersizeintPipeBufMinTx;//MinTxspaceforabletowriteintPipeBufMinRx;//MinRxdataforabletoread}IPCONFIG;大家应该注意到所有的成员都是32位的数据类型,所以这里的pi和pDst指针都定义为指向32位类型数据的指针。在做完必要性的检测之后,就会把pi指向数据缓冲中的数据直接拷贝到pDst+Item指向的数据缓冲中去。两个细节性的问题:1)为什么只拷一个32位?因为这两种类型的Configuration的ConfigurationEntry都是32位类型的数据。2)为什么Item要事先减一?因为Tag=CFGTAG_OS/CFGTAG_IP,Item的值都是从1开始的。这样系统的配置就被修改了,后面程序的执行就会根据新的配置去操作。这里只分析了AddEntry的过程,RemoveEntry的过程基本上差不多,不同的是用系统默认配置的值去覆盖系统配置。//----------------------------------------------------------------------------------------//SPConfig()-CFGTAG_IPandCFGTAG_OSServiceProvider//----------------------------------------------------------------------------------------staticintSPConfig(HANDLEhCfg,uintTag,uintItem,uintOp,HANDLEhCfgEntry){uint*pi,*pdst,*pdef; (void)hCfg;//Gettheinformationif(CfgEntryInfo(hCfgEntry,0,(UINT8**)(&pi))0)return(-1);//SetuptohandleIPorOSif(Tag==CFGTAG_IP){//BoundthevalueofItemif(ItemCFGITEM_IP_MAX)return(-1);pdst=(uint*)&_ipcfg;pdef=(uint*)&ipcfgcopy;}elseif(Tag==CFGTAG_OS){//BoundthevalueofItemif(ItemCFGITEM_OS_MAX)return(-1);pdst=(uint*)&_oscfg;pdef=(uint*)&oscfgcopy;}else{return(-1);}//VerifyItemif(!Item)return(-1);Item--;//Ifthisisanadd,addtheentryif(Op==CFGOP_ADD)
本文标题:从Cfgdemo项目来分析协议栈的启动
链接地址:https://www.777doc.com/doc-765940 .html