Wiki

Clone wiki

bacnet-phpextension / Home

本モジュールはオープンソースとして提供します。
自由に改変・再配布していただいて構いません。
ただし、本モジュール使用により発生した如何なる損害・不利益についても当方責任を負いかねます。
また、本モジュールを使用して発生した如何なる損害・不利益についても当方に損害賠償の請求などを行わないことに同意された方のみ利用いただけるものとし、利用した時点で同意されたものといたします。

※lib64ディレクトリにコンパイル済みのモジュールを登録しています。環境条件があえば、そのまま使用できます。

bacnet-phpextensionについて

このコードはPHPの拡張モジュールです。
BacnetプロトコルをPHPから行えるようにするためのモジュールです。

プロトコルスタックとして、bacnet-stack-0.8.6.zipを使用しています。

対応バージョン

ソフトウェア バージョン
PHP 7.2
bacnet-stack 0.8.6
CentOS Linux release 7.7.1908 (Core)
gcc 4.8.5 20150623

この拡張モジュールはphphizeを使わず、phpのソースコード一式を使って構築しています。 以下コンパイルなどの説明をする際にはその環境をベースに説明します。
phphizeを使った環境でコンパイルする際には読み替えが必要な個所は適宜読み替えてください。

コンパイル方法

bacnet-stackをコンパイルします。
このライブラリ自体についてはダウンロード元のサイトで確認ください。

本拡張モジュールをエクステンションとしてロードする形で使用できるようにするためには bacnet-stackを共有ライブラリとしてコンパイルする必要があります。

しかし、bacnet-stackは静的ライブラリとしてコンパイルする形でのMakefileの提供となっています。
ですので、bacnet-stackを共有ライブラリとしてコンパイルできるようにMakefileを変更してコンパイルを実行します。

bacnet-stackのコンパイル

適当な作業ディレクトリに「bacnet-stack-0.8.6.zip」を展開します

$ mv bacnet-stack-0.8.6.zip /usr/local/src/
$ cs /usr/local/src
$ unzip bacnet-stack-0.8.6.zip

bacnet-stack-0.8.6/Makefile に以下の変更を加えます

1.共有ライブラリmekeルールの追加

slibrary:
    $(MAKE) -s -C lib slib
をlibrary: のルールの次あたりに追加します。

2.makeクリーンに共有ライブラリのクリーンを追加 clean: のルールに

    $(MAKE) -s -C lib sclean
を追加します。

bacnet-stack-0.8.6/lib/Makefile を変更します。

#Makefile to build BACnet Library with GCC

# tools - only if you need them.
# Most platforms have this already defined
# CC = gcc
# AR = ar
# MAKE = make
# SIZE = size
#
# Assumes rm and cp are available

BACNET_PORT_DIR = ../ports/${BACNET_PORT}
BACNET_OBJECT = ../demo/object
BACNET_HANDLER = ../demo/handler
BACNET_CORE = ../src
BACNET_INCLUDE = ../include
# compiler configuration
#STANDARDS = -std=c99
INCLUDE1 = -I$(BACNET_PORT_DIR) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER)
INCLUDE2 = -I$(BACNET_INCLUDE)
INCLUDES = $(INCLUDE1) $(INCLUDE2)

# target
TARGET = bacnet
LIBRARY = lib$(TARGET).a
SLIBRARY = lib$(TARGET).so  // ここ追加

CORE_SRC = \
        $(BACNET_CORE)/apdu.c \
        $(BACNET_CORE)/npdu.c \
        $(BACNET_CORE)/bacdcode.c \
        $(BACNET_CORE)/bacint.c \
        $(BACNET_CORE)/bacreal.c \
        $(BACNET_CORE)/bacstr.c \
        $(BACNET_CORE)/bacapp.c \
        $(BACNET_CORE)/bacprop.c \
        $(BACNET_CORE)/bactext.c \
        $(BACNET_CORE)/bactimevalue.c \
        $(BACNET_CORE)/datetime.c \
        $(BACNET_CORE)/indtext.c \
        $(BACNET_CORE)/key.c \
        $(BACNET_CORE)/keylist.c \
        $(BACNET_CORE)/proplist.c \
        $(BACNET_CORE)/debug.c \
        $(BACNET_CORE)/bigend.c \
        $(BACNET_CORE)/arf.c \
        $(BACNET_CORE)/awf.c \
        $(BACNET_CORE)/cov.c \
        $(BACNET_CORE)/dcc.c \
        $(BACNET_CORE)/iam.c \
        $(BACNET_CORE)/ihave.c \
        $(BACNET_CORE)/rd.c \
        $(BACNET_CORE)/rp.c \
        $(BACNET_CORE)/rpm.c \
        $(BACNET_CORE)/timesync.c \
        $(BACNET_CORE)/whohas.c \
        $(BACNET_CORE)/whois.c \
        $(BACNET_CORE)/wp.c \
        $(BACNET_CORE)/wpm.c \
        $(BACNET_CORE)/abort.c \
        $(BACNET_CORE)/reject.c \
        $(BACNET_CORE)/bacerror.c \
        $(BACNET_CORE)/ptransfer.c \
        $(BACNET_CORE)/memcopy.c \
        $(BACNET_CORE)/filename.c \
        $(BACNET_CORE)/tsm.c \
        $(BACNET_CORE)/bacaddr.c \
        $(BACNET_CORE)/address.c \
        $(BACNET_CORE)/bacdevobjpropref.c \
        $(BACNET_CORE)/bacpropstates.c \
        $(BACNET_CORE)/alarm_ack.c \
        $(BACNET_CORE)/event.c \
        $(BACNET_CORE)/getevent.c \
        $(BACNET_CORE)/get_alarm_sum.c \
        $(BACNET_CORE)/readrange.c \
        $(BACNET_CORE)/timestamp.c \
        $(BACNET_CORE)/version.c

