1. 程式人生 > >CCS+C6678LE開發記錄08:乙太網介面測試示例之程式碼研究

CCS+C6678LE開發記錄08:乙太網介面測試示例之程式碼研究

在已經通過測試之後我想研究一下測試用例的實現原理,至少應該明白大致原理。

為了方便貼程式碼,我將原始例項的程式碼做了精簡;

為了探索其原理,我修改/添加了少量程式碼。

主要程式碼如下

#include <stdio.h>
#include <ti/ndk/inc/netmain.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include "ti/platform/platform.h"
#include "ti/platform/resource_mgr.h"

static int counter=0;
static HANDLE hHello=0;
char *HostName    = "TMS320C6678";
char *LocalIPAddr = "169.254.11.119";   // My PC Local IP
char *LocalIPMask = "255.255.255.0";    // Not used when using DHCP
char *GatewayIP   = "192.168.2.101";    // Not used when using DHCP
char *DomainName  = "demo.net";         // Not used when using DHCP
char *DNSServer   = "0.0.0.0";          // Used when set to anything but zero
Uint8 clientMACAddress[6] = {0x01, 0x02, 0x03, 0x04, 0x0C, 0xEF}; /* MAC Addr */


static void   NetworkOpen();
static void   NetworkClose();
static void   NetworkIPAddr(IPN IPAddr, uint IfIdx, uint fAdd);
extern int    dtask_udp_hello();

void EVM_init()
{
	printf("\nEVM_Init()\n");
	platform_init_flags   sFlags;
	platform_init_config  sConfig;
	memset( (void *) &sFlags,  0, sizeof(platform_init_flags));
	memset( (void *) &sConfig, 0, sizeof(platform_init_config));
	sFlags.pll  = 0;  /* PLLs for clocking  */
	sFlags.ddr  = 0;  /* External memory    */
	sFlags.tcsl = 1;  /* Time stamp counter */
	sFlags.phy  = 1;  /* Ethernet           */
	sFlags.ecc  = 0;  /* Memory ECC         */
	sConfig.pllm = 0; /* Use libraries default clock divisor */
	platform_init(&sFlags, &sConfig);
}

Void Hello(UArg arg0, UArg arg1)
{
	while(1)
	{
		printf("Hello\n");
		Task_sleep(2000);
		if(counter>=3) break;
	}
}

Void Test(UArg arg0,UArg arg1);

int main()
{
	Task_Handle task1 = Task_create(Test, NULL, NULL);
	Task_Handle task2 = Task_create(Hello, NULL, NULL);
	if (task1==NULL || task2==NULL)
	{
		printf("Task_create() failed!\n");
		BIOS_exit(0);
	}
	BIOS_start();
}

Void Test(UArg arg0,UArg arg1)
{
        QMSS_CFG_T qmss_cfg;
        CPPI_CFG_T cppi_cfg;

        uint32_t coreID = platform_get_coreid();
        uint32_t master=(coreID==0)?1:0;

        qmss_cfg.master_core = master;
        qmss_cfg.max_num_desc = MAX_NUM_DESC;
        qmss_cfg.desc_size = MAX_DESC_SIZE;
        qmss_cfg.mem_region = Qmss_MemRegion_MEMORY_REGION0;

        cppi_cfg.master_core = master;
        cppi_cfg.dma_num = Cppi_CpDma_PASS_CPDMA;
        cppi_cfg.num_tx_queues = NUM_PA_TX_QUEUES;
        cppi_cfg.num_rx_channels = NUM_PA_RX_CHANNELS;

        res_mgr_init_qmss(&qmss_cfg);
        res_mgr_init_cppi(&cppi_cfg);
        res_mgr_init_pass();


        int rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
        if( rc!=0 )
        {
    	    NC_SystemClose();
    	    return;
        }

        HANDLE hCfg = CfgNew();
        if( !hCfg )
        {
    	    NC_SystemClose();
    	    return;
        }
        CfgAddEntry( hCfg,CFGTAG_SYSINFO,CFGITEM_DHCP_HOSTNAME,0,strlen(HostName),(UINT8*)HostName,0);

	CI_IPNET NA;
	bzero( &NA, sizeof(NA) );
	NA.IPAddr  = inet_addr(LocalIPAddr);
	NA.IPMask  = inet_addr(LocalIPMask);
	strcpy( NA.Domain, DomainName );
	NA.NetType = 0;
        CfgAddEntry( hCfg, CFGTAG_IPNET, 1, 0,sizeof(CI_IPNET), (UINT8 *)&NA, 0 );

	CI_ROUTE RT;
	bzero( &RT, sizeof(RT) );
	RT.IPDestAddr = 0;
	RT.IPDestMask = 0;
	RT.IPGateAddr = inet_addr(GatewayIP);
	CfgAddEntry( hCfg, CFGTAG_ROUTE, 0, 0,sizeof(CI_ROUTE), (UINT8 *)&RT, 0 );

	IPN IPTmp = inet_addr(DNSServer);
	if( IPTmp )
	{
		CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 );
	}

        rc = DBG_WARN;
        CfgAddEntry(hCfg,CFGTAG_OS,CFGITEM_OS_DBGPRINTLEVEL,CFG_ADDMODE_UNIQUE, sizeof(uint),(UINT8 *)&rc,0);

        rc = 8192;
        CfgAddEntry(hCfg,CFGTAG_IP,CFGITEM_IP_SOCKUDPRXLIMIT,CFG_ADDMODE_UNIQUE,sizeof(uint),(UINT8 *)&rc,0);

        do
        {
            rc = NC_NetStart( hCfg, NetworkOpen, NetworkClose, NetworkIPAddr );
        } while( rc > 0 );

        CfgFree( hCfg );

        NC_SystemClose();
}

