04-27-2010 04:04 AM
お世話になります。
LabVIEW8.6.1を使用しております。
フロントパネルに三菱シーケンサにアクセスするためのMXComponentのActiveXコンテナを
配置して、インボークノードを使用して三菱シーケンサと通信を行っております。
添付図中央にあるIActEazyIF3/ReadDeviceBlockインボークノードのlplDataノードは
本来配列なのですが、LabVIEWがポインタの引数を単一のスカラ値と判断しているようで
図のように配列のワイヤになっていません。
ReadDeviceBlockはマニュアルには下記のように記載されています。
Visual C++
lRet = object.ReadDeviceBlock(szDevice, lSize, *lplData)
Long lRet 戻り値(Output)
CString szDevice デバイス名(Input)
Long lSize 読出し点数(Input)
Long *lplData 読み出したデバイス値(Output)
szDevice(varDevice)にて指定したデバイスから,lSize(varSize)分のデバイス値を一括して読み出します。
読み出したデバイス値は,lData(lplDataまたはlpvarData)に格納されます。
lData(lplDataまたはlpvarData)は,lSize(varSize)以上の配列を確保してください。
図のようにシーケンサのD100番地から2個データを取得してそれを配列に入れたいのですが、
LabVIEWでは出来ません。
Visual C++ では出来ました。
CとLabVIEWでは配列の型が違うことが分かっておりますが、LabVIEWで2個読み取る事は出来ないでしょうか?
現状対応としてはD100番地とD101番地それぞれReadDeviceBlockを2回実行して2個のデータを読み出していますが、
この方法ですとCでも同様ですが、あるアドレスに対して2バイト書き込みと1バイト読み出しが別々のスレッドで
行われると競合が発生し、タイミングによっては正しく読み取りが出来ません。
何か対処法がありましたら教えて下さい。
よろしくお願いします。
04-27-2010 09:14 AM
lplDataが (long *) なので、long の配列が格納されたデータ領域の「先頭アドレス(DWORD)」そのものが、
long値(I32) として返ってきている感じでしょうか。あたかも、(long)((long *)lplData) とキャストしたかのように・・・
ちょっと試してみていただきたいですが、添付のVIをサブviとしてダイアグラムに配置し、当該インボークノードにつないだ
lSize と同じものと、インボークノードの出力 lplData を接続すると、サブviからの出力の返り値 [I32] が所定の配列に
なりそうでしょうか。
添付のVIは、予め lSize の数だけ要素を持つ [I32] 配列を受け皿として用意し、そのデータ領域に、lplData が指す
メモリ領域の先頭から (lSize*4) バイトだけコピーします(kernel32.dll の RtlMoveMemory() を呼び出し)。
RtlMoveMemory() は本来2つのポインタを取りますが、第1引数に1次元配列データのポインタ、第2引数を I32 に
することで、lplData の中身(データの先頭アドレス)を渡しています。
もし、lplData が、本来の配列データの先頭アドレスを保持しているなら、これで [I32] へ持っていけるかなと。
なお、*lplData の long値データは little endian とみなされ、LabVIEW側で自動的に big endian に直して
格納してくれるようで、エンディアン変換の手間は要らないようです。
(逆に、元データが big endian だと、LabVIEWがひっくり返してしまうので自分で戻さないといけないかも)
※ lSize と lplData は必ず対応するものを接続して下さい。用意した受け皿の配列アドレスと大きさで
RtlMoveMemory() を呼び出しているので、バッファオーバーランや不正な上書きは起こらないと思いますが、
lplData が無関係な値を指していると、不正な memory read になるかも知れません。
(lSize が 0 でも大丈夫そうです。lplData が NULL のときはcaseで排除はしていますが・・)
04-27-2010 09:04 PM
M.Shiraishiさん
アドバイスありがとう御座います。
lplDataには三菱シーケンサD100番地の値(アドレスではなく)が戻りますので、(long)((long *)lplData)
のキャストでは無く *((long *)lplData) になります。
作成して頂いたviを添付図のように配線して試しました。
やはり、アドレスが返ってきている訳ではないので、100427-sample-subvi-1.viの結果は0が二つ
入っているだけです。
MXComponentのActiveXをラップするActiveXを自作することで対応出来そうですが、
ActiveXのコードを書いた経験が無いため、最小限の時間と労力で実現出来る方法を調べております。
ちなみにlplDataの値が0以外の値であっても、RtlMoveMemory()を使用しているLabVIEWが
クラッシュすることはありませんでした。
取り急ぎご報告させて頂きました。
今後ともよろしくお願いします。
04-27-2010 09:34 PM
h.seki 様
>lplDataには三菱シーケンサD100番地の値(アドレスではなく)が戻りますので、(long)((long *)lplData)
>のキャストでは無く *((long *)lplData) になります。
うーむ、なるほど、そうでしたか。
それって本当に、「lplData」ではなく「*((long *)lplData」、あるいは問題点を明示すると「((long *)lplData)[0]」が
返ってしまっているのですね。
(だとすると、元々のインボークノードの作られ方に大いに問題があるような・・・)
値(配列の第1要素)が返っているのだとすると、その値の格納されていたアドレスが分からない限り、その隣の
データを取ってくるのは難しそうですね・・・・・残念。。。
04-27-2010 11:12 PM
06-26-2013 02:06 AM
その後、どうなったか教えて下さい。
私も、同じで、データを1個ずつ呼んでいます
01-31-2024 07:36 PM