1. 程式人生 > >C++實現cat021(0.26版)報文解析

C++實現cat021(0.26版)報文解析

最近接觸了一個小專案,使用C++對cat021(0.26)報文進行解析。剛開始沒有頭緒,之後在參考了CSDN博主TimiWang的文章:https://blog.csdn.net/wangtingming/article/details/52400656(十分感謝)和閱讀了英文文件之後,磕磕絆絆完成了這個小專案。在此,做一個小結。
1:預備知識
cat021報文格式(佈局):

說明:
資料型別(cat)=021,佔1個位元組,表示資料塊含有ADSB報文。
長度標誌(LEN)佔2個位元組,表示整個資料塊的總長度(包括cat和LEN欄位)佔有的位元組數。
FSPEC表示欄位說明(標誌位所在)。
注:詳細的報文解釋說明請查閱官方文件。

http://www.eurocontrol.int/publications/cat021-automatic-dependent-surveillance-broadcast-ads-b-messages-part-12

2:核心程式編寫
首先宣告並定義了兩個類對解析資料進行封裝保護。
 

class DatagramUap
{
private:
    int frn,len;
    std::string dataitemname;//資料名
    std::string dataitemNum;//資料編號
    std::vector<BYTE>databytes;//解析之後每個資料項對應的位元組存放處(容器)
public:
    void setFrn(int value3)
    {
        len=value3;
    }
    int getfrn(){return frn;}
    void setLen(int value4)
    {
        len=value4;
    }
    int getLen(){return len;}
    void setDataitemname(std::string value5)
    {
        dataitemname=value5;
    }
    std::string& getDataitemname(){return dataitemname;}
    void setDataitemNum(std::string value6){dataitemNum=value6;}
    std::string& getDataitemNum(){return dataitemNum;}
    void setDatabytes(std::vector<BYTE> value)
    {
        databytes=value;
    }
    std::vector<BYTE> getDatabytes(){return databytes;}
}
class DataBlock
{
private:
    int cat,len;
    std::<DatagramUap> dataitem;
public:
    void setCat(int value1){cat=value1;}
    int getCat(){return cat;}
    void setLen(int value2){len=value2;}
    int getLen(){return len;}
    void setDataitem(std::list<DatagramUap> v1)
    {
        dataitem=v1;
    }
    std::list<DatagramUap> getDataitem(){return dataitem;}
}

接下來開始編寫資料包解析函式:
 

DataBlock DataParser(BYTE datas[])
{
    int cat=0;//初始化
    int len=0;
    std::vector<BYTE> fspecbytes;//建立一個空的容器
    BYTE temp[4];//建立臨時陣列
    DataBlock datablock;
    for(auto i=0;i<1;++i){temp[i]=data[i];}
    cat=temp1[0];
    for(auto i=0;i<sizeof(temp1);++i)
    {
        temp1[i]=0;//重置陣列,每個元素置零
    }
    for(auto i=0;i<2;++i}
    {
        temp1[i]=datas[i+1];
    }
    BYTE c;
    c=temp1[0];
    temp1[0]=temp1[1];
    temp1[1]=c;
    len=temp1[0];//LEN佔兩個位元組,一般後一個位元組即可表示資料總長度
    for(auto i=0;i<sizeof(temp1);++i) {temp[i]=0;}
    fspecbytes=getFspecBytes(datas);//獲取標誌符所佔位元組
    std::list<DatagramUap> dataitems=DatagramParser(fspecbytes,len,datas);//解析出資料項的實體列表
    
    datablock.setCat(cat);
    datalock.setLen(len);
    datablock.setDataitem(dataitem);

    return datablock;
}

上述程式中,在對cat和LEN進行對應分析之後,緊接著開始對標示符所佔位元組數進行分析。

//解析出標誌符所佔位元組
std::vector<BYTE> getFspecBytes(BYTE datas[])
{
    int count=3;
    std::vector<BYTE> fspecbytes;//定義一個空容器
    //如果下一個位元組是識別符號
    while(IsMoreFspec(datas[count]))
    {
        ++count;
    }
    //確定識別符號位元組數
    std::vector<BYTE> lhs(count-2);
    fspecbytes=lhs;
    for(auto i=0;i<(count-2);++i)
    {
        fspecbytes[i]=datas[i+3];
    }
    return fspecbytes;
}