static void NetworkOpen()
{
        hHello = DaemonNew( SOCK_DGRAM,0,7,dtask_udp_hello,OS_TASKPRINORM,OS_TASKSTKNORM,0,1);
}

static void NetworkClose()
{
        DaemonFree( hHello );
}

static void NetworkIPAddr( IPN IPAddr, uint IfIdx, uint fAdd )
{
        IPN IPTmp;
        if( fAdd )  printf("Network Added: ");
        else  printf("Network Removed: ");
        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 );
}

int dtask_udp_hello( SOCKET s, UINT32 unused )
{
	printf("TASK execution %d\n",++counter);

        (void)unused;

        struct timeval tv;
        tv.tv_sec  = 3;
        tv.tv_usec = 0;
        setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv));
        setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));

        struct sockaddr_in sin1;
        int sz=sizeof(sin1);
        int recvSize;
        HANDLE hBuffer;
        unsigned char* pBuf;
        while(1)
        {
            recvSize=recvncfrom( s, (void**)&pBuf, 0, (PSA)&sin1, &sz, &hBuffer );
            if(recvSize<=0) break;
            sendto( s, pBuf, recvSize, 0, (PSA)&sin1, sz );
            recvncfree( hBuffer );
        }

        // Since the socket is still open, return "1"
        // (we need to leave UDP sockets open)
        return 1;
}

其中EVM_init()函式被設定為在main()函式之前執行,具體設定在一個*.cfg檔案中,

部分內容如下

var Memory  =   xdc.useModule('xdc.runtime.Memory');
var BIOS    =   xdc.useModule('ti.sysbios.BIOS');
var Task    =   xdc.useModule('ti.sysbios.knl.Task');
var HeapBuf =   xdc.useModule('ti.sysbios.heaps.HeapBuf');
var Log     =   xdc.useModule('xdc.runtime.Log');
//...省略...
Program.sectMap["sharedL2"] = "DDR3"; 
Program.sectMap["systemHeap"] = "DDR3";
Program.sectMap[".sysmem"]  = "DDR3";
Program.sectMap[".args"]    = "DDR3";
Program.sectMap[".cio"]     = "DDR3";
Program.sectMap[".far"] 	= 	"DDR3";
Program.sectMap[".rodata"] 	= 	"DDR3";
Program.sectMap[".neardata"] 	= 	"DDR3";
//...省略...
Startup.lastFxns.$add('&EVM_init');
BIOS.taskEnabled			=   true;

Ecm.eventGroupHwiNum[0] = 7;
Ecm.eventGroupHwiNum[1] = 8;
Ecm.eventGroupHwiNum[2] = 9;
Ecm.eventGroupHwiNum[3] = 10;
Global.IPv6 = true;

注意其中的

Startup.lastFxns.$add('&EVM_init');

在主函式中執行BIOS_start()會完成一些主動操作

(似乎是因為main函式在DSP中的地位和在PC上不一樣)

總之,在執行完EVM_init()完成基本的初始化後,建立我們的主要任務:

Task_Handle task1 = Task_create(Test, NULL, NULL);
Task_Handle task2 = Task_create(Hello, NULL, NULL);

其中Hello任務只是為了演示一下,每隔2秒(sleep(2000))列印一個“Hello”字樣

而Test任務則執行了QMSS、CPPI、PA等等的初始化,完成了基本網路配置

啟動Network服務後,關聯了dtask_udp_hello任務,等待乙太網介面的連線

另一邊使用PC執行測試,傳送字串進行互動。

因為我們的程式中設定了一個計數器counter

每次傳送一個字串,dtask_udp_hello()就執行一次,counter++

在Hello任務中,一旦發現條件counter>=3滿足了就會退出while()迴圈,它的使命也就終結了

(注意並不是真的終結,因為沒有執行KillTask這樣的命令,只是Hello任務不再執行任何操作罷了)

這樣只剩下Test任務獨自運行了

某次測試如下


本文原創,博文地址