这几天接到一个小项目,需要解析 CAT021报文。费了九牛二虎之力终于看懂了报文解析的规则,接下来我就对我从二进制数据到实例出各数据项相应的对象的过程做一个小结,希望能帮到有需要的朋友。
下载地址:https://download.csdn.net/download/wangtingming/9619187
首先是总体方法:
/// <summary>
/// 接收到的数据解析
/// </summary>
/// <param name="datas"></param>
/// <returns></returns>
private static DataBlock DateParser(byte[] datas)
{
int cat = 0;
int len = 0;
byte[] fspecbytes;
byte[] temp = new byte[4];
DataBlock datablock = new DataBlock();
Array.Copy(datas, 0, temp, 0, 1);
cat = BitConverter.ToInt32(temp, 0);
Array.Clear(temp, 0, temp.Length);
Array.Copy(datas, 1, temp, 0, 2);
Array.Reverse(temp, 0, 2);
len = BitConverter.ToInt32(temp, 0);
Array.Clear(temp, 0, temp.Length);
fspecbytes = getFspecBytes(datas);
List<DatagramUap> dataitems = DatagramParser(fspecbytes, len,datas);
datablock.Cat = cat;
datablock.Len = len;
datablock.Dataitem = dataitems;
return datablock;
}
接下来是核心方法:
/// <summary>
/// 解析出数据项的实体列表
/// </summary>
/// <param name="fspecbytes"></param>
/// <param name="len"></param>
/// <param name="datas"></param>
/// <returns></returns>
private static List<DatagramUap> DatagramParser(byte[] fspecbytes, int len, byte[] datas)
{
int count = 0;
List<DatagramUap> dataitems = new List<DatagramUap>();
while (count < fspecbytes.Length)
{
int index = 7;
while (index > 0)
{
byte[] tempbytes = new byte[fspecbytes.Length];
Array.Copy(fspecbytes, tempbytes, fspecbytes.Length);
tempbytes[count] <<= 7 - index;
tempbytes[count] >>= 7;
byte[] temp1 = new byte[4];
temp1[0] = tempbytes[count];
if (BitConverter.ToInt32(temp1, 0) != 0)
{
DatagramUap datagramuap = InitDategram(count, index);
dataitems.Add(datagramuap);
}
index--;
}
count++;
}
int currnetbytenum = 0;
byte[] databytes = new byte[len - 3 - fspecbytes.Length];
Array.Copy(datas, 3 + fspecbytes.Length, databytes, 0, databytes.Length);
foreach (DatagramUap dataitem in dataitems)
{
byte[] bytes = new byte[dataitem.Len];
Array.Copy(databytes, currnetbytenum, bytes, 0, bytes.Length);
dataitem.Databytes = bytes;
currnetbytenum += dataitem.Len;
}
return dataitems;
}
根据位置确定数据项:
/// <summary>
/// 根据位置确定数据项
/// </summary>
/// <param name="count">符号字节第几个字节</param>
/// <param name="index">字节第几位</param>
/// <returns></returns>
private static DatagramUap InitDategram(int count, int index)
{
DatagramUap datagram = new DatagramUap();
switch (count)
{
case 0:
Dategram0(index,datagram);
break;
case 1:
Dategram1(index, datagram);
break;
case 2:
Dategram2(index, datagram);
break;
case 3:
Dategram3(index, datagram);
break;
case 4:
Dategram4(index, datagram);
break;
}
return datagram;
}
解析出标识符所占的字节:
/// <summary>
/// 解析出标识符所占的字节
/// </summary>
/// <param name="dates"></param>
/// <returns></returns>
private static byte[] getFspecBytes(byte[] dates)
{
int count = 3;
byte[] fspecbytes;
//如果下一个字节是标识符
while (IsMoreFspec(dates[count]))
{
count++;
}
//确定标识符字节数
fspecbytes = new byte[count - 2];
Array.Copy(dates, 3, fspecbytes, 0, fspecbytes.Length);
return fspecbytes;
}
判断下一个字节是否是符号字节:
/// <summary>
/// 判断下一个字节是否是符号字节
/// </summary>
/// <param name="temp"></param>
/// <returns></returns>
private static Boolean IsMoreFspec(byte temp)
{
Boolean ismore = false;
byte[] tempbytes = new byte[4];
temp <<= 7;
temp >>= 7;
tempbytes[0] = temp;
if (BitConverter.ToInt32(tempbytes, 0) == 0)
{
ismore = false;
}
else { ismore = true; }
return ismore;
}
当为第1个描述符字节时,初始化对象,其他初始化对象过程一样,看源代码就知道:
/// <summary>
/// 当为第1个描述符字节时,初始化对象
/// </summary>
/// <param name="index"></param>
/// <param name="datagram"></param>
private static void Dategram0(int index, DatagramUap datagram)
{
switch (index)
{
case 7:
datagram.Dateitemname = "数据源识别";
datagram.DateitemNum = "1021/010";
datagram.Fra = 1;
datagram.Len = 2;
break;
case 6:
datagram.Dateitemname = "目标报告描述符";
datagram.DateitemNum = "1021/040";
datagram.Fra = 2;
datagram.Len = 2;
break;
case 5:
datagram.Dateitemname = "日时间";
datagram.DateitemNum = "1021/030";
datagram.Fra = 3;
datagram.Len = 3;
break;
case 4:
datagram.Dateitemname = "在WGS-84坐标中的位置";
datagram.DateitemNum = "1021/130";
datagram.Fra = 4;
datagram.Len = 8;
break;
case 3:
datagram.Dateitemname = "目标地址";
datagram.DateitemNum = "1021/080";
datagram.Fra = 5;
datagram.Len = 3;
break;
case 2:
datagram.Dateitemname = "几何高度";
datagram.DateitemNum = "1021/140";
datagram.Fra = 6;
datagram.Len = 2;
break;
case 1:
datagram.Dateitemname = "品质因素";
datagram.DateitemNum = "1021/090";
datagram.Fra = 7;
datagram.Len = 2;
break;
}
}
最后再测试一下:
static void Main(string[] args)
{
byte[] temp = { 0x15, 0x00, 0x18, 0xE9, 0x95, 0x80, 0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x00, 0x78, 0x0A, 0x4E, 0x10, 0x08, 0x7D, 0xFB, 0xD8, 0x7F, 0xF6, 0xF6 };
DataBlock datablock = DateParser(temp);
}
其他方法或类如果需要可以留言。这个解析过程,从看文档到写这个demo花了大概一下午时间,所以肯定有很多地方考虑不周,希望大家不要吐槽~~
具体到每个数据项的值我还没有做,不过这个都解析出来了,那后面的也就渣渣呐~~~