学习zigbee入门-10

来源:互联网 发布:java bloomfilter原理 编辑:程序博客网 时间:2024/05/18 01:40

【转】学习zigbee入门-10

SimpleApp 例子解读-2 程序分析:

        灯开关灯实验:开关设备通过发送命令切换控制设备的状态,并通过指示灯的状态变化反应操作是否成功。

       在SimpleApp,SimpleController.c(灯管理器设备)按键处理函数zb_HandleKeys中,当SW1被按下,它将使设备作为协调器使用;期间按下SW2,它将是该设备作为路由器启动。

1.网络形成:

ZDO_StartDevice

功能描述:在网络中启动设备,协调器、路由器、终端设备都可以用该函数启动,启动之后,设备根据自身的类型去建立或发现和加入网络。 
看看ZDO_StartDevice函数完整形式:

void ZDO_StartDevice( byte logicalType,

                                      devStartModes_t startMode,

                                     byte beaconOrder,

                                     byte superframeOrder )
{
ZStatus_t ret;

ret = ZUnsupportedMode;

#if defined(ZDO_COORDINATOR)                 //--条件编译语句,选择性的启动协调器
if ( logicalType == NODETYPE_COORDINATOR ) //--逻辑类型,协调器 
{
    if ( startMode == MODE_HARD )            //--启动模式,硬件启动(软件启动无线龙注释暂不启动) 
    {
      devState = DEV_COORD_STARTING;        //--协调器启动   
      ret = NLME_NetworkFormationRequest( zgConfigPANID, zgDefaultChannelList, //--网路形成请求
                                          zgDefaultStartingScanDuration, beaconOrder,
                                          superframeOrder, false );
    }
    else if ( startMode == MODE_RESUME )     //--恢复
    {
      // Just start the coordinator
      devState = DEV_COORD_STARTING;
      ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false ); //--路由启动请求 
    }
    else
    {
#if defined( LCD_SUPPORTED ) //--液晶显示支持(--条件编译)
      //HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
      ClearScreen();
      Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);
      Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);
#endif
    }
}
#endif // !ZDO_COORDINATOR

#if !defined ( ZDO_COORDINATOR ) || defined( SOFT_START ) //--不是协调器,软件启动 
if ( logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE )//--逻辑类型,路由,终端设备
{
    if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) ) //--启动模式,加入,再加入
    {
      devState = DEV_NWK_DISC;

#if defined( MANAGED_SCAN ) //--管理扫描
      ZDOManagedScan_Next();   //--调用管理扫描
      ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask, BEACON_ORDER_15_MSEC );//--网络发现请求
#else
      ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
#endif
    }
    else if ( startMode == MODE_RESUME ) //--恢复
    {
      if ( logicalType == NODETYPE_ROUTER ) //--路由
      {
        ZMacScanCnf_t scanCnf;              //--扫描确认
        devState = DEV_NWK_ORPHAN;          //--设备已经失去了其母节点的信息

        /* if router and nvram is available, fake successful orphan scan */ 
        //--如果路由器和NVRAM可用,假成功的孤儿扫描
        scanCnf.hdr.Status = ZSUCCESS;    
        scanCnf.ScanType = ZMAC_ORPHAN_SCAN;
        scanCnf.UnscannedChannels = 0;
        scanCnf.ResultListSize = 0;
        nwk_ScanJoiningOrphan(&scanCnf);

        ret = ZSuccess;
      }
      else                          //--终端节点
      {
        devState = DEV_NWK_ORPHAN;
        ret = NLME_OrphanJoinRequest( zgDefaultChannelList, //--再加入请求
                                      zgDefaultStartingScanDuration );
      }
    }
    else
    {
#if defined( LCD_SUPPORTED )
     // HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
      Print8(HAL_LCD_LINE_1,10,"StartDevice ERR",1);
      Print8(HAL_LCD_LINE_2,10,"MODE unknown",1);
#endif
    }
}
#endif //!ZDO COORDINATOR || SOFT_START

if ( ret != ZSuccess )
    osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY );
}


2、绑定:

zb_BindDevice ----已知扩展地址的绑定(1.4.3-1.2.1把已知和未知的结合起来了,还结合了绑定移除)

                           ---未知设备扩展地址的绑定

                           ---移除绑定

