using Common; 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 { /// Fixed Type FixedBurst = 0b00, /// Extended Type ExtendBurst = 0b01, } /// Package options which to send address to read or write public class SendAddrPackOptions { /// /// 突发类型 /// /// 0 public required BurstType BurstType { get; set; } /// /// 任务ID /// /// 1 public required byte CommandID { get; set; } /// /// 标识写入还是读取 /// /// true public required bool IsWrite { get; set; } /// /// 突发长度:0是32bits,255是32bits x 256 /// /// 255 public required byte BurstLength { get; set; } /// /// 目标地址 /// /// 0 public required 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 }; /// /// 时间戳 /// /// 1234567 public required UInt32 Timestamp { get; set; } /// /// 数据包类型 /// /// 0 public required PackType Type { get; set; } /// /// Task ID /// /// 0 public required byte CommandID { get; set; } /// /// Whether is succeed to finish command /// /// true public required 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.Number.NumberToBytes(address, 4).Value; Array.Copy(bytesAddr, 0, arr, 4, bytesAddr.Length); return arr; } /// /// 讲地址包转化为Json格式的地址包选项 /// /// 字符串 public override string ToString() { var opts = new SendAddrPackOptions() { BurstType = (BurstType)(commandType >> 6), CommandID = Convert.ToByte((commandType >> 4) & 0b0011), IsWrite = Convert.ToBoolean(commandType & 0x01), BurstLength = burstLength, Address = address, }; return JsonConvert.SerializeObject(opts); } /// /// 根据字节数组构建地址包 /// /// 字节数组 /// 是否校验地址包包头 /// 地址包 public static Result FromBytes(byte[] bytes, bool checkSign = true) { if (bytes.Length != 8) { return new(new ArgumentException( "Bytes are not equal to 8 bytes.", nameof(bytes) )); } if (checkSign && bytes[0] != (byte)PackSign.SendAddr) { return new(new ArgumentException( "The sign of bytes is not SendAddr Package, but you can disable it by set checkSign false.", nameof(bytes) )); } var address = Common.Number.BytesToUInt64(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) { if (bodyData.Length > 256 * (32 / 8)) throw new Exception("The data of SendDataPackage can't over 256 * 32bits"); if (bodyData.Length % 4 != 0) throw new Exception("The data of SendDataPackage should be divided by 4"); 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 class RecvDataPackage { readonly UInt32 timestamp; readonly byte sign = (byte)PackSign.RecvData; readonly byte commandID; readonly byte resp; readonly byte _reserved = 0; readonly byte[] bodyData; /// /// FPGA->Server 读响应包 /// 构造函数 /// /// 时间戳 /// 任务ID号 /// 读响应包响应 /// 数据 public RecvDataPackage(UInt32 timestamp, byte commandID, byte resp, byte[] bodyData) { this.timestamp = timestamp; this.commandID = commandID; this.resp = resp; this.bodyData = bodyData; _ = this.sign; _ = this._reserved; } /// /// 通过接受包选项构建读响应包 /// /// 接收包(读响应包和写响应包)选项 public RecvDataPackage(RecvPackOptions opts) { this.timestamp = opts.Timestamp; 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() { Timestamp = this.timestamp, Type = RecvPackOptions.PackType.ReadResp, CommandID = this.commandID, IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true), Data = this.bodyData, }; return opts; } } /// /// 读取是否成功 /// public bool IsSuccessful { get { return Convert.ToBoolean((this.resp >> 1) == 0b01 ? false : true); } } /// /// 从字节数组构建读响应包 /// /// 字节数组 /// 读响应包 public static Result FromBytes(byte[] bytes) { if (bytes[4] != (byte)PackSign.RecvData) return new(new ArgumentException( $"The sign of bytes is not RecvData Package, Sign: 0x{BitConverter.ToString([bytes[0]])}", nameof(bytes) )); return new RecvDataPackage( Number.BytesToUInt32(bytes[..4]).Value, bytes[5], bytes[6], bytes[8..]); } /// /// [TODO:description] /// /// [TODO:parameter] /// [TODO:return] public static bool IsRecvDataPackage(byte[] bytes) { return bytes[4] == (byte)PackSign.RecvData; } /// /// 将数据包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var bodyDataLen = bodyData.Length; var arr = new byte[8 + bodyDataLen]; Buffer.BlockCopy( Number.UInt32ArrayToBytes([this.timestamp]).Value, 0, arr, 0, 4); arr[4] = this.sign; arr[5] = this.commandID; arr[6] = this.resp; arr[7] = this.resp; Array.Copy(bodyData, 0, arr, 8, bodyDataLen); return arr; } } /// 写响应包 public class RecvRespPackage { readonly UInt32 timestamp; readonly byte sign = (byte)PackSign.RecvResp; readonly byte commandID; readonly byte resp; readonly byte _reserved = 0; /// /// 构建写响应包 /// /// 时间戳 /// 任务ID /// 写响应 public RecvRespPackage(UInt32 timestamp, byte commandID, byte resp) { this.timestamp = timestamp; this.commandID = commandID; this.resp = resp; _ = this.sign; _ = this._reserved; } /// /// 通过接受包选项构建写响应包 /// /// 接收包(读响应包和写响应包)选项 public RecvRespPackage(RecvPackOptions opts) { this.timestamp = opts.Timestamp; this.commandID = opts.CommandID; this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00); } /// /// 获取写响应包选项 /// public RecvPackOptions Options { get { var opts = new RecvPackOptions() { Timestamp = this.timestamp, Type = RecvPackOptions.PackType.WriteResp, CommandID = commandID, IsSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? false : true), Data = null, }; return opts; } } /// /// 写入是否成功 /// public bool IsSuccessful { get { return Convert.ToBoolean((this.resp >> 1) == 0b01 ? false : true); } } /// /// 从字节数组构建写响应包 /// /// 字节数组 /// 写响应包 public static Result FromBytes(byte[] bytes) { if (bytes[4] != (byte)PackSign.RecvResp) return new(new ArgumentException( $"The sign of bytes is not RecvResp Package, Sign: 0x{BitConverter.ToString([bytes[4]])}", nameof(bytes) )); var timestamp = Number.BytesToUInt32(bytes[..4]).Value; return new RecvRespPackage(timestamp, bytes[5], bytes[6]); } /// /// [TODO:description] /// /// [TODO:parameter] /// [TODO:return] public static bool IsRecvRespPackage(byte[] bytes) { return bytes[4] == (byte)PackSign.RecvResp; } /// /// 将数据包转化为字节数组 /// /// 字节数组 public byte[] ToBytes() { var arr = new byte[8]; Buffer.BlockCopy( Number.UInt32ArrayToBytes([this.timestamp]).Value, 0, arr, 0, 4); arr[4] = this.sign; arr[5] = this.commandID; arr[6] = this.resp; arr[7] = this._reserved; return arr; } } }