//判斷下一個位元組是否是符號位元組
bool IsMoreFspec(BYTE temp)
{
    bool ismore=false;
    BYTE tempbytes[4];
    temp<<=7;//按位左移7位
    temp>>=7;
    tempbytes[0]=temp;
    if(0==tempbytes[0]) {ismore=false;}
    else
    {
        ismore=true;
    }
    return ismore;
}

而後再解析出資料項的實體列表

std::list<DatagramUap> DatagramParser(std::vector<BYTE> fspecbytes,int len,BYTE datas[])
{
    int count=0;
    std::list<DatagramUap> dataitems;
    std::list<DatagramUap>::iterator iter;
    int rhs=fspecbytes.size();
    while(count<rhs)
    {
        int index=7;
        while(index>0)
        {
            std::vector<BYTE> tempbytes(rhs);
            for(auto i=0;i<rhs;++i)
            {
                tempbytes[i]=fspecbytes[i];
            }
            tempbytes[count]<<=7-index;
            tempbytes[count]>>=7;
            BYTE temp2[4];
            temp2[0]=tempbytes[count];
            if(temp2[0]!=0)
            {
                DatagramUap datagramuap=InitDatagram(count,index);
                dataitems.push_back(datagramuap);//依次從列尾增加元素
            }
            index--;
        }
        ++count;
    }
    int currentbytenum=0;
    std::vector<BYTE> databytes(len-3-rhs);
    for(auto i=0;i<(len-3-rhs);++i)
    {
        databytes[i]=datas[i+3+rhs];
    }
    //遍歷容器,封裝資料
    for(iter=dataitems.begin();iter!=dataitems.end();iter++)
    {
        int temp5=(*iter).getLen();
        std::vector<BYTE> bytes(temp5);
        for(auto i=0;i<temp5;++i)
        {
            bytes[i]=databytes[i+currentbytenum];
        }
        (*iter).setDatabytes(bytes);//將每一項資料段對應位元組存入容器中封裝起來
        currentbytenum+=(*iter).getLen();
    }
return dataitems;
}
//根據位置確定資料項
//引數解釋:count——識別符號位元組中的第幾個位元組;index——位元組第幾位
DatagramUap InitDatagram(int count,int index)
{
    DatagramUap datagram;
    switch(count)
    {
    case 0:
        Datagram0(index,datagram);
        break;
    case 1:
        Datagram1(index,datagram);
        break;
    case 2:
        Datagram2(index,datagram);
        break;
    case 3:
        Datagram3(index,datagram);
        break;
    case 4:
        Datagram4(index,datagram);
        break;
    case 5:
        Datagram5(index,datagram);
        break;
    case 6:
        Datagram6(index,datagram);
        break;
    }
    return datagram;
}
//符合條件時,初始化物件
void Datagram0(int index,DatagramUap& datagram)
{
    switch(index)
    {
    case 7:
        datagram.setDataitemname("資料來源識別");//設定資料項名
        datagram.setDataitemNum("1021/010");//設定資料項參考編號
        datagram.setFrn(1);//設定欄位參考編號
        datagram.setLen(2);//設定該資料段對應位元組的位元組數
        break;
    case 6:
        datagram.setDataitemname("目標報告描述符");
        datagram.setDataitemNum("1021/040");
        datagram.setFrn(2);
        datagram.setLen(2);
        break;
    case 5:
        datagram.setDataitemname("日時間");
        datagram.setDataitemNum("1021/030");
        datagram.setFrn(3);
        datagram.setLen(3);
        break;
    case 4:
        datagram.setDataitemname("在WGS-84座標中的位置");
        datagram.setDataitemNum("1021/130");
        datagram.setFrn(4);
        datagram.setLen(8);
        break;
    case 3:
        datagram.setDataitemname("目標地址");
        datagram.setDataitemNum("1021/080");
        datagram.setFrn(5);
        datagram.setLen(3);
        break;
    case 2:
        datagram.setDataitemname("幾何高度");
        datagram.setDataitemNum("1021/140");
        datagram.setFrn(6);
        datagram.setLen(2);
        break;
    case 1:
        datagram.setDataitemname("品質因素");
        datagram.setDataitemNum("1021/090");
        datagram.setFrn(7);
        datagram.setLen(2);
        break;
    }
}

