feat: svl, sww, ads

This commit is contained in:
anjingyu 2024-04-14 23:28:33 +08:00
parent 63930a3d9b
commit 12b922053c
478 changed files with 236828 additions and 0 deletions

105
ads/.gitignore vendored Normal file
View File

@ -0,0 +1,105 @@
# AdMake
.build/
bin/
lib/
# C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# C++
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# CMake
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

58
ads/CMakeLists.txt Normal file
View File

@ -0,0 +1,58 @@
cmake_minimum_required (VERSION 3.15)
include (declare)
enable_msvc_mt_md ()
project (dcads)
# set (ADMAKE_ENABLE_EXCEPTION ON)
# set (ADMAKE_DISABLE_ADDRESS_SANITIZER ON)
set (ADMAKE_IGNORE_VCPKG ON)
include (admake)
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
include_directories (
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/source")
if (DEFINED ADMAKE_BUILD_TEST)
file (GLOB_RECURSE TEST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.c")
add_executable (${TARGET_NAME}_test ${TEST_SRC})
add_dependencies (${TARGET_NAME}_test ${TARGET_NAME})
target_link_libraries (${TARGET_NAME}_test ${TARGET_NAME})
else ()
file (GLOB_RECURSE CONTROL_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/source/control/*.c")
file (GLOB_RECURSE CONTROL_APP_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/source/control_app/*.c")
extract_version (
FILE ${CMAKE_CURRENT_SOURCE_DIR}/source/version.c
PREFIX "DCADS"
MAJOR OUTPUT_MAJOR
MINOR OUTPUT_MINOR
PATCH OUTPUT_PATCH)
set (DCADS_VERSION "${OUTPUT_MAJOR}.${OUTPUT_MINOR}.${OUTPUT_PATCH}")
add_library (${TARGET_NAME}_OBJ OBJECT ${CONTROL_SRC})
target_link_libraries (${TARGET_NAME}_OBJ
INTERFACE admake::disable_warnings
PRIVATE admake::disable_warnings)
target_set_mt (${TARGET_NAME}_OBJ)
add_library (${TARGET_NAME} STATIC $<TARGET_OBJECTS:${TARGET_NAME}_OBJ>)
add_library (${TARGET_NAME}_SO SHARED $<TARGET_OBJECTS:${TARGET_NAME}_OBJ>)
set_target_properties (${TARGET_NAME}_SO PROPERTIES
OUTPUT_NAME "dcads")
add_executable (main ${CONTROL_APP_SRC})
target_link_libraries (main PRIVATE ${TARGET_NAME})
endif ()

4
ads/README.md Normal file
View File

@ -0,0 +1,4 @@
# ADS
A simple ADS system for learning.

View File

@ -0,0 +1,3 @@
#pragma once

View File

@ -0,0 +1,77 @@
#pragma once
#include <stdint.h>
struct PathPoint
{
/// \brief
/// Vehicle coordinate system - Right-Forward-Up(RFU)
/// z-axis - points up through the roof of the vehicle perpendicular to the ground;
/// y-axis - points out the front of the vehicle in the direction of travel;
/// x-axis - points out the right-hand side of the vehicle when facing forward;
/// unit: m.
double z;
double y;
double x;
/// \brief
/// Direction on the y-x plane, unit: degree, range: [0, 360)
double theta;
/// \brief
/// accumulated distance from beginning of the path, unit: m
double s;
/// \brief Curvature of a point.
double kappa;
/// \brief Derivative of kappa w.r.t s.
double dkappa;
/// \brief Derivative of derivative of kappa w.r.t s.
double ddkappa;
/// \brief The point required by lat controller
int lat_use_point;
};
struct TrajectoryPoint
{
/// \brief Linear velocity, unit: m/s
double velocity;
/// \brief Linear acceleration, unit: m/s^2
double acc;
/// \brief Realtive time form beginning of the trajectory, unit: s
double relative_ts;
/// \brief Path point information
PathPoint path_point;
};
struct RealtimeTrajectory
{
/// \brief Latitude of device, unit: degrees, range: (-90, 90]
double latitude;
/// \brief Longitude of device, unit: degrees, range: (-180, 180]
double longitude;
/// \brief Central-median on the map, unit: degrees, range: (-180, 180]
double centralMedian;
/// \brief Vehicle trajectory planning in this heading, positive is North to East, unit: degrees, range: [0, 360).
double heading;
/// \brief Send trajectory time, unit: s
double send_ts;
/// \brief Receive trajectory time, unit: s
double recv_ts;
/// \brief The information of trajectory points.
struct TrajectoryPoint *trajectory;
size_t trajectory_size;
}

View File

@ -0,0 +1,46 @@
#pragma once
struct VehicleParams
{
/// \brief The wheelbase, unit: m
double wheelbase;
/// \brief The maximum speed, unit: m/s
double max_speed;
/// \brief The minimum speed, unit: m/s
double min_speed;
/// \brief The maximum steering angle of the front wheels, unit: degree
double max_steer_angle;
/// \brief The minimum steering angle of the front wheels, unit: degree
double min_steer_angle;
/// \brief The maximum acceleration of the vehicle, unit: m/s^2
double max_acc;
/// \brief The minimum acceleration of the vehicle, unit: m/s^2
double min_acc;
/// \brief The transmission coefficient between steering wheel and front wheel.
double wheel_coeff;
/// \brief Front tire cornering stiffness, unit: N/rad
double fcs;
/// \brief Rear tire cornering stiffness, unit: N/rad
double rcs;
/// \brief Mass, unit: kg
double mass;
/// \brief Distance from the center of front wheel to the CoM(center of mass), unit: m
double dis_front;
/// \brief Distance from the center of rear wheel to the CoM(center of mass), unit: m
double dis_rear;
/// \brief Moment of inertia (rotational inertia), unit: kg * m^2
double j;
};

View File

@ -0,0 +1,92 @@
#pragma once
struct VehicleChassisRealtimeFeedback
{
/// \brief The timestamp of this message, unit: s
double ts;
/// \brief Longitudinal speed, unit: m/s
double longitudinal_speed;
/// \brief Lateral speed, unit: m/s
double lateral_speed;
/// \brief Front wheel angle, unit: degree
double front_wheel_angle;
/// \brief Steer wheel angle, unit: degree
double steer_wheel_angle;
/// \brief Longitudinal acceleration, unit: m/s^2
double longitudinal_acc;
/// \brief Laterial acceleration, unit: m/s^2
double laterial_acc;
};
struct VehiclePosePositionRealtimeFeedback
{
/// \brief The absolute GMT timestamp of this message, uint: s
double abs_ts;
/// \brief The timestamp of this message, unit: s
double ts;
/// \brief Latitude of the device, unit: degree, range: (-90, 90]
double latitude;
/// \brief longitude of the device, unit: degree, range: (-180, 180]
double longitude;
/// \brief Altitude of the device, unit: m
double altitude;
/// \brief Speed of the device, unit: m/s
double speed;
/// \brief Roll angle of the device, unit: degree, range: (-180, 180]
double roll;
/// \brief Pitch angle of the device, unit: degree, range: (-180, 180]
double pitch
/// \brief Yaw angle of the device, unit: degree, range: (0, 360]
double yaw;
/// \brief Northbound velocity, the direction always point to the real north, parallel to the warp, unit: m/s
double north_velocity;
/// \brief Eastbound velocity, the direction always point to the real east, parallel to the weft, unit: m/s
double east_velocity;
/// \brief Upbound velocity, unit: m/s
///
/// \remarks
/// \p north_velocity, \p east_velocity, and \p up_velocity constitude the standard right-hand coordinate system.
double up_velocity;
/// \brief Angular velocity around the longitudianl axis, unit: deg/s
double x_angluar_velocity;
/// \brief Angular velocity around the laterial axis, unit: deg/s
double y_angluar_velocity;
/// \brief Angular velocity around the down axis, unit: deg/s
double z_angluar_velocity;
/// \brief Longitudinal acceleration, unit: m/s^2
double longitudinal_acc;
/// \brief Laterial acceleration, unit: m/s^2
double laterial_acc;
/// \brief Down acceleration, unit: m/s^2
double down_acc;
};
struct VehicleRealtimeFeedback
{
VehicleChassisRealtimeFeedback chassis;
VehiclePosePositionRealtimeFeedback pp;
};

6
ads/source/version.c Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#define DCADS_MAJOR_VERSION 0
#define DCADS_MINOR_VERSION 0
#define DCADS_PATCH_VERSION 1

244
qdataanalyzer/.clang-format Normal file
View File

@ -0,0 +1,244 @@
---
# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
Language: Cpp
# BasedOnStyle: Google
# 访问说明符的偏移(public private)
AccessModifierOffset: -4
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
AlignAfterOpenBracket: Align
# 连续的宏定义时,对齐所有的宏定义的名称.
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
# 连续的赋值时,对齐所有的等号
AlignConsecutiveAssignments: AcrossComments
# 连续声明时, 对齐所有声明的变量名
AlignConsecutiveDeclarations: AcrossComments
# 左对齐换行(使用反斜杠换行)的反斜杠
AlignEscapedNewlines: Left
# 换行的时候对齐操作符
AlignOperands: Align
# 对齐连续的尾随的注释
AlignTrailingComments: true
# 如果函数调用或花括号初始化器列表不适合一行, 则允许将所有参数放到下一行.
AllowAllArgumentsOnNextLine: true
# 允许函数声明的所有参数在放在下一行
AllowAllParametersOfDeclarationOnNextLine: false
# 允许短的块放在同一行
AllowShortBlocksOnASingleLine: false
# 允许短的case标签放在同一行
AllowShortCaseLabelsOnASingleLine: false
# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中, 空函数), All
AllowShortFunctionsOnASingleLine: None
# 是否允许短if单行 If true, if (a) return; 可以放到同一行
AllowShortIfStatementsOnASingleLine: false
# 允许短的循环保持在同一行
AllowShortLoopsOnASingleLine: false
# lambda是否可以放在一行 (None/Empty/All)
AllowShortLambdasOnASingleLine: None
# 总是在定义返回类型后换行(deprecated)
AlwaysBreakAfterDefinitionReturnType: None
# AllDefinitions(所有的定义, 不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
AlwaysBreakAfterReturnType: None
# 总是在多行string字面量前换行
AlwaysBreakBeforeMultilineStrings: true
# 总是在template声明后换行
AlwaysBreakTemplateDeclarations: Yes
# false表示函数实参要么都在同一行, 要么都各自一行
BinPackArguments: true
# false表示所有形参要么都在同一行, 要么都各自一行
BinPackParameters: true
# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义, 与Attach类似),
# Mozilla(除枚举、函数、记录定义, 与Attach类似), Stroustrup(除函数定义、catch、else, 与Attach类似),
# Allman(总是在大括号前换行), GNU(总是在大括号前换行, 并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom
# 注:这里认为语句块也属于函数
BreakBeforeBraces: Custom
# 大括号换行, 只有当BreakBeforeBraces设置为Custom时才有效
BraceWrapping:
# 命名空间定义后面
AfterNamespace: false
# class定义后面
AfterClass: true
# 控制语句后面
AfterControlStatement: true
# enum定义后面
AfterEnum: false
# 函数定义后面
AfterFunction: true
# struct定义后面
AfterStruct: false
# union定义后面
AfterUnion: false
# extern定义后面
AfterExternBlock: false
# catch之前
BeforeCatch: false
# else之前
BeforeElse: false
# lambda之前
BeforeLambdaBody: false
BeforeWhile: false
# 缩进大括号
IndentBraces: false
# false 时, 空方法体 {} 放在一行
SplitEmptyFunction: false
# false 时, 空记录(例如, 类, 结构或联合){} 放在一行
SplitEmptyRecord: false
# false 且 AfterNamespace == true 时 空命名空间体可放到一行: {}
SplitEmptyNamespace: false
# 控制语句之前 缩进大括号 (if/ for/ while/ switch/..) (Never/MultiLine/Always)
AfterControlStatement: Never
# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
BreakBeforeBinaryOperators: NonAssignment
# 继承时 BeforeColon ‘:’前换行
BreakInheritanceList: BeforeComma
# 三元运算符 true 符号前换行 false 符号后换行
BreakBeforeTernaryOperators: true
# 在构造函数的初始化列表的逗号前换行
BreakConstructorInitializers: BeforeComma
# 允许在格式化时中断字符串文字
BreakStringLiterals: true
# 每行字符的限制0表示没有限制
ColumnLimit: 100
# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变
CommentPragmas: "^ IWYU pragma:"
# true连续的名称空间声明将位于同一行. 如果为false则在新行上声明每个名称空间.
CompactNamespaces: false
# 构造函数的初始化列表要么都在同一行,要么都各自一行
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# 构造函数的初始化列表的缩进宽度
ConstructorInitializerIndentWidth: 4
# 延续的行的缩进宽度
ContinuationIndentWidth: 4
# 去除C++11的列表初始化的大括号{后和}前的空格
Cpp11BracedListStyle: true
# 继承最常用的指针和引用的对齐方式
DerivePointerAlignment: false
# 关闭格式化
DisableFormat: false
# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental)
ExperimentalAutoDetectBinPacking: false
# true 自动检测补全命名空间尾部的大括号
FixNamespaceComments: true
# 需要被解读为foreach循环而不是函数调用的宏
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
# include 分组排序方式 Preserve(按组排序) Merge(合并成一组排序)Regroup(按 IncludeCategories 重新分组排序)
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^stdafx\.h$'
Priority: 0
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: "^<.*"
Priority: 2
- Regex: ".*"
Priority: 3
# 指定在file-to-main-include映射中被允许的后缀的正则表达式
IncludeIsMainRegex: "([-_](test|unittest))?$"
# 缩进case标签
IndentCaseLabels: false
# 预处理代码缩进样式. None(不缩进)AfterHash(缩进)
IndentPPDirectives: None
# 缩进宽度
IndentWidth: 4
# 函数在返回类型后换行,是否缩进函数名
IndentWrappedFunctionNames: false
# 保留在块开始处的空行(OC 没用)
KeepEmptyLinesAtTheStartOfBlocks: false
# 开始一个块的宏的正则表达式
MacroBlockBegin: ""
# 结束一个块的宏的正则表达式
MacroBlockEnd: ""
# 连续最大空行数
MaxEmptyLinesToKeep: 1
# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
NamespaceIndentation: None
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
# 指针和引用的对齐: Left(int* a;), Right(int *a;), Middle(int * a;)
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- "c++"
- "C++"
CanonicalDelimiter: ""
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ""
BasedOnStyle: google
# 允许重新排版注释
ReflowComments: true
# 允许排序#include,首字母排序
SortIncludes: true
# true using 自动排序
SortUsingDeclarations: true
# 在C风格类型转换后添加空格
SpaceAfterCStyleCast: false
# template 关键字后添加空格
SpaceAfterTemplateKeyword: false
# false 移除 = += 两侧的空格
SpaceBeforeAssignmentOperators: true
# false 删除case中:前的空格
SpaceBeforeCaseColon: false
# 初始化 c++ 11 对象的前面空格
SpaceBeforeCpp11BracedList: false
# 构造函数:前加空格
SpaceBeforeCtorInitializerColon: true
# 继承的:前面加空格
SpaceBeforeInheritanceColon: true
# 开圆括号之前添加一个空格: Never, ControlStatements, Always
SpaceBeforeParens: ControlStatements
# false 清除 for 循环:前面的空格 for (auto v : values) {}
SpaceBeforeRangeBasedForLoopColon: true
# 在空的圆括号中添加空格
SpaceInEmptyParentheses: false
# 在尾随的评论前添加的空格数(只适用于//)
SpacesBeforeTrailingComments: 1
# 在尖括号内部前后添加空格 < int >
SpacesInAngles: false
# 快捷数组 内部加空格 [ 1, 2, 3 ]; :前加空格 f({a : 1, b : 2, c : 3});
SpacesInContainerLiterals: true
# 在C风格类型转换的括号中添加空格
SpacesInCStyleCastParentheses: false
# 在圆括号的(后和)前添加空格
SpacesInParentheses: false
# 在方括号的[后和]前添加空格lamda表达式和未指明大小的数组的声明不受影响
SpacesInSquareBrackets: false
# 标准: Cpp03, Cpp11, Auto
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
# tab宽度
TabWidth: 4
# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
UseTab: Never

57
qdataanalyzer/.gitignore vendored Normal file
View File

@ -0,0 +1,57 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.so.*
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
moc_*.h
qrc_*.cpp
ui_*.h
*.qmlc
*.jsc
Makefile*
*build-*
*.qm
*.prl
# Qt unit tests
target_wrapper.*
# QtCreator
*.autosave
# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCreator CMake
CMakeLists.txt.user*
# QtCreator 4.8< compilation database
compile_commands.json
# QtCreator local machine specific files for imported projects
*creator.user*
*_qmlcache.qrc
# mdbook
book/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
cmake_minimum_required (VERSION 3.16)
project (qdataanalyzer VERSION 1.0.0 LANGUAGES CXX)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (TARGET_NAME "${CMAKE_PROJECT_NAME}")
find_package (Qt6 REQUIRED COMPONENTS Core PrintSupport Widgets)
qt_standard_project_setup ()
qt_add_executable (${TARGET_NAME} main.cpp)
# Thirdparty libraries
get_filename_component (THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rd-party")
file (GLOB QCUSTOMPLOT_SRC "${THIRDPARTY_DIR}/qcustomplot/source/*.cpp")
target_include_directories (${TARGET_NAME} PRIVATE "${THIRDPARTY_DIR}/qcustomplot/include")
target_sources (${TARGET_NAME} PRIVATE ${QCUSTOMPLOT_SRC})
target_link_libraries (${TARGET_NAME} PRIVATE Qt6::Core Qt6::Widgets Qt6::PrintSupport)
set_target_properties (${TARGET_NAME} PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON)
# Resource files
file (GLOB RESOURCE_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/source/qrc/*.gif"
"${CMAKE_CURRENT_SOURCE_DIR}/source/qrc/*.png")
qt_add_resources (${TARGET_NAME} imageresources
PREFIX "/images"
FILES ${RESOURCE_SRC}
)
file (GLOB
"${CMAKE_CURRENT_SOURCE_DIR}/source/qrc/*.ts")
qt_add_translations (${TARGET_NAME}
TS_FILES qdataanalyzer_en.ts qdataanalyzer_zh.ts)

93
qdataanalyzer/README.md Normal file
View File

@ -0,0 +1,93 @@
# qdataanalyzer
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://jihulab.com/donkeyws/qdataanalyzer.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://jihulab.com/donkeyws/qdataanalyzer/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

View File

@ -0,0 +1,6 @@
[book]
authors = ["donkey"]
language = "en"
multilingual = false
src = "src"
title = "QDataAnalyzer Documentation"

View File

View File

@ -0,0 +1,17 @@
# Summary
- [Introduction](README.md)
# User Guide
- [Installation](guide/installation.md)
- [Basic Operations](guide/basic.md)
- [Advanced Features](guide/advanced.md)
# Reference Guide
- [Command Line Tool](cli/README.md)
- [logger](cli/logger.md)
- [player](cli/player.md)
- [For Developer](dev/README.md)
- [Add New Parser](dev/new_parser.md)

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Installer>
<Name>QDataAnalyzer</Name>
<Version>0.1.0</Version>
<Title>QDataAnalyzer Installer</Title>
<Publisher>Donkey</Publisher>
<StartMenuDir>QDataAnalyzer</StartMenuDir>
<TargetDir>@ApplicationsDir@/QDataAnalyzer</TargetDir>
<CreateLocalRepository>false</CreateLocalRepository>
<RunProgram>@TargetDir@/qda</RunProgram>
<StartMenuDir>QDataAnalyzer</StartMenuDir>
</Installer>

View File

@ -0,0 +1,47 @@
#!pwsh
#
# Download the latest vc_redist.x64.exe
#
# Author: donkey <anjingyu_ws@foxmail.com>
# For 2015-2022
$DownloadUrl = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
function DownloadTo
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)][String] $Url,
[Parameter(Mandatory=$False,Position=2,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)][String] $DstDir
)
if ("" -eq $DstDir)
{
$DstDir = Get-Location
}
# If it is a directory
if (Test-Path -PathType "Container" $DstDir)
{
# Remote-Item -Recurse -Force <Directory>
# New-Item -ItemType "directory" -Path "${DstDir}"
$DstDir = Join-Path $DstDir $(Split-Path "${Url}" -Leaf)
}
else
{
$_TmpDir = $(Split-Path "${DstDir}")
New-Item -ItemType "directory" -Path "${_TmpDir}"
}
if (-Not (Test-Path $DstDir))
{
$_StartTime = Get-Date
(New-Object System.Net.WebClient).DownloadFile($Url, $DstDir)
Write-Host "Time taken: $((Get-Date).Subtract($_StartTime).Seconds) second(s)"
}
return "$DstDir"
}
DownloadTo "$DownloadUrl"

View File

@ -0,0 +1,62 @@
#!/usr/bin/env bash
#
# Download vc_redist.x64.exe
#
# Author: donkey <anjingyu_ws@foxmail.com>
function download_to()
{
if [ $# -lt 1 ]; then
error "Need at least one argument, <url> [dir or path] [force overwrite]."
return
fi
if ! command -v "curl" 1>/dev/null 2>&1; then
echo "The command line tool 'curl' is required, please install it."
exit -1
fi
local _URL=$1
local _FPATH="${PWD}"
local _FNAME=$(basename "$_URL")
local _FORCE="false"
if [ $# -gt 1 ]; then
_FPATH=$2
fi
if [ $# -gt 2 ]; then
_FORCE="$3"
fi
# If the output is not a directory, assume you want to download file as other name.
if [ ! -d "$_FPATH" ]; then
_FNAME=$(basename "$_FPATH")
_FPATH=$(dirname "$_FPATH")
fi
pushd "$_FPATH" 1>/dev/null 2>&1
# If the file has been existent, ignore
if [ ! -f $_FNAME ] || [ "$_FORCE" = "true" ]; then
echo "Downloading ${green}${_FNAME}${normal} into ${yellow}${_FPATH}${normal} ..."
if ! curl --location --progress-bar --fail -L "${_URL}" -o "${_FNAME}"; then
echo "Download failed. Check that the release/filename are correct."
exit 1
fi
fi
popd 1>/dev/null 2>&1
echo "$_FNAME"
}
function main()
{
local _DOWNLOAD_URL="https://aka.ms/vs/17/release/vc_redist.x64.exe"
download_to "$_DOWNLOAD_URL"
}
main "$@"

View File

@ -0,0 +1,30 @@
#!/pwsh
#
# Create package via QtIFW command line tools
#
# Author: donkey <anjingyu_ws@foxmail.com>
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
$QtIfwBinCreator = ""
if (Test-Path env:QTIFWDIR)
{
$QtIfwBinCreator = Join-Path "$env:QTIFWDIR" "bin" "binarycreator.exe"
if (-Not (Test-Path "$QtIfwBinCreator")) {
Write-Host "The binarycreator is not existent: $QtIfwBinCreator"
exit -1
}
}
elseif ($null -eq (Get-Command "binarycreator" -ErrorAction SilentlyContinue))
{
Write-Host "Failed to find binarycreator, please install QtIFW firstly."
exit -1
}
else
{
$QtIfwBinCreator = "binarycreator.exe"
}
# Run the install command
& $QtIfwBinCreator --offline-only -c "$PSScriptRoot\config\config.xml" -p "$PSScriptRoot\packages" "$PSScriptRoot\installer.exe"

View File

@ -0,0 +1,138 @@
// Utility function like QString QDir::toNativeSeparators(const QString & pathName) [static]
var Dir = new function () {
this.toNativeSparator = function (path) {
if (systemInfo.productType == "windows") {
return path.replace(/\//g, '\\');
}
return path;
}
};
function Component() {
component.loaded.connect(this, Component.prototype.installerLoaded);
installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
if (systemInfo.productType == "windows") {
installer.installationStarted.connect(this, Component.prototype.installVCRedist);
}
}
Component.prototype.createOperations = function() {
component.createOperations();
if (systemInfo.productType === "windows") {
component.addOperation("CreateShortcut",
"@TargetDir@/qda.exe",
"@StartMenuDir@/QDataAnalyzer.lnk",
"workingDirectory=@TargetDir@");
var configPath = installer.environmentVariable("LOCALAPPDATA");
try {
component.addOperation("Mkdir", configPath + "/QDataAnalyzer/Config");
} catch (err) {
QMessageBox.warning("copy.config", "Copy Config Mkdir", "Failed to mkdir: " + configPath, QMessageBox.OK);
}
try {
component.addOperation("CopyDirectory", "@TargetDir@/Config", configPath + "/QDataAnalyzer/Config");
} catch (err) {
QMessageBox.warning("copy.config", "Copy Config", "Failed to copy the default configuration files into LocalAppData.", QMessageBox.OK);
}
}
}
Component.prototype.installVCRedist = function () {
var registryVC2017x64 = installer.execute("reg", new Array("QUERY", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64", "/v", "Installed"))[0];
var doInstall = false;
if (!registryVC2017x64) {
doInstall = true;
} else {
var bld = installer.execute("reg", new Array("QUERY", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64", "/v", "Bld"))[0];
var elements = bld.split(" ");
bld = parseInt(elements[elements.length - 1]);
if (bld < 30139) {
doInstall = true;
}
}
if (doInstall) {
QMessageBox.information("vcRedist.install", "Install VS Redistributables", "The application requires Visual Studio 2017 Redistributables, Please follow the steps to install it now.", QMessageBox.OK);
var dir = installer.value("TargetDir");
installer.execute(dir + "/vc_redist.x64.exe", "/norestart", "/passive");
}
}
// Called as soon as the component was loaded
Component.prototype.installerLoaded = function()
{
if (installer.addWizardPage(component, "TargetWidget", QInstaller.TargetDirectory)) {
var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
if (widget != null) {
widget.targetDirectory.textChanged.connect(this, Component.prototype.targetChanged);
widget.targetChooser.clicked.connect(this, Component.prototype.chooseTarget);
widget.windowTitle = "Installation Folder";
widget.targetDirectory.text = Dir.toNativeSparator(installer.value("TargetDir"));
}
}
}
// Callback when one is clicking on the button to select where to install your application
Component.prototype.chooseTarget = function () {
var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
if (widget != null) {
var newTarget = QFileDialog.getExistingDirectory("Choose your target directory.", widget.targetDirectory.text);
if (newTarget != "") {
widget.targetDirectory.text = Dir.toNativeSparator(newTarget);
}
}
}
Component.prototype.targetChanged = function (text) {
var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
if (widget != null) {
if (text != "") {
widget.complete = true;
installer.setValue("TargetDir", text);
if (installer.fileExists(text + "/components.xml")) {
var warning = "<font color='red'>" + qsTr("A previous installation exists in this folder. If you wish to continue, everything will be overwritten.") + "</font>";
widget.labelOverwrite.text = warning;
} else {
widget.labelOverwrite.text = "";
}
return;
}
widget.complete = false;
}
}
// For updating
// Component.prototype.targetChanged = function (text) {
// var widget = gui.currentPageWidget(); // get the current wizard page
// var install = false;
//
// if (widget != null) {
// if (text != "") {
// if (installer.fileExists(text + "/components.xml")) {
// var result = QMessageBox.question("quit.question", "Installer", "Do you want to overwrite previous installation?",
// QMessageBox.Yes | QMessageBox.No);
// if (result == QMessageBox.Yes) {
// install = true;
// }
// } else {
// install = true;
// }
// } else {
// install = false;
// }
// }
//
// widget.complete = install;
//
// if (install) {
// installer.setValue("TargetDir", text);
// }
// }

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Package>
<DisplayName>QDataAnalyzer Core</DisplayName>
<Description>Install core component</Description>
<Version>0.1.0</Version>
<ReleaseDate>2023-10-31</ReleaseDate>
<Default>script</Default>
<Script>install.qs</Script>
<ForcedInstallation>true</ForcedInstallation>
<ForcedUpdate>true</ForcedUpdate>
<Essential>true</Essential>
<UserInterfaces>
<UserInterface>targetwidget.ui</UserInterface>
</UserInterfaces>
</Package>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TargetWidget</class>
<widget class="QWidget" name="TargetWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Please specify the folder where Miam-Player will be installed.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="targetDirectory"/>
</item>
<item>
<widget class="QToolButton" name="targetChooser"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="labelOverwrite"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,123 @@
#include "ConstBuffer.h"
ConstBuffer::ConstBuffer(unsigned long bufLength, bool bReadWait, bool bWriteWait,
unsigned short frameLength)
: m_iBufferLength(bufLength)
, m_pBuffer(nullptr)
, m_bIsOneCycle(true)
, m_iReadIndex(0)
, m_iWriteIndex(0)
, m_bReadWait(bReadWait)
, m_bWriteWait(bWriteWait)
, m_iFrameLength(frameLength)
{
m_pBuffer = new unsigned char[bufLength];
}
ConstBuffer::~ConstBuffer()
{
if (m_pBuffer != nullptr) {
delete m_pBuffer;
}
}
// 写数据
int ConstBuffer::write(unsigned char* data, unsigned short length)
{
if (length > m_iBufferLength) {
// 写入帧长不满足要求
return -1;
}
// if (!verifyFrameLength(data, length)) {
// //帧长不匹配
// return -2;
//}
/*QByteArray byteArr((char*)data, length);*/
QMutexLocker locker(&m_mutex);
while (IsFull(length)) { // 当读写指针在同一周期内时
if (m_bWriteWait) {
// add wait here,to wait for sufficient buf to write
m_condWrite.wait(&m_mutex);
} else {
return 0;
}
}
for (int i = 0; i < length; i++) {
m_pBuffer[m_iWriteIndex] = data[i]; // 想缓存中写入数据
m_iWriteIndex++;
if (m_iWriteIndex == m_iBufferLength) { // 当缓存已经写满数据
m_iWriteIndex = 0;
m_bIsOneCycle = false;
}
}
if (m_bWriteWait) {
m_condRead.wakeOne();
}
return length;
}
// 读数据
unsigned short ConstBuffer::read(unsigned char* data, unsigned short length)
{
if (m_iFrameLength > length) { // 读取数据长度小于帧长
return -1;
}
{
QMutexLocker locker(&m_mutex);
// 当帧长为空时
while (IsEmpty(m_iFrameLength)) {
if (m_bReadWait) {
// add wait here, to wait for sufficient data to read
m_condRead.wait(&m_mutex);
} else {
return 0;
}
}
for (int i = 0; i < m_iFrameLength; i++) {
data[i] = m_pBuffer[m_iReadIndex];
m_iReadIndex++;
if (m_iReadIndex >= m_iBufferLength) {
m_iReadIndex -= m_iBufferLength;
m_bIsOneCycle = true;
}
}
}
if (m_bReadWait) {
m_condWrite.wakeOne();
}
return m_iFrameLength;
}
void ConstBuffer::clear()
{
m_bIsOneCycle = true;
m_iReadIndex = 0;
m_iWriteIndex = 0;
}
// 验证帧长
bool ConstBuffer::verifyFrameLength(unsigned char* buf, unsigned short length)
{
if (length != m_iFrameLength) {
return 0;
}
return 1;
}
// memory is full, no place to write
// two different situations: readIndex and writeIndex is in one cycle or not
// one argument: the length of frame
bool ConstBuffer::IsFull(unsigned short length)
{
if (m_bIsOneCycle) {
return m_iWriteIndex + length > m_iReadIndex + m_iBufferLength;
}
return m_iWriteIndex + length > m_iReadIndex;
}
// memory is empty, no data to read
// two different situations: readIndex and writeIndex is in one cycle or not
bool ConstBuffer::IsEmpty(unsigned short length)
{
if (m_bIsOneCycle == true) {
return m_iReadIndex + length > m_iWriteIndex;
}
return m_iReadIndex + length >= m_iBufferLength + m_iWriteIndex;
}

View File

@ -0,0 +1,49 @@
#pragma once
#include "IBuffer.h"
#include <QByteArray>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
class ConstBuffer : public IBuffer
{
public:
// 构造函数包含四个参数:
// 1. 缓冲区长度
// 2. 是否等待读数据
// 3. 是否等待写数据
// 4. 固定帧长度
explicit ConstBuffer(unsigned long bufLength, bool readWait, bool writeWait,
unsigned short frameLength);
~ConstBuffer();
int write(unsigned char* data, unsigned short length); // 写数据
unsigned short read(unsigned char* data, unsigned short length); // 读数据
void clear();
private:
unsigned char* m_pBuffer;
unsigned long m_iBufferLength; // 缓冲区长度
unsigned short m_iFrameLength; // 帧长
unsigned long m_iReadIndex; // 读索引
unsigned long m_iWriteIndex; // 写索引
QMutex m_mutex;
bool m_bIsOneCycle; // 是否在一圈内
bool m_bReadWait; // 读等待
bool m_bWriteWait; // 写等待
QWaitCondition m_condRead;
QWaitCondition m_condWrite;
private:
inline unsigned short GetFrameLength() override
{
return m_iFrameLength;
}
bool verifyFrameLength(unsigned char* buf, unsigned short length); // 验证帧长
bool IsFull(unsigned short length) override;
bool IsEmpty(unsigned short length) override;
};

View File

@ -0,0 +1,21 @@
#pragma once
#include "MacroInfo.h"
class IBuffer
{
public:
IBuffer()
{}
~IBuffer()
{}
public:
virtual unsigned short read(unsigned char* buf, unsigned short length) = 0; // 读取数据
virtual int write(unsigned char* buf, unsigned short length) = 0; // 写入数据
virtual void clear() = 0; // 清空数据
private:
virtual unsigned short GetFrameLength() = 0;
virtual bool verifyFrameLength(unsigned char* buf, unsigned short length) = 0; // 验证帧长
virtual bool IsFull(unsigned short length) = 0; // 是否填满
virtual bool IsEmpty(unsigned short length) = 0; // 是否为空
};

View File

@ -0,0 +1,134 @@
#include "VarBuffer.h"
VarBuffer::VarBuffer(unsigned long length, bool bReadWait, bool bWriteWait)
: m_iBufferLength(length)
, m_pBuffer(nullptr)
, m_iReadIndex(0)
, m_iWriteIndex(0)
, m_bIsOneCycle(true)
, m_bReadWait(bReadWait)
, m_bWriteWait(bWriteWait)
{
m_pBuffer = new unsigned char[length];
}
VarBuffer::~VarBuffer()
{
if (nullptr != m_pBuffer)
delete m_pBuffer;
}
// detect the frame length, frame length is an unsigned short
unsigned short VarBuffer::GetFrameLength()
{
int diff = m_iBufferLength - m_iReadIndex;
if (diff >= 6 && m_pBuffer[m_iReadIndex] == 0xEB && m_pBuffer[m_iReadIndex + 1] == 0x90)
return m_pBuffer[m_iReadIndex + 5] * 256 + m_pBuffer[m_iReadIndex + 4];
else if (diff < 6 && m_pBuffer[m_iReadIndex % m_iBufferLength] == 0xEB
&& m_pBuffer[(m_iReadIndex + 1) % m_iBufferLength] == 0x90)
return m_pBuffer[(m_iReadIndex + 5) % m_iBufferLength] * 256
+ m_pBuffer[(m_iReadIndex + 4) % m_iBufferLength];
else
throw "GET FRAME LENGTH ERROR: didn't read the right frame head";
}
// verify the to-be-written frame length, frame length is an unsigned short
bool VarBuffer::verifyFrameLength(unsigned char* buf, unsigned short length)
{
if (buf[0] != 0xEB || buf[1] != 0x90) {
return false;
}
if (*(reinterpret_cast<unsigned short*>(buf + VarHeadLength)) != length) {
// printf("%x, %x, %x \n", buf[2], buf[3]*256, length);
return false;
}
return true;
}
// read data from memory to an output buffer
// two arguments: the point and the length of output buffer
// correct: return frame length
// error: return -1
unsigned short VarBuffer::read(unsigned char* buf, unsigned short length)
{
int frameLength = 0;
{
QMutexLocker locker(&m_mutex);
while (IsEmpty(0)) {
if (m_bReadWait) {
// add wait here, to wait for sufficient data to read
m_condRead.wait(&m_mutex);
} else {
return 0;
}
}
frameLength = GetFrameLength();
if (frameLength > length) {
// throw "READ ERROR: the frame data length is larger than output data buffer";
return -1;
}
for (int i = 0; i < frameLength; i++) {
buf[i] = m_pBuffer[m_iReadIndex];
m_iReadIndex++;
if (m_iReadIndex >= m_iBufferLength) {
m_iReadIndex = 0;
m_bIsOneCycle = true;
}
}
}
m_condWrite.wakeOne();
return frameLength;
}
// write one frame data to memory
// one argument: the length of frame to write in (unsigned short)
int VarBuffer::write(unsigned char* buf, unsigned short length)
{
if (length < MIN_FRAME_LENGTH || length > m_iBufferLength) {
return -1;
}
{
QMutexLocker locker(&m_mutex);
while (IsFull(length)) {
if (m_bWriteWait) {
// add wait here, to wait for sufficient data to read
m_condWrite.wait(&m_mutex);
} else {
return 0;
}
}
for (int i = 0; i < length; i++) {
m_pBuffer[m_iWriteIndex] = buf[i];
m_iWriteIndex++;
if (m_iWriteIndex == m_iBufferLength) {
m_iWriteIndex = 0;
m_bIsOneCycle = false;
}
}
}
m_condRead.wakeOne();
return length;
}
// memory is full, no place to write
// tow different situations: readIndex and writeIndex is in one cycle or not
// one argument: the length of frame
bool VarBuffer::IsFull(unsigned short length)
{
if (m_bIsOneCycle == true) {
return m_iWriteIndex + length > m_iReadIndex + m_iBufferLength;
}
return m_iWriteIndex + length > m_iReadIndex;
}
// memory is empty, no data to read
// tow different situations: readIndex and writeIndex is in one cycle or not
bool VarBuffer::IsEmpty(unsigned short length)
{
if (m_bIsOneCycle == true) {
return m_iReadIndex + length >= m_iWriteIndex;
// return m_iReadIndex == m_iWriteIndex;
}
return m_iReadIndex + length >= m_iWriteIndex + m_iBufferLength;
// return m_iReadIndex == m_iWriteIndex + m_iBufferLength;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <QByteArray>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include "IBuffer.h"
#define MIN_FRAME_LENGTH 28
class VarBuffer : public IBuffer
{
public:
explicit VarBuffer(unsigned long bufLength, bool readWait, bool writeWait);
~VarBuffer();
unsigned short read(unsigned char* buf, unsigned short length) override;
int write(unsigned char* buf, unsigned short length) override;
unsigned short GetFrameLength() override;
private:
unsigned long m_iReadIndex;
unsigned long m_iWriteIndex;
unsigned char* m_pBuffer;
unsigned long m_iBufferLength;
unsigned short m_iFrameLength; // 帧长
bool m_bReadWait;
bool m_bWriteWait;
QWaitCondition m_condRead;
QWaitCondition m_condWrite;
QMutex m_mutex;
bool m_bIsOneCycle;
private:
bool IsFull(unsigned short length) override;
bool IsEmpty(unsigned short length) override;
bool verifyFrameLength(unsigned char* buf, unsigned short length);
};

View File

@ -0,0 +1,99 @@
cmake_minimum_required (VERSION 3.15)
project (qgt)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
set (CMAKE_AUTOUIC ON)
set (CMAKE_AUTOMOC ON)
set (CMAKE_AUTORCC ON)
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
# include (CMakeListsPub)
if (WIN32)
enable_language ("RC")
set (WIN32_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/UI/gtt.rc")
endif ()
set (Qt5_CMAKE_DIR "C:/Qt/Qt5.12.12/5.12.12/msvc2017_64/lib/cmake")
set (Qt5_DIR "${Qt5_CMAKE_DIR}/Qt5")
if (NOT DEFINED ENV{QTIFWDIR})
set (CPACK_IFW_ROOT "C:/Qt/QtIFW-4.6.1")
endif ()
set (COMPONENTS_LIST Core Xml Network Gui Widgets PrintSupport)
foreach (COMP ${COMPONENTS_LIST})
set (Qt5${COMP}_DIR "${Qt5_CMAKE_DIR}/Qt5${COMP}")
endforeach ()
find_package(Qt5 COMPONENTS ${COMPONENTS_LIST} REQUIRED)
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
file (GLOB SRC
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Buffer/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/CustomPlot/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Decode/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Network/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Process/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Public/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Widget/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/*.ui"
"${CMAKE_CURRENT_SOURCE_DIR}/*.qrc")
if (WIN32)
add_executable (${TARGET_NAME} WIN32 ${SRC} ${WIN32_RESOURCES})
else ()
add_executable (${TARGET_NAME} ${SRC})
endif ()
set_target_properties (${TARGET_NAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON)
target_include_directories (${TARGET_NAME}
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Buffer"
"${CMAKE_CURRENT_SOURCE_DIR}/CustomPlot"
"${CMAKE_CURRENT_SOURCE_DIR}/Decode"
"${CMAKE_CURRENT_SOURCE_DIR}/Network"
"${CMAKE_CURRENT_SOURCE_DIR}/Process"
"${CMAKE_CURRENT_SOURCE_DIR}/Public"
"${CMAKE_CURRENT_SOURCE_DIR}/Widget"
"${CMAKE_CURRENT_SOURCE_DIR}/Library/ffmpeg-4.1.3-win64-dev/include")
target_link_directories (${TARGET_NAME}
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/Library/ffmpeg-4.1.3-win64-dev/lib")
target_link_libraries (${TARGET_NAME}
ws2_32
avcodec
avdevice
avfilter
avformat
avutil
swresample
swscale
postproc
Qt5::Xml
Qt5::Network
Qt5::Gui
Qt5::Core
Qt5::Widgets
Qt5::PrintSupport)
if ("${Qt5_VERSION}" VERSION_LESS "5.14.0")
qt5_use_modules (${TARGET_NAME} ${COMPONENTS_LIST})
endif ()
set (CPACK_IFW_PACKAGE_TITLE "General Testing Tool")

View File

@ -0,0 +1,30 @@
#include "ConfigInfo.h"
Param::Param(QObject* parent)
: QObject(parent), m_pCurveWidget(nullptr), m_pVideoWidget(nullptr), m_pChannelGroup(nullptr)
{}
Param::~Param()
{
if (m_pChannelGroup) {
delete m_pChannelGroup;
m_pChannelGroup = nullptr;
}
}
void Param::setCurveWidget(CurveWidget* curveWidget)
{
m_pCurveWidget = curveWidget;
}
CurveWidget* Param::getCurveWidget()
{
return m_pCurveWidget;
}
void Param::setVideoWidget(VideoWidget* videoWidget)
{
m_pVideoWidget = videoWidget;
}
VideoWidget* Param::getVideoWidget()
{
return m_pVideoWidget;
}

View File

@ -0,0 +1,143 @@
#pragma once
#include <QByteArray>
#include <QObject>
#include <QString>
#include <map>
#include <vector>
#include "CurveWidget.h"
#include "VideoWidget.h"
struct DataStore {
QString m_strStoreType; // 离线或在线
QString m_strDateTime; // 数据日期
QString m_strDataPath; // 数据路径
};
struct Frame {
QString m_strHead; // 帧头
unsigned int m_uiRow; // 行数
unsigned int m_uiColumn; // 列数
unsigned int m_uiFrameLen; // 帧长
unsigned short m_usHeadAddr; // 帧头位置
unsigned short m_usSubFrameType; // 副帧类型
unsigned short m_usIdAddr; // Id副帧位置
unsigned short m_usIdStart; // Id副帧起始值
unsigned short m_usIdEnd; // Id结束值
double m_dFrameTime; // 每帧发送间隔
QByteArray m_headArray; // 帧头
QByteArray m_subHeadArray; // 反码副帧
unsigned short m_usBeforeHeadLen;
DataStore m_dataStore; // 数据存储路径
};
class Channel
{
public:
Channel() : m_uiMinorFrame(0), m_uiSubFrame(0), m_uiAbsolutePos(0)
{}
~Channel()
{}
public:
unsigned int m_uiMinorFrame;
unsigned int m_uiSubFrame;
unsigned int m_uiAbsolutePos;
};
class ChannelGroup
{
public:
ChannelGroup() : m_uiChannelNum(0)
{}
~ChannelGroup()
{}
unsigned int m_uiChannelNum;
std::vector<Channel*> m_vecChannel;
};
struct Formula {
int equaNum = 0; // 最高次方
double Equation[10] = {0.0}; // 系数公式
};
class Param : public QObject
{
Q_OBJECT
public:
Param(QObject* parent = Q_NULLPTR);
~Param();
void setCurveWidget(CurveWidget* curveWidget);
CurveWidget* getCurveWidget();
void setVideoWidget(VideoWidget* videoWidget);
VideoWidget* getVideoWidget();
unsigned int m_uiId; // 参数编号
QString m_strCode; // 代号
QString m_strTitle; // 名称
QString m_strChannelGroup; // 通道
ChannelGroup* m_pChannelGroup = nullptr; // 参数通道结构
unsigned short m_usModel; // 参数类型:模拟量、数字量、视频、状态量
QString m_strFill; // 无效填充
QByteArray m_fillArray;
unsigned short m_usType; // 基本数据类型
QString m_strBit; // 状态量比特位十六进制表示
unsigned short m_usOrder; // 大小端
QString m_strFormula; // 转换公式
Formula m_formula; // 公式信息
QString m_strUnit; // 物理单位
// 图像特有
unsigned short m_usFormat; // 图像格式
unsigned int m_uiWidth; // 图像宽度
unsigned int m_uiHeight; // 图像高度
private:
CurveWidget* m_pCurveWidget; // 曲线窗口
VideoWidget* m_pVideoWidget; // 视频窗口
};
struct ConfigInfo {
QString m_strValidName;
Frame* m_pFrame = nullptr;
std::map<unsigned int, Param*> m_mapUIntParam;
};
static double GetBCDTimeCode(const unsigned char* pData)
{
double d = 0.0;
d += (*pData & 0x0F) * 0.1; // 低位 //0.1ms
d += ((*pData & 0xF0) >> 4); // 1ms
d += (*(pData + 1) & 0x0F) * 10; // 10ms
d += ((*(pData + 1) & 0xF0) >> 4) * 100; // 100ms
d += (*(pData + 2) & 0x0F) * 1000; // 1000ms(1s)
d += ((*(pData + 2) & 0xF0) >> 4) * 10000; // 10s
d += (*(pData + 3) & 0x0F) * 60000; // 60s(1min)
d += ((*(pData + 3) & 0xF0) >> 4) * 600000; // 10min
d += (*(pData + 4) & 0x0F) * 3600000; // 60min(1hour)
d += ((*(pData + 4) & 0x30) >> 4) * 36000000; // 高位 //10hour
return d;
}
// 获取时分秒形式时码值
static QString GetBCDTimeCodeHMS(const unsigned char* pData)
{
double dMillSecond = 0.0;
dMillSecond += (*pData & 0x0F) * 0.1; // 低位 //0.1ms
dMillSecond += ((*pData & 0xF0) >> 4); // 1ms
dMillSecond += (*(pData + 1) & 0x0F) * 10; // 10ms
dMillSecond += ((*(pData + 1) & 0xF0) >> 4) * 100; // 100ms
QString strMillSecond = QString::number(dMillSecond, 'f', 1);
int iSecond = 0;
iSecond += (*(pData + 2) & 0x0F) * 1; // 1000ms(1s)
iSecond += ((*(pData + 2) & 0xF0) >> 4) * 10; // 10s
QString strSecond = QString::number(iSecond);
int iMinute = 0;
iMinute += (*(pData + 3) & 0x0F) * 1; // 60s(1min)
iMinute += ((*(pData + 3) & 0xF0) >> 4) * 10; // 10min
QString strMinute = QString::number(iMinute);
int iHour = 0;
iHour += (*(pData + 4) & 0x0F) * 1; // 60min(1hour)
iHour += ((*(pData + 4) & 0x30) >> 4) * 10; // 高位 //10hour
QString strHour = QString::number(iHour);
QString strTime = strHour + "h" + strMinute + "m" + strSecond + "s" + strMillSecond + "ms";
return strTime;
}

View File

@ -0,0 +1,277 @@
#include "CurveWidget.h"
CurveWidget::CurveWidget(QWidget* parent)
: QWidget(parent)
, m_iWgtWidth(0)
, m_iWgtHeight(0)
, m_pPlotTitle(nullptr)
, m_pRubberBand(nullptr)
, m_pCPGraph(nullptr)
, m_dYMax(0.0)
, m_dYMin(0.0)
, m_uiParseStatus(0)
, m_bRefTime(false)
{
ui.setupUi(this);
setWindowFlags(Qt::FramelessWindowHint);
initCurvePlot();
// connect(ui.pb_changeCoord,&QPushButton::clicked,this,&CurveWidget::changeCoord); //坐标切换
connect(ui.pb_zoomCoordY, &QPushButton::clicked, this, &CurveWidget::zoomCoordY); // Y轴缩放
connect(ui.pb_resetCoord, &QPushButton::clicked, this, &CurveWidget::resetCoord); // 坐标重置
connect(ui.pb_hide, &QPushButton::clicked, this, &CurveWidget::hideWindow); // 隐藏窗口
connect(&m_timer, &QTimer::timeout, this, &CurveWidget::refreshCurve);
ui.le_curValue->setEnabled(false); // 当前值窗口
// ui.pb_changeCoord->setToolTip("坐标转换:\n实时解析时改变X轴显示方式");
ui.pb_zoomCoordY->setToolTip("Y轴缩放\n点击按钮,利用Ctrl+鼠标滚轮进行Y轴缩放");
ui.pb_resetCoord->setToolTip("坐标重置");
ui.pb_hide->setToolTip("关闭窗口");
// ui.pb_changeCoord->setEnabled(false); //坐标切换
ui.pb_zoomCoordY->setEnabled(false); // Y轴缩放
ui.pb_resetCoord->setEnabled(false); // 坐标重置
}
CurveWidget::~CurveWidget()
{
delete m_pCurveInfo;
m_pCurveInfo = nullptr;
}
void CurveWidget::initCurvePlot()
{
m_axisRange.axisMinX = 0.0;
m_axisRange.axisMaxX = 100.0;
m_axisRange.axisMinY = 0.0;
m_axisRange.axisMaxY = 100.0;
m_pPlotTitle = new QCPPlotTitle(ui.wgt_curvePlot);
m_pPlotTitle->setFont(QFont("sans", 12, QFont::Bold));
ui.wgt_curvePlot->xAxis->setRange(m_axisRange.axisMinX, m_axisRange.axisMaxX);
ui.wgt_curvePlot->yAxis->setRange(m_axisRange.axisMinY, m_axisRange.axisMaxY);
ui.wgt_curvePlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); // 支持拖拽和缩放
ui.wgt_curvePlot->axisRect()->setRangeZoom(Qt::Horizontal); // 水平缩放
ui.wgt_curvePlot->xAxis->setLabel("时间(ms)");
ui.wgt_curvePlot->plotLayout()->insertRow(0);
ui.wgt_curvePlot->plotLayout()->addElement(0, 0, m_pPlotTitle);
m_pRubberBand = new QRubberBand(QRubberBand::Rectangle, ui.wgt_curvePlot);
connect(ui.wgt_curvePlot, &QCustomPlot::mousePress, this, &CurveWidget::mousePressEvent);
connect(ui.wgt_curvePlot, &QCustomPlot::mouseMove, this, &CurveWidget::mouseMoveEvent);
connect(ui.wgt_curvePlot, &QCustomPlot::mouseRelease, this, &CurveWidget::mouseReleaseEvent);
}
void CurveWidget::setParam(CurveInfo*& curveInfo)
{
m_pCurveInfo = curveInfo;
strTitle = curveInfo->m_strTitle;
m_usModel = curveInfo->m_usCurveModel;
m_count = curveInfo->m_curveCount;
ui.lb_curveName->setText(strTitle);
ui.wgt_curvePlot->yAxis->setLabel(strTitle);
// 添加曲线
m_pCPGraph = ui.wgt_curvePlot->addGraph();
QPen pen;
pen.setColor(curveInfo->m_curveColor); // 曲线颜色
m_pCPGraph->setPen(pen);
m_pCPGraph->setVisible(true);
if (m_usModel == 4) { // 状态量
m_pCPGraph->setLineStyle((QCPGraph::lsStepLeft)); // 阶梯型曲线
}
curveInfo->m_pGPGraph = m_pCPGraph;
}
void CurveWidget::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Control) {
ui.wgt_curvePlot->axisRect()->setRangeZoom(Qt::Vertical);
}
}
void CurveWidget::keyReleaseEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Control) {
ui.wgt_curvePlot->axisRect()->setRangeZoom(Qt::Horizontal);
}
}
void CurveWidget::resizeEvent(QResizeEvent* event)
{
QSize size = event->size();
m_iWgtWidth = size.width();
m_iWgtHeight = size.height();
resizeSubControl(m_iWgtWidth, m_iWgtHeight);
}
void CurveWidget::resizeSubControl(int width, int height)
{
ui.wgt_background->setGeometry(0, 0, width, height);
// 曲线信息
int iHeight = ui.lb_curveInfo->height();
ui.lb_curveInfo->setGeometry(0, 0, width, iHeight);
ui.lb_curveInfo->setStyleSheet("background-color:rgb(113,113,113)");
// 关闭按钮
QRect rect = ui.pb_hide->geometry();
ui.pb_hide->setGeometry(width - 5 - rect.width(), rect.y(), rect.width(), rect.height());
// 重置按钮
rect = ui.pb_resetCoord->geometry();
ui.pb_resetCoord->setGeometry(width - (5 + rect.width()) * 2, rect.y(), rect.width(),
rect.height());
// Y轴缩放
rect = ui.pb_zoomCoordY->geometry();
ui.pb_zoomCoordY->setGeometry(width - (5 + rect.width()) * 3, rect.y(), rect.width(),
rect.height());
// 坐标切换
// rect = ui.pb_changeCoord->geometry();
// ui.pb_changeCoord->setGeometry(width - (5 + rect.width()) * 4, rect.y(), rect.width(),
// rect.height()); 曲线控件
ui.wgt_curvePlot->setGeometry(0, iHeight, width, height - iHeight);
}
void CurveWidget::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::RightButton) {
m_originPoint = event->pos(); // 鼠标原始位置
m_pRubberBand->setGeometry(QRect(m_originPoint, QSize()));
m_pRubberBand->show();
}
}
void CurveWidget::mouseMoveEvent(QMouseEvent* event)
{
if (event->buttons() && Qt::RightButton) {
if (m_pRubberBand->isVisible()) {
QPoint point = event->pos();
m_pRubberBand->setGeometry(QRect(m_originPoint, event->pos()).normalized());
}
}
int axisX = event->pos().x();
int axisY = event->pos().y();
double coordX = ui.wgt_curvePlot->xAxis->pixelToCoord((double)axisX);
double coordY = ui.wgt_curvePlot->yAxis->pixelToCoord((double)axisY);
QString strTip = QString("x:%1,y:%2")
.arg(QString::number(coordX, 10, 1))
.arg(QString::number(coordY, 10, 3));
QToolTip::showText(cursor().pos(), strTip, ui.wgt_curvePlot);
}
void CurveWidget::mouseReleaseEvent(QMouseEvent* event)
{
if (m_pRubberBand->isVisible()) {
const QRect zoomRect = m_pRubberBand->geometry();
int xp1, yp1, xp2, yp2;
zoomRect.getCoords(&xp1, &yp1, &xp2, &yp2);
double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
// 把鼠标坐标点 转换为QCustomPlot内部坐标值pixelToCoord 函数)
// coordToPixel 函数与之相反 是把内部坐标值 转换为外部坐标点
x1 = ui.wgt_curvePlot->xAxis->pixelToCoord(xp1);
x2 = ui.wgt_curvePlot->xAxis->pixelToCoord(xp2);
y1 = ui.wgt_curvePlot->yAxis->pixelToCoord(yp1);
y2 = ui.wgt_curvePlot->yAxis->pixelToCoord(yp2);
ui.wgt_curvePlot->xAxis->setRange(x1, x2);
ui.wgt_curvePlot->yAxis->setRange(y1, y2);
m_pRubberBand->hide();
ui.wgt_curvePlot->replot();
}
}
/*
//坐标切换
void CurveWidget::changeCoord() {
if (m_pCurveInfo->m_bIsZeroX == false) { //false:固定间距显示
m_pCurveInfo->m_bIsZeroX = true;
}
else if (m_pCurveInfo->m_bIsZeroX == true) { //true:从零开始显示
m_pCurveInfo->m_bIsZeroX = false;
}
}*/
// Y轴缩放
void CurveWidget::zoomCoordY()
{
ui.wgt_curvePlot->replot();
}
// 坐标重置
void CurveWidget::resetCoord()
{
// 修改坐标轴范围
ui.wgt_curvePlot->xAxis->setRange(m_axisRange.axisMinX, m_axisRange.axisMaxX);
ui.wgt_curvePlot->yAxis->setRange(m_dYMin, m_dYMax);
ui.wgt_curvePlot->replot();
}
// 隐藏窗口
void CurveWidget::hideWindow()
{
emit hideCurveWidget(m_count);
}
void CurveWidget::startRefresh(bool status)
{
if (status == true) {
m_timer.start(500);
} else if (status == false) {
m_timer.stop();
}
}
void CurveWidget::refreshCurve()
{
int iSize = m_pCurveInfo->m_vecAxisY.size();
if (iSize == 0) {
return;
}
m_mutex.lock();
if (m_uiParseStatus == 2) { // 在线解析
double dValue = (double)m_pCurveInfo->m_vecAxisY.at(iSize - 1);
QString strValue = QString::number(dValue, 'f', 3);
ui.le_curValue->setText(strValue); // 当前值窗口
if (m_pCurveInfo->m_vecAxisX.size() > 3000) {
m_pCurveInfo->m_vecAxisX.erase(m_pCurveInfo->m_vecAxisX.begin(),
m_pCurveInfo->m_vecAxisX.end() - 2000);
}
if (m_pCurveInfo->m_vecAxisY.size() > 3000) {
m_pCurveInfo->m_vecAxisY.erase(m_pCurveInfo->m_vecAxisY.begin(),
m_pCurveInfo->m_vecAxisY.end() - 2000);
}
}
m_pCurveInfo->m_pGPGraph->setData(m_pCurveInfo->m_vecAxisX, m_pCurveInfo->m_vecAxisY);
m_axisRange.axisMinX = m_pCurveInfo->minX;
m_axisRange.axisMaxX = m_pCurveInfo->maxX;
m_axisRange.axisMaxY = m_pCurveInfo->maxY;
m_axisRange.axisMinY = m_pCurveInfo->minY;
ui.wgt_curvePlot->xAxis->setRange(m_axisRange.axisMinX, m_axisRange.axisMaxX);
m_dYMin = m_axisRange.axisMinY - (m_axisRange.axisMaxY - m_axisRange.axisMinY) / 2.0;
m_dYMax = m_axisRange.axisMaxY + (m_axisRange.axisMaxY - m_axisRange.axisMinY) / 2.0;
ui.wgt_curvePlot->yAxis->setRange(m_dYMin, m_dYMax);
ui.wgt_curvePlot->replot();
m_mutex.unlock();
}
void CurveWidget::clearWidget()
{
m_pCurveInfo->m_vecAxisX.clear();
m_pCurveInfo->m_vecAxisY.clear();
m_pCurveInfo->m_pGPGraph->clearData();
m_axisRange.axisMinX = 0.0;
m_axisRange.axisMaxX = 100.0;
m_axisRange.axisMinY = 0.0;
m_axisRange.axisMaxY = 100.0;
ui.wgt_curvePlot->xAxis->setLabel("时间(ms)");
ui.wgt_curvePlot->xAxis->setRange(m_axisRange.axisMinX, m_axisRange.axisMaxX);
ui.wgt_curvePlot->yAxis->setRange(m_axisRange.axisMinY, m_axisRange.axisMaxY);
ui.wgt_curvePlot->replot();
}
void CurveWidget::parseFinished()
{
refreshCurve();
}
void CurveWidget::setParseStatus(unsigned int status)
{
m_uiParseStatus = status;
if (m_uiParseStatus == 0 || m_uiParseStatus == 1) { // 无任务解析或离线解析
// ui.pb_changeCoord->setEnabled(false); //坐标切换
ui.pb_zoomCoordY->setEnabled(true); // Y轴缩放
ui.pb_resetCoord->setEnabled(true); // 坐标重置
} else if (m_uiParseStatus == 2) { // 实时解析
// ui.pb_changeCoord->setEnabled(true); //坐标切换
ui.pb_zoomCoordY->setEnabled(false); // Y轴缩放
ui.pb_resetCoord->setEnabled(false); // 坐标重置
}
}

View File

@ -0,0 +1,96 @@
#pragma once
#include <QTimer>
#pragma execution_character_set("utf-8")
#include <QMutex>
#include <QMutexLocker>
#include <QRect>
#include <QString>
#include <QToolTip>
#include <QWidget>
#include "qcustomplot.h"
#include "ui_CurveWidget.h"
typedef struct {
double axisMinX;
double axisMaxX;
double axisMinY;
double axisMaxY;
} AxisRange;
struct CurveInfo {
QVector<double> m_vecAxisX; // X轴数据
QVector<double> m_vecAxisY; // Y轴数据
QString m_strTitle; // 曲线主题
QColor m_curveColor; // 曲线颜色
int m_curveCount; // 曲线编号
unsigned short m_usCurveModel; // 曲线类型
QCPGraph* m_pGPGraph = nullptr; // 曲线
double maxX = 0.0;
double minX = 0.0;
double maxY = 0.0;
double minY = 0.0;
bool m_bIsInited = false; // 是否初始化
// bool m_bIsZeroX=false; //实时解析时X轴是否从零开始 false:固定间距显示true:从零开始显示
};
class CurveWidget : public QWidget
{
Q_OBJECT
public:
CurveWidget(QWidget* parent = Q_NULLPTR);
~CurveWidget();
void setParam(CurveInfo*& curveInfo);
CurveInfo* getCurveInfo()
{
return m_pCurveInfo;
}
QCustomPlot* getCustomplot()
{
return ui.wgt_curvePlot;
}
void startRefresh(bool status);
void clearWidget();
bool m_bRefTime; // 基准时间设置
private:
Ui::CurveWidgetClass ui;
QString strTitle;
unsigned short m_usModel;
int m_count;
int m_iWgtWidth;
int m_iWgtHeight;
AxisRange m_axisRange;
QCPPlotTitle* m_pPlotTitle;
QRubberBand* m_pRubberBand;
QPoint m_originPoint;
QCPGraph* m_pCPGraph;
CurveInfo* m_pCurveInfo;
QTimer m_timer;
QMutex m_mutex;
double m_dYMax;
double m_dYMin;
unsigned int m_uiParseStatus; // 0无任务解析1离线解析2在线解析
private:
void initCurvePlot();
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void resizeSubControl(int width, int height);
signals:
void hideCurveWidget(int count);
private slots:
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
// void changeCoord(); //坐标切换
void zoomCoordY(); // Y轴缩放
void resetCoord(); // 坐标重置
void hideWindow(); // 隐藏窗口
void refreshCurve();
public slots:
void parseFinished();
void setParseStatus(unsigned int status);
};

View File

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CurveWidgetClass</class>
<widget class="QWidget" name="CurveWidgetClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>516</width>
<height>250</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="windowTitle">
<string>CurveWidget</string>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QWidget" name="wgt_background" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>510</width>
<height>240</height>
</rect>
</property>
<widget class="QCustomPlot" name="wgt_curvePlot" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>40</y>
<width>510</width>
<height>200</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="lb_curveInfo">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>510</width>
<height>30</height>
</rect>
</property>
<property name="font">
<font>
<family>Noto Sans S Chinese Light</family>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="pb_hide">
<property name="geometry">
<rect>
<x>485</x>
<y>5</y>
<width>20</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
<widget class="QLabel" name="lb_curveName">
<property name="geometry">
<rect>
<x>5</x>
<y>5</y>
<width>100</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>130</x>
<y>5</y>
<width>206</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lb_curValue">
<property name="text">
<string>当前值:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="le_curValue">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pb_resetCoord">
<property name="geometry">
<rect>
<x>460</x>
<y>5</y>
<width>20</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>R</string>
</property>
</widget>
<widget class="QPushButton" name="pb_zoomCoordY">
<property name="geometry">
<rect>
<x>435</x>
<y>5</y>
<width>20</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>Y</string>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,236 @@
#include "XxwTracer.h"
XxwTracer::XxwTracer(QCustomPlot* _plot, TracerType _type, QObject* parent)
: QObject(parent), m_plot(_plot), m_type(_type)
{
m_visible = true;
m_tracer = Q_NULLPTR; // 跟踪的点
m_label = Q_NULLPTR; // 显示的数值
m_arrow = Q_NULLPTR; // 箭头
if (m_plot) {
QColor clrDefault(Qt::red); // 跟踪点颜色
QBrush brushDefault(Qt::NoBrush);
QPen penDefault(clrDefault);
// penDefault.setBrush(brushDefault);
penDefault.setWidthF(1);
m_tracer = new QCPItemTracer(m_plot);
m_tracer->setStyle(QCPItemTracer::tsCircle);
m_tracer->setPen(penDefault);
m_tracer->setBrush(brushDefault);
// 设置跟踪锚定点
m_label = new QCPItemText(m_plot);
m_label->setLayer("overlay");
m_label->setClipToAxisRect(false);
m_label->setPadding(QMargins(5, 5, 5, 5));
m_label->setBrush(brushDefault);
m_label->setPen(penDefault);
m_label->position->setParentAnchor(m_tracer->position);
// m_label->setFont(QFont("宋体", 8));
m_label->setFont(QFont("Arial", 8));
m_label->setColor(clrDefault);
m_label->setText("");
m_arrow = new QCPItemLine(m_plot);
QPen arrowPen(clrDefault, 1);
m_arrow->setPen(penDefault);
m_arrow->setLayer("overlay");
m_arrow->setClipToAxisRect(false);
m_arrow->setHead(QCPLineEnding::esSpikeArrow); // 设置头部为箭头形状
switch (m_type) {
case XAxisTracer: {
m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
m_tracer->position->setTypeY(QCPItemPosition::ptAxisRectRatio);
m_tracer->setSize(7);
m_label->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter);
m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_arrow->end);
m_arrow->start->setCoords(0, 20); // 偏移量
break;
}
case YAxisTracer: {
m_tracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio);
m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
m_tracer->setSize(7);
m_label->setPositionAlignment(Qt::AlignRight | Qt::AlignHCenter);
m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_label->position);
m_arrow->start->setCoords(-20, 0); // 偏移量
break;
}
case DataTracer: {
m_tracer->position->setTypeX(QCPItemPosition::ptPlotCoords);
m_tracer->position->setTypeY(QCPItemPosition::ptPlotCoords);
m_tracer->setSize(5);
m_label->setPositionAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_arrow->end->setParentAnchor(m_tracer->position);
m_arrow->start->setParentAnchor(m_arrow->end);
m_arrow->start->setCoords(20, 0);
break;
}
default:
break;
}
setVisible(false);
}
}
XxwTracer::~XxwTracer()
{
if (m_plot) {
if (m_tracer)
m_plot->removeItem(m_tracer);
if (m_label)
m_plot->removeItem(m_label);
if (m_arrow)
m_plot->removeItem(m_arrow);
}
}
void XxwTracer::setPen(const QPen& pen)
{
if (m_tracer)
m_tracer->setPen(pen);
if (m_arrow)
m_arrow->setPen(pen);
}
void XxwTracer::setBrush(const QBrush& brush)
{
if (m_tracer)
m_tracer->setBrush(brush);
}
void XxwTracer::setLabelPen(const QPen& pen)
{
if (m_label) {
m_label->setPen(pen);
m_label->setBrush(Qt::NoBrush);
m_label->setColor(pen.color());
}
}
void XxwTracer::setText(const QString& text)
{
if (m_label)
m_label->setText(text);
}
void XxwTracer::setVisible(bool vis)
{
m_visible = vis;
if (m_tracer)
m_tracer->setVisible(m_visible);
if (m_label)
m_label->setVisible(m_visible);
if (m_arrow)
m_arrow->setVisible(m_visible);
}
void XxwTracer::updatePosition(double xValue, double yValue)
{
if (!m_visible) {
setVisible(true);
m_visible = true;
}
if (yValue > m_plot->yAxis->range().upper)
yValue = m_plot->yAxis->range().upper;
switch (m_type) {
case XAxisTracer: {
m_tracer->position->setCoords(xValue, 1);
m_label->position->setCoords(0, 15);
m_arrow->start->setCoords(0, 15);
m_arrow->end->setCoords(0, 0);
setText(QString::number(xValue));
break;
}
case YAxisTracer: {
m_tracer->position->setCoords(0, yValue);
m_label->position->setCoords(-20, 0);
// m_arrow->start->setCoords(20, 0);
// m_arrow->end->setCoords(0, 0);
setText(QString::number(yValue));
break;
}
case DataTracer: {
m_tracer->position->setCoords(xValue, yValue);
m_label->position->setCoords(20, 20);
// setText(QString("x:%1,y:%2").arg(xValue).arg(yValue));
QString xVal = QString::number(xValue, 'f', 6);
QString yVal = QString::number(yValue, 'f', 6);
QString Val = "x:" + xVal + ",y:" + yVal;
setText(Val);
break;
}
default:
break;
}
}
XxwTraceLine::XxwTraceLine(QCustomPlot* _plot, LineType _type, QObject* parent)
: QObject(parent), m_type(_type), m_plot(_plot)
{
m_lineV = Q_NULLPTR;
m_lineH = Q_NULLPTR;
initLine();
}
XxwTraceLine::~XxwTraceLine()
{
if (m_plot) {
if (m_lineV)
m_plot->removeItem(m_lineV);
if (m_lineH)
m_plot->removeItem(m_lineH);
}
}
void XxwTraceLine::initLine()
{
if (m_plot) {
QPen linesPen(Qt::red, 1, Qt::DashLine); // 设置游标颜色和宽度
if (VerticalLine == m_type || Both == m_type) {
m_lineV = new QCPItemStraightLine(m_plot); // 垂直线
m_lineV->setLayer("overlay");
m_lineV->setPen(linesPen);
m_lineV->setClipToAxisRect(true);
m_lineV->point1->setCoords(0, 0);
m_lineV->point2->setCoords(0, 0);
}
if (HorizonLine == m_type || Both == m_type) {
m_lineH = new QCPItemStraightLine(m_plot); // 水平线
m_lineH->setLayer("overlay");
m_lineH->setPen(linesPen);
m_lineH->setClipToAxisRect(true);
m_lineH->point1->setCoords(0, 0);
m_lineH->point2->setCoords(0, 0);
}
}
}
void XxwTraceLine::updatePosition(double xValue, double yValue)
{
if (VerticalLine == m_type || Both == m_type) {
if (m_lineV) {
m_lineV->point1->setCoords(xValue, m_plot->yAxis->range().lower);
m_lineV->point2->setCoords(xValue, m_plot->yAxis->range().upper);
}
}
if (HorizonLine == m_type || Both == m_type) {
if (m_lineH) {
m_lineH->point1->setCoords(m_plot->xAxis->range().lower, yValue);
m_lineH->point2->setCoords(m_plot->xAxis->range().upper, yValue);
}
}
}

View File

@ -0,0 +1,73 @@
#pragma warning(disable : 4819)
#ifndef MYTRACER_H
#define MYTRACER_H
#include <QObject>
#include "qcustomplot.h"
///
/// \brief The XxwTracer class:在图表中显示鼠标所在位置的x,y值的追踪显示器
///
class XxwTracer : public QObject
{
Q_OBJECT
public:
enum TracerType {
XAxisTracer, // 依附在x轴上显示x值
YAxisTracer, // 依附在y轴上显示y值
DataTracer // 在图中显示x,y值
};
explicit XxwTracer(QCustomPlot* _plot, TracerType _type, QObject* parent = Q_NULLPTR);
~XxwTracer();
void setPen(const QPen& pen);
void setBrush(const QBrush& brush);
void setText(const QString& text);
void setLabelPen(const QPen& pen);
void updatePosition(double xValue, double yValue);
void setVisible(bool m_visible);
protected:
bool m_visible; // 是否可见
TracerType m_type; // 类型
QCustomPlot* m_plot; // 图表
QCPItemTracer* m_tracer; // 跟踪的点
QCPItemText* m_label; // 显示的数值
QCPItemLine* m_arrow; // 箭头
};
///
/// \brief The XxwCrossLine class:用于显示鼠标移动过程中的鼠标位置的直线
///
class XxwTraceLine : public QObject
{
public:
enum LineType {
VerticalLine, // 垂直线
HorizonLine, // 水平线
Both // 同时显示水平和垂直线
};
explicit XxwTraceLine(QCustomPlot* _plot, LineType _type = VerticalLine,
QObject* parent = Q_NULLPTR);
~XxwTraceLine();
void initLine();
void updatePosition(double xValue, double yValue);
void setVisible(bool vis)
{
if (m_lineV)
m_lineV->setVisible(vis);
if (m_lineH)
m_lineH->setVisible(vis);
}
protected:
bool m_visible; // 是否可见
LineType m_type; // 类型
QCustomPlot* m_plot; // 图表
QCPItemStraightLine* m_lineV; // 垂直线
QCPItemStraightLine* m_lineH; // 水平线
};
#endif // MYTRACER_H

View File

@ -0,0 +1,52 @@
#include "customplotZoom.h"
CustomPlotZoom::CustomPlotZoom(QWidget* parent)
: QCustomPlot(parent)
, mZoomMode(false)
, mRubberBand(new QRubberBand(QRubberBand::Rectangle, this))
{}
CustomPlotZoom::~CustomPlotZoom()
{}
void CustomPlotZoom::setZoomMode(bool mode)
{
mZoomMode = mode;
}
void CustomPlotZoom::mousePressEvent(QMouseEvent* event)
{
if (mZoomMode) {
if (event->button() == Qt::RightButton) {
mOrigin = event->pos();
mRubberBand->setGeometry(QRect(mOrigin, QSize()));
mRubberBand->show();
}
}
QCustomPlot::mousePressEvent(event);
}
void CustomPlotZoom::mouseMoveEvent(QMouseEvent* event)
{
if (mRubberBand->isVisible()) {
mRubberBand->setGeometry(QRect(mOrigin, event->pos()).normalized());
}
QCustomPlot::mouseMoveEvent(event);
}
void CustomPlotZoom::mouseReleaseEvent(QMouseEvent* event)
{
if (mRubberBand->isVisible()) {
const QRect zoomRect = mRubberBand->geometry();
int xp1, yp1, xp2, yp2;
zoomRect.getCoords(&xp1, &yp1, &xp2, &yp2);
double x1 = xAxis->pixelToCoord(xp1);
double y1 = xAxis->pixelToCoord(yp1);
double x2 = xAxis->pixelToCoord(xp2);
double y2 = xAxis->pixelToCoord(yp2);
xAxis->setRange(x1, x2);
yAxis->setRange(y1, y2);
mRubberBand->hide();
replot();
}
QCustomPlot::mouseReleaseEvent(event);
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <QPoint>
#include "qcustomplot.h"
class QRubberBand;
class QMouseEvent;
class QWidget;
class CustomPlotZoom : public QCustomPlot
{
Q_OBJECT
public:
CustomPlotZoom(QWidget* parent = 0);
virtual ~CustomPlotZoom();
void setZoomMode(bool mode);
protected:
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
private:
bool mZoomMode;
QRubberBand* mRubberBand;
QPoint mOrigin;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,199 @@
#include "FfmpegDecodeNew.h"
FfmpegDecodeNew::FfmpegDecodeNew(QObject* parent)
: QThread(parent)
, m_bNeedWork(false)
, m_pConstBuffer(nullptr)
, m_pAVPacket(nullptr)
, m_pAVCodec(nullptr)
, m_pAVCodecParserContext(nullptr)
, m_pAVCodecContext(nullptr)
, m_pAVFrameSrc(nullptr)
, m_pAVFrameDes(nullptr)
, m_pSwsContext(nullptr)
, m_bSwsContext(false)
, m_bImageUpdated(false)
, m_iWidth(0) // 图像宽度
, m_iHeight(0) // 图像高度
{
m_pConstBuffer = new ConstBuffer(VideoBufferLength, false, false, VideoPacketLength);
}
FfmpegDecodeNew::~FfmpegDecodeNew()
{
if (m_pConstBuffer) {
delete m_pConstBuffer;
m_pConstBuffer = nullptr;
}
}
void FfmpegDecodeNew::setParam(unsigned short format, int width, int height)
{
m_usFormat = format;
m_iWidth = width;
m_iHeight = height;
switch (m_usFormat) {
case 1: // 444P
m_AVPixelFormat = AV_PIX_FMT_YUV444P;
break;
case 2: // 422P
m_AVPixelFormat = AV_PIX_FMT_YUV422P;
break;
case 3: // 420P
m_AVPixelFormat = AV_PIX_FMT_YUV420P;
break;
case 4: // NV12
m_AVPixelFormat = AV_PIX_FMT_NV12;
break;
case 5: // RGB24
m_AVPixelFormat = AV_PIX_FMT_RGB24;
break;
default:
break;
}
}
void FfmpegDecodeNew::init()
{
// 1注册所有编解码器(codecs)、解析器(parsers)以及码流过滤器(bitstream filters)
avcodec_register_all();
// 2申请分配压缩数据包空间
m_pAVPacket = av_packet_alloc();
if (!m_pAVPacket) { // 申请分配压缩数据包空间失败
return;
}
// 3查找H264压缩格式视频解码器
m_pAVCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!m_pAVCodec) { // 未找到编解码器
return;
}
// 4查找解析器
m_pAVCodecParserContext = av_parser_init(m_pAVCodec->id);
if (!m_pAVCodecParserContext) { // 未找到解析器
return;
}
// 5分配视频编解码器上下文
m_pAVCodecContext = avcodec_alloc_context3(m_pAVCodec);
if (!m_pAVCodecContext) { // 无法分配视频编解码器上下文
return;
}
// 6打开解码器
if (avcodec_open2(m_pAVCodecContext, m_pAVCodec, NULL) < 0) {
return;
}
// 7申请视频帧
m_pAVFrameSrc = av_frame_alloc();
if (!m_pAVFrameSrc) { // 申请视频帧存储空间失败
return;
}
av_image_alloc(m_pAVFrameSrc->data, m_pAVFrameSrc->linesize, m_iWidth, m_iHeight,
m_AVPixelFormat, 1);
// 11申请转换后视频帧
m_pAVFrameDes = av_frame_alloc();
if (!m_pAVFrameDes) {
return;
}
av_image_alloc(m_pAVFrameDes->data, m_pAVFrameDes->linesize, m_iWidth, m_iHeight,
AV_PIX_FMT_RGB24, 1);
/*
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, m_iWidth, m_iHeight);
uint8_t* pBuffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
m_pAVFrameDes = av_frame_alloc();
m_pAVFrameDes->data[0] = pBuffer;
avpicture_fill((AVPicture*)m_pAVFrameDes, pBuffer, AV_PIX_FMT_RGB24, m_iWidth, m_iHeight);
*/
// 12初始化图像格式转换
/*m_pSwsContext = sws_getContext(m_iWidth, m_iHeight, m_AVPixelFormat,
m_iWidth, m_iHeight, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);*/
m_pSwsContext = sws_getContext(m_iWidth, m_iHeight, (AVPixelFormat)m_AVPixelFormat, m_iWidth,
m_iHeight, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
}
void FfmpegDecodeNew::run()
{
m_bNeedWork = true;
unsigned short usRecvSize = 0;
unsigned char* pVideoBuffer = new unsigned char[VideoPacketLength];
int ret = 0;
while (m_bNeedWork) {
usRecvSize = m_pConstBuffer->read(pVideoBuffer, VideoPacketLength);
if (usRecvSize <= 0) {
continue;
}
unsigned char* pBuffer = pVideoBuffer;
while (0 < usRecvSize) {
// 8获取AVPacket压缩数据
ret = av_parser_parse2(m_pAVCodecParserContext, m_pAVCodecContext, &(m_pAVPacket->data),
&(m_pAVPacket->size), pBuffer, usRecvSize, AV_NOPTS_VALUE,
AV_NOPTS_VALUE, 0);
if (ret < 0) {
return;
}
pBuffer += ret;
usRecvSize -= ret;
if (m_pAVPacket->size) { // 说明获取到AVPacket压缩数据
decode(m_pAVCodecContext, m_pAVFrameSrc, m_pAVPacket);
}
}
}
}
void FfmpegDecodeNew::decode(AVCodecContext* pCodecContext, AVFrame* pFrame, AVPacket* pPacket)
{
// 9发送AVPacket数据到Ffmepg放到解码队列中
int ret = avcodec_send_packet(pCodecContext, pPacket);
if (ret < 0) {
return;
}
while (0 <= ret) {
// 10从解码队列中取出1个AVFrame数据
ret = avcodec_receive_frame(pCodecContext, pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if (ret < 0) {
return;
}
/*
//验证一下是否可以根据pFrame对m_pAVFrameDes操作av_image_alloc和sws_getContext
if (m_bSwsContext == false) {
av_image_alloc(m_pAVFrameDes->data, m_pAVFrameDes->linesize, pFrame->width,
pFrame->height, AV_PIX_FMT_RGB24, 1);
//12初始化图像格式转换
m_pSwsContext = sws_getContext(pFrame->width, pFrame->height,
(AVPixelFormat)pFrame->format, pFrame->width, pFrame->height, AV_PIX_FMT_RGB24,
SWS_FAST_BILINEAR, NULL, NULL, NULL); m_iWidth = pFrame->width; //图像宽度 m_iHeight =
pFrame->height; //图像高度 m_bSwsContext = true;
}
if (m_bSwsContext == true) {
// (13) 进行图像格式转换
sws_scale(m_pSwsContext, m_pAVFrameSrc->data, m_pAVFrameSrc->linesize, 0,
m_pAVFrameSrc->height, m_pAVFrameDes->data, m_pAVFrameDes->linesize);
//14对转换后的数据进行处理
m_bImageUpdated = true;
m_image = QImage((uchar*)m_pAVFrameDes->data[0],
m_iWidth,m_iHeight,QImage::Format_RGB888);
}
*/
// (13) 进行图像格式转换
sws_scale(m_pSwsContext, pFrame->data, pFrame->linesize, 0, pCodecContext->height,
m_pAVFrameDes->data, m_pAVFrameDes->linesize);
// 14对转换后的数据进行处理
QMutexLocker locker(&m_mutex);
m_bImageUpdated = true;
m_image =
QImage((uchar*)m_pAVFrameDes->data[0], m_iWidth, m_iHeight, QImage::Format_RGB888);
}
}
bool FfmpegDecodeNew::getImage(QImage& image)
{
QMutexLocker locker(&m_mutex);
if (m_bImageUpdated) {
image = m_image;
m_bImageUpdated = false;
return true;
}
return false;
}

View File

@ -0,0 +1,59 @@
#pragma once
#include <QImage>
#include <QMutex>
#include <QMutexLocker>
#include <QThread>
#include "ConstBuffer.h"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/pixfmt.h"
#include "libavutil/samplefmt.h"
#include "libswscale/swscale.h"
}
class FfmpegDecodeNew : public QThread
{
Q_OBJECT
public:
FfmpegDecodeNew(QObject* parent = Q_NULLPTR);
~FfmpegDecodeNew();
void init();
void setParam(unsigned short format, int width, int height);
inline IBuffer* getConstBuffer()
{
return m_pConstBuffer;
}
bool getImage(QImage& image);
void stop()
{
m_bNeedWork = false;
m_bImageUpdated = false;
}
private:
bool m_bNeedWork;
ConstBuffer* m_pConstBuffer;
AVPacket* m_pAVPacket; // 压缩数据包
const AVCodec* m_pAVCodec; // 解码器
AVCodecParserContext* m_pAVCodecParserContext; // 解析器
AVCodecContext* m_pAVCodecContext;
AVFrame* m_pAVFrameSrc;
AVFrame* m_pAVFrameDes;
SwsContext* m_pSwsContext;
AVPixelFormat m_AVPixelFormat;
bool m_bSwsContext;
QMutex m_mutex;
bool m_bImageUpdated;
QImage m_image;
unsigned short m_usFormat; // 图像格式
int m_iWidth; // 图像宽度
int m_iHeight; // 图像高度
private:
void run() override;
void decode(AVCodecContext* pCodecContext, AVFrame* pFrame, AVPacket* pPacket);
};

View File

@ -0,0 +1,135 @@
#include "FfmpegDecodeOld.h"
ConstBuffer* FfmpegDecodeOld::m_pConstBuffer =
new ConstBuffer(VideoBufferLength, false, false, VideoPacketLength);
FfmpegDecodeOld::FfmpegDecodeOld(QObject* parent)
: QThread(parent)
, m_bNeedWork(false)
, m_sBufferSize(VideoPacketLength)
, m_pBuffer(nullptr)
, m_pAVIOContext(nullptr)
, m_pAVInputFormat(nullptr)
, m_pAVFormatContext(nullptr)
, m_iId(-1)
, m_pAVPacket(nullptr)
, m_pAVCodec(nullptr)
, m_pAVCodecContext(nullptr)
, m_pAVFrameSrc(nullptr)
, m_pAVFrameDes(nullptr)
, m_pAVCodecParameters(nullptr)
, m_pSwsContext(nullptr)
{}
FfmpegDecodeOld::~FfmpegDecodeOld()
{}
int FfmpegDecodeOld::read_data(void* opaque, uint8_t* buf, int buf_size)
{
FfmpegDecodeOld* pFfmpegDecodeOld = (FfmpegDecodeOld*)opaque;
unsigned short usRecvSize = pFfmpegDecodeOld->getConstBuffer()->read(buf, buf_size);
return usRecvSize;
}
void FfmpegDecodeOld::init()
{
// 1注册所有编解码器(codecs)、解析器(parsers)以及码流过滤器(bitstream filters)
avcodec_register_all();
// 2申请内存
m_pBuffer = (uint8_t*)av_malloc(sizeof(uint8_t) * m_sBufferSize);
// 3申请一个AVIOContext
m_pAVIOContext = avio_alloc_context(m_pBuffer, m_sBufferSize, 0, NULL, read_data, NULL, NULL);
// 4探测网络流格式
if (av_probe_input_buffer(m_pAVIOContext, &m_pAVInputFormat, "", NULL, 0, 0) < 0) {
return;
}
// 5申请一个AVFormatContext
m_pAVFormatContext = avformat_alloc_context();
// 6将申请到的AVIOContext句柄挂载至之前申请的m_pAVFormatContext中
m_pAVFormatContext->pb = m_pAVIOContext;
// 7打开输入的AVFormatContext
if (avformat_open_input(&m_pAVFormatContext, "", m_pAVInputFormat, NULL) < 0) {
return;
}
// 8检索流信息
if (avformat_find_stream_info(m_pAVFormatContext, NULL) < 0) {
return;
}
// 9打印格式信息
av_dump_format(m_pAVFormatContext, 0, "", 0);
// 10判断是否有视频编码解码器
for (int i = 0; i < m_pAVFormatContext->nb_streams; ++i) {
if (m_pAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
m_iId = i;
break;
}
}
if (m_iId == -1) {
avformat_close_input(&m_pAVFormatContext); // 关闭流信息
return;
}
// 11找到流的解码器
m_pAVCodec = avcodec_find_decoder(m_pAVFormatContext->streams[m_iId]->codecpar->codec_id);
if (!m_pAVCodec) {
return; // 未找到解码器
}
// 12分配视频编解码器上下文
m_pAVCodecContext = avcodec_alloc_context3(m_pAVCodec);
if (!m_pAVCodecContext) { // 无法分配视频编解码器上下文
return;
}
// 13将编解码器参数从输入流复制到输出编解码器上下文
m_pAVCodecParameters = m_pAVFormatContext->streams[m_iId]->codecpar;
if (avcodec_parameters_to_context(m_pAVCodecContext,
m_pAVFormatContext->streams[m_iId]->codecpar)
< 0) {
return;
}
// 14打开解码器
if (avcodec_open2(m_pAVCodecContext, m_pAVCodec, NULL) < 0) {
return;
}
// 15申请视频帧存储空间
m_pAVFrameSrc = av_frame_alloc();
if (!m_pAVFrameSrc) { // 申请视频帧存储空间失败
return;
}
// 16申请分配压缩数据包空间
av_init_packet(m_pAVPacket);
if (!m_pAVPacket) { // 申请分配压缩数据包空间失败
return;
}
// 19初始化图像数据存储空间
m_pAVFrameDes = av_frame_alloc();
if (!m_pAVFrameDes) {
return;
}
av_image_alloc(m_pAVFrameDes->data, m_pAVFrameDes->linesize, m_pAVCodecParameters->width,
m_pAVCodecParameters->height, AV_PIX_FMT_RGB24, 1);
// 20初始化图像格式转换
m_pSwsContext = sws_getContext(m_pAVCodecParameters->width, m_pAVCodecParameters->height,
(AVPixelFormat)m_pAVCodecParameters->format,
m_pAVCodecParameters->width, m_pAVCodecParameters->height,
AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
}
void FfmpegDecodeOld::run()
{
int get_pict = 0;
int ret = -1;
// 17获取一个AVPacket数据
while (0 <= av_read_frame(m_pAVFormatContext, m_pAVPacket)) {
if (m_pAVPacket->stream_index == m_iId) {
// 18对AVPacket数据解码并将数据保存到m_pAVFrame中
if (0 <= avcodec_decode_video2(m_pAVCodecContext, m_pAVFrameSrc, &get_pict,
m_pAVPacket)) {
if (get_pict) {
// (21)进行图像格式转换
sws_scale(m_pSwsContext, m_pAVFrameSrc->data, m_pAVFrameSrc->linesize, 0,
m_pAVFrameSrc->height, m_pAVFrameDes->data, m_pAVFrameDes->linesize);
// 22对转换后的数据进行处理
}
}
}
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <QThread>
#include "ConstBuffer.h"
extern "C" {
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#include "libavutil/pixfmt.h"
}
class FfmpegDecodeOld : public QThread
{
Q_OBJECT
public:
FfmpegDecodeOld(QObject* parent = Q_NULLPTR);
~FfmpegDecodeOld();
void init();
static IBuffer* getConstBuffer()
{
return m_pConstBuffer;
}
private:
bool m_bNeedWork;
static ConstBuffer* m_pConstBuffer;
size_t m_sBufferSize;
uint8_t* m_pBuffer;
AVIOContext* m_pAVIOContext;
AVInputFormat* m_pAVInputFormat;
AVFormatContext* m_pAVFormatContext;
int m_iId;
AVPacket* m_pAVPacket; // 压缩数据包
const AVCodec* m_pAVCodec; // 解码器
AVCodecContext* m_pAVCodecContext;
AVCodecParameters* m_pAVCodecParameters;
AVFrame* m_pAVFrameSrc;
AVFrame* m_pAVFrameDes;
SwsContext* m_pSwsContext;
private:
void run() override;
static int read_data(void* opaque, uint8_t* buf, int buf_size);
};

View File

@ -0,0 +1,753 @@
#include "FrameConfig.h"
#include <utility> /**< std::pair std::make_pair */
#include <QDir>
#include <QMessageBox>
FrameConfig::FrameConfig(QWidget* parent)
: QWidget(parent)
, m_pSingleton(nullptr)
, m_strExePath("")
, m_strDataPath("")
, m_strModelType("")
, m_pStatusInfoModel(nullptr)
, strFileDir(".\\")
, m_pValidProcess(nullptr)
, m_pNetDataRecv(nullptr)
, m_uiDataProcFinished(0)
, m_uiDataProcNum(0)
, m_bOfflineParse(false) // 是否正在进行离线解析
, m_bRealParse(false) // 是否正在进行实时解析
, m_uiParseStatus(0)
{
ui.setupUi(this);
m_pSingleton = Singleton::CreateInstance();
m_mapUIntAfterProc.clear();
m_mapUIntProcess.clear();
initNetworkType(); // 初始化网络选择
loadConfigFiles(); // 加载XML配置文件
initStatusInfo(); // 初始化状态信息
connect(ui.pb_loadFile, &QPushButton::clicked, this, &FrameConfig::loadConfigFiles);
connect(ui.pb_offlineParse, &QPushButton::clicked, this, &FrameConfig::startOfflineParse);
connect(ui.pb_realParse, &QPushButton::clicked, this, &FrameConfig::startRealParse);
// 进度条
ui.pb_progressBar->setRange(0, 100);
ui.pb_progressBar->setValue(0);
ui.le_networkIP->setText("225.0.0.151");
ui.le_networkPort->setText("11511");
}
FrameConfig::~FrameConfig()
{}
void FrameConfig::initModelType()
{
ui.cb_modelType->clear();
ui.cb_modelType->addItem("请选择产品型号!");
connect(ui.cb_modelType, &QComboBox::currentTextChanged, this, &FrameConfig::selectModelType);
}
void FrameConfig::initNetworkType()
{
ui.cb_networkType->clear();
ui.cb_networkType->addItem("请选择网络类型!");
ui.cb_networkType->addItem("UDP组播");
ui.cb_networkType->addItem("UDP单播");
connect(ui.cb_networkType, &QComboBox::currentTextChanged, this,
&FrameConfig::selectNetworkType);
}
void FrameConfig::initStatusInfo()
{
m_pStatusInfoModel = new QStandardItemModel(this);
m_pStatusInfoModel->setColumnCount(3);
m_pStatusInfoModel->setHorizontalHeaderLabels({"序号", "时间", "事件"});
ui.tv_statusInfo->setModel(m_pStatusInfoModel);
ui.tv_statusInfo->setColumnWidth(0, 60);
ui.tv_statusInfo->setColumnWidth(1, 150);
ui.tv_statusInfo->setColumnWidth(2, 200);
ui.tv_statusInfo->header()->setDefaultAlignment(Qt::AlignLeft); // 设置表头居中
ui.tv_statusInfo->header()->hide();
}
void FrameConfig::displayStatusInfo(bool isSucess, QString statusInfo)
{
int rowCount = m_pStatusInfoModel->rowCount();
QStandardItem* itemNum = new QStandardItem(QString::number(rowCount + 1));
QString strTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
QStandardItem* itemTime = new QStandardItem(strTime); // 时间
QStandardItem* itemInfo = new QStandardItem(statusInfo); // 信息
m_pStatusInfoModel->setItem(rowCount, 0, itemNum);
m_pStatusInfoModel->setItem(rowCount, 1, itemTime);
m_pStatusInfoModel->setItem(rowCount, 2, itemInfo);
if (isSucess == false) {
m_pStatusInfoModel->item(rowCount, 0)->setForeground(QBrush(QColor(255, 0, 0))); // 红色
m_pStatusInfoModel->item(rowCount, 1)->setForeground(QBrush(QColor(255, 0, 0)));
m_pStatusInfoModel->item(rowCount, 2)->setForeground(QBrush(QColor(255, 0, 0)));
} else {
m_pStatusInfoModel->item(rowCount, 0)->setForeground(QBrush(QColor(0, 0, 0))); // 黑色
m_pStatusInfoModel->item(rowCount, 1)->setForeground(QBrush(QColor(0, 0, 0)));
m_pStatusInfoModel->item(rowCount, 2)->setForeground(QBrush(QColor(0, 0, 0)));
}
for (int i = 0; i < 3; i++) {
// m_pStatusInfoModel->item(rowCount, i)->setTextAlignment(Qt::AlignHCenter |
// Qt::AlignLeft);
m_pStatusInfoModel->item(rowCount, i)->setTextAlignment(Qt::AlignLeft);
}
ui.tv_statusInfo->scrollToBottom(); // 滚动到底部
}
void FrameConfig::loadConfigFiles()
{
if (m_bOfflineParse == true) {
displayStatusInfo(false, "正在离线解析数据!");
return;
}
if (m_bRealParse == true) {
displayStatusInfo(false, "正在实时解析数据!");
return;
}
initModelType();
m_configFilesList.clear();
m_mapStrConfigInfo.clear();
m_strExePath = m_pSingleton->getExePath();
QString strDir = m_strExePath + "/Config/";
QDir dir(strDir);
QStringList fileFilters;
fileFilters << "*.xml";
// 遍历目录下所有满足条件的文件名
QStringList configFiles = dir.entryList(fileFilters, QDir::Files | QDir::Readable,
QDir::Name); // 获取所有目录名称列表
for (QString fileName : configFiles) {
QStringList strSplitList = fileName.split(".");
QString strSuffix = strSplitList.at(strSplitList.length() - 1);
QString strValidName = fileName.mid(0, fileName.length() - strSuffix.length() - 1);
// 读取配置文件
if (!readConfigFile(strDir, fileName, strValidName)) {
continue;
}
ui.cb_modelType->addItem(strValidName);
m_configFilesList.append(strValidName);
}
QMutexLocker locker(&m_mutex);
m_pSingleton->setConfigInfo(m_mapStrConfigInfo);
}
bool FrameConfig::readConfigFile(QString strdir, QString strfile, QString strvalid)
{
QFile file(strdir + strfile);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
QDomDocument domDoc;
if (!domDoc.setContent(&file)) {
file.close();
return false;
}
file.close();
ConfigInfo* configInfo = new ConfigInfo();
configInfo->m_strValidName = strvalid;
QDomElement rootElement = domDoc.documentElement(); // 返回根节点
QDomElement frameElement =
rootElement.firstChildElement("FrameInfo").firstChildElement("Frame"); // 返回根节点的子节点
if (!frameElement.isNull()) {
Frame* pFrame = new Frame();
pFrame->m_strHead = frameElement.attribute("head");
// 解析帧头
char cHead[2] = {0x00, 0x00};
unsigned short usHead = pFrame->m_strHead.toUShort(nullptr, 16);
memcpy(cHead, (char*)&usHead + 1, 1);
memcpy(cHead + 1, (char*)&usHead, 1);
pFrame->m_headArray = QByteArray(cHead, 2);
pFrame->m_usSubFrameType = frameElement.attribute("subFrameType").toUShort();
if (pFrame->m_usSubFrameType == 2) { // 反码副帧
// 求反码副帧帧头
unsigned short usTemp = 0xFFFF;
unsigned short usSubHead = ~(usHead & usTemp);
memcpy(cHead, (char*)&usSubHead + 1, 1);
memcpy(cHead + 1, (char*)&usSubHead, 1);
pFrame->m_subHeadArray = QByteArray(cHead, 2);
}
pFrame->m_usHeadAddr = frameElement.attribute("headAddr").toUShort();
pFrame->m_usIdAddr = frameElement.attribute("idAddr").toUShort();
pFrame->m_usIdStart = frameElement.attribute("idStart").toUShort();
pFrame->m_uiRow = frameElement.attribute("row").toUInt();
pFrame->m_uiColumn = frameElement.attribute("column").toUInt();
pFrame->m_dFrameTime = frameElement.attribute("frameTime").toDouble(); // 帧间隔
pFrame->m_usIdEnd = pFrame->m_usIdStart + pFrame->m_uiRow - 1;
// 计算帧长
pFrame->m_uiFrameLen = pFrame->m_uiRow * pFrame->m_uiColumn;
switch (pFrame->m_usHeadAddr) {
case 1: // 帧头在每行最前
pFrame->m_usBeforeHeadLen = 0;
break;
case 2: // 帧头在每行最后
pFrame->m_usBeforeHeadLen = pFrame->m_uiColumn - 2;
break;
default:
break;
}
configInfo->m_pFrame = pFrame;
}
QDomElement paramElement =
rootElement.firstChildElement("ParamInfo").firstChildElement("Param"); // 返回根节点的子节点
while (!paramElement.isNull()) {
Param* param = new Param();
param->m_uiId = paramElement.attribute("id").toUInt();
param->m_strCode = paramElement.attribute("code");
param->m_strTitle = paramElement.attribute("title");
param->m_strChannelGroup = paramElement.attribute("channelGroup");
param->m_pChannelGroup = new ChannelGroup();
// 对通道进行拆分
QString strChannelGroup = param->m_strChannelGroup;
channelDeal(configInfo->m_pFrame, param, strChannelGroup);
param->m_usModel = paramElement.attribute("model").toUShort();
if (param->m_usModel == 3) { // 图像
param->m_usFormat = paramElement.attribute("format").toUShort(); // 原始图像格式
param->m_uiWidth = paramElement.attribute("width").toUInt(); // 一帧图像像素宽度
param->m_uiHeight = paramElement.attribute("height").toUInt(); // 一帧图像像素高度
}
if (param->m_usModel == 2 || param->m_usModel == 3) { // 数字量和图像
if (paramElement.hasAttribute("fill")) {
param->m_strFill = paramElement.attribute("fill");
}
} else if (param->m_usModel == 1 || param->m_usModel == 4) { // 模拟量和状态量
param->m_strFill = "";
}
// 获取填充值
char cFill = 0x00;
QString strFill = param->m_strFill;
// 剔除0x
if (strFill.contains("0x")) {
strFill = strFill.remove("0x");
}
unsigned short usFill = 0;
for (int i = 0; i < strFill.size(); i += 2) {
unsigned short usFill = strFill.mid(i, 2).toUShort(nullptr, 16);
memcpy(&cFill, (char*)&usFill, 1);
param->m_fillArray.append(cFill);
}
param->m_usType = paramElement.attribute("type").toUShort();
param->m_usOrder = paramElement.attribute("order").toUShort();
param->m_strBit = paramElement.attribute("bit");
param->m_strFormula = paramElement.attribute("formula");
// 坐标公式处理
if (param->m_strFormula != "") {
formulaDeal(param);
}
param->m_strUnit = paramElement.attribute("unit");
configInfo->m_mapUIntParam.insert(std::pair<unsigned int, Param*>(param->m_uiId, param));
paramElement = paramElement.nextSiblingElement();
}
m_mapStrConfigInfo.insert(std::pair<QString, ConfigInfo*>(configInfo->m_strValidName, configInfo));
return true;
}
void FrameConfig::channelDeal(Frame* frame, Param* param, QString channelGroup)
{
if (channelGroup.contains(
";", Qt::CaseInsensitive)) { // 包含";",可能是分段连续列、分段单列、分段单坐标
if (channelGroup.contains("") && channelGroup.contains("Col-")) { // 说明存在连续列
for (unsigned int i = 0; i < frame->m_uiRow; i++) { // 对每一行进行处理
QStringList strChannelList = channelGroup.split(";");
for (int j = 0; j < strChannelList.size(); j++) {
QString strTemp = strChannelList.at(j);
QStringList strTempList = strTemp.split("");
QString strStart = strTempList.at(0); // 第一个
QString strEnd = strTempList.at(1); // 最后一个
unsigned int uiStart = 0;
unsigned int uiEnd = 0;
uiStart = strStart.split("-").at(1).toUInt();
uiEnd = strEnd.split("-").at(1).toUInt();
for (unsigned int k = uiStart; k <= uiEnd; k++) {
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = i;
pChannel->m_uiSubFrame = k;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * i + k; // 绝对位置
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
}
}
param->m_pChannelGroup->m_uiChannelNum = param->m_pChannelGroup->m_vecChannel.size();
} else if (!channelGroup.contains("")
&& channelGroup.contains("Col-")) { // 说明包含列,但不包含连续列
for (unsigned int i = 0; i < frame->m_uiRow; i++) { // 对每一行进行处理
QStringList strChannelList = channelGroup.split(";");
for (int j = 0; j < strChannelList.size(); j++) {
QString strTemp = strChannelList.at(j);
unsigned int uiColumn = strTemp.split("-").at(1).toUInt();
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = i;
pChannel->m_uiSubFrame = uiColumn;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * i + uiColumn; // 绝对位置
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
}
param->m_pChannelGroup->m_uiChannelNum = param->m_pChannelGroup->m_vecChannel.size();
} else if (!channelGroup.contains("") && !channelGroup.contains("Col-")
&& channelGroup.contains("#")) { // 说明为单坐标
QStringList strChannelList = channelGroup.split(";");
for (int i = 0; i < strChannelList.size(); i++) {
QString strTemp = strChannelList.at(i);
QStringList strTempList = strTemp.split("#");
QStringList strLeftList = strTempList.at(0).split(","); // 行
QStringList strRightList = strTempList.at(1).split(","); // 列
unsigned int uiRow = 0;
unsigned int uiColumn = 0;
for (unsigned int i = 0; i < strLeftList.size(); i++) {
uiRow = strLeftList.at(i).toUInt();
for (unsigned int j = 0; j < strRightList.size(); j++) {
uiColumn = strRightList.at(j).toUInt();
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = uiRow;
pChannel->m_uiSubFrame = uiColumn;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * uiRow + uiColumn;
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
}
param->m_pChannelGroup->m_uiChannelNum =
param->m_pChannelGroup->m_vecChannel.size();
}
}
} else { // 不包含";",可能是连续列、单列、单坐标
if (channelGroup.contains("") && channelGroup.contains("Col-")) { // 说明存在连续列
for (unsigned int i = 0; i < frame->m_uiRow; i++) { // 对每一行进行处理
QStringList strTempList = channelGroup.split("");
QString strStart = strTempList.at(0); // 第一个
QString strEnd = strTempList.at(1); // 最后一个
unsigned int uiStart = 0;
unsigned int uiEnd = 0;
uiStart = strStart.split("-").at(1).toUInt();
uiEnd = strEnd.split("-").at(1).toUInt();
for (unsigned int k = uiStart; k <= uiEnd; k++) {
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = i;
pChannel->m_uiSubFrame = k;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * i + k; // 绝对位置
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
}
param->m_pChannelGroup->m_uiChannelNum = param->m_pChannelGroup->m_vecChannel.size();
} else if (!channelGroup.contains("")
&& channelGroup.contains("Col-")) { // 说明包含列,但不包含连续列
for (unsigned int i = 0; i < frame->m_uiRow; i++) { // 对每一行进行处理
unsigned int uiColumn = channelGroup.split("-").at(1).toUInt();
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = i;
pChannel->m_uiSubFrame = uiColumn;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * i + uiColumn; // 绝对位置
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
param->m_pChannelGroup->m_uiChannelNum = param->m_pChannelGroup->m_vecChannel.size();
} else if (!channelGroup.contains("") && !channelGroup.contains("Col-")
&& channelGroup.contains("#")) { // 说明为单坐标
QStringList strTempList = channelGroup.split("#");
QStringList strLeftList = strTempList.at(0).split(","); // 行
QStringList strRightList = strTempList.at(1).split(","); // 列
unsigned int uiRow = 0;
unsigned int uiColumn = 0;
for (unsigned int i = 0; i < strLeftList.size(); i++) {
uiRow = strLeftList.at(i).toUInt();
for (unsigned int j = 0; j < strRightList.size(); j++) {
uiColumn = strRightList.at(j).toUInt();
Channel* pChannel = new Channel();
pChannel->m_uiMinorFrame = uiRow;
pChannel->m_uiSubFrame = uiColumn;
pChannel->m_uiAbsolutePos = frame->m_uiColumn * uiRow + uiColumn;
param->m_pChannelGroup->m_vecChannel.push_back(pChannel);
}
}
param->m_pChannelGroup->m_uiChannelNum = param->m_pChannelGroup->m_vecChannel.size();
}
}
}
void FrameConfig::formulaDeal(Param* param)
{
// 利用正则表达式对公式进行匹配
QRegExp regFormula("^\\[((-?\\d+)|((-?\\d+)(\\.\\d+)))(,((-?\\d+)|((-?\\d+)(\\.\\d+))))*\\]$");
if (regFormula.exactMatch(param->m_strFormula)) {
int iStart = param->m_strFormula.indexOf("[") + 1;
int iEnd = param->m_strFormula.indexOf("]");
QString strValid = param->m_strFormula.mid(iStart, iEnd - iStart);
QStringList strList = strValid.split(",");
int equaNum = strList.size() - 1; // 最高次方
param->m_formula.equaNum = equaNum;
for (int i = 0; i < strList.size(); i++) {
param->m_formula.Equation[i] = strList.at(equaNum - i).toDouble();
}
}
}
void FrameConfig::selectModelType()
{
if (m_bOfflineParse == true) {
displayStatusInfo(false, "正在离线解析数据!");
return;
}
if (m_bRealParse == true) {
displayStatusInfo(false, "正在实时解析数据!");
return;
}
m_strModelType = ui.cb_modelType->currentText();
if (m_strModelType == "请选择产品型号!") {
return;
}
m_pSingleton->setModelType(m_strModelType);
emit switchModelType(m_strModelType);
}
void FrameConfig::selectNetworkType()
{
if (ui.cb_networkType->currentText() == "请选择网络类型!") {
return;
}
QRegExp ipExp(
"\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-"
"9]?)\\b");
QRegExp portExp(
"^([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]"
"\\d|6553[0-5])$");
// 判断IP地址和端口号
QString strIP = ui.le_networkIP->text(); // IP地址
QString strPort = ui.le_networkPort->text(); // 端口号
bool bIpExp = ipExp.exactMatch(strIP);
bool bPortExp = portExp.exactMatch(strPort);
if (!bIpExp || !bPortExp) {
displayStatusInfo(false, "IP地址或端口号有误!");
return;
}
QHostAddress hostAddress = QHostAddress(strIP);
QString strNetworkType = ui.cb_networkType->currentText();
if (strNetworkType == "UDP单播") {
m_network.type = 1;
} else if (strNetworkType == "UDP组播") {
if (!hostAddress.isMulticast()) {
displayStatusInfo(false, "组播地址设置有误!");
return;
}
m_network.type = 2;
}
m_network.ip = strIP;
m_network.port = strPort.toUShort();
}
void FrameConfig::startOfflineParse()
{
if (ui.cb_modelType->currentText() == "请选择产品型号!") {
displayStatusInfo(false, "请选择产品型号!");
return;
}
if (m_bRealParse == true) {
displayStatusInfo(false, "正在实时解析数据!");
return;
}
if (m_bOfflineParse == false) {
QString fileName = QFileDialog::getOpenFileName(this, QObject::tr("请选择数据文件"),
strFileDir, "*.*;;*.bin;;*.dat");
if (fileName == "") {
return;
}
m_bOfflineParse = true;
m_uiParseStatus = 1; // 离线解析
ui.pb_offlineParse->setText("停止");
displayStatusInfo(true, "开始离线解析数据!");
int pos = fileName.lastIndexOf("/");
strFileDir = fileName.left(pos);
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
return;
}
QByteArray byteArray = file.readAll();
startAfterProc(byteArray);
} else if (m_bOfflineParse == true) {
stopAfterProc();
m_bOfflineParse = false;
m_uiParseStatus = 0;
ui.pb_offlineParse->setText("离线解析");
displayStatusInfo(true, "离线解析数据结束!");
}
emit parseStatus(m_uiParseStatus);
}
void FrameConfig::startAfterProc(QByteArray byteArray)
{
createDataPath(m_uiParseStatus);
map<QString, ConfigInfo*>::iterator mapIter;
mapIter = m_mapStrConfigInfo.begin();
while (mapIter != m_mapStrConfigInfo.end()) {
if ((*mapIter).first != m_strModelType) {
++mapIter;
continue;
}
ValidAfterProc* m_pValidAfterProc = new ValidAfterProc();
connect(m_pValidAfterProc, &ValidAfterProc::validDataExtract, this,
&FrameConfig::validDataExtract);
connect(m_pValidAfterProc, &ValidAfterProc::finished, m_pValidAfterProc,
&ValidAfterProc::deleteLater);
m_pValidAfterProc->init((*mapIter).second->m_pFrame);
m_pValidAfterProc->setData(byteArray);
m_pValidAfterProc->start();
++mapIter;
}
}
// 按变量个数进行提取
void FrameConfig::validDataExtract(QByteArray byteArray)
{
displayStatusInfo(true, "开始解析数据!");
ui.pb_progressBar->setValue(0);
m_uiDataProcFinished = 0;
auto mapIter = m_mapStrConfigInfo.find(m_strModelType);
if (mapIter != m_mapStrConfigInfo.end()) {
// 针对每个参数建立一个数据处理线程
m_uiDataProcNum = (unsigned int)mapIter->second->m_mapUIntParam.size();
for (auto param : mapIter->second->m_mapUIntParam) {
if (param.second->m_usModel == 1 || param.second->m_usModel == 4) { // 工程量或状态量
CurveWidget* curveWidget = param.second->getCurveWidget();
curveWidget->clearWidget();
curveWidget->m_bRefTime = false;
AnalogAfterProc* pAnalogAfterProc = new AnalogAfterProc();
connect(pAnalogAfterProc, &AnalogAfterProc::parseFinished, curveWidget,
&CurveWidget::parseFinished);
connect(pAnalogAfterProc, &AnalogAfterProc::finished, this,
&FrameConfig::dataProcFinished);
connect(pAnalogAfterProc, &AnalogAfterProc::finished, pAnalogAfterProc,
&AnalogAfterProc::deleteLater);
pAnalogAfterProc->init(mapIter->second->m_pFrame, param);
pAnalogAfterProc->setData(byteArray);
pAnalogAfterProc->start();
} else if (param.second->m_usModel == 2) { // 数字量
DigitalAfterProc* pDigitalAfterProc = new DigitalAfterProc();
connect(pDigitalAfterProc, &DigitalAfterProc::finished, this,
&FrameConfig::dataProcFinished);
connect(pDigitalAfterProc, &DigitalAfterProc::finished, pDigitalAfterProc,
&DigitalAfterProc::deleteLater);
pDigitalAfterProc->init(mapIter->second->m_pFrame, param);
pDigitalAfterProc->setData(byteArray);
pDigitalAfterProc->start();
} else if (param.second->m_usModel == 3) { // 图像
VideoAfterProc* pVideoAfterProc = new VideoAfterProc();
connect(pVideoAfterProc, &VideoAfterProc::dataProcFinished, this,
&FrameConfig::dataProcFinished);
connect(pVideoAfterProc, &VideoAfterProc::finished, pVideoAfterProc,
&VideoAfterProc::deleteLater);
pVideoAfterProc->init(mapIter->second->m_pFrame, param);
pVideoAfterProc->getFfmpegDecode();
VideoWidget* videoWidget = param.second->getVideoWidget();
if (videoWidget != nullptr) {
// 建立播放窗口与视频数据解析线程之间的关系
connect(videoWidget, &VideoWidget::startPlayer, pVideoAfterProc,
&VideoAfterProc::startPlayer);
connect(videoWidget, &VideoWidget::videoSpeed, pVideoAfterProc,
&VideoAfterProc::videoSpeed);
connect(videoWidget, &VideoWidget::setPlayPos, pVideoAfterProc,
&VideoAfterProc::setPlayPos);
connect(pVideoAfterProc, &VideoAfterProc::playedCount, videoWidget,
&VideoWidget::playedCount);
}
pVideoAfterProc->setData(byteArray);
pVideoAfterProc->start();
m_mapUIntAfterProc.insert(std::make_pair(param.second->m_uiId, pVideoAfterProc));
}
}
}
}
void FrameConfig::dataProcFinished()
{
++m_uiDataProcFinished;
if (m_uiDataProcFinished < m_uiDataProcNum) {
int value = (int)((m_uiDataProcFinished * 1.0 / m_uiDataProcNum * 1.0) * 100.0);
ui.pb_progressBar->setValue(value);
return;
}
ui.pb_progressBar->setValue(100);
displayStatusInfo(true, "提取数据结束!");
}
void FrameConfig::stopAfterProc()
{
// 停止视频窗口播放
auto mapIter = m_mapStrConfigInfo.find(m_strModelType);
if (mapIter != m_mapStrConfigInfo.end()) {
m_uiDataProcNum = (unsigned int)mapIter->second->m_mapUIntParam.size();
for (auto param : mapIter->second->m_mapUIntParam) {
if (param.second->m_usModel == 1 || param.second->m_usModel == 4) { // 工程量或状态量
} else if (param.second->m_usModel == 3) { // 图像
param.second->getVideoWidget()->stopPlay();
}
}
}
for (auto afterproc : m_mapUIntAfterProc) { // 关闭数据解析
afterproc.second->stop();
}
m_mapUIntAfterProc.clear();
ui.pb_progressBar->setValue(0);
}
void FrameConfig::startRealParse()
{
if (ui.cb_modelType->currentText() == "请选择产品型号!") {
displayStatusInfo(false, "请选择产品型号!");
return;
}
if (ui.cb_networkType->currentText() == "请选择网络类型!") {
displayStatusInfo(false, "请选择网络类型!");
return;
}
if (m_bOfflineParse == true) {
displayStatusInfo(false, "正在离线解析数据!");
return;
}
if (m_bRealParse == false) {
m_bRealParse = true;
m_uiParseStatus = 2; // 在线解析
ui.pb_realParse->setText("停止");
displayStatusInfo(true, "开始实时解析数据!");
selectNetworkType();
startProcess();
} else if (m_bRealParse == true) {
stopProcess();
m_bRealParse = false;
m_uiParseStatus = 0;
ui.pb_realParse->setText("实时解析");
displayStatusInfo(true, "实时解析数据结束!");
}
emit parseStatus(m_uiParseStatus);
}
void FrameConfig::startProcess()
{
createDataPath(m_uiParseStatus);
Frame* pFrame = nullptr;
auto mapIter = m_mapStrConfigInfo.find(m_strModelType);
if (mapIter != m_mapStrConfigInfo.end()) {
m_uiDataProcNum = (unsigned int)mapIter->second->m_mapUIntParam.size();
for (auto param : mapIter->second->m_mapUIntParam) {
pFrame = mapIter->second->m_pFrame;
if (param.second->m_usModel == 1 || param.second->m_usModel == 4) { // 工程量或状态量
CurveWidget* curveWidget = param.second->getCurveWidget();
curveWidget->clearWidget();
curveWidget->startRefresh(true);
curveWidget->m_bRefTime = false;
AnalogProcess* pAnalogProcess = new AnalogProcess();
connect(pAnalogProcess, &AnalogProcess::finished, pAnalogProcess,
&AnalogProcess::deleteLater);
pAnalogProcess->init(mapIter->second->m_pFrame, param);
pAnalogProcess->start();
m_mapUIntProcess.insert(std::make_pair(param.second->m_uiId, pAnalogProcess));
} else if (param.second->m_usModel == 2) { // 数字量
DigitalProcess* pDigitalProcess = new DigitalProcess();
connect(pDigitalProcess, &DigitalProcess::finished, pDigitalProcess,
&DigitalProcess::deleteLater);
pDigitalProcess->init(mapIter->second->m_pFrame, param);
pDigitalProcess->start();
m_mapUIntProcess.insert(std::make_pair(param.second->m_uiId, pDigitalProcess));
} else if (param.second->m_usModel == 3) { // 图像
VideoWidget* videoWidget = param.second->getVideoWidget();
videoWidget->clearWidget();
VideoProcess* pVideoProcess = new VideoProcess();
connect(pVideoProcess, &VideoProcess::finished, pVideoProcess,
&VideoProcess::deleteLater);
pVideoProcess->init(mapIter->second->m_pFrame, param);
pVideoProcess->getFfmpegDecode();
if (videoWidget != nullptr) {
// 建立播放窗口与视频数据解析线程之间的关系
connect(videoWidget, &VideoWidget::startPlayer, pVideoProcess,
&VideoProcess::startPlayer);
// connect(pVideoProcess, &VideoProcess::playedCount, videoWidget,
// &VideoWidget::playedCount);
}
pVideoProcess->start();
m_mapUIntProcess.insert(std::make_pair(param.second->m_uiId, pVideoProcess));
}
}
m_pValidProcess = new ValidProcess();
connect(m_pValidProcess, &ValidProcess::finished, m_pValidProcess,
&ValidProcess::deleteLater);
m_pValidProcess->init(mapIter->second->m_pFrame, m_mapUIntProcess);
m_pValidProcess->start();
}
m_pNetDataRecv = new NetDataRecv();
connect(m_pNetDataRecv, &NetDataRecv::finished, m_pNetDataRecv, &NetDataRecv::deleteLater);
m_pNetDataRecv->init(pFrame, m_network, m_pValidProcess);
m_pNetDataRecv->start();
}
void FrameConfig::stopProcess()
{
auto mapIter = m_mapStrConfigInfo.find(m_strModelType);
if (mapIter != m_mapStrConfigInfo.end()) {
m_uiDataProcNum = (unsigned int)mapIter->second->m_mapUIntParam.size();
for (auto param : mapIter->second->m_mapUIntParam) {
if (param.second->m_usModel == 1 || param.second->m_usModel == 4) { // 工程量或状态量
param.second->getCurveWidget()->startRefresh(false); // 停止曲线界面刷新
} else if (param.second->m_usModel == 3) { // 图像
param.second->getVideoWidget()->stopPlay(); // 停止图像窗口播放
}
}
}
if (m_pNetDataRecv) { // 关闭网络接收
m_pNetDataRecv->stop();
m_pNetDataRecv->quit();
m_pNetDataRecv->wait();
delete m_pNetDataRecv;
m_pNetDataRecv = nullptr;
}
if (m_pValidProcess) { // 关闭缓存处理
m_pValidProcess->stop();
m_pValidProcess->quit();
m_pValidProcess->wait();
delete m_pValidProcess;
m_pValidProcess = nullptr;
}
for (auto process : m_mapUIntProcess) { // 关闭数据解析
process.second->stop();
process.second->quit();
process.second->wait();
delete process.second;
process.second = nullptr;
}
m_mapUIntProcess.clear();
}
void FrameConfig::createDataPath(unsigned int status)
{
QString strStatus = "";
if (status == 1) { // 离线解析
strStatus = "Offline";
} else if (status == 2) { // 实时解析
strStatus = "Real";
}
// 根据时间建立数据存储路径
QString strDateTime = QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss");
m_strDataPath = m_strExePath + "/Data/" + m_strModelType + "_" + strStatus + "_" + strDateTime;
auto succ = QDir(m_strDataPath).mkpath(".");
m_pSingleton->setDataPath(m_strDataPath);
// 创建数据存储文件
auto mapIter = m_mapStrConfigInfo.find(m_strModelType);
if (mapIter != m_mapStrConfigInfo.end()) {
mapIter->second->m_pFrame->m_dataStore.m_strStoreType = strStatus; // 存储类型
mapIter->second->m_pFrame->m_dataStore.m_strDateTime = strDateTime; // 存储日期
mapIter->second->m_pFrame->m_dataStore.m_strDataPath = m_strDataPath; // 数据存储路径
}
}

View File

@ -0,0 +1,90 @@
#pragma once
#include <QComboBox>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QHostAddress>
#include <QMutex>
#include <QMutexLocker>
#include <QPushButton>
#include <QRegExp>
#include <QStandardItemModel>
#include <QWidget>
#include <QtXml>
#include "ConfigInfo.h"
#include "Singleton.h"
#include "tinyxml2.h"
#include "ui_FrameConfig.h"
#include "AnalogProcess.h"
#include "DigitalProcess.h"
#include "IProcess.h"
#include "NetDataRecv.h"
#include "ValidProcess.h"
#include "VideoProcess.h"
#include "AnalogAfterProc.h"
#include "DigitalAfterProc.h"
#include "IAfterProc.h"
#include "ValidAfterProc.h"
#include "VideoAfterProc.h"
class FrameConfig : public QWidget
{
Q_OBJECT
public:
FrameConfig(QWidget* parent = nullptr);
~FrameConfig();
private:
Ui::FrameConfigClass ui;
Singleton* m_pSingleton;
QStringList m_configFilesList; // 配置文件
QString m_strExePath;
QString m_strDataPath;
std::map<QString, ConfigInfo*> m_mapStrConfigInfo;
QString m_strModelType;
QMutex m_mutex;
QStandardItemModel* m_pStatusInfoModel;
int m_iNetworkType;
Network m_network;
QString strFileDir;
std::map<unsigned int, VideoAfterProc*> m_mapUIntAfterProc;
std::map<unsigned int, IProcess*> m_mapUIntProcess;
ValidProcess* m_pValidProcess;
NetDataRecv* m_pNetDataRecv;
unsigned int m_uiDataProcFinished;
unsigned int m_uiDataProcNum;
bool m_bOfflineParse; // 是否正在进行离线解析
bool m_bRealParse; // 是否正在进行实时解析
unsigned int m_uiParseStatus; // 0无任务解析1离线解析2在线解析
private:
void initModelType();
void initNetworkType();
void initStatusInfo();
void startAfterProc(QByteArray byteArray);
void stopAfterProc();
void startProcess();
void stopProcess();
void createDataPath(unsigned int status);
private slots:
void loadConfigFiles();
void selectModelType();
void selectNetworkType();
void startOfflineParse();
void startRealParse();
bool readConfigFile(QString strdir, QString strfile, QString strname);
void channelDeal(Frame* frame, Param* param, QString channel);
void formulaDeal(Param* param);
// void dataChannelDeal(Frame* frame,Param* param, QString strTemp);
void validDataExtract(QByteArray byteArray);
void dataProcFinished();
public slots:
void displayStatusInfo(bool isSucess, QString statusInfo);
signals:
void switchModelType(QString modeltype);
void parseStatus(unsigned status);
};

View File

@ -0,0 +1,496 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FrameConfigClass</class>
<widget class="QWidget" name="FrameConfigClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>970</height>
</rect>
</property>
<property name="windowTitle">
<string>FrameConfig</string>
</property>
<widget class="QGroupBox" name="gb_offlineParse">
<property name="geometry">
<rect>
<x>10</x>
<y>85</y>
<width>275</width>
<height>70</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox#gb_offlineParse{
border:1px solid rgb(129, 129, 129);
margin-top:2ex;
}
QGroupBox#gb_offlineParse::title{
subcontrol-origin:margin;
subcontrol-position:top left;
left:20px;
}</string>
</property>
<property name="title">
<string>离线解析</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>5</x>
<y>15</y>
<width>266</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>解析进度:</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="pb_progressBar">
<property name="value">
<number>24</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pb_offlineParse">
<property name="geometry">
<rect>
<x>195</x>
<y>45</y>
<width>75</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#pb_offlineParse{
background-color:rgb(255,255,255);
}
QPushButton#pb_offlineParse:hover{
background-color:rgb(240,240,240);
}</string>
</property>
<property name="text">
<string>离线解析</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="gb_realParse">
<property name="geometry">
<rect>
<x>10</x>
<y>160</y>
<width>276</width>
<height>101</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox#gb_realParse{
border:1px solid rgb(129, 129, 129);
margin-top:2ex;
}
QGroupBox#gb_realParse::title{
subcontrol-origin:margin;
subcontrol-position:top left;
left:20px;
}</string>
</property>
<property name="title">
<string>实时解析</string>
</property>
<widget class="QPushButton" name="pb_realParse">
<property name="geometry">
<rect>
<x>195</x>
<y>75</y>
<width>75</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#pb_realParse{
background-color:rgb(255,255,255);
}
QPushButton#pb_realParse:hover{
background-color:rgb(240,240,240);
}</string>
</property>
<property name="text">
<string>实时解析</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>5</x>
<y>15</y>
<width>266</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="lb_multiAddrSend">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<family>SimSun-ExtB</family>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>网络地址:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="le_networkIP">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>30</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lb_multiPortSend">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<family>SimSun-ExtB</family>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">QLabel#lb_columnNum2{
Font:75 11pt;
}</string>
</property>
<property name="text">
<string>端口:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="le_networkPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>30</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>5</x>
<y>45</y>
<width>266</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="lb_networkType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>55</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>网络类型:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_networkType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QComboBox#cb_networkType{
border:1px solid;
}</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QGroupBox" name="gb_configLoad">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>275</width>
<height>70</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox#gb_configLoad{
border:1px solid rgb(129, 129, 129);
margin-top:2ex;
}
QGroupBox#gb_configLoad::title{
subcontrol-origin:margin;
subcontrol-position:top left;
left:20px;
}</string>
</property>
<property name="title">
<string>配置加载</string>
</property>
<widget class="QWidget" name="layoutWidget_2">
<property name="geometry">
<rect>
<x>5</x>
<y>15</y>
<width>266</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lb_modelType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>55</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>型号选择:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_modelType">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QComboBox#cb_modelType{
border:1px solid;
}</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pb_loadFile">
<property name="geometry">
<rect>
<x>195</x>
<y>45</y>
<width>75</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#pb_loadFile{
background-color:rgb(255,255,255);
}
QPushButton#pb_loadFile:hover{
background-color:rgb(240,240,240);
}</string>
</property>
<property name="text">
<string>刷新配置</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="gb_frameConfig">
<property name="geometry">
<rect>
<x>295</x>
<y>10</y>
<width>1615</width>
<height>950</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QGroupBox#gb_frameConfig{
border:1px solid rgb(129, 129, 129);
margin-top:2ex;
}
QGroupBox#gb_frameConfig::title{
subcontrol-origin:margin;
subcontrol-position:top left;
left:20px;
}</string>
</property>
<property name="title">
<string>状态信息</string>
</property>
<widget class="QTreeView" name="tv_statusInfo">
<property name="geometry">
<rect>
<x>10</x>
<y>15</y>
<width>1595</width>
<height>925</height>
</rect>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,127 @@
#include "GeneralTesting.h"
#include <QFileDialog>
#include <QStandardPaths>
GeneralTesting::GeneralTesting(QWidget* parent)
: QMainWindow(parent)
, m_bIsNormalShow(true)
, m_fInitWidth(1920.0) // 初始化宽度
, m_fInitHeight(1080.0) // 初始化高度
, m_bMoving(false)
, m_fMaxWidth(0.0)
, m_fMaxHeight(0.0)
// 窗口界面
, m_pFrameConfig(nullptr)
, m_pParamParse(nullptr)
, m_pVideoParse(nullptr)
{
ui.setupUi(this);
// Set the icon for the main window
setWindowIcon(QIcon(":/GeneralTesting/UI/gtt128x128.png"));
createWidget(); // 创建子窗口
getWindowRatio();
}
GeneralTesting::~GeneralTesting()
{
if (m_pFrameConfig) {
delete m_pFrameConfig;
m_pFrameConfig = nullptr;
}
if (m_pParamParse) {
delete m_pParamParse;
m_pParamParse = nullptr;
}
if (m_pVideoParse) {
delete m_pVideoParse;
m_pVideoParse = nullptr;
}
}
void GeneralTesting::createWidget()
{
m_pFrameConfig = new FrameConfig(this);
m_pParamParse = new ParamParse(this);
m_pVideoParse = new VideoParse(this);
connect(m_pFrameConfig, &FrameConfig::switchModelType, m_pParamParse,
&ParamParse::switchModelType);
connect(m_pFrameConfig, &FrameConfig::switchModelType, m_pVideoParse,
&VideoParse::switchModelType);
connect(m_pFrameConfig, &FrameConfig::parseStatus, m_pParamParse, &ParamParse::parseStatus);
connect(m_pFrameConfig, &FrameConfig::parseStatus, m_pVideoParse, &VideoParse::parseStatus);
ui.sw_pageSwitch->addWidget(m_pFrameConfig);
ui.sw_pageSwitch->addWidget(m_pParamParse);
ui.sw_pageSwitch->addWidget(m_pVideoParse);
ui.sw_pageSwitch->setCurrentWidget(m_pFrameConfig);
}
// 获取屏幕分辨率
void GeneralTesting::getWindowRatio()
{
QScreen* m_pScreen = QApplication::primaryScreen();
m_windMaxSize = m_pScreen->availableVirtualSize();
m_fMaxWidth = m_windMaxSize.width();
m_fMaxHeight = m_windMaxSize.height();
if (m_fInitWidth < m_fMaxWidth && m_fInitHeight < m_fMaxHeight) {
float fDeltaWidth = (m_fMaxWidth - m_fInitWidth) / 2.0;
float fDeltaHeight = (m_fMaxHeight - m_fInitHeight) / 2.0;
this->setGeometry(fDeltaWidth, fDeltaHeight, m_fInitWidth, m_fInitHeight);
this->setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);
} else {
// 最大化窗体,此时默认占满可使用屏幕尺寸.
this->setWindowState(Qt::WindowMaximized);
}
}
void GeneralTesting::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton) {
m_bMoving = true;
QCursor cursor = this->cursor();
Qt::CursorShape shape = cursor.shape();
}
}
void GeneralTesting::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton) {
m_bMoving = false;
}
}
void GeneralTesting::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton) {
}
}
void GeneralTesting::mouseMoveEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton) {
}
}
void GeneralTesting::on_actionQuit_triggered()
{
this->close();
}
void GeneralTesting::on_actionImport_triggered()
{
auto fileName = QFileDialog::getOpenFileName(
this, tr("Open Log File"), QStandardPaths::displayName(QStandardPaths::HomeLocation),
tr("Binary File (*.bin)"));
}
void GeneralTesting::on_actionMain_triggered()
{
ui.sw_pageSwitch->setCurrentWidget(m_pFrameConfig);
}
void GeneralTesting::on_actionConfig_triggered()
{
ui.sw_pageSwitch->setCurrentWidget(m_pParamParse);
}
void GeneralTesting::on_actionVideo_triggered()
{
ui.sw_pageSwitch->setCurrentWidget(m_pVideoParse);
}

