2016-08-15

LabVIEW における VI の実行状態

LabVIEW でプログラムを作っている仮定で、VI の実行状態に関して困ったり調べたりしたのでメモしておく。

VI というのは、大雑把に言うとユーザー定義の関数である。名前空間的なものを含めて、すべての VI は必ずユニークな名前がある。 GetVoltage.vi とか。

で、プログラム実行中に、VI名を指定して、そのVIの実行状態を知ることができる。状態は、4つで、 「Bad」「Idle」「Run on Top Level」「Running」だ。

Bad は、実行できない状態である。通常、開発システムで編集なので、メモリ上に載っているけれど、コンパイルが通らない状態だ。

Idle は、コンパイルが通るが、実行されていない。

開発ツールのVIウィンドウの実行ボタンをクリックして実行したり、実行形式にビルドしてあって最初に実行されるVIである場合、Run on Top Level という状態になる。main() 関数が最初に動いているみたいな状態だ。

で、Running という名前が直感に反する。VI は、任意の VI の中に配置すると、サブルーチン呼び出してきに呼び出せる。ユーザー定義の関数だから、当然、そういう使い方をする。仮に、Main.vi の中に、Sub.vi を配置しているとしよう。

Main.vi を実行すると、Main.viは「Run on Top Level」状態になる。このとき、Sub.vi の処理自体が実行されている状態でなくても「Running」になる。Main.vi によってメモリ上にロードされて、Main.vi から実行依頼(正確には、メッセージがパス)されているのを待っているときでも、Running になる。

だが罠がある。

デフォルトでは VI は再入可能ではない。Main.vi が Sub.vi を呼び出している間は、他のところから Sub.vi を呼び出せない。実行中の処理が終了するまで、メッセージを渡すのを待つ。

けれど、オプションで再入可能にできる。そしてこの場合は、呼び出しごとにメモリ領域が確保され、「Sub.vi:1」「Sub:vi:2」という風にVI名が識別される。ところが、メモリー上に Sub.vi:1 とかのリストを取得する手段がない。どういうことだよ。なので動いてたら殺すみたいなのをするのに、やたら苦労する。


2016-08-09

久しぶりに LabVIEW で並行処理コードをかく

久しぶりに LabVIEW を使って、コードを書いている。UIフレームワーク+信号処理ライブラリ+ビジュアルプログラミング言語のIDE というところでしょうか。

National Instruments 製のハードウェア(電圧入力とか、CAN入出力とか、カメラによる画像入出力とかのデバイス)を使うなら、ドライバーとUIで全力で手抜きできる。Init、Start、Read、Stop するためのアイコンを置いて、Read の戻り値をUIコンポーネントに接続するだけでいい。

あと、実行単位が静的に決まっているときの並行処理コードも楽ちんである。



基本的に、左のほうのアイコンから、右のほうのアイコンに、データが伝搬されていく。四角く囲んであるのは、Whileループで、条件が成立するまで繰り返し実行される。

で、上と下の While ループどうしは依存関係がないので、なんとなく並行処理するようになる。両方のループが完了すると、右のほうにワイヤーが集約されたところで join されてめでたく終了する。便利だ。

便利なんだけど、あまりに久しぶりなので、細かいことを忘れていたり、他のプログラミング言語でできたことをうまくLabVIEWの考え方にマッピングできなくて、時間がかかっている。知り合いのトイプー使いが「プログラミングはスポーツみたいなもんで、すっと体が動くようになるといいね」みたいなことを言っていて、まさにそのとおりだと感じている。

2016-08-06

Garmin ConnectIQ ウィジェットを作った雑感

Garmin の ConnectIQ 対応 GPS ウォッチのウィジェットを作った。 リオの時刻が分かるという単純なもの

2つのタイムゾーンで時刻表示するだけなら、そういうウィジェットがあるんだけれど、これは、「リオの時刻を指定して、現在地の時刻を表示」ができる。国際映像とかを見ていて、リオの◯日◯時に次の試合がある、とか言われたときに、こっちでいつのなのかを知りたいであろう。

逆に「現在地の時刻を指定して、リオの時刻を表示」ができる。これは、土曜の午後7時にスポーツバーで集合することになったはいいが、その時間に競技やってんのか? リオでは何時だっけ?というのを知るときに使う。ちなみに日本で午後7時は、リオの午前7 時なので、試合のライブはないであろう。マラソンでさえ、9時半スタートである。

Connect IQ のウィジェットというのは、時刻表示モードのときに、ワンアクションで簡易的に表示/操作ができるアプリだ。たとえば天気だとか、スマホの通知とか、カレンダーとか、そういうのを見るのに使う。複数タイムゾーン時計のウィジェットも存在する。

今回作った、RIO Clock は「現在地/リオの時刻を指定する」という操作がある。で、このUIにちょっとだけ苦労した。

まず技術的には、picker クラスを継承することで、時刻を選択できる感じがあったのだけれど、挫折した。かなりプリミティブに描画を実装する必要があった。何がだるいかというと、機種ごとに画面サイズがばらばらなのだ。動的に計算できるんだけど、時刻を選択するだけなのに、やりすぎだろうと。

そんなわけで単純に、1時間単位で、次/前を操作していくことにした。したんだけど、もういっこやっかいなのが、操作イベントのとりかた。

何かを選択するときに、up/down ボタンを使う系の機種と、タッチパネルをスワイプする系の機種がある。物理的なイベントを検出してコールバックする InputDelegate というクラスがあって、これを使うと onUpButton とかを検出できる。けど全機種とかだるい。

BehaviorDelegate というクラスがあって、こっちはもっと抽象化されている。たとえば何かを選択するときには、up/down をしたときであれ、スワイプした時であれ onNextPage が呼び出される。onNextPage とかが標準的なUIに対応しているのであろう、と信じて、これを使うことにした。

ただ、上下で選択なのか、左右で選択なのかは、機種ごとに違うので表示がことなる。まあしょうがない。画面サイズも違うので、機種ごとに表示位置を定義するXMLを書いた。