【BACnet】1.整体学习方法与学习资源

2019-04-15 13:05发布

Author:forsakening (仅供参考)
@2013/03/21 - initial
@2013/12/28 - revise 

参考资源:

在BACnet官方维护的网站上http://www.bacnet.org/Developer/index.html可以看见有许多关于BACnet的开源工程,笔者选择了两个工程作为参考与研究:    a)BACnet Protocol Stack:可以移植在各种嵌入式设备上,兼容了各种平台:linux win32 pic单片机 arm7,且实现的功能较为完善,提供各种服务,对于BVLL较为详细  这个工程的归档路径:http://sourceforge.net/projects/bacnet/files/  这里面有bacnet-docs,这个目录下其实就是整个工程的API手册,非常值得看一下(Added at 2013/3/23)    b)BACnet Stack for Linux:针对于linux开发的BACnet协议栈,包括BACnet/Ethernet 和 BACnet/Ip 两种方案,其中对于BVLL说的并不是特别详细,主要实现server功能    对于a)选取的版本为bacnet-stack-0.8.0   b)选取的版本为bacnet4linux-0.3.12 (截止至2013/3/21为最新版本),对于这两个工程已经传到我的csdn资源下。    a)的下载地址:http://download.csdn.net/detail/forsakening/5164256       b)的下载地址:http://download.csdn.net/detail/forsakening/5164254  

BACnet Protocol Stack的学习思路

1. BACnet Protocol Stack工程简介

BACnet Protocol Stack工程是Steve Karg大神在sourceforge上维护的一个关于BACnet的开源工程,它随着工程的应用与发展而相应的进行更新。目前已经更新至0.8.2版本(Till 2013/12/18)。 在下载并解压缩BACnet Protocol Stack源码之后,可以看到如下所示的文件及文件夹分布:
图1 BACnet Protocol Stack-0.8.1文件分布
BACnet Protocol Stack工程如同其它开源工程,拥有详细的说明文档,如根目录下就有readme.txt文件。 由于BACnet Protocol Stack工程可以移植于Linux与Win平台下,所以在根目录下的文件基本上就是针对Linux或Win平台的配置文件,如makefile、脚本等,使用户可以直接进行编译操作。 工程中的其它文件夹是包括主要代码、说明文档、demo例程、编译库等: bin ---- BACnet Protocol Stack工程会提供一部分例程,用于模拟实现BACnet的一些功能,如发送i-am-router报文,发送who-is应用服务等,具体生成的二进制应用程序放在bin文件夹下; demo ---- 是BACnet Protocol Stack工程服务例程文件夹,BACnet Protocol Stack工程针对Linux、win32系统实现了多个例程,此文件夹就存放例程的具体代码实现; doc ----- 工程的说明文档,包括faq、编译说明等; include ----- BACnet工程的头文件放在这个文件夹,如BACnet协议网络层的协议报文类型、应用层的对象类型、服务类型等,均用C语言中的枚举、结构体等数据结构表示; lib ----- 工程将一些通用的c文件编译后打包成静态库; ports ---- 此目录和具体的平台或嵌入式os相关,在此文件夹下包括了二级目录如linux、lwip、win32、arm7等,如以本文选择的linux系统为例,在linux文件夹下包含如下文件 图2 ./ports/linux目录下文件分布
此文件夹存在的目的是为各种不同的“port”提供BACnet服务程序,和之前demo文件夹下的例程不同,此目录下的应用程序提供了更多更大的BACnet服务,可以完全充当BACnet控制器,而demo目录下的例程只能提供某一种服务,从这个层面理解,demo目录提供的例程是ports目录下的子集,实际上从代码流程中也可以看出ports目录下的函数调用较demo目录更为复杂;
src ---- 顾名思义,此文件夹下存放BACnet协议栈具体的实现源码,包括mstp状态机、对象模型、BACnet/IP中的BVLL、APDU与NPDU的处理等

2. 建立sourceingsht工程

