using DotNext; using Newtonsoft.Json; namespace WebProtocol { /// The Sign of Package public enum PackSign { /// Package: Send Read or Write Address to Device SendAddr = 0x00, /// Package: Send Data Which Update the flash of Device SendData = 0xFF, /// RecvData = 0x0F, /// RecvResp = 0xF0, } /// Package Burst Type public enum BurstType { /// Extended Type ExtendBurst = 0b00, /// Fixed Type FixedBurst = 0b01, } /// Package options which to send address to read or write public class SendAddrPackOptions { /// /// 突发类型 /// /// 0 public BurstType BurstType { get; set; } /// /// 任务ID /// /// 1 public byte CommandID { get; set; } /// /// 标识写入还是读取 /// /// true public bool IsWrite { get; set; } /// /// 突发长度:0是32bits,255是32bits x 256 /// /// 255 public byte BurstLength { get; set; } /// /// 目标地址 /// /// 0 public UInt32 Address { get; set; } /// /// 转换为Json格式字符串 /// /// Json String public override string ToString() { return JsonConvert.SerializeObject(this); } } /// Package Options which to receive from boards public class RecvPackOptions { /// 数据包类型 public enum PackType { /// 读响应包 ReadResp, /// 写响应包 WriteResp }; /// /// 数据包类型 /// /// 0 public PackType Type { get; set; } /// /// Task ID /// /// 0 public byte CommandID { get; set; } /// /// Whether is succeed to finish command /// /// true public bool IsSuccess { get; set; } /// /// Return Data /// /// [] public byte[]? Data { get; set; } /// /// Convert to Json String /// /// Json String public override string ToString() { return JsonConvert.SerializeObject(this); } } /// Server->FPGA 地址包 public class SendAddrPackage { readonly byte sign = (byte)PackSign.SendAddr; readonly byte commandType; readonly byte burstLength; readonly byte _reserved = 0; readonly UInt32 address; /// /// 使用地址包选项构造地址包 /// /// 地址包选项 public SendAddrPackage(SendAddrPackOptions opts) { byte byteBurstType = Convert.ToByte((byte)opts.BurstType << 6); byte byteCommandID = Convert.ToByte((opts.CommandID & 0x03) << 4); byte byteIsWrite = (opts.IsWrite ? (byte)0x01 : (byte)0x00); this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite); this.burstLength = opts.BurstLength; this.address = opts.Address; } /// /// 使用完整参数构造地址包 /// /// 突发类型 /// 任务ID /// 是否是写数据 /// 突发长度 /// 设备地址 public SendAddrPackage(BurstType burstType, byte commandID, bool isWrite, byte burstLength, UInt32 address) { byte byteBurstType = Convert.ToByte((byte)burstType << 6); byte byteCommandID = Convert.ToByte((commandID & 0x03) << 4); byte byteIsWrite = (isWrite ? (byte)0x01 : (byte)0x00); this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite); this.burstLength = burstLength; this.address = address; } /// /// 使用二进制参数构建地址包 /// /// 二进制命令类型 /// 突发长度 /// 写入或读取的地址 public SendAddrPackage(byte commandType, byte burstLength, UInt32 address) { this.commandType = commandType; this.burstLength = burstLength; this.address = address; } /// /// 获取对应地址包选项 /// public SendAddrPackOptions Options { get { return new SendAddrPackOptions() { Address = this.address, BurstLength = this.burstLength, BurstType = (BurstType)(this.commandType >> 6), CommandID = Convert.ToByte((this.commandType >> 4) & 0b11), IsWrite = Convert.ToBoolean(this.commandType & 1) }; } } /// /// 将地址包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var arr = new byte[8]; arr[0] = sign; arr[1] = commandType; arr[2] = burstLength; arr[3] = _reserved; var bytesAddr = Common.NumberProcessor.NumberToBytes(address, 4).Value; Array.Copy(bytesAddr, 0, arr, 4, bytesAddr.Length); return arr; } /// /// 讲地址包转化为Json格式的地址包选项 /// /// 字符串 public override string ToString() { var opts = new SendAddrPackOptions(); opts.BurstType = (BurstType)(commandType >> 6); opts.CommandID = Convert.ToByte((commandType >> 4) & 0b0011); opts.IsWrite = Convert.ToBoolean(commandType & 0x01); opts.BurstLength = burstLength; opts.Address = address; return JsonConvert.SerializeObject(opts); } /// /// 根据字节数组构建地址包 /// /// 字节数组 /// 是否校验地址包包头 /// 地址包 public static Result FromBytes(byte[] bytes, bool checkSign = true) { if (bytes.Length != 8) { throw new ArgumentException( "Bytes are not equal to 8 bytes.", nameof(bytes) ); } if (checkSign && bytes[0] != (byte)PackSign.SendAddr) { throw new ArgumentException( "The sign of bytes is not SendAddr Package, but you can disable it by set checkSign false.", nameof(bytes) ); } var address = Common.NumberProcessor.BytesToNumber(bytes[4..]).Value; return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address)); } } /// 数据包 public struct SendDataPackage { readonly byte sign = (byte)PackSign.SendData; readonly byte[] _reserved = new byte[3]; readonly byte[] bodyData; /// /// 根据数据内容构建数据包 /// /// 数据 public SendDataPackage(byte[] bodyData) { this.bodyData = bodyData; _ = _reserved; } /// /// 将数据包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var bodyDataLen = bodyData.Length; var arr = new byte[4 + bodyDataLen]; arr[0] = sign; Array.Copy(bodyData, 0, arr, 4, bodyDataLen); return arr; } } /// FPGA->Server 读响应包 public struct RecvDataPackage { readonly byte sign = (byte)PackSign.RecvData; readonly byte commandID; readonly byte resp; readonly byte _reserved = 0; readonly byte[] bodyData; /// /// FPGA->Server 读响应包 /// 构造函数 /// /// 任务ID号 /// 读响应包响应 /// 数据 public RecvDataPackage(byte commandID, byte resp, byte[] bodyData) { this.commandID = commandID; this.resp = resp; this.bodyData = bodyData; _ = this.sign; _ = this._reserved; } /// /// FPGA->Server 读响应包 /// 构造函数 /// /// 任务ID号 /// 是否读取成功 /// 数据 public RecvDataPackage(byte commandID, bool isSuccess, byte[] bodyData) { this.commandID = commandID; this.resp = Convert.ToByte(isSuccess); this.bodyData = bodyData; } /// /// 通过接受包选项构建读响应包 /// /// 接收包(读响应包和写响应包)选项 public RecvDataPackage(RecvPackOptions opts) { this.commandID = opts.CommandID; this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00); this.bodyData = opts.Data ?? (byte[])[0, 0, 0, 0]; } /// /// 获取读响应包选项 /// public RecvPackOptions Options { get { var opts = new RecvPackOptions(); opts.Type = RecvPackOptions.PackType.ReadResp; opts.CommandID = commandID; opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); opts.Data = bodyData; return opts; } } /// /// 读取是否成功 /// public bool IsSuccessful { get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } } /// /// 从字节数组构建读响应包 /// /// 字节数组 /// 读响应包 public static Result FromBytes(byte[] bytes) { if (bytes[0] != (byte)PackSign.RecvData) throw new ArgumentException( "The sign of bytes is not RecvData Package!", nameof(bytes) ); return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]); } /// /// 将数据包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var bodyDataLen = bodyData.Length; var arr = new byte[4 + bodyDataLen]; arr[0] = this.sign; arr[1] = this.commandID; arr[2] = this.resp; Array.Copy(bodyData, 0, arr, 4, bodyDataLen); return arr; } } /// 写响应包 public struct RecvRespPackage { readonly byte sign = (byte)PackSign.RecvResp; readonly byte commandID; readonly byte resp; readonly byte _reserved = 0; /// /// 构建写响应包 /// /// 任务ID /// 写响应 public RecvRespPackage(byte commandID, byte resp) { this.commandID = commandID; this.resp = resp; _ = this.sign; _ = this._reserved; } /// /// 构建写响应包 /// /// 任务ID /// 是否写成功 public RecvRespPackage(byte commandID, bool isSuccess) { this.commandID = commandID; this.resp = Convert.ToByte(isSuccess); } /// /// 通过接受包选项构建写响应包 /// /// 接收包(读响应包和写响应包)选项 public RecvRespPackage(RecvPackOptions opts) { this.commandID = opts.CommandID; this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00); } /// /// 获取写响应包选项 /// public RecvPackOptions Options { get { var opts = new RecvPackOptions(); opts.Type = RecvPackOptions.PackType.WriteResp; opts.CommandID = commandID; opts.IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); opts.Data = null; return opts; } } /// /// 写入是否成功 /// public bool IsSuccessful { get { return Convert.ToBoolean((resp >> 1) == 0b01 ? false : true); } } /// /// 从字节数组构建写响应包 /// /// 字节数组 /// 写响应包 public static Result FromBytes(byte[] bytes) { if (bytes[0] != (byte)PackSign.RecvResp) throw new ArgumentException( "The sign of bytes is not RecvResp Package!", nameof(bytes) ); return new RecvRespPackage(bytes[1], bytes[2]); } /// /// 将数据包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var arr = new byte[4]; arr[0] = this.sign; arr[1] = this.commandID; arr[2] = this.resp; return arr; } } }