HANDLER_SRC = \
        $(BACNET_HANDLER)/dlenv.c \
        $(BACNET_HANDLER)/txbuf.c \
        $(BACNET_HANDLER)/noserv.c \
        $(BACNET_HANDLER)/h_npdu.c \
        $(BACNET_HANDLER)/h_whois.c \
        $(BACNET_HANDLER)/h_iam.c  \
        $(BACNET_HANDLER)/h_rp.c \
        $(BACNET_HANDLER)/h_rp_a.c \
        $(BACNET_HANDLER)/h_rpm.c \
        $(BACNET_HANDLER)/h_rpm_a.c \
        $(BACNET_HANDLER)/h_rr.c \
        $(BACNET_HANDLER)/h_rr_a.c  \
        $(BACNET_HANDLER)/h_wp.c  \
        $(BACNET_HANDLER)/h_wpm.c \
        $(BACNET_HANDLER)/h_alarm_ack.c  \
        $(BACNET_HANDLER)/h_arf.c  \
        $(BACNET_HANDLER)/h_arf_a.c  \
        $(BACNET_HANDLER)/h_awf.c  \
        $(BACNET_HANDLER)/h_rd.c  \
        $(BACNET_HANDLER)/h_dcc.c  \
        $(BACNET_HANDLER)/h_ts.c  \
        $(BACNET_HANDLER)/h_whohas.c  \
        $(BACNET_HANDLER)/h_ihave.c  \
        $(BACNET_HANDLER)/h_cov.c  \
        $(BACNET_HANDLER)/h_ccov.c  \
        $(BACNET_HANDLER)/h_ucov.c  \
        $(BACNET_HANDLER)/h_getevent.c  \
        $(BACNET_HANDLER)/h_gas_a.c  \
        $(BACNET_HANDLER)/h_get_alarm_sum.c  \
        $(BACNET_HANDLER)/h_pt.c  \
        $(BACNET_HANDLER)/h_pt_a.c  \
        $(BACNET_HANDLER)/h_upt.c  \
        $(BACNET_HANDLER)/s_arfs.c \
        $(BACNET_HANDLER)/s_awfs.c \
        $(BACNET_HANDLER)/s_dcc.c \
        $(BACNET_HANDLER)/s_ihave.c \
        $(BACNET_HANDLER)/s_iam.c  \
        $(BACNET_HANDLER)/s_cov.c  \
        $(BACNET_HANDLER)/s_ptransfer.c \
        $(BACNET_HANDLER)/s_rd.c \
        $(BACNET_HANDLER)/s_rp.c  \
        $(BACNET_HANDLER)/s_rpm.c  \
        $(BACNET_HANDLER)/s_readrange.c  \
        $(BACNET_HANDLER)/s_ts.c \
        $(BACNET_HANDLER)/s_cevent.c  \
        $(BACNET_HANDLER)/s_router.c  \
        $(BACNET_HANDLER)/s_uevent.c  \
        $(BACNET_HANDLER)/s_whohas.c \
        $(BACNET_HANDLER)/s_whois.c  \
        $(BACNET_HANDLER)/s_wpm.c  \
        $(BACNET_HANDLER)/s_upt.c \
        $(BACNET_HANDLER)/s_wp.c

PORT_ARCNET_SRC = \
        $(BACNET_PORT_DIR)/arcnet.c

PORT_MSTP_SRC = \
        $(BACNET_PORT_DIR)/rs485.c \
        $(BACNET_PORT_DIR)/dlmstp.c \
        $(BACNET_PORT_DIR)/timer.c \
        $(BACNET_CORE)/ringbuf.c \
        $(BACNET_CORE)/fifo.c \
        $(BACNET_CORE)/mstp.c \
        $(BACNET_CORE)/mstptext.c \
        $(BACNET_CORE)/crc.c \