View File

@ -0,0 +1,51 @@
#pragma once
#include <QActionGroup>
#include <QDebug>
#include <QDesktopWidget>
#include <QFont>
#include <QList>
#include <QMouseEvent>
#include <QScreen>
#include <QWidget>
#include <QtWidgets/QMainWindow>
#include "FrameConfig.h"
#include "ParamParse.h"
#include "VideoParse.h"
#include "ui_GeneralTesting.h"
class GeneralTesting : public QMainWindow
{
Q_OBJECT
public:
GeneralTesting(QWidget* parent = nullptr);
~GeneralTesting();
void createWidget(); // 创建界面
private:
Ui::GeneralTestingClass ui;
bool m_bIsNormalShow; // 窗口是否正常显示
float m_fInitWidth; // 初始设计宽度
float m_fInitHeight; // 初始设计高度
bool m_bMoving; // 鼠标是否正在移动
QSize m_windMaxSize; // 窗口最大尺寸
float m_fMaxWidth;
float m_fMaxHeight;
// 窗口界面
QList<QWidget*> m_widgetList;
FrameConfig* m_pFrameConfig; // 帧结构配置界面
ParamParse* m_pParamParse; // 参数解析界面
VideoParse* m_pVideoParse; // 视频解析界面
private:
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void getWindowRatio(); // 获取屏幕分辨率
private slots:
void on_actionQuit_triggered();
void on_actionImport_triggered();
void on_actionMain_triggered();
void on_actionConfig_triggered();
void on_actionVideo_triggered();
};

