using GBNewEnergy.Protocol.Enums;
using GBNewEnergy.Protocol.Exceptions;
using GBNewEnergy.Protocol.Extensions;
using GBNewEnergy.Protocol.NEProperties;
using System;
using System.IO;
namespace GBNewEnergy.Protocol
{
///
/// 新能源包
///
public class NEPackage : NEBufferedEntityBase
{
public NEPackage(byte[] header, byte[] body, NEGlobalConfigs nEConfigs) : base(header, body, nEConfigs)
{
}
public NEPackage(byte[] buf, NEGlobalConfigs nEConfigs) : base(buf, nEConfigs)
{
}
public NEPackage(INEProperties nEProperties, NEGlobalConfigs nEConfigs)
: base(nEProperties, nEConfigs)
{ }
///
/// 固定为24个字节长度
///
public const int HeaderFixedByteLength = 24;
///
/// 起始符
///
public const byte BeginFlag = 0x23;
///
/// 校验位1字节
///
private const int CheckBit = 1;
///
/// 命令标识
///
public NEMsgId MsgId { get; private set; }
///
/// 应答标志
///
public NEAskId AskId { get; private set; }
///
/// 车辆识别码
///
public string VIN { get; private set; }
///
/// 数据加密方式
/// 0x01:数据不加密;0x02:数据经过 RSA 算法加密;0x03:数据经过 AES128 位算法加密;“0xFE”表示异常,“0xFF”表示无效
///
public NEEncryptMethod EncryptMethod { get; private set; }
///
/// 数据单元长度是数据单元的总字节数,有效值范围:0-65531
///
public int DataUnitLength { get; private set; }
///
/// 采用BCC(异或检验)法,校验范围从命令单元的第一个字节开始,同后一个字节异或,直到校验码前一个字节为止,
/// 校验码占用一个字节,当数据单元存在加密时,应先加密后检验,先校验后解密
///
public byte BCCCode { get; private set; }
///
/// 头数据
///
public byte[] Header { get; private set; }
///
/// 数据体
///
public NEBodies Bodies { get; protected set; }
protected override void ToBuffer()
{
// 固定单元长度
DataUnitLength = Bodies.Buffer.Length;
Buffer = new byte[HeaderFixedByteLength + DataUnitLength + CheckBit];
Buffer[0] = BeginFlag;
Buffer[1] = BeginFlag;
Buffer[2] = (byte)MsgId;
Buffer[3] = (byte)AskId;
Buffer.WriteLittle(VIN, 4);
Buffer[21] = (byte)EncryptMethod;
Buffer.WriteLittle(DataUnitLength, 22, 2);
if (NEConfigs.Encrypt != null)
{
Buffer.WriteLittle(NEConfigs.Encrypt.Encrypt(Bodies.Buffer), 24, DataUnitLength);
}
else
{
Buffer.WriteLittle(Bodies.Buffer, 24, DataUnitLength);
}
BCCCode = Buffer.ToXor(2, (HeaderFixedByteLength + DataUnitLength - 1));
Buffer[HeaderFixedByteLength + DataUnitLength] = BCCCode;
Header = new byte[HeaderFixedByteLength];
Array.Copy(Buffer, 0, Header, 0, HeaderFixedByteLength);
}
protected override void InitializeProperties(INEProperties nEProperties)
{
NEPackageProperty nEPackageProperty = (NEPackageProperty)nEProperties;
VIN = nEPackageProperty.VIN;
MsgId = nEPackageProperty.MsgId;
AskId = nEPackageProperty.AskId;
Bodies = nEPackageProperty.Bodies;
EncryptMethod = NEConfigs.EncryptMethod;
}
protected override void InitializePropertiesFromBuffer()
{
if (Buffer[0] != BeginFlag && Buffer[1] == BeginFlag) throw new NEException(NEErrorCode.BeginFlagError, $"{Buffer[0]},{Buffer[1]}");
MsgId = (NEMsgId)Buffer[2];
AskId = (NEAskId)Buffer[3];
VIN = Buffer.ReadStringLittle(4, 17);
EncryptMethod = (NEEncryptMethod)Buffer[21];
DataUnitLength = Buffer.ReadUShortH2LLittle(22, 2);
// 进行BCC校验码
// 校验位 = 报文长度 - 最后一位(校验位) - 偏移量(2)
int checkBit = Buffer.Length - CheckBit - 2;
byte bCCCode = Buffer.ToXor(2, checkBit);
byte bCCCode2 = Buffer[Buffer.Length - CheckBit];
if (bCCCode != bCCCode2)
{
throw new NEException(NEErrorCode.BCCCodeError, $"request:{bCCCode2}!=calculate:{bCCCode}");
}
BCCCode = bCCCode2;
byte[] bodiesBytes = new byte[DataUnitLength + CheckBit];
Array.Copy(Buffer, HeaderFixedByteLength, bodiesBytes, 0, bodiesBytes.Length);
if (NEConfigs.Encrypt != null)
{
Bodies = NEBodiesFactory.GetNEBodiesByMsgId(MsgId, NEConfigs.Encrypt.Decrypt(bodiesBytes),NEConfigs);
}
else
{
Bodies = NEBodiesFactory.GetNEBodiesByMsgId(MsgId, bodiesBytes, NEConfigs);
}
Header = new byte[HeaderFixedByteLength];
Array.Copy(Buffer, 0, Header, 0, HeaderFixedByteLength);
}
}
}