ZStack里的网络传输功能比较像系统上的udp socket编程. 它可以支持广播,组播,及点到点的单播传输方式。
网络传输的功能所用的主要数据类型及函数在工程的”profile/AF.h”里.
typedef enum
{
afAddrNotPresent = AddrNotPresent, //表示地址不存在
afAddr16Bit = Addr16Bit, //表示目的地址是一个16位地址
afAddr64Bit = Addr64Bit, //表示目的地址是一个64位地址
afAddrGroup = AddrGroup, //表示目的地址是组播的
afAddrBroadcast = AddrBroadcast //表示目的地址是广播的
} afAddrMode_t; //地址模式类型, 相应相当于socket里指定IP地址是IPV4地址还是IPV6地址
typedef struct
{
union
{
uint16 shortAddr; //16位地址, 广播地址就是0xffff
ZLongAddr_t extAddr; //64位地址
} addr;
afAddrMode_t addrMode; //指定使用的地址模式类型
uint8 endPoint; //指定目的端点, 也就是相当于目的端口号
uint16 panId; //由网络层自动设置此成员
} afAddrType_t; //地址类型. 不管是要发出广播,组播或单播网络数据都是使用此类型的对象来指定, 其它完全一样。
typedef uint16 cId_t;
typedef struct
{
uint8 EndPoint; //端口号(1 ~ 240)
uint16 AppProfId; // app profile id
uint16 AppDeviceId; // app device id
uint8 AppDevVer:4; // app device version
// AppProfId, AppDeviceId, AppDevVer这三项可以随便设置,只要收发两方一致即可
uint8 Reserved:4; // AF_V1_SUPPORT uses for AppFlags:4.
// Cluster(簇,群)表示在收发一个endPoint端口号上的数据时再进一步的分类,发出数据时需指定Cluster的值是多少
uint8 AppNumInClusters; //指定本端口号支持多少个输入的Cluster个数.
cId_t *pAppInClusterList; //指向支持输入的具体Cluster值的数组首地址
uint8 AppNumOutClusters; //指定本端口支持多少个输出的Cluster个
cId_t *pAppOutClusterList; //指定支持输入的具体Cluster值的数组首地址
} SimpleDescriptionFormat_t; //此类型用于描述一个端口号里的具体设置
typedef struct
{
uint8 endPoint; //使用的端口号
uint8 *task_id; // 指向任务的id
SimpleDescriptionFormat_t *simpleDesc; //描述一个端口号里的具体设置
afNetworkLatencyReq_t latencyReq; //收发网络数据后的延时策略,通常设noLatencyReqs
} endPointDesc_t; //描述在任务里绑定使用的endPoint端口号的相关配置.
----------
extern afStatus_t afRegister( endPointDesc_t *epDesc ); //此函数用于任务里绑定端口号使用,当网络协议本里接收此端口号的数据后,会设置绑定任务里的事件(SYS_EVENT_MSG), 并把接收到的网络数据通过发消息(消息事件类型为AF_INCOMING_MSG_CMD)到任务里。 任务里通过接收消息的方式就可以获取到接收到网络数据了。
//发出网络数据的函数
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP, uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
uint8 options, uint8 radius );
// dstAddr指定目的地址及目的端口号, srcEP指定源端口号的配置, cID指定使用具体哪一个Cluster,
options表示发出时的使用的选项, radius通常设为AF_DEFAULT_RADIUS
// options有:
#define AF_PREPROCESS 0x04 // Will force APS to callback to preprocess before calling NWK layer
#define AF_LIMIT_CONCENTRATOR 0x08
#define AF_ACK_REQUEST 0x10
#define AF_DISCV_ROUTE 0x20
#define AF_EN_SECURITY 0x40
#define AF_SKIP_ROUTING 0x80
//当任务调用afRegister函数绑定端口号后,网络协议栈里接收到此端口号的数据时,会设置任务有SYS_EVENT_MSG事件并把接收的网络数据通过发消息的方式传到任务。 在任务事件处理函数里通过接收消息来获取到接收的网络数据.
typedef struct
{
osal_event_hdr_t hdr; //hdr的event为 AF_INCOMING_MSG_CMD
uint16 groupId; /* Message's group ID - 0 if not set */
uint16 clusterId; /* Message's cluster ID */
afAddrType_t srcAddr; /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
it's an InterPAN message */
uint16 macDestAddr; /* MAC header destination short address */
uint8 endPoint; /* destination endpoint */
uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */
uint8 LinkQuality; /* The link quality of the received data frame */
uint8 correlation; /* The raw correlation value of the received data frame */
int8 rssi; /* The received RF power in units dBm */
uint8 SecurityUse; /* deprecated */
uint32 timestamp; /* receipt timestamp from MAC */
uint8 nwkSeqNum; /* network header frame sequence number */
afMSGCommandFormat_t cmd; //cmd里的Data成员指向接收到数据缓冲区首地址, cmd里的DataLength为接收到数据长度.
} afIncomingMSGPacket_t; //接收到网络数据的消息类型
----------
//当网络状态发生变化时(如网络掉线,加入网络等), 网络协议栈会设置任务的SYS_EVENT_MSG事件, 并发出消息到任务里。消息类型为ZDO_STATE_CHANGE. 如:
afIncomingMSGPacket_t *MSGpkt;
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(mytask_id);
if (MSGpkt->hdr.event == ZDO_STATE_CHANGE)
{
int status = (devStates_t)(MSGpkt->hdr.status);
}
----------
//状态有
typedef enum
{
DEV_HOLD, // Initialized - not started automatically
DEV_INIT, // Initialized - not connected to anything
DEV_NWK_DISC, // Discovering PAN's to join
DEV_NWK_JOINING, // Joining a PAN
DEV_NWK_REJOIN, // ReJoining a PAN, only for end devices
DEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust center
DEV_END_DEVICE, // Started as device after authentication
DEV_ROUTER, // Device joined, authenticated and is a router
DEV_COORD_STARTING, // Started as Zigbee Coordinator
DEV_ZB_COORD, // Started as Zigbee Coordinator
DEV_NWK_ORPHAN // Device has lost information about its parent..
} devStates_t;
//
实现定时网络广播功能的代码:
MyApp.h
#ifndef __MYAPP_H
#define __MYAPP_H
#include "hal_key.h"
#include "OnBoard.h"
#include "MT_UART.h"
#include "AF.h"
#define TIME_OUT 0x0010 //time out event;
extern void MyApp_Init(uint8 task_id );
extern uint16 MyApp_ProcessEvent(uint8 task_id, uint16 event );
extern void Handle_keys(keyChange_t * key_evt);
extern void Handle_uart(mtOSALSerialData_t *pmsg);
extern void myprintf(char *str);
extern void Handle_status(uint8 status);
extern void Handle_msg( afIncomingMSGPacket_t *pkt );
#endif
MyApp.c
#include "hal_led.h"
#include "hal_key.h"
#include "MyApp.h"
#include "OnBoard.h"
#include "AF.h"
#include "MT_UART.h"
#include "hal_key.h"
#include "hal_uart.h"
#include "MT.h"
#include <stdio.h>
#include <string.h>
#include "ZDApp.h"
#include "AF.h"
uint8 mytask_id; //用于记录任务号
uint8 transId;
#define TIMER_LEN 5000 // 5s
#define MYPOINT 20
#define ARRAY_SIZE(a) ((sizeof(a))/sizeof(a[0]))
#define CID_BCAST 1
#define CID_GROUP 2
afAddrType_t Bcast_addr;
endPointDesc_t mypoint_desc;
cId_t cids[] = {
CID_BCAST,
CID_GROUP,
};
const SimpleDescriptionFormat_t simpleDesc = {
MYPOINT,
0x1234, //AppProfId
0x0001, //AppDeviceId
0,
0,
ARRAY_SIZE(cids),
cids,
ARRAY_SIZE(cids),
cids,
};
void MyApp_Init(uint8 task_id )
{
mytask_id = task_id; //
transId = 0;
// HalLedSet(HAL_LED_ALL, HAL_LED_MODE_TOGGLE);
RegisterForKeys(mytask_id);
MT_UartRegisterTaskID(mytask_id);
// Bcast_addr 初始化,用于指定发出是广播用
Bcast_addr.addrMode = (afAddrMode_t)AddrBroadcast;
Bcast_addr.addr.shortAddr = 0xffff;
Bcast_addr.endPoint = MYPOINT;
mypoint_desc.endPoint = MYPOINT;
mypoint_desc.task_id = &mytask_id;
mypoint_desc.simpleDesc = (SimpleDescriptionFormat_t *)&simpleDesc;
mypoint_desc.latencyReq = noLatencyReqs;
afRegister(&mypoint_desc);
osal_start_timerEx(mytask_id, TIME_OUT, TIMER_LEN);
}
void Handle_keys(keyChange_t * key_evt)
{
if (key_evt->keys & HAL_KEY_SW_1)
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE);
HalUARTWrite(0, "s1\n\r", 4);
}
if (key_evt->keys & HAL_KEY_SW_2)
{
HalLedSet(HAL_LED_2, HAL_LED_MODE_TOGGLE);
HalUARTWrite(0, "s2\n\r", 4);
}
}
void myprintf(char *str)
{
HalUARTWrite(0, str, strlen(str));
}
void Handle_uart(mtOSALSerialData_t *pmsg)
{
uint8 len = pmsg->msg[0];
HalUARTWrite(0, &(pmsg->msg[1]), len);
}
void Handle_status(uint8 status)
{
switch(status)
{
case DEV_ZB_COORD:
myprintf("work as coordinator\n\r");
break;
case DEV_END_DEVICE:
myprintf("work as end_device\n\r");
break;
}
}
void Handle_msg( afIncomingMSGPacket_t *pkt )
{
HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //接收到网络数据后,通过uart输出
}
uint16 MyApp_ProcessEvent(uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG ) //系统消息的处理, 也就是调用osal_msg_send产生的事件
{
//接收系统消息
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(mytask_id);
while ( MSGpkt )
{
if (MSGpkt->hdr.event == KEY_CHANGE) //按键事件处理
Handle_keys((keyChange_t *)MSGpkt);
if (MSGpkt->hdr.event == CMD_SERIAL_MSG) //串口事件处理
Handle_uart((mtOSALSerialData_t*)MSGpkt);
if (MSGpkt->hdr.event == AF_INCOMING_MSG_CMD) // zigbee网络数据的接收事件处理
Handle_msg(MSGpkt);
if (MSGpkt->hdr.event == ZDO_STATE_CHANGE) //zigbee网络状态事件处理
Handle_status(MSGpkt->hdr.status);
osal_msg_deallocate( (uint8 *)MSGpkt ); // free
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(mytask_id);
}
return events ^ SYS_EVENT_MSG;
}
if (events & TIME_OUT)
{
//定时发出网络广播数据
static int num = 0;
char buf[30];
sprintf(buf, "bcast: %d\n\r", num++);
if (AF_DataRequest(&Bcast_addr, &mypoint_desc, CID_BCAST, strlen(buf),
buf, &transId, AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS) != afStatus_SUCCESS)
{
myprintf("send failed\n\r");
}
osal_start_timerEx(mytask_id, TIME_OUT, TIMER_LEN);
}
return 0;
}