// Successfully started a ZigBee network
if ( devState == DEV_COORD_STARTING ) {
devState = DEV_ZB_COORD; }
osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); }
…… }
⑧ ZDO事件轮询中处理ZDO状态改变事件
void ZDO_UpdateNwkStatus( devStates_t state )
{
// Endpoint/Interface descriptor list. epList_t *epDesc = epList;
byte bufLen = sizeof(osal_event_hdr_t); osal_event_hdr_t *msgPtr;
ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr(); (void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. while ( epDesc ) {
if ( epDesc->epDesc->endPoint != ZDO_EP ) {
msgPtr = (osal_event_hdr_t *)osal_msg_allocate( bufLen ); if ( msgPtr ) {
msgPtr->event = ZDO_STATE_CHANGE; // Command ID msgPtr->status = (byte)state;
osal_msg_send( *(epDesc->epDesc->task_id), (byte *)msgPtr ); } }
epDesc = epDesc->nextDesc; } }
(2)无线转串口数据传输
协调在网络启动后,就开始监听无线信号和串口信息。一旦有节点加入到网络当中,协调器将会将新加入节点的地址信息汇报给网关。当协调器监听到发送给自己无线信号时,将从无线信号包中解析出命令帧,在确认命令格式正确无误时,协调器将该命令帧通过串口发送给网关,其实现代码如下:
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
20
#ifdef COORD uint8 i;
memcpy(RfRx.RxBuf,pkt->cmd.Data,32);
if((RfRx.RXDATA.Head == '&') && (RfRx.RXDATA.LastByte == '*')) {
memcpy(UartTxBuf.TxBuf,RfRx.RxBuf,32); for(i=0; i<8; i++) {
UartTxBuf.TXDATA.Laddr[i] = RfRx.RXDATA.Laddr[i]; }
for(i=0; i<2; i++) {
UartTxBuf.TXDATA.Saddr[i] = RfRx.RXDATA.Saddr[1-i]; }
UartTxBuf.TXDATA.CRC = CheckUartData(&UartTxBuf.TxBuf[1],29); HalUARTWrite ( HAL_UART_PORT_0, UartTxBuf.TxBuf, 32); } #endif …… }
(3)串口转无线数据传输
协调器不但要监听无线网络中的数据帧,还要与网关进行数据交互,本系统是通过串口实现与网关的通信的。在Z-Stack中需要使能MT监测任务才能实现对串口数据的收发,部分初始化代码如下所示:
void osalInitTasks( void ) {
??
#if defined( MT_TASK ) MT_TaskInit( taskID++ ); #endif ?? }
在MT_TaskInit函数中调用了MT_UartInit函数,该函数就是串口的初始化函数。具体初始化包括对串口的波特率,缓存区大小,流控制等进行了配置,特别决定了串口的处理方式为DMA方式,最后还指定了串口数据处理的回调函数。通过设置HAL_UART_DMA宏为1,再调用HalUARTOpen函数打开串口时,判断该配置宏,选择采用DMA方式打开串口,即调用HalUARTOpenDMA函数,初始化DMA,打开串口。
完成初始化工作后,然后在相应的层注册一个串口事件,即可将串口数据反馈到相应的层。本系统在应用层注册了串口事件,在系统消息中对串口消息进行
21
了处理,其处理代码如下:
void UartRxComCallBack(void) { uint16 DstAddr; if((UartRxBuf.RxBuf[0] == '&') && (UartRxBuf.RxBuf[31] == '*')) { memcpy(RfTx.TxBuf,UartRxBuf.RxBuf,32); DstAddr = RfTx.TXDATA.Saddr[0]; DstAddr <<= 8; DstAddr += RfTx.TXDATA.Saddr[1]; if(SendData(DstAddr, RfTx.TxBuf, 32) == 0)//发送数据失败 { memset(&RfTx.TxBuf[4],'x',26); memcpy(RfTx.TXDATA.Laddr,UartRxBuf.RXDATA.Laddr,8);//加入地址 RfTx.TXDATA.DataBuf[0] = 'E'; RfTx.TXDATA.DataBuf[1] = '1';//串口输出E1 memcpy(UartTxBuf.TxBuf,RfTx.TxBuf,32); UartTxBuf.TXDATA.CRC = CheckUartData(&UartTxBuf.TxBuf[1],29); HalUARTWrite(HAL_UART_PORT_0, UartTxBuf.TxBuf, 32);//串口输出 } else { P1_1 = !P1_1; } } memset(UartRxBuf.RxBuf,0,32); }
对串口消息的处理中,协调器首先对命令帧的格式进行了确认,然后通过memcpy(RfTx.TxBuf,UartRxBuf.RxBuf,32);从串口接收缓存区将数据拷贝到无线发送缓存区,从缓存区提取出目的地址后,通过无线发送函数SendData将数据发送出去。
4.1.2 终端节点模块软件设计
ZigBee节点软件包括加入到无线通信网络,采集光传感信息,控制LED台灯以及查询链路连接状态。其工作流程图如图18所示:
22
开始硬件初始化Zigbee协议栈初始化查找网络有网络?Y申请加入N加入成功?Y处理用户事件N
图18 节点软件设计流程图
(1)加入网络
终端设备的启动与协调器不同是从ZDO_StartDevice的调用开始的,该函数首先判断设备类型是终端设备,然后通过调用ZDO_StartDevice 函数启动设备,该函数调用了网络发现请求函数NLME_NetworkDiscoveryRequest来寻找一个可用网络,同样,也有其对应的确认函数ZDO_NetworkDiscoveryConfirmCB,在网络发现确认函数中,对网络信息进行校验,再发送一个网络发现确认消息给ZDO层,ZDO层得知网络已经发现后,会调用网络加入请求函数NLME_JoinRequest,加入到网络当中,网络加入确认则是在更新网络信息之后设置了ZDO_STATE_CHANGE_EVT,通过该事件,最后会发送消息个API层,通知器进行启动确认,从而完成整个启动过程。
① ZDO_StartDevice函数发现网络:
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
{
……
#if !defined ( ZDO_COORDINATOR ) || defined( SOFT_START )
if ( logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE ) {
23