VOFA修改数据解析GPCHC

参考资源

协议引擎开发 | VOFA-Plus上位机

Vodka: VOFA+ Plugins - Gitee.com

VOFA+ 5分钟实现 数据通信、波形显示_vofa使用教程-CSDN博客

效果展示

一、下载官方结构程序

协议引擎开发 | VOFA-Plus上位机

复制为自己需要的,然后在基础上修改

gpchc.h

cpp 复制代码
#ifndef GPCHC_H
#define GPCHC_H

#include "dataengineinterface.h"

class GPCHC : public QObject, public DataEngineInterface
{
    Q_OBJECT
    Q_INTERFACES(DataEngineInterface)
    // 插件唯一ID,需与FireWater区分
    Q_PLUGIN_METADATA(IID "VOFA+.Plugin.GPCHC")

public:
    explicit GPCHC();
    ~GPCHC();
    void ProcessingDatas(char *data, int count);
private:
    // 复用原变量(图片通道扩充计数),若不需要图片解析可保留
    uint32_t image_count_mutation_count_ = 0;
    
    // 辅助函数:解析单帧$GPCHC数据
    bool ParseGPCHCFrame(const QString &frameStr, QVector<float> &datas);
};

#endif // GPCHC_H

gpchc.cpp

cpp 复制代码
#include "gpchc.h"
#include <QString>
#include <QStringList>
#include <QRegExp>
#include <QDebug>

GPCHC::GPCHC()
{
}

GPCHC::~GPCHC()
{
}

bool GPCHC::ParseGPCHCFrame(const QString &frameStr, QVector<float> &datas)
{
    datas.clear();

    // 严格校验帧头
    if (!frameStr.startsWith("$GPCHC,")) {
        qDebug() << "无效帧头:" << frameStr;
        return false;
    }

    // 分离校验和(*后的内容)
    int starIndex = frameStr.indexOf('*');
    QString validFramePart;
    if (starIndex != -1) {
        validFramePart = frameStr.left(starIndex);
    } else {
        validFramePart = frameStr; // 无校验和时使用完整帧(容错处理)
    }

    // 修正:使用正确的枚举值(QString::KeepEmptyParts)
    QStringList fields = validFramePart.split(',', QString::KeepEmptyParts);

    // 校验字段数量(至少24个字段,索引0-23)
    if (fields.size() < 24) {
        qDebug() << "字段数量不足,实际:" << fields.size() << ",帧内容:" << validFramePart;
        return false;
    }

    bool convertOk;
    float fieldValue;

    // 按索引提取有效字段(增加越界检查)
    auto appendField = [&](int index) {
        if (index >= fields.size()) {
            qDebug() << "字段索引越界:" << index;
            return;
        }
        QString field = fields[index].trimmed(); // 去除首尾空白字符
        if (field.isEmpty()) return; // 跳过空字段
        fieldValue = field.toFloat(&convertOk);
        if (convertOk) {
            datas.append(fieldValue);
        } else {
            qDebug() << "字段转换失败,索引:" << index << ",值:" << field;
        }
    };

    // 依次提取需要的字段(索引1-23中有效字段)
    appendField(1);   // GPSWeek
    appendField(2);   // GPSTime
    appendField(3);   // Heading
    appendField(4);   // Pitch
    appendField(5);   // Roll
    appendField(6);   // gyro x
    appendField(7);   // gyro y
    appendField(8);   // gyro z
    appendField(9);   // acc x
    appendField(10);  // acc y
    appendField(11);  // acc z
    appendField(14);  // Altitude
    appendField(15);  // Ve
    appendField(16);  // Vn
    appendField(17);  // Vu
    appendField(18);  // V
    appendField(19);  // NSV1
    appendField(20);  // NSV2
    appendField(21);  // Status
    appendField(22);  // Age
    appendField(23);  // Warning

    return !datas.isEmpty();
}

void GPCHC::ProcessingDatas(char *data, int count)
{
    frame_list_.clear();

    if (count <= 0 || data == nullptr) {
        return;
    }

    // 修正:使用fromLatin1替代fromAscii(Qt5.13中fromAscii已废弃)
    QString rawData = QString::fromLatin1(data, count);

    // 修正:使用正确的枚举值(QString::SkipEmptyParts)
    QStringList frameList = rawData.split(QRegExp("\r?\n"), QString::SkipEmptyParts);

    for (const QString &singleFrame : frameList) {
        Frame currentFrame;
        currentFrame.is_valid_ = false;
        currentFrame.image_size_ = 0;
        QVector<float> frameDatas;

        if (ParseGPCHCFrame(singleFrame, frameDatas)) {
            currentFrame.datas_ = frameDatas;
            currentFrame.is_valid_ = true;
        }

        // 修正帧索引计算(基于原始数据中的实际位置)
        int start = rawData.indexOf(singleFrame);
        currentFrame.start_index_ = (start != -1) ? start : 0;
        currentFrame.end_index_ = currentFrame.start_index_ + singleFrame.length() - 1;

        frame_list_.append(currentFrame);
    }
}

