Files
2025-11-26 11:18:26 +08:00

592 lines
16 KiB
C#
Raw Permalink 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SERVER
{
/// <summary>
/// Hex文件处理
/// </summary>
public class HexFile
{
/// <summary> 加载文件大小 </summary>
private const int _loadFileSize = 1024 * 1024 * 2;
/// <summary> 加载数据大小 </summary>
private const int _loadDataSize = 1024 * 1024 * 2;
/// <summary> 加载Hex文件数据 </summary>
private byte[] _LoadHexFileData = new byte[_loadFileSize];
/// <summary> 加载数据Buff </summary>
private byte[] _LoadDataBuff = new byte[_loadDataSize];
/// <summary> 加载结束地址 </summary>
private int _LoadEndAddr;
/// <summary> C1-Hex文件起始值 </summary>
private int _HexStart_C1 = 0;
/// <summary> 解析出的文件数据 </summary>
private byte[] _ParseData;
/// <summary> 解析出的配置数据 </summary>
private byte[] _ParseConfigData;
/// <summary> 匹配起始值 </summary>
private int _matchingValue;
private readonly int _matchingAddr = 49152; //0xC000 匹配数据起始地址
/// <summary> 匹配数据 </summary>
private byte[] _matchingData = new byte[512];
/// <summary>
/// 解析Hex文件
/// </summary>
/// <param name="filePath"></param>
public byte[] DealHexFile(Stream filePath)
{
bool tmpRet = LoadDataFromFile(filePath);
byte[] checkSum = new byte[4];
int tmpIdx = 0;
int tmpLineCnt = 1;
int tmpHexValidLenght = _LoadEndAddr - _HexStart_C1;
if (tmpRet)
{
StringBuilder parse = new StringBuilder();
//Dim tmpStrBuffer As String
for (tmpIdx = _HexStart_C1; tmpIdx < _LoadEndAddr; tmpIdx++)
{
parse.Append(HexByteStr(_LoadDataBuff[tmpIdx])); //<10ms
}
_ParseData = ConvertHexStringToBytes(parse.ToString());
Array.Copy(_ParseData, _matchingValue, _matchingData, 0, _matchingData.Length);
//Console.WriteLine($"——解析匹配数据——:{vbCrLf}{BitConverter.ToString(_matchingData)}")
//'Dim a() As Byte = {&H0}
//'Dim b As String = Encoding.GetEncoding("GBK").GetString(a)
////_matchingData
//byte[] project = new byte[2]; //项目编码 2 Bytes
//Array.Copy(_matchingData, 0, project, 0, project.Length);
////Dim projects As String = Encoding.GetEncoding("GBK").GetString(project)
//string projects = $"{project[0] + project[1] * 256}";
//projects = projects.Replace("\0", "");
//byte[] roomId = new byte[4]; //房型Id 4 Bytes
//Array.Copy(_matchingData, project.Length, roomId, 0, roomId.Length);
////Dim roomIds As String = Encoding.GetEncoding("GBK").GetString(roomId)
//string roomIds = $"{BitConverter.ToUInt32(roomId, 0)}";
//roomIds = roomIds.Replace("\0", "");
//byte[] version = new byte[20]; //版本号 20 Bytes
//Array.Copy(_matchingData, (project.Length + roomId.Length), version, 0, version.Length);
//string versions = Encoding.GetEncoding("GBK").GetString(version);
//versions = versions.Replace("\0", "");
//byte[] mcu = new byte[16]; //MCU型号 16 Bytes
//Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length), mcu, 0, mcu.Length);
//string mcus = Encoding.GetEncoding("GBK").GetString(mcu);
//mcus = mcus.Replace("\0", "");
//byte[] central = new byte[16]; //中控型号 16 Bytes
//Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length + mcu.Length), central, 0, central.Length);
//string centrals = Encoding.GetEncoding("GBK").GetString(central);
//centrals = centrals.Replace("\0", "");
//byte[] remark = new byte[64]; //备注 64 Bytes
//Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length + mcu.Length + central.Length), remark, 0, remark.Length);
// string remarks = Encoding.GetEncoding("GBK").GetString(remark);
//remarks = remarks.Replace("\0", "");
////MatchingInfo(projects, roomIds, versions, mcus, centrals, remarks);
}
return _ParseData;
}
public string Get_HexStart_C1()
{
return HexStringToBytes(_HexStart_C1);
}
/// <summary>
/// 获取Hex文件中信息
/// </summary>
/// <returns></returns>
public string GetHexInfo()
{
//_matchingData
byte[] project = new byte[2]; //项目编码 2 Bytes
Array.Copy(_matchingData, 0, project, 0, project.Length);
//Dim projects As String = Encoding.GetEncoding("GBK").GetString(project)
string projects = $"{project[0] + project[1] * 256}";
projects = projects.Replace("\0", "");
byte[] roomId = new byte[4]; //房型Id 4 Bytes
Array.Copy(_matchingData, project.Length, roomId, 0, roomId.Length);
//Dim roomIds As String = Encoding.GetEncoding("GBK").GetString(roomId)
string roomIds = $"{BitConverter.ToUInt32(roomId, 0)}";
roomIds = roomIds.Replace("\0", "");
byte[] version = new byte[20]; //版本号 20 Bytes
Array.Copy(_matchingData, (project.Length + roomId.Length), version, 0, version.Length);
string versions = Encoding.GetEncoding("GBK").GetString(version);
versions = versions.Replace("\0", "");
byte[] mcu = new byte[16]; //MCU型号 16 Bytes
Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length), mcu, 0, mcu.Length);
string mcus = Encoding.GetEncoding("GBK").GetString(mcu);
mcus = mcus.Replace("\0", "");
byte[] central = new byte[16]; //中控型号 16 Bytes
Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length + mcu.Length), central, 0, central.Length);
string centrals = Encoding.GetEncoding("GBK").GetString(central);
centrals = centrals.Replace("\0", "");
byte[] remark = new byte[64]; //备注 64 Bytes
Array.Copy(_matchingData, (project.Length + roomId.Length + version.Length + mcu.Length + central.Length), remark, 0, remark.Length);
string remarks = Encoding.GetEncoding("GBK").GetString(remark);
remarks = remarks.Replace("\0", "");
return centrals;
}
/// <summary>
/// 加载hex文件数据
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private bool LoadDataFromFile(Stream path)
{
Array.Clear(_LoadHexFileData, 0, _LoadHexFileData.Length);
try
{
//System.IO.Stream fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
if (path.Length <= _loadFileSize)
{
path.Read(_LoadHexFileData, 0, (int)path.Length);
}
else
{
return false;
}
path.Close();
}
catch (Exception ex)
{
return false;
}
return HexFileToData(_LoadHexFileData, _LoadDataBuff, ref _LoadEndAddr);
}
private string HexByteStr(byte hexByte)
{
if (hexByte < 16)
{
return "0" + Convert.ToString(hexByte, 16).ToUpper();
}
else
{
return Convert.ToString(hexByte, 16).ToUpper();
}
}
/// <summary>
/// 解析Hex文件到Byte数组
/// </summary>
/// <param name="hexBuffer"></param>
/// <param name="dataBuffer"></param>
/// <param name="endAddr"></param>
/// <returns></returns>
private bool HexFileToData(byte[] hexBuffer, byte[] dataBuffer, ref int endAddr)
{
int i = 0;
//行数
int LineCnt = 0;
int DataType_00_Idx = 0;
//清空数据缓存区域
for (i = 0; i < dataBuffer.Length; i++)
{
dataBuffer[i] = 0xFF;
}
//本行数据缓存
byte[] dataStrBuf = new byte[32];
byte[] dataValBuf = new byte[16];
//首地址标记
bool headAddrFlag = true;
//本行地址值
int tmpLineAdd = 0;
//偏移地址 0x04 数据类型指示偏移地址
int LineAddOffestBase = 0;
//结束地址
endAddr = 0;
byte[] flashAddressBuf = new byte[4];
int flashAddress = 0;
//INSTANT C# NOTE: The ending condition of VB 'For' loops is tested only on entry to the loop. Instant C# has created a temporary variable in order to use the initial value of hexBuffer.Length for every iteration:
int tempVar = hexBuffer.Length;
for (i = 0; i < tempVar; i++)
{
//首先找到冒号
if (hexBuffer[i] == 0x3A) //&H3A = ":"
{
LineCnt += 1;
//B0数据长度
int dataLen = (StrToHex(hexBuffer[i + 1]) * 16 + StrToHex(hexBuffer[i + 2]));
if (dataLen > 0)
{
//ByCheckSum
byte checkSum = (byte)(StrToHex(hexBuffer[i + 9 + dataLen * 2]) * 16 + StrToHex(hexBuffer[i + 10 + dataLen * 2]));
//取出整行数据
byte[] rowDataStrBuf = new byte[42];
byte[] rowDataValBuf = new byte[21];
int rowLen = 0;
Array.Clear(rowDataStrBuf, 0, 42);
Array.Clear(rowDataValBuf, 0, 21);
rowLen = (dataLen * 2) + 10;
Array.Copy(hexBuffer, i + 1, rowDataStrBuf, 0, rowLen);
StrToHex(rowDataValBuf, rowDataStrBuf, Convert.ToUInt16(rowLen / 2.0));
//using System;
int tempVar2 = Convert.ToInt32(rowLen / 2.0);
byte tempCheckSum = GetSumChecks(rowDataValBuf, ref tempVar2);
if (tempCheckSum != 0xFF)
{
return false; //CheckSum校验不通过返回错误
}
//B4~Bx数据内容
Array.Clear(dataStrBuf, 0, 32);
Array.Clear(dataValBuf, 0, 16);
Array.Copy(hexBuffer, i + 9, dataStrBuf, 0, dataLen * 2);
StrToHex(dataValBuf, dataStrBuf, (UInt16)dataLen);
}
//B1~B2取出地址位的值
Array.Copy(hexBuffer, i + 3, flashAddressBuf, 0, 4);
//本行地址取出来放在 flashAddress中
UInt16 tempVar3 = (UInt16)tmpLineAdd;
StrToHex(ref tempVar3, flashAddressBuf);
tmpLineAdd = tempVar3;
flashAddress = LineAddOffestBase + tmpLineAdd;
//B3数据类型
var dataType = StrToHex(hexBuffer[i + 8]);
switch (dataType)
{
case 0: //数据记录
DataType_00_Idx = DataType_00_Idx + 1;
//将第一个00类型数据的地址作为起始地址 保存到 _HexStart_C1
if (DataType_00_Idx == 1)
{
_HexStart_C1 = flashAddress;
_matchingValue = _matchingAddr - _HexStart_C1;
}
Array.Copy(dataValBuf, 0, dataBuffer, flashAddress, dataLen);
endAddr = flashAddress + dataLen;
break;
case 1: //文件结束
if (endAddr == 0)
{
return false;
}
else
{
return true;
}
//break;
case 2:
case 3:
case 5: //扩展段地址, 开始段地址, 开始线性地址’
continue;
case 4: //扩展线性地址
if (dataLen == 2)
{
LineAddOffestBase = (dataValBuf[0] * 256 + dataValBuf[1]) * 65536;
}
else
{
return false; //确认DataLen必须是2否则报错
}
break;
default:
return false;
}
}
}
return false;
}
public static void StrToHex(byte[] pbDest, byte[] pbSrc, UInt16 nLen)
{
byte h1 = 0;
byte h2 = 0;
byte s1 = 0;
byte s2 = 0;
int i = 0;
for (i = 0; i < nLen; i++)
{
h1 = pbSrc[2 * i];
h2 = pbSrc[2 * i + 1];
s1 = (byte)(toupper(h1) - 0x30);
if (s1 > 9)
{
s1 -= 7;
}
s2 = (byte)(toupper(h2) - 0x30);
if (s2 > 9)
{
s2 -= 7;
}
pbDest[i] = (byte)(s1 * 16 + s2);
}
}
private void StrToHex(ref UInt16 pbDest, byte[] pbSrc)
{
byte[] pBufDest = new byte[2];
byte h1 = 0;
byte h2 = 0;
byte s1 = 0;
byte s2 = 0;
UInt16 i = 0;
for (i = 0; i < 2; i++)
{
h1 = pbSrc[2 * i];
h2 = pbSrc[2 * i + 1];
s1 = (byte)(toupper(h1) - 0x30);
if (s1 > 9)
{
s1 -= 7;
}
s2 = (byte)(toupper(h2) - 0x30);
if (s2 > 9)
{
s2 -= 7;
}
pBufDest[i] = (byte)(s1 * 16 + s2);
}
//pbDest = (pBufDest(0) << 8) + pBufDest(1)
pbDest = (UInt16)(pBufDest[0] * 256 + pBufDest[1]);
}
private byte StrToHex(/*object*/ int src)
{
if (Convert.ToInt32(src) >= 0x30 && Convert.ToInt32(src) <= 0x39)
{
return Convert.ToByte((src - 0x30));
}
else if (Convert.ToInt32(src) >= 0x41 && Convert.ToInt32(src) <= 0x46)
{
return Convert.ToByte((src - 0x41 + 10));
}
else if (Convert.ToInt32(src) >= 0x61 && Convert.ToInt32(src) <= 0x66)
{
return Convert.ToByte((src - 0x61 + 10));
}
else
{
return 0;
}
}
public static byte toupper(byte val)
{
if (val >= 0x61 && val <= 0x7A)
{
return (byte)(val - 0x20);
}
else
{
return val;
}
}
/// <summary>
/// 和校验
/// 求Byte数组的和校验
/// </summary>
/// <param name="dataPacket">Byte数组</param>
/// <returns></returns>
public byte GetSumChecks(byte[] dataPacket, ref int len)
{
int sum = 0;
for (var idx = 0; idx < len; idx++)
{
sum += dataPacket[idx];
sum &= 0xFF;
}
sum = (~sum) & 0xFF;
return (byte)sum;
}
//&H
public byte[] GetStringToDataByte(string str)
{
List<byte> dataList = new List<byte>();
for (int index = 0; index < str.Length; index += 2)
{
dataList.Add(Convert.ToByte($"{str.Substring(index, 2)}"));
}
return dataList.ToArray();
}
/// <summary>
/// 16进制原码字符串转字节数组
/// </summary>
/// <param name="hexString">"AABBCC"或"AA BB CC"格式的字符串</param>
/// <returns></returns>
public static byte[] ConvertHexStringToBytes(string hexString)
{
hexString = hexString.Replace(" ", "");
if (hexString.Length % 2 != 0)
{
throw new ArgumentException("参数长度不正确,必须是偶数位。");
}
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
{
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
return returnBytes;
}
/// <summary>
/// Byte[] 转 File
/// </summary>
/// <param name="fileData"></param>
public void ByteToFile(byte[] fileData)
{
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss") + ".bin";
string dirPath = @"D:\测试";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, fileName);
FileStream fileStream = new(filePath, FileMode.Create);
fileStream.Write(fileData, 0, fileData.Length);
fileStream.Close();
}
public string HexStringToBytes(int set)
{
string str = set.ToString("X6");
return str;
}
/// Name: CRC-16/IBM x16+x15+x2+1
/// Poly: 0x8005
/// Init: 0x0000
/// Refin: true
/// Refout: true
/// Xorout: 0x0000
///*************************************************************************
public static byte[] Crc16(byte[] buffer, int start = 0, int len = 0)
{
if (buffer == null || buffer.Length == 0) return null;
if (start < 0) return null;
if (len == 0) len = buffer.Length - start;
int length = start + len;
if (length > buffer.Length) return null;
ushort crc = 0;// Initial value
for (int i = start; i < length; i++)
{
crc ^= buffer[i];
for (int j = 0; j < 8; j++)
{
if ((crc & 1) > 0)
crc = (ushort)((crc >> 1) ^ 0xA001);// 0xA001 = reverse 0x8005
else
crc = (ushort)(crc >> 1);
}
}
byte[] ret = BitConverter.GetBytes(crc);
Array.Reverse(ret);
return ret;
}
public static int NetCRC16_Data(byte[] aStr, int len, int crc_id)
{
int xda, xdapoly;
int i, j, xdabit;
xda = 0xFFFF;
xdapoly = 0xA001; // (X**16 + X**15 + X**2 + 1)
for (i = 0; i < len; i++)
{
if ((i == crc_id) || (i == (crc_id + 1)))
{
xda ^= 0x00;
}
else
{
xda ^= aStr[i];
}
for (j = 0; j < 8; j++)
{
xdabit = (byte)(xda & 0x01);
xda >>= 1;
if (xdabit!=0) xda ^= xdapoly;
}
}
return xda;
}
}
}