4G GPTAS も動き始めました。
で、やはり15年前のテクノロジーには無理があります。そこで、色々と考えたのですが、EPICS base で色々と書き直すのが良いのではと思い始めました。そこで、1日ぐらいでどこまでできるか試してみました。
目標:アマゾンで売っている中華USB温度計(1000円強)を epics で読む。
この温度計はとっても安いので、実験室のそこいらじゅうにおいて色々な場所の温度をモニターしています。結晶成長する時に部屋の温度変化は大敵なので。今のところ、github に転がっていた linux 用読み取りコードと手製の script を組み合わせて web 上に温度変化を表示していますが、これをepicsで読んでみようという目標です。epics は raspberry pi 4B で走らせます。中華温度計は USB HID デバイスなのでちょっと一筋縄ではいかないため、最初には良い課題かと思いました。
EPICS を Raspberry Pi 4B に載せる
アカウント登録のため ldap 走らせる。(ホームディレクトリはNFSなのでautofsも)
(これはうちの研究室の特殊事情です。いらない人はいらない。)
sudo apt-get install autofs
sudo echo "/home /etc/auto.home" | sudo tee -a /etc/auto.master
sudo echo "* -fstype=nfs4,soft xxx.xxx.xxx.xxx:/volume1/labhome&" | tee -a /etc/auto.home
sudo systemctl restart autofs
sudo apt-get install libnss-ldapd
## check and edit if necessary: /etc/ldap/ldap.conf
## /etc/nsswitch.conf
## /etc/nslcd.conf
## /etc/pam.d/common-password
## /etc/pam.d/common-session
EPICS を入れる
sudo apt-get install libreadline-dev
sudo apt-get install libpcre3-dev
(if necessary, install g++ and make)
cd "~/work/tmp/epics" (ここをworking directory にしました。適宜変えてください)
wget https://epics.anl.gov/download/base/base-7.0.6.tar.gz
tar zxvf base-7.0.6.tar.gz
cd base-7.0.6
make
時間かかります。。。30分ぐらい?
echo "export EPICS_BASE=\${PWD}/base-7.0.6" > setEnvVar
echo "export EPICS_HOST_ARCH=\$(\${EPICS_BASE}/startup/EpicsHostArch)" >> setEnvVar
echo "export PATH=\${EPICS_BASE}/bin/\${EPICS_HOST_ARCH}:\${PATH}" >> setEnvVar
source setEnvVar
softIoc
動いた!ともかく、base は入った。getting started に従って test.db も作って softIoc -d test.db も試しました。問題なし。
Asyn と Stream Device をいれます。
(~/work/tmp/epics で)
mkdir support
cd support
git clone https://github.com/epics-modules/asyn.git
cd asyn/
## edit asyn/configure/RELEASE(以下私のRELEASE fileの主要な変更点)
HOME=/home/sato
SUPPORT=$(HOME)/work/tmp/epics/support
EPICS_BASE=$(HOME)/work/tmp/epics/base-7.0.6
##
(IPAC, SNCSEQ, CALC, SSCANはこの時点では comment out)
make
cd ~/work/tmp/epics/support
git clone https://github.com/paulscherrerinstitute/StreamDevice.git
cd StreamDevice/
## 同様に stream のなかの configure/RELEASE も編集します
##
ASYN=$(SUPPORT)/asyn
PCRE_INCLUDE=/usr/include
PCRE_LIB=/usr/lib
##
rm GNUmakefile
make
(これでできるはずです)
EPICS に calc と drvAsynUSBHID を入れる
中華温度計は USB HID デバイスなので KEK ご謹製の drvAsynUSBHID で読むことを考えました。あと、中華温度計はバイナリで妙なデータを返してくるので calc を入れて、scalcout を使ってバイナリデータを温度に変換することを考えました(ここが一番ややこしかった。)
calc モジュールを入れる
cd ~/work/tmp/epics/support/
wget https://github.com/epics-modules/calc/archive/R3-6-1.tar.gz
tar zxvf R3-6-1.tar.gz
cd calc-R3-6-1/
##edit configure/RELEASE (いつも通りなので詳細は割愛。今回は SSCAN と SNCSEQ をはずしました)
make
drvAsynUSBHID を入れる(hidraw を使います。libusb じゃない方です。cmake も入れます。)
sudo apt-get install libhidapi-hidraw0 libhidapi-dev cmake
cd ~/work/tmp/epics/support
wget http://cerldev.kek.jp/trac/EpicsUsersJP/raw-attachment/wiki/epics/bbb/debian/USBHID/USB_SP4T/drvAsynUSBHID_20170704.tar.gz
tar zxvf drvAsynUSBHID_20170704.tar.gz
mv drvAsynUSBHID-master-4b0e4ee13cb65512d4ccb12a82d6ab3aacb3b0e5 drvAsynUSBHID
(master-の後の数字はこれとは違うかもしれません。)
## Edit configure/RELEASE (今回はasyn, StreamDevice, TOP, SUPPORT等を設定します。)
## Makefile を一応チェックします。(変更なし)
## (重要)中華温度計読み取りのため、drvAsynUSBHID を少しいじります。いじり方は別に書きます。
make
さて、ようやく中華温度計読み取り IOC を作ります!
読み取りIOC の名前を testTEMPer として ~/work/tmp/epics/TEST の中に作ります。
makeBaseApp.pl でテンプレートを作ります。
mkdir ~/work/tmp/epics/TEST/testTEMPer
cd ~/work/tmp/epics/TEST/testTEMPer
makeBaseApp.pl -t ioc testTEMPer
makeBaseApp.pl -i -t ioc testTEMPer
で、出来上がった testTEMPer のなかの configure/RELEASE をいじります。
## 追加/変更する内容
SUPPORT=~/work/tmp/epics/support
ASYN=$(SUPPORT)/asyn
STREAM=$(SUPPORT)/StreamDevice
DRVASYNUSBHID=$(SUPPORT)/drvAsynUSBHID
続いて testTEMPerApp/src/Makefile をいじります。追加するのは
PROD_LDLIBS += -lhidapi-hidraw
testTEMPer_DBD += asyn.dbd
testTEMPer_DBD += stream.dbd
testTEMPer_DBD += drvAsynUSBHID.dbd
testTEMPer_DBD += calc.dbd
testTEMPer_LIBS += asyn
testTEMPer_LIBS += stream
testTEMPer_LIBS += drvAsynUSBHID
testTEMPer_LIBS += calc
(つまり asyn, stream, drvAsynUSBHID, calc を使いますよ、と書くわけです。)
testTEMPerApp/Db/Makefile をいじります。追加するのは:
DB += testTEMPer.db
で、つくります
cd ~/work/tmp/epics/TEST/testTEMPer
make
実行スクリプト st.cmd をいじります
cd ~/work/tmp/epics/TEST/testTEMPer/iocBoot/ioctestTEMPer/
## edit st.cmd 修正/追加内容は以下の通り
epicsEnvSet("STREAM_PROTOCOL_PATH", ".:${TOP}/testTEMPerApp/Db" )
drvAsynUSBHIDConfigure($(dev), "0x0c45", "0x7401", "", "/dev/hidraw1", "1")
epicsEnvSet("dev", "HID1")
dbLoadRecordes("db/testTEMPer.db", "USER=TEST,DEV=$(dev)")
chmod u+x st.cmd
IOC本体はできました。次に、testTEMPer database ファイルと protocol ファイルを作ります。
中華温度計は /dev/hidraw1 (0じゃないんです、、、) に binary で0x00 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00を送ると binary で 8byte 返してきます。このうち(0から数えて)2,3byte目が温度情報です。(buf[3]&0xFF + buf[2]<<8)*125.0/32000. が温度です。なんとややこしい。(あれ、今気がついたけど、これ、short (2byte)の little endian で読むだけじゃないの?アホだった???まぁ、いいや。)
で、proto ファイル(~/work/tmp/epics/TEST/testTEMPer/testTEMPerApp/Db/testTEMPER.proto)は以下の様な感じになります。
TERMINATOR="";
LockTimeout = 500;
ReplyTimeout = 100;
ReadTimeout = 100;
WriteTimeout = 1000;
setsw {
out "%r";
}
getsw {
MaxInput = 8;
out 0x00 0x01 0x80 0x33 0x01 0x00 0x00 0x00 0x00;
in "%8c";
}
重要な点:MaxInput を指定して terminator を無視させます。その上で%8c で unsigned char で8byte 読み込みます。(それでも、なんかwarning 行ってくるけど、、、多分stream deviceのバグ。)
次に、database file ですが、次の通りです:
record(stringin, "$(USER):testTEMPer:get") {
field(DTYP, "stream")
field(FTVL, "UCHAR")
field(SCAN, "1 second")
field(INP, "@testTEMPer.proto getsw $(DEV)")
field(NELM, 8)
field(FLNK, "$(USER):testTEMPer:calctemp")
}
record(scalcout, "$(USER):testTEMPer:calctemp"){
field(INAA, "$(USER):testTEMPer:get")
field(CALC, "((BYTE(AA[2,2])<<8)+BYTE(AA[3,3]))*125.0/32000.")
field(OUT, "$(USER):testTEMPer:temperature")
field(FLNK, "$(USER):testTEMPer:temperature")
}
record(ai, "$(USER):testTEMPer:temperature"){
field(INP, "")
field(FLNK, "")
field(SCAN, "Passive")
}
重要な点:stream から UCHAR で8個分読みます。testTEMPer.proto に定義された、getsw を使います。$(DEV)は st.cmd に定義した HID1 ですね。1秒おきに定期的に読みます。(温度なんで)で、その読み取りはstringin (文字列型)にして forward link (FLNK) で calctemp に送ります。calctemp ではscalcout を使ってbyte ごとに読んで(AA[2,2]という様に始まりと終わりを指定しないとエラーになることに注意)、それをシフトしたりなんだかんだりで温度に変換します。で、それを FLINKで testTEMPer:temperature に送ります。で、ai (analog input)で受けます。このrecordは何もしないので”Passive” の何もしないrecordにしておきます。
まだあります。中華温度計のデバイスファイル /dev/hidraw1 の読み取り許可を与えねばなりません。
手は色々とあります。今回は
udev rules 弄りました
/etc/udev/rules.d/50-usb-temper.rules を書きました。内容は:
KERNEL=="hidraw*",ATTRS{idVendor}=="0c45",ATTRS{idProduct}=="7401",MODE="0666"
##本当は、/dev/hidraw* を dialout のgroup にして、userの副グループにdialout を足すのが綺麗な気がしますが、今回は楽しました。
これで、温度計を抜き差しします。
これで、動くはず。
まず、testTEMPer を動かします。
cd ~/work/tmp/epics/TEST/testTEMPer/iocBoot/ioctestTEMPer/
./st.cmd
これでEPICS IOCが動きます。
他のターミナルを開いて
cd ~/work/tmp/epics
source setEnvVar
caget TEST:testTEMPer:temperature
で温度が読めます。
camonitor TEST:testTEMPer:temperature
で連続モニターができます。
ここまでくればあとは簡単。
CS-Studio (Phoebus)をダウンロードします。
https://controlssoftware.sns.ornl.gov/css_phoebus/
MacOS用は Java も入っていて簡単に動きます。(他は試してないです。)
このページのinstructionに従ってインストールします。
CSS_Phoebus.app を立ち上げて、
Applications->Display->New Display
を選びます。あとは、この画面に要素を配置していくだけです。要素のPV Name というところに、TEST:testTEMPer:temperature を入れると勝手にIOCに繋いでデータを取ってきてくれます。
Text Update
Meter
StripChart
を配置した例は以下の通り。走らせるには緑の右矢印をクリック。下の画面になります。