zigbee2007中工程执行流程(初始化部分) 小记

废话什么的就不罗嗦了,直接开说 
首先找到工程的主文件,即整个工程的入口 
ZMain\ZMain.c 
进入主函数 int main() 如下

 1 int main( void )
 2 {
 3   // Turn off interrupts
 4   osal_int_disable( INTS_ALL );
 5 
 6   // Initialization for board related stuff such as LEDs
 7   HAL_BOARD_INIT();
 8 
 9   // Make sure supply voltage is high enough to run
10   zmain_vdd_check();
11 
12   // Initialize stack memory
13  zmain_ram_init(); 14 15 // Initialize board I/O 16  InitBoard( OB_COLD ); 17 18 // Initialze HAL drivers 19  HalDriverInit(); 20 21 // Initialize NV System 22  osal_nv_init( NULL ); 23 24 // Initialize basic NV items 25  zgInit(); 26 27 // Initialize the MAC 28  ZMacInit(); 29 30 // Determine the extended address 31  zmain_ext_addr(); 32 33 #ifndef NONWK 34 // Since the AF isn't a task, call it's initialization routine 35  afInit(); 36 #endif 37 38 // Initialize the operating system 39  osal_init_system(); 40 41 // Allow interrupts 42  osal_int_enable( INTS_ALL ); 43 44 // Final board initialization 45  InitBoard( OB_READY ); 46 47 // Display information about this device 48  zmain_dev_info(); 49 50 /* Display the device info on the LCD */ 51 #ifdef LCD_SUPPORTED 52  zmain_lcd_init(); 53 #endif 54 55 #ifdef WDT_IN_PM1 56 /* If WDT is used, this is a good place to enable it. */ 57  WatchDogEnable( WDTIMX ); 58 #endif 59 60 osal_start_system(); // No Return from here 61 62 // Shouldn't get here 63 return ( 0 ); 64 } 

整理上面的程序,容易知道,进入main后,首先是各种检测和初始化,之后是 这里我们比较感兴趣的 
osal_init_system(); 以及最后的 osal_start_system()

先说系统初试化 
(附 osalInitTasks()位于 OSAL.c 中)

uint8 osal_init_system( void )
{
  // Initialize the Memory Allocation System
  osal_mem_init();

  // Initialize the message queue
  osal_qHead = NULL;

#if defined( OSAL_TOTAL_MEM )
  osal_msg_cnt = 0;
#endif

  // Initialize the timers
 osalTimerInit(); // Initialize the Power Management System  osal_pwrmgr_init(); // Initialize the system tasks.  osalInitTasks(); // Setup efficient search for the first free block of heap.  osal_mem_kick(); return ( SUCCESS ); }

照例,先是系统级的初始化,这里我们直接看工程对应的 
osalInitTasks(); (位于 OSAL_SerialApp.c) 
跟踪并打开如下

 1 void osalInitTasks( void )
 2 {
 3   uint8 taskID = 0;
 4 
 5   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
 6   //osal_mem_alloc()为当前OSAL中的各任务分配存储空间(实际上是一个任务数组),函数返回指向任务缓冲
 7   //区的指针,因此tasksEvents指向该任务数组(任务队列).注意tasksEvents和后面谈到的tasksArr[]里的顺
 8   //序是一一对应的, tasksArr[ ]中的第i个事件处理函数对应于tasksEvents中的第i个任务的事件.
 9 
10   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
11   //申请内存空间,大小为 sizeof( uint16 )乘tasksCnt
12   //sizeof( uint16 )是4个字节,即一个任务的长度(同样是uint16定义)
13   //乘以任务数量tasksCnt
14 
15   macTaskInit( taskID++ ); 16 nwk_init( taskID++ ); 17 Hal_Init( taskID++ ); 18 #if defined( MT_TASK ) 19 MT_TaskInit( taskID++ ); 20 #endif 21 APS_Init( taskID++ ); 22 #if defined ( ZIGBEE_FRAGMENTATION ) 23 APSF_Init( taskID++ ); 24 #endif 25 ZDApp_Init( taskID++ ); 26 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined(ZIGBEE_PANID_CONFLICT ) 27 ZDNwkMgr_Init( taskID++ ); 28 #endif 29  SerialApp_Init( taskID ); 30 }

在这部分中 
1、主要任务就是对各个系统内的层次进行初始化,其中核心的 SerialApp_Init( taskID ) 处在最后 
2、注意此处的taskID,表示任务的优先级,在 ZDProfile.c 中有其定义,如下

1 typedef struct
2 {
3   void *next;
4   uint8 taskID;
5   uint16 clusterID;
6 } ZDO_MsgCB_t;

注意结构体 ZDO_MsgCB_t 后面还会提到,可见这个结构体中包含了 任务ID 和 簇ID

3、现在回头看第一句

1   uint8 taskID = 0;
2   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);//此步骤的关键作用在于
3   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
    • 首先令id=0
    • (uint16 *) 是强制转换,不说,关键在于后面 
      osal_mem_alloc( sizeof( uint16 ) * tasksCnt),来看函数的原文描述,如下
    • 1    @fn      osal_mem_alloc
      2       @brief   Implementation of the allocator functionality.
      3       @param   size - number of bytes to allocate from the heap.
      4       @return  void * - pointer to the heap allocation; NULL if error or failure.

      也就是说,该函数负责 执行分配功能 ,osal_mem_alloc( uint16 size ),其中size就是要分配的字节大小,sizeof( uint16 )是4个字节,即一个任务的长度(同样是uint16定义),乘以任务数量tasksCnt,即全部内存空间。 
      这里看一下 tsaksCnt,跟踪可知

            const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
              uint16 *tasksEvents;
      sizeof 表示返回一个对象或者类型所占的内存字节数。
            也就是,通过这样  tasksCnt 就可以得到总共的任务个数,tasksArr是任务列表,稍后说。
      

      接上面说,osal_mem_alloc 的返回 :如果成功执行则返回指向一个缓存的指针,一个无类型指针指向被分配的新的缓存区。

      • 之后将上面返回的空指针(指向被分配的缓存区)赋给tasksEvents
      • 之后第三句 osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt))
         1  * @fn      osal_memset
         2  * @brief   Set memory buffer to value.
         3  * 
         4  * @param   dest - pointer to buffer
         5  * @param   value - what to set each uint8 of the message
         6  * @param   size - how big
         7 
         8  * @return  value of next widget, 0 if no widget found 9 10 void *osal_memset( void *dest, uint8 value, int len ) 11  { 12 return memset( dest, value, len ); 13 }

        该函数的作用是给内存设定指定地址、指定内容、指定大小的,话说怎么感觉那么像三归 哈~ 
        osal_memset()把开辟的内存全部设置为0;sizeof( uint16 )是4个字节,即一个任务的长度(同样是uint16定义),乘以任务数量tasksCnt,即全部内存空间

        以上,总结一下第3点: 
        首先令taskID=0,期间通过 tasksCnt的定义 顺带计算osal中总的任务数量 (任务队列数组的总字节数 除以 每个任务的字节数 unit16都是4) 
        然后tasksEvents = (uint16 )osal_mem_alloc( sizeof( uint16 ) tasksCnt)进行内存空间的分配,成功后将结果 也就是指向 heap allocation 的空指针 赋给 tasksEvents 
        然后通过 osal_memset()把开辟的内存(tasksEvents指向的区域)全部设置对应的值value为0,大小就是 
        sizeof( uint16 )是4个字节,即一个任务的长度(同样是uint16定义),乘以任务数量tasksCnt, 即全部内存空间。

        =========================================================================================
        4、下面开始说 osalInitTasks( void ) 中的 SerialApp_Init( taskID ),跟踪打开如下

         1 void SerialApp_Init( uint8 task_id )
         2 {
         3         halUARTCfg_t uartConfig;
         4 
         5         P0SEL &= 0xDf;                  //设置P0.5口为普通IO
         6         P0DIR |= 0x20;                  //设置P0.5为输出
         7         LAMP_PIN = 1;                   //高电平继电器断开;低电平继电器吸合
         8         P0SEL &= ~0x40;                 //设置P0.6为普通IO口
         9         P0DIR &= ~0x40;                 //设置P0.6为输入口
        10         P0SEL &= 0x7f;                  //P0_7配置成通用io
        11 
        12     SerialApp_TaskID = task_id;
        13     //SerialApp_RxSeq = 0xC3;
        14 
        15     afRegister( (endPointDesc_t *)&SerialApp_epDesc );
        16 
        17  RegisterForKeys( task_id ); 18 19 uartConfig.configured = TRUE; // 2x30 don't care - see uart driver. 20 uartConfig.baudRate = SERIAL_APP_BAUD; 21 uartConfig.flowControl = FALSE; 22 uartConfig.flowControlThreshold = SERIAL_APP_THRESH; // 2x30 don't care - see uart driver. 23 uartConfig.rx.maxBufSize = SERIAL_APP_RX_SZ; // 2x30 don't care - see uart driver. 24 uartConfig.tx.maxBufSize = SERIAL_APP_TX_SZ; // 2x30 don't care - see uart driver. 25 uartConfig.idleTimeout = SERIAL_APP_IDLE; // 2x30 don't care - see uart driver. 26 uartConfig.intEnable = TRUE; // 2x30 don't care - see uart driver. 27 uartConfig.callBackFunc = SerialApp_CallBack; 28 HalUARTOpen (UART0, &uartConfig); 29 30 #if defined ( LCD_SUPPORTED ) 31 HalLcdWriteString( "SerialApp", HAL_LCD_LINE_2 ); 32 #endif 33 //HalUARTWrite(UART0, "Init", 4); 34 //ZDO_RegisterForZDOMsg( SerialApp_TaskID, End_Device_Bind_rsp ); 35 //ZDO_RegisterForZDOMsg( SerialApp_TaskID, Match_Desc_rsp ); 36 }

        此为 串口app任务 的初始化 ,下面进行相关语句分析,没提到的不另做说明 
        4.1 afRegister( (endPointDesc_t *)&SerialApp_epDesc ); 
        作用:Register an Application’s EndPoint description ,注册一个应用的端点描述符

         1 * @fn      afRegister
         2 
         3 * @brief   Register an Application's EndPoint description.
         4 
         5 * @param   epDesc - pointer to the Application's endpoint descriptor.
         6 
         7 * @return  afStatus_SUCCESS - Registered
         8 *          afStatus_MEM_FAIL - not enough memory to add descriptor
         9 *          afStatus_INVALID_PARAMETER - duplicate endpoint
        10 
        11 afStatus_t afRegister( endPointDesc_t *epDesc )
        12 { 13 epList_t *ep; 14 15 // Look for duplicate endpoint 16 if ( afFindEndPointDescList( epDesc->endPoint ) ) 17 return ( afStatus_INVALID_PARAMETER ); 18 19 ep = afRegisterExtended( epDesc, NULL ); 20 21 return ((ep == NULL) ? afStatus_MEM_FAIL : afStatus_SUCCESS); 22 }

        函数类型为 afStatus_t , 跟踪可知 typedef ZStatus_t afStatus_t;又 typedef Status_t ZStatus_t;又 typedef uint8 Status_t; 
        函数参数为 epDesc - pointer to the Application’s endpoint descriptor,即一个 endPointDesc_t 类型的指针

        在 afRegister( (endPointDesc_t *)&SerialApp_epDesc ) 中 可见,该注册函数指向了 SerialApp_epDesc 对应的指针 
        下面具体看一下这个指针类型

        1 typedef struct
        2 {
        3   byte endPoint;
        4   byte *task_id;  // Pointer to location of the Application task ID.
        5   SimpleDescriptionFormat_t *simpleDesc;
        6   afNetworkLatencyReq_t latencyReq;
        7 } endPointDesc_t;

        这个也就是 端点描述符的定义,这里展看结构体中的 SimpleDescriptionFormat_t 看一下

         1 typedef struct
         2 {                                  //关于此冒号的用法,见
         3   byte          EndPoint;
         4   uint16        AppProfId;
         5   uint16        AppDeviceId;       //app设备ID
         6   byte          AppDevVer:4;       //app版本号,冒号4,此处冒号用法为 “定义变量:占位符”表明定义的变量的需要位数
         7   byte          Reserved:4;        //保留,具体是什么可以自己看着办,比如下面的实例中用来表示 程序的版本标识           
         8                                    // AF_V1_SUPPORT uses for AppFlags:4.
         9   byte          AppNumInClusters;
        10   cId_t         *pAppInClusterList;
        11   byte          AppNumOutClusters;
        12   cId_t         *pAppOutClusterList; 13 } SimpleDescriptionFormat_t;

        附:变量声明加冒号 C语言变量声明加冒号的用法(占位符) 
        上面这两个定义,均在 AF.h 中 
        下面 对照程序中的 SerialApp_epDesc 看一下,下面的函数定位于 SerialApp.c 中

        1 const endPointDesc_t SerialApp_epDesc =
        2 {
        3     SERIALAPP_ENDPOINT,
        4     &SerialApp_TaskID,
        5     (SimpleDescriptionFormat_t *)&SerialApp_SimpleDesc,
        6     noLatencyReqs
        7 };

        又其中 SerialApp_SimpleDesc 可得

         1 const SimpleDescriptionFormat_t SerialApp_SimpleDesc =
         2 {
         3     SERIALAPP_ENDPOINT,              //  int   Endpoint;
         4     SERIALAPP_PROFID,                //  uint16 AppProfId[2];
         5     SERIALAPP_DEVICEID,              //  uint16 AppDeviceId[2];
         6     SERIALAPP_DEVICE_VERSION,        //  int   AppDevVer:4;
         7     SERIALAPP_FLAGS,                 //  int   AppFlags:4;
         8     SERIALAPP_MAX_CLUSTERS,          //  byte  AppNumInClusters;
         9     (cId_t *)SerialApp_ClusterList,  //  byte *pAppInClusterList;
        10     SERIALAPP_MAX_CLUSTERS,          //  byte  AppNumOutClusters;
        11     (cId_t *)SerialApp_ClusterList   //  byte *pAppOutClusterList;
        12 };

        具体来说,看一下这几个参数的情况,在 SerialApp.h 中

        #define SERIALAPP_ENDPOINT               11
        #define SERIALAPP_PROFID                 0x0F05
        #define SERIALAPP_DEVICEID               0x0001
        #define SERIALAPP_DEVICE_VERSION         0
        #define SERIALAPP_FLAGS                  0

        `故可知,相关参数,在头文件中定义

        4.2 下面看一下 RegisterForKeys( task_id ) 
        它完成任务对按键事件的注册工作,这里如果不注册的话在后来的程序里是不会产生KEY_CHANG这个事件。

        byte RegisterForKeys( byte task_id ) 

        // Allow only the first task 
        if ( registeredKeysTaskID == NO_TASK_ID ) 

        registeredKeysTaskID = task_id;//注意这句话,就是给任务注册。和任务的ID号联系起来 
        return ( true ); 

        else 
        return ( false ); 
        }

        这样就把任务和事件联系在了一起

转载于:https://www.cnblogs.com/ifner/p/4438192.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值