//--设备建立绑定和移除绑定信息相关
void zb_BindDevice ( uint8 create,        //--是否创建绑定,ture为创建,false则解除
                    uint16 commandId,     //--命令ID,基于某种命令的绑定
                    uint8 *pDestination ) //--指向扩展地址的指针 
{
zAddrType_t destination;            //--目的设备的类型
uint8 ret = ZB_ALREADY_IN_PROGRESS; //--

if ( create )                     //--是否创建绑定,ture为创建,false则解除    
{
    if (sapi_bindInProgress == 0xffff) //--绑定地址为0xffff
    {
      if ( pDestination )                  //--已知扩展地址的绑定,即*pDestination为非NULL
      {
        destination.addrMode = Addr64Bit; //--目的地址模式,长地址
        osal_cpyExtAddr( destination.addr.extAddr, pDestination );//--把扩展地址复制到extAddr中
       //--通过APSME_BindRequest创建绑定请求
        ret = APSME_BindRequest( sapi_epDesc.endPoint, commandId,
                                            &destination, sapi_epDesc.endPoint );

        if ( ret == ZSuccess )
        {
          // Find nwk addr //--发现网络地址,得到被绑定设备的短地址
          ZDP_NwkAddrReq(pDestination, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );

          osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
        }
      }
      else
     {
        ret = ZB_INVALID_PARAMETER;
        destination.addrMode = Addr16Bit;
        destination.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
        if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumOutClusters,
                                                sapi_epDesc.simpleDesc->pAppOutClusterList ) )
        {
          // Try to match with a device in the allow bind mode --匹配一个允许绑定模式下的设备
          ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
              sapi_epDesc.simpleDesc->AppProfId, 1, &commandId, 0, (cId_t *)NULL, 0 );
        }
        else if ( ZDO_AnyClusterMatches( 1, &commandId, sapi_epDesc.simpleDesc->AppNumInClusters,
                                                sapi_epDesc.simpleDesc->pAppInClusterList ) )
        {
          ret = ZDP_MatchDescReq( &destination, NWK_BROADCAST_SHORTADDR,
              sapi_epDesc.simpleDesc->AppProfId, 0, (cId_t *)NULL, 1, &commandId, 0 );
        }

        if ( ret == ZB_SUCCESS )
        {
          // Set a timer to make sure bind completes --设置一个时间,确保绑定完成。
          osal_start_timerEx(sapi_TaskID, ZB_BIND_TIMER, AIB_MaxBindingTime);
          sapi_bindInProgress = commandId; //--允许基于命令的绑定过程
          return; // dont send cback event
        }
      }
    }

    SAPI_SendCback( SAPICB_BIND_CNF, ret, commandId );
} //--end if (creat)
else //--绑定移除

{
    // Remove local bindings for the commandId 
   BindingEntry_t *pBind;

    // Loop through bindings an remove any that match the cluster
    while ( pBind = bindFind( sapi_epDesc.simpleDesc->EndPoint, commandId, 0 ) )
    {
       bindRemoveEntry(pBind); //--完成从绑定表中移除绑定条目
    }
    osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
} //--end else 
return;
}

在上面调用了APS绑定函数APSME_BindRequest(),该函数如下原型:

extern ZStatus_t APSME_BindRequest( byte SrcEndpInt,

                                                               uint16 ClusterId, 
                                                                      zAddrType_t *DstAddr,

                                                                byte DstEndpInt);

在两个设备之间建立绑定,通过调用函数 APSME-BIND.confirm返回,如果绑定成功调用 ZDP_NwkAddrReq()得到目的设备的16位短地址。

afStatus_t ZDP_NwkAddrReq( byte *IEEEAddress, //--被请求设备的IEEE地址

                                                byte ReqType,        //--想得到的响应类型
                                                       byte StartIndex,

                                                byte SecurityEnable );

ReqType //--想得到的响应类型,它的值可能有以下两者之一:

ZDP_NWKADDR_REQTYPE_SINGLE:返回设备的短地址和扩展地址。

ZDP_NWKADDR_REQTYPE_EXTENDED:返回设备的短地址和扩展地址和所有相关设备的短地址。

调用这个函数可以产生一个根据已知遥远设备的IEEE地址,请求得到16为短地址的信息。该信息以广播形式发送到网络中的所有设备。

未知扩展地址的绑定(则按钮可以被利用):

