SCPIによる測定器の自動化

[ネットワーク自動化 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/network-automation) 12/17分のエントリー

# モチベーション

測定器を用いたネットワーク機器のパフォーマンス計測や状態計測(光量計測 など)は
決められた計測メニューを繰り返し実施する事が多く、その都度に設定するのは非効率となる。

また、一定のインターバルを設定した長期間計測やパラメーターを変えながらの繰り返し計測を実施する場合
測定器によっては、計測メニュー 等でフレキシブルに対応する事が出来ない。

上記の問題点を解消する為に測定器をプログラマブルに制御し、自動化したい。

# SCPI

SCPI(Standard Commands for Programmable Instruments)は
測定器の統一的な制御を目的としたコマンド群となる。

SCPIはGPIB(※) 等で知られるIEEE 488規格の中で産まれたコマンド群である為
元々はGPIB通信 などで使用されてきたが
現在ではTCP/IP通信、シリアル通信、USB通信 等にも対応している。
※当時のHP（HP -> Agilent -> Keysight）が測定器とPC等を接続し制御する為に開発したHPIBという規格が
　他社でも広く採用されたもの（後にIEEE 488 として標準化された）

GPIBは測定器インターフェースのデファクトスタンダード的な役割を持っていたものの
GPIBケーブル、コネクタのサイズの大きさや接続数制限、ケーブル長制限といった問題を抱えていた。
様々なインターフェースに対応した事で
PCと測定器を接続する際にPC側にGPIBインターフェースを持つ必要は無くなった。

SCPIはIEEE 488.2で定義された共通コマンドと各測定器に固有なサブシステムコマンドの2種類に大別される。
どちらのコマンドも値を設定する場合はコマンドに続いてパラメーターを指定し
値を参照したい場合はコマンドの最後に?（クエスチョンマーク） を付与する。

■ 共通コマンド
　先頭が＊（アスタリスク）でその後、3文字が続く

　*XXX

　例）製品名を確認する
　　*IDN?
　　→　VIAVI Solutions,MTS 6000A V2,00001,ISU,18.00

■ サブシステムコマンド
　階層構造を持ち、階層間のキーワードを：（コロン）で区切る

　SYSTem:
　　　　　　DATe
　　　　　　TIMe
　　　　　　SCReen

　例）システムの日付を設定する、日付を確認する
　　SYSTem:DATe 2020,01,01
　　SYSTem:DATe?
　　→　2020,01,01

SCPIの利用形態としては様々あり、以下がその1部の例となる。

![interface.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153663/d367adb1-c82b-830e-8d9d-ff6f904fa477.png)

VISA（Virtual Instrument Software Architecture）とはSCPI環境で使用されるライブラリであり
インターフェース（RJ45、RS-232、USB、GPIB）の違いを吸収し、統一的な環境を提供する。
　Python だとPyVISA という実装がある

ただ、今回はVISAライブラリを利用せずに最も汎用的に使える RAW SOCKETを利用する事とする。
　上図だと1番下の例


# 検証目的と環境

### 検証目的

光スペクトラムアナライザー（OSA）を用いて、WDM装置からの光信号を10分間隔で1日間計測する。
　OSAの種類によっては、インターバル時間と計測期間を指定できるものもあるが本検証対象は非対応


### 検証環境

端末：CentOS 7.2、Python 2.7.5
測定器：VIAVI Solutions MTS 6000A V2（本体） + I-PMD（OSAモジュール）

端末と測定器をUTPケーブルで接続し、測定器と計測対象である伝送装置を光ケーブルで接続する。

![env1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153663/e62be5f7-a30c-0f4f-1115-b253822642ae.png)

伝送装置のコンポーネントであるMux/Demux や ROADMにはMonitor Portと呼ばれるポートがある事が多く
伝送装置が伝送している光信号をモニタリングする事が出来る。
これを利用する事でプロダクション環境であってもin-serviceで光信号の計測が可能となる。

# 検証コード

■ 実際に手動で計測する手順

前提
　計測には前もって設定してある計測メニューを使用

計測
　測定器のハードキー「START」を押下して計測を開始

計測結果のファイル保存
　測定器のハードキー「FILE」を押下
　その後、測定器のソフトキー「Store」→「Save」→「Enter」→「Exit」を押下

