打印

TI的TCP/IP协议栈--NDK(2)

[复制链接]
749|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Orchids|  楼主 | 2017-11-10 16:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
TI的TCP/IP协议栈--NDK


四、操作系统配置结构体和NDK配置结构体
       以上两个结构体的值可以直接赋值,但是有两个原因说明增加这个参数给系统配置是有用的:
       第一,它为所有的网络配置提供了固定的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);
  • }

复制代码
      2、加载配置
       实例如下:假设两个函数
  • MyMemorySize()返回线性buffer中的配置的存储大小
  • MyMemoryLoad()从flash中加载线性buffer
  • int NetworkTest()
  • {
  • 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(;;);
  • }
  • //
  • // 首先加载装有配置信息的线性存储块
  • //
  • // 分配一个buffer用来装载配置信息
  • size = MyMemorySize();
  • if( !size )
  •   goto main_exit;
  • pBuf = malloc( size );
  • if( !pBuf )
  •   goto main_exit;
  • // 将配置信息从flash装载到buffer中
  • MyMemoryLoad( pBuf, size );
  • //
  • // 创建新配置并且加载配置信息
  • //
  • // 创建一个新配置
  • hCfg = CfgNew();
  • if( !hCfg )
  • {
  •   printf("Unable to create configuration/n");
  •   free( pBuf );
  •   goto main_exit;
  • }
  • // 加载配置信息(然后我们可以释放buffer)
  • CfgLoad( hCfg, size, pBuf );
  • Free( 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);
  • }

复制代码

       六、ping NDK目标系统,以下代码例子配置IP重组最大的尺寸为65500个字节。
  • uint tmp = 65500;
  • CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_IPREASMMAXSIZE,
  •   CFG_ADDMODE_UNIQUE, sizeof(uint), (UINT8*) &tmp, 0);

复制代码
      七、发送和接收UDP数据包超过最大传输单元尺寸的方法:
       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) );

复制代码
      八、UDP数据报有效载荷时间戳
       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);</i>

复制代码
      九、调试信息
       包括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以上)内存块
  • 48:48 ( 75%)   18:96 ( 56%)   8:128 ( 33%)   28:256 ( 77%)   1:512 ( 16%)   0:1536   0:3072
  • (21504/46080 mmAlloc: 61347036/0/61346947, mmBulk: 25/0/17)
  • 18:96 ( 56%):内存管理器的页的大小是3072 bytes,至多被分成18块*96字节,使用了一页的56%。
  • mmAlloc: 61347036/0/61346947  :调用了mmAlloc()函数61347036次,失败了0次,调用mmFree()函数61346947次。在任何时候,调用mmAlloc()的次数 + 失败的次数 = 调用mmFree()的次数 + 应该分配而未分配的次数。假如在最终的报告中有 mmAlloc:n1/n2/n3,n1+n2应该等于n3,如果不等,就有内存泄露。

复制代码

       十三、NC_NetStart()函数流程
  • NC_NetStart()
  • {
  • 设备初始化;
  • 创建配置启动线程;
  • 网络调度器(NetScheduler(););
  • 关闭配置;
  • 关闭设备;
  • }

复制代码

[color=rgb(51, 102, 153) !important]

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

697

主题

993

帖子

4

粉丝