SimpleGXC
三菱電機 MELSEC PLC 開発環境 GX Works に於けるシミュレータ機能(GX2: GX Simulator2, GX3: GX Simulator3) の起動中に,
その仮想PLCデバイスに対して VC++, .NET (C#, VB.NET) 言語から値を読書きするための関数を実装したライブラリを作成した。
MX Component がなくても実行できます ( Clean な PC に GXWorks だけ install したのち動作確認した)
最終更新:2025-09-03 SimpleGXC_1.1_0903_User(ver. 1.1 更新履歴)
機能(関数)
関数は VC++, .NET 共, 同一であり, 引数等は 本家のを模倣してゐる。ただし 数値データの型は必要最低の unsigned short 型 (typedef as QWORD) にしてゐる。
いかに関数を列挙する。
- ランダム書込(WriteDeviceRandom) ※イ
- ランダム読込(ReadDeviceRandom) ※イ
- 一括書込(WriteDeviceBlock) ※イ
- 一括読込(ReadDeviceBlock) ※イ
- 1点デバイス書込み (SetDevice) ※イ
- 1点デバイス読込 (GetDevice) ※イ
- インテリユニットデバイス一括書き込み (WriteBuffer)
- インテリユニットデバイス一括読み込み(ReadBuffer)
ランダム読書にかんしては 本家同様, デバイス群を \n(区切り文字) でを連結することで指定することもできるし,
デバイス群を格納した文字配列(文字列) の配列を渡すことで指定することもできる。
なお、※イ は, インテリユニットデバイス (U*\G*) も指定できることを示しています(仮想PLCのインテリにアクセスする需要はあまりないと思いますが)。
サポートしているデバイス
D, M, X, Y, L, B, W, TS, TC, TN, CS, CC, CN, Z, V, ZR, R, F、およびインテリユニットデバイス。
なお, TS は タイマ接点(いわゆる T), TC はタイマコイル, TN はタイマ現在値である。カウンタもまたしかり。
サポートしている仮想のPLC( Works で設定したCPUのこと)
- Q(GX Sim2) :モーション・ロボットCPU, BASIC・C言語コントローラなど一部の特殊製品を除く、多くの CPU (分類が多いため割愛)
- R (GX Sim3) : Rn*(無印), Rn*EN (CCLinkIE内蔵) , Rn*P(計装CPU) , Rn* PSF(SIL2 機能 二重化対応 計装CPU), Rn*SF(安全CPU)
+ ただし, FX5U (GX Sim3) はv1.1 の時点では非対応です。
+ マルチCPU構成の場合も、 v1.1 の時点では非対応です。
+ (GX Works 3 において) システムNo が標準1 ではない場合においても非対応です。
読込の場合は参照渡し
MX Component 同様, 読み込みの関数において取得データは参照渡しの箱に格納される。
ステータス
いづれの関数も 引数は配列、戻り値intには最後に発生したエラーについて格納しており、オープン・クローズぞこない、タイムアウトなどの定数は列挙体(enumErrorCode) がある。
メモリ消費量
数万回実行で、数MB上昇
速度
数十ミリ秒~数百ミリ秒 (パソコンによる)
動作確認PC
新規インストールした Windows 11 パソコンに, 体験版 GXWorks2, GX Works3 をインストールし動作確認した。
つまり、 開発環境 GX Works2, 3 の製品差(シリアルナンバー)に依存しないことがわかりました。
もちろん Windows 10 でも動作したのを確認した。 Windows 7 でも動作するはず。
ただし, VC++:Visual Studio C++ 2015 以上の Runtime のインストールが必要(すでにインストールされている場合もあります)
DL
SimpleGXC_1.1_0903_User(v1.1, 2025-0903)
VC++ Lib, .h および C++/CLI DLL (.NET用), それらを用いたサンプルプロジェクトを同梱してゐる。
DLLの動作環境
VC++:Visual Studio C++ 2015 再頒布 (直リンクx64)
サンプルアプリの動作環境
.NET8 : (直リンクx64 )
サンプルアプリでは .NET8 を使っているが, .NET 4 のアプリでも利用できます。
利用規定
本製品は、GX Works2 , GX Works3 の利用規定 からすると, あまりよろしくありません。
したがって, これを利用したアプリは, あくまでも研究・趣味用とのみでの限定になります。
使い方(共通)
VC++ アプリなら、 ヘッダファイル, lib をインクルードしコンパイル。
C# , VB.NET アプリなら, DLL を参照しコンパイル。実行と同じフォルダに DLL, lib を設置しておく。
サンプルコード(VC++の場合)
state = ins1->WriteDeviceRandom(dev, 1000, Senddat);
state = ins1->ReadDeviceRandom(dev, 1000, Rcvdat);
if (isConsole && state == (byte)enumErrorCode::NothingErr) for (int j = 0; j < 1000; j++)printf("%04x ", Rcvdat[j]); if (isConsole)printf("\n\n Random dev[] \n\n\n"); Sleep(TIMEMSEC); state = ins1->WriteDeviceRandom(dev_, 1000, Senddat);
state = ins1->ReadDeviceRandom(dev_, 1000, Rcvdat);
if (isConsole && state == (byte)enumErrorCode::NothingErr) for (int j = 0; j < 1000; j++)printf("%04x ", Rcvdat[j]); if (isConsole)printf("\n\n Random dev*[] \n\n\n"); Sleep(TIMEMSEC); state = ins1->WriteDeviceBlock("D3001", 1000, Senddat);
state = ins1->ReadDeviceBlock("D3001", 1000, Rcvdat);
if (isConsole && state == (byte)enumErrorCode::NothingErr) for (int j = 0; j < 1000; j++)printf("%04x ", Rcvdat[j]); if (isConsole)printf("\n\n Block dev[] \n\n\n"); Sleep(TIMEMSEC); state = ins1->SetDevice("D4001", Senddat[0]);
state = ins1->GetDevice("D4001", Rcvdat[0]);
if (isConsole && state == (byte)enumErrorCode::NothingErr) for (int j = 0; j < 1000; j++)printf("%04x ", Rcvdat[j]); if (isConsole)printf("\n\n One Device dev[] \n\n\n"); Sleep(TIMEMSEC); state = ins1->WriteBuffer(0, 10, 1200, Senddat);
state = ins1->ReadBuffer(0, 10, 1200, Rcvdat);
if (isConsole && state == (byte)enumErrorCode::NothingErr) for (int j = 0; j < 1000; j++)printf("%04x ", Rcvdat[j]);
if (isConsole)printf("\n\n Buffer dev[] \n\n\n");
Sleep(TIMEMSEC);
サンプルコード(C#の場合)
state = ins1.WriteDeviceRandom(dev, 1000, Senddat);
state = ins1.ReadDeviceRandom(dev, 1000, ref Rcvdat);
if (isConsole && state == (byte)enumErrorCode.NothingErr) for (int j = 0; j < 1000; j++) Console.Write("{1:X} ", j, Rcvdat[j]);
if(isConsole)Console.WriteLine("\n\n Random dev[] \n\n\n");
Thread.Sleep(TIMESEC);
state = ins1.WriteDeviceRandom(dev_, 1000, Senddat);
state = ins1.ReadDeviceRandom(dev_, 1000, ref Rcvdat);
if (isConsole && state == (byte)enumErrorCode.NothingErr) for (int j = 0; j < 1000; j++) Console.Write("{1:X} ", j, Rcvdat[j]);
if(isConsole)Console.WriteLine("\n\n Random dev* \n\n\n");
Thread.Sleep(TIMESEC);
state = ins1.WriteDeviceBlock("D3001", 1000, Senddat);
state = ins1.ReadDeviceBlock("D3001", 1000, ref Rcvdat);
if (isConsole && state == (byte)enumErrorCode.NothingErr) for (int j = 0; j < 1000; j++) Console.Write("{1:X} ", j, Rcvdat[j]);
if(isConsole)Console.WriteLine("\n\n Block \n\n\n");
Thread.Sleep(TIMESEC);
state = ins1.SetDevice("D4001", Senddat[0]);
state = ins1.GetDevice("D4001", ref Rcvdat[0]);
if (isConsole && state == (byte)enumErrorCode.NothingErr) for (int j = 0; j < 1; j++) Console.Write("{1:X} ", j, Rcvdat[j]);
if(isConsole) Console.WriteLine("\n\n Get \n\n\n");
Thread.Sleep(TIMESEC);
state = ins1.WriteBuffer(0, 10, 1200, Senddat);
state = ins1.ReadBuffer(0, 10, 1200, ref Rcvdat);
if (isConsole && state == (byte)enumErrorCode.NothingErr) for (int j = 0; j < 1000; j++) Console.Write("{1:X} ", j, Rcvdat[j]);
if (isConsole) Console.WriteLine("\n\n Buffer \n\n\n");
Thread.Sleep(TIMESEC);
更新履歴
ver 1.1 (2025.0903)
<add> インテリユニットデバイスへのアクセスをサポートした。
(WriteBuffer, ReadBuffer を用いるか, または “U*\G* 型式指定での Random, Block の実行より可)
<fix> 以下
・ GX Sim3 において設定したCPUの種類によっては動作しない不具合があったので修正(ただしv1.1 時点では FX5Uのシミュレーション は非対応です)。
・Random 読み書きにおいて、あらゆる種類のデバイスを組み合わせた場合発生する不具合について修正
ver 1.0 (2025.0808)
new