View File

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/GeneralTesting">
<file>UI/background.png</file>
<file>UI/Open.png</file>
<file>UI/gtt128x128.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GeneralTestingClass</class>
<widget class="QMainWindow" name="GeneralTestingClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>926</width>
<height>635</height>
</rect>
</property>
<property name="windowTitle">
<string>通用数据测试软件</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QStackedWidget" name="sw_pageSwitch">
<property name="styleSheet">
<string notr="true">QStackedWidget#sw_pageSwitch{
border:1px solid;
}
</string>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="page_1"/>
<widget class="QWidget" name="page_2"/>
<widget class="QWidget" name="page_3"/>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>926</width>
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Microsoft YaHei UI</family>
</font>
</property>
<property name="defaultUp">
<bool>false</bool>
</property>
<property name="nativeMenuBar">
<bool>false</bool>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>文件</string>
</property>
<addaction name="actionImport"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>视图</string>
</property>
<addaction name="actionMain"/>
<addaction name="actionConfig"/>
<addaction name="actionVideo"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionImport"/>
</widget>
<action name="actionQuit">
<property name="text">
<string>退出</string>
</property>
<property name="toolTip">
<string>退出</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="actionImport">
<property name="icon">
<iconset resource="GeneralTesting.qrc">
<normaloff>:/GeneralTesting/UI/Open.png</normaloff>:/GeneralTesting/UI/Open.png</iconset>
</property>
<property name="text">
<string>导入</string>
</property>
<property name="toolTip">
<string>导入</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionMain">
<property name="text">
<string>主界面</string>
</property>
<property name="toolTip">
<string>主界面</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="actionConfig">
<property name="text">
<string>参数配置</string>
</property>
<property name="toolTip">
<string>参数配置</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
<action name="actionVideo">
<property name="text">
<string>视频显示</string>
</property>
<property name="shortcut">
<string>Ctrl+H</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="GeneralTesting.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,6 @@
#define VideoBufferLength 500 * 1024
#define DataBufferLength 500 * 1024
#define VarHeadLength 4
#define VideoPacketLength 4096
#define DataAchiveBuffer 1024 * 1024

