RaspberryPiとUbuntuでEPICSはじめました#7 StreamDevice(実践編)
見出し画像

RaspberryPiとUbuntuでEPICSはじめました#7 StreamDevice(実践編)

note_project

この記事は、EPICS(Experimental Physics and Industrial Control System)の初学用にまとめた記事です。

前回、#6ではEPICSへStreamDeviceのインストールを行いました。
今回はこの環境を使用してStreamDeviceを使用してみましょう。

StreamDeviceで何ができるのか思い出してみましょう。
確か「バイナリストリーム」だったと思います。
この動きだけ確認してみましょう。

参考

ここにあります。(終わり)
と言うことで、参考にしてやってみます。
1と2は前回のインストール編で完了しましたので3からです。

以下かなり抜粋と意訳
3. Build an Application
To use StreamDevice, your application must be built with the asyn and stream libraries and must load asyn.dbd and stream.dbd.
Include the following lines in your application Makefile:
PROD_LIBS += stream
PROD_LIBS += asyn
自分のアプリケーションに2行追加して何とかするみたいですね。
4. The Startup Script
StreamDevice is based on protocol files. 
protocolファイルを作成が必要なようですね。
5. The Protocol File
Put the protocol file in one of the directories listed in STREAM_PROTOCOL_PATH.
プロトコルファイルのパスがあるようなので確認しましょう。
6. Configure the Records
To make a record use StreamDevice, set its DTYP field to "stream".
The INP or OUT link has the form "@file protocol bus [address [parameters]]".
なんか使うために色々設定しろと書いています。

3. Build an Application
今回は新しい環境で試してみたいと思います。
まず環境を新規作成してみましょう。/opt/epics/base/appへ移動して

epics@ubuntu:/opt/epics/base/app$ mkdir bs
epics@ubuntu:/opt/epics/base/app$ cd bs
epics@ubuntu:/opt/epics/base/app/bs$ makeBaseApp.pl -l
Valid application types are:
	support
	example
	caPerl
	ioc
	caClient
Valid iocBoot types are:
	ioc
	example

epics@ubuntu:/opt/epics/base/app/bs$ makeBaseApp.pl -t ioc iocbs
epics@ubuntu:/opt/epics/base/app/bs$ ls
Makefile  configure  iocbsApp

epics@ubuntu:/opt/epics/base/app/bs$ makeBaseApp.pl -i -t ioc iocbs
Using target architecture linux-arm (only one available)
The following applications are available:
   iocbs
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name? 

epics@ubuntu:/opt/epics/base/app/bs$ ls
Makefile  configure  iocBoot  iocbsApp

iocbs_DBD += stream.dbd
iocbs_DBD += asyn.dbd

PROD_LIBS += stream
PROD_LIBS += asyn
を追加します。
ここはどんなアプリでも共通です。
さて、制御対象をどうしましょう?ってことになります。
目先にあるのはRaspberryPiのみですから制御するものがありません。
なので今回はWEBサーバーを相手にしてみましょう!これだって立派な制御対象です。なのでLANで通信ができるように、
iocbs_DBD += drvAsynIPPort.dbd
を加えます。シリアル通信を行うならば
iocbs_DBD += drvAsynSerialPort.dbd
ってなりますが、今回はLANですので上です。

epics@ubuntu:/opt/epics/base/app/bs$ vi iocbsApp/src/Makefile

...
# iocbs.dbd will be made up from these files:
iocbs_DBD += base.dbd
iocbs_DBD += stream.dbd
iocbs_DBD += asyn.dbd

# Include dbd files from all support applications:
# iocbs_DBD += xxx.dbd
# iocbs_DBD += drvAsynSerialPort.dbd
iocbs_DBD += drvAsynIPPort.dbd

# Add all the support libraries needed by this IOC
#iocbs_LIBS += xxx
iocbs_LIBS += stream
iocbs_LIBS += asyn
...

