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

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能16 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G16 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt