using System.Net; using DotNext; namespace Peripherals.DebuggerClient; /// /// FPGA调试器的内存地址映射常量 /// class DebuggerAddr { /// /// 触发器启动地址 /// public const UInt32 Start = 0x5100_0000; /// /// 刷新操作地址 /// public const UInt32 Fresh = 0x5100_FFFF; /// /// 信号标志读取地址 /// public const UInt32 Signal = 0x5000_0001; /// /// 数据读取基地址 /// public const UInt32 Data = 0x5100_0000; /// /// 捕获模式设置地址 /// public const UInt32 Mode = 0x5101_0000; } /// /// FPGA调试器命令常量 /// class DebuggerCmd { /// /// 启动触发器命令 /// public const UInt32 Start = 0xFFFF_FFFF; /// /// 刷新命令 /// public const UInt32 Fresh = 0x0000_0000; /// /// 清除信号标志命令 /// public const UInt32 ClearSignal = 0xFFFF_FFFF; } /// /// 信号捕获模式枚举 /// public enum CaptureMode : byte { /// /// 无捕获模式 /// None = 0, /// /// 低电平触发模式 /// Logic0 = 1, /// /// 高电平触发模式 /// Logic1 = 2, /// /// 上升沿触发模式 /// Rise = 3, /// /// 下降沿触发模式 /// Fall = 4, } /// /// FPGA调试器客户端,用于通过UDP协议与FPGA调试器进行通信 /// public class DebuggerClient { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); readonly int timeout = 2000; readonly int taskID; readonly int port; readonly string address; private IPEndPoint ep; private UInt32 captureDataAddr = 0x5100_0000; /// /// 初始化FPGA调试器客户端 /// /// FPGA设备的IP地址 /// 通信端口号 /// 任务标识符 /// 通信超时时间(毫秒),默认2000ms /// 当timeout为负数时抛出 public DebuggerClient(string address, int port, int taskID, int timeout = 2000) { if (timeout < 0) throw new ArgumentException("Timeout couldn't be negative", nameof(timeout)); this.address = address; this.taskID = taskID; this.port = port; this.ep = new IPEndPoint(IPAddress.Parse(address), port); this.timeout = timeout; } /// /// 设置信号捕获模式 /// /// 要设置的线 /// 要设置的捕获模式 /// 操作结果,成功返回true,失败返回错误信息 public async ValueTask> SetMode(UInt32 wireNum, CaptureMode mode) { if (wireNum > 512) { return new(new ArgumentException($"Wire Num can't be over 512, but receive num: {wireNum}")); } UInt32 data = ((UInt32)mode); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, DebuggerAddr.Mode + wireNum, data, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set mode: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to SetMode returned false"); return new(new Exception("Failed to set mode")); } return true; } /// /// 启动信号触发器开始捕获 /// /// 操作结果,成功返回true,失败返回错误信息 public async ValueTask> StartTrigger() { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, DebuggerAddr.Start, DebuggerCmd.Start, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to start trigger: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to StartTrigger returned false"); return new(new Exception("Failed to start trigger")); } return true; } /// /// 读取触发器状态标志 /// /// 操作结果,成功返回状态标志字节,失败返回错误信息 public async ValueTask> ReadFlag() { var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, DebuggerAddr.Signal, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read flag: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1) { logger.Error("ReadAddr returned invalid data for flag"); return new(new Exception("Failed to read flag")); } return ret.Value.Options.Data[3]; } /// /// 清除触发器状态标志 /// /// 操作结果,成功返回true,失败返回错误信息 public async ValueTask> ClearFlag() { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, DebuggerAddr.Signal, DebuggerCmd.ClearSignal, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to clear flag: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to ClearFlag returned false"); return new(new Exception("Failed to clear flag")); } return true; } /// /// 从指定偏移地址读取捕获的数据 /// /// Port数量 /// 操作结果,成功返回捕获数据,失败返回错误信息 public async ValueTask> ReadData(UInt32 portNum) { var captureData = new byte[1024 * 4 * portNum]; { var ret = await UDPClientPool.ReadAddr4Bytes(this.ep, this.taskID, this.captureDataAddr, captureData.Length / 4, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read data: {ret.Error}"); return new(ret.Error); } if (ret.Value.Length != captureData.Length) { logger.Error($"Receive capture data length should be {captureData.Length} instead of {ret.Value.Length}"); return new(new Exception($"Receive capture data length should be {captureData.Length} instead of {ret.Value.Length}")); } Buffer.BlockCopy(ret.Value, 0, captureData, 0, captureData.Length); } return captureData; } /// /// 刷新调试器状态,重置内部状态机 /// /// 操作结果,成功返回true,失败返回错误信息 public async ValueTask> Refresh() { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, DebuggerAddr.Fresh, DebuggerCmd.Fresh, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to refresh: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to Refresh returned false"); return new(new Exception("Failed to refresh")); } return true; } }