594 lines
14 KiB
C#
594 lines
14 KiB
C#
// 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 FpgaMeasurementInstrumentsLib;
|
|
using NLog;
|
|
using Raytheon.Common;
|
|
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Raytheon.Instruments
|
|
{
|
|
/// <summary>
|
|
/// This class serves as an interface to FPGAs that implement a UDP interface.
|
|
/// It allows for the ability to read and write to registers.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// NLog logger
|
|
/// </summary>
|
|
private readonly ILogger _logger;
|
|
/// <summary>
|
|
/// Raytheon configuration
|
|
/// </summary>
|
|
private readonly IConfigurationManager _configurationManager;
|
|
private readonly IConfiguration _configuration;
|
|
|
|
#endregion
|
|
|
|
#region PrivateFuctions
|
|
|
|
/// <summary>
|
|
/// The Finalizer
|
|
/// </summary>
|
|
~CommFpgaEthernet()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this object
|
|
/// </summary>
|
|
/// <param name="disposing"></param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
try
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (_state == State.Ready)
|
|
{
|
|
_udpClient.Close();
|
|
|
|
_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
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read data off of the socket
|
|
/// </summary>
|
|
/// <param name="dataRead">The data that was read</param>
|
|
/// <returns>The number of bytes read</returns>
|
|
private int ReadData(ref byte[] dataRead)
|
|
{
|
|
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, _localPort);
|
|
|
|
dataRead = _udpClient.Receive(ref remoteIPEndPoint);
|
|
|
|
int numBytesRead = dataRead.Length;
|
|
|
|
return numBytesRead;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send a command message and get a response message
|
|
/// </summary>
|
|
/// <param name="commandMsg">The message to send</param>
|
|
/// <param name="rspMsg">The response</param>
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send data out of the socket
|
|
/// </summary>
|
|
/// <param name="dataToSend">The data to send</param>
|
|
/// <returns>The number of bytes sent</returns>
|
|
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
|
|
|
|
/// <summary>
|
|
/// CommFpgaEthernet factory constructor
|
|
/// </summary>
|
|
/// <param name="deviceName"></param>
|
|
/// <param name="configurationManager"></param>
|
|
public CommFpgaEthernet(string deviceName, IConfigurationManager configurationManager, ILogger logger)
|
|
{
|
|
Name = deviceName;
|
|
|
|
_logger = logger;
|
|
|
|
_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");
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="fpgaName"></param>
|
|
/// <param name="localPort">The port on the local computer</param>
|
|
/// <param name="remotePort">The port that the FPGA is using</param>
|
|
/// <param name="remoteAddress">The address that the FPGA is using</param>
|
|
public CommFpgaEthernet(string name, int localPort, int remotePort, string remoteAddress)
|
|
{
|
|
_name = name;
|
|
_logger = LogManager.GetCurrentClassLogger();
|
|
_selfTestResult = SelfTestResult.Unknown;
|
|
_state = State.Uninitialized;
|
|
|
|
_localPort = localPort;
|
|
_remotePort = remotePort;
|
|
_remoteAddress = remoteAddress;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool ClearErrors()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string DetailedStatus
|
|
{
|
|
get
|
|
{
|
|
return "This is a FPGA Ethernet called " + _name;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public bool DisplayEnabled
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
set
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose of this object
|
|
/// </summary>
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public bool FrontPanelEnabled
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
set
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public InstrumentMetadata Info
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void Initialize()
|
|
{
|
|
Initialize(string.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="fpga"></param>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return _name;
|
|
}
|
|
set
|
|
{
|
|
_name = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public SelfTestResult PerformSelfTest()
|
|
{
|
|
_selfTestResult = SelfTestResult.Unknown;
|
|
return _selfTestResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reads a single register
|
|
/// </summary>
|
|
/// <param name="page">The page of the register to read from</param>
|
|
/// <param name="address">The register address to read from</param>
|
|
/// <returns>The data at the address</returns>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="fpgaName"></param>
|
|
/// <param name="address"></param>
|
|
/// <param name="numberOfWordsToRead"></param>
|
|
/// <param name="dataRead"></param>
|
|
/// <param name="shallWeIncrementAddress"></param>
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
Shutdown();
|
|
|
|
Initialize();
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public SelfTestResult SelfTestResult
|
|
{
|
|
get
|
|
{
|
|
return _selfTestResult;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void Shutdown()
|
|
{
|
|
// lock up the FPGA resource
|
|
lock (_syncObj)
|
|
{
|
|
if (_state == State.Ready)
|
|
{
|
|
_udpClient.Close();
|
|
|
|
_state = State.Uninitialized;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public State Status
|
|
{
|
|
get
|
|
{
|
|
return _state;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write to a single register
|
|
/// </summary>
|
|
/// <param name="page">The page of the register to read from</param>
|
|
/// <param name="address">The address to write to</param>
|
|
/// <param name="value">The data to write</param>
|
|
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"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="fpgaName"></param>
|
|
/// <param name="address"></param>
|
|
/// <param name="numberOfBytes"></param>
|
|
/// <param name="data"></param>
|
|
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"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="page"></param>
|
|
/// <param name="address"></param>
|
|
/// <param name="data"></param>
|
|
/// <param name="incrementAddress"></param>
|
|
/// <param name="byteSwap"></param>
|
|
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"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads firmware
|
|
/// </summary>
|
|
/// <param name="fpgaName"></param>
|
|
public void LoadFirmware(string fpgaName)
|
|
{
|
|
Initialize(fpgaName);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|