エラーだらけのVNA通信ルーチン。
ENAとの通信でどうしてもうまくいかない。
ブレークポイント入れると動くという気持ち悪い動作が治らない。
一説にはVS2012なら動くという噂もある。こういうのは嫌いだ。
追記。
KeysightのVBAのサンプルプログラムもSCPIバスを観察してると、
同じコマンド構成になってたが、正常に動いてた。
結局、実行速度が遅くないとE5071Cが反応できないという結論に至り、
コマンドごとにスリープを入れたら動きました。あほらしい。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Diagnostics; namespace IVICommunicator { public class VNATalker : IDisposable { private Ivi.Visa.Interop.ResourceManager RM; private Ivi.Visa.Interop.FormattedIO488 DMM; public string VesaAdress; public string IDN; public enum InstTyep { PNA, ENA, ZNB, SNP, Unkown }; private InstTyep InstrumentType; // Dispose したかどうか private bool _disposed = false; // IDisposable に必須のメソッドの実装 public void Dispose() { Dispose(true); // Dispose() によってリソースの解放を行ったので、 // GC での解放が必要が無いことを GC に通知します。 GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Dispose がまだ実行されていないときだけ実行 if (!_disposed) { if (DMM.IO != null) { DMM.IO.Close(); } // disposing が true の場合(Dispose() が実行された場合)は // マネージリソースも解放します。 if (disposing) { // マネージリソースの解放 IDN = null; VesaAdress = null; } // アンマネージリソースの解放 System.Runtime.InteropServices.Marshal.ReleaseComObject(DMM); System.Runtime.InteropServices.Marshal.ReleaseComObject(RM); DMM = null; RM = null; _disposed = true; } } // ファイナライザー(デストラクター) // // Dispose() が呼び出されていない場合のみ // 実行されます。 ~VNATalker() { Dispose(false); } private void CheckDisposed() { if (_disposed) throw new ObjectDisposedException(GetType().FullName); } public void SetInstrumentAdress(string strAdress) { if (strAdress == null) { VesaAdress = ""; } else { RM = new Ivi.Visa.Interop.ResourceManager(); DMM = new Ivi.Visa.Interop.FormattedIO488(); VesaAdress = strAdress; } } public string ConnectInstrument() { { try { int sysTimeOut = 2000; DMM.IO = (Ivi.Visa.Interop.IMessage)RM.Open(VesaAdress, Ivi.Visa.Interop.AccessMode.NO_LOCK, sysTimeOut); //都度通信終了メッセージを送る。(LowSecketの場合、ENDMessageが規格上送れないので、下の処理をする。) DMM.IO.SendEndEnabled = false; if (VesaAdress.IndexOf("SOCKET") >= 0) { //データの終端を示す文字は、ASCII の 10、ラインフィード <LF> DMM.IO.TerminationCharacter = 10; //ソケット接続時のみ、終端文字で読み取りを終了させる設定です。GPIB や USB、LAN(VXI-11 プロトコル)で接続する場合は、この設定は不要 DMM.IO.TerminationCharacterEnabled = true; } DMM.WriteString("*IDN?"); IDN = DMM.ReadString(); DMM.IO.Timeout = 30000; int TIMEOUT = DMM.IO.Timeout; if (IDN.IndexOf("E50") > 0) { InstrumentType = InstTyep.ENA; } else if (IDN.IndexOf("N52") > 0) { InstrumentType = InstTyep.PNA; } else if (IDN.IndexOf("ZNB") > 0) { InstrumentType = InstTyep.ZNB; } else { InstrumentType = InstTyep.Unkown; } if (InstrumentType == InstTyep.PNA) { //Sパラ保存形式を設定。 DMM.WriteString(":MMEM:STOR:TRAC:FORM:SNP DB"); } else if (InstrumentType == InstTyep.ENA) { //Sパラ保存形式を設定。 DMM.WriteString(":MMEM:STOR:SNP:FORM DB"); } return IDN; } catch (Exception ex) { return ex.Message; } } } public void DisConnectInstrument() { CheckDisposed(); DMM.IO.Close(); } public MemoryStream StoreSparaMater(int PortNum, int Chnnel) { string Chan = Chnnel.ToString(); MemoryStream ResSnP = null; if (InstrumentType == InstTyep.ENA) { ResSnP = StoreSparaMaterENA(PortNum, Chan); } else if (InstrumentType == InstTyep.PNA) { ResSnP = StoreSparaMaterPNA(PortNum, Chan); } else if (InstrumentType == InstTyep.ZNB) { ResSnP = StoreSparaMaterZNBZ50(PortNum, Chan); } else { ResSnP = null; } return ResSnP; } public MemoryStream StoreSparaMaterZNBSpecialImp(int PortNum, int Chnnel) { string Chan = Chnnel.ToString(); MemoryStream ResSnP = null; if (InstrumentType == InstTyep.ENA) { ResSnP = StoreSparaMaterENA(PortNum, Chan); } else if (InstrumentType == InstTyep.PNA) { ResSnP = StoreSparaMaterPNA(PortNum, Chan); } else if (InstrumentType == InstTyep.ZNB) { ResSnP = StoreSparaMaterZNBPortImp(PortNum, Chan); } else { ResSnP = null; } return ResSnP; } private MemoryStream StoreSparaMaterPNA(int PortNum, string Chan) { string readfile = @"'D:\pna_temp_data_s" + PortNum.ToString() + "p.s" + PortNum.ToString() + "p'"; string SelectedPort = "1"; for (int i = 1; i < PortNum; i++) { SelectedPort = SelectedPort + "," + ((int)(i + 1)).ToString(); } //Sパラを本体に保存 //DMM.WriteString(":MMEM:STOR " + readfile); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); DMM.WriteString(":CALC" + Chan + ":PAR:CAT:EXT?"); string DefinedCatalogs = DMM.ReadString(); string DefinedCatalog = DefinedCatalogs.Substring(0, DefinedCatalogs.IndexOf(",")); DefinedCatalog = DefinedCatalog.Substring(DefinedCatalog.IndexOf("CH"), DefinedCatalog.Length - DefinedCatalog.IndexOf("CH")); DMM.WriteString(":CALC" + Chan + ":PAR:SEL '" + DefinedCatalog + "'"); DMM.WriteString(":CALC" + Chan + ":DATA:SNP:PORT:Save '" + SelectedPort + "'," + readfile); //Keysight推奨の新しい形式 DMM.WriteString(":MMEM:TRAN? " + readfile); //ファイル転送 Byte[] SparaData = DMM.ReadIEEEBlock(Ivi.Visa.Interop.IEEEBinaryType.BinaryType_UI1); DMM.WriteString("*OPC?"); sts = DMM.ReadString(); //非同期でファイル削除命令発行 Task.Factory.StartNew(() => { DMM.WriteString(":MMEM:DEL " + readfile); }); DMM.WriteString("*OPC?"); sts = DMM.ReadString(); //バイトデータをメモリストリームに変換 MemoryStream Mst = new MemoryStream(SparaData); return Mst; } private MemoryStream StoreSparaMaterZNBZ50(int PortNum, string Chan) { string readfile = @"'temp_data_s" + PortNum.ToString() + "p.s" + PortNum.ToString() + "p'"; string SelectedPort = "1"; for (int i = 1; i < PortNum; i++) { SelectedPort = SelectedPort + "," + ((int)(i + 1)).ToString(); } //Sパラを本体に保存 //DMM.WriteString(":MMEM:STOR " + readfile); DMM.WriteString(":MMEM:STOR:TRAC:PORT " + Chan + ", " + readfile + ", LOGPhase, CIMPedance , " + SelectedPort); DMM.WriteString(":MMEM:DATA? " + readfile); //ファイル転送 Byte[] SparaData = DMM.ReadIEEEBlock(Ivi.Visa.Interop.IEEEBinaryType.BinaryType_UI1); DMM.WriteString("*OPC?"); int sts = (int)DMM.ReadNumber(); //非同期でファイル削除命令発行 Task.Factory.StartNew(() => { DMM.WriteString(":MMEM:DEL " + readfile); }); //バイトデータをメモリストリームに変換 MemoryStream Mst = new MemoryStream(SparaData); return Mst; } private MemoryStream StoreSparaMaterZNBPortImp(int PortNum, string Chan) { string readfile = @"'temp_data_s" + PortNum.ToString() + "p.s" + PortNum.ToString() + "p'"; string SelectedPort = "1"; for (int i = 1; i < PortNum; i++) { SelectedPort = SelectedPort + "," + ((int)(i + 1)).ToString(); } //Sパラを本体に保存 //DMM.WriteString(":MMEM:STOR " + readfile); DMM.WriteString(":MMEM:STOR:TRAC:PORT " + Chan + ", " + readfile + ", LOGPhase, PIMPedance , " + SelectedPort); DMM.WriteString(":MMEM:DATA? " + readfile); //ファイル転送 Byte[] SparaData = DMM.ReadIEEEBlock(Ivi.Visa.Interop.IEEEBinaryType.BinaryType_UI1); DMM.WriteString("*OPC?"); int sts = (int)DMM.ReadNumber(); //非同期でファイル削除命令発行 Task.Factory.StartNew(() => { DMM.WriteString(":MMEM:DEL " + readfile); }); //バイトデータをメモリストリームに変換 MemoryStream Mst = new MemoryStream(SparaData); return Mst; } private MemoryStream StoreSparaMaterENA(int PortNum, string Chan) { string readfile = @"D:\temp_dataS" + PortNum.ToString() + "P.s" + PortNum.ToString() + "p"; readfile = @"""" + readfile + @""""; string SelectedPort = "1"; for (int i = 1; i < PortNum; i++) { SelectedPort = SelectedPort + "," + ((int)(i + 1)).ToString(); } //Sパラを本体に保存 //DMM.WriteString(":MMEM:STOR " + readfile); DMM.WriteString(":DISP:WIND" + Chan + ":ACT",true); Trace.WriteLine(":DISP:WIND" + Chan + ":ACT"); DMM.WriteString(":MMEM:STOR:SNP:TYPE:S" + PortNum.ToString() + "P " + SelectedPort, true); Trace.WriteLine(":MMEM:STOR:SNP:TYPE:S" + PortNum.ToString() + "P " + SelectedPort); DMM.WriteString(":MMEM:STOR:SNP:DATA " + readfile, true); Trace.WriteLine(":MMEM:STOR:SNP:DATA " + readfile); DMM.FlushWrite(true); MemoryStream Mst = null; if (ErrorCheck()) { DMM.WriteString(":MMEM:TRAN? " + readfile, true); Trace.WriteLine(":MMEM:TRAN? " + readfile); //ファイル転送 Byte[] SparaData = DMM.ReadIEEEBlock(Ivi.Visa.Interop.IEEEBinaryType.BinaryType_UI1, false, true); DMM.WriteString("*OPC?",true); Trace.WriteLine("*OPC?"); int sts = (int)DMM.ReadNumber(); Trace.WriteLine("> " + sts.ToString()); DMM.WriteString(":MMEM:DEL " + readfile,false); Trace.WriteLine(":MMEM:DEL " + readfile); Mst = new MemoryStream(SparaData); } return Mst; } private bool ErrorCheck() { string sErr; string[] vErrNo; string sResponse; bool res = true; DMM.WriteString(":SYST:ERR?", true); Trace.WriteLine(":SYST:ERR?"); sErr = DMM.ReadString(); Trace.WriteLine("> " + sErr); vErrNo = sErr.Split(','); if(vErrNo[0] != "0") { res = false; sResponse = vErrNo[1]; foreach(string errstr in vErrNo) { Trace.WriteLine("err> "+ errstr); } } return res; } /// <summary> /// ポートエクステンションを有効化して、ポートエクステンション値を設定 /// </summary> /// <param name="psecArray"></param> /// <param name="ChanNo"></param> /// <returns></returns> public int SetPortExt(double[] psecArray, int ChanNo) { if (InstrumentType == InstTyep.ENA) { //ポートエクステンション on DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EXT ON"); for (int i = 1; i <= psecArray.Length; i++) { //DMM.WriteString(":SENS" + ChanNo.ToString() + ":PORT" + i.ToString() + ":ZREF 50, 0"); double psec = psecArray[i - 1] / (Math.Pow(10d, 12d)); string sec = psec.ToString("0.00000E0"); DMM.WriteString(":SENS" + ChanNo.ToString() + "CORR:EXT:PORT" + i.ToString() + ":TIME " + sec); } DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.PNA) { //ポートエクステンション on DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EXT ON"); for (int i = 1; i <= psecArray.Length; i++) { double psec = psecArray[i - 1] / (Math.Pow(10d, 12d)); string sec = psec.ToString("0.00000E0"); DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EXT:PORT" + i.ToString() + ":TIME " + sec); } DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.ZNB) { for (int i = 1; i <= psecArray.Length; i++) { double psec = psecArray[i - 1] / (Math.Pow(10d, 12d)); string sec = psec.ToString("0.00000E0"); DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EDEL" + i.ToString() + ":TIME " + sec); } DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else { return -1; } } public int LoadCalPNA(string CalfileName) { DMM.WriteString(":MMEM:LOAD '" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } public int LoadCalENA(string CalfileName) { DMM.WriteString(":MMEM:LOAD '" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } public int LoadCalZNB(string CalfileName) { DMM.WriteString("MMEM:LOAD:STAT 1,'" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } public int SaveCalPNA(string CalfileName) { DMM.WriteString(":MMEM:DEL '" + CalfileName + "'"); DMM.WriteString(":MMEM:STOR:CSAR '" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } public int SaveCalENA(string CalfileName) { DMM.WriteString(":MMEM:DEL '" + CalfileName + "'"); DMM.WriteString(":MMEM:STOR '" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } public int SaveCalZNB(string CalfileName) { DMM.WriteString(":MMEM:DEL '" + CalfileName + "'"); DMM.WriteString("MMEM:STOR:STAT 1,'" + CalfileName + "'"); DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } /// <summary> /// ネットアナに設定されているポートエクステンションを持ってくる。 /// </summary> /// <param name="ports"></param> /// <param name="ChanNo"></param> /// <returns></returns> public double[] GetPortExt(int ports, int ChanNo) { double[] Res = new double[ports]; if (InstrumentType == InstTyep.ENA) { for (int i = 1; i <= ports; i++) { DMM.WriteString(":SENS" + ChanNo.ToString() + "CORR:EXT:PORT" + i.ToString() + ":TIME?"); double sec = Convert.ToDouble(DMM.ReadNumber()); Res[i - 1] = sec * Math.Pow(10d, 12d); DMM.WriteString("*OPC?"); int sts = (int)DMM.ReadNumber(); } return Res; } else if (InstrumentType == InstTyep.PNA) { for (int i = 1; i <= ports; i++) { DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EXT:PORT" + i.ToString() + ":TIME?"); double sec = Convert.ToDouble(DMM.ReadNumber()); Res[i - 1] = sec * Math.Pow(10d, 12d); DMM.WriteString("*OPC?"); int sts = (int)DMM.ReadNumber(); } return Res; } else if (InstrumentType == InstTyep.ZNB) { for (int i = 1; i <= ports; i++) { DMM.WriteString(":SENS" + ChanNo.ToString() + ":CORR:EDEL" + i.ToString() + ":TIME?"); double sec = Convert.ToDouble(DMM.ReadNumber()); Res[i - 1] = sec * Math.Pow(10d, 12d); DMM.WriteString("*OPC?"); int sts = (int)DMM.ReadNumber(); } return Res; } else { for (int i = 1; i <= ports; i++) { Res[i - 1] = -1; } return Res; } } private string[] FixtureOnOff = new string[50]; private string[] PortZConvOnOff = new string[50]; private string[] MatchCirOnOff = new string[50]; public int PresrveFixtureState(int ChanNo) { if (InstrumentType == InstTyep.ENA) { //DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:STAT ON"); DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:STAT?"); string fsimonoff = DMM.ReadString(); if (fsimonoff.IndexOf("1") > -1) { FixtureOnOff[ChanNo - 1] = "1"; } else { FixtureOnOff[ChanNo - 1] = "0"; } DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT?"); //portmattcing string fsimMatchCir = DMM.ReadString(); if (fsimMatchCir.IndexOf("1") > -1) { MatchCirOnOff[ChanNo - 1] = "1"; } else { MatchCirOnOff[ChanNo - 1] = "0"; } DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT?"); //PortZCon string PortZComv = DMM.ReadString(); if (PortZComv.IndexOf("1") > -1) { PortZConvOnOff[ChanNo - 1] = "1"; } else { PortZConvOnOff[ChanNo - 1] = "0"; } DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.PNA) { DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:STAT?"); string fsimonoff = DMM.ReadString(); if (fsimonoff.IndexOf("1") > -1) { FixtureOnOff[ChanNo - 1] = "1"; } else { FixtureOnOff[ChanNo - 1] = "0"; } DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT?"); //portmattcing string fsimMatchCir = DMM.ReadString(); if (fsimMatchCir.IndexOf("1") > -1) { MatchCirOnOff[ChanNo - 1] = "1"; } else { MatchCirOnOff[ChanNo - 1] = "0"; } DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT?"); //PortZCon string PortZComv = DMM.ReadString(); if (PortZComv.IndexOf("1") > -1) { PortZConvOnOff[ChanNo - 1] = "1"; } else { PortZConvOnOff[ChanNo - 1] = "0"; } DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.ZNB) { FixtureOnOff[ChanNo - 1] = ""; MatchCirOnOff[ChanNo - 1] = ""; PortZConvOnOff[ChanNo - 1] = ""; return 0; } else { return -1; } } public int RestoreFixtureState(int ChanNo) { if (InstrumentType == InstTyep.ENA) { DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:STAT " + FixtureOnOff[ChanNo - 1]); DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT " + MatchCirOnOff[ChanNo - 1]); //portmattcing DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT " + PortZConvOnOff[ChanNo - 1]); //PortZCon DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.PNA) { DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:STAT " + FixtureOnOff[ChanNo - 1]); DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT " + MatchCirOnOff[ChanNo - 1]); //portmattcing DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT " + PortZConvOnOff[ChanNo - 1]); //PortZCon DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else { return -1; } } public int NormalizeFixtureState(int ChanNo) { if (InstrumentType == InstTyep.ENA) { DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT OFF"); //portmattcing DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT OFF"); //PortZCon DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.PNA) { DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:PMC:STAT OFF"); //portmattcing DMM.WriteString(":CALC" + ChanNo.ToString() + ":FSIM:SEND:ZCON:STAT OFF"); //PortZCon DMM.WriteString("*OPC?"); string sts = DMM.ReadString(); return 0; } else if (InstrumentType == InstTyep.ZNB) { //フィクスチャ切らなくてもいつでもZ0=50のデータが手に入る。 return 0; } else { return -1; } } } }