Z-Wave技术与zipgateway源码剖析

1 Z-Wave简介

1.1 什么是Z-Wave技术

Z-Wave是一种新兴的基于射频的、低成本、低功耗、高可靠、适于网络的短距离无线通信技术。工作频带为908.42MHz(美国)~868.42MHz(欧洲),采用FSK(BFSK/GFSK)调制方式,早期的数据传输速率为9.6 kbps(现在40kbps),信号的有效覆盖范围在室内是30m,室外可超过100m,适合于窄带宽应用场合。随着通信距离的增大,设备的复杂度、功耗以及系统成本都在增加,相对于现有的各种无线通信技术,Z-Wave技术将是最低功耗和最低成本的技术,有力地推动着低速率无线个人区域网。

1.2 Z-Wave技术特征

(1) 低成本

(2) 低功耗

(3) 高可靠性

(4) 全网覆盖

(5) 通用性

(6) …..

1.3 Z-Wave技术应用

Z-Wave技术目前主要专注于家庭自动化领域,力求为用户提供一个更加舒适、方便和更具人性化的智能家居环境。Z-Wave网络的安装简单易行,各种符合标准的家庭设备都能方便地“安装”到家庭网络中,也能方便地从家庭网络“ 卸载”。

Z-Wave在其家庭网络中定义了三种类型的设备:控制器(controller)、路由从设备(routing slave)和从设备(slave)。当需要安装新的节点设备时,首先激活网络中的控制器和其他所有节点,激活可以同步也可以不同步。控制器被第一次激活后,通过广播查询新节点的请求,如果收到新节点的回应,控制器会向这个节点分配一个ID,通过这个ID来规定自己的属主关系。新节点需要向控制器报告它周围的邻居表(即在射频范围之内的所有节点),使得控制器有一个全面的网络拓扑信息,从而建立了一个无缝的网状结构通信网络。

Z-Wave在家庭中的应用主要包括照明控制、读取仪表(水、电、气)、家用电器功能控制、身份识别、通路(出入口)管制、能量管理系统、预警火灾等。

另外,Z-Wave还可以和传感器网络结合在一起使用,通过在家电和家具中部署基于Z-Wave的传感器节点,并使它们与Internet连接,用户就可以采用远程监控系统实现对家电的远程遥控。例如可以在回家之前半小时打开空调,这样回家的时候就可以直接享受适合的室温,也可以遥控电饭锅、微波炉、电冰箱、电话机、电视机、录像机、电脑等家电,按照自己的意愿完成相应的煮饭、烧菜、查收电话留言、选择录制电视和电台节目以及下载网上资料到电脑中等操作,也可以通过图像传感设备随时监控家庭安全情况。

1.4 Z-wave协议栈

相对于其他无线通信标准而言,Z-Wave协议栈显得更为紧凑和简单。Z-Wave协议栈包括四层:媒介访问控制(MAC)层、传输层、路由层和应用层,Z-Wave协议栈模型如图1所示,其各层的主要功能如下:

1.MAC层主要用于控制射频媒介,数据流采用曼彻斯特编码。

2. 传输层主要用于提供节点之间可靠的、透明的数据传输,主要功能包括重新传输、帧校验和帧确认等。

3. 路由层的主要功能包括:控制节点间数据帧的路由、确保数据帧在不同节点间能够多次重复传输、扫描网络拓扑和维持路由表(routing table)等。

4.应用层负责Z-Wave网络中的译码和指令的执行,主要功能包括:曼彻斯特译码、指令识别、分配HomeID和NodeID、实现网络中控制器的复制(replication)以及对传送和接收帧的有效载荷(pyload)进行控制。


图1 Z-Wave协议栈模型


 

2 Z/IP Gateway

2.1 ZIP Gateway定义

在Z-Wave网络中,Z/IP Gateway是一个允许网络客户端连接并且控制节点的应用程序。

 

Zipgateway需要以太网连接,它可以访问原始以太网帧。在Linux平台上,原始以太网的连接是通过使用linux TAP/TUN驱动程序来实现的,其网络结构图如下所示:


