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