| 290 | |
| 291 | 最終的には設置場所や予算の関係で、当初の構成でないとダメだということになったので、netDev + darwin を諦めて、modbusで実装することにした。 |
| 292 | |
| 293 | === modbus === |
| 294 | |
| 295 | 以前modbusを使ったIOCを作成しようとしたが、色々と知識不足で断念した経緯があった。[[br]] |
| 296 | |
| 297 | modbusモジュールをPF EPICS環境にインストール。 |
| 298 | |
| 299 | {{{ |
| 300 | [epics@pfrproc1 ~]$ cd /pf/epics/R315.5/modules/soft/ |
| 301 | [epics@pfrproc1 soft]$ mkdir modbus |
| 302 | [epics@pfrproc1 soft]$ cd modbus/ |
| 303 | [epics@pfrproc1 modbus]$ wget https://github.com/epics-modules/modbus/archive/R2-10-1.tar.gz |
| 304 | [epics@pfrproc1 modbus]$ tar zxvf R2-10-1.tar.gz |
| 305 | [epics@pfrproc1 modbus]$ mv modbus-R2-10-1 2-10-1 |
| 306 | [epics@pfrproc1 modbus]$ cd 2-10-1 |
| 307 | [epics@pfrproc1 2-10-1]$ emacs -nw configure/RELEASE |
| 308 | |
| 309 | #SUPPORT=/corvette/home/epics/devel |
| 310 | #-include $(TOP)/../configure/SUPPORT.$(EPICS_HOST_ARCH) |
| 311 | |
| 312 | #ASYN=$(SUPPORT)/asyn-4-31 |
| 313 | ASYN=$(EPICS_BASE)/../modules/soft/asyn/4-31/ |
| 314 | |
| 315 | #EPICS_BASE=/corvette/usr/local/epics-devel/base-3.15.5 |
| 316 | EPICS_BASE=/pf/epics/R315.5/base |
| 317 | |
| 318 | [epics@pfrproc1 2-10-1]$ make |
| 319 | }}} |
| 320 | |
| 321 | 次にiocを作成した。[[br]] |
| 322 | modbusはasynPortDriverを使うようなので、asynも有効にする。 |
| 323 | |
| 324 | {{{ |
| 325 | [michkawa@pfrproc6 ~]$ mkdir -p epics/modbus/pfarthrm/ |
| 326 | [michkawa@pfrproc6 ~]$ cd epics/modbus/pfarthrm/ |
| 327 | [michkawa@pfrproc6 pfarthrm]$ makeBaseApp.pl -t pfModules pfarthrm |
| 328 | [michkawa@pfrproc6 pfarthrm]$ makeBaseApp.pl -i -t pfModules pfarthrm |
| 329 | [michkawa@pfrproc6 pfarthrm]$ emacs -nw configure/RELEASE |
| 330 | |
| 331 | ASYN = $(EPICS_BASE)/../modules/soft/asyn/4-31 |
| 332 | #STREAM = $(EPICS_BASE)/../modules/soft/stream/2-7-7 |
| 333 | MODBUS = $(EPICS_BASE)/../modules/soft/modbus/2-10-1 |
| 334 | |
| 335 | EPICS_BASE = /pf/epics/R315.5/base |
| 336 | }}} |
| 337 | |
| 338 | src/Makefileには、 |
| 339 | |
| 340 | {{{ |
| 341 | ifneq ($(MODBUS),) |
| 342 | pfarthrm_DBD += modbusSupport.dbd |
| 343 | pfarthrm_LIBS += modbus |
| 344 | endif |
| 345 | }}} |
| 346 | |
| 347 | を追加して、asynで必要なdriverを設定する。 |
| 348 | 今回は{{{IPPort}}}ドライバなので、 |
| 349 | |
| 350 | {{{ |
| 351 | pfarthrm_DBD += drvAsynIPPort.dbd # IP Port Driver |
| 352 | }}} |
| 353 | を設定。 |
| 354 | |
| 355 | dbファイルは、普通のasynPortDriverの書き方。 |
| 356 | |
| 357 | {{{ |
| 358 | record(ai, "$(R)") { |
| 359 | field(DTYP, "asynFloat64") |
| 360 | field(INP, "@asyn($(PORT) $(OFFSET))$(TYPE)") |
| 361 | field(SCAN, "1 second") |
| 362 | field(FLNK, "$(FLNK)") |
| 363 | } |
| 364 | }}} |
| 365 | |
| 366 | ややこしいのがst.cmdの書き方で、{{{drvModbusAsynConfigure}}}を使って、アクセスするレジスタや範囲、型を指定する方法らしい。 |
| 367 | |
| 368 | [https://cars9.uchicago.edu/software/epics/modbusDoc.html#Creating_a_modbus_port_driver Creating a modbus port driver] |
| 369 | |
| 370 | 更に話がややこしいのが、GM用のmodbusレジスタの設定。 |
| 371 | |
| 372 | [https://web-material3.yokogawa.com/IM04L55B01-01JA.pdf?_ga=2.35954336.1696056082.1563237256-1465924258.1537346367 データアクイジションシステム GM ユーザーズマニュアル ] |
| 373 | |
| 374 | マニュアルを見れば一応書いてはあるが、マニュアル中のレジスタマップにあるレジスタ番号をそのまま使うのではなく、レジスタマップの一番最初の数値をオフセットとして引いた値をアドレスとして使用する必要がある。[[br]] |
| 375 | 始めは、レジスタ値をそのまま書いていたが、アドレス設定が16bit分しかないのに何でマニュアルのアドレス値がそれをオーバーしているのかが不思議だった。結局マニュアルをしっかり読めということだ。[[br]] |
| 376 | |
| 377 | この2つの設定のどことどこが対応するかを理解するまでが苦労した。[[br]] |
| 378 | |
| 379 | 実際の例として、今回の構成で各モジュールへのレジスタへアクセスするには、以下の様に設定する。 |
| 380 | |
| 381 | |
| 382 | || slot || 1 || 2 || 3 || 4 || 5 || 6 || 7 || |
| 383 | || Main || CPU || DO || AI || AI || AI || AI || EXT || |
| 384 | || Sub1 || EXT || AI || AI || AI || AI || AI || EXT || |
| 385 | || Sub2 || EXT || AI || AI || AI || AI || AI || - || |
| 386 | |
| 387 | mainの3番モジュール(AI) |
| 388 | |
| 389 | * db(template) |
| 390 | {{{ |
| 391 | record(ai, "$(R)") { |
| 392 | field(DTYP, "asynFloat64") |
| 393 | field(INP, "@asyn($(PORT) $(OFFSET))$(TYPE)") |
| 394 | field(SCAN, "1 second") |
| 395 | field(FLNK, "$(FLNK)") |
| 396 | } |
| 397 | }}} |
| 398 | |
| 399 | * db(substitutions) |
| 400 | {{{ |
| 401 | file "db/Ykgw_GM_ai.template" { |
| 402 | pattern { R, PORT, OFFSET, TYPE, FLNK } |
| 403 | {"RFA:ARE:GM90:0101", "GM_E1_A1_2", 0, "FLOAT32_LE", "RFA:ARE:GM90:CAV1:WTMPIN"} |
| 404 | {"RFA:ARE:GM90:0102", "GM_E1_A1_2", 2, "FLOAT32_LE", "RFA:ARE:GM90:CAV1:WTMPO"} |
| 405 | {"RFA:ARE:GM90:0103", "GM_E1_A1_2", 4, "FLOAT32_LE", "RFA:ARE:GM90:CAV1:CTMP"} |
| 406 | {"RFA:ARE:GM90:0104", "GM_E1_A1_2", 6, "FLOAT32_LE", "RFA:ARE:GM90:MASK_SIC:WTMPIN"} |
| 407 | {"RFA:ARE:GM90:0105", "GM_E1_A1_2", 8, "FLOAT32_LE", "RFA:ARE:GM90:MASK_SIC:WTMPO"} |
| 408 | {"RFA:ARE:GM90:0106", "GM_E1_A1_2", 10, "FLOAT32_LE", "RFA:ARE:GM90:MASK:WTMPO"} |
| 409 | {"RFA:ARE:GM90:0107", "GM_E1_A1_2", 12, "FLOAT32_LE", "RFA:ARE:GM90:CAV2:WTMPIN"} |
| 410 | {"RFA:ARE:GM90:0108", "GM_E1_A1_2", 14, "FLOAT32_LE", "RFA:ARE:GM90:CAV2:WTMPO"} |
| 411 | {"RFA:ARE:GM90:0109", "GM_E1_A1_2", 16, "FLOAT32_LE", "RFA:ARE:GM90:CAV2:CTMP"} |
| 412 | {"RFA:ARE:GM90:0110", "GM_E1_A1_2", 18, "FLOAT32_LE", ""} |
| 413 | : |
| 414 | }}} |
| 415 | |
| 416 | * st.cmd |
| 417 | {{{ |
| 418 | drvAsynIPPortConfigure ("$(DEV)", "172.28.14.101:502") |
| 419 | modbusInterposeConfig("$(DEV)", 0, 1000,0) |
| 420 | drvModbusAsynConfigure("GM_E1_A1_2", "$(DEV)", 1, 4, 1100, 20, 7, 1000, "GM_E1") |
| 421 | }}} |
| 422 | |
| 423 | この設定で必要なのは、 |
| 424 | * {{{drvModbusAsynConfigure}}}の4番目の引き数{{{4}}}を、マニュアルのファンクションコードに合わせること |
| 425 | [[Image(GM_function_table.png,400)]] |
| 426 | * {{{drvModbusAsynConfigure}}}の5番目の引き数{{{1100}}}は、レジスタマップを参照することになるが、今回例示するモジュールのレジスタは、下図の{{{チャネル0101のデータの下位ワード - 0x400001}}}なので、{{{1100}}}を設定する |
| 427 | |
| 428 | [[Image(GM_modbus_addr_table.png,400)]] |
| 429 | * modbusのデータは16bit単位なので、連続するアドレスにアクセスして32bit浮動小数点に分解する場合には2bitずつoffsetを設定し、アクセスするデータ長も2倍で設定する。({{{drvModbusAsynConfigure}}}の6番目の引き数{{{20}}}) |
| 430 | * {{{drvModbusAsynConfigure}}}の7番目の引き数{{{7}}}は、modbus device support の{{{FLOAT32_LE}}}を表していて、DBファイルのINPフィールドの{{{$(TYPE)}}}の部分と合わせる必要がある。 |