该绑定方式下,在发送绑定请求钱,先要让被绑定的目的设备处于允许绑定的迷失,通过调用函数 zb_AllowBind()进入该模式,

void zb_AllowBind ( uint8 timeout )
{

osal_stop_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER);

if ( timeout == 0 )
{
    afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
}
else
{
    afSetMatch(sapi_epDesc.simpleDesc->EndPoint, TRUE);
    if ( timeout != 0xFF )
    {
      if ( timeout > 64 )
      {
        timeout = 64;
      }
      osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);
    }
}
return;
}

注意:timeout是进入绑定模式的持续时间(s),如果设置为0xff,则设备任何时候都处于允许绑定模式,;若为0x00,则设备处于取消绑定模式。

同时该实验中,最大益处时间为64,仅仅一个命令可以再任何时候允许绑定模式。

调用该函数使设备在给定的事件内进入允许绑定模式,一个在允许绑定模式下同等的设备调用函数zb_BindDevice能与之建立绑定,目的地址为空。

在里面调用函数afSetMatch(),使之允许相应ZDO的匹配描述符请求。

在目的设备处于允许绑定时间内,源设备可以调用函数zb_BindDevice发起绑定请求。执行代码如上玫瑰红在指间调用了函数ZDP_MatchDescReq(),将建立和发送一个匹配描述符请求,用这个函数在一个应用中的输入/输出串列表中搜素匹配某条件的设备/应用。
afStatus_t ZDP_MatchDescReq( zAddrType_t *dstAddr, //--目的地址
                                uint16 nwkAddr,     //--已知的16位网络地址 
                                uint16 ProfileID,   //--应用模式ID,串ID作为参考
                                byte NumInClusters, //--在输入串列表中串ID的数量
                                cId_t *InClusterList,//--输入串ID的队列(每一个字节) 
                                byte NumOutClusters, //--在输出串列表中串ID的数量
                                cId_t *OutClusterList,//--输出串ID的队列(每一个字节)
                                byte SecurityEnable ) //--信息安全类型

注意:afStatus_t这个函数用于AF发送信息,因此,这个状态值是被定义在ZComDef.h文件中的AF状态值。

该绑定相应处理在 SAPI_ProcessZDOMsgs()中:
    case Match_Desc_rsp:
      {
        zAddrType_t dstAddr;
        ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );

        if ( sapi_bindInProgress != 0xffff )
        {
          // Create a binding table entry--创建绑定条目
          dstAddr.addrMode = Addr16Bit;
          dstAddr.addr.shortAddr = pRsp->nwkAddr;

          if ( APSME_BindRequest( sapi_epDesc.simpleDesc->EndPoint,
                     sapi_bindInProgress, &dstAddr, pRsp->epList[0] ) == ZSuccess )
          {
            osal_stop_timerEx(sapi_TaskID, ZB_BIND_TIMER);
            osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, 250 );
            sapi_bindInProgress = 0xffff;

            // Find IEEE addr --发现IEEE地址
            ZDP_IEEEAddrReq( pRsp->nwkAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );

            // Send bind confirm callback to application --发送一个确认绑定到应用
            zb_BindConfirm( sapi_bindInProgress, ZB_SUCCESS );
          }
        }
      }
      break;

注意:以上将到的zb_AllowBind和zb_BindDevice ,最终都将用函数APSME_BindRequest()创建绑定

不同的是前者采用目的地址是64位的扩展地址,后者采用的是16位的网络地址。前者已知扩展地址,调用ZDP_NwkAddr_Req()函数获取目的设备的短地址,后者利用描述符匹配得到了短地址,然后调用ZDP_IEEEAddrReq()获得目的设备的扩展地址。

绑定解除:建立和移除绑定都调用了函数zb_BindDevice (),但是执行的代码不同。

3. 命令:

命令是为了实现某种特定的通信而制定的一种强制性的通信方式

3.1使用

该例子中// Define the Command ID's used in this application
       define TOGGLE_LIGHT_CMD_ID               1 //--切换灯状态的一个命令,可以说是 一个串,ID为1,

看灯设备的输入列表:

// List of output and input commands for Switch device
const cId_t zb_InCmdList[NUM_OUT_CMD_SWITCH] = --输入列表

TOGGLE_LIGHT_CMD_ID
};

