zmain_dev_info(); #ifdef LCD_SUPPORTED zmain_lcd_init(); #endif
#ifdef WDT_IN_PM1
WatchDogEnable( WDTIMX ); #endif
osal_start_system(); return 0; }
主函数要做的事情非常简单,首先进行了一些初始化,包括各层的初始化,硬件初始化,以及任务的初始化等,然后就进入到操作系统当中,即
osal_start_system(); 就再也出不来了。操作系统的作用就是如果有事件发生,就把这个消息通知给处理该事件的事件处理函数去执行,然后一直的循环查找有没有事件发生。另外说一下,事件是定义在任务当中的,即一个任务可能有多个事件,每个任务对应一个事件处理函数。在这个程序中,一共有6个任务,有兴趣的同学可以自己查看void osalInitTasks( void )函数的代码。 接下来看一下zigbee协调器是怎么建立网络的
首先我们必须选择SimpleCollectorEB版本,在APP文件下看到sapi.c源文件。找到SAPI_Init(byte task_id)函数,此函数是进行sapi层的初始化,代码如下
void SAPI_Init( byte task_id ) {
sapi_TaskID = task_id;//将操作系统初始化任务时定义的任务id号传进来 sapi_bindInProgress = 0xffff;//设置不允许绑定
sapi_epDesc.task_id = &sapi_TaskID;//给端口描述符的任务ID号赋值,感觉也就是端口收到的数据或者消息就交给ID号指定的任务来处理。 sapi_epDesc.endPoint = 0;//端口描述符端口号初始化为0。
#if ( SAPI_CB_FUNC )//编译通过
sapi_epDesc.endPoint = zb_SimpleDesc.EndPoint;//端口号赋值
sapi_epDesc.task_id = &sapi_TaskID;//任务ID赋值,与上面的任务ID的值是相同的。
sapi_epDesc.simpleDesc = (SimpleDescriptionFormat_t
*)&zb_SimpleDesc;//简单描述符赋值,是描述一个端口最基本的信息
sapi_epDesc.latencyReq = noLatencyReqs;//这是一个枚举类型的,不清楚具体含义,不过大家都设成noLatencyReqs,除此之外还有两个值。
afRegister( &sapi_epDesc );//将定义的端点在AF层注册,一定要注册后端点才会生效 #endif
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);//设置描述符不能匹配
// Register callback evetns from the ZDApp
ZDO_RegisterForZDOMsg( sapi_TaskID, NWK_addr_rsp );//在sapi层注册网络地址事件,这个函数可以截取空中发来的消息,有兴趣的可以查查资料,第一个函数是截取的消息发到哪个任务中去,第二个参数,cluserID是消息的类型。 ZDO_RegisterForZDOMsg( sapi_TaskID, Match_Desc_rsp );//同理,在sapi层注册匹配描述符事件。
#if ( SAPI_CB_FUNC )
#if (defined HAL_KEY) && (HAL_KEY == TRUE) // Register for HAL events
RegisterForKeys( sapi_TaskID );//注册按键响应事件
if ( HalKeyRead () == HAL_KEY_SW_5)
{ uint8 startOptions = ZCD_STARTOPT_CLEAR_STATE | ZCD_STARTOPT_CLEAR_CONFIG;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset(); }
#endif // HAL_KEY
osal_set_event(task_id, ZB_ENTRY_EVENT);//在这里设置了一个进入事件,第一个参数是task_id是任务的ID号,因此我们可以在sapi层的事件处理函数中找到这个进入事件是怎么处理的。 #endif }
在UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )函数中,找到
if ( events & ZB_ENTRY_EVENT ) {
uint8 startOptions;
// Give indication to application of device startup #if ( SAPI_CB_FUNC )
zb_HandleOsalEvent( ZB_ENTRY_EVENT ); #endif
// LED off cancels HOLD_AUTO_START blink set in the stack HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);//为了方便观察实验现象,将第四个灯关闭。
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
if ( startOptions & ZCD_STARTOPT_AUTO_START ) {
zb_StartRequest(); } else {
// blink leds and wait for external input to config and restart HalLedBlink(HAL_LED_2, 0, 50, 500); }
return (events ^ ZB_ENTRY_EVENT ); }
这个时候,程序就停在这里,只能看到LED_2在闪烁。这个时候我们可以按下按键1,然后去找一下,事件处理函数中如何对此事件进行相应。找到UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )函数中的关于按键的处理: case KEY_CHANGE: #if ( SAPI_CB_FUNC )
zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys ); #endif
break;
进入到HandleKeys函数中,找到
if ( keys & HAL_KEY_SW_1 ) {
if ( myAppState == APP_INIT ) {
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );//读取flash中的设备类型
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE ) {
logicalType = ZG_DEVICETYPE_COORDINATOR;//将设备类型改变为协调器类型
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);//将设备类型写入到flash中 }
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );//读取启动模式
startOptions = ZCD_STARTOPT_AUTO_START;//将启动模式赋值为自动启动模式
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );//将启动模式存入到flash中
zb_SystemReset();//系统重启设置。这时候flash中,启动模式就变成了ZCD_STARTOPT_AUTO_START,系统重启以后,系统继续刚才讲过的过程,不同的是在进行到进入事件处理函数时,if ( startOptions &
ZCD_STARTOPT_AUTO_START )的值成立,调用if语句里面的zb_StartRequest()函数;即执行开始请求函数。 }
接下来进入到zb_StartRequest函数中看一看,原代码如下: void zb_StartRequest() {
uint8 logicalType;
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );//从flash中读出设备类型。
// Check for bad combinations of compile flag definitions and device type setting.
if ((logicalType > ZG_DEVICETYPE_ENDDEVICE) || //可以判断if里面语句为0,执行else
#if !ZG_BUILD_ENDDEVICE_TYPE // Only RTR or Coord possible. (logicalType == ZG_DEVICETYPE_ENDDEVICE) || #endif
#if !ZG_BUILD_RTR_TYPE // Only End Device possible. (logicalType == ZG_DEVICETYPE_ROUTER) || (logicalType == ZG_DEVICETYPE_COORDINATOR) || #elif ZG_BUILD_RTRONLY_TYPE // Only RTR possible. (logicalType == ZG_DEVICETYPE_COORDINATOR) || #elif !ZG_BUILD_JOINING_TYPE // Only Coord possible. (logicalType == ZG_DEVICETYPE_ROUTER) || #endif
(0)) {
logicalType = ZB_INVALID_PARAMETER;
SAPI_SendCback(SAPICB_START_CNF, logicalType, 0); } else {
logicalType = ZB_SUCCESS; //将设备类型改为ZB_SUCCESS ZDOInitDevice(zgStartDelay); // 执行初始化设备函数。 }
return; }
那么接下来去初始化设备函数中看一下,右键,go to definition
uint8 ZDOInitDevice( uint16 startDelay ) {
uint8 networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE; //首先更改了网络状态为初始化新网络状态 uint16 extendedDelay = 0; if ( devState == DEV_HOLD ) {
zgInitItems( FALSE ); }
ZDConfig_InitDescriptors();
_NIB.CapabilityInfo = ZDO_Config_Node_Descriptor.CapabilityFlags;
devState = DEV_INIT; // 设备状态改为初始化 ZDApp_LeaveCtrlInit(); //离开控制初始化
ZDApp_LeaveCtrlStartup( &devState, &startDelay );//检查离开控制时的一些设置