Qt 实现 Asterix 报文解析库

【写在前面】

最近工作中需要解析 Cat 21Cat 62ADS-B 数据 ( 自己的工作包含航空领域 )。

然后,因为整个 Asterix 协议类别非常之多,每个类别的版本也多,纯手工实现每个版本解析根本不现实 ( 然鹅公司之前的解析库就是这么做的且做的太烂 )。

于是花了很多时间去寻找一个好用的解析库,比如 Wireshark 的 Asterix 解析部分 ( 可惜因为是插件,有点难移出来 )。

最后找了很久( Asterix 好像应用比较局限,资料实在太少 ),终于找到一个实现相当良好的工具:AsterixInspector 一个显示Asterix数据文件内容的工具https://asterix.sourceforge.net/ 基于该工具,我将核心部分移植出来并进行简化,最终实现 :Asterix数据报文解析库。https://github.com/mengps/AsterixParser


【正文开始】

该库目前支持的类别有:

  • Cat1 (track UAP only)

  • Cat2

  • Cat4

  • Cat7 (downlink UAP only)

  • Cat8

  • Cat10

  • Cat11

  • Cat20

  • Cat21

  • Cat23

  • Cat34

  • Cat48

  • Cat62

  • Cat63

  • Cat64

  • Cat65

  • Cat240

  • Cat247

因为自己做的工作仅仅是包装得更好用罢了,所以这里简单讲一下用法即可( 偷懒直接用了我的注释 ):

SimpleAsterixRecordBlock 是报文解析后数据项的存储块。

cpp 复制代码
/**
 * @brief The SimpleAsterixRecordBlock struct
 */
struct SimpleAsterixRecordBlock
{
    /*! [字段引用编号] */
    int frn;
    /*! [数据项ID,例如(I062/070)] */
    QString id;
    /*! [数据项名称] */
    QString name;
    /*! [数据项原始值] */
    QByteArray rawValue;
    /*! [数据项刻度] */
    qreal scale;
    /*! [数据项单位] */
    QString unit;
    /*! [数据项实际值] */
    QVariant value;
    /*! [子数据块列表] */
    QList<SimpleAsterixRecordBlock> subBlock;
};

SimpleReservedExpansionField是报文数据项 **[RE]**解析后的存储块 ( 目前只支持Cat 21 )。

cpp 复制代码
/**
 * @brief The SimpleReservedExpansionField struct
 */
struct SimpleReservedExpansionField
{
    struct SubField {
        /*! [字段名称] */
        QString name;
        /*! [字段原始值] */
        QByteArray value;
    };
    /*! [字段类型] */
    quint8 type = 0;
    /*! [子字段列表] */
    QList<SubField> subField;
};

AsterixParser提供的接口:

cpp 复制代码
    /**
     * @brief getCategory 获取类别
     * @param asterixData Asterix数据包
     * @return int
     */
    int getCategory(const uchar *asterixData);

    /**
     * @brief getU8 字节转U8
     * @param data 原始字节
     * @return quint8
     */
    quint8 getU8(const QByteArray &data);

    /**
     * @brief getU16 字节转U16
     * @param data 原始字节
     * @return quint16
     */
    quint16 getU16(const QByteArray &data);

    /**
     * @brief getU32 字节转U32
     * @param data 原始字节
     * @return quint32
     */
    quint32 getU32(const QByteArray &data);

    /**
     * @brief parseToFsnMap 解析为{fsn, block}映射
     * @param asterixData Asterix数据包
     * @return QMap<int, SimpleAsterixRecordBlock>
     */
    QMap<int, SimpleAsterixRecordBlock> parseToFsnMap(const uchar *asterixData);

    /**
     * @brief parseToIdMap 解析为{id, block}映射
     * @param asterixData Asterix数据包
     * @return QMap<int, SimpleAsterixRecordBlock>
     */
    QMap<QString, SimpleAsterixRecordBlock> parseToIdMap(const uchar *asterixData);

    /**
     * @brief parseReservedExpansionField 解析保留扩展字段
     * @warning 目前仅实现[cat021]
     * @param cat 类别
     * @param ref 扩展字段记录块
     * @return QMap<int, SimpleReservedExpansionField>
     */
    QMap<int, SimpleReservedExpansionField> parseReservedExpansionField(int cat, const SimpleAsterixRecordBlock &ref);

【使用示例】

使用起来就非常简单了:

cpp 复制代码
#include <QCoreApplication>
#include <QDebug>
#include <QtEndian>

#include "asterixparser.h"

QString applyUnitAndScale(const QVariant &value, qreal scale, const QString &unit)
{
    if (qFuzzyCompare(scale, 1))
        return QString::number(value.toDouble()) + (unit.isEmpty() ? "" : (" "  + unit));
    else
        return QString::number(value.toDouble() * scale, 'f', 10) + (unit.isEmpty() ? "" : (" "  + unit));
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    //cat021
    uchar test[] = {
          0x15, 0x00, 0x35, 0xcb, 0x19, 0x71
        , 0x11, 0xc1, 0x01, 0x04, 0x16, 0x00, 0x11, 0x44, 0x4c, 0x65, 0x80, 0x09, 0xf1, 0x80, 0x2c, 0x25
        , 0xd8, 0x59, 0xe5, 0xff, 0xe0, 0x07, 0x4c, 0x65, 0x80, 0x02, 0x7b, 0x2d, 0x35, 0x08, 0x12, 0x00
        , 0x03, 0x34, 0x81, 0x37, 0xcf, 0x5d, 0xa0, 0x01, 0x07, 0x88, 0x10, 0x01, 0x11, 0x11, 0x02
    };

    //cat062
    /*uchar test[] = {
        0x3e, 0x00, 0x2b, 0x19, 0x31, 0x10, 0x47, 0x88, 0xf6, 0x00, 0x56, 0xfe, 0x34, 0x01, 0x27, 0xad,
        0x07, 0x00, 0x60, 0x6c, 0x31, 0x00, 0x00, 0x00, 0xc1, 0x01, 0x32, 0xff, 0xe1, 0x01, 0x60, 0x6c,
        0x31, 0x00, 0x00, 0x00, 0x4e, 0xee, 0x00, 0x93, 0x00, 0x00, 0x00
    };*/

    AsterixParser parser(QT_STRINGIFY(PWD_PATH) + QString("/../asterixSpecification"));

    auto map = parser.parseToFsnMap(test);

    for (const auto &block: map) {
        qDebug() << block.frn << block.id << block.name << block.rawValue;
        if (!block.subBlock.isEmpty()) {
            for (const auto &subBlock: block.subBlock)
                qDebug() << "  "
                         << subBlock.frn
                         << subBlock.id
                         << subBlock.name
                         << subBlock.value
                         << applyUnitAndScale(subBlock.value, subBlock.scale, subBlock.unit);
        }
    }

    auto ref_map = parser.parseReservedExpansionField(parser.getCategory(test), map[48]);
    for (const auto &ref: ref_map) {
        for (const auto &subField: ref.subField)
            qDebug() << "  "
                     << subField.name
                     << (subField.value.size() == 1 ? (parser.getU8(subField.value)) : (parser.getU16(subField.value)));
    }


    return app.exec();
}

【效果展示】

Cat 21 解析结果:

Cat 62 解析结果:


【结语】

关于规范文件生成部分[asterixSpecification]:

一般做法是:[规范pdf] -> [.ast] → [.xml],具体可以看我的项目主页提供的资料。

项目链接(多多star呀..⭐_⭐):

CSDN 的:

https://download.csdn.net/download/u011283226/88975636https://download.csdn.net/download/u011283226/88975636 Github 的:

https://github.com/mengps/AsterixParserhttps://github.com/mengps/AsterixParser

相关推荐
沐泽Mu1 小时前
嵌入式学习-QT-Day07
c++·qt·学习·命令模式
沐泽Mu1 小时前
嵌入式学习-QT-Day09
开发语言·qt·学习
林浔09066 小时前
QT信号槽
开发语言·qt
kiiila6 小时前
【Qt】编辑框/按钮控件---实现HelloWorld
开发语言·qt
lw向北.12 小时前
Qt For Android之环境搭建(Qt 5.12.11 Qt下载SDK的处理方案)
android·开发语言·qt
小灰灰搞电子13 小时前
Qt实现Android的图案密码(图形解锁)源码分享
开发语言·qt
kiiila1 天前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
黄金右肾1 天前
Qt之数据库使用(十四)
sql·qt·sqlite·database
杨德杰1 天前
QT多媒体开发(一):概述
qt·音视频·多媒体
小王爱吃月亮糖1 天前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio