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,选中自己的解析,即可

相关推荐
郝学胜-神的一滴1 小时前
Qt自定义TabWidget:实现左侧标签与水平文本布局
开发语言·c++·qt·程序人生
计算机程序设计小李同学1 小时前
基于JavaServer Pages(JSP)技术开发的食谱分享平台
java·开发语言
cjp5602 小时前
019.C#管道服务,两软件间用json数据交互
开发语言·c#·json
我是一只小青蛙8882 小时前
C++模板进阶技巧全解析
java·开发语言
燃于AC之乐2 小时前
C/C++内存管理核心解析:分布、管理方式与定位new应用
开发语言·c++·内存管理
写代码的【黑咖啡】3 小时前
Python中的JSON处理(标准库)
开发语言·python·json
Elias不吃糖10 小时前
Java Lambda 表达式
java·开发语言·学习
guygg8810 小时前
一级倒立摆MATLAB仿真程序
开发语言·matlab
情缘晓梦.10 小时前
C语言指针进阶
java·开发语言·算法