一般在建立sourcinsight工程时,我们总是选取需要的文件进行加入,否则很多同名的文件在阅读代码时造成不便,如函数调用。通过阅读其根目录下的makefile,对于BACnet工程添加对应的源代码文件为 BACNET_PORT ?= linux BACNET_PORT_DIR = ../ports/${BACNET_PORT}BACNET_OBJECT = ../demo/object BACNET_HANDLER = ../demo/handler BACNET_CORE = ../src BACNET_INCLUDE = ../include 则添加的文件有:../ports/linux  . ./demo/*   ../src ...include 这样建立起来的工程即是只有linux可用的工程,若要兼容于其它平台如PIC单片机,则依照makefile中的步骤:添加相应的ports即可。

3. Linux下的编译过程

 阅读根目录下的readme.txt可以看出,若要在linux平台下编译,直接输入make clean all即可,如下是其make的过程: make -s -C lib clean make -s -C demo clean make -s -C demo/router clean make -s -C lib all make -s -C demo all
可以看出对lib及demo两个target进行了编译,实际上此版本对应的makefile不如bacnet-stack-0.7.1版本来的详细,如下是bacnet-stack-0.7.1版本的主要过程: (因为0.8.0版本的make在主make中加入了-s选项)(Added at 3/23) 先是删除---------------------------------------------------- make -C lib clean make[1]: Entering directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/lib' rm -rf core ../src/apdu.o ../src/npdu.o ../src/bacdcode.o ../src/bacint.o ../src/bacreal.o ../src/bacstr.o ../src/bacapp.o ../src/bacprop.o ../src/bactext.o ../src/datetime.o ../src/indtext.o ../src/key.o ../src/keylist.o ../src/proplist.o ../src/debug.o ../src/bigend.o ../src/arf.o ../src/awf.o ../src/cov.o ../src/dcc.o ../src/iam.o ../src/ihave.o ../src/rd.o ../src/rp.o ../src/rpm.o ../src/timesync.o ../src/whohas.o ../src/whois.o ../src/wp.o ../src/wpm.o ../src/abort.o ../src/reject.o ../src/bacerror.o ../src/ptransfer.o ../src/memcopy.o ../src/filename.o ../src/tsm.o ../src/bacaddr.o ../src/address.o ../src/bacdevobjpropref.o ../src/bacpropstates.o ../src/alarm_ack.o ../src/event.o ../src/getevent.o ../src/get_alarm_sum.o ../src/readrange.o ../src/timestamp.o ../src/version.o ../ports/linux/bip-init.o ../src/bvlc.o ../src/bip.o ../demo/handler/dlenv.o ../demo/handler/txbuf.o ../demo/handler/noserv.o ../demo/handler/h_npdu.o ../demo/handler/h_whois.o ../demo/handler/h_iam.o ../demo/handler/h_rp.o ../demo/handler/h_rp_a.o ../demo/handler/h_rpm.o ../demo/handler/h_rpm_a.o ../demo/handler/h_rr.o ../demo/handler/h_wp.o ../demo/handler/h_wpm.o ../demo/handler/h_alarm_ack.o ../demo/handler/h_arf.o ../demo/handler/h_arf_a.o ../demo/handler/h_awf.o ../demo/handler/h_rd.o ../demo/handler/h_dcc.o ../demo/handler/h_ts.o ../demo/handler/h_whohas.o ../demo/handler/h_ihave.o ../demo/handler/h_cov.o ../demo/handler/h_ccov.o ../demo/handler/h_ucov.o ../demo/handler/h_getevent.o ../demo/handler/h_get_alarm_sum.o ../demo/handler/h_pt.o ../demo/handler/h_pt_a.o ../demo/handler/h_upt.o ../demo/handler/s_arfs.o ../demo/handler/s_awfs.o ../demo/handler/s_dcc.o ../demo/handler/s_ihave.o ../demo/handler/s_iam.o ../demo/handler/s_cov.o ../demo/handler/s_ptransfer.o ../demo/handler/s_rd.o ../demo/handler/s_router.o ../demo/handler/s_rp.o ../demo/handler/s_rpm.o ../demo/handler/s_ts.o ../demo/handler/s_cevent.o ../demo/handler/s_uevent.o ../demo/handler/s_whohas.o ../demo/handler/s_whois.o ../demo/handler/s_upt.o ../demo/handler/s_wp.o ../demo/object/device.o ../demo/object/ai.o ../demo/object/ao.o ../demo/object/av.o ../demo/object/bi.o ../demo/object/bo.o ../demo/object/bv.o ../demo/object/csv.o ../demo/object/lc.o ../demo/object/lsp.o ../demo/object/ms-input.o ../demo/object/mso.o ../demo/object/msv.o ../demo/object/nc.o ../demo/object/trendlog.o ../demo/object/bacfile.o libbacnet.a make[1]: Leaving directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/lib' make -C demo clean make[1]: Entering directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/demo' make -b -C readprop clean 然后是编译新的文件---------------------------------------- 1)编译lib,放在lib文件夹下,生成的是libbacnet.a make -C lib all make[1]: Entering directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/lib' cc -c -Wall -Wmissing-prototypes -Os -I../ports/linux -I../demo/object -I../demo/handler -I../include -DPRINT_ENABLED=1 -DBACAPP_ALL -DBACFILE -DINTRINSIC_REPORTING -DBACDL_BIP=1 -DBBMD_ENABLED=1 -DWEAK_FUNC= ../src/apdu.c -o ../src/apdu.o 2)编译demo,放在demo文件夹下 make[1]: Leaving directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/lib' make -C demo all make[1]: Entering directory `/mnt/hgfs/share_Fedora10/Graduation/bacnet-stack-0.7.1/bacnet-stack-0.7.1/demo' make -b -C readprop all 如此工程便是编译完成。

4. 测试bacnet协议栈

在bin目录下有readme.txt,可以看出要想在linux平台下运行某一程序,如bacserv,输入./bacserv 1234即代表此bacnet设备的id为1234  (此应用程序在demo/server下面也有) [root@zx server]# ./bacserv 1234 BACnet Server Demo BACnet Stack Version 0.8.0 BACnet Device ID: 1234 Max APDU: 1476 实际上此程序bacserv对应的是发送I-Am服务原语,通过wireshark抓包对应BACnet协议从上至下依次为APDU -> NPDU -> BVLL -> (UDP+IP): APDU:

NPDU:
BVLL:
可以看出,此服务程序发送bacnet I-Am报文,且报文格式符合BACnet协议。

5. 后序(Add @2012/12/18

一、通过BACnet Protocol Stack工程来对BACnet协议栈的学习,或者是对BACnet的开发,最重要的还是要多分析源代码、多理解BACnet协议标准。个人感觉BACnet Protocol Stack工程中的Linux下源码还是不难理解的,只是有些关系到BACnet具体协议规程需要理清。 二、关于BACnet开发我也有一些想法: (1)BACnet应用中最重要的就是BACnet控制器,而控制器无疑需要BACnet协议栈的支持,很多文章中都提及在linux操作系统下实现BACnet协议栈,虽然这样开发起来较为方便,但这却增加了硬件成本,所以可以考虑采取低端的MCU来实现BACnet控制器:嵌入式OS + 嵌入式IP协议栈(只需要简单的IP协议栈即可,因为BACnet/IP中只用到了TCP/IP中的UDP技术) + BACnet Protocol Stack;嵌入式OS有很多,包括常见的ucos、rt-thread、freertos等;常见的嵌入式IP协议栈则有Lwip、fnet等;按照这种思路来实现BACnet控制器
(2)其实BACnet Protocol Stack工程中ports目录下有lwip,表示BACnet协议栈可以支持lwip,经过笔者测试,当前版本(bacnet-stack-0.8.0)中lwip这个分支开发的并不是很完善,只是简单的实现了BACnet/IPv4,很难完全支持lwip,而且lwip本身也有部分缺点(如对并发访问处理不够完善),所以完善lwip这部分是一个研究点 (3)BACnet还有一个方向就是BACnet路由器的研究,在BACnet Protocol Stack工程中demo目录下已经有了router例程,这个例程针对linux主要实现了MSTP与IPv4端口之间的路由,笔者的硕士毕业论文有一部分就是关于BACnet/IPv4与BACnet/IPv6网络之间的路由(论文质量那个水啊,说起来都是泪啊!!!各位学生朋友,加油、努力哈!!!),并且实现了一个BACnet路由器用于连接这两种BACnet异构网络

bacnet4linux(BACnet Stack for Linux)

bacnet4linux这个工程虽然页是steve karg大神的大作,但它在实现上显然没有前述的bacnet protocol stack工程更加稳定。 值得一提的是,bacnet4linux工程实现了一个http服务,使得用户可以通过浏览器访问BACnet控制器。