WinCE应用程序助手简介

供稿:成都英创信息技术有限公司

  • 关键词:WinCE,应用程序助手
  • 作者:emtronix
  • 摘要:一个高质量的应用程序,首先表现在较少的现场维护,不仅大幅度降低了设备开发费用,同时也为客户赢得后续的市场声誉。因此如何在设备出厂之前就能确定应用程序的基本质量,就变得至关重要了。

背景

  在基于英创工控主板的智能整机设备的开发过程中,客户应用程序的开发通常都是最为关键性的工作,其工作量往往也是最大的。一个高质量的应用程序,首先表现在较少的现场维护,不仅大幅度降低了设备开发费用,同时也为客户赢得后续的市场声誉。因此如何在设备出厂之前就能确定应用程序的基本质量,就变得至关重要了。

  

  基于我们十多年长期不断地对客户应用程序的技术支持的经验,一般来说,如果一个应用程序在完成基本的应用功能的基础上,整个应用进程(包括进程的所有活动线程)的CPU负载率保持在一个合理的水平,比如低于70%,那么我们就可以认为运行于英创工控主板上的这个应用程序其质量是有基本保证的。为了方便客户随时了解应用程序的运行状况,我们计划在主板中嵌入一款称为应用程序助手(AppHelper)的监测程序。AppHelper仅使用很少的CPU资源,就可为客户提供系统各个进程的CPU开销情况,对客户的应用进程,还将提供进程中各个活动线程的运行状况。客户根据这些信息及可方便及时的了解程序运行的总体情况,快速确定程序代码需要优化的地方。


  本文的后续部分主要介绍AppHelper的使用方法及信息输出的格式。


AppHelper的输出接口


  CE应用程序助手AppHelper的主要功能是提供系统运行状况的基本信息。这些基本信息可支持多种通讯接口输出,这些接口包括调试串口、USB OTG接口、应用串口COM2 – COM9、以太网接口。客户可根据自身设备的特点,方便地选择输出接口。调试串口是AppHelper的缺省输出接口。


  AppHelper输出信息的基本格式都是标准的ASCII码字符串,客户通过PC上的一款串口终端窗口程序(推荐使用开源的Tara Term),就可看到输出的信息。


  若客户希望使用USB或应用串口来观察AppHelper的输出信息,需要通过执行主板上的AppHelperConfig进行端口配置:

  \> AppHelperConfig p1 [p2]


  上式中p1 = 1, 2, .. 9;其中 = 1表示使用COM1端口,在英创主板中COM1端口是基于USB OTG的虚拟串口,英创公司的EM335x产品线和EM928x产品线的所有产品均支持USB OTG虚拟串口功能,虚拟串口的使用方法与实际物理串口完全一致。参数p1 = 2 – 9分别对应物理串口COM2 – COM9。注意在选择物理串口时,应避免使用低速串口。参数p2为串口的波特率,缺省配置为115200bps。除非特别的需求,一般不设置该参数,即推荐使用115200波特率。


  用户只需在输出串口上输入3个以上的字符(键盘连按3次以上),就会激活AppHelper。AppHelper将按2秒间隔输出系统运行状态信息。


  若用户希望通过以太网口来观察AppHelper的输出信息,则可通过telnet登录系统后,直接运行SysInfo.exe,就可在CMD窗口看到系统的运行信息。SysInfo可带一个输入参数,来确定输出信息的时间,缺省的时间为10s。AppHelper每2秒输出一次系统运行参数。


AppHelper信息输出格式


  AppHelper的输出格式如下:


  AppHelper v0.1 Oct 18 2015 17:36:33 Emtronix(c)

  CPU:2% FreeMemory=148.59MiB FreeNand=123.99MiB

  ….


  第一行是AppHelper的版本信息,第二行是系统总的CPU负载、程序内存的剩余空间,以及NandFlash的剩余空间。之后的每一行是一个进程或线程的CPU占用率。其中每个进程的名称就是对应的exe文件名,而对线程来说,系统只提供有线程ID。客户一般说来很难根据线程ID来辨识具体是应用程序中哪个线程,例如串口接收线程。