ハードキー
　測定器に搭載されている物理的なキー
![hardkey_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153663/246dcfb3-082f-5faf-b378-29c5519a22fa.png)

ソフトキー
　測定器の画面上に表示されるソフトウェア的に再現されたキー
　画面によりキーの内容が変わる
![softkey_all.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153663/cfcd92d1-de35-52ac-7388-44fee8d12058.png)


■ コード

上記のオペレーションを以下の通りにコードで表現

```python
import socket
import time

ip = '192.168.0.100'
port = 8000
status = ''

# TCPソケットを生成し測定器に接続
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect((ip, port))

# リモート制御をする場合は最初に*REMコマンドを実行し、Programmed Mode に変更
# コマンドの最後に改行コードを挿入（VISAライブラリを利用している場合は考慮不要）
s1.send('*REM\n')

# 測定器本体への接続（Port 8000）とは別にOSAモジュールへの接続が必要
# MOD:FUNC:PORT?コマンドでOSAモジュールへの接続Portを確認（default Port 8002）
# コマンドパラメーターとして、モジュール搭載位置(pwrside,slic1)とモジュール名(I-PMDモジュール＝"PIB") を指定
s1.send('MOD:FUNC:PORT?pwrside,slic1,"PIB"\n')
port = int(s1.recv(1024))

# OSAモジュールへ接続
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.connect((ip, port))
s2.send('*REM\n')


# 計測を1日間(600秒 x 144回) 実行
for i in range(144):
    # ハードキー：START を押下
    s1.send('KEY START\n')
    time.sleep(5)

    # 計測に数秒を要する為、OSAモジュールの状態を監視
    while 'STOPPED' not in status:
        # OSAモジュールの現ステータスを確認
        s2.send('STATus:ACQ?\n')
        status = s2.recv(1024)
        time.sleep(1)

    # ハードキー：FILE を押下
    s1.send('KEY FILE\n')
    time.sleep(5)

    # ソフトキー：SK1 = Store を押下
    s2.send('KEY SK1\n')
    time.sleep(5)

    # ソフトキー：SK2 = Save を押下
    s2.send('KEY SK2\n')
    time.sleep(5)

    # ソフトキー：SK7 = Enter を押下
    s2.send('KEY SK7\n')
    time.sleep(5)

    # ソフトキー：SK7 = Exit を押下
    s2.send('KEY SK7\n')

    time.sleep(575)

s2.close()
s1.close()
```


■ 補足

SCPI用Port
　下記コマンドからも分かるように、IANAの割当はPort 5025 となっているが
　今回の対象測定器はPort 8000 となる。

```bash
# whatportis 5025
+----------+------+----------+-------------+
| Name     | Port | Protocol | Description |
+----------+------+----------+-------------+
| scpi-raw | 5025 | tcp, udp | SCPI-RAW    |
+----------+------+----------+-------------+
```

キー入力間のsleep処理
　本来であれば、共通コマンドの*WAIコマンドを使い
　実行コマンドの終了を確認後に次の処理へ移るが
　今回の対象測定器では実装が確認出来なかった為、time.sleepを利用した。
　計測のインターバルにそれ程の精度は求めていない為、許容する。

計測結果のファイル保存
　ファイル名は事前の設定により、任意の文字列+数字の連番 となっている為
　自動でユニークなファイル名となる。


以上、かなり原始的なプログラミングとはなるが
その分、手動オペレーションとのイメージの乖離がない自動計測を可能とした。


# まとめ

SCPIを使用する事で主にフィールドワークで活躍していた測定器を
リモートから制御する事が可能となった。

汎用サーバー、CPUで様々な事が代替できるようになっているものの
正確な値の計測、光特性の計測等 特化した用途では専用測定器の使いどころが
まだまだあり、この分野への自動化による効率化も必要と考える。

今回の検証のように計測結果をデータとして保持する事で
計測データをサーバーへ転送、パース、時系列DB登録 とする事による可視化や
計測作業のコード化 をする事でCI/CDに組み込む事も容易となった。

また、ここまではまだ試せていないが
測定器と計測対象の間にプログラマブルなL1スイッチなどを設置し
計測対象を切り替えられるようになると、テストの性質によってはInsertion Lossに
注意が必要となるものの、活用範囲が広がると思われる。