//>>*************************************************************************** // UNCLASSIFIED // // COPYRIGHT 2017 RAYTHEON MISSILE SYSTEMS // ALL RIGHTS RESERVED // This data was developed pursuant to Contract Number HQ0147-12-C-0004/1088370 // with the US Government. The US Government's rights in and to this // copyrighted data are as specified in DFAR 252.227-7013 // which was made part of the above contract. // // Distribution Statement: D -Distribution authorized to the DoD and DoD // contractors only based on Critical Technology Requirements, May 2001. // Other requests shall be referred to PEO THEATER AIR DEFENSE (PMS 422). // Warning: - This document contains technical data whose export is restricted // by the Arms Export Control Act (Title 22, U.S.C.) or Export // Administration Act of 1979, as amended (Title 50, U.S.C.). Violations // of these laws are subject to severe criminal penalties. Disseminate in // accordance with provisions of DoD 5230.25. // Destruction Notice: - For unclassified, limited distribution information, // destroy by any method that will prevent disclosure of contents or // reconstruction of the document. Classified information, destroy in // accordance with DoD-5220.22-M or OPNAVINST 5510.1h. //>>*************************************************************************** using NLog; using Raytheon.Common; using System; using System.Net.Sockets; using System.Text; using System.Threading; namespace Raytheon.Instruments { /// /// public class SpecAnKeysightScpi : ISpecAnalyzer { #region PublicMembers #endregion #region PrivateMembers private const string _READ_ERROR_CODE_CMD = "SYST:ERR?"; private const string _SELFTESTCMD = "*TST? "; private const string _RESETCMD = "*RST"; /*private const string _ISOPCCMD = "*STB? "; private const string _FREQCMD = ":FREQ:FIX"; private const string _PWRLEVELMD = "POW:REF"; private const string _OUTPUTON = ":OUTPut ON"; private const string _OUTPUTOFF = ":OUTPut OFF";*/ private const string _INIT_IMMEDIATE = "INIT:IMM"; private const string _MARKER_SET_MAX = "CALC:MARK:MAX"; private const string _MARKER_QUERY_MAX_X = "CALC:MARK:X?"; private const string _MARKER_QUERY_MAX_Y = "CALC:MARK:Y?"; private const string _AVG_OFF = "AVER OFF"; private const string _AVG_ON = "AVER ON"; private const string _AVG_LOG = "AVER:TYPE LOG"; private const string _AVG_RMS = "AVER:TYPE RMS"; //private const string _AVG_SCAL = "AVER:TYPE SCAL"; private const string _AVG_COUNT = "AVER:COUN"; private const string _ATTENUATION_AUTO_ON = "POWer:ATTenuation:AUTO ON"; private const string _ATTENUATION_AUTO_OFF = "POWer:ATTenuation:AUTO OFF"; private const string _ATTENUATION_SET = "POWer:ATTenuation"; //private const string _POWER_LEVEL = "POWer:LEVel"; //private const string _POWER_LEVEL_AUTO_ON = "POWer:LEVel:AUTO ON"; //private const string _POWER_LEVEL_AUTO_OFF = "POWer:LEVel:AUTO OFF"; private const string _FREQ_CENTER = "SENS:FREQ:CENT"; private const string _FREQ_SPAN = "SENS:FREQ:SPAN"; private const string _RBW_SET = "BWID"; private const string _RBW_AUTO_ON = "BWID:AUTO On"; private const string _RBW_AUTO_OFF = "BWID:AUTO Off"; private const string _VBW_SET = "BWID:VID"; private const string _VBW_AUTO_ON = "BWID:VID:AUTO On"; private const string _VBW_AUTO_OFF = "BWID:VID:AUTO Off"; private int m_PORT = 5025; private const int m_READ_TIMEOUT = 10000; private readonly string _address; private byte[] _readBuffer; private NetworkStream _tcpStream; private State _state; private SelfTestResult _selfTestResult; private string _name; /// /// NLog logger /// private readonly ILogger _logger; /// /// Raytheon configuration /// private readonly IConfigurationManager _configurationManager; private readonly IConfiguration _configuration; #endregion #region PrivateFunctions /// /// The Finalizer which will release resources if required /// ~SpecAnKeysightScpi() { Dispose(false); } /// /// Convert scpi data to string /// /// /// private string ConvertToString(ref byte[] data) { string rsp = System.Text.Encoding.ASCII.GetString(data); return rsp; } /// /// Dispose of this object /// /// protected virtual void Dispose(bool disposing) { try { if (disposing) { if (_state == State.Ready) { Reset(); _tcpStream.Close(); _tcpStream.Dispose(); _state = State.Uninitialized; } } } catch (Exception) { try { //ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace); } catch (Exception) { //Do not rethrow. Exception from error logger that has already been garbage collected } } } /// /// Get the error code. /// /// The error code. /// The error description. private string GetErrorCode(out int errorCode) { // not calling IOQuery() here so IOQuery() can call GetErrorCode() after each query string command = _READ_ERROR_CODE_CMD + "\n"; byte[] commandBuffer = Encoding.ASCII.GetBytes(command); // send the data out _tcpStream.Write(commandBuffer, 0, commandBuffer.Length); // clear our buffer Array.Clear(_readBuffer, 0, _readBuffer.Length); // read the response int numBytesRead = _tcpStream.Read(_readBuffer, 0, _readBuffer.Length); // convert to a string string rspStr = ConvertToString(ref _readBuffer); // parse the response string[] tokens = rspStr.Split(','); errorCode = Util.ConvertStringToInt32(tokens[0]); // it should always be 2 if (tokens.Length >= 2) { return tokens[1]; } else { return ""; } } /// /// /// /// /// /// private bool IsOperationCompleted(string statusString, string expectedResult = "1") { bool completed = false; // If Scope returns '+x' instead of 'x', where 'x' is any character, trim it. if (statusString.IndexOf('+') == 0) { statusString = statusString.TrimStart('+'); } if (statusString.Equals(expectedResult) == true) { completed = true; } return completed; } #endregion /// /// SpecAnKeysightScpi factory constructor /// /// /// public SpecAnKeysightScpi(string deviceName, IConfigurationManager configurationManager, ILogger logger) { const int READ_BUFFER_SIZE = 512; Name = deviceName; _logger = logger; _configurationManager = configurationManager; _configuration = _configurationManager.GetConfiguration(Name); _address = _configuration.GetConfigurationValue("SpecAnKeysightScpi", "Address", "127.0.0.1"); m_PORT = _configuration.GetConfigurationValue("SpecAnKeysightScpi", "Port", 5025); _readBuffer = new byte[READ_BUFFER_SIZE]; TcpClient scopeSocketConn = new TcpClient(_address, m_PORT); _tcpStream = scopeSocketConn.GetStream(); _tcpStream.ReadTimeout = m_READ_TIMEOUT; _state = State.Uninitialized; _selfTestResult = SelfTestResult.Unknown; } /// /// /// /// /// public SpecAnKeysightScpi(string name, string address) { const int READ_BUFFER_SIZE = 512; _name = name; _logger = LogManager.GetCurrentClassLogger(); _address = address; _readBuffer = new byte[READ_BUFFER_SIZE]; TcpClient scopeSocketConn = new TcpClient(_address, m_PORT); _tcpStream = scopeSocketConn.GetStream(); _tcpStream.ReadTimeout = m_READ_TIMEOUT; _state = State.Uninitialized; _selfTestResult = SelfTestResult.Unknown; } /// /// /// /// public bool ClearErrors() { throw new NotImplementedException(); } /// /// /// /// /// public void ConfigureAveraging(SpecAnAveragingType type, int numOfAverages) { if (type == SpecAnAveragingType.NONE) { string command = _AVG_OFF + "\n"; IOWrite(command); } else { string onCommand = _AVG_ON + "\n"; IOWrite(onCommand); string countCommand = _AVG_COUNT + " " + numOfAverages.ToString() + "\n"; IOWrite(onCommand); if (type == SpecAnAveragingType.LOG) { string logCommand = _AVG_LOG + "\n"; IOWrite(logCommand); } else if (type == SpecAnAveragingType.RMS) { string rmsCommand = _AVG_RMS + "\n"; IOWrite(rmsCommand); } /*else if (type == SpecAnAveragingType.SCAL) { //@@@ resulting in error -224 string scalCommand = _AVG_SCAL + "\n"; IOWrite(scalCommand); }*/ else { throw new Exception("unsupported averaging type: " + type.ToString()); } } } /// /// /// /// /// public void ConfigureBandwidth(int rbw, int vbw) { if (rbw == -99) { string command = _RBW_AUTO_ON + "\n"; IOWrite(command); } else { string command = _RBW_AUTO_OFF + "\n"; IOWrite(command); command = _RBW_SET + " " + rbw.ToString() + "\n"; IOWrite(command); } if (vbw == -99) { string command = _VBW_AUTO_ON + "\n"; IOWrite(command); } else { string command = _VBW_AUTO_OFF + "\n"; IOWrite(command); command = _VBW_SET + " " + vbw.ToString() + "\n"; IOWrite(command); } } /// /// /// /// /// public void ConfigureFrequency(int centerFreq, int span) { string command = _FREQ_CENTER + " " + centerFreq.ToString() + "\n"; IOWrite(command); command = _FREQ_SPAN + " " + span.ToString() + "\n"; IOWrite(command); } /// /// /// /// /// public void ConfigurePowerLevel(/*int referanceLevel, */int attenuation) { /*if (referanceLevel == -99) { string command = _POWER_LEVEL_AUTO_ON + " " + referanceLevel.ToString() + "\n"; IOWrite(command); } else { string command = _POWER_LEVEL_AUTO_OFF + " " + referanceLevel.ToString() + "\n"; IOWrite(command); command = _POWER_LEVEL + " " + referanceLevel.ToString() + "\n"; IOWrite(command); }*/ if (attenuation == -99) { string command = _ATTENUATION_AUTO_ON + "\n"; IOWrite(command); } else { string command = _ATTENUATION_AUTO_OFF + "\n"; IOWrite(command); command = _ATTENUATION_SET + " " + attenuation.ToString() + "\n"; IOWrite(command); } } /// /// /// public string DetailedStatus { get { return "This is a Scpi Spec An"; } } /// /// /// public bool DisplayEnabled { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } /// /// Dispose of this objects resources /// public void Dispose() { try { Dispose(true); GC.SuppressFinalize(this); } catch (Exception) { try { //ErrorLogger.Instance().Write(err.Message + "\r\n" + err.StackTrace); } catch (Exception) { //Do not rethrow. Exception from error logger that has already been garbage collected } } } /// /// /// public bool FrontPanelEnabled { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } /// /// /// public InstrumentMetadata Info { get { throw new NotImplementedException(); } } /// /// /// public void Initialize() { // if we have not yet been initialized, go ahead and create the socket if (_state == State.Uninitialized) { Reset(); // we already connected to the instrument in the constructor _state = State.Ready; } else { throw new Exception("expected the state of System " + _name + " to be Uninitialized, state was: " + _state.ToString()); } } /// /// /// /// /// public string IOQuery(string command, int timeout = 10000) { _tcpStream.ReadTimeout = timeout; // send the command IOWrite(command, false); // clear our buffer Array.Clear(_readBuffer, 0, _readBuffer.Length); // read from the response int numBytesRead = _tcpStream.Read(_readBuffer, 0, _readBuffer.Length); // convert response to a string string rspStr = ConvertToString(ref _readBuffer); // check for errors int err = 0; string message = GetErrorCode(out err); if (err != 0) { throw new Exception("SpecAnKeysightScpi:IOQuery() - Spec An " + _name + " returned error code: " + err.ToString() + ", " + message); } return rspStr; } /// /// /// /// public void IOWrite(string command, bool shallWeCheckForError = true) { // convert to a byte array byte[] commandBuffer = Encoding.ASCII.GetBytes(command); // send the data out _tcpStream.Write(commandBuffer, 0, commandBuffer.Length); // check for errors if (shallWeCheckForError == true) { int err = 0; string errorMessage = GetErrorCode(out err); if (err != 0) { throw new Exception("SpecAnKeysightScpi:IOWrite() - Device " + _name + " returned error code: " + err.ToString() + "," + errorMessage); } } } /// /// /// /// public double MeasurePeakAmplitude() { //Initiate a single sweep string command = _INIT_IMMEDIATE + "\n"; IOWrite(command); //@@@ probably need to wait until sweep is completed //although examples dont show that..have to try it out with a real signal // Set the marker to the maximum peak command = _MARKER_SET_MAX + "\n"; IOWrite(command); //Query and read the marker frequency command = _MARKER_QUERY_MAX_Y + "\n"; string rspStr = IOQuery(command); string[] tokens = rspStr.Split('\n'); double amp = Util.ConvertStringToDouble(tokens[0]); return amp; } /// /// /// /// public double MeasurePeakFrequency() { //Initiate a single sweep string command = _INIT_IMMEDIATE + "\n"; IOWrite(command); //@@@ probably need to wait until sweep is completed //although examples dont show that..have to try it out with a real signal // Set the marker to the maximum peak command = _MARKER_SET_MAX + "\n"; IOWrite(command); //Query and read the marker frequency command = _MARKER_QUERY_MAX_X + "\n"; string rspStr = IOQuery(command); string[] tokens = rspStr.Split('\n'); double freq = Util.ConvertStringToDouble(tokens[0]); return freq; } /// /// /// public string Name { get { return _name; } set { _name = value; } } /// /// /// public SelfTestResult SelfTestResult { get { return _selfTestResult; } } /// /// /// public State Status { get { return _state; } } /// /// /// /// public SelfTestResult PerformSelfTest() { try { // change the timeout to account for the long self test _tcpStream.ReadTimeout = 120000; // send the command and get the rsponse string command = _SELFTESTCMD + "\n"; string rspStr = IOQuery(command); // parse the response string[] tokens = rspStr.Split('\n'); //Check if self test is completed; returns status of "0". if (IsOperationCompleted(tokens[0], "0") == false) { string errorMsg = "System " + _name + " returned an error: " + tokens[0]; throw new Exception(errorMsg); } _selfTestResult = SelfTestResult.Pass; return SelfTestResult.Pass; } catch (Exception) { throw; } finally { // restore the timeout _tcpStream.ReadTimeout = m_READ_TIMEOUT; } } /// /// /// public void Reset() { // Resets the instrument string command = _RESETCMD + "\n"; IOWrite(command); Thread.Sleep(3000); /*command = _ISOPCCMD + "\n"; string rspStr = IOQuery(command); // parse the response string[] tokens = rspStr.Split('\n'); if (IsOperationCompleted(tokens[0]) == false) { throw new Exception("Reset was not completed."); }*/ } /// /// /// public void Shutdown() { string errorMsg = ""; if (_state == State.Ready) { try { //Reset System Reset(); } catch (Exception err) { errorMsg += err.Message + " "; } _state = State.Uninitialized; } // the stream was created in the constructor, dispose of it here try { if (_tcpStream != null) { _tcpStream.Dispose(); _tcpStream = null; } } catch (Exception err) { errorMsg += err.Message + " "; } if (errorMsg != "") { throw new Exception("System " + _name + " Had an error: " + errorMsg); } } } }