简介
一、摘要
1.描述
- 本文主要描述的是如何通过使用C#解析常用MCU的刷写格式文件,如Bin,S19,Hex,Mot,Serc。
- 本软编写的语言是基于C#语言,并未使用其他关联的DLL文件,所以不同的电脑之间兼容性很好,不会出现调用异常的问题。
- 郑重申明,关于实现方法,我也是从网上很多地方学习而来,大家若觉得版权问题可以联系我随时删除。
2.关键字
文件解析,C#,Bin,S19,Hex,Mot,Serc。
二、为何选择C#解析
- C#解析文件有很多好用的字符串处理函数,不过其实方式方法都一样,只要知道了解析方法,使用任何语言都是一样轻松的。
三、BIN文件解析
/*-----define---------------------------------*/
private const int BLOCK_BUFF_LEN = 83886080;
private const byte MOT_LINE_LEN = 16;
private const byte HEX_LINE_LEN = 16;
/*-----enum and struct------------------------*/
private class DataInfo_Type
{
internal int len;
internal uint startAddr;
internal uint endAddr;
internal byte[] buff;
}
/*-----variable statement---------------------*/
private readonly List<DataInfo_Type> g_DataInfos = new List<DataInfo_Type>();
/***********************************************
* Name :PushDataInfo
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private void PushDataInfo(uint? startAddr, uint? endAddr, uint? minStartAddr, uint? maxEndAddr, byte[] p_buff, int len)
{
int m = 0; int n = 0;
if (minStartAddr == null) { minStartAddr = 0; }
if (maxEndAddr == null) { maxEndAddr = 0xFFFFFFFF; }
if ((startAddr > maxEndAddr) || (endAddr < minStartAddr)) { return; }
if (startAddr < minStartAddr) { m = (int)(minStartAddr - startAddr); }
if (endAddr > maxEndAddr) { n = (int)(endAddr - maxEndAddr); }
len = len - m - n;
DataInfo_Type dataInfo = new DataInfo_Type
{
len = len,
startAddr = (uint)(startAddr + m),
endAddr = (uint)(endAddr - n),
buff = new byte[len]
};
CommonLib.Copy(dataInfo.buff, p_buff, m, len);
g_DataInfos.Add(dataInfo);
}
/***********************************************
* Name :AnalysisBinFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool AnalysisBinFile(string path, uint? minStartAddr, uint? maxEndAddr)
{
try
{
FileStream file = new FileStream(path, FileMode.Open);
int lenth = (int)file.Length;
if (lenth == 0) { return false; }
byte[] data = new byte[BLOCK_BUFF_LEN];
uint? startAddr = minStartAddr;
if (startAddr == null) { startAddr = 0; }
uint? endAddr = (uint?)(startAddr + lenth - 1);
_ = file.Read(data, 0, lenth);
PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth);
file.Close();
return true;
}
catch { return false; }
}
四、BIN文件生成
/***********************************************
* Name :StorageBinFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool StorageBinFile(string path, uint startAddr, byte[] p_buff, int len)
{
try
{
Stream file = new FileStream(path, FileMode.Create);
BinaryWriter binWriter = new BinaryWriter(file, Encoding.Unicode);
binWriter.Write(p_buff, (int)startAddr, len);
binWriter.Close();
file.Close();
return true;
}
catch { return false; }
}
五、S19,M0T,SREC文件解析
/***********************************************
* Name :MotCheckSum
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private byte MotCheckSum(byte[] buff, int len)
{
byte ret = 0x00;
for (int i = 0; i < len; i++) { ret += buff[i]; }
return (byte)(0xFF - ret);
}
/***********************************************
* Name :AnalysisMotFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool AnalysisMotFile(string path, uint? minStartAddr, uint? maxEndAddr, List<string> ignoreLines)
{
int lenth = 0;
uint? startAddr = null;
uint? endAddr = null;
byte[] data = new byte[BLOCK_BUFF_LEN];
StreamReader reader = new StreamReader(path);
while (true)
{
string line = reader.ReadLine();
if (line == null) { break; }
if (line == string.Empty) { continue; }
if (ignoreLines != null) { foreach (string str in ignoreLines) { if (str == line.Replace(" ", "")) { continue; } } }
string type = line.Substring(0, 2);
int len = (line.Length / 2) - 1;
if (len != (Convert.ToInt32(line.Substring(2, 2), 16) + 1))
{
reader.Close();
reader.Dispose();
return false;
}
byte[] buff = new byte[256];
for (int i = 0; i < len; i++) { buff[i] = Convert.ToByte(line.Substring((i + 1) * 2, 2), 16); }
if (buff[len - 1] != MotCheckSum(buff, len - 1))
{
reader.Close();
reader.Dispose();
return false;
}
uint address;
switch (type)
{
case "S1":
address = 0;
address |= ((uint)buff[1]) << 8;
address |= ((uint)buff[2]) << 0;
if (startAddr == null) { startAddr = address; }
if ((endAddr != null) && (address != (endAddr + 1)))
{
PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth);
lenth = 0;
startAddr = address;
}
endAddr = address + (uint)(len - 4) - 1;
CommonLib.Copy(data, lenth, buff, 3, len - 4);
lenth += len - 4;
break;
case "S2":
address = 0;
address |= ((uint)buff[1]) << 16;
address |= ((uint)buff[2]) << 8;
address |= ((uint)buff[3]) << 0;
if (startAddr == null) { startAddr = address; }
if ((endAddr != null) && (address != (endAddr + 1)))
{
PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth);
lenth = 0;
startAddr = address;
}
endAddr = address + (uint)(len - 5) - 1;
CommonLib.Copy(data, lenth, buff, 4, len - 5);
lenth += len - 5;
break;
case "S3":
address = 0;
address |= ((uint)buff[1]) << 24;
address |= ((uint)buff[2]) << 16;
address |= ((uint)buff[3]) << 8;
address |= ((uint)buff[4]) << 0;
if (startAddr == null) { startAddr = address; }
if ((endAddr != null) && (address != (endAddr + 1)))
{
PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth);
lenth = 0;
startAddr = address;
}
endAddr = address + (uint)(len - 6) - 1;
CommonLib.Copy(data, lenth, buff, 5, len - 6);
lenth += len - 6;
break;
case "S7":
case "S8":
case "S9":
break;
default:
break;
}
}
if (lenth != 0) { PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth); }
reader.Close();
reader.Dispose();
return true;
}
六、S19,M0T,SREC文件生成
/***********************************************
* Name :StorageMotFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool StorageMotFile(string path, uint? startAddr, byte[] p_buff, int len)
{
try
{
int lenth;
int block = len / MOT_LINE_LEN;
byte[] buff = new byte[256];
if (startAddr == null) { startAddr = 0x00; }
StreamWriter writeFile = new StreamWriter(path);
string str = "S011000000486578766965772056312E3038D1";
writeFile.WriteLine(str);
if ((len % MOT_LINE_LEN) != 0) { block += 1; }
byte addrLen = startAddr > 0xFFFFFF ? (byte)4 : (byte)3;
for (int i = 0; i < block; i++)
{
for (int j = 0; j < addrLen; j++) { buff[j + 1] = (byte)((startAddr + (i * MOT_LINE_LEN)) >> ((addrLen - j - 1) * 8)); }
lenth = ((i + 1) * MOT_LINE_LEN) > len ? len - (i * MOT_LINE_LEN) : MOT_LINE_LEN;
buff[0] = (byte)(lenth + addrLen + 1);
CommonLib.Copy(buff, addrLen + 1, p_buff, MOT_LINE_LEN * i, lenth);
buff[lenth + addrLen + 1] = MotCheckSum(buff, lenth + addrLen + 1);
str = "S" + Convert.ToString(addrLen - 1, 16);
str += CommonLib.ToStr(buff, lenth + addrLen + 2).Replace(" ", "");
writeFile.WriteLine(str);
}
buff[0] = (byte)(addrLen + 1);
CommonLib.Fill(buff, 1, 0xFF, 4);
buff[addrLen + 1] = MotCheckSum(buff, addrLen + 1);
str = "S" + Convert.ToString(11 - addrLen, 16);
str += CommonLib.ToStr(buff, addrLen + 2).Replace(" ", "");
writeFile.WriteLine(str);
writeFile.Flush();
writeFile.Close();
return true;
}
catch { return false; }
}
七、HEX文件解析
/***********************************************
* Name :HexCheckSum
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private byte HexCheckSum(byte[] buff, int len)
{
byte ret = 0x00;
for (int i = 0; i < len; i++) { ret += buff[i]; }
return (byte)(0x100 - ret);
}
/***********************************************
* Name :AnalysisBinFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool AnalysisHexFile(string path, uint? minStartAddr, uint? maxEndAddr, List<string> ignoreLines)
{
int lenth = 0;
uint? deviationAddr = null;
uint? startAddr = null;
uint? endAddr = null;
byte[] data = new byte[BLOCK_BUFF_LEN];
StreamReader reader = new StreamReader(path);
while (true)
{
string line = reader.ReadLine();
if (line == null) { break; }
if (line == string.Empty) { continue; }
if (ignoreLines != null) { foreach (string str in ignoreLines) { if (str == line.Replace(" ", "")) { continue; } } }
if (line.Substring(0, 1) != ":")
{
reader.Close();
reader.Dispose();
return false;
}
byte type = Convert.ToByte(line.Substring(7, 2), 16);
int len = line.Length / 2;
if (len != (Convert.ToInt32(line.Substring(1, 2), 16) + 5))
{
reader.Close();
reader.Dispose();
return false;
}
byte[] buff = new byte[80];
for (int i = 0; i < len; i++) { buff[i] = Convert.ToByte(line.Substring((i * 2) + 1, 2), 16); }
if (buff[len - 1] != HexCheckSum(buff, len - 1))
{
reader.Close();
reader.Dispose();
return false;
}
switch (type)
{
case 0x00:
if (deviationAddr == null) { deviationAddr = 0x00; }
uint? address = deviationAddr;
address += ((uint)buff[1]) << 8;
address += ((uint)buff[2]) << 0;
if (startAddr == null) { startAddr = address; }
if ((endAddr != null) && (address != (endAddr + 1)))
{
PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth);
lenth = 0;
startAddr = address;
}
endAddr = address + (uint)(len - 5) - 1;
CommonLib.Copy(data, lenth, buff, 4, len - 5);
lenth += len - 5;
break;
case 0x01:
break;
case 0x02:
deviationAddr = 0x00;
for (int i = 0; i < len - 5; i++)
{
deviationAddr <<= 8;
deviationAddr += buff[i + 4];
}
deviationAddr <<= 4;
break;
case 0x03:
break;
case 0x04:
deviationAddr = 0x00;
for (int i = 0; i < len - 5; i++)
{
deviationAddr <<= 8;
deviationAddr += buff[i + 4];
}
deviationAddr <<= 16;
break;
case 0x05:
break;
default:
break;
}
}
if (lenth != 0) { PushDataInfo(startAddr, endAddr, minStartAddr, maxEndAddr, data, lenth); }
reader.Close();
reader.Dispose();
return true;
}
八、HEX文件生成
/***********************************************
* Name :StorageHexFile
* Author :WangHu
* Function:***
* Version :V1.0.0
* Data :2022.5.20
***********************************************/
private bool StorageHexFile(string path, uint? startAddr, byte[] p_buff, int len)
{
try
{
ushort? address = null;
uint? deviationAddr = null;
int block = len / HEX_LINE_LEN;
byte[] buff = new byte[256];
if (startAddr == null) { startAddr = 0x00; }
StreamWriter writeFile = new StreamWriter(path);
if ((len % HEX_LINE_LEN) != 0) { block += 1; }
string str;
for (int i = 0; i < block; i++)
{
if ((address == null) || (address == 0x00))
{
buff[0] = 0x02;
buff[1] = 0x00;
buff[2] = 0x00;
buff[3] = startAddr > 0xFFFFF ? (byte)4 : (byte)2;
if (buff[3] == 2)
{
buff[4] = (byte)(startAddr >> 12);
buff[5] = (byte)(startAddr >> 4);
deviationAddr = startAddr & 0xFFFFFFF0;
}
if (buff[3] == 4)
{
buff[4] = (byte)(startAddr >> 24);
buff[5] = (byte)(startAddr >> 16);
deviationAddr = startAddr & 0xFFFF0000;
}
buff[6] = HexCheckSum(buff, 6);
str = ":" + CommonLib.ToStr(buff, 7).Replace(" ", "");
writeFile.WriteLine(str);
address = (ushort)(startAddr - deviationAddr);
}
buff[1] = (byte)(address >> 8);
buff[2] = (byte)(address >> 0);
buff[3] = 0x00;
int lenth = ((i + 1) * HEX_LINE_LEN) > len ? len - (i * HEX_LINE_LEN) : HEX_LINE_LEN;
buff[0] = (byte)lenth;
address += (ushort)lenth;
startAddr += (uint)lenth;
CommonLib.Copy(buff, 4, p_buff, HEX_LINE_LEN * i, lenth);
buff[lenth + 4] = HexCheckSum(buff, lenth + 4);
str = ":" + CommonLib.ToStr(buff, lenth + 5).Replace(" ", "");
writeFile.WriteLine(str);
}
str = ":00000001FF";
writeFile.WriteLine(str);
writeFile.WriteLine("");
writeFile.Flush();
writeFile.Close();
return true;
}
catch { return false; }
}
九、源码下载
十、其他
本文主要是讲解BIN,S19,M0T,SREC,HEX文件解析,后续章节会对源码的内容进行讲解,方便新手查询,有些地方可能会有描述性的错误,希望看到的朋友及时指出,我会及时更正错误,其他地方有些借鉴的描述,写此文章的目的是为了交流,非商业用途,欢迎私信讨论,感谢大家阅读。