4. The Startup Script
プロトコルファイルのディレクトリを用意してプロトコルファイルを準備、それを入出力先のポート今回は"web"って名前にして割り当てます。
まず入出力ポートの準備です。制御対象は世界のgoogle様にしました。多少のエラーも許してくれるでしょう。--;
制御内容はwebページの取得ですからtelnetで手動でHPを取得する手順をそのまま書くことになります。


epics@ubuntu:~$ telnet www.google.co.jp 80
Trying 172.217.161.67...
Connected to www.google.co.jp.
Escape character is '^]'.
GET / HTTP/1.1
Host:www.google.co.jp
HTTP/1.1 200 OK
Date: Wed, 08 Jul 2020 05:06:30 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=Shift_JIS
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
 path=/; domain=.google.co.jp; Secure
...

今回の場合は、drvAsynIPPortConfigureの設定はtelnetで使う先と同じですね。

epics@ubuntu:/opt/epics/base/app/bs$ mkdir protocols
epics@ubuntu:/opt/epics/base/app/bs$ vi iocBoot/iocbs/st.cmd

変更内容
epicsEnvSet("STREAM_PROTOCOL_PATH", ".:../../protocols")
## Load record instances
#dbLoadRecords("db/xxx.db","user=epics")
dbLoadRecords("db/bs.db","user=epics")
drvAsynIPPortConfigure "web","www.google.co.jp:80",0,0,0

5. The Protocol File
説明が逆の方が分かりやすそうですが、先ほど準備したプロトコルファイルのディレクトリへプロトコルファイルを格納します。outは制御対象に対する取得要求を書くことになりますので上記telenetの際のアクセスで使ったGETとHostを行います。inは取得する側なのですがstringinは39文字制限?とか書いてあるようなので真似して39文字で止めてます。まあ改行が最初に来るから今回意味がないかもですが。


epics@ubuntu:/opt/epics/base/app/bs$ vi protocols/bs.proto

# bs.protoの中身
Terminator = CR LF;

getVal {
 out "GET / HTTP/1.1\nHost: www.google.co.jp\n";
 in "%39c";
 ExtraInput = Ignore;
}

6. Configure the Records
レコードと上記で設定したstreamをiocbsApp/Db/bs.dbへ追記して関連させます。
"http:get"レコードは、"bs.proto"の"setValue"を使って"web"ポートとのやり取りしてレコードを操作するよって宣言します。まあこの辺の正しい解釈は置いといて現状はこれくらいで抑えて置きましょう。

epics@ubuntu:/opt/epics/base/app/bs$ vi iocbsApp/Db/bs.db

# Db/bs.dbの中身
record(stringin, "http:get")
{
 field(DESC, "get bitstream")
 field(DTYP, "stream")
 field(INP, "@bs.proto getVal web")
}

epics@ubuntu:/opt/epics/base/app/bs$ vi ./iocbsApp/Db/Makefile

修正点
#DB += xxx.db
DB += bs.db

さあmakeの前にいつものあれやっておきましょう。
今回はASYNとSTREAMの追加です。
STREAMの作成が中途半端ですとここで泣きます。私は泣きました。
ちなみにmakeがうまくいかない時はmake distcleanをしてからmakeするとうまくいくこともあります。依存関係のなんんちゃら言うやつですね。特にMakefileをいじくり回したり依存するパッケージをmakeし直すことがあれば一度上記をやってから依存するパッケージをmakeした方が良いです。老婆心ながら。

epics@ubuntu:/opt/epics/base/app/bs$ vi configure/RELEASE
# Makeの前に追加しておきましょう。
ASYN=$(EPICS_BASE)/../asyn4-38
# この手順で作成するとSTREAM=$(EPICS_BASE)/../streamではないので注意。
STREAM=$(EPICS_BASE)/../stream/StreamDevice

はいではmakeして実行権限を変更して実行です。


epics@ubuntu:/opt/epics/base/app/rpi_gpio$ make
...
epics@ubuntu:/opt/epics/base/app/bs$ cd iocBoot/iocbs
epics@ubuntu:/opt/epics/base/app/bs/iocBoot/iocbs$ ls -l
total 12
-rw-rw-r-- 1 epics epics 124 Jul  7 05:10 Makefile
-rw-rw-r-- 1 epics epics 221 Jul  7 05:54 envPaths
-rw-rw-r-- 1 epics epics 516 Jul  7 05:44 st.cmd

epics@ubuntu:/opt/epics/base/app/bs/iocBoot/iocbs$ sudo chmod +x st.cmd
...
epics@ubuntu:/opt/epics/base/app/bs/iocBoot/iocbs$ ls -l
total 12
-rw-rw-r-- 1 epics epics 124 Jul  7 05:10 Makefile
-rw-rw-r-- 1 epics epics 221 Jul  7 05:54 envPaths
-rwxrwxr-x 1 epics epics 516 Jul  7 05:44 st.cmd

epics@ubuntu:/opt/epics/base/app/bs/iocBoot/iocbs$ sudo ./st.cmd
[sudo] password for epics: 
#!../../bin/linux-arm/iocbs
< envPaths
epicsEnvSet("IOC","iocbs")
epicsEnvSet("TOP","/opt/epics/base-7.0.4/app/bs")
epicsEnvSet("ASYN","/opt/epics/base/../asyn4-38")
epicsEnvSet("STREAM","/opt/epics/base/../stream/StreamDevice")
epicsEnvSet("EPICS_BASE","/opt/epics/base")
cd "/opt/epics/base-7.0.4/app/bs"
## Register all support components
dbLoadDatabase "dbd/iocbs.dbd"
iocbs_registerRecordDeviceDriver pdbbase
epicsEnvSet("STREAM_PROTOCOL_PATH", ".:../../protocols")
## Load record instances
#dbLoadRecords("db/xxx.db","user=epics")
dbLoadRecords("db/bs.db","user=epics"
drvAsynIPPortConfigure "web","www.google.co.jp:80",0,0,0
cd "/opt/epics/base-7.0.4/app/bs/iocBoot/iocbs"
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.4
## Rev. 2020-07-05T10:04+0000
############################################################################
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=epics"
epics> dbpf http:get 0
DBF_STRING:         "0"       
epics> dbgf http:get
DBF_STRING:         "HTTP/1.1 200 OK"   
epics> 

一度dbpf http:get 0にてダミーデータを書いていますがこの時リクエストと取得をしています。
それで次のdbgf http:getで取得したデータが表示されました(先頭の1行のみですが)。何度やってもHTTP/1.1 200 OKの1行目だけなので面白味がありませんね。すみません。題材が悪かったかもです。

さてMacやWindowsなどからPythonで扱うにはどうしたら良いでしょうか。まだやるのか!って言われそうですが簡単なのでお付き合いください。(^^;
簡単です。ただし注意が必要でcaputには処理待ちwait=Trueを入れる必要があります。処理待ちにすることでサーバーから読み込まれるまで待ちます、待たないと読み込む前にcagetをしてしまうため値がなく0になりますので要注意です。

>>> import epics
>>> epics.caput('http:get.VAL','0',wait=True)
>>> print(epics.caget('http:get.VAL'))
HTTP/1.1 200 OK

初歩も初歩のお試しですが、なんとなく処理の流れが掴めたのではないでしょうか?!
Mac,WindowsPC から epicsで取得要求して、RaspberryPiでGoogleから取得した結果をMac,WindowPCで見るなんで手間のかかること普通はしませんけどね、まあなんとなく流れが掴めたら儲けもの。

とりあえずここまでお付き合い頂きありがとうございました。

教訓:題材選びは変化するものの方が面白い

で、今回の題材でStreamDeviceを使う意味があったのか?・・・まあ動いたからよしにしましょう。おしまい



この記事が参加している募集

私の仕事

この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
note_project
開発歴=物心ついた時のIT土方です。 初心に戻って色々試していきますのでお付き合いください。