图2 z-wave 网络结构图

 

2.2 Gateway的主要功能

l  在端口41230/4123接收封装了Z/IP command的数据包

l  Z/IP是封装了Z-wave command的UDP/IP包

l  提取z-wave的command指令

l  再将提取的z-wave指令封装在serial帧中,通过serial API发给对应的chip来完成与期望节点的通信。

 

图3 z-wave 网络模拟

 

地址与路由


如下图,phone controller想控制编号为2的灯泡,那么他是怎样完成通信的呢?

 

通过寻址和路由完成,大致的通信过程如下:


图4 z-wave 寻址通信模型

 

2.3 Gateway

 

图5 zipgateway 时序图

 

2.3.1 配置文件读取与解析

首先,需要解析zipgateway的配置文件zipgateway.cfg,这个文件定义了zipgateway的很多基本设置,例如使用的串口端口、IP地址、认证证书文件以及PSK等等。

1.     static char* cfgfile = INSTALL_SYSCONFDIR "/" PACKAGE_TARNAME".cfg"

然后通过文件描述符去读取里面的各个参数已经配置的值,并将读取出的值放在一个全局的router_config结构体中。

 

图6 配置文件

2.3.2 虚拟网卡tap0

TUN/TAP驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装。利用tun/tap驱动,可以将tcp/ip协议栈处理好的网络分包传给任何一个使用tun/tap驱动的进程,由进程重新处理后再发到物理链路中。

 

Zipgateway中的驱动程序是在tapdev-drv.c中完成的,当config文件解析完成后,便会执行驱动程序的初始化:

process_start(&tapdev_process); //启动进程

fd = open(DEVTAP,O_RDWR) ;  //打开设备节点

ioctl(fd,TUNSETIFF,(void*)&ifr);  //打开虚拟网卡

ioctl(fd,SIOCGIFHWADDR,&ifr);   //获取网卡物理地址

设备驱动tap0启动后,通过select调用去轮询读端,一旦有数据产生,意思是从我们的pc controller/pyzip发来数据了,将此数据读取出来,这个数据存放在uip_buf中的,接下来就可以对接收到的数据进行处理了,拿到buf直接抛进contiki的uIP协议栈中了。

 

图7 tap0 & 桥接

其数据处理方式简化模式如下:

