概述
【转】学习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公共应用模式
家庭自动化(灯开关、窗帘、温度计、加热单元)
工业工厂监控(温度、压力、红外)
。。。。。。。。。。。。。。。。。。
最后
以上就是贪玩香菇为你收集整理的学习zigbee入门-10的全部内容,希望文章能够帮你解决学习zigbee入门-10所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复