// 设备的简单描述符
const SimpleDescriptionFormat_t zb_SimpleDesc =
{
MY_ENDPOINT_ID,             // Endpoint
MY_PROFILE_ID,              // Profile ID
DEV_ID_COLLECTOR,          // Device ID
DEVICE_VERSION_COLLECTOR, // Device Version
0,                          // Reserved
NUM_IN_CMD_COLLECTOR,      // Number of Input Commands
(cId_t *) zb_InCmdList,     // Input Command List
NUM_OUT_CMD_COLLECTOR,     // Number of Output Commands
(cId_t *) NULL              // Output Command List
};

开关设备看输出列表:

// List of output and input commands for Switch device
const cId_t zb_OutCmdList[NUM_OUT_CMD_SWITCH] = //--设备输出列表
{
TOGGLE_LIGHT_CMD_ID
};

// Define SimpleDescriptor for Switch device --简单描述符
const SimpleDescriptionFormat_t zb_SimpleDesc =
{
MY_ENDPOINT_ID,             // Endpoint
MY_PROFILE_ID,              // Profile ID
DEV_ID_SWITCH,              // Device ID
DEVICE_VERSION_SWITCH,      // Device Version
0,                          // Reserved
NUM_IN_CMD_SWITCH,          // Number of Input Commands
(cId_t *) NULL,             // Input Command List
NUM_OUT_CMD_SWITCH,         // Number of Output Commands
(cId_t *) zb_OutCmdList     // Output Command List
};

描述好后调用afRegister()登记一个EP描述符

afStatus_t afRegister( endPointDesc_t *epDesc )
{
epList_t *ep = afRegisterExtended( epDesc, NULL );

return ((ep == NULL) ? afStatus_MEM_FAIL : afStatus_SUCCESS);
}

该函数在SAPI_Init()函数中被调用,这样就可以使用该断点了,从而可以使用该命令串

命令的发送通过函数zb_SendDataRequest ()来完成。发送数据函数也调用了AF_DataRequest()

该例子是基于绑定的命令传输,所以目的地址为指定的0xFFFF,这样,设备将自动的去绑定表格中区查找真正的目的地址,如果绑定表多余一个目的地址,那么该信息将被复制多次分别发送出去。实验中调用函数

    zb_SendDataRequest( 0xFFFE, SENSOR_REPORT_CMD_ID, 2, pData, 0, AF_ACK_REQUEST, 0 );

3.2 串

Cluster: is a container for one or more attributes. (一个或更多属性的集合) ,

前面提到的 TOGGLE_LIGHT_CMD_ID即为一个串。


       3.3 ZCL

ZCL在zigbee中充当仓库的角色,设计者在构造一个新的配置文件profile时,应当为相关的ZCL簇添加新的配置文件,ZCL由基础层和功能区域组成。基础层通上层提供下列API:

产生请求与应答命令;注册应用属性表;注册串库管理者回收函数;

注册簇库的回调函数;注册配置文件profile的实际和逻辑标识符之间的转化表。

功能区域又分成通用(general)区域,灯控(lighting)区域,报警(alarming)区域等,通用区域向上层提供的API函数为:

产生请求和响应命令;          注册应用程序命令的回调函数

注意:zcl通过判断串ID来达到相应的作用的。系统中首先对串库进行设置,根据不同的ID设置不同的功能,这样ID和功能形成一一对应。无线控制过程中,就不需要传输大量的命令,只需要传输串ID,后通过串ID,判断需要执行的命令就可以了。

3.4 profile -配置文件

Profile: a collection of device descriptions, which together form a cooperative application. (配置文件:共同促成交互式应用的多种设备描述项的集合。)

   Profile是对逻辑设备及其接口的描述集合,是面向某个应用类别的公约、准则。

1)为甚需要profile

需要一种共同的语言来交流数据;需要一个良好的处理动作设置;不同厂商的设备互用性;最终用户需要简单和可靠性的操作;产品的消费适应性;允许可靠的一致的测试程序被创建。

2)什么是profile

profile规范如下:

设置一个设备的应用范围;设置一个串的功能(设置一个设备状态属性、设置一个信息传达的命令);各个设备串的详细描述;各个设备的特殊功能描述。

3)profile的分类:

公用profile ;厂商profile

4)zigbee公共应用模式

家庭自动化(灯开关、窗帘、温度计、加热单元)

工业工厂监控(温度、压力、红外)

。。。。。。。。。。。。。。。。。。

0 0
原创粉丝点击