FPGA_WebLab/server/src/WebProtocol.cs

503 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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是32bits255是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;
}
}
}