View File

@ -0,0 +1,107 @@
#include "NetDataRecv.h"
#include <QNetworkDatagram>
NetDataRecv::NetDataRecv(QObject* parent)
: QThread(parent)
, m_bNeedWork(false)
, m_pProcess(nullptr)
, m_pFrame(nullptr)
, m_socketId(nullptr)
{
m_network.ip = "";
m_network.port = 0;
m_network.type = 0;
}
NetDataRecv::~NetDataRecv()
{
m_file.write(m_fileArray);
m_file.flush();
m_file.close();
}
void NetDataRecv::init(Frame* frame, Network network, IProcess* process)
{
m_pFrame = frame;
m_network = network;
m_pProcess = process;
createDataPath("Network");
initNetwork();
}
void NetDataRecv::createDataPath(QString title)
{
QString strFilePath = m_pFrame->m_dataStore.m_strDataPath + "/" + title + "_"
+ m_pFrame->m_dataStore.m_strStoreType + "_"
+ m_pFrame->m_dataStore.m_strDateTime + ".bin";
m_file.setFileName(strFilePath);
m_file.open(QIODevice::WriteOnly);
}
void NetDataRecv::initNetwork()
{
// 创建用于监听的套接字
m_socketId = new QUdpSocket(this);
m_socketId->bind(QHostAddress::AnyIPv4, m_network.port,
QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
// 设置套接字缓冲区: 1M
m_socketId->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, NET_BUFFER);
// 组播
if (m_network.type == 2) {
m_socketId->joinMulticastGroup(QHostAddress(m_network.ip));
m_socketId->setSocketOption(QAbstractSocket::MulticastLoopbackOption, true);
}
}
void NetDataRecv::send()
{
QByteArray sendArray;
m_socketId->writeDatagram(sendArray, QHostAddress(m_network.ip), m_network.port);
}
void NetDataRecv::run()
{
m_bNeedWork = true;
while (m_bNeedWork) {
// 接收数据
QNetworkDatagram datagram = m_socketId->receiveDatagram(NET_BUFFER);
if (!datagram.isValid()) {
QThread::usleep(1);
continue;
}
auto recvdata = datagram.data();
// 将数据放到缓冲区
if (m_pProcess) {
QMutexLocker locker(&m_mutex);
m_pProcess->getConstBuffer()->write((unsigned char*)recvdata.data(),
(unsigned short)recvdata.size());
m_fileArray.append((char*)recvdata.data(), recvdata.size());
if (DataAchiveBuffer <= m_fileArray.size()) {
m_file.write(m_fileArray);
m_file.flush();
m_fileArray.clear();
}
}
}
}
void NetDataRecv::stop()
{
m_bNeedWork = false;
quit();
wait();
if (m_network.type == 2) {
m_socketId->leaveMulticastGroup(QHostAddress(m_network.ip));
}
delete m_socketId;
m_socketId = nullptr;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include <QMutex>
#include <QThread>
#include <QUdpSocket>
#include "ConfigInfo.h"
#include "ValidProcess.h"
#define NET_BUFFER 65535
struct Network {
QString ip; ///< IP Address
unsigned short port; ///< Port number
int type; ///< UDP socket type, 1: singlecast, 2: multicast, 3: broadcast
};
class NetDataRecv : public QThread
{
Q_OBJECT
public:
NetDataRecv(QObject* parent = nullptr);
~NetDataRecv();
void init(Frame* frame, Network network, IProcess* process);
void initNetwork();
void send();
void stop();
private:
Frame* m_pFrame;
Network m_network;
IProcess* m_pProcess;
QUdpSocket* m_socketId;
ip_mreq m_mreq;
bool m_bNeedWork;
QMutex m_mutex;
QFile m_file;
QByteArray m_fileArray;
private:
void run() override;
void createDataPath(QString title);
};

View File

@ -0,0 +1,229 @@
#include "ParamParse.h"
#include <utility> /**< std::pair */
#include "MyButton.h"
ParamParse::ParamParse(QWidget* parent)
: QWidget(parent)
, m_pScrollLayout(nullptr)
, m_pStandardItemModel(nullptr)
, m_pSingleton(nullptr)
, m_strExePath("")
{
ui.setupUi(this);
m_pSingleton = Singleton::CreateInstance();
initParamList(); // 初始化参数列表
initScrollArea(); // 初始化滚动区域
}
ParamParse::~ParamParse()
{
delete m_pScrollLayout;
m_pScrollLayout = nullptr;
delete m_pStandardItemModel;
m_pStandardItemModel = nullptr;
ClearCurveWidgets();
}
// 初始化参数列表
void ParamParse::initParamList()
{
if (m_pStandardItemModel) {
m_pStandardItemModel->clear();
delete m_pStandardItemModel;
m_pStandardItemModel = nullptr;
}
m_pStandardItemModel = new QStandardItemModel();
m_pStandardItemModel->setColumnCount(6);
m_pStandardItemModel->setHorizontalHeaderLabels(
{"参数名称", "参数代号", "参数单位", "曲线颜色", "执行操作", "编号索引"});
ui.tv_paramList->setModel(m_pStandardItemModel);
ui.tv_paramList->setColumnWidth(0, 120); // 第一列
ui.tv_paramList->setColumnWidth(1, 80); // 第二列
ui.tv_paramList->setColumnWidth(2, 80); // 第三列
ui.tv_paramList->setColumnWidth(3, 80); // 第四列
ui.tv_paramList->setColumnWidth(4, 80); // 第五列
ui.tv_paramList->setColumnWidth(5, 40); // 第六列
ui.tv_paramList->header()->setDefaultAlignment(Qt::AlignCenter); // 设置表头居中
ui.tv_paramList->setColumnHidden(5, true); // 编号索引列隐藏
// 树状结构样式表
ui.tv_paramList->setStyleSheet("QTreeView::item{min-height:30px;align:center;}");
}
void ParamParse::initScrollArea()
{
m_pScrollLayout = new QGridLayout(ui.sa_wgtContent);
}
void ParamParse::ClearCurveWidgets()
{
for (auto curveWidget : m_mapIntCurveWidget) {
if (curveWidget.second) {
curveWidget.second->close();
delete curveWidget.second;
curveWidget.second = nullptr;
}
}
m_mapIntCurveWidget.clear();
}
void ParamParse::switchModelType(QString modeltype)
{
ClearCurveWidgets();
QMutexLocker locker(&m_mutex);
m_mapStrConfigInfo = m_pSingleton->getConfigInfo();
initParamList();
int count = 1;
auto configIter = m_mapStrConfigInfo.find(modeltype);
if (configIter != m_mapStrConfigInfo.end()) {
// 添加节点信息
QStandardItem* m_frameItem = new QStandardItem(configIter->first);
m_pStandardItemModel->appendRow(m_frameItem);
m_frameItem->setCheckable(false);
for (auto param : configIter->second->m_mapUIntParam) {
// 数字量和图像不显示
if (param.second->m_usModel == 2 || param.second->m_usModel == 3) {
continue;
}
// 参数名称
QString strTitle = param.second->m_strTitle;
QStandardItem* m_pTitleItem = new QStandardItem(strTitle);
m_frameItem->appendRow(m_pTitleItem);
// 参数代号
QString strCode = param.second->m_strCode;
QStandardItem* m_pCodeItem = new QStandardItem(strCode);
m_frameItem->setChild(m_pTitleItem->index().row(), 1, m_pCodeItem);
// 参数单位
QString strUnit = param.second->m_strUnit;
QStandardItem* m_pUnitItem = new QStandardItem(strUnit);
m_frameItem->setChild(m_pTitleItem->index().row(), 2, m_pUnitItem);
// 曲线颜色
QStandardItem* m_pColorItem = new QStandardItem("————");
QColor color =
QColor(qSin(count - 1) * 100 + 100, qSin((count - 1) * 2 + 0.6) * 100 + 100,
qSin((count - 1) * 1.3 + 0.6) * 100 + 100);
m_pColorItem->setForeground(color);
m_pColorItem->setTextAlignment(Qt::AlignCenter);
m_frameItem->setChild(m_pTitleItem->index().row(), 3, m_pColorItem);
// 执行操作
QStandardItem* m_pOperaItem = new QStandardItem("");
m_frameItem->setChild(m_pTitleItem->index().row(), 4, m_pOperaItem);
MyButton* m_pOperaBtn = new MyButton(m_pOperaItem, this); // 显示操作
m_pOperaBtn->setFixedSize(50, 20);
switch (param.second->m_usModel) {
case 1: // 工程量
m_pOperaBtn->setText("曲线");
break;
// case 2: //数字量
// m_pOperaBtn->setText("另存");
// break;
case 4: // 状态量
m_pOperaBtn->setText("阶梯");
break;
default:
break;
}
m_pOperaBtn->setStyleSheet(
"font-size:14px;\n"
"border:solid 1px;\n"
"background:white;\n"
"font-family:PingFangSC-Regular,PingFang SC;\n"
"font-weight:400;\n"
"color:#155bd4;\n"
"line-height:20px;");
connect(m_pOperaBtn, &MyButton::onSingleClick, this, &ParamParse::operateItem);
QHBoxLayout* m_pHBoxLayout = new QHBoxLayout();
m_pHBoxLayout->setMargin(5);
m_pHBoxLayout->addWidget(m_pOperaBtn);
QWidget* m_pOperaWidget = new QWidget();
m_pOperaWidget->setFixedSize(60, 30);
m_pOperaWidget->setLayout(m_pHBoxLayout);
ui.tv_paramList->setIndexWidget(m_pOperaItem->index(), m_pOperaWidget);
// 创建曲线窗口
{
// 工程量或状态量
if ("曲线" == m_pOperaBtn->text() || "阶梯" == m_pOperaBtn->text()) {
CurveInfo* pCurveInfo = new CurveInfo();
pCurveInfo->m_strTitle = strTitle;
pCurveInfo->m_curveColor = color;
pCurveInfo->m_curveCount = count;
CurveWidget* curveWidget = new CurveWidget(ui.sa_wgtContent);
connect(curveWidget, &CurveWidget::hideCurveWidget, this,
&ParamParse::hideCurveWidget);
connect(this, &ParamParse::setParseStatus, curveWidget,
&CurveWidget::setParseStatus);
if ("曲线" == m_pOperaBtn->text()) {
pCurveInfo->m_usCurveModel = 1;
} else if ("阶梯" == m_pOperaBtn->text()) {
pCurveInfo->m_usCurveModel = 4;
}
curveWidget->setParam(pCurveInfo);
curveWidget->setVisible(false);
m_mapIntCurveWidget.insert(std::pair<int, CurveWidget*>(count, curveWidget));
qDebug() << "map size: " << m_mapIntCurveWidget.size();
param.second->setCurveWidget(curveWidget);
}
// else if ("另存" == m_pOperaBtn->text()) { //数字量
//}
}
// 编号索引
QStandardItem* m_pIndexItem = new QStandardItem(QString::number(count));
m_frameItem->setChild(m_pTitleItem->index().row(), 5, m_pIndexItem);
m_pIndexItem->setTextAlignment(Qt::AlignCenter);
++count;
}
} else {
qDebug() << "The model type(" << modeltype << ") is unsupported!";
}
}
void ParamParse::operateItem(QStandardItem* item, QPushButton* button)
{
QModelIndex index = item->index();
// 参数名称
QString strTitle = index.sibling(index.row(), 0).data().toString();
// 曲线颜色
QStandardItem* colorItem = m_pStandardItemModel->itemFromIndex(index.sibling(index.row(), 3));
QColor color = colorItem->foreground().color();
// 编号索引
int count = index.sibling(index.row(), 5).data().toInt();
if ("曲线" == button->text() || "阶梯" == button->text()) { // 工程量或状态量
for (auto iter : m_mapIntCurveWidget) {
m_pScrollLayout->removeWidget(iter.second);
}
// Relayout
size_t i = 0;
for (auto iter : m_mapIntCurveWidget) {
if (count == iter.first) {
iter.second->setVisible(!iter.second->isVisible());
}
if (iter.second->isVisible()) {
m_pScrollLayout->addWidget(iter.second, i / 2, i % 2);
i++;
}
}
}
}
void ParamParse::hideCurveWidget(int count)
{
// 移除所关闭的曲线窗口
m_mapIntCurveWidget.at(count)->hide();
}
void ParamParse::parseStatus(unsigned int status)
{
m_uiParseStatus = status;
emit setParseStatus(m_uiParseStatus);
}

View File

@ -0,0 +1,50 @@
#pragma once
#include <QGridLayout>
#include <QMutex>
#include <QPushButton>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QString>
#include <QWidget>
#include "ui_ParamParse.h"
#include "ConfigInfo.h"
#include "CurveWidget.h"
#include "Singleton.h"
#include <map>
class ParamParse : public QWidget
{
Q_OBJECT
public:
ParamParse(QWidget* parent = nullptr);
~ParamParse();
private:
Ui::ParamParseClass ui;
QStandardItemModel* m_pStandardItemModel;
QGridLayout* m_pScrollLayout; // 滚动区域布局
QStringList m_configFilesList; // 配置文件
Singleton* m_pSingleton;
QString m_strExePath;
std::map<QString, ConfigInfo*> m_mapStrConfigInfo;
std::map<int, CurveWidget*> m_mapIntCurveWidget;
QMutex m_mutex;
unsigned int m_uiParseStatus; // 0无任务解析1离线解析2在线解析
private:
void initParamList();
void initScrollArea();
void ClearCurveWidgets();
private slots:
void operateItem(QStandardItem* item, QPushButton* widget);
void hideCurveWidget(int count);
public slots:
void switchModelType(QString modeltype);
void parseStatus(unsigned int status);
signals:
void setParseStatus(unsigned int status);
};

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParamParseClass</class>
<widget class="QWidget" name="ParamParseClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>808</width>
<height>625</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>ParamParse</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="tv_paramList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">QTreeView#tv_paramList{
border:1px solid #D5D5D5;
}</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
</widget>
<widget class="QScrollArea" name="sa_paramShow">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<widget class="QWidget" name="sa_wgtContent">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>69</width>
<height>605</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>tv_paramList</tabstop>
<tabstop>sa_paramShow</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,459 @@
#include "AnalogAfterProc.h"
AnalogAfterProc::AnalogAfterProc(QObject* parent) : IAfterProc(parent)
{}
AnalogAfterProc::~AnalogAfterProc()
{
m_file.flush();
m_file.close();
}
void AnalogAfterProc::run()
{
double dStartTime = 0.0;
double dCodeTime = 0.0;
m_uiDataSize = m_byteArray.size();
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
m_tempArray = m_byteArray.mid(m_uiIndex, m_pFrame->m_uiFrameLen);
unsigned char* pData = (unsigned char*)m_tempArray.data();
unsigned int uiCodePos = 0;
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
uiCodePos = 2;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
uiCodePos = 0;
}
if (m_pParam->getCurveWidget()->m_bRefTime == false) { // 未设置基准时间
dStartTime = GetBCDTimeCode(pData + uiCodePos); // 初始时码值
QString strTime = "时间(ms)-基准时间:" + GetBCDTimeCodeHMS(pData + uiCodePos);
QCustomPlot* pCustomPlot = m_pParam->getCurveWidget()->getCustomplot();
pCustomPlot->xAxis->setLabel(strTime);
m_pParam->getCurveWidget()->m_bRefTime = true;
}
dCodeTime = GetBCDTimeCode(pData + uiCodePos) - dStartTime; // 时码值
// 提取一个数据,添加一个时间
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
m_ableArray = m_validArray;
m_validArray.clear();
// 将数据写入文件中
m_file.write(m_ableArray);
m_file.flush();
// 处理有效工程量数据
validDataDeal(dCodeTime);
m_uiIndex += m_pFrame->m_uiFrameLen;
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_byteArray.clear();
emit parseFinished();
}
unsigned int AnalogAfterProc::getDataNum()
{
unsigned int uiChannelNum = m_pParam->m_pChannelGroup->m_uiChannelNum; // 所占通道数量
unsigned short usType = m_pParam->m_usType;
unsigned int uiDataNum = 0;
// 计算有效数据个数
switch (usType) {
case 1:
case 2:
uiDataNum = uiChannelNum;
break;
case 3:
case 4:
uiDataNum = uiChannelNum / 2;
break;
case 5:
case 6:
uiDataNum = uiChannelNum / 4;
break;
case 7:
case 8:
uiDataNum = uiChannelNum / 8;
break;
default:
break;
}
return uiDataNum;
}
// 处理有效数据
void AnalogAfterProc::validDataDeal(qreal time)
{
// 获取时码
double dFrameTime = m_pFrame->m_dFrameTime; // 帧间隔
unsigned int uiDataNum = getDataNum(); // 有效数据个数
double dTimeInterval = dFrameTime / (uiDataNum * 1.0);
unsigned short usModel = m_pParam->m_usModel; // 参数类型
unsigned short usOrder = m_pParam->m_usOrder; // 大小端
unsigned int m_uiIndex = 0;
unsigned int m_uiNum = 0;
double dTime = 0.0;
unsigned int m_uiDataSize = m_ableArray.size();
unsigned char* pData = (unsigned char*)m_ableArray.data();
if (usModel == 1) { // 模拟量
switch (m_pParam->m_usType) {
case 1: { // char
while (m_uiIndex < m_uiDataSize) {
char cData = (char)m_ableArray.at(m_uiIndex);
dTime = time + dTimeInterval * m_uiNum;
// 对char进行处理
setCurveData(dTime, cData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 2: { // unsigned char
while (m_uiIndex < m_uiDataSize) {
unsigned char ucData = (unsigned char)m_ableArray.at(m_uiIndex);
dTime = time + dTimeInterval * m_uiNum;
// 对unsigned char进行处理
setCurveData(dTime, ucData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 3: { // short
while (m_uiIndex + 2 <= m_uiDataSize) {
short sData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, sData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 4: { // unsigned short
while (m_uiIndex + 2 <= m_uiDataSize) {
unsigned short usData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, usData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 5: { // int
while (m_uiIndex + 4 <= m_uiDataSize) {
int iData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
iData = *(reinterpret_cast<const int*>(cTemp));
} else if (usOrder == 2) { // 小端
iData = *(reinterpret_cast<const int*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, iData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 6: { // unsigned int
while (m_uiIndex + 4 <= m_uiDataSize) {
unsigned int uiData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
uiData = *(reinterpret_cast<const unsigned int*>(cTemp));
} else if (usOrder == 2) { // 小端
uiData = *(reinterpret_cast<const unsigned int*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, uiData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 7: { // long long
while (m_uiIndex + 8 <= m_uiDataSize) {
long long llData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
llData = *(reinterpret_cast<const long long*>(cTemp));
} else if (usOrder == 2) { // 小端
llData = *(reinterpret_cast<const long long*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, llData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
case 8: { // unsigned long long
while (m_uiIndex + 8 <= m_uiDataSize) {
unsigned long long ullData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
ullData = *(reinterpret_cast<const unsigned long long*>(cTemp));
} else if (usOrder == 2) { // 小端
ullData = *(reinterpret_cast<const unsigned long long*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ullData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
default:
break;
}
} else if (usModel == 4) { // 状态量
QString strBit = m_pParam->m_strBit; // 状态量比特位
unsigned int iBit = strBit.toInt(nullptr, 16);
switch (m_pParam->m_usType) {
case 1: { // char
while (m_uiIndex < m_uiDataSize) {
char cData = (char)m_ableArray.at(m_uiIndex);
// 对char进行处理
char cBit = *(char*)&iBit;
cData &= cBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, cData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 2: { // unsigned char
while (m_uiIndex < m_uiDataSize) {
unsigned char ucData = (unsigned char)m_ableArray.at(m_uiIndex);
// 对unsigned char进行处理
unsigned char cBit = *(unsigned char*)&iBit;
ucData &= cBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ucData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 3: { // short
while (m_uiIndex + 2 <= m_uiDataSize) {
short sData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
}
sData &= (short)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, sData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 4: { // unsigned short
while (m_uiIndex + 2 <= m_uiDataSize) {
unsigned short usData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
}
usData &= (unsigned short)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, usData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 5: { // int
while (m_uiIndex + 4 <= m_uiDataSize) {
int iData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
iData = *(reinterpret_cast<const int*>(cTemp));
} else if (usOrder == 2) { // 小端
iData = *(reinterpret_cast<const int*>(pData));
}
iData &= (int)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, iData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 6: { // unsigned int
while (m_uiIndex + 4 <= m_uiDataSize) {
unsigned int uiData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
uiData = *(reinterpret_cast<const unsigned int*>(cTemp));
} else if (usOrder == 2) { // 小端
uiData = *(reinterpret_cast<const unsigned int*>(pData));
}
uiData &= (unsigned int)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, uiData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 7: { // long long
while (m_uiIndex + 8 <= m_uiDataSize) {
long long llData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
llData = *(reinterpret_cast<const long long*>(cTemp));
} else if (usOrder == 2) { // 小端
llData = *(reinterpret_cast<const long long*>(pData));
}
llData &= (long long)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, llData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
case 8: { // unsigned long long
while (m_uiIndex + 8 <= m_uiDataSize) {
unsigned long long ullData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
ullData = *(reinterpret_cast<const unsigned long long*>(cTemp));
} else if (usOrder == 2) { // 小端
ullData = *(reinterpret_cast<const unsigned long long*>(pData));
}
ullData &= (unsigned long long)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ullData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
default:
break;
}
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_ableArray.clear();
}
void AnalogAfterProc::setCurveData(qreal time, qreal value)
{
qreal qValue = value;
if (m_pParam->m_formula.equaNum != 0) {
qValue = convertData(value); // 对原始数据进行处理
}
CurveInfo* curveInfo = m_pParam->getCurveWidget()->getCurveInfo();
// 对char进行处理
curveInfo->m_vecAxisX.push_back(time);
curveInfo->m_vecAxisY.push_back(qValue);
curveInfo->maxX = time;
curveInfo->minX = 0;
if (curveInfo->m_bIsInited == false) {
curveInfo->minY = 0.99 * qValue;
curveInfo->maxY = 1.01 * qValue;
curveInfo->m_bIsInited = true;
}
if (curveInfo->minY > qValue) {
curveInfo->minY = qValue;
}
if (curveInfo->maxY < qValue) {
curveInfo->maxY = qValue;
}
}
qreal AnalogAfterProc::convertData(qreal value)
{
qreal qValue = 0.0;
int iEqualNum = m_pParam->m_formula.equaNum; // 最高次方
double Equation[10];
for (int i = 0; i < 10; i++) {
Equation[i] = m_pParam->m_formula.Equation[i];
}
for (int j = iEqualNum; j >= 0; j--) {
for (int k = 0; k < j; k++) {
Equation[j] *= value;
}
qValue += Equation[j];
}
return qValue;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <QObject>
#include "IAfterProc.h"
class AnalogAfterProc : public IAfterProc
{
Q_OBJECT
public:
AnalogAfterProc(QObject* parent = Q_NULLPTR);
~AnalogAfterProc();
private:
void run() override;
unsigned int getDataNum();
void validDataDeal(qreal time);
void setCurveData(qreal time, qreal value);
qreal convertData(qreal value);
signals:
void parseFinished();
};

View File

@ -0,0 +1,484 @@
#include "AnalogProcess.h"
AnalogProcess::AnalogProcess(QObject* parent) : IProcess(parent)
{}
AnalogProcess::~AnalogProcess()
{
if (m_pConstBuffer) {
delete m_pConstBuffer;
m_pConstBuffer = nullptr;
}
m_file.write(m_fileArray);
m_file.flush();
m_file.close();
}
void AnalogProcess::run()
{
unsigned char* m_ReadBuffer = new unsigned char[m_pFrame->m_uiFrameLen];
unsigned short usReadLen = 0;
double dStartTime = 0.0;
m_bNeedWork = true;
while (m_bNeedWork) {
usReadLen = m_pConstBuffer->read(m_ReadBuffer, m_pFrame->m_uiFrameLen);
if (usReadLen <= 0) {
QThread::usleep(1);
continue;
}
m_tempArray = QByteArray((char*)m_ReadBuffer, m_pFrame->m_uiFrameLen);
unsigned char* pData = (unsigned char*)m_tempArray.data();
unsigned int uiCodePos = 0;
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
uiCodePos = 2;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
uiCodePos = 0;
}
if (m_pParam->getCurveWidget()->m_bRefTime == false) { // 未设置基准时间
dStartTime = GetBCDTimeCode(pData + uiCodePos); // 初始时码值
QString strTime = "时间(ms)-基准时间:" + GetBCDTimeCodeHMS(pData + uiCodePos);
QCustomPlot* pCustomPlot = m_pParam->getCurveWidget()->getCustomplot();
pCustomPlot->xAxis->setLabel(strTime);
m_pParam->getCurveWidget()->m_bRefTime = true;
}
double dCodeTime = GetBCDTimeCode(pData + uiCodePos) - dStartTime; // 时码值
// 提取一个数据,添加一个时间
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
m_ableArray = m_validArray;
m_validArray.clear();
// 将数据写入文件中
m_fileArray.append(m_ableArray);
if (DataAchiveBuffer <= m_fileArray.size()) {
m_file.write(m_fileArray);
m_file.flush();
m_fileArray.clear();
}
// 处理有效工程量数据
validDataDeal(dCodeTime);
}
}
unsigned int AnalogProcess::getDataNum()
{
unsigned int uiChannelNum = m_pParam->m_pChannelGroup->m_uiChannelNum; // 所占通道数量
unsigned short usType = m_pParam->m_usType;
unsigned int uiDataNum = 0;
// 计算有效数据个数
switch (usType) {
case 1:
case 2:
uiDataNum = uiChannelNum;
break;
case 3:
case 4:
uiDataNum = uiChannelNum / 2;
break;
case 5:
case 6:
uiDataNum = uiChannelNum / 4;
break;
case 7:
case 8:
uiDataNum = uiChannelNum / 8;
break;
default:
break;
}
return uiDataNum;
}
// 处理有效数据
void AnalogProcess::validDataDeal(qreal time)
{
// 获取时码
double dFrameTime = m_pFrame->m_dFrameTime; // 帧间隔
unsigned int uiDataNum = getDataNum(); // 有效数据个数
double dTimeInterval = dFrameTime / (uiDataNum * 1.0);
unsigned short usModel = m_pParam->m_usModel; // 参数类型
unsigned short usOrder = m_pParam->m_usOrder; // 大小端
unsigned int m_uiIndex = 0;
unsigned int m_uiNum = 0;
double dTime = 0.0;
unsigned int m_uiDataSize = m_ableArray.size();
unsigned char* pData = (unsigned char*)m_ableArray.data();
if (usModel == 1) { // 模拟量
switch (m_pParam->m_usType) {
case 1: { // char
while (m_uiIndex < m_uiDataSize) {
char cData = (char)m_ableArray.at(m_uiIndex);
dTime = time + dTimeInterval * m_uiNum;
// 对char进行处理
setCurveData(dTime, cData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 2: { // unsigned char
while (m_uiIndex < m_uiDataSize) {
unsigned char ucData = (unsigned char)m_ableArray.at(m_uiIndex);
dTime = time + dTimeInterval * m_uiNum;
// 对unsigned char进行处理
setCurveData(dTime, ucData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 3: { // short
while (m_uiIndex + 2 <= m_uiDataSize) {
short sData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, sData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 4: { // unsigned short
while (m_uiIndex + 2 <= m_uiDataSize) {
unsigned short usData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, usData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 5: { // int
while (m_uiIndex + 4 <= m_uiDataSize) {
int iData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
iData = *(reinterpret_cast<const int*>(cTemp));
} else if (usOrder == 2) { // 小端
iData = *(reinterpret_cast<const int*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, iData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 6: { // unsigned int
while (m_uiIndex + 4 <= m_uiDataSize) {
unsigned int uiData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
uiData = *(reinterpret_cast<const unsigned int*>(cTemp));
} else if (usOrder == 2) { // 小端
uiData = *(reinterpret_cast<const unsigned int*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, uiData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 7: { // long long
while (m_uiIndex + 8 <= m_uiDataSize) {
long long llData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
llData = *(reinterpret_cast<const long long*>(cTemp));
} else if (usOrder == 2) { // 小端
llData = *(reinterpret_cast<const long long*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, llData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
case 8: { // unsigned long long
while (m_uiIndex + 8 <= m_uiDataSize) {
unsigned long long ullData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
ullData = *(reinterpret_cast<const unsigned long long*>(cTemp));
} else if (usOrder == 2) { // 小端
ullData = *(reinterpret_cast<const unsigned long long*>(pData));
}
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ullData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
default:
break;
}
} else if (usModel == 4) { // 状态量
QString strBit = m_pParam->m_strBit; // 状态量比特位
unsigned int iBit = strBit.toInt(nullptr, 16);
switch (m_pParam->m_usType) {
case 1: { // char
while (m_uiIndex < m_uiDataSize) {
char cData = (char)m_ableArray.at(m_uiIndex);
// 对char进行处理
char cBit = *(char*)&iBit;
cData &= cBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, cData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 2: { // unsigned char
while (m_uiIndex < m_uiDataSize) {
unsigned char ucData = (unsigned char)m_ableArray.at(m_uiIndex);
// 对unsigned char进行处理
unsigned char cBit = *(unsigned char*)&iBit;
ucData &= cBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ucData);
++m_uiIndex;
++m_uiNum;
}
break;
}
case 3: { // short
while (m_uiIndex + 2 <= m_uiDataSize) {
short sData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
sData = *(reinterpret_cast<const short*>(pData + m_uiIndex));
}
sData &= (short)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, sData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 4: { // unsigned short
while (m_uiIndex + 2 <= m_uiDataSize) {
unsigned short usData = 0x0000;
if (usOrder == 1) { // 大端
char cTemp = pData[m_uiIndex];
pData[m_uiIndex] = pData[m_uiIndex + 1];
pData[m_uiIndex] = cTemp;
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
} else if (usOrder == 2) { // 小端
usData = *(reinterpret_cast<const unsigned short*>(pData + m_uiIndex));
}
usData &= (unsigned short)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, usData);
m_uiIndex += 2;
++m_uiNum;
}
break;
}
case 5: { // int
while (m_uiIndex + 4 <= m_uiDataSize) {
int iData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
iData = *(reinterpret_cast<const int*>(cTemp));
} else if (usOrder == 2) { // 小端
iData = *(reinterpret_cast<const int*>(pData));
}
iData &= (int)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, iData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 6: { // unsigned int
while (m_uiIndex + 4 <= m_uiDataSize) {
unsigned int uiData = 0x00000000;
if (usOrder == 1) { // 大端
char cTemp[4] = {0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 3];
cTemp[1] = pData[m_uiIndex + 2];
cTemp[2] = pData[m_uiIndex + 1];
cTemp[3] = pData[m_uiIndex];
uiData = *(reinterpret_cast<const unsigned int*>(cTemp));
} else if (usOrder == 2) { // 小端
uiData = *(reinterpret_cast<const unsigned int*>(pData));
}
uiData &= (unsigned int)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, uiData);
m_uiIndex += 4;
++m_uiNum;
}
break;
}
case 7: { // long long
while (m_uiIndex + 8 <= m_uiDataSize) {
long long llData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
llData = *(reinterpret_cast<const long long*>(cTemp));
} else if (usOrder == 2) { // 小端
llData = *(reinterpret_cast<const long long*>(pData));
}
llData &= (long long)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, llData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
case 8: { // unsigned long long
while (m_uiIndex + 8 <= m_uiDataSize) {
unsigned long long ullData = 0x0000000000000000;
if (usOrder == 1) { // 大端
char cTemp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
cTemp[0] = pData[m_uiIndex + 7];
cTemp[1] = pData[m_uiIndex + 6];
cTemp[2] = pData[m_uiIndex + 5];
cTemp[3] = pData[m_uiIndex + 4];
cTemp[4] = pData[m_uiIndex + 3];
cTemp[5] = pData[m_uiIndex + 2];
cTemp[6] = pData[m_uiIndex + 1];
cTemp[7] = pData[m_uiIndex];
ullData = *(reinterpret_cast<const unsigned long long*>(cTemp));
} else if (usOrder == 2) { // 小端
ullData = *(reinterpret_cast<const unsigned long long*>(pData));
}
ullData &= (unsigned long long)iBit;
dTime = time + dTimeInterval * m_uiNum;
setCurveData(dTime, ullData);
m_uiIndex += 8;
++m_uiNum;
}
break;
}
default:
break;
}
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_ableArray.clear();
}
void AnalogProcess::setCurveData(qreal time, qreal value)
{
m_mutex.lock();
qreal qValue = value;
if (m_pParam->m_formula.equaNum != 0) {
qValue = convertData(value); // 对原始数据进行处理
}
// QMutexLocker locker(&m_mutex);
CurveInfo* curveInfo = m_pParam->getCurveWidget()->getCurveInfo();
// 对char进行处理
curveInfo->m_vecAxisX.push_back(time);
curveInfo->m_vecAxisY.push_back(qValue);
/* if (curveInfo->m_vecAxisX.size() > 3000) {
curveInfo->m_vecAxisX.erase(curveInfo->m_vecAxisX.begin(), curveInfo->m_vecAxisX.end() -
2000);
}
if (curveInfo->m_vecAxisY.size() > 3000) {
curveInfo->m_vecAxisY.erase(curveInfo->m_vecAxisY.begin(), curveInfo->m_vecAxisY.end() -
2000);
}*/
curveInfo->maxX = time;
// if (curveInfo->m_bIsZeroX == false) { //false:固定间距显示
curveInfo->minX = curveInfo->maxX - 200;
//}
// else if(curveInfo->m_bIsZeroX==true){ //true:从零开始显示
// curveInfo->minX = 0;
//}
if (curveInfo->m_bIsInited == false) {
curveInfo->minY = 0.99 * qValue;
curveInfo->maxY = 1.01 * qValue;
curveInfo->m_bIsInited = true;
}
if (curveInfo->minY > qValue) {
curveInfo->minY = qValue;
}
if (curveInfo->maxY < qValue) {
curveInfo->maxY = qValue;
}
m_mutex.unlock();
}
qreal AnalogProcess::convertData(qreal value)
{
qreal qValue = 0.0;
int iEqualNum = m_pParam->m_formula.equaNum; // 最高次方
double Equation[10];
for (int i = 0; i < 10; i++) {
Equation[i] = m_pParam->m_formula.Equation[i];
}
for (int j = iEqualNum; j >= 0; j--) {
for (int k = 0; k < j; k++) {
Equation[j] *= value;
}
qValue += Equation[j];
}
return qValue;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <QMutex>
#include "IProcess.h"
class AnalogProcess : public IProcess
{
public:
AnalogProcess(QObject* parent = Q_NULLPTR);
~AnalogProcess();
QMutex m_mutex;
private:
void run() override;
unsigned int getDataNum();
void validDataDeal(qreal time);
void setCurveData(qreal time, qreal value);
qreal convertData(qreal value);
};

View File

@ -0,0 +1,59 @@
#include "DigitalAfterProc.h"
DigitalAfterProc::DigitalAfterProc(QObject* parent) : IAfterProc(parent)
{}
DigitalAfterProc::~DigitalAfterProc()
{
m_file.flush();
m_file.close();
}
void DigitalAfterProc::run()
{
m_uiDataSize = m_byteArray.size();
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
m_tempArray = m_byteArray.mid(m_uiIndex, m_pFrame->m_uiFrameLen);
// 提取一个数据,添加一个时间
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
m_uiIndex += m_pFrame->m_uiFrameLen;
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_byteArray.clear();
if (m_fillArray.size() != 0) {
rejectFillData();
} else {
m_ableArray = m_validArray;
m_validArray.clear();
}
// 将数据写入文件中
m_file.write(m_ableArray);
m_file.flush();
m_ableArray.clear();
}
// 剔除无效填充数据
void DigitalAfterProc::rejectFillData()
{
m_uiDataSize = m_validArray.size();
m_uiIndex = 0;
while (m_uiIndex + m_usFillSize <= m_uiDataSize) {
if (m_validArray.at(m_uiIndex) != m_fillArray.at(0)) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else if (m_validArray.at(m_uiIndex) == m_fillArray.at(0)) {
if (m_validArray.mid(m_uiIndex, m_usFillSize) != m_fillArray) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else {
m_uiIndex += m_usFillSize;
}
}
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_validArray.clear();
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "IAfterProc.h"
class DigitalAfterProc : public IAfterProc
{
public:
DigitalAfterProc(QObject* parent = Q_NULLPTR);
~DigitalAfterProc();
private:
void run() override;
void rejectFillData();
};

View File

@ -0,0 +1,73 @@
#include "DigitalProcess.h"
DigitalProcess::DigitalProcess(QObject* parent) : IProcess(parent)
{}
DigitalProcess::~DigitalProcess()
{
if (m_pConstBuffer) {
delete m_pConstBuffer;
m_pConstBuffer = nullptr;
}
m_file.write(m_fileArray);
m_file.flush();
m_file.close();
}
void DigitalProcess::run()
{
unsigned char* m_ReadBuffer = new unsigned char[m_pFrame->m_uiFrameLen];
unsigned short usReadLen;
m_bNeedWork = true;
while (m_bNeedWork) {
usReadLen = m_pConstBuffer->read(m_ReadBuffer, m_pFrame->m_uiFrameLen);
if (usReadLen <= 0) {
QThread::usleep(1);
continue;
}
// 提取通道数据
m_tempArray = QByteArray((char*)m_ReadBuffer, m_pFrame->m_uiFrameLen);
// 从数据通道中提取数据
// 提取一个数据,添加一个时间
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
// 剔除无效数据
if (m_usFillSize != 0) {
rejectFillData();
} else {
m_ableArray = m_validArray;
m_validArray.clear();
}
// 将数据写入文件中
m_fileArray.append(m_ableArray);
m_ableArray.clear();
if (DataAchiveBuffer <= m_fileArray.size()) {
m_file.write(m_fileArray);
m_file.flush();
m_fileArray.clear();
}
}
}
void DigitalProcess::rejectFillData()
{
m_uiDataSize = m_validArray.size();
m_uiIndex = 0;
while (m_uiIndex + m_usFillSize <= m_uiDataSize) {
if (m_validArray.at(m_uiIndex) != m_fillArray.at(0)) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else if (m_validArray.at(m_uiIndex) == m_fillArray.at(0)) {
if (m_validArray.mid(m_uiIndex, m_usFillSize) != m_fillArray) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else {
m_uiIndex += m_usFillSize;
}
}
}
m_validArray.remove(0, m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "IProcess.h"
class DigitalProcess : public IProcess
{
public:
DigitalProcess(QObject* parent = Q_NULLPTR);
~DigitalProcess();
private:
void run() override;
void rejectFillData();
};

View File

@ -0,0 +1,41 @@
#include "IAfterProc.h"
IAfterProc::IAfterProc(QObject* parent)
: QThread(parent)
, m_pSingleton(nullptr)
, m_uiIndex(0)
, m_uiDataSize(0)
, m_pChannelGroup(nullptr)
, m_pFrame(nullptr)
{
m_pSingleton = Singleton::CreateInstance();
}
IAfterProc::~IAfterProc()
{}
void IAfterProc::init(Frame* frame, std::pair<const unsigned int, Param*>& pUIntParam)
{
m_pFrame = frame;
m_pUIntParam = pUIntParam;
m_pParam = m_pUIntParam.second;
m_pChannelGroup = m_pUIntParam.second->m_pChannelGroup;
m_fillArray = m_pUIntParam.second->m_fillArray;
m_usFillSize = m_fillArray.size();
// 创建文件存储路径
createDataPath(m_pParam->m_strTitle);
}
void IAfterProc::setData(QByteArray byteArray)
{
m_byteArray = byteArray;
}
void IAfterProc::createDataPath(QString title)
{
QString strFilePath = m_pFrame->m_dataStore.m_strDataPath + "/" + title + "_"
+ m_pFrame->m_dataStore.m_strStoreType + "_"
+ m_pFrame->m_dataStore.m_strDateTime + ".bin";
m_file.setFileName(strFilePath);
m_file.open(QIODevice::WriteOnly);
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <utility> /**< std::pair */
#include <QFile>
#include <QThread>
#include "ConfigInfo.h"
#include "ConstBuffer.h"
#include "Singleton.h"
class IAfterProc : public QThread
{
Q_OBJECT
public:
explicit IAfterProc(QObject* parent = Q_NULLPTR);
~IAfterProc();
virtual void init(Frame* frame, std::pair<const unsigned int, Param*>& pUIntParam);
void setData(QByteArray byteArray);
protected:
Singleton* m_pSingleton;
ConfigInfo* m_pConfigInfo;
Frame* m_pFrame;
std::pair<unsigned int, Param*> m_pUIntParam;
ChannelGroup* m_pChannelGroup;
Param* m_pParam;
QByteArray m_fillArray;
unsigned short m_usFillSize;
unsigned int m_uiIndex;
unsigned int m_uiDataSize;
QByteArray m_byteArray; // 原始数据
QByteArray m_tempArray;
QByteArray m_validArray; // 有效数据
QByteArray m_ableArray; // 可用数据
QFile m_file;
protected:
void createDataPath(QString title);
signals:
void displayStatusInfo(bool isSucess, QString statusInfo);
};

View File

@ -0,0 +1,39 @@
#include "IProcess.h"
IProcess::IProcess(QObject* parent)
: QThread(parent)
, m_pSingleton(nullptr)
, m_bNeedWork(false)
, m_pConstBuffer(nullptr)
, m_uiIndex(0)
, m_uiDataSize(0)
, m_pChannelGroup(nullptr)
, m_pFrame(nullptr)
{
m_pSingleton = Singleton::CreateInstance();
}
IProcess::~IProcess()
{}
void IProcess::init(Frame* frame, std::pair<const unsigned int, Param*>& pUIntParam)
{
m_pFrame = frame;
m_pUIntParam = pUIntParam;
m_pParam = m_pUIntParam.second;
m_pChannelGroup = m_pUIntParam.second->m_pChannelGroup;
m_fillArray = m_pUIntParam.second->m_fillArray;
m_usFillSize = m_fillArray.size();
m_pConstBuffer = new ConstBuffer(DataBufferLength, false, false, m_pFrame->m_uiFrameLen);
// 创建文件存储路径
createDataPath(m_pParam->m_strTitle);
}
void IProcess::createDataPath(QString title)
{
QString strFilePath = m_pFrame->m_dataStore.m_strDataPath + "/" + title + "_"
+ m_pFrame->m_dataStore.m_strStoreType + "_"
+ m_pFrame->m_dataStore.m_strDateTime + ".bin";
m_file.setFileName(strFilePath);
m_file.open(QIODevice::WriteOnly);
}

View File

@ -0,0 +1,54 @@
#pragma once
#include <utility> /**< std::pair */
#include <QFile>
#include <QThread>
#include "ConfigInfo.h"
#include "ConstBuffer.h"
#include "Singleton.h"
class IProcess : public QThread
{
Q_OBJECT
public:
explicit IProcess(QObject* parent = Q_NULLPTR);
~IProcess();
inline IBuffer* getConstBuffer()
{
return m_pConstBuffer;
}
inline void stop()
{
m_bNeedWork = false;
}
virtual void init(Frame* frame, std::pair<const unsigned int, Param*>& pUIntParam);
inline unsigned short getProcessModel()
{
return m_pParam->m_usModel;
}
protected:
Singleton* m_pSingleton;
bool m_bNeedWork;
ConstBuffer* m_pConstBuffer;
ConfigInfo* m_pConfigInfo;
Frame* m_pFrame;
std::pair<unsigned int, Param*> m_pUIntParam;
ChannelGroup* m_pChannelGroup;
Param* m_pParam;
QByteArray m_fillArray;
unsigned short m_usFillSize;
unsigned int m_uiIndex;
unsigned int m_uiDataSize;
QByteArray m_byteArray; // 原始数据
QByteArray m_tempArray;
QByteArray m_validArray; // 有效数据
QByteArray m_ableArray; // 可用数据
QFile m_file;
QByteArray m_fileArray;
protected:
void createDataPath(QString title);
};

View File

@ -0,0 +1,124 @@
#include "ValidAfterProc.h"
ValidAfterProc::ValidAfterProc(QObject* parent) : IAfterProc(parent)
{}
ValidAfterProc::~ValidAfterProc()
{
m_file.flush();
m_file.close();
}
void ValidAfterProc::init(Frame* frame)
{
m_pFrame = frame;
createDataPath("Valid");
}
void ValidAfterProc::run()
{
m_uiDataSize = m_byteArray.size();
m_uiIndex = 0;
// 副帧类型
if (m_pFrame->m_usSubFrameType == 1) { // 无副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]) {
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
m_validArray.append(m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen));
m_uiIndex += m_pFrame->m_uiFrameLen;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
m_validArray.append(m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen));
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
} else {
++m_uiIndex;
}
}
} else if (m_pFrame->m_usSubFrameType == 2) { // 反码副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]
&& m_pFrame->m_subHeadArray[0]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn]
&& m_pFrame->m_subHeadArray[1]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn
+ 1]) {
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
m_validArray.append(m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen));
m_uiIndex += m_pFrame->m_uiFrameLen;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
m_validArray.append(m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen));
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
} else {
++m_uiIndex;
}
}
} else if (m_pFrame->m_usSubFrameType == 3) { // ID副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]
&& m_pFrame->m_headArray[0]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn]
&& m_pFrame->m_headArray[1]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn
+ 1]) {
QByteArray startId = QByteArray::number(m_pFrame->m_usIdStart, 16); // 第一个Id号
QByteArray endId = QByteArray::number(m_pFrame->m_usIdEnd, 16); // 最后一个Id号
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
if (startId[0] == m_byteArray[m_uiIndex + m_pFrame->m_usIdAddr]
&& endId[0]
== m_byteArray[m_uiIndex + m_pFrame->m_usIdAddr
+ m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn]) {
m_validArray.append(m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen));
m_uiIndex += m_pFrame->m_uiFrameLen;
}
} else if (m_pFrame->m_usHeadAddr == 2) {
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
if (startId[0]
== m_byteArray[m_uiIndex - m_pFrame->m_usBeforeHeadLen
+ m_pFrame->m_usIdAddr]
&& endId[0]
== m_byteArray[m_uiIndex - m_pFrame->m_usBeforeHeadLen
+ m_pFrame->m_usIdAddr + m_pFrame->m_uiFrameLen
- m_pFrame->m_uiColumn]) {
m_validArray.append(m_byteArray.mid(
m_uiIndex - m_pFrame->m_usBeforeHeadLen, m_pFrame->m_uiFrameLen));
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
}
} else {
++m_uiIndex;
}
}
}
// 将数据写入文件中
m_file.write(m_validArray);
m_file.flush();
emit validDataExtract(m_validArray);
m_uiDataSize = 0;
m_uiIndex = 0;
m_byteArray.clear();
m_validArray.clear();
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <QByteArray>
#include "IAfterProc.h"
class ValidAfterProc : public IAfterProc
{
Q_OBJECT
public:
ValidAfterProc(QObject* parent = Q_NULLPTR);
~ValidAfterProc();
void init(Frame* frame);
private:
void run() override;
signals:
void validDataExtract(QByteArray byteArray);
};

View File

@ -0,0 +1,178 @@
#include "ValidProcess.h"
ValidProcess::ValidProcess(QObject* parent) : IProcess(parent)
{}
ValidProcess::~ValidProcess()
{
if (m_pConstBuffer) {
delete m_pConstBuffer;
m_pConstBuffer = nullptr;
}
m_file.write(m_fileArray);
m_file.flush();
m_file.close();
}
void ValidProcess::init(Frame* frame, map<unsigned int, IProcess*>& mapUIntProcess)
{
m_pFrame = frame;
m_mapUIntProcess = mapUIntProcess;
m_pConstBuffer = new ConstBuffer(DataBufferLength, false, false, m_pFrame->m_uiFrameLen);
createDataPath("Valid");
}
void ValidProcess::run()
{
unsigned char* m_ReadBuffer = new unsigned char[m_pFrame->m_uiFrameLen];
unsigned short usReadLen;
m_uiDataSize = 0;
m_uiIndex = 0;
m_bNeedWork = true;
while (m_bNeedWork) {
usReadLen = m_pConstBuffer->read(m_ReadBuffer, m_pFrame->m_uiFrameLen);
if (usReadLen <= 0) {
QThread::usleep(1);
continue;
}
m_byteArray.append((char*)m_ReadBuffer, (int)m_pFrame->m_uiFrameLen);
m_uiDataSize = m_byteArray.size();
m_uiIndex = 0;
// 副帧类型
if (m_pFrame->m_usSubFrameType == 1) { // 无副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]) {
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
m_validArray = m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex += m_pFrame->m_uiFrameLen;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
m_validArray = m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
} else {
++m_uiIndex;
}
}
m_byteArray.remove(0, m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
} else if (m_pFrame->m_usSubFrameType == 2) { // 反码副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]
&& m_pFrame->m_subHeadArray[0]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn]
&& m_pFrame->m_subHeadArray[1]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn
+ 1]) {
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
m_validArray = m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex += m_pFrame->m_uiFrameLen;
} else if (m_pFrame->m_usHeadAddr == 2) { // 帧头在每行最后
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
m_validArray = m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
} else {
++m_uiIndex;
}
}
m_byteArray.remove(0, m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
} else if (m_pFrame->m_usSubFrameType == 3) { // ID副帧
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
if (m_pFrame->m_headArray[0] == m_byteArray[m_uiIndex]
&& m_pFrame->m_headArray[1] == m_byteArray[m_uiIndex + 1]
&& m_pFrame->m_headArray[0]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn]
&& m_pFrame->m_headArray[1]
== m_byteArray[m_uiIndex + m_pFrame->m_uiFrameLen - m_pFrame->m_uiColumn
+ 1]) {
QByteArray startId = QByteArray::number(m_pFrame->m_usIdStart, 16); // 第一个Id号
QByteArray endId = QByteArray::number(m_pFrame->m_usIdEnd, 16); // 最后一个Id号
if (m_pFrame->m_usHeadAddr == 1) { // 帧头在每行最前
if (startId[0] == m_byteArray[m_uiIndex + m_pFrame->m_usIdAddr]
&& endId[0]
== m_byteArray[m_uiIndex + m_pFrame->m_usIdAddr
+ m_pFrame->m_uiFrameLen
- m_pFrame->m_uiColumn]) {
m_validArray = m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex += m_pFrame->m_uiFrameLen;
}
} else if (m_pFrame->m_usHeadAddr == 2) {
if (m_pFrame->m_usBeforeHeadLen <= m_uiIndex) { // 说明第一个子帧满足
if (startId[0]
== m_byteArray[m_uiIndex - m_pFrame->m_usBeforeHeadLen
+ m_pFrame->m_usIdAddr]
&& endId[0]
== m_byteArray[m_uiIndex - m_pFrame->m_usBeforeHeadLen
+ m_pFrame->m_usIdAddr
+ m_pFrame->m_uiFrameLen
- m_pFrame->m_uiColumn]) {
m_validArray =
m_byteArray.mid(m_uiIndex - m_pFrame->m_usBeforeHeadLen,
m_pFrame->m_uiFrameLen);
frameExtract();
m_uiIndex -= m_pFrame->m_usBeforeHeadLen;
m_uiIndex += m_pFrame->m_uiFrameLen;
} else {
++m_uiIndex;
}
}
}
} else {
++m_uiIndex;
}
}
m_byteArray.remove(0, m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
}
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_byteArray.clear();
m_validArray.clear();
}
void ValidProcess::frameExtract()
{
for (auto process : m_mapUIntProcess) {
if (process.second) {
if (process.second->getProcessModel() == 3) { // 图像
VideoProcess* pVideoProcess = (VideoProcess*)process.second;
if (pVideoProcess->getVideoPlayStatus() == false) {
continue;
}
}
process.second->getConstBuffer()->write((unsigned char*)m_validArray.data(),
(unsigned short)m_validArray.size());
}
}
m_fileArray.append(m_validArray);
m_validArray.clear();
if (DataAchiveBuffer <= m_fileArray.size()) {
m_file.write(m_fileArray);
m_file.flush();
m_fileArray.clear();
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <map>
#include "IProcess.h"
#include "VideoProcess.h"
class ValidProcess : public IProcess
{
public:
ValidProcess(QObject* parent = Q_NULLPTR);
~ValidProcess();
void init(Frame* frame, std::map<unsigned int, IProcess*>& mapUIntProcess);
private:
std::map<unsigned int, IProcess*> m_mapUIntProcess;
private:
void run() override;
void frameExtract();
};

View File

@ -0,0 +1,143 @@
#include "VideoAfterProc.h"
VideoAfterProc::VideoAfterProc(QObject* parent)
: IAfterProc(parent)
, m_pFfmpegDecodeNew(nullptr)
, m_bNeedWork(false)
, m_bIsPlay(false)
, m_ulSpeedTime(10)
{}
VideoAfterProc::~VideoAfterProc()
{
m_file.flush();
m_file.close();
}
void VideoAfterProc::getFfmpegDecode()
{
m_pFfmpegDecodeNew = m_pUIntParam.second->getVideoWidget()->getFfmpegDecode();
}
void VideoAfterProc::run()
{
m_uiDataSize = m_byteArray.size();
m_uiIndex = 0;
while (m_uiIndex + m_pFrame->m_uiFrameLen <= m_uiDataSize) {
m_tempArray = m_byteArray.mid(m_uiIndex, m_pFrame->m_uiFrameLen);
// 从数据通道中提取数据
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
m_uiIndex += m_pFrame->m_uiFrameLen;
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_byteArray.clear();
// 剔除无效填充数据
if (m_usFillSize != 0) {
rejectFillData();
} else {
m_ableArray = m_validArray;
m_validArray.clear();
}
emit dataProcFinished();
// 将数据写入文件中
m_file.write(m_ableArray);
m_file.flush();
m_file.close();
// 进行视频播放
resetVideoData();
QByteArray tempValid;
m_bNeedWork = true;
while (m_bNeedWork) {
if (m_bIsPlay == true) { // 视频播放
while (m_uiIndex + VideoPacketLength <= m_uiDataSize) {
if (m_bIsPlay == false) {
break;
}
tempValid = m_ableArray.mid(m_uiIndex, VideoPacketLength);
m_pFfmpegDecodeNew->getConstBuffer()->write((unsigned char*)tempValid.data(),
VideoPacketLength);
m_uiIndex += VideoPacketLength;
emit playedCount(m_uiDataSize, m_uiIndex);
QThread::msleep(m_ulSpeedTime);
}
if (m_bIsPlay == true) {
// 计算末尾剩余视频
unsigned int m_uiDeltaSize = m_uiDataSize - m_uiIndex;
tempValid = m_ableArray.mid(m_uiIndex, m_uiDeltaSize);
m_pFfmpegDecodeNew->getConstBuffer()->write((unsigned char*)tempValid.data(),
(unsigned short)m_uiDeltaSize);
emit playedCount(m_uiDataSize, m_uiDataSize);
// 重新赋值
resetVideoData();
startPlayer(false);
}
}
}
m_ableArray.clear();
}
// 剔除无效填充数据
void VideoAfterProc::rejectFillData()
{
m_uiDataSize = m_validArray.size();
m_uiIndex = 0;
while (m_uiIndex + m_usFillSize <= m_uiDataSize) {
if (m_validArray.at(m_uiIndex) != m_fillArray.at(0)) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else if (m_validArray.at(m_uiIndex) == m_fillArray.at(0)) {
if (m_validArray.mid(m_uiIndex, m_usFillSize) != m_fillArray) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else {
m_uiIndex += m_usFillSize;
}
}
}
m_uiDataSize = 0;
m_uiIndex = 0;
m_validArray.clear();
}
void VideoAfterProc::startPlayer(bool status)
{
m_bIsPlay = status;
if (status == true) {
m_pFfmpegDecodeNew->start();
} else if (status == false) {
m_pFfmpegDecodeNew->stop();
}
}
void VideoAfterProc::stop()
{
m_bNeedWork = false;
}
void VideoAfterProc::setPlayPos(int pos)
{
QMutexLocker locker(&m_mutex);
m_uiIndex = (unsigned int)((m_uiDataSize * 1.0) * (pos * 1.0 / 100.0));
}
void VideoAfterProc::resetVideoData()
{
m_uiDataSize = m_ableArray.size();
m_uiIndex = 0;
}
void VideoAfterProc::videoSpeed(QString speed)
{
if (speed == "x1") {
m_ulSpeedTime = 10;
} else if (speed == "x2") {
m_ulSpeedTime = 5;
} else if (speed == "x5") {
m_ulSpeedTime = 2;
} else if (speed == "x10") {
m_ulSpeedTime = 1;
}
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <QObject>
#include "FfmpegDecodeNew.h"
#include "IAfterProc.h"
class VideoAfterProc : public IAfterProc
{
Q_OBJECT
public:
VideoAfterProc(QObject* parent = Q_NULLPTR);
~VideoAfterProc();
void getFfmpegDecode();
void stop();
private:
FfmpegDecodeNew* m_pFfmpegDecodeNew;
bool m_bNeedWork;
bool m_bIsPlay;
QMutex m_mutex;
unsigned long m_ulSpeedTime;
private:
void run() override;
void rejectFillData();
void resetVideoData();
signals:
void dataProcFinished();
void playedCount(unsigned int num, unsigned int count);
public slots:
void startPlayer(bool status);
void videoSpeed(QString speed);
void setPlayPos(int pos);
};

View File

@ -0,0 +1,150 @@
#include "VideoProcess.h"
VideoProcess::VideoProcess(QObject* parent)
: IProcess(parent)
//, m_pFfmpegDecodeOld(nullptr)
, m_pFfmpegDecodeNew(nullptr)
, m_bIsPlay(false)
{
/*
m_pFfmpegDecodeOld = new FfmpegDecodeOld();
//将获取的数据传入到FFmpeg模块中
m_pFfmpegDecodeOld->start();
*/
}
VideoProcess::~VideoProcess()
{
if (m_pConstBuffer) {
delete m_pConstBuffer;
m_pConstBuffer = nullptr;
}
m_file.write(m_fileArray);
m_file.flush();
m_file.close();
}
void VideoProcess::getFfmpegDecode()
{
m_pConstBuffer = new ConstBuffer(VideoBufferLength, false, false, m_pFrame->m_uiFrameLen);
m_pFfmpegDecodeNew = m_pUIntParam.second->getVideoWidget()->getFfmpegDecode();
}
void VideoProcess::run()
{
/*Ffmpeg探测网络流格式勿删
unsigned char* m_pOriginBuffer = new unsigned char[m_pFrame->m_uiValidFrameLen];
unsigned short usRecvSize = 0;
m_bNeedWork = true;
while (m_bNeedWork) {
usRecvSize =m_pConstBuffer->read(m_pOriginBuffer, m_pFrame->m_uiValidFrameLen);
if (usRecvSize <= 0) {
continue;
}
//剔除视频中的无效数据
//向FFmpeg中写入数据每次写入VideoPacketLength个字节
QByteArray videoArray;
m_pFfmpegDecodeOld->getConstBuffer()->write((unsigned
char*)videoArray.data(),VideoPacketLength);
}*/
unsigned char* m_ReadBuffer = new unsigned char[m_pFrame->m_uiFrameLen];
unsigned short usReadLen;
m_bNeedWork = true;
while (m_bNeedWork) {
if (m_bIsPlay == false) {
continue;
}
usReadLen = m_pConstBuffer->read(m_ReadBuffer, m_pFrame->m_uiFrameLen);
if (usReadLen <= 0) {
QThread::usleep(1);
continue;
}
// 提取通道数据
m_tempArray = QByteArray((char*)m_ReadBuffer, m_pFrame->m_uiFrameLen);
// 从数据通道中提取数据
// 提取一个数据,添加一个时间
for (auto channel : m_pParam->m_pChannelGroup->m_vecChannel) {
m_validArray.append(m_tempArray.at(channel->m_uiAbsolutePos));
}
m_tempArray.clear();
// 剔除无效数据
if (m_usFillSize != 0) {
rejectFillData();
} else {
m_ableArray.append(m_validArray);
m_validArray.clear();
}
// 将数据写入文件中
m_fileArray.append(m_ableArray);
if (DataAchiveBuffer <= m_fileArray.size()) {
m_file.write(m_fileArray);
m_file.flush();
m_fileArray.clear();
}
// 将数据放到播放器中
validDataDeal();
}
}
void VideoProcess::rejectFillData()
{
m_uiDataSize = m_validArray.size();
m_uiIndex = 0;
while (m_uiIndex + m_usFillSize <= m_uiDataSize) {
if (m_validArray.at(m_uiIndex) != m_fillArray.at(0)) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else if (m_validArray.at(m_uiIndex) == m_fillArray.at(0)) {
if (m_validArray.mid(m_uiIndex, m_usFillSize) != m_fillArray) {
m_ableArray.append(m_validArray.at(m_uiIndex));
++m_uiIndex;
} else {
m_uiIndex += m_usFillSize;
}
}
}
m_validArray.remove(0, m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
}
void VideoProcess::validDataDeal()
{
/*
if (m_bIsPlay == true) {
//将数据放到播放器中
m_uiDataSize = m_ableArray.size();
m_uiIndex = 0;
QByteArray tempValid;
while (m_uiIndex + VideoPacketLength <= m_uiDataSize) {
tempValid = m_ableArray.mid(m_uiIndex, VideoPacketLength);
m_pFfmpegDecodeNew->getConstBuffer()->write((unsigned char*)tempValid.data(),
VideoPacketLength); m_uiIndex += VideoPacketLength;
}
m_ableArray.remove(0,m_uiIndex);
m_uiDataSize = 0;
m_uiIndex = 0;
}
else if(m_bIsPlay == false){
m_ableArray.clear();
m_uiDataSize = 0;
m_uiIndex = 0;
}*/
if (m_bIsPlay == true) {
// 将数据放到播放器中
m_pFfmpegDecodeNew->getConstBuffer()->write((unsigned char*)m_ableArray.data(),
(unsigned short)m_ableArray.size());
m_ableArray.clear();
} else if (m_bIsPlay == false) {
m_ableArray.clear();
}
}
void VideoProcess::startPlayer(bool status)
{
m_bIsPlay = status;
if (m_bIsPlay == true) {
m_pFfmpegDecodeNew->start();
} else if (m_bIsPlay == false) {
m_pFfmpegDecodeNew->stop();
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "ConstBuffer.h"
#include "IProcess.h"
// #include"FfmpegDecodeOld.h"
#include "FfmpegDecodeNew.h"
class VideoProcess : public IProcess
{
public:
VideoProcess(QObject* parent = Q_NULLPTR);
~VideoProcess();
void getFfmpegDecode();
bool getVideoPlayStatus()
{
return m_bIsPlay;
}
private:
// FfmpegDecodeOld* m_pFfmpegDecodeOld;
FfmpegDecodeNew* m_pFfmpegDecodeNew;
bool m_bIsPlay;
private:
void run() override;
void rejectFillData();
void validDataDeal();
public slots:
void startPlayer(bool status);
};

View File

@ -0,0 +1,21 @@
#include "DirOperation.h"
#include <QDir>
#include <QString>
bool DirOperation::CreateDir(std::string path)
{
if (path == "")
return false;
return QDir().mkpath(path.c_str());
}
std::string DirOperation::GetExePath()
{
return QDir::currentPath().toStdString();
}
std::string DirOperation::ConcatePath(std::string path1, std::string path2)
{
return QDir::cleanPath(QDir(path1.c_str()).filePath(path2.c_str())).toStdString();
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <string>
/**
* @brief boost库的文件 \n
*/
class DirOperation
{
public:
DirOperation(){};
~DirOperation(){};
/**
* @brief
* @param[in] dir
* @return
* -<em>false</em>
* -<em>true</em>
*/
static bool CreateDir(std::string dir);
/**
* @brief
* @return
*/
static std::string GetExePath();
/**
* @brief
* @param[in] path1 1
* @param[in] path2 2
* @return
*/
static std::string ConcatePath(std::string path1, std::string path2);
};

View File

@ -0,0 +1,104 @@
/*
* crc.h
*
* Created on: 2017710
* Author: Administrator
*/
#pragma once
#include <stdint.h>
static const uint16_t crc16_table[] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
static unsigned int crc32_tab[256];
class CRC
{
public:
static unsigned short CalCRC16(void* pData, unsigned int dwNumOfBytes)
{
unsigned short wCRC = 0x0000;
unsigned char* pbDataBuf = (unsigned char*)pData;
while (0 != (dwNumOfBytes--))
wCRC = crc16_byte(wCRC, *pbDataBuf++);
return wCRC;
}
static unsigned int CalCRC32(unsigned char* array, unsigned int nDatalen)
{
static bool s_bInitFlag = false;
unsigned int dGain = 0xFFFFFFFF;
int i = 0;
if (s_bInitFlag == false) {
s_bInitFlag = true;
for (i = 0; i < 256; i++) {
crc32_tab[i] = 0x00000000;
}
fun_Init_CRC32();
}
while (nDatalen--)
dGain = (dGain >> 8) ^ crc32_tab[(dGain & 0xFF) ^ ((*array++) & 0xFF)];
return dGain ^ 0xFFFFFFFF;
}
private:
static unsigned short crc16_byte(unsigned short crc, const unsigned char data)
{
return (crc << 8) ^ crc16_table[((crc >> 8) ^ data) & 0xff];
}
static unsigned int CRC::fun_Reflect(unsigned int ref, unsigned char ch)
{
unsigned int value = 0;
int i = 0;
for (i = 1; i < (ch + 1); i++) {
if (ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
static void CRC::fun_Init_CRC32(void)
{
unsigned int ulPolynomial = 0x04c11db7;
unsigned int i = 0, j = 0;
for (i = 0; i <= 0xFF; i++) /*256 Values representing ascii character ades*/
{
crc32_tab[i] = fun_Reflect(i, 8) << 24;
for (j = 0; j < 8; j++) {
crc32_tab[i] = (crc32_tab[i] << 1) ^ (crc32_tab[i] & (1 << 31) ? ulPolynomial : 0);
}
crc32_tab[i] = fun_Reflect(crc32_tab[i], 32);
}
return;
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
#include "Singleton.h"
Singleton* Singleton::m_pInstance = nullptr;
QMutex Singleton::m_mutex;
Singleton::Singleton() : m_strExePath(""), m_strModelType("")
{}
Singleton::~Singleton()
{}
Singleton* Singleton::CreateInstance()
{
if (m_pInstance == nullptr) {
QMutexLocker locker(&m_mutex);
if (m_pInstance == nullptr) {
m_pInstance = new Singleton();
}
}
return m_pInstance;
}
bool Singleton::setExePath(QString path)
{
if (path == "") {
return false;
}
m_strExePath = path;
return true;
}
QString Singleton::getExePath()
{
return m_strExePath;
}
void Singleton::setConfigInfo(std::map<QString, ConfigInfo*>& mapStrConfigInfo)
{
m_mapStrConfigInfo = mapStrConfigInfo;
}
std::map<QString, ConfigInfo*>& Singleton::getConfigInfo()
{
return m_mapStrConfigInfo;
}
void Singleton::setModelType(QString modeltype)
{
m_strModelType = modeltype;
}
QString Singleton::getModelType()
{
return m_strModelType;
}
void Singleton::setDataPath(QString path)
{
m_strDataPath = path;
}
QString Singleton::getDataPath()
{
return m_strDataPath;
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <map>
#include <QMutex>
#include <QString>
#include "ConfigInfo.h"
class Singleton
{
public:
~Singleton();
static Singleton* CreateInstance();
bool setExePath(QString path);
QString getExePath();
void setConfigInfo(std::map<QString, ConfigInfo*>& mapStrConfigInfo);
std::map<QString, ConfigInfo*>& getConfigInfo();
void setModelType(QString modeltype);
QString getModelType();
void setDataPath(QString path);
QString getDataPath();
private:
static Singleton* m_pInstance;
static QMutex m_mutex;
QString m_strExePath;
QString m_strDataPath; // 数据存储路径
std::map<QString, ConfigInfo*> m_mapStrConfigInfo;
QString m_strModelType;
private:
Singleton();
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1 @@
IDI_APP_ICON ICON DISCARDABLE "gtt.ico"

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Some files were not shown because too many files have changed in this diff Show More