PORT_ETHERNET_SRC = \
        $(BACNET_PORT_DIR)/ethernet.c

PORT_BIP_SRC = \
        $(BACNET_PORT_DIR)/bip-init.c \
        $(BACNET_CORE)/bvlc.c \
        $(BACNET_CORE)/bip.c

PORT_BIP6_SRC = \
        $(BACNET_HANDLER)/h_bbmd6.c \
        $(BACNET_PORT_DIR)/bip6.c \
        $(BACNET_CORE)/vmac.c \
        $(BACNET_CORE)/bvlc6.c

PORT_ALL_SRC = \
        $(PORT_ARCNET_SRC) \
        $(PORT_MSTP_SRC) \
        $(PORT_ETHERNET_SRC) \
        $(PORT_BIP_SRC) \
        $(PORT_BIP6_SRC)

ifeq (${BACDL_DEFINE},-DBACDL_BIP=1)
PORT_SRC = ${PORT_BIP_SRC}
endif
ifeq (${BACDL_DEFINE},-DBACDL_BIP6=1)
PORT_SRC = ${PORT_BIP6_SRC}
endif
ifeq (${BACDL_DEFINE},-DBACDL_MSTP=1)
PORT_SRC = ${PORT_MSTP_SRC}
endif
ifeq (${BACDL_DEFINE},-DBACDL_ARCNET=1)
PORT_SRC = ${PORT_ARCNET_SRC}
endif
ifeq (${BACDL_DEFINE},-DBACDL_ETHERNET=1)
PORT_SRC = ${PORT_ETHERNET_SRC}
endif
ifdef BACDL_ALL
PORT_SRC = ${PORT_ALL_SRC}
endif

// ここから
DEVICE_SRC = \
        ${BACNET_OBJECT}/device.c \
        ${BACNET_OBJECT}/ai.c \
        ${BACNET_OBJECT}/ao.c \
        ${BACNET_OBJECT}/av.c \
        ${BACNET_OBJECT}/bi.c \
        ${BACNET_OBJECT}/bo.c \
        ${BACNET_OBJECT}/bv.c \
        ${BACNET_OBJECT}/nc.c \
        ${BACNET_OBJECT}/lsp.c \
        ${BACNET_OBJECT}/lc.c \
        ${BACNET_OBJECT}/ms-input.c \
        ${BACNET_OBJECT}/mso.c \
        ${BACNET_OBJECT}/msv.c \
        ${BACNET_OBJECT}/trendlog.c \
        ${BACNET_OBJECT}/bacfile.c \
        ${BACNET_OBJECT}/osv.c \
        ${BACNET_OBJECT}/piv.c \
        ${BACNET_OBJECT}/schedule.c
// ここまで追加


SRCS = ${CORE_SRC} ${PORT_SRC} ${HANDLER_SRC}
SRCS2 = ${CORE_SRC} ${PORT_SRC} ${HANDLER_SRC} ${DEVICE_SRC}  // ここ追加

OBJS = ${SRCS:.c=.o}
SOBJS = ${SRCS2:.c=.o}  // ここ追加

# use local includes, but other values from calling Makefile
CFLAGS  = $(WARNINGS) $(DEBUGGING) $(OPTIMIZATION) $(STANDARDS) $(INCLUDES) $(DEFINES)

all: $(LIBRARY)

lib: $(LIBRARY)

slib: $(SLIBRARY)  // ここ追加

$(LIBRARY): $(OBJS) Makefile
        $(AR) rcs $@ $(OBJS)

.c.o:
        ${CC} -c ${CFLAGS} $*.c -o $@

depend:
        rm -f .depend
        ${CC} -MM ${CFLAGS} *.c >> .depend

clean:
        rm -rf core $(OBJS) $(LIBRARY)

include: .depend

// ここから
$(SLIBRARY): $(SOBJS) Makefile 
        ${CC} -shared -fPIC -o libbacnet.so $(SOBJS)

$(SOBJS):
        ${CC} -c ${CFLAGS} -fPIC $*.c -o $@

sclean:
        rm -rf core $(SOBJS) $(SLIBRARY)
// ここまで追加

コンパイルを開始します。

$ make clean
$ make slibrary

を実行すると、/lib ディレクトリにlibbacnet.soが生成されます。

※「 -fPIC を付けて再コンパイルしてください」というようなエラーが発生する場合 make clean が正しく行われていない可能性があります。
※make cleanをすると、コンパイル済みのファイルがすべて削除されます。

