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