应用线程命名


  为了客户更容易识别应用线程,AppHelper为应用程序提供了2个API函数。应用程序在创建线程后,通过API函数来为该线程注册一个希望字符串名;当线程退出时,则通过API函数注销该字符串。AppHelper提供的这两个API函数为:

  BOOL RegisterThreadName(DWORD dwThreadID, TCHAR* sThreadName);

  BOOL UnRegisterThreadName(DWORD dwThreadID);


  注册操作一般直接跟在线程创建之后,其代码如下:

  DWORD  dwThreadID = 0;

  TCHAR   sThreadName[] = L” ReceiveThread”;  // 注意32个字符!

   // create rx thread

   m_hRxThread  = CreateThread((LPSECURITY_ATTRIBUTES)NULL,

                                   0,

                              

    (LPTHREAD_START_ROUTINE)ReceiveThread,

                                   (LPVOID)pPara,

                                   0,

                                   &dwThreadID);

  RegisterThreadName(dwThreadID, sThreadName);


  线程名注销操作则更简单,直接放在线程退出之前即可。


  以下是AppHelper提供的这两个API函数的具体实现,该代码应包含在应用程序之中。


  struct _THREAD_INDEX

  {

      DWORD   dwSize;             // struct size in byte

      DWORD   dwThreadID;         // a thread id

     TCHAR   szThreadName[32];   // user-defined name associated with the

                                 // thread id above

      struct _THREAD_INDEX    *pNext;             // = NULL

  };

  typedef struct _THREAD_INDEX    THREAD_INDEX, *PTHREAD_INDEX;


  BOOL RegisterThreadName(DWORD dwThreadID, TCHAR* sThreadName)

  {

      BOOL            bRet = TRUE;

      THREAD_INDEX    ThreadNode;

      PTHREAD_INDEX   pNode = &ThreadNode;

      DWORD           dwLen;

      HANDLE          hDevFile = NULL;


      memset(&ThreadNode, 0, sizeof(THREAD_INDEX));

      pNode->dwSize = sizeof(THREAD_INDEX);

  

      dwLen = wcslen(sThreadName);

      if(!dwThreadID || (dwLen >= 32))

      {

          bRet = FALSE;

          goto cleanup;

      }


      pNode->dwThreadID = dwThreadID;

      wcscpy(pNode->szThreadName, sThreadName);


      hDevFile = CreateFile(L"HLP1:",             // name of device

                      GENERIC_READ|GENERIC_WRITE, // desired access

                      0,                          // sharing mode

                      NULL,                       // security attributes

                      OPEN_EXISTING,              // creation disposition

                      0,                          // flags/attributes

                      NULL);                      // template file

      if(hDevFile == INVALID_HANDLE_VALUE)

      {

          hDevFile = NULL;

          bRet = FALSE;

          goto cleanup;

      }


      dwLen = 0;

      if(!WriteFile(hDevFile, pNode, sizeof(THREAD_INDEX), &dwLen, NULL))

      {

          bRet = FALSE;

      }

      CloseHandle(hDevFile);


  cleanup:

      return bRet;

  }


  BOOL UnRegisterThreadName(DWORD dwThreadID)

  {

      BOOL            bRet = TRUE;

      THREAD_INDEX    ThreadNode;

      PTHREAD_INDEX   pNode = &ThreadNode;

      DWORD           dwLen;

      HANDLE          hDevFile = NULL;


      memset(&ThreadNode, 0, sizeof(THREAD_INDEX));

      pNode->dwSize = sizeof(THREAD_INDEX);


      if(!dwThreadID)

      {

          bRet = FALSE;

          goto cleanup;

      }


      pNode->dwThreadID = dwThreadID;


      hDevFile = CreateFile(L"HLP1:",             // name of device

                      GENERIC_READ|GENERIC_WRITE, // desired access

                      0,                          // sharing mode

                      NULL,                       // security attributes

                      OPEN_EXISTING,              // creation disposition

                      0,                          // flags/attributes

                      NULL);                      // template file

      if(hDevFile == INVALID_HANDLE_VALUE)

      {

          hDevFile = NULL;

          bRet = FALSE;

          goto cleanup;

      }


      dwLen = 0;

      if(!WriteFile(hDevFile, pNode, sizeof(THREAD_INDEX), &dwLen, NULL))

      {

          bRet = FALSE;

      }

      CloseHandle(hDevFile);


  cleanup:

      return bRet;

  }


  预计在2015年10月底前,AppHelper将首先安装到EM335x产品线的所有主板,并在11月份部署到EM928x产品线。欢迎新老客户评估测试CE应用程序助手。

发布时间:2016年6月24日 13:45  人气:   审核编辑(苏强)
更多内容请访问(成都英创信息技术有限公司
相关链接

我有需求