//>>*************************************************************************** // 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 System; using System.Net.Sockets; using System.Text; using System.Threading; using NLog; using Raytheon.Common; using Raytheon.Units; namespace Raytheon.Instruments { /// /// public class PowerMeterKeysightScpi : IPowerMeter { #region PublicMembers #endregion #region PrivateMembers private const string _READ_ERROR_CODE_CMD = "SYST:ERR?"; private const string _RESETCMD = "*RST"; private const string _ISOPCCMD = "*STB? "; private const string _SELFTESTCMD = "*TST? "; private const string _MEASURE = "MEAS?"; private const string _FREE_RUN_MODE = "INIT:CONT ON"; private const string _SENSE = "SENS"; private const string _AVERAGE = ":AVER"; private const string _STATE = ":STAT"; private const string _DISPLAY = "DISP"; private const string _WINDOW = ":WIND"; private const string _NUMERIC = ":NUM"; private const string _RESOLUTION = ":RES"; private const string _ZERO = "CALibration:ZERO:AUTO ONCE"; private const string _AUTO = ":AUTO"; private const string _CAL = "CAL"; private const string _ONCE = "ONCE"; 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; private readonly ILogger _logger; private readonly IConfigurationManager _configurationManager; private readonly IConfiguration _configuration; #endregion #region PrivateFunctions /// /// The Finalizer which will release resources if required /// ~PowerMeterKeysightScpi() { Dispose(false); } /// /// Calibrate Chanel A or B /// Channel A = 1 /// Channel B = 2 /// /// private void Calibrate(int channelNumber) { if ((channelNumber < 1) || (channelNumber > 2)) { string errMsg = "Channel [" + channelNumber.ToString() + "] Invalid "; throw new Exception("" + errMsg); } // write calibrate string command = _CAL + channelNumber.ToString() + _AUTO + " " + _ONCE; IOWrite(command); } /// /// 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) { if (disposing) { if (_state == State.Ready) { Reset(); _tcpStream.Close(); _tcpStream.Dispose(); _state = State.Uninitialized; } } } /// /// 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 HasItTriggered() { return false; // Check the Trigger Event register to see if the event has properly triggered /*string command = m_ISITCOMPLETEDCMD + "\n"; string rspStr = IOQuery(command); bool isTriggered = false; string[] tokens = rspStr.Split('\n'); // check to see if it is triggered. if (IsOperationCompleted(tokens[0]) == true) { isTriggered = true; } return isTriggered;*/ } /// /// /// /// /// private string IOQuery(string command) { // 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("PowerMeterKeysightScpi:IOQuery() - Power Meter " + _name + " returned error code: " + err.ToString() + ", " + message); } return rspStr; } /// /// /// /// private 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("PowerMeterKeysightScpi:IOWrite() - Device " + _name + " returned error code: " + err.ToString() + "," + errorMessage); } } } /// /// /// /// /// /// 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; } /// /// - Set auto averaging /// - enable or disable filtering /// /// /// private void SetAverage(int SenseCount, bool enableAutoAverage) { string errMsg; if ((SenseCount < 1) || (SenseCount > 2)) { errMsg = "Sensor Count [" + SenseCount.ToString() + "] Invalid "; throw new Exception(errMsg); } string command = _SENSE + SenseCount.ToString() + _AVERAGE + _STATE + enableAutoAverage.ToString(); IOWrite(command); } /*@@@ Not Needed I don't think /// /// Set Power Meter Interface /// /// /// /// private void SetInterface(uint IPAddress, uint GPIBAddress) { // UP Address // strip off all but last byte const UInt32 Mask = 0x00000000FF; byte[] ByteArray = new byte[sizeof(uint)]; // 4 bytes in a Uint32 for (int i = 0; i < sizeof(uint); i++) { ByteArray[i] = (byte)(IPAddress & Mask); IPAddress = (IPAddress >> 8); // right shift to next byte } // output SYSTem:COMMunicaiton:LAN:ADDRess + IP Address formatted 0.0.0.0 to 255.255.255.255 string command = m_SysComm + m_IPAddr + ByteArray[3].ToString() + '.' + ByteArray[2].ToString() + '.' + ByteArray[1].ToString() + '.' + ByteArray[0].ToString(); IOWrite(command); //GPIB Address if (GPIBAddress > 30) { string GPIB_errMsg = "GPIB Address: [" + GPIBAddress + "] Out of Range"; throw new Exception(GPIB_errMsg); } command = m_SysComm + m_GPIB + GPIBAddress.ToString(); IOWrite(command); }*/ /// /// /// /// /// /// private void SetResolution(int windowNumber, int numValue, int resolution) { string errMsg; if ((windowNumber < 1) || (windowNumber > 2)) { errMsg = "Window Number[" + windowNumber.ToString() + "] Invalid "; throw new Exception(errMsg); } if ((numValue < 1) || (numValue > 2)) { errMsg = "Numeric [" + numValue.ToString() + "] Invalid "; throw new Exception(errMsg); } if ((resolution < 1) || (resolution > 4)) { errMsg = "Resolution Level [" + resolution.ToString() + "] Invalid "; throw new Exception(errMsg); } string command = _DISPLAY + _WINDOW + windowNumber.ToString() + _NUMERIC + numValue.ToString() + _RESOLUTION + " " + resolution.ToString(); IOWrite(command); } #endregion /// /// PowerMeterKeysightScpi factory constructor /// /// /// public PowerMeterKeysightScpi(string deviceName, IConfigurationManager configurationManager) { const int READ_BUFFER_SIZE = 512; Name = deviceName; _logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}"); _configurationManager = configurationManager; _configuration = _configurationManager.GetConfiguration(Name); _selfTestResult = SelfTestResult.Unknown; _state = State.Uninitialized; _readBuffer = new byte[READ_BUFFER_SIZE]; _address = _configuration.GetConfigurationValue("PowerMeterKeysightScpi", "Address", "127.0.0.1"); m_PORT = _configuration.GetConfigurationValue("PowerMeterKeysightScpi", "Address", 5025); TcpClient scopeSocketConn = new TcpClient(_address, m_PORT); _tcpStream = scopeSocketConn.GetStream(); _tcpStream.ReadTimeout = m_READ_TIMEOUT; _state = State.Uninitialized; _selfTestResult = SelfTestResult.Unknown; } /// /// /// /// /// public PowerMeterKeysightScpi(string deviceName, string address) { const int READ_BUFFER_SIZE = 512; _name = deviceName; _logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}"); _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 int Channels { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } /// /// /// /// public bool ClearErrors() { throw new NotImplementedException(); } /// /// /// public string DetailedStatus { get { return "This is a Scpi Power Meter"; } } /// /// /// public bool DisplayEnabled { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } /// /// Dispose of this objects resources /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// /// /// /// /// public bool EnableChannel(int channel, bool enable) { throw new NotImplementedException(); } /// /// /// 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 Power GetMeasurement(int channel) { // for now, just use free running mode with default expected power levels const string EXPECTED_POWER = "DEF"; const string RESOLUTION = "DEF"; //@@@ TBD if this is needed turn off system header // for now, just use free running mode with default expected power levels // if we need better resolution, we will extend the IPowerInterface string command = _FREE_RUN_MODE + "\n"; IOWrite(command); //MEAS1? DEF,DEF,(@1) //MEAS? DEF,DEF,(@1) command = _MEASURE + " " + EXPECTED_POWER + "," + RESOLUTION + ",(@" + channel.ToString() + ")" + "\n"; string rspStr = IOQuery(command); string[] tokens = rspStr.Split('\n'); double power = Util.ConvertStringToDouble(tokens[0]); return Power.FromWatts(power); } /// /// /// 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 = 90000; // send the command and get the response 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 = "Power Meter " + _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 power meter 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 bool SetFrequency(int channel, Frequency frequency) { int freq = Convert.ToInt32(frequency.Hertz); string command = "SENSe1:FREQuency " + freq.ToString() + "HZ" + "\n"; IOWrite(command); return true; } /// /// /// 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); } } /// /// /// /// public bool ZeroMeter() { throw new NotImplementedException(); // zero the power meter /* string command = _ZERO + "\n"; IOWrite(command); // or if ((channelNumber < 1) || (channelNumber > 4)) { string errMsg = "Channel [" + channelNumber.ToString() + "] Invalid "; throw new Exception(errMsg); } string command = m_CAL + channelNumber.ToString() + m_Zero + m_Auto + m_Space + m_Once; IOWrite(command);*/ } } }