//在此只列出部分對應函式。
對於完整的程式碼,請下載底部檔案查閱。

int main()
{
	//測試資料
	BYTE temp[] = { 0x15,0x00,0x32,0xff,0xa1,0xdb,0x86,0xff,0xff,0x01,0x21,0x2d,0x15,0xa3,0x00,0x3f,
		0xa2,0xb3,0x01,0x45,0x0b,0xc8,0x89,0x91,0xa7,0x03,0xb4,0x00,0x07,0x48,0x00,0xea,
		0x00,0x9a,0x03,0x3a,0xcd,0xf6,0x34,0x40,0x71,0xe3,0x1d,0xe0,0x00,0x00,0x00,0x05,
		0x8f,0xb0
	};

	DataBlock datalock = DataParser(temp);
	list<DatagramUap>::iterator iter0;
	list<DatagramUap> temp0;
	
	temp0=datalock.getDataitem();
	int i = 1;
	for (iter0 = temp0.begin(); iter0 != temp0.end(); iter0++)
	{
		//int i = 1;
		cout << "第" << std::dec<<i << "個數據。" << endl;
		cout << "資料條款名:"<< (*iter0).getDataitemname().c_str() << endl;
		cout << "資料編號:" << (*iter0).getDataitemNum().c_str() << endl;
		string num = (*iter0).getDataitemNum();
		vector<BYTE> temp10 = (*iter0).getDatabytes();

		//加入條件判斷,符合則輸出資料項對應的值
		if (num =="1021/010")//注意相等的表示
		{
			DataSourceIdentifiction(temp10);
		}
		else if (num == "1021/020")
		{
			EmitterCategory(temp10);
		}
		else if (num == "1021/030")
		{
			TimeOfDay(temp10);
		}
		else if (num == "1021/032")
		{
			TimeofDayAccuracy(temp10);
		}
		else if (num == "1021/040")
		{
			Target(temp10);
		}
		else if (num == "1021/070")
		{
			Mode3_ACodeinOctalRepresentation(temp10);
		}
		else if (num == "1021/080")
		{
			TargetAddress(temp10);
		}
		else if (num == "1021/090")
		{
			FigureOfMerit(temp10);
		}
		else if (num == "1021/095")
		{
			VelocityAccuracy(temp10);
		}
		else if (num == "1021/110")
		{

		}
		else if (num == "1021/130")
		{
			PositionWGS_84(temp10);
		}
		else if (num == "1021/131")
		{
			SignalAmplitude(temp10);
		}
		else if (num == "1021/140")
		{
			GeometricAltitude(temp10);
		}
		else if (num == "1021/145")
		{
			FlightLevel(temp10);
		}
		else if (num == "1021/146")
		{
			IntermediateStateSelectedAltitude(temp10);
		}
		else if (num == "1021/148")
		{
			FinalStateSelectedAltitude(temp10);
		}
		else if (num == "1021/157")
		{
			GeometricVerticalRate(temp10);
		}
		else if (num == "1021/160")
		{
			GroundVector(temp10);
		}
		else if (num == "1021/170")
		{
			TargetIdentification(temp10);
		}
		else if (num == "1021/200")
		{
			TargetStatus(temp10);
		}
		else if (num == "1021/210")
		{
			LinkTechnologyIndicator(temp10);
		}
		++i;

	}
	return 0;
}

 

對於該版本的報文的常規資料段解析方式在附件中有指出,在本文中沒有講述。

最後,歡迎大家討論指正,不足之處請一定指出,謝謝。

連結如下:https://download.csdn.net/download/qingfengleerge/10581608