Zigbee网络处理器应用简介

本文首先介绍Zigbee的若干基本概念,然后针对TI Zigbee解决方案中的Zigbee网络处理器(ZNP)应用形式,介绍如何创建一个Zigbee网络,并与已有的节点进行通信。

基本概念

Zigbee

Zigbee是一种短距离、低速率、低功耗的无线传感器网络技术,包含了从底层网络到上层应用的完整定义,标准由Zigbee联盟制定,最新规格为Zigbee 3.0。
多个IC厂商提供包含Zigbee技术的产品,本文只讨论TI的解决方案。

信道

Zigbee可以在Sub-1GHz、2.4GHz等多个频率范围工作,一般选择在2.4GHz频率范围,这个范围中又划分出16个具体的频点(信道),对应编号从11(0x0B)到26(0x1A)。当同一个或相邻近的物理空间中有多个Zigbee网络时,需要错开信道。

设备类型

Zigbee网络中的设备分为三种类型:协调器(Coordinator)、路由(Router)和终端节点(End Device)。其中,协调器负责建立网络,并为新加入的节点分配地址(当网络建立、节点入网后,即使去掉协调器,网络也能正常工作);路由负责将收到数据转发给其他节点,以拓展网络的覆盖范围;终端节点只能接收和发送自身的数据,不能转发。
需要说明的是:(1)路由本身也具有终端节点的功能,可以收发自身的数据;(2)终端节点可以不依赖路由,直接通过协调器入网。所以,一个完整的Zigbee网络,可以没有终端节点,只有协调器和路由;也可以没有路由,只有协调器和终端节点。

网络地址

Zigbee设备在出厂时都有一个唯一的8字节MAC地址,但在加入网络时,会被协调器分配一个两字节的网络地址,后续以这个网络地址通信。协调器的网络地址是0x0000。0xFFFF是广播地址,如果将通信的目的地址设为0xFFFF,那么所有节点都会收到。

PANID

PANID是Zigbee网络的标识,即使同一信道里有多个Zigbee网络,只要它们的PANID不同,也可以共存并独立工作。

Z-Stack

Z-Stack是TI的Zigbee协议栈,包含文档、源代码和预编译的库,可以从TI网站上下载。Z-Stack使用IAR编译和调试,生成的hex文件通过烧写器烧写进Zigbee芯片当中。

ZNP

ZNP,即Zigbee网络处理器,是TI的Zigbee解决方案的一种应用形式。在这种形式下,Zigbee芯片只负责处理底层网络的功能,而将上层应用交给主机处理,ZNP与主机之间通过USB或UART连接。Zigbee芯片实现ZNP功能所需的固件及其源码,以及接口API的说明都包含在Z-Stack中。所谓接口API,指主机通过USB或UART与ZNP通信的帧格式,以及命令和参数的定义。在主机侧,TI提供了对接口API的包装,即znp-host-framework,C语言实现,开源,代码托管在TI的Git网站上,另外在GitHub上还有适用于Node.js的版本。

安全

Zigbee网络支持安全加密机制,通信数据采集AES加密。密钥的分发有两种方法:一种是预先配置在所有需要加入网络的节点上;另一种是只配置在协调器上,节点入网时分发到节点。

配置ZNP

TI有多款芯片可以用作ZNP,我们选择CC2538,通过其自带的USB接口连接主机,硬件dongle可以从淘宝采购。对应的工程文件在Z-Stack的Projects\zstack\ZNP\CC2538目录当中。
Z-Stack中默认开启了安全加密,可以通过修改代码禁用:

Projects/zstack/Tools/CC2538DB/f8wConfig.cfg

21(修改宏定义): DSECURE=0

Components/stack/bdb/bdb_touchlink.h

50(注释掉此行): //#error SECURE must be globally defined to TRUE.

如果按照TI提供的参考设计,配置了CC2592作为PA,还需要使能它:

Components/hal/target/CC2538ZNP/hal_board_cfg.h

84(增加一行): #define HAL_PA_LNA_CC2592

使用ZNP创建网络

将CC2538 USB dongle连接到主机,就可以从主机上发命令控制它了。CC2538的USB接口是一个CDC设备,在Windows上无需安装驱动,会被识别成一个串口;在Linux系统上,需要确保内核包含USB CDC设备驱动,会被识别成/dev/ttyACMx(x是序号,从0开始)。

Z-Tool

Z-Tool是Z-Stack附带的一个测试工具,可以用它给ZNP发送指令。在安装Z-Stack以后,在安装目录下找到Tools\Z-Tool\Z-Tool.exe,双击打开,它会自动搜索并连接ZNP。

Zigbee网络处理器应用简介_第1张图片
Z-Tool

