// UNCLASSIFIED /*------------------------------------------------------------------------- RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON COMPANY. THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT. UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. -------------------------------------------------------------------------*/ using System; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using FpgaMeasurementInstrumentsLib; using NLog; using Raytheon.Common; namespace Raytheon.Instruments { /// /// This class serves as an interface to FPGAs that implement a UDP interface. /// It allows for the ability to read and write to registers. /// public class CommFpgaEthernet : IFpgaComm, IDisposable { #region PrivateClassMembers private UdpClient _udpClient; private readonly int _localPort; private readonly int _remotePort; private readonly string _remoteAddress; private static object _syncObj = new Object(); private SelfTestResult _selfTestResult; private State _state; private string _name; private readonly ILogger _logger; private readonly IConfigurationManager _configurationManager; private readonly IConfiguration _configuration; #endregion #region PrivateFuctions /// /// The Finalizer /// ~CommFpgaEthernet() { Dispose(false); } /// /// Dispose of this object /// /// protected virtual void Dispose(bool disposing) { if (disposing) { if (_state == State.Ready) { _udpClient.Close(); _state = State.Uninitialized; } } } /// /// Read data off of the socket /// /// The data that was read /// The number of bytes read private int ReadData(ref byte[] dataRead) { IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, _localPort); dataRead = _udpClient.Receive(ref remoteIPEndPoint); int numBytesRead = dataRead.Length; return numBytesRead; } /// /// Send a command message and get a response message /// /// The message to send /// The response private void SendCommandGetResponse(FPGACmdMessage commandMsg, ref FPGARspMessage rspMsg) { uint rxBufferSize = rspMsg.GetEntireMsgLength(); uint rxNumBytesExpected = rxBufferSize; uint dataToSendNumBytes = commandMsg.GetEntireMsgLength(); // send the command byte[] dataToSend = new byte[dataToSendNumBytes]; // get a pointer to the data GCHandle sendPinnedArray = GCHandle.Alloc(dataToSend, GCHandleType.Pinned); IntPtr pByte = sendPinnedArray.AddrOfPinnedObject(); commandMsg.Format(pByte); sendPinnedArray.Free(); // send the data int numBytesSent = SendData(dataToSend); if (dataToSendNumBytes != numBytesSent) { throw new Exception("wanted to send: " + dataToSendNumBytes.ToString() + " bytes, SendData() reported that it sent: " + numBytesSent.ToString()); } // read the response byte[] rspBuffer = new byte[rxBufferSize]; int numBytesRead = ReadData(ref rspBuffer); if (numBytesRead != rxNumBytesExpected) { throw new Exception("received " + numBytesRead.ToString() + " bytes, expected " + rxNumBytesExpected.ToString()); } // populate the rspMsg object GCHandle rxPinnedArray = GCHandle.Alloc(rspBuffer, GCHandleType.Pinned); IntPtr pBytePtr = rxPinnedArray.AddrOfPinnedObject(); rspMsg.Parse(pBytePtr); rxPinnedArray.Free(); } /// /// Send data out of the socket /// /// The data to send /// The number of bytes sent private int SendData(byte[] dataToSend) { IPAddress addy = IPAddress.Parse(_remoteAddress); IPEndPoint ipEndPoint = new IPEndPoint(addy, _remotePort); int numBytesSent = _udpClient.Send(dataToSend, dataToSend.Length, ipEndPoint); return numBytesSent; } #endregion #region PublicFuctions /// /// CommFpgaEthernet factory constructor /// /// /// public CommFpgaEthernet(string deviceName, IConfigurationManager configurationManager) { Name = deviceName; _logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}"); _configurationManager = configurationManager; _configuration = _configurationManager.GetConfiguration(Name); _selfTestResult = SelfTestResult.Unknown; _state = State.Uninitialized; _localPort = _configuration.GetConfigurationValue("CommFpgaEthernet", "LocalPort", 0); _remotePort = _configuration.GetConfigurationValue("CommFpgaEthernet", "RemotePort", 0); _remoteAddress = _configuration.GetConfigurationValue("CommFpgaEthernet", "RemoteAddress", "127.0.0.1"); } /// /// /// /// /// The port on the local computer /// The port that the FPGA is using /// The address that the FPGA is using public CommFpgaEthernet(string deviceName, int localPort, int remotePort, string remoteAddress) { _name = deviceName; _logger = LogManager.GetLogger($"{this.GetType().Name} - {deviceName}"); _selfTestResult = SelfTestResult.Unknown; _state = State.Uninitialized; _localPort = localPort; _remotePort = remotePort; _remoteAddress = remoteAddress; } /// /// /// /// public bool ClearErrors() { return false; } /// /// /// public string DetailedStatus { get { return "This is a FPGA Ethernet called " + _name; } } /// /// /// public bool DisplayEnabled { get { return false; } set { throw new NotImplementedException(); } } /// /// Dispose of this object /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// /// public bool FrontPanelEnabled { get { return false; } set { throw new NotImplementedException(); } } /// /// /// public InstrumentMetadata Info { get { throw new NotImplementedException(); } } /// /// /// public void Initialize() { Initialize(string.Empty); } /// /// /// /// public void Initialize(string fpga) { //5 second timeout const int TIMEOUT = 5000; lock (_syncObj) { if (_state == State.Uninitialized) { _udpClient = new UdpClient(_localPort); _udpClient.Client.ReceiveBufferSize = int.MaxValue; _udpClient.Client.SendBufferSize = int.MaxValue; _udpClient.Client.SendTimeout = TIMEOUT; _udpClient.Client.ReceiveTimeout = TIMEOUT; _state = State.Ready; } else { throw new Exception("expected the state to be Uninitialized, state was: " + _state.ToString() + " on card " + _name); } } } /// /// /// public string Name { get { return _name; } set { _name = value; } } /// /// /// /// public SelfTestResult PerformSelfTest() { _selfTestResult = SelfTestResult.Unknown; return _selfTestResult; } /// /// Reads a single register /// /// The page of the register to read from /// The register address to read from /// The data at the address public uint Read(string fpgaName, uint address) { // lock up the FPGA resource lock (_syncObj) { FPGACmdMessage cmd = new FPGAReadRegisterCmdMessage((FPGACmdMessage.Page)0, address); // this get populated in SendCommandGetResponse() FPGARspMessage rsp = new FPGAReadRegisterRspMessage(0, 0); SendCommandGetResponse(cmd, ref rsp); return rsp.GetData(); } } /// /// /// /// /// /// /// /// public void ReadBlock(string fpgaName, uint address, uint numberOfWordsToRead, bool shallWeIncrementAddress, ref uint[] dataRead) { // lock up the FPGA resource lock (_syncObj) { if (shallWeIncrementAddress) { FPGACmdMessage cmd = new FPGAReadRegisterCmdBlockIncrMessage((FPGACmdMessage.Page)0, address, numberOfWordsToRead, false); // this get populated in SendCommandGetResponse() FPGARspMessage rsp = new FPGAReadRegisterBlockIncrRspMessage(0, ref dataRead); SendCommandGetResponse(cmd, ref rsp); } else { throw new Exception("Not Implemented"); } } } /// /// /// public void Reset() { Shutdown(); Initialize(); } /// /// /// public SelfTestResult SelfTestResult { get { return _selfTestResult; } } /// /// /// public void Shutdown() { // lock up the FPGA resource lock (_syncObj) { if (_state == State.Ready) { _udpClient.Close(); _state = State.Uninitialized; } } } /// /// /// public State Status { get { return _state; } } /// /// Write to a single register /// /// The page of the register to read from /// The address to write to /// The data to write public void Write(string fpgaName, uint address, uint value) { // lock up the FPGA resource lock (_syncObj) { FPGACmdMessage cmd = new FPGAWriteRegisterCmdMessage((FPGACmdMessage.Page)0, address, value); // this get populated in SendCommandGetResponse() FPGARspMessage rsp = new FPGAWriteRegisterRspMessage(0, 0); SendCommandGetResponse(cmd, ref rsp); if (rsp.GetAddress() != address) { throw new Exception("Command write on address: " + address.ToString("X8") + ", received address: " + rsp.GetAddress().ToString("X8")); } else if (rsp.GetData() != 0xace0beef) { throw new Exception("Command write on address: " + address.ToString("X8") + " returned value: " + rsp.GetData().ToString("X8")); } } } /// /// /// /// /// /// /// public void WriteBlock(string fpgaName, uint address, uint numberOfWordsToWrite, uint[] data, bool shallWeIncrementAddress) { // lock up the FPGA resource lock (_syncObj) { FPGACmdMessage cmd = null; if (shallWeIncrementAddress) { cmd = new FPGAWriteRegisterCmdBlockIncrMessage((FPGACmdMessage.Page)0, address, data, false); } else { cmd = new FPGAWriteRegisterCmdBlockMessage((FPGACmdMessage.Page)0, address, data, false); } // this get populated in SendCommandGetResponse() FPGARspMessage rsp = new FPGAWriteRegisterRspMessage(0, 0); SendCommandGetResponse(cmd, ref rsp); if (rsp.GetAddress() != address) { throw new Exception("Command write on address: " + address.ToString("X8") + ", received address: " + rsp.GetAddress().ToString("X8")); } else if (rsp.GetData() != 0xace0beef) { throw new Exception("Command write on address: " + address.ToString("X8") + " returned value: " + rsp.GetData().ToString("X8")); } } } /// /// /// /// /// /// /// /// public void WriteRegister(uint page, uint address, uint[] data, bool incrementAddress = true, bool byteSwap = true) { // lock up the FPGA resource lock (_syncObj) { if (page > (uint)FPGACmdMessage.Page.PAGE3) { throw new Exception("input parameter 'page' is out of range: " + page.ToString()); } FPGACmdMessage cmd; if (incrementAddress) { cmd = new FPGAWriteRegisterCmdBlockIncrMessage((FPGACmdMessage.Page)page, address, data, byteSwap); } else { cmd = new FPGAWriteRegisterCmdBlockMessage((FPGACmdMessage.Page)page, address, data, byteSwap); } // this get populated in SendCommandGetResponse() FPGARspMessage rsp = new FPGAWriteRegisterRspMessage(0, 0); SendCommandGetResponse(cmd, ref rsp); if (rsp.GetAddress() != address) { throw new Exception("Command write on address: " + address.ToString("X8") + ", received address: " + rsp.GetAddress().ToString("X8")); } else if (rsp.GetData() != 0xace0beef) { throw new Exception("Command write on address: " + address.ToString("X8") + " returned value: " + rsp.GetData().ToString("X8")); } } } /// /// Loads firmware /// /// public void LoadFirmware(string fpgaName) { Initialize(fpgaName); } #endregion } }