{
    uip_len = tapdev_poll(); //tapdev6.c select、read调用返回

     if(uip_len> 0) { // 有数据,抛进协议栈里面处理

         uip_input();

         if(uip_len > 0) {

               // uip_input返回后,如果buf中有数据,说明要返回各个controller,比如pc,pyzip脚本

               tcpip_ipv6_output();

     }
 }

Tap0驱动程序起来后,刚开始时没有数据流过来的,还有很多的初始化工作没有准备好,所以紧接着所做的最最重要的一件事情,就是启动我们zipgateway的主要进程了,它就是zip process。

2.3.3 ZIP process

ZIP process是在ZIP_Router.c里面定义的一个auto start process。

进入Zip process的主代码段,通过判断传入的event事件类型,来进行相应的动作。我们初次传入的是ev=PROCESS_EVENT_INIT,即初始化阶段,如下理出了zip process的初始化流程。


图8 zip process:reset时序

 

2.3.4 DTLS server

DTLS server给客户端提供安全链接的服务的,即UDP传输提供端到端的安全通道,目前的版本仅支Pre-Shared-Key(PSK)方式。

OpenSSL API及基本流介绍

SSL通信模型采用标准的C/S结构,因此基于OpenSSL的程序可以被分为两个部分:ClientServer。上图1-1是建立SSL通信的流程简图,说明了基于OpenSSL的程序所要遵循的以下几个重要步骤。

(1)OpenSSL初始化

       OpenSSL在使用之前,必须进行相应的初始化工作。完成初始化功能的函数原型为

1.        int SSL_library_int(void); //初始化SSL算法库函数加载要用到的算法 ),调用SSL函数之前必须调用此函数  

2.       void SSL_load_error_strings(void); //错误信息的初始化 

(2)创建CTX

       OpenSSL中,CTX是指SSL会话环境。建立连接时使用不同的协议,其CTX也不一样。创建CTX的过程中会依次用到以下OpenSSL函数:

3.        SSL_CTX_new()         //申请SSL会话环境,clientserver都会用到

4.        //若有验证对方证书的需求,则需调用  

5.        SSL_CTX_set_verify()            //指定证书验证方式  

6.        SSL_CTX_load_verify_location()  //SSL会话环境加载本应用所信任的CA证书列表  

7.        //若有加载证书的需求,则需调用  

8.        SSL_CTX_use_certificate_file()       //SSL会话加载本应用的证书  

9.        SSL_CTX_use_certificate_chain_file() //SSL会话加载本应用的证书所属的证书链  

10.     SSL_CTX_use_PrivateKey_file()        //SSL会话加载本应用的私钥  

11.    SSL_CTX_check_private_key()          //验证所加载的私钥和证书是否相匹配

(3)创建SSL套接字

       在此之前要先创建普通的流套接字,完成TCP三次握手,建立普通的TCP连接。然后创建SSL套接字,并将之与流套接字绑定。这一过程中会使用以下几个函数

1.   SSL *SSl_new(SSL_CTX *ctx);  //创建一个SSL套接字  

2.   int SSL_set_fd(SSL *ssl,int fd);   //以读写模式绑定流套接字  

3.   int SSL_set_rfd(SSL *ssl,int fd);  //以只读模式绑定流套接字  

4.   int SSL_set_wfd(SSL *ssl,int fd);  //以只写模式绑定流套接字

(4)完成SSL握手

        在这一步,我们需要在普通TCP连接的基础上,建立SSL连接。与普通流套接字建立连接的过程类似:Client使用函数SSL_connect()(类似于流套接字中用的connect())发起握手,而Server使用函数SSL_accept()(类似于流套接字中用的accept())对握手进行响应,从而完成握手过程。两函数原型如下:

1.   int SSL_connect(SSL *ssl);  

2.   int SSL_accept(SSL *ssl);  

握手过程完成之后,Client通常会要求Server发送证书信息,以便对Server进行鉴别。其实现会用到以下几个函数:

1.   X509 *SSL_get_peer_certificate(SSL *ssl);  //从SSL套接字中获取对方的证书信息  

2.   X509_NAME *X509_get_subject_name(X509 *a); //得到证书所用者的名字

3.   SSL_CTX_use_certificate_file//指定使用的证书文件

4.   SSL_CTX_use_PrivateKey_file//指定使用的私钥文件

5.   SSL_CTX_set_cipher_list  //指定使用的加密算法(123456789012345678901234567890AA)

(5)进行数据传输

        经过前面的一系列过程后,就可以进行安全的数据传输了。在数据传输阶段,需要使用SSL_read( )SSL_write( )来代替普通流套接字所使用的read( )write( )函数,以此完成对SSL套接字的读写操作,两个新函数的原型分别如下:

1.   int SSL_read(SSL *ssl,void *buf,int num);            //SSL套接字读取数据  

2.   int SSL_write(SSL *ssl,const void *buf,int num);     //SSL套接字写入数据

(6)会话结束

        当Client和Server之间的通信过程完成后,就使用以下函数来释放前面过程中申请的SSL资源:

1.   int SSL_shutdown(SSL *ssl);       //关闭SSL套接字  

2.   void SSl_free(SSL *ssl);          //释放SSL套接字  

3.   void SSL_CTX_free(SSL_CTX *ctx);  //释放SSL会话环境

其流程图如下:

图9 SSL一般流程

DTLS初始化完成后,便进入while true循环等待连接事件了,这里我们主要等待的是有uIP处理后的tcpip_event事件。

2.3.5 Resource directory

Resource directory是一个包含z-wave网络中所有节点信息的database,该模块起来后,就会去探测(probe)网络中节点的信息,包括该节点所支持的Command Class,capability,end point等等信息,并把他们存储起来,探测过程结束后,保存到对应的数据库中,然后通过DHCP为这些网络中未分配ip地址的节点分配ip地址。

RD中有两个很重要的结构体,分别用来保存node和end point节点信息,如下:


当node被添加到网络后,都会存放在一个nat_table中,该结构体保存了每一个节点的信息:

 

初始化过程:

ResourceDirectory是在ZipRouter reset过程中最后才初始化的。


ZIP_Router_Reset(){

    ……

    ApplicationInitProtocols(){

        rd_init()

    }
}

网络中的节点怎样区分?通过HomeID以及NodeID,而且每一个z-wave node都会有ipv4和ipv6地址,HomeID是在网络初始化的时候分配的,nodeID在 一个z-wave网络中也是唯一的,gateway的nodeID则默认被分配为1,而ip地址则通过dhcp模块来动态分配。

 

图10 resource directory时序

这里会把gateway加入到数据库中,最后通过start_discover方法为其动态分配ip地址,在SerialAPI_GetInitData返回后,会将网络中存在的node信息保存在nodelist中,然后循环将他们加进nat_table中并为新的node配置ip地址。

2.3.6 Comand Class

前面提到tap0端一旦接收到数据,就会往uIP协议栈里面扔,uIP协议栈里面解析头部,处理完数据后,我们会得到它其实是一个udp_input数据,最终走到tcpip_uipcall中,在这里会给DTLS server抛一个tcpip_event,表示客户端数据过来了。

图11 Z/IP Command

下面是整个数据包的格式:

图12 数据包格式 

DTLS server读取数据,根据得到的nodeID是否与Controller的MyNodeID进行比较,如果相同,说明数据将发往gateway,调用UDPCommandHandler进行UDP指令数据的处理,解析出各种携带的command class以及对应封装的command。

如果你是一个SUC,或者primary controller,必须支持以下Conmand Class以及对应的command,即下面的CC是我们目前gateway需要支持的Network Manager相关的:

Command Class name

Command Class identifier

value

Supported command identifier

value

Network Management Inclusion

COMMAND_CLASS_NETWORK_MANAGEMENT_INCLUSION

0x34

NODE_ADD

0x01

NODE_REMOVE

0x02

Network Management Basic Node

COMMAND_CLASS_NETWORK_MANAGEMENT_BASIC

0x4D

LEARN_MODE_SET

0x01

NODE_INFORMATION_SEND

0x05

DEFAULT_SET

0x06

Network Management Proxy

COMMAND_CLASS_NETWORK_MANAGEMENT_PROXY

0x52

NODE_LIST_GET

0x01

NODE_LIST_REPORT

0x02

NODE_INFO_CACHED_GET

0x03

Network Management Primary

COMMAND_CLASS_NETWORK_MANAGEMENT_PRIMARY

0x54

CONTROLLER_CHANGE

0x01

 

 

 

通过解析UDP数据包中的Conmand Class以及封装的command,接下来就是通过Serial API封装,发送给我们的chip了。

2.3.7 Serial Communication

   串口即串行接口,是计算机上一种非常通用设备通信的协议,它可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。

Zipgateway中使用的Serial API,是一套允许主机与Z-wave芯片通信的API。根据现有的芯片系列,可以通过RS-232或者USB物理接口来进行访问Serial API。

图13 Serial API通信模型

 

    如果使用RS-232实现串口通信,则必须按如下进行设置:

Parameter

Value

波特率

115200 bits/s

数据位

8

数据停止位

1

 

ARM主控制器以波特率115200 bits/s8 bit数据位、1 bit停止位方式通过异步串行口(UART)Z-Wave无线模块进行通信(chip)。

如果使用USB连接实现串口通信则必须按照USB通信设备类准则(USB CDC)来实现。

Serial API启动

Zip process启动起来干的第一件事就是启动并初始化Serial API模块。

1. ZipSerialAPIPortName=/dev/ttyS2  

2. process_start  (&serial_api_process,cfg.serial_port)

初始化完成后,获取serial api的相关信息,然后发送第一个ACK包给到chip,表示我已就绪。接着获取gateway的相关信息。

Init初始化结束时,会重置一些添加节点,学习模式等命令。

          ZW_AddNodeToNetwork(ADD_NODE_STOP,0);

          ZW_RemoveNodeFromNetwork(REMOVE_NODE_STOP,0);

         ZW_SetLearnMode(ZW_SET_LEARN_MODE_DISABLE, 0);

Gateway中通信具体实现

    Gateway与zw chip通过简单的协议来进行通信,其通信使用的frametype有如下四种:ACK, NCK,CAN以及DataFrame类型。

ACK frame表示接收端接收到了一个有效的数据帧。

当主机发送了一个数据帧给zw chip后,必须等待chip回一个ACK帧。如果传输出现了错误或其他低概率事件导致传输失败,chip便会回一个其他帧。

gateway会等待1500mstimeout时延等待这个ack帧。

ACK帧的结构如下,是一个8bit的数值,定义为0x06

7

6

5

4

3

2

1

0

ACK(0x06)

NCK frame表示接收端收到的数据有错误,收到NCK时需要进行数据重传(retransmit),其结构如下,定义为0x15

7

6

5

4

3

2

1

0

NCK(0x15)

CAN frame表示接收端丢弃了一个有效的数据帧。Chip正在等待gateway给他发一个ACK帧,但是gateway却为其发送了一个data frame,因此,chip此时会回应gateway一个CAN frame,此时就会发生重传。

7

6

5

4

3

2

1

0

CAN(0x18)

Date Frame,数据帧里面封装了期望的Serial API指令以及请求指令时一些必要的参数。

每一个Data Frame都必须以一个start of frame (SOF)开头,紧接着的是帧的总长度,类型,然后才是封装的Serial APIcommand ID以及对应的参数,最后以一个校验和checksum结尾,其具体结构如下:

7

6

5

4

3

2

1

0

SOF(0x01)

Length

Type

Serial API Command ID

Serial API Command Parameter 1

Serial API Command Parameter n

Checksum

 

帧类型和含义说明:

类型

含义

SOF(start of frame)

主要用来同步,其值为0x01

Length

以字节为单位的帧长度,不包括SOF和checksum

Type

该数据帧的类型有如下三种

0x00REQrequest请求帧

0x01RESresponse 回应帧

0x02…0xFF: 保留位

Serial API Command ID

这个值必须是serial api中支持的ID值(ZW_SerialAPI.h)

Serial API Command Parameters

携带的额外必要的参数

Checksum

校验和

 

校验和主要用来检验帧的完整性,其值初始化为0xFF,伴随着帧结构中其他结构的异或结果传送给chip端。

Checksum = 0xFF ⊕ Length ⊕ Type ⊕ Cmd ID ⊕ CmdParm[1] ⊕ …⊕ Cmd Parm[n]

 

一个基本的发送和接收流程如下,这边的host即我们的zipgateway了,ZW即我们的z-wave chip:

在Serial API模块初始化完成后,既可以开始serial的通信了,在serial API version 4之后的版本中,serial初始化以后,需要初步建立节点的信息帧有必要发送Node Information Command来存储新的Node Information Frame(NIF)。

3 Pyzip & MDNS browser

3.1 Pyzip

PyZIP是一个zipgateway的客户端程序:,他的特点如下:

基于python语言编写而成

利用pyzip可以对ZWgateway进行基本的测试

生成Cert Key用来连接Portal )

主界面:

 


Z-Wave Portal应用

这里提到的portal是指Z-Wave webserver,利用它我们可以发现网络中的Gateway并且想Gateway以及网络中的节点发送Z-wave Command。

在android phone上的界面如下:


       

3.2 MDNS Browser

MDNS Browser是一个展示z-wave节点及其存储在Resource Directory中数据的一个应用程序,目前该应用程序还无法与z-wave network通信,仅有展示功能。

主界面:

 

4 总结

本篇文章主要对Z-Wave技术和核心部分ZIPGateway的流程和核心功能进行了梳理。

随着技术的进一步完善和发展,业界更多的注意力和研发力量将转移到应用的设计和实现、互连互通测试以及市场推广等方面。相信在不远的将来,将会有越来越多的Z-Wave设备进入我们的生活,使我们的生活变得更加便利。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值