本拡張モジュールを使うにあたって、作成されたlibbacnet.soは/usr/lib64/に コピー、移動、あるいはシンボリックリンクを貼ってください。

追加したライブラリを有効にするために

$ sudo ldconfig
をしておきます。

本拡張モジュールのコンパイル

phpのソースを展開したディレクトリを/usr/local/src/php-srcとした場合、 /usr/local/src/php-src/ext/bacnet/ディレクトリとして本コードをクローンします。

そのうえで、/usr/local/src/php-srcにて

$ ./buildconf
$ ./configure --with-bacnet=shared
$ ./make

を実行します。コンパイルに成功すれば、modules/bacnet.soが生成されています。
テストは

$ ./sapi/cli/php -d extension=./modules/bacnet.so -f ./ext/bacnet/test_bacnet.php
で行うことができます。

使い方

以下一例です。

#!php
<?php

class TestBACNet
{
    protected $bacnetInstance;

    public $deviceInstance = 1245;
//    public $deviceInstance = 112233;
    public $objectType;
    public $objectInstance;
    public $property;

    public function __construct($port = null, $bbmdPort = null, $bbmdAddress = null)
    {
        $this->bacnetInstance = new Bacnet($port, $bbmdPort, $bbmdAddress);
        $this->bacnetInstance->initialize();
//        $this->bacnetInstance = new Bacnet();
//        $this->bacnetInstance->initialize($port, $bbmdPort, $bbmdAddress);
    }

    public function initialize($port = null, $bbmdPort = null, $bbmdAddress = null)
    {
        $this->bacnetInstance->initialize($port, $bbmdPort, $bbmdAddress);
    }

    public function setDeviceInstance($di)
    {
        $this->deviceInstance = $di;
    }

    public function getBacnetInstance()
    {
        if(!$this->bacnetInstance) {
            $this->bacnetInstance =  new Bacnet();
        }
        return $this->bacnetInstance;
    }

    public function readPropetyHandler($arg)
    {
        print("--read propety--\n");
        var_dump($arg);
    }

    public function readRangeHandler($arg)
    {
        print("--read range--\n");
        var_dump($arg);
    }

    public function whois()
    {
        $res = $this->bacnetInstance->whois();
        var_dump($res);
    }

    public function readPropety()
    {
        $di = $this->deviceInstance;
        $ot = 8;
        $oi = $this->deviceInstance;
        $prop = 75;
//        $prop = 76;

        $ot = 1;
        $oi = 0;
        $prop = 85;


        $this->bacnetInstance->readPropertyAckHandler([$this, "readPropetyHandler"]);
        $res = $this->bacnetInstance->readprop($di, $ot, $oi, $prop);
        if(!$res) {
            var_dump($this->bacnetInstance->getLastErrorMsg());
        }
    }

    public function readRange()
    {
        $di = $this->deviceInstance;
        $ot = 20;
        $oi = 2;
        $prop = 131;
        $dt = 4;

        $this->bacnetInstance->readRangeAckHandler([$this, "readRangeHandler"]);
        $res = $this->bacnetInstance->readrange($di, $ot, $oi, $prop, $dt);
        if(!$res) {
            var_dump($this->bacnetInstance->getLastErrorMsg());
        }
    }
}

//$obj = new TestBACNet();
$obj1 = new TestBACNet(47809, 47808, '192.168.8.220');
$obj2 = new TestBACNet();
$obj2->setDeviceInstance(112233);

// whois
//$obj->whois();

// readprop
$obj1->readPropety();
$obj2->readPropety();

// readrange
$obj1->readRange();
$obj2->readRange();

本モジュールを有効にすることで、Bacnetクラスが使えるようになります。
このクラスが、whois、readprop、readrangeメソッドを持っており、適切な引数で呼び出すことでbacnetプロトコルを実行できます。
readprop、readrangeメソッドは非同期処理になるので、コールバックメソッドを登録して結果を取得します。

また、プロパティ名、プロパティ値、オブジェクトタイプ名、オブジェクト対応値はそれぞれ getPropName(10)、getPropIdFromName('apdu-segment-timeout')、getObjectName(14)、getObjectTypeFromName('multi-state-output')メソッドで 対応したものを取得することができます。

注意事項

※PHP拡張機能は + 1.ZTSかNTSかどちらのmaintainerか + 2.デバックモードが有効かどうか + 3.PHPのバージョン が一致している必要があります。

CentOSでは、NTZ、no-debugでコンパイルされたPHPがインストールされているので、上述のコンパイルオプションとなりますが、 環境に応じて変更する必要があります。

ZTSでコンパイルするには、

--enable-maintainer-zts

デバッグモードでコンパイルするには

--enable-debug

を./configure 時にオプションに追加する必要があります。

参考URL

http://bacnet.sourceforge.net/

Updated