gpchc.json

cs 复制代码
{
    "name": "GPCHC",
    "description": "GPCHC数据解析插件,用于解析$GPCHC格式的GPS/IMU数据帧",
    "version": "1.0.0",
    "author": "",
    "pluginId": "VOFA+.Plugin.GPCHC",
    "dataFormat": {
        "frameHeader": "$GPCHC,",
        "frameFooter": "\r\n",
        "checksumEnabled": true,
        "encoding": "ASCII"
    },
    "fields": [
        {"index": 1, "name": "GPSWeek", "unit": "", "description": "GPS周数"},
        {"index": 2, "name": "GPSTime", "unit": "s", "description": "GPS时间"},
        {"index": 3, "name": "Heading", "unit": "°", "description": "航向角"},
        {"index": 4, "name": "Pitch", "unit": "°", "description": "俯仰角"},
        {"index": 5, "name": "Roll", "unit": "°", "description": "横滚角"},
        {"index": 6, "name": "GyroX", "unit": "°/s", "description": "陀螺仪X轴数据"},
        {"index": 7, "name": "GyroY", "unit": "°/s", "description": "陀螺仪Y轴数据"},
        {"index": 8, "name": "GyroZ", "unit": "°/s", "description": "陀螺仪Z轴数据"},
        {"index": 9, "name": "AccX", "unit": "m/s²", "description": "加速度计X轴数据"},
        {"index": 10, "name": "AccY", "unit": "m/s²", "description": "加速度计Y轴数据"},
        {"index": 11, "name": "AccZ", "unit": "m/s²", "description": "加速度计Z轴数据"},
        {"index": 14, "name": "Altitude", "unit": "m", "description": "高度"},
        {"index": 15, "name": "Ve", "unit": "m/s", "description": "东向速度"},
        {"index": 16, "name": "Vn", "unit": "m/s", "description": "北向速度"},
        {"index": 17, "name": "Vu", "unit": "m/s", "description": "天向速度"},
        {"index": 18, "name": "V", "unit": "m/s", "description": "合速度"},
        {"index": 19, "name": "NSV1", "unit": "", "description": "卫星数量1"},
        {"index": 20, "name": "NSV2", "unit": "", "description": "卫星数量2"},
        {"index": 21, "name": "Status", "unit": "", "description": "状态码"},
        {"index": 22, "name": "Age", "unit": "s", "description": "数据龄期"},
        {"index": 23, "name": "Warning", "unit": "", "description": "警告标志"}
    ],
    "minFieldsCount": 24,
    "notes": "解析逻辑遵循$GPCHC帧格式,包含校验和处理及字段越界检查"
}

gpchc.pro

cs 复制代码
# 核心:移除GUI模块,编译为插件库
QT -= gui
TEMPLATE = lib
CONFIG += plugin
TARGET = gpchc  # 插件名称(需与JSON的name一致)

# 导出宏(配合头文件Q_DECL_EXPORT/IMPORT)
DEFINES += GPCHC_LIBRARY

# 源文件/头文件(保留核心引用)
SOURCES += gpchc.cpp
HEADERS += \
    gpchc.h \
    ../shared/dataengineinterface.h

# 头文件搜索路径(确保能找到公共接口)
INCLUDEPATH += ../shared/

# ========== 简化核心:统一输出到构建目录 ==========
# 插件库输出路径:构建目录下的 plugins/dataengines
DESTDIR = $$OUT_PWD/plugins/dataengines
# 临时构建文件(obj等)输出路径(可选,保持整洁)
OBJECTS_DIR = $$OUT_PWD/obj
MOC_DIR = $$OUT_PWD/moc
RCC_DIR = $$OUT_PWD/rcc

# ========== 自动拷贝JSON配置到插件输出目录 ==========
# 确保JSON文件和插件库在同一目录(VOFA+识别插件必需)
json.files = gpchc.json
json.path = $$DESTDIR
COPIES += json

# ========== 移除自动部署逻辑(改为手动拷贝) ==========
# 注释/删除所有win32/macx/unix的INSTALLS部署规则
# 后续只需拷贝 $$OUT_PWD/plugins 整个文件夹到VOFA+的plugins目录即可

二、下载安装QT

【免费下载】 Qt 5.13.2 开源版 Windows x86 安装包-CSDN博客

导入项目发现需要下载VS2017

Visual Studio 2017下载地址和安装教程(图解版)_visual studio 2017官方下载-CSDN博客

安装完成后,即可加载

点击构建即可生成动态链接文件,文件一般位于dataengines/build-xxxx...-release/release

将生成的文件拷贝到vofa对应位置

重新启动vofa,选中自己的解析,即可

相关推荐
用户805533698035 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner5 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz10 天前
QML Hello World 入门示例
qt
xcyxiner13 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner14 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner14 天前
DicomViewer (添加模型类)3
qt
xcyxiner15 天前
DicomViewer (目录调整) 2
qt
xcyxiner15 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00617 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术17 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript