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;
}
}