【備忘録】socketで測定器からバイナリデータを取得するときのトラブル解決
背景
NIやKeysightのVISAツールの容量が大きくインストールに時間がかかるためそれらを用いずソケット通信で測定器の遠隔操作をしているが、測定器のローカルファイルを転送させるコマンド(:MMEM:DATA? など)でバイナリデータを取得してそれをそのままファイルとして書き込むと壊れたファイルになってしまう問題があり(※)、どうしたら正常なファイルとして保存することができるのかを調べた。
※ VISAライブラリのバイナリqueryだと正常に転送できる
原因と解決
共有フォルダ機能を使って測定器からコピーしてきたオリジナルのファイルとソケット通信で受信したバイナリデータを比較してみたところ、ソケットの受信データは元々のファイルのバイナリの頭に数バイトのデータが追加された形になっていることが分かった。
ソケット受信データ = 謎のバイト列 + ファイルデータ
このことを手掛かりに通信の規格などを調べてみると以下のサイトがヒットした。
ページ内にリンクが張られているアプリケーションノートを確認すると、IEEE 488.2で1GB未満のバイナリデータの送信の規格が以下のように決められていることが分かる。
データの先頭:「#」
2バイト目:「「データ長」の長さ」
3バイト目~:送信するデータ長
データ長のバイト以降:ファイルのデータ
続いて250kBのデータを送信する場合の例が記されている。
['#', '6', '2', '5', '0', '0', '0', '0', ...(以降はファイルのデータ)]
ここで注意すべきは、「「データ長」の長さ」も「データ長」も、文字列として送信されるという点だ。例えば上記例での2バイト目は'6'=0x36だが、データ長のサイズは54バイトではなく6バイトである。データ長の方も、250kB=250000Bを文字列として送信している。
上記のことを踏まえ、受信データの2バイト目をデコードし、2+(2バイト目の値)バイト目以降のデータをファイルに書き込むことで正常なファイルを得ることができた。
補足
ソケットでスクリーンショットなど数百kBのデータを受信するとなると繰り返し文を用いる必要があり、受信データの正確なサイズが分からないと受信タイムアウトで判定するしかなくなるため測定効率が落ちる問題が生じる。上記の内容からデータサイズも把握することができるため、この問題も解決した。
1GB以上のファイルは「「データ長」の長さ」が0になるため対応がまた異なるが、現状1GB以上のファイルを遠隔操作コマンドで転送する予定はないため対策は考えていない。