如上图所示,界面左上角是Z-Tool支持的各种命令,分为System、AF等多个类别。下面介绍使用这些命令控制ZNP创建网络的步骤。

  1. 配置启动选项,在下次复位前清除网络状态和所有配置

    命令:SimpleAPI/ZB_WRITE_CONFIGURATION
    参数:ConfigId: 3(ZCD_NV_STARTUP_OPTION),Len: 1,Value: [3]

  2. 复位

    命令:SimpleAPI/ZB_SYSTEM_RESET

  3. 配置设备类型

    命令:SimpleAPI/ZB_WRITE_CONFIGURATION
    参数:ConfigId: 135(ZCD_NV_LOGICAL_TYPE),Len: 1,Value: [0](协调器)

  4. 设置PANID

    命令:Util/UTIL_SET_PANID
    参数:PanId: 6

  5. 设置信道(复位后生效)

    命令:Util/UTIL_SET_CHANNELS
    参数:Channels: 0x00020000(即17信道,计算方法:1<<17 = 0x00020000)

  6. 设置信道(立即生效)

    命令:AppConfig/APP_CNF_BDB_SET_CHANNEL
    参数:isPrimary: TRUE, Channels: 0x00020000(计算方法同上一条命令)

  7. 注册应用程序(对于创建网络来说,这一步不是必需的,但后面收发数据需要)

    命令:AF/AF_REGISTER
    参数:
    EndPoint: 11
    AppProfID: 3845
    AppDeviceId: 256
    AppDevVer: 0
    LatencyReq: 0
    AppNumInClusters: 1
    AppInClusterList: [1]
    AppNumOutClusters: 1
    AppOutClusterList: [1]

  8. 启动网络

    命令:ZDO/ZDO_STARTUP_FROM_APP

  9. 配置启动选项,在下次复位后保持网络状态和配置

    命令:ZB_WRITE_CONFIGURATION
    参数:ConfigId: 3(ZCD_NV_STARTUP_OPTION),Len: 1, Value: 0

Node.js

以上步骤可以通过Node.js脚本实现:

const znp = require('cc-znp')
znp.request('SAPI', 'writeConfiguration', {
            configid: 3,
            len: 1,
            value: [0x03]
        })
znp.request('SAPI', 'systemReset', {})
znp.request('SAPI', 'writeConfiguration', {
                configid: 0x87,
                len: 1,
                value: [0] //coordinator
            })
znp.request('UTIL', 'setPanid', {
                panid: 6
            })
znp.request('UTIL', 'setChannels', {
                channels: 0x00020000
            })
znp.sendCmd(1, 'RPC_SYS_DEBUG', 0x08, new Buffer([1, 0, 0, 2, 0]))
znp.request('AF', 'register', {
                endpoint: 0x0B, 
                appprofid: 0xF05, 
                appdeviceid: 0x100, 
                appdevver: 0, 
                latencyreq: 0, 
                appnuminclusters: 1, 
                appinclusterlist: [1], 
                appnumoutclusters: 1, 
                appoutclusterlist: [1] 
            })
znp.request('ZDO', 'startupFromApp', {
                startdelay: 0
            }
znp.request('SAPI', 'writeConfiguration', {
            configid: 3,
            len: 1,
            value: [0]
        })

发送数据(待发送的数据放在buffer变量中):

znp.request('AF', 'dataRequest', {
                dstaddr: 0xFFFF,
                destendpoint: 0x0B,
                srcendpoint: 0x0B,
                clusterid: 0x0001,
                transid: 1,
                options: 0,
                radius: 0x7,
                len: buffer.length,
                data: buffer
            })

接收数据:

znp.on('AREQ', function (msg) {
    if(msg.ind === 'incomingMsg') {
        var srcaddr = msg.data.srcaddr;
        var data = msg.data.data;
    }
});

C语言

在Linux上,可以使用TI提供的znp-host-framework来操作ZNP。其中提供了一个cmdLine例程,可以在命令行中交互式地设置创建网络的参数,主要步骤与上文大体一致,缺少了AppConfig/APP_CNF_BDB_SET_CHANNEL这条命令(设置信道并立即生效),可以自行添加:

/*
 * mtAppCnf.c
 *
 * This module contains the API for the MT App Config Interface
 *
 */
#include 
#include 
#include "mtAppCnf.h"
#include "mtParser.h"
#include "rpc.h"
#include "dbgPrint.h"

extern uint8_t srspRpcBuff[RPC_MAX_LEN];

uint8_t appCnfBdbSetChannel(mtBdbSetChannelFormat_t *req)
{
    uint8_t status;
    uint8_t cmInd = 0;
    uint32_t cmdLen = 5;
    uint8_t *cmd = malloc(cmdLen);

    if (cmd)
    {
        cmd[cmInd++] = req->isPrimary;
        memcpy((cmd + cmInd), req->channelMask, 4);
        cmInd += 4;

        status = rpcSendFrame((MT_RPC_CMD_SREQ | MT_RPC_SYS_APP_CNF),
        MT_APP_CNF_BDB_SET_CHANNEL, cmd, cmdLen);

        if (status == MT_RPC_SUCCESS)
        {
            rpcWaitMqClientMsg(50);
            status = srspRpcBuff[2];
        }

        free(cmd);
        return status;
    }
    else
    {
        dbg_print(PRINT_LEVEL_WARNING, "Memory for cmd was not allocated\n");
        return 1;
    }
}

TODO

  • 新节点入网:需要在Zigbee协调器上控制是否允许新节点入网。

你可能感兴趣的:(Zigbee网络处理器应用简介)