Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
21df3a8ee3 | ||
|
d86a45680b | ||
d3ccaba32f | |||
7c2a29740b | |||
8f72fbded7 | |||
|
798962e8bb | ||
|
fd494f2a03 | ||
|
dbe7c1a64e | ||
|
559867bd31 | ||
|
7284f18c43 | ||
|
fb27b0fa57 | ||
|
77dd027ff7 | ||
|
8e0018480b | ||
|
16757c5f78 | ||
|
ef7aa73c8d | ||
95b68bc67d | |||
d0966cfcc7 | |||
d6a36c0450 | |||
27e5db45d6 | |||
|
51f9a2af52 | ||
|
0b3198c90e | ||
|
f55d3aa9df | ||
|
bf3ad2be2f | ||
|
f230e4cc8b | ||
baa991dba0 | |||
|
b46cd406a7 | ||
|
6810dbd801 |
33
.gitea/workflows/release_windows.yaml
Normal file
33
.gitea/workflows/release_windows.yaml
Normal file
@ -0,0 +1,33 @@
|
||||
name: Release tag
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [windows11]
|
||||
steps:
|
||||
- name: Clone repository
|
||||
run: |
|
||||
$ref = "${{ github.ref }}"
|
||||
if ($ref -like 'refs/heads/*') {
|
||||
$branch = $ref -replace '^refs/heads/', ''
|
||||
} elseif ($ref -like 'refs/tags/*') {
|
||||
$branch = $ref -replace '^refs/tags/', ''
|
||||
} else {
|
||||
$branch = $ref
|
||||
}
|
||||
git clone --depth 1 --branch=$branch https://${{ secrets.GIT_USERNAME }}:${{ secrets.GIT_PASSWORD }}@amass.fun/gitea/${{ gitea.repository }}.git .
|
||||
git checkout ${{ github.sha }}
|
||||
- name: Build and deploy
|
||||
run: |
|
||||
resources/build.ps1 build
|
||||
resources/build.ps1 deploy
|
||||
resources/build.ps1 changelog
|
||||
- name: Upload Gitea Release
|
||||
uses: akkuman/gitea-release-action@v1
|
||||
with:
|
||||
body_path: build/CHANGELOG.txt
|
||||
files: |-
|
||||
build/视觉防夹设备上位机工具*.zip
|
@ -12,5 +12,7 @@
|
||||
<file>resources/prompt_delete.svg</file>
|
||||
<file>resources/successfull.svg</file>
|
||||
<file>resources/warning.svg</file>
|
||||
<file>qml/MessageBar.qml</file>
|
||||
<file>qml/Object.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
166
Application.cpp
166
Application.cpp
@ -40,7 +40,7 @@ Application::Application(int &argc, char **argv)
|
||||
font.setFamily("微软雅黑");
|
||||
m_app->setFont(font);
|
||||
m_app->setApplicationName(APPLICATION_NAME);
|
||||
m_app->setApplicationVersion(QString("V%1").arg(APP_VERSION));
|
||||
m_app->setApplicationVersion(QString("v%1").arg(APP_VERSION));
|
||||
m_player->open();
|
||||
}
|
||||
|
||||
@ -127,7 +127,24 @@ void Application::setCurrentAntiClipAreaEnabled(bool enabled) {
|
||||
emit currentAntiClipAreaEnabledChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateAntiClipAreaPoints(m_currentAntiClipAreaEnabled, m_currentAntiClipAreaPoints);
|
||||
device->updateAntiClipAreaPoints(m_currentAntiClipAreaEnabled, m_currentAntiClipAreaPoints,
|
||||
m_currentAntiClipSensitivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::currentAntiClipSensitivity() const {
|
||||
return m_currentAntiClipSensitivity;
|
||||
}
|
||||
|
||||
void Application::setCurrentAntiClipSensitivity(int sensitivity) {
|
||||
if (m_currentAntiClipSensitivity != sensitivity) {
|
||||
m_currentAntiClipSensitivity = sensitivity;
|
||||
emit currentAntiClipSensitivityChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateAntiClipAreaPoints(m_currentAntiClipAreaEnabled, m_currentAntiClipAreaPoints,
|
||||
m_currentAntiClipSensitivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,7 +170,7 @@ void Application::updateOpenDoorAreaPoints(const QList<QPointF> &points) {
|
||||
void Application::updateAntiClipAreaPoints(const QList<QPointF> &points) {
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateAntiClipAreaPoints(m_currentAntiClipAreaEnabled, points);
|
||||
device->updateAntiClipAreaPoints(m_currentAntiClipAreaEnabled, points, m_currentAntiClipSensitivity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +181,80 @@ void Application::updateShieldedAreaPoints(const QList<QPointF> &points) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::currentDeviceFlip() const {
|
||||
return m_currentDeviceFlip;
|
||||
}
|
||||
void Application::setCurrentDeviceFlip(bool flip) {
|
||||
if (m_currentDeviceFlip != flip) {
|
||||
m_currentDeviceFlip = flip;
|
||||
emit currentDeviceFlipChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateFlip(flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::currentDeviceRotation() const {
|
||||
return m_currentDeviceRotation;
|
||||
}
|
||||
|
||||
void Application::setCurrentDeviceRotation(int rotation) {
|
||||
if (m_currentDeviceRotation != rotation) {
|
||||
m_currentDeviceRotation = rotation;
|
||||
emit currentDeviceRotationChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateRotation(rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::currentHelmetThreshold() const {
|
||||
return m_currentHelmetThreshold;
|
||||
}
|
||||
|
||||
void Application::setCurrentHelmetThreshold(int threshold) {
|
||||
if (m_currentHelmetThreshold != threshold) {
|
||||
m_currentHelmetThreshold = threshold;
|
||||
emit currentHelmetThresholdChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateDetectThreshold(m_currentHelmetThreshold, m_currentHeadThreshold, m_currentDetectFrameSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::currentHeadThreshold() const {
|
||||
return m_currentHeadThreshold;
|
||||
}
|
||||
|
||||
void Application::setCurrentHeadThreshold(int threshold) {
|
||||
if (m_currentHeadThreshold != threshold) {
|
||||
m_currentHeadThreshold = threshold;
|
||||
emit currentHeadThresholdChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateDetectThreshold(m_currentHelmetThreshold, m_currentHeadThreshold, m_currentDetectFrameSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::currentDetectFrameSize() const {
|
||||
return m_currentDetectFrameSize;
|
||||
}
|
||||
|
||||
void Application::setCurrentDetectFrameSize(int size) {
|
||||
if (m_currentDetectFrameSize != size) {
|
||||
m_currentDetectFrameSize = size;
|
||||
emit currentDetectFrameSizeChanged();
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
device->updateDetectThreshold(m_currentHelmetThreshold, m_currentHeadThreshold, m_currentDetectFrameSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask, const QString &gateway,
|
||||
const QString &dns) {
|
||||
if (!m_device.expired()) {
|
||||
@ -180,9 +271,13 @@ void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QS
|
||||
void Application::connectToDevice(int index) {
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
disconnect(device.get(), &DeviceConnection::rotationChanged, this, &Application::onDeviceRotationChanged);
|
||||
disconnect(device.get(), &DeviceConnection::flipChanged, this, &Application::onDeviceFlipChanged);
|
||||
disconnect(device.get(), &DeviceConnection::openDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
|
||||
disconnect(device.get(), &DeviceConnection::shieldedAreaChanged, this, &Application::onDeviceShieldedArea);
|
||||
disconnect(device.get(), &DeviceConnection::antiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
|
||||
disconnect(device.get(), &DeviceConnection::detectThresholdChanged, this,
|
||||
&Application::onDeviceDetectThresholdChanged);
|
||||
disconnect(device.get(), &DeviceConnection::networkInfomationChanged, this,
|
||||
&Application::onDeviceNetworkInfomation);
|
||||
disconnect(device.get(), &DeviceConnection::firmwareChanged, this, &Application::onDeviceFirmware);
|
||||
@ -202,9 +297,13 @@ void Application::connectToDevice(int index) {
|
||||
auto device = m_devices->device(index);
|
||||
m_device = device;
|
||||
|
||||
connect(device.get(), &DeviceConnection::rotationChanged, this, &Application::onDeviceRotationChanged);
|
||||
connect(device.get(), &DeviceConnection::flipChanged, this, &Application::onDeviceFlipChanged);
|
||||
connect(device.get(), &DeviceConnection::openDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
|
||||
connect(device.get(), &DeviceConnection::shieldedAreaChanged, this, &Application::onDeviceShieldedArea);
|
||||
connect(device.get(), &DeviceConnection::antiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
|
||||
connect(device.get(), &DeviceConnection::detectThresholdChanged, this,
|
||||
&Application::onDeviceDetectThresholdChanged);
|
||||
connect(device.get(), &DeviceConnection::networkInfomationChanged, this,
|
||||
&Application::onDeviceNetworkInfomation);
|
||||
connect(device.get(), &DeviceConnection::firmwareChanged, this, &Application::onDeviceFirmware);
|
||||
@ -220,22 +319,34 @@ void Application::connectToDevice(int index) {
|
||||
}
|
||||
});
|
||||
device->setLiveStreamEnabled(true);
|
||||
auto area = device->area();
|
||||
m_currentOpenDoorAreaWay = area.openDoorAreaWay;
|
||||
m_currentOpenDoorAreaPoints = area.openDoorArea;
|
||||
m_currentShieldedAreaEnabled = area.shieldedAreaEnabled;
|
||||
m_currentShieldedAreaPoints = area.shieldedArea;
|
||||
m_currentAntiClipAreaEnabled = area.antiClipAreaEnabled;
|
||||
m_currentAntiClipAreaPoints = area.antiClipArea;
|
||||
auto info = device->infomation();
|
||||
m_currentOpenDoorAreaWay = info.openDoorAreaWay;
|
||||
m_currentOpenDoorAreaPoints = info.openDoorArea;
|
||||
m_currentShieldedAreaEnabled = info.shieldedAreaEnabled;
|
||||
m_currentShieldedAreaPoints = info.shieldedArea;
|
||||
m_currentAntiClipAreaEnabled = info.antiClipAreaEnabled;
|
||||
m_currentAntiClipAreaPoints = info.antiClipArea;
|
||||
m_currentAntiClipSensitivity = info.antiClipSensitivity;
|
||||
m_currentNetworkInfomation = device->networkInfomation();
|
||||
m_currentFirmware = device->infomation().firmwareVersion;
|
||||
m_currentDeviceConnected = device->isConnected();
|
||||
m_currentDeviceFlip = info.flip;
|
||||
m_currentDeviceRotation = info.rotation;
|
||||
m_currentHelmetThreshold = info.helmetThreshold;
|
||||
m_currentHeadThreshold = info.headThreshold;
|
||||
m_currentDetectFrameSize = info.detectFrameSize;
|
||||
emit currentDeviceRotationChanged();
|
||||
emit currentDeviceFlipChanged();
|
||||
emit currentOpenDoorAreaPointsChanged();
|
||||
emit currentShieldedAreaPointsChanged();
|
||||
emit currentAntiClipAreaPointsChanged();
|
||||
emit currentOpenDoorAreaWayChanged();
|
||||
emit currentShieldedAreaEnabledChanged();
|
||||
emit currentAntiClipAreaEnabledChanged();
|
||||
emit currentAntiClipSensitivityChanged();
|
||||
emit currentHelmetThresholdChanged();
|
||||
emit currentHeadThresholdChanged();
|
||||
emit currentDetectFrameSizeChanged();
|
||||
emit currentNetworkInfomationChanged();
|
||||
}
|
||||
emit currentFirmwareChanged();
|
||||
@ -248,23 +359,34 @@ void Application::startSearchDevice() {
|
||||
}
|
||||
|
||||
void Application::upgradeDevice(const QString &file) {
|
||||
constexpr auto versionPrefix = "RD_T009";
|
||||
if (m_device.expired()) return;
|
||||
auto device = m_device.lock();
|
||||
auto infomation = device->infomation();
|
||||
auto versionPrefix = infomation.softwareVersion.left(7);
|
||||
constexpr auto version = "RD_T009_V21R003B013";
|
||||
QFileInfo fileInfo(file);
|
||||
QString baseName = fileInfo.baseName();
|
||||
int position = baseName.indexOf(versionPrefix);
|
||||
if (position < 0 || ((baseName.length() - position) < std::strlen(version))) {
|
||||
emit newMessage(2, "OTA升级", "文件名格式不合法!");
|
||||
LOG(error) << "baseName: " << baseName.toStdString() << ", position: " << position;
|
||||
return;
|
||||
}
|
||||
QString firmware = baseName.mid(position, std::strlen(version));
|
||||
if (!m_device.expired()) {
|
||||
auto device = m_device.lock();
|
||||
QString firmware = baseName.mid(position);
|
||||
if (device->isConnected()) {
|
||||
device->requestOta(firmware, file);
|
||||
} else {
|
||||
emit newMessage(2, "OTA升级", "设备已离线,请重新连接设备!");
|
||||
}
|
||||
}
|
||||
|
||||
void Application::resetDevice() {
|
||||
if (m_device.expired()) return;
|
||||
auto device = m_device.lock();
|
||||
if (device->isConnected()) {
|
||||
device->requestReset();
|
||||
} else {
|
||||
emit newMessage(2, "恢复出厂设置", "设备已离线,请重新连接设备!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,14 +395,28 @@ void Application::onDeviceOpenDoorArea(DeviceConnection::AreaWay way, const QLis
|
||||
setCurrentOpenDoorAreaPoints(points);
|
||||
}
|
||||
|
||||
void Application::onDeviceRotationChanged(int rotation) {
|
||||
setCurrentDeviceRotation(rotation);
|
||||
}
|
||||
void Application::onDeviceFlipChanged(bool flip) {
|
||||
setCurrentDeviceFlip(flip);
|
||||
}
|
||||
|
||||
void Application::onDeviceShieldedArea(bool enabled, const QList<QPointF> &points) {
|
||||
setCurrentShieldedAreaEnabled(enabled);
|
||||
setCurrentShieldedAreaPoints(points);
|
||||
}
|
||||
|
||||
void Application::onDeviceAntiClipArea(bool enabled, const QList<QPointF> &points) {
|
||||
void Application::onDeviceAntiClipArea(bool enabled, const QList<QPointF> &points, int sensitivity) {
|
||||
setCurrentAntiClipAreaEnabled(enabled);
|
||||
setCurrentAntiClipAreaPoints(points);
|
||||
setCurrentAntiClipSensitivity(sensitivity);
|
||||
}
|
||||
|
||||
void Application::onDeviceDetectThresholdChanged(int helmetThreshold, int headThreshold, int detectFrameSize) {
|
||||
setCurrentHelmetThreshold(helmetThreshold);
|
||||
setCurrentHeadThreshold(headThreshold);
|
||||
setCurrentDetectFrameSize(detectFrameSize);
|
||||
}
|
||||
|
||||
void Application::onDeviceNetworkInfomation(const NetworkInfomation &info) {
|
||||
|
@ -34,12 +34,23 @@ class Application : public QObject {
|
||||
setCurrentShieldedAreaPoints NOTIFY currentShieldedAreaPointsChanged)
|
||||
Q_PROPERTY(bool currentAntiClipAreaEnabled READ currentAntiClipAreaEnabled WRITE setCurrentAntiClipAreaEnabled
|
||||
NOTIFY currentAntiClipAreaEnabledChanged)
|
||||
Q_PROPERTY(int currentAntiClipSensitivity READ currentAntiClipSensitivity WRITE setCurrentAntiClipSensitivity NOTIFY currentAntiClipSensitivityChanged)
|
||||
Q_PROPERTY(int currentHelmetThreshold READ currentHelmetThreshold WRITE setCurrentHelmetThreshold NOTIFY
|
||||
currentHelmetThresholdChanged)
|
||||
Q_PROPERTY(int currentHeadThreshold READ currentHeadThreshold WRITE setCurrentHeadThreshold NOTIFY
|
||||
currentHeadThresholdChanged)
|
||||
Q_PROPERTY(int currentDetectFrameSize READ currentDetectFrameSize WRITE setCurrentDetectFrameSize NOTIFY
|
||||
currentDetectFrameSizeChanged)
|
||||
Q_PROPERTY(QList<QPointF> currentAntiClipAreaPoints READ currentAntiClipAreaPoints WRITE
|
||||
setCurrentAntiClipAreaPoints NOTIFY currentAntiClipAreaPointsChanged)
|
||||
Q_PROPERTY(
|
||||
NetworkInfomation currentNetworkInfomation READ currentNetworkInfomation NOTIFY currentNetworkInfomationChanged)
|
||||
Q_PROPERTY(QString currentFirmware MEMBER m_currentFirmware NOTIFY currentFirmwareChanged)
|
||||
Q_PROPERTY(bool currentDeviceConnected MEMBER m_currentDeviceConnected NOTIFY currentDeviceConnectedChanged)
|
||||
|
||||
Q_PROPERTY(bool currentDeviceFlip READ currentDeviceFlip WRITE setCurrentDeviceFlip NOTIFY currentDeviceFlipChanged)
|
||||
Q_PROPERTY(int currentDeviceRotation READ currentDeviceRotation WRITE setCurrentDeviceRotation NOTIFY
|
||||
currentDeviceRotationChanged)
|
||||
friend class Amass::Singleton<Application>;
|
||||
|
||||
public:
|
||||
@ -61,9 +72,26 @@ public:
|
||||
|
||||
bool currentAntiClipAreaEnabled() const;
|
||||
void setCurrentAntiClipAreaEnabled(bool enabled);
|
||||
int currentAntiClipSensitivity() const;
|
||||
void setCurrentAntiClipSensitivity(int sensitivity);
|
||||
QList<QPointF> currentAntiClipAreaPoints() const;
|
||||
void setCurrentAntiClipAreaPoints(const QList<QPointF> &points);
|
||||
|
||||
bool currentDeviceFlip() const;
|
||||
void setCurrentDeviceFlip(bool flip);
|
||||
|
||||
int currentDeviceRotation() const;
|
||||
void setCurrentDeviceRotation(int rotation);
|
||||
|
||||
int currentHelmetThreshold() const;
|
||||
void setCurrentHelmetThreshold(int threshold);
|
||||
|
||||
int currentHeadThreshold() const;
|
||||
void setCurrentHeadThreshold(int threshold);
|
||||
|
||||
int currentDetectFrameSize() const;
|
||||
void setCurrentDetectFrameSize(int size);
|
||||
|
||||
Q_INVOKABLE void updateOpenDoorAreaPoints(const QList<QPointF> &points);
|
||||
Q_INVOKABLE void updateAntiClipAreaPoints(const QList<QPointF> &points);
|
||||
Q_INVOKABLE void updateShieldedAreaPoints(const QList<QPointF> &points);
|
||||
@ -71,6 +99,7 @@ public:
|
||||
const QString &gateway, const QString &dns);
|
||||
Q_INVOKABLE void connectToDevice(int index);
|
||||
Q_INVOKABLE void upgradeDevice(const QString &file);
|
||||
Q_INVOKABLE void resetDevice();
|
||||
Q_INVOKABLE void startSearchDevice();
|
||||
|
||||
int exec();
|
||||
@ -84,17 +113,26 @@ signals:
|
||||
void currentOpenDoorAreaWayChanged();
|
||||
void currentShieldedAreaEnabledChanged();
|
||||
void currentAntiClipAreaEnabledChanged();
|
||||
void currentAntiClipSensitivityChanged();
|
||||
void currentHelmetThresholdChanged();
|
||||
void currentDetectFrameSizeChanged();
|
||||
void currentHeadThresholdChanged();
|
||||
void currentNetworkInfomationChanged();
|
||||
void currentFirmwareChanged();
|
||||
void currentDeviceConnectedChanged();
|
||||
void currentDeviceOtaProgressChanged(bool status, int progress, const QString &message);
|
||||
void currentDeviceFlipChanged();
|
||||
void currentDeviceRotationChanged();
|
||||
void newMessage(int type, const QString &title, const QString &message);
|
||||
|
||||
protected:
|
||||
Application(int &argc, char **argv);
|
||||
void onDeviceRotationChanged(int rotation);
|
||||
void onDeviceFlipChanged(bool flip);
|
||||
void onDeviceOpenDoorArea(DeviceConnection::AreaWay way, const QList<QPointF> &points);
|
||||
void onDeviceShieldedArea(bool enabled, const QList<QPointF> &points);
|
||||
void onDeviceAntiClipArea(bool enabled, const QList<QPointF> &points);
|
||||
void onDeviceAntiClipArea(bool enabled, const QList<QPointF> &points, int sensitivity);
|
||||
void onDeviceDetectThresholdChanged(int helmetThreshold, int headThreshold, int detectFrameSize);
|
||||
void onDeviceNetworkInfomation(const NetworkInfomation &info);
|
||||
void onDeviceFirmware(const QString &firmware);
|
||||
void onDeviceConnected();
|
||||
@ -114,10 +152,16 @@ private:
|
||||
bool m_currentShieldedAreaEnabled = false;
|
||||
QList<QPointF> m_currentShieldedAreaPoints;
|
||||
bool m_currentAntiClipAreaEnabled = false;
|
||||
int m_currentAntiClipSensitivity = 1;
|
||||
QList<QPointF> m_currentAntiClipAreaPoints;
|
||||
NetworkInfomation m_currentNetworkInfomation;
|
||||
QString m_currentFirmware;
|
||||
bool m_currentDeviceConnected = false;
|
||||
bool m_currentDeviceFlip = false;
|
||||
int m_currentDeviceRotation = 0;
|
||||
int m_currentHelmetThreshold = 1;
|
||||
int m_currentHeadThreshold = 2;
|
||||
int m_currentDetectFrameSize = 3;
|
||||
};
|
||||
|
||||
#endif // APPLICATION_H
|
||||
|
@ -1,13 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(AntiClipSettings VERSION 1.3 LANGUAGES C CXX)
|
||||
project(AntiClipSettings VERSION 1.8 LANGUAGES C CXX)
|
||||
set(APPLICATION_NAME "视觉防夹设备上位机工具")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(Projects_ROOT E:/Projects)
|
||||
set(Libraries_ROOT ${Projects_ROOT}/Libraries)
|
||||
if(LINUX)
|
||||
set(Libraries_ROOT /opt/Libraries CACHE STRING "Libraries directory.")
|
||||
else()
|
||||
set(Libraries_ROOT E:/Projects/Libraries CACHE STRING "Libraries directory.")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Qml Quick Network QuickControls2)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Qml Quick Network QuickControls2)
|
||||
@ -19,25 +23,45 @@ if (Qt6_FOUND)
|
||||
add_compile_definitions(
|
||||
BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WIN10
|
||||
)
|
||||
set(FFmpeg_ROOT ${Libraries_ROOT}/ffmpeg-7.0.2-full_build-shared)
|
||||
else()
|
||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
if(LINUX)
|
||||
set(BOOST_ROOT ${Libraries_ROOT}/boost_1_83_0)
|
||||
else()
|
||||
set(BOOST_ROOT ${Libraries_ROOT}/boost_1_83_0_msvc2022_64bit)
|
||||
endif()
|
||||
set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_83)
|
||||
set(FFmpeg_ROOT ${Libraries_ROOT}/ffmpeg-6.1.1-full_build-shared)
|
||||
endif()
|
||||
option(Boost_USE_STATIC_LIBS OFF)
|
||||
|
||||
set(FFmpeg_ROOT ${Libraries_ROOT}/ffmpeg-6.1.1-full_build-shared)
|
||||
set(OpenSSL_ROOT D:/Qt/Tools/OpenSSLv3/Win_x64)
|
||||
set(OPENSSL_INCLUDE_DIR ${OpenSSL_ROOT}/include)
|
||||
set(OpenSSL_LIBRARY_DIRS ${OpenSSL_ROOT}/lib)
|
||||
set(OpenSSL_LIBRARIES libssl libcrypto)
|
||||
|
||||
set(FFmpeg_INCLUDE_DIR ${FFmpeg_ROOT}/include)
|
||||
set(FFmpeg_LIB_DIR ${FFmpeg_ROOT}/lib)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
if(LINUX)
|
||||
set(MBEDTLS_ROOT ${Libraries_ROOT}/mbedtls-3.6.2)
|
||||
set(JPEGTURBO_ROOT ${Libraries_ROOT}/libjpeg-turbo-3.1.0)
|
||||
else()
|
||||
set(MBEDTLS_ROOT ${Libraries_ROOT}/mbedtls-3.6.2_msvc2022_64bit_debug)
|
||||
set(JPEGTURBO_ROOT ${Libraries_ROOT}/libjpeg-turbo-3.0.3_msvc2022_64bit_debug)
|
||||
endif()
|
||||
else()
|
||||
set(JPEGTURBO_ROOT ${Libraries_ROOT}/libjpeg-turbo-3.0.3_msvc2022_64bit_release)
|
||||
set(MBEDTLS_ROOT ${Libraries_ROOT}/mbedtls-3.6.2_msvc2022_64bit_release)
|
||||
endif()
|
||||
|
||||
set(MbedTLS_DIR ${MBEDTLS_ROOT}/lib/cmake/MbedTLS)
|
||||
|
||||
set(JPEGTURBO_INCLUDE_DIR ${JPEGTURBO_ROOT}/include)
|
||||
set(JPEGTURBO_LIB_DIR ${JPEGTURBO_ROOT}/lib)
|
||||
|
||||
@ -95,8 +119,13 @@ set_target_properties(AntiClipSettings PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
add_subdirectory(${Projects_ROOT}/Kylin/Universal Universal)
|
||||
add_subdirectory(${Projects_ROOT}/Kylin/Encrypt Encrypt)
|
||||
include(CPack)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(Kylin
|
||||
GIT_REPOSITORY https://amass.fun/gitea/amass/Kylin.git
|
||||
)
|
||||
set(KYLIN_WITH_FLUENT OFF)
|
||||
FetchContent_MakeAvailable(Kylin)
|
||||
|
||||
target_include_directories(AntiClipSettings
|
||||
PRIVATE ${FFmpeg_INCLUDE_DIR}
|
||||
@ -122,8 +151,9 @@ target_link_libraries(AntiClipSettings
|
||||
PRIVATE avformat
|
||||
PRIVATE Universal
|
||||
PRIVATE Encrypt
|
||||
PRIVATE turbojpeg-static
|
||||
PRIVATE Ws2_32
|
||||
$<$<PLATFORM_ID:Linux>:turbojpeg>
|
||||
$<$<PLATFORM_ID:Windows>:turbojpeg-static>
|
||||
$<$<PLATFORM_ID:Windows>:Ws2_32>
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
@ -4,13 +4,18 @@
|
||||
#include <QFileInfo>
|
||||
#include <QPointF>
|
||||
#include <QTimer>
|
||||
#include <WinSock2.h>
|
||||
#include <QTimerEvent>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/serialize.hpp>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <mbedtls/md5.h>
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <WinSock2.h>
|
||||
#endif
|
||||
|
||||
DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} {
|
||||
}
|
||||
@ -24,9 +29,9 @@ void DeviceConnection::close() {
|
||||
m_otaTimer->deleteLater();
|
||||
m_otaTimer = nullptr;
|
||||
}
|
||||
if (m_timerId > 0) {
|
||||
killTimer(m_timerId);
|
||||
m_timerId = -1;
|
||||
if (m_heartbeatTimerId > 0) {
|
||||
killTimer(m_heartbeatTimerId);
|
||||
m_heartbeatTimerId = -1;
|
||||
}
|
||||
if (m_commandSocket != nullptr) {
|
||||
m_commandSocket->deleteLater();
|
||||
@ -73,10 +78,6 @@ void DeviceConnection::connect(const Infomation &infomation) {
|
||||
m_h264Socket->connectToHost(infomation.ip, 8000);
|
||||
}
|
||||
|
||||
DeviceConnection::Area DeviceConnection::area() const {
|
||||
return m_area;
|
||||
}
|
||||
|
||||
NetworkInfomation DeviceConnection::networkInfomation() const {
|
||||
return m_networkInfomation;
|
||||
}
|
||||
@ -213,15 +214,16 @@ void DeviceConnection::requestAntiClipArea() {
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points) {
|
||||
void DeviceConnection::updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points, int sensitivity) {
|
||||
Task task;
|
||||
task.command = "a03opendoor5_setdata";
|
||||
task.task = [this, enabled, points]() {
|
||||
task.task = [this, enabled, points, sensitivity]() {
|
||||
boost::json::object request;
|
||||
request["func"] = "a03opendoor5_setdata";
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
data["value"] = enabled ? "1" : "0";
|
||||
data["sensitivity"] = std::to_string(sensitivity);
|
||||
boost::json::array pointArray;
|
||||
for (auto &p : points) {
|
||||
boost::json::object point;
|
||||
@ -242,6 +244,56 @@ void DeviceConnection::updateAntiClipAreaPoints(bool enabled, const QList<QPoint
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
QFuture<bool> DeviceConnection::updateDetectThreshold(int helmetThreshold, int headThreshold, int detectFrameSize) {
|
||||
constexpr auto command = "headdetectparam_setdata";
|
||||
Task task;
|
||||
task.command = command;
|
||||
task.task = [this, helmetThreshold, headThreshold, detectFrameSize, command]() {
|
||||
boost::json::object request;
|
||||
request["func"] = command;
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
if (headThreshold >= 0) {
|
||||
data["headthreshold"] = headThreshold;
|
||||
}
|
||||
if (helmetThreshold >= 0) {
|
||||
data["hatthreshold"] = helmetThreshold;
|
||||
}
|
||||
if (detectFrameSize >= 0) {
|
||||
data["detectframenum"] = detectFrameSize;
|
||||
}
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
};
|
||||
task.future = std::make_shared<QFutureInterface<bool>>();
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
auto ret = task.future->future();
|
||||
m_requests.push(task);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeviceConnection::requestHeadDetectThreshold() {
|
||||
constexpr auto command = "headdetectparam_getdata";
|
||||
Task task;
|
||||
task.command = command;
|
||||
task.task = [this, command]() {
|
||||
boost::json::object request;
|
||||
request["func"] = command;
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
};
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::requestResolution(Resolution resolution) {
|
||||
Task task;
|
||||
task.command = "quality_setdata";
|
||||
@ -262,6 +314,44 @@ void DeviceConnection::requestResolution(Resolution resolution) {
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::updateRotation(int rotation) {
|
||||
Task task;
|
||||
task.command = "a23imagerotate_setdata";
|
||||
task.task = [this, rotation]() {
|
||||
boost::json::object request;
|
||||
request["func"] = "a23imagerotate_setdata";
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
data["value"] = std::to_string(rotation);
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
LOG(info) << "updateRotation: " << text;
|
||||
};
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
m_requests.push(task);
|
||||
}
|
||||
void DeviceConnection::updateFlip(bool flip) {
|
||||
Task task;
|
||||
task.command = "a04imageflipping_setdata";
|
||||
task.task = [this, flip]() {
|
||||
boost::json::object request;
|
||||
request["func"] = "a04imageflipping_setdata";
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
data["value"] = flip ? "2" : "1";
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
};
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::requestVersion() {
|
||||
Task task;
|
||||
task.command = "a15devicedetail_getdata";
|
||||
@ -281,6 +371,27 @@ void DeviceConnection::requestVersion() {
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::requestVideoInformation() {
|
||||
constexpr const char *commands[] = {"a23imagerotate_getdata", "a04imageflipping_getdata"};
|
||||
for (auto command : commands) {
|
||||
Task task;
|
||||
task.command = command;
|
||||
task.task = [this, command]() {
|
||||
boost::json::object request;
|
||||
request["func"] = command;
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
};
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
m_requests.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceConnection::requestNetworkInfomation() {
|
||||
Task task;
|
||||
task.command = "netconfig_getdata";
|
||||
@ -332,17 +443,21 @@ QFuture<bool> DeviceConnection::updateNetworkInfomation(bool dhcp, const QString
|
||||
void DeviceConnection::requestOta(const QString &firmware, const QString &file) {
|
||||
m_otaProgress = 0;
|
||||
emit otaProgressChanged(true, m_otaProgress, "正在向设备发起OTA请求......");
|
||||
if (m_timerId > 0) {
|
||||
killTimer(m_timerId);
|
||||
m_timerId = -1;
|
||||
if (m_heartbeatTimerId > 0) {
|
||||
killTimer(m_heartbeatTimerId);
|
||||
m_heartbeatTimerId = -1;
|
||||
}
|
||||
if (!m_requests.empty()) {
|
||||
while (!m_requests.empty()) { // 清除之前的命令
|
||||
m_requests.pop();
|
||||
}
|
||||
Task task;
|
||||
task.command = "a22devicefirmware_setdata";
|
||||
task.task = [this, file, firmware]() {
|
||||
#ifdef Q_OS_LINUX
|
||||
std::ifstream ifs(file.toStdString(), std::ifstream::binary);
|
||||
#else
|
||||
std::ifstream ifs(Amass::StringUtility::UTF8ToGBK(file.toStdString()), std::ifstream::binary);
|
||||
#endif
|
||||
m_uploadBuffer = std::vector<uint8_t>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
m_sendedSize = 0;
|
||||
|
||||
@ -377,10 +492,36 @@ void DeviceConnection::requestOta(const QString &firmware, const QString &file)
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::requestReset() {
|
||||
Task task;
|
||||
task.command = "a12factory_setdata";
|
||||
task.task = [this]() {
|
||||
boost::json::object request;
|
||||
request["func"] = "a12factory_setdata";
|
||||
request["deviceid"] = "0";
|
||||
boost::json::object data;
|
||||
data["value"] = "1";
|
||||
|
||||
request["data"] = std::move(data);
|
||||
auto text = boost::json::serialize(request);
|
||||
m_commandSocket->write(text.data(), text.size());
|
||||
};
|
||||
task.future = std::make_shared<QFutureInterface<bool>>();
|
||||
if (m_requests.empty()) {
|
||||
task.task();
|
||||
}
|
||||
auto ret = task.future->future();
|
||||
m_requests.push(task);
|
||||
}
|
||||
|
||||
void DeviceConnection::transferBinContent() {
|
||||
constexpr int SliceSize = 1024;
|
||||
constexpr int WaitMd5CheckTime = 3000; // ms
|
||||
if (m_sendedSize >= m_uploadBuffer.size()) return;
|
||||
if (m_sendedSize >= m_uploadBuffer.size()) {
|
||||
LOG(warning) << "file size is wrong, sended size: " << m_sendedSize
|
||||
<< "ota file size: " << m_uploadBuffer.size();
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[1 + sizeof(int32_t) + 1024];
|
||||
int sendSize = SliceSize;
|
||||
@ -407,18 +548,6 @@ void DeviceConnection::transferBinContent() {
|
||||
} else if (m_sendedSize >= m_uploadBuffer.size()) {
|
||||
LOG(info) << "transfer ota file finished, wait " << WaitMd5CheckTime
|
||||
<< " ms for send check, total sended size: " << m_sendedSize;
|
||||
// QTimer::singleShot(WaitMd5CheckTime, this, [this]() {
|
||||
// boost::json::object request;
|
||||
// request["func"] = "a22devicefirmware_setdata";
|
||||
// request["deviceid"] = "0";
|
||||
// boost::json::object data;
|
||||
// data["target_linux04_firmware"] = "RD_T009_V21R003B001";
|
||||
// request["data"] = std::move(data);
|
||||
// auto text = boost::json::serialize(request);
|
||||
// m_commandSocket->write(text.data(), text.size());
|
||||
// LOG(info) << "request md5 check result: " << text;
|
||||
// });
|
||||
|
||||
if (m_otaTimer == nullptr) {
|
||||
m_otaTimer = new QTimer(this);
|
||||
m_otaTimer->setSingleShot(true);
|
||||
@ -437,7 +566,7 @@ void DeviceConnection::transferBinContent() {
|
||||
m_h264Socket->close();
|
||||
},
|
||||
type);
|
||||
m_otaTimer->start(60 * 1000);
|
||||
m_otaTimer->start(5 * 60 * 1000); // 固件升级五分钟,正常升级2.5分钟左右(包含算法模型)
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,8 +598,8 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
||||
} else if (value == "2") {
|
||||
way = Quadrangle;
|
||||
}
|
||||
m_area.openDoorAreaWay = way;
|
||||
m_area.openDoorArea = points;
|
||||
m_infomation.openDoorAreaWay = way;
|
||||
m_infomation.openDoorArea = points;
|
||||
emit openDoorAreaChanged(way, points);
|
||||
} else if (function == "a03opendoor4_getdata") {
|
||||
auto &data = reply.at("data").as_object();
|
||||
@ -484,8 +613,8 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
||||
point.setY(obj.at("y").as_double());
|
||||
points.push_back(point);
|
||||
}
|
||||
m_area.shieldedAreaEnabled = value == "1";
|
||||
m_area.shieldedArea = points;
|
||||
m_infomation.shieldedAreaEnabled = value == "1";
|
||||
m_infomation.shieldedArea = points;
|
||||
emit shieldedAreaChanged(value == "1", points);
|
||||
} else if (function == "a03opendoor5_getdata") {
|
||||
auto &data = reply.at("data").as_object();
|
||||
@ -499,9 +628,12 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
||||
point.setY(obj.at("y").as_double());
|
||||
points.push_back(point);
|
||||
}
|
||||
m_area.antiClipAreaEnabled = value == "1";
|
||||
m_area.antiClipArea = points;
|
||||
emit antiClipAreaChanged(value == "1", points);
|
||||
m_infomation.antiClipAreaEnabled = value == "1";
|
||||
m_infomation.antiClipArea = points;
|
||||
if (data.contains("sensitivity")) {
|
||||
m_infomation.antiClipSensitivity = std::stoi(static_cast<std::string>(data.at("sensitivity").as_string()));
|
||||
}
|
||||
emit antiClipAreaChanged(value == "1", points, m_infomation.antiClipSensitivity);
|
||||
} else if (function == "netconfig_getdata") {
|
||||
auto &data = reply.at("data").as_object();
|
||||
m_networkInfomation.dhcp = data.at("type").as_string() == "dhcp";
|
||||
@ -570,7 +702,7 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
||||
emit otaProgressChanged(true, m_otaProgress, "设备正在升级中,请稍后......");
|
||||
} else {
|
||||
m_otaTimer->stop(); // 这里不需要再超时了
|
||||
emit otaProgressChanged(true, 100, "设备正在升级中,请于一分钟后重新连接wifi搜索设备");
|
||||
emit otaProgressChanged(true, 100, "设备正在升级中,请于五分钟后重新连接wifi搜索设备");
|
||||
}
|
||||
} else {
|
||||
const char *message = nullptr;
|
||||
@ -591,10 +723,69 @@ QString DeviceConnection::handleCommand(const std::string_view &replyText, const
|
||||
}
|
||||
emit otaProgressChanged(false, m_otaProgress, tip);
|
||||
}
|
||||
} else if (function == "a23imagerotate_getdata") {
|
||||
// {"data":{"value":"2"},"deviceid":"0","flag":"ok","func":"a23imagerotate_getdata"}
|
||||
auto &data = reply.at("data").as_object();
|
||||
auto &value = data.at("value").as_string();
|
||||
m_infomation.rotation = std::stoi(static_cast<std::string>(value));
|
||||
emit rotationChanged(m_infomation.rotation);
|
||||
} else if (function == "a04imageflipping_getdata") {
|
||||
// {"data":{"value":"1"},"deviceid":"0","flag":"ok","func":"a04imageflipping_getdata"}
|
||||
auto &data = reply.at("data").as_object();
|
||||
auto &value = data.at("value").as_string();
|
||||
m_infomation.flip = value == "2";
|
||||
emit flipChanged(m_infomation.flip);
|
||||
} else if (function == "a04imageflipping_setdata") {
|
||||
if ((task != nullptr) && (task->command.toStdString() == function)) {
|
||||
if (task->timeoutTimer) {
|
||||
task->timeoutTimer->stop();
|
||||
}
|
||||
bool status = true;
|
||||
if (task->future) {
|
||||
task->future->reportFinished(&status);
|
||||
}
|
||||
}
|
||||
requestVideoInformation();
|
||||
} else if (function == "a23imagerotate_setdata") {
|
||||
if ((task != nullptr) && (task->command.toStdString() == function)) {
|
||||
if (task->timeoutTimer) {
|
||||
task->timeoutTimer->stop();
|
||||
}
|
||||
bool status = true;
|
||||
if (task->future) {
|
||||
task->future->reportFinished(&status);
|
||||
}
|
||||
}
|
||||
requestVideoInformation();
|
||||
} else if (function == "a12factory_setdata") {
|
||||
LOG(info) << "device factory reset";
|
||||
} else if (function == "headdetectparam_getdata") {
|
||||
auto &data = reply.at("data").as_object();
|
||||
if (data.contains("hatthreshold")) {
|
||||
m_infomation.helmetThreshold = data.at("hatthreshold").as_int64();
|
||||
}
|
||||
if (data.contains("headthreshold")) {
|
||||
m_infomation.headThreshold = data.at("headthreshold").as_int64();
|
||||
}
|
||||
if (data.contains("detectframenum")) {
|
||||
m_infomation.detectFrameSize = data.at("detectframenum").as_int64();
|
||||
}
|
||||
emit detectThresholdChanged(m_infomation.helmetThreshold, m_infomation.headThreshold,
|
||||
m_infomation.detectFrameSize);
|
||||
} else if (function == "thresholdwithhat_setdata") {
|
||||
if ((task != nullptr) && (task->command.toStdString() == function)) {
|
||||
if (task->timeoutTimer) {
|
||||
task->timeoutTimer->stop();
|
||||
}
|
||||
bool status = true;
|
||||
if (task->future) {
|
||||
task->future->reportFinished(&status);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(warning) << "unknown reply: " << replyText;
|
||||
}
|
||||
return QString::fromStdString(std::string(std::move(function)));
|
||||
return QString::fromStdString(std::string(function));
|
||||
}
|
||||
|
||||
void DeviceConnection::onConnected() {
|
||||
@ -605,8 +796,10 @@ void DeviceConnection::onConnected() {
|
||||
requestShieldedArea();
|
||||
requestAntiClipArea();
|
||||
requestNetworkInfomation();
|
||||
requestVideoInformation();
|
||||
requestHeadDetectThreshold();
|
||||
emit connected();
|
||||
m_timerId = startTimer(2500);
|
||||
m_heartbeatTimerId = startTimer(2500);
|
||||
if (m_otaProgress == 99) {
|
||||
m_otaProgress = -1;
|
||||
emit otaProgressChanged(true, 100, "设备升级成功!");
|
||||
@ -614,6 +807,9 @@ void DeviceConnection::onConnected() {
|
||||
if (m_otaTimer != nullptr) {
|
||||
m_otaTimer->stop();
|
||||
}
|
||||
if (m_requestTimerId < 0) {
|
||||
m_requestTimerId = startTimer(HeartbeatInterval);
|
||||
}
|
||||
} else if (socket == m_h264Socket) {
|
||||
if (m_videoEnabled) {
|
||||
setLiveStreamEnabled(true);
|
||||
@ -624,9 +820,13 @@ void DeviceConnection::onConnected() {
|
||||
void DeviceConnection::onDisconnected() {
|
||||
auto socket = dynamic_cast<QTcpSocket *>(sender());
|
||||
if (socket == m_commandSocket) {
|
||||
if (m_timerId > 0) {
|
||||
killTimer(m_timerId);
|
||||
m_timerId = -1;
|
||||
if (m_requestTimerId > 0) {
|
||||
killTimer(m_requestTimerId);
|
||||
m_requestTimerId = -1;
|
||||
}
|
||||
if (m_heartbeatTimerId > 0) {
|
||||
killTimer(m_heartbeatTimerId);
|
||||
m_heartbeatTimerId = -1;
|
||||
}
|
||||
emit disconnected();
|
||||
if ((m_otaProgress >= 0) && (m_otaProgress <= 98)) {
|
||||
@ -665,7 +865,6 @@ void DeviceConnection::onH264ReadyRead() {
|
||||
void DeviceConnection::onCommandReadyRead() {
|
||||
auto data = m_commandSocket->readAll();
|
||||
m_commandBuffer.push_back(data);
|
||||
|
||||
while (!m_commandBuffer.isEmpty()) {
|
||||
auto packageSize = ntohl(*reinterpret_cast<uint32_t *>(m_commandBuffer.data()));
|
||||
if (m_commandBuffer.size() < (packageSize + sizeof(uint32_t))) break;
|
||||
@ -677,9 +876,13 @@ void DeviceConnection::onCommandReadyRead() {
|
||||
auto &task = m_requests.front();
|
||||
if (task.command == command) {
|
||||
m_requests.pop();
|
||||
} else {
|
||||
LOG(warning) << "current command[" << command.toStdString() << "] is no the task queue's head["
|
||||
<< task.command.toStdString() << "]";
|
||||
}
|
||||
if (!m_requests.empty()) {
|
||||
m_requests.front().task();
|
||||
auto &command = m_requests.front();
|
||||
command.task();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -691,6 +894,8 @@ void DeviceConnection::onErrorOccurred(QAbstractSocket::SocketError socketError)
|
||||
}
|
||||
|
||||
void DeviceConnection::timerEvent(QTimerEvent *event) {
|
||||
using namespace std::chrono;
|
||||
if (event->timerId() == m_heartbeatTimerId) {
|
||||
if (isConnected()) {
|
||||
int index = heartbeats % 3;
|
||||
if (index == 0) {
|
||||
@ -702,4 +907,22 @@ void DeviceConnection::timerEvent(QTimerEvent *event) {
|
||||
}
|
||||
heartbeats++;
|
||||
}
|
||||
} else if (event->timerId() == m_requestTimerId) {
|
||||
if (!m_requests.empty()) {
|
||||
auto &command = m_requests.front();
|
||||
auto elapsed = duration_cast<milliseconds>(system_clock::now() - command.time);
|
||||
if (elapsed > (HeartbeatInterval * 2)) {
|
||||
LOG(info) << "not received command[" << command.command.toStdString() << "] more than "
|
||||
<< (HeartbeatInterval * 2).count() << " ms, consider it failed, send next command.";
|
||||
m_requests.pop();
|
||||
if (!m_requests.empty()) {
|
||||
m_requests.front().task();
|
||||
}
|
||||
} else if (elapsed > HeartbeatInterval) {
|
||||
LOG(info) << "not received command[" << command.command.toStdString() << "] more than "
|
||||
<< HeartbeatInterval.count() << " ms, resend it.";
|
||||
command.task();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,10 @@
|
||||
#include <QTcpSocket>
|
||||
#include <queue>
|
||||
#include <string_view>
|
||||
#include <QPointF>
|
||||
|
||||
class NetworkInfomation;
|
||||
class QTimer;
|
||||
|
||||
class DeviceConnection : public QObject {
|
||||
Q_OBJECT
|
||||
@ -19,6 +21,7 @@ class DeviceConnection : public QObject {
|
||||
|
||||
public:
|
||||
constexpr static auto WirelessAddress = "192.168.10.2";
|
||||
constexpr static auto HeartbeatInterval = std::chrono::milliseconds(2500);
|
||||
enum Resolution {
|
||||
Video_360P = 0,
|
||||
Video_720P,
|
||||
@ -34,11 +37,10 @@ public:
|
||||
QString softwareVersion;
|
||||
QString firmwareVersion;
|
||||
QString ip;
|
||||
};
|
||||
Q_ENUM(AreaWay)
|
||||
|
||||
class Area {
|
||||
public:
|
||||
int rotation = 0;
|
||||
bool flip = false;
|
||||
|
||||
QList<QPointF> openDoorArea;
|
||||
AreaWay openDoorAreaWay;
|
||||
|
||||
@ -47,7 +49,12 @@ public:
|
||||
|
||||
QList<QPointF> antiClipArea;
|
||||
bool antiClipAreaEnabled;
|
||||
int antiClipSensitivity = 1;
|
||||
int helmetThreshold = 1;
|
||||
int headThreshold = 1;
|
||||
int detectFrameSize = 1;
|
||||
};
|
||||
Q_ENUM(AreaWay)
|
||||
|
||||
using H264FrameCallback = std::function<void(const char *data, uint32_t size)>;
|
||||
DeviceConnection(QObject *parent = nullptr);
|
||||
@ -60,19 +67,23 @@ public:
|
||||
void setLiveStreamEnabled(bool enabled);
|
||||
|
||||
NetworkInfomation networkInfomation() const;
|
||||
Area area() const;
|
||||
|
||||
void requestOpenDoorArea();
|
||||
QFuture<bool> updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points);
|
||||
void requestShieldedArea();
|
||||
void updateShieldedAreaPoints(bool enabled, const QList<QPointF> &points);
|
||||
void requestAntiClipArea();
|
||||
void updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points);
|
||||
void updateAntiClipAreaPoints(bool enabled, const QList<QPointF> &points, int sensitivity);
|
||||
void requestResolution(Resolution resolution);
|
||||
void requestNetworkInfomation();
|
||||
QFuture<bool> updateDetectThreshold(int helmetThreshold, int headThreshold, int detectFrameSize);
|
||||
void requestHeadDetectThreshold();
|
||||
QFuture<bool> updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask, const QString &gateway,
|
||||
const QString &dns);
|
||||
void requestVersion();
|
||||
void requestVideoInformation();
|
||||
void updateRotation(int rotation);
|
||||
void updateFlip(bool flip);
|
||||
|
||||
/**
|
||||
* @brief 对设备升级OTA,主要有几个步骤
|
||||
@ -84,13 +95,17 @@ public:
|
||||
* @param file
|
||||
*/
|
||||
void requestOta(const QString &firmware, const QString &file);
|
||||
void requestReset();
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void openDoorAreaChanged(AreaWay way, const QList<QPointF> &points);
|
||||
void shieldedAreaChanged(bool enabled, const QList<QPointF> &points);
|
||||
void antiClipAreaChanged(bool enabled, const QList<QPointF> &points);
|
||||
void antiClipAreaChanged(bool enabled, const QList<QPointF> &points, int sensitivity);
|
||||
void rotationChanged(int rotation);
|
||||
void flipChanged(bool flip);
|
||||
void detectThresholdChanged(int helmetThreshold, int headThreshold, int detectFrameSize);
|
||||
void networkInfomationChanged(const NetworkInfomation &info);
|
||||
void firmwareChanged(const QString &firmware);
|
||||
void otaProgressChanged(bool status, int progress, const QString &message);
|
||||
@ -99,6 +114,7 @@ protected:
|
||||
class Task {
|
||||
public:
|
||||
QString command;
|
||||
std::chrono::system_clock::time_point time = std::chrono::system_clock::now();
|
||||
std::function<void()> task;
|
||||
std::shared_ptr<QTimer> timeoutTimer = nullptr;
|
||||
std::shared_ptr<QFutureInterface<bool>> future;
|
||||
@ -131,9 +147,9 @@ private:
|
||||
|
||||
H264FrameCallback m_frameCallback;
|
||||
std::queue<Task> m_requests;
|
||||
int m_timerId = -1;
|
||||
int m_requestTimerId = -1;
|
||||
int m_heartbeatTimerId = -1;
|
||||
int heartbeats = 0;
|
||||
Area m_area;
|
||||
NetworkInfomation m_networkInfomation;
|
||||
QString m_firmware;
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "DeviceListModel.h"
|
||||
#include "BoostLog.h"
|
||||
#include "DeviceConnection.h"
|
||||
#include "Settings.h"
|
||||
#include <QNetworkDatagram>
|
||||
#include <QNetworkInterface>
|
||||
#include <QTimer>
|
||||
@ -138,6 +139,8 @@ void DeviceListModel::startSearchDevice() {
|
||||
emit searchProgressChanged();
|
||||
m_timerId = startTimer(1000);
|
||||
emit isSearchingChanged();
|
||||
} else {
|
||||
LOG(warning) << "cannot creat udp sockets.";
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +189,7 @@ void DeviceListModel::onDeviceDisconnected() {
|
||||
}
|
||||
|
||||
void DeviceListModel::onDeviceReplyReadyRead() {
|
||||
using namespace Amass;
|
||||
auto udp = dynamic_cast<QUdpSocket *>(sender());
|
||||
while (udp->hasPendingDatagrams()) {
|
||||
QNetworkDatagram datagram = udp->receiveDatagram();
|
||||
@ -202,7 +206,12 @@ void DeviceListModel::onDeviceReplyReadyRead() {
|
||||
if (reply.contains("sw_ver")) {
|
||||
device.softwareVersion = QString::fromStdString(std::string(reply.at("sw_ver").as_string()));
|
||||
}
|
||||
if (!device.softwareVersion.startsWith("RD_T009")) continue; // 其它设备不予显示
|
||||
auto settings = Singleton<Settings>::instance();
|
||||
auto supportedDevices = settings->supportedDevices();
|
||||
auto item = std::find_if(supportedDevices.cbegin(), supportedDevices.cend(), [&device](const std::string &model) {
|
||||
return device.softwareVersion.startsWith(QString::fromStdString(model));
|
||||
});
|
||||
if (item == supportedDevices.cend()) continue; // 其它设备不予显示
|
||||
device.ip = datagram.senderAddress().toString();
|
||||
|
||||
auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(),
|
||||
|
22
Settings.cpp
22
Settings.cpp
@ -25,20 +25,36 @@ void Settings::save() {
|
||||
ptree.put("Application.DataCollection.ImageQuality", m_imageQuality);
|
||||
ptree.put("Application.DataCollection.ImageQuality.<xmlcomment>", "0-100,仅对jpg有效");
|
||||
|
||||
for (auto &device : m_supportedDevices) {
|
||||
ptree.add("Application.SupportedDevices.Model", device);
|
||||
}
|
||||
|
||||
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
|
||||
boost::property_tree::write_xml(SettingsFilePath, ptree, std::locale(), settings);
|
||||
}
|
||||
|
||||
void Settings::load() {
|
||||
boost::property_tree::ptree ptree;
|
||||
m_supportedDevices.clear();
|
||||
try {
|
||||
boost::property_tree::read_xml(SettingsFilePath, ptree);
|
||||
m_imageFormat = static_cast<ImageFormat>(ptree.get<int>("Application.DataCollection.ImageFormat"));
|
||||
m_imageQuality = ptree.get<int>("Application.DataCollection.ImageQuality");
|
||||
for (auto &child : ptree.get_child("Application.SupportedDevices")) {
|
||||
if (child.first != "Model") continue;
|
||||
m_supportedDevices.push_back(child.second.get<std::string>(""));
|
||||
}
|
||||
} catch (...) {
|
||||
LOG(error) << "parse " << SettingsFilePath << " failed.";
|
||||
}
|
||||
LOG(info) << "image format: " << m_imageFormat << ", quality: " << m_imageQuality;
|
||||
std::ostringstream oss;
|
||||
oss << "[";
|
||||
for (auto &device : m_supportedDevices) {
|
||||
oss << device << ", ";
|
||||
}
|
||||
oss << "]";
|
||||
LOG(info) << "image format: " << m_imageFormat << ", quality: " << m_imageQuality
|
||||
<< ", supported devices: " << oss.str();
|
||||
}
|
||||
|
||||
ImageFormat Settings::imageFormat() const {
|
||||
@ -48,3 +64,7 @@ ImageFormat Settings::imageFormat() const {
|
||||
int Settings::imageQuality() const {
|
||||
return m_imageQuality;
|
||||
}
|
||||
|
||||
std::list<std::string> Settings::supportedDevices() const {
|
||||
return m_supportedDevices;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ public:
|
||||
void load();
|
||||
ImageFormat imageFormat() const;
|
||||
int imageQuality() const;
|
||||
std::list<std::string> supportedDevices() const;
|
||||
|
||||
protected:
|
||||
Settings();
|
||||
@ -19,6 +20,7 @@ protected:
|
||||
private:
|
||||
ImageFormat m_imageFormat = ImageFormat::Jpeg; // 0: jpg 1: yuv
|
||||
int m_imageQuality = 100;
|
||||
std::list<std::string> m_supportedDevices{"RD_T009", "RD_T013"};
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
||||
|
@ -16,6 +16,13 @@ Item {
|
||||
property color antiClipAreaColor: "blue"
|
||||
property var antiClipAreaPoints: []
|
||||
property bool antiClipAreaEnabled: false
|
||||
property int antiClipSensitivity: 1
|
||||
property alias helmetThreshold: helmetInput.text
|
||||
property alias headThreshold: headInput.text
|
||||
property alias detectFrameSize: detectFrameInput.text
|
||||
property alias flip: flipSwitch.checked
|
||||
property alias videoRotation: rotateComboBox.currentIndex
|
||||
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
@ -238,17 +245,45 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
Grid {
|
||||
GridLayout {
|
||||
id: controlBar
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
columns: 2
|
||||
spacing: 10
|
||||
verticalItemAlignment: Qt.AlignVCenter
|
||||
|
||||
Label { text: qsTr("图像: ") }
|
||||
|
||||
Row {
|
||||
enabled: root.enabled
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("旋转")
|
||||
}
|
||||
Item {width: 10; height:10}
|
||||
ComboBox {
|
||||
id: rotateComboBox
|
||||
model: ["0°","90°","180°","270°"]
|
||||
onCurrentIndexChanged: {
|
||||
App.currentDeviceRotation = rotateComboBox.currentIndex
|
||||
}
|
||||
}
|
||||
Item {width: 70; height:10}
|
||||
Label {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("翻转")
|
||||
}
|
||||
Item {width: 10; height:10}
|
||||
Switch {
|
||||
id: flipSwitch
|
||||
onToggled: App.currentDeviceFlip=flipSwitch.checked
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("开门区域: ")
|
||||
}
|
||||
|
||||
Row {
|
||||
enabled: root.enabled
|
||||
RadioButton {
|
||||
@ -274,9 +309,16 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: 14
|
||||
text: qsTr("防夹区域: ")
|
||||
}
|
||||
|
||||
Label {text: qsTr("防夹区域: ")}
|
||||
Row {
|
||||
Flow{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
enabled: root.enabled
|
||||
RadioButton {
|
||||
text: "关闭"
|
||||
@ -292,9 +334,115 @@ Item {
|
||||
onToggled: {
|
||||
App.currentAntiClipAreaEnabled=true
|
||||
}
|
||||
Layout.rightMargin: 20
|
||||
}
|
||||
|
||||
}
|
||||
RowLayout {
|
||||
Label { text: qsTr("灵敏度: ")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
ComboBox {
|
||||
id: antiClipSensitivityComboBox
|
||||
enabled: root.enabled
|
||||
implicitWidth: 60
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
model: [1,2,3,4,5]
|
||||
currentIndex: root.antiClipSensitivity-1
|
||||
onCurrentIndexChanged: {
|
||||
App.currentAntiClipSensitivity = antiClipSensitivityComboBox.currentIndex+1
|
||||
}
|
||||
Layout.rightMargin: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: 14
|
||||
text: qsTr("阈值设置: ")
|
||||
}
|
||||
Flow {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Label { text: qsTr("安全帽阈值: ")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
TextField {
|
||||
id: helmetInput
|
||||
enabled: root.enabled
|
||||
implicitWidth: 60
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
selectByMouse: true
|
||||
ToolTip.visible: helmetInput.hovered
|
||||
ToolTip.text: "阈值范围 0-300"
|
||||
validator: IntValidator {
|
||||
bottom: 0
|
||||
top: 300
|
||||
}
|
||||
Layout.rightMargin: 20
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label { text: qsTr("头肩阈值: ")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
TextField {
|
||||
id: headInput
|
||||
enabled: root.enabled
|
||||
implicitWidth: 60
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
selectByMouse: true
|
||||
ToolTip.visible: headInput.hovered
|
||||
ToolTip.text: "阈值范围 0-300"
|
||||
validator: IntValidator {
|
||||
bottom: 0
|
||||
top: 300
|
||||
}
|
||||
Layout.rightMargin: 20
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label { text: qsTr("识别帧数: ")
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
TextField {
|
||||
id: detectFrameInput
|
||||
enabled: root.enabled
|
||||
implicitWidth: 60
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
selectByMouse: true
|
||||
ToolTip.visible: detectFrameInput.hovered
|
||||
ToolTip.text: "帧数范围 0-30"
|
||||
validator: IntValidator {
|
||||
bottom: 0
|
||||
top: 30
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
enabled: root.enabled
|
||||
text: "保存"
|
||||
onClicked: {
|
||||
if(App.currentHelmetThreshold !== parseInt(helmetInput.text)){
|
||||
App.currentHelmetThreshold= parseInt(helmetInput.text)
|
||||
window.showSuccess("安全帽阈值设置成功",2500)
|
||||
}
|
||||
if(App.currentHeadThreshold !== parseInt(headInput.text)){
|
||||
App.currentHeadThreshold= parseInt(headInput.text)
|
||||
window.showSuccess("头肩阈值设置成功",2500)
|
||||
}
|
||||
if(App.currentDetectFrameSize !== parseInt(detectFrameInput.text)){
|
||||
App.currentDetectFrameSize= parseInt(detectFrameInput.text)
|
||||
window.showSuccess("识别帧数设置成功",2500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Label {text: qsTr("屏蔽区域: ")}
|
||||
Row {
|
||||
|
48
qml/Main.qml
48
qml/Main.qml
@ -48,7 +48,8 @@ ApplicationWindow {
|
||||
id: emptyHint
|
||||
visible: false
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("未搜索到设备")
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("未搜索到设备\n请尝试关闭Windows防火墙后再重试")
|
||||
}
|
||||
delegate: Rectangle {
|
||||
width: deviceList.width
|
||||
@ -80,7 +81,7 @@ ApplicationWindow {
|
||||
deviceList.currentIndex = index
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if (!softwareVersion.includes("R003")) {
|
||||
if (softwareVersion.includes("T009") && !softwareVersion.includes("R003")) {
|
||||
showMessageDialog(2, "网络设置", "当前设备不支持有线网络设置!")
|
||||
} else if (onlineStatus) {
|
||||
networkPopup.open()
|
||||
@ -118,7 +119,13 @@ ApplicationWindow {
|
||||
shieldedAreaEnabled: App.currentShieldedAreaEnabled
|
||||
shieldedAreaPoints: App.currentShieldedAreaPoints
|
||||
antiClipAreaEnabled: App.currentAntiClipAreaEnabled
|
||||
antiClipSensitivity: App.currentAntiClipSensitivity
|
||||
antiClipAreaPoints: App.currentAntiClipAreaPoints
|
||||
helmetThreshold: App.currentHelmetThreshold
|
||||
headThreshold: App.currentHeadThreshold
|
||||
detectFrameSize: App.currentDetectFrameSize
|
||||
flip: App.currentDeviceFlip
|
||||
videoRotation: App.currentDeviceRotation
|
||||
}
|
||||
|
||||
NetworkSettingPopup {
|
||||
@ -161,6 +168,7 @@ ApplicationWindow {
|
||||
}
|
||||
Item {}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "升级"
|
||||
onClicked: {
|
||||
if (deviceList.currentIndex < 0) {
|
||||
@ -173,17 +181,40 @@ ApplicationWindow {
|
||||
otaPopup.open()
|
||||
}
|
||||
}
|
||||
Item {}
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 5
|
||||
text: "重置"
|
||||
onClicked: {
|
||||
if (deviceList.currentIndex < 0) {
|
||||
showMessageDialog(2, "恢复出厂设置", "请先选择设备")
|
||||
return
|
||||
} else {
|
||||
showMessageDialog(2, "恢复出厂设置", "设备将会重启,重启后配置恢复默认", () => {
|
||||
App.resetDevice()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
spacing: (parent.width - (2 * 100)) / 3
|
||||
}
|
||||
|
||||
function showMessageDialog(type, title, message) {
|
||||
MessageBar {
|
||||
id: messageBar
|
||||
root: window.contentItem
|
||||
}
|
||||
function showSuccess(text, duration) {
|
||||
return messageBar.showSuccess(text, duration)
|
||||
}
|
||||
|
||||
function showMessageDialog(type, title, message, callback) {
|
||||
let component = Qt.createComponent("MessageDialog.qml")
|
||||
if (component.status === Component.Ready) {
|
||||
let dialog = component.createObject(window, {
|
||||
"type": type,
|
||||
"titleText": title,
|
||||
"text": message
|
||||
"text": message,
|
||||
"callback": callback
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
@ -197,11 +228,14 @@ ApplicationWindow {
|
||||
dialog = Qt.createQmlObject("import QtQuick.Dialogs; FileDialog {}", window, "myDynamicSnippet")
|
||||
}
|
||||
if (dialog) {
|
||||
dialog.nameFilters = nameFilters;
|
||||
dialog.nameFilters = nameFilters
|
||||
dialog.visible = true
|
||||
dialog.accepted.connect(function () {
|
||||
let fileUrl = isQt5 ? dialog.fileUrl.toString() : dialog.selectedFile.toString()
|
||||
let localFilePath = fileUrl.startsWith("file:///") ? fileUrl.substring(8) : fileUrl
|
||||
let localFilePath = fileUrl
|
||||
if (fileUrl.startsWith("file:///")) {
|
||||
localFilePath = fileUrl.substring(Qt.platform.os === "windows" ? 8 : 7)
|
||||
}
|
||||
onSelected(localFilePath)
|
||||
dialog.destroy()
|
||||
})
|
||||
|
101
qml/MessageBar.qml
Normal file
101
qml/MessageBar.qml
Normal file
@ -0,0 +1,101 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
Object {
|
||||
id: control
|
||||
property var root
|
||||
property var screenLayout: null
|
||||
property int layoutY: 75
|
||||
|
||||
function showSuccess(text,duration=1000){
|
||||
return create("success",text,duration)
|
||||
}
|
||||
|
||||
function create(type,text,duration){
|
||||
if(screenLayout){
|
||||
let last = screenLayout.getLastloader()
|
||||
if(last.type === type && last.text === text){
|
||||
last.duration = duration
|
||||
if (duration > 0) last.restart()
|
||||
return last
|
||||
}
|
||||
} else {
|
||||
initScreenLayout()
|
||||
}
|
||||
return contentComponent.createObject(screenLayout,{type:type,text:text,duration:duration,})
|
||||
}
|
||||
|
||||
function initScreenLayout() {
|
||||
if(control.screenLayout == null) {
|
||||
control.screenLayout = screenLayoutComponent.createObject(root)
|
||||
screenLayout.y = control.layoutY
|
||||
screenLayout.z = 100000
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id:contentComponent
|
||||
Rectangle {
|
||||
id: content
|
||||
property int duration: 1500
|
||||
property string type
|
||||
property alias text: message.text
|
||||
color: "#EBF8ED"
|
||||
radius: 3.2
|
||||
border.width: 1
|
||||
border.color: Qt.darker(content.color)
|
||||
layer.enabled: true
|
||||
x:(parent.width - width) / 2
|
||||
width: 200
|
||||
height: 32
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
Image {
|
||||
width: 32
|
||||
height: 32
|
||||
fillMode: Image.Pad
|
||||
source: "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
Label {
|
||||
id: message
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id:delayTimer
|
||||
interval: duration
|
||||
running: duration > 0
|
||||
repeat: duration > 0
|
||||
onTriggered: content.close()
|
||||
}
|
||||
function close(){
|
||||
content.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id:screenLayoutComponent
|
||||
Column{
|
||||
parent: Overlay.overlay
|
||||
z:999
|
||||
spacing: 5
|
||||
width: root.width
|
||||
move: Transition {
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
easing.type: Easing.InOutQuad
|
||||
duration: 167
|
||||
}
|
||||
}
|
||||
onChildrenChanged: if(children.length === 0) destroy()
|
||||
function getLastloader(){
|
||||
if(children.length > 0){
|
||||
return children[children.length - 1]
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ Dialog {
|
||||
property alias text: textLabel.text
|
||||
property alias textFontSize: textLabel.font.pixelSize
|
||||
property int type: MessageDialog.Type.Successful
|
||||
property var callback
|
||||
closePolicy: Popup.CloseOnEscap | Popup.NoAutoClose
|
||||
background: Rectangle {
|
||||
radius: 8
|
||||
@ -62,14 +63,44 @@ Dialog {
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton
|
||||
Row {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 6
|
||||
Layout.preferredWidth: 72
|
||||
Layout.preferredHeight: 40
|
||||
spacing: 10
|
||||
Button {
|
||||
id: okButton
|
||||
width: 72
|
||||
height: 40
|
||||
font.family: control.font.family
|
||||
text: "关闭"
|
||||
text: "好的"
|
||||
font.pixelSize: 14
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
font: parent.font
|
||||
color: parent.down ? "#FFFFFF" : "#53627C"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
border.color: "#E1E4E8"
|
||||
border.width: 1
|
||||
color: parent.down ? "#F25959" : "#FFFFFF"
|
||||
radius: 2
|
||||
}
|
||||
onClicked: {
|
||||
if(callback !== undefined){
|
||||
callback()
|
||||
}
|
||||
control.accept()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
visible: callback !== undefined
|
||||
width: 72
|
||||
height: 40
|
||||
font.family: control.font.family
|
||||
text: "取消"
|
||||
font.pixelSize: 14
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
@ -78,7 +109,6 @@ Dialog {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
border.color: "#E1E4E8"
|
||||
border.width: 1
|
||||
@ -88,6 +118,7 @@ Dialog {
|
||||
onClicked: control.reject()
|
||||
}
|
||||
}
|
||||
}
|
||||
onTypeChanged: {
|
||||
if (type === MessageDialog.Type.Successful || type === MessageDialog.Type.Ok) {
|
||||
image.source = "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
|
||||
|
5
qml/Object.qml
Normal file
5
qml/Object.qml
Normal file
@ -0,0 +1,5 @@
|
||||
import QtQml 2.15
|
||||
|
||||
QtObject {
|
||||
default property list<QtObject> children
|
||||
}
|
@ -41,6 +41,7 @@ Popup {
|
||||
Layout.fillWidth: true
|
||||
readOnly: true
|
||||
placeholderText: "请选择升级bin文件"
|
||||
selectByMouse: true
|
||||
}
|
||||
Button {
|
||||
enabled: otaFinished
|
||||
|
129
resources/build.ps1
Normal file
129
resources/build.ps1
Normal file
@ -0,0 +1,129 @@
|
||||
param($type)
|
||||
# 该脚本设置为 UTF8-bom 编码即可支持中文
|
||||
|
||||
$MsvcScript = 'D:\Program Files\Microsoft Visual Studio\2022\\Community\Common7\Tools\Launch-VsDevShell.ps1'
|
||||
if (!(Test-Path $MsvcScript)) { $MsvcScript = 'D:\Program Files\Microsoft Visual Studio\2022\\Professional\Common7\Tools\Launch-VsDevShell.ps1' }
|
||||
. $MsvcScript -SkipAutomaticLocation -Arch amd64
|
||||
|
||||
$qtHome = "D:\Qt\5.15.2\msvc2019_64"
|
||||
$openSSLRoot = "D:\Qt\Tools\OpenSSLv3\Win_x64"
|
||||
|
||||
$librariesPath = "E:\Projects\Libraries"
|
||||
if (!(Test-Path $librariesPath)) { $librariesPath = "D:\Projects\Libraries" }
|
||||
$boostRoot = "$librariesPath\boost_1_83_0_msvc2022_64bit"
|
||||
|
||||
# 6.1.1 版本支持 windows7
|
||||
$ffmpegRoot = "$librariesPath\ffmpeg-6.1.1-full_build-shared"
|
||||
|
||||
$projectPath = Get-Location
|
||||
$buildPath = Join-Path -Path $projectPath -ChildPath "build"
|
||||
|
||||
$fileContent = (Get-Content -Path "CMakeLists.txt") -join " "
|
||||
if ($fileContent -match 'project\([^\)]+VERSION\s+([0-9]+\.[0-9]+)') {
|
||||
$version = $Matches[1]
|
||||
} else {
|
||||
Write-Output "未找到版本号"
|
||||
}
|
||||
|
||||
$deployPath = Join-Path -Path $buildPath -ChildPath "视觉防夹设备上位机工具v$version"
|
||||
$zipFilePath = Join-Path -Path $buildPath -ChildPath "视觉防夹设备上位机工具v$version.zip"
|
||||
$changelogPath = Join-Path -Path $buildPath -ChildPath "CHANGELOG.txt"
|
||||
|
||||
function Build() {
|
||||
if (!(Test-Path $buildPath\CMakeCache.txt)) {
|
||||
cmake.exe -G Ninja -S . -B build `
|
||||
-DCMAKE_BUILD_TYPE=Release `
|
||||
-DCMAKE_PREFIX_PATH=$qtHome `
|
||||
-DQT_DIR="$qtHome\lib\cmake\Qt5" `
|
||||
-DQt5_DIR="$qtHome\lib\cmake\Qt5" `
|
||||
-DLibraries_ROOT="$librariesPath"
|
||||
}
|
||||
|
||||
cmake.exe --build $buildPath --target all
|
||||
}
|
||||
|
||||
function Deploy() {
|
||||
if (Test-Path $deployPath) {
|
||||
Remove-Item $deployPath -Recurse -Force
|
||||
}
|
||||
New-Item $deployPath -ItemType Directory
|
||||
Copy-Item $buildPath\AntiClipSettings.exe $deployPath\视觉防夹设备上位机工具v$version.exe
|
||||
& $qtHome\bin\windeployqt.exe $deployPath\视觉防夹设备上位机工具v$version.exe --qmldir=$qtHome\qml
|
||||
# Remove-Item -Path $deployPath\d3dcompiler_47.dll -Force # 删了这个会导致Windows 7 无法正常显示
|
||||
Remove-Item -Path $deployPath\Qt5Multimedia.dll -Force
|
||||
Remove-Item -Path $deployPath\Qt5MultimediaQuick.dll -Force
|
||||
Remove-Item -Path $deployPath\Qt5RemoteObjects.dll -Force
|
||||
Remove-Item -Path $deployPath\Qt5Test.dll -Force
|
||||
Remove-Item -Path $deployPath\Qt5QuickTest.dll -Force
|
||||
Remove-Item -Path $deployPath\Qt5WinExtras.dll -Force
|
||||
Remove-Item -Path $deployPath\translations -Recurse -Force # 暂时不需要翻译文件
|
||||
Remove-Item -Path $deployPath\qmltooling -Recurse -Force
|
||||
Remove-Item -Path $deployPath\QtTest -Recurse -Force
|
||||
Remove-Item -Path $deployPath\QtGraphicalEffects -Recurse -Force
|
||||
|
||||
|
||||
# $modules = "QmlCore"
|
||||
# foreach ($module in $modules) {
|
||||
# Copy-Item -Path $qtHome\bin\Qt6$module.dll -Destination $deployPath
|
||||
# }
|
||||
|
||||
# if (-Not (Test-Path -Path $deployPath\qml\QtCore)) {
|
||||
# New-Item $deployPath\qml\QtCore -ItemType Directory
|
||||
# $plugins = "qtqmlcoreplugin.dll", "qmldir", "plugins.qmltypes"
|
||||
# foreach ($plugin in $plugins) {
|
||||
# Copy-Item -Path $QtHome\qml\QtCore\$plugin -Destination $deployPath\qml\QtCore
|
||||
# }
|
||||
# }
|
||||
|
||||
Copy-Item $openSSLRoot\bin\libssl-3-x64.dll $deployPath
|
||||
Copy-Item $openSSLRoot\bin\libcrypto-3-x64.dll $deployPath
|
||||
|
||||
$boosts = "atomic", "thread", "filesystem", "log", "json"
|
||||
foreach ($boost in $boosts) {
|
||||
Copy-Item -Path $boostRoot\lib\boost_$boost-vc143-mt-x64-1_83.dll -Destination $deployPath
|
||||
}
|
||||
|
||||
# 暂时不需要 avfilter-9、avformat-60、postproc-57、avdevice-60
|
||||
$ffmpegs = "avcodec-60", "avutil-58", "swresample-4", "swscale-7"
|
||||
foreach ($ffmpeg in $ffmpegs) {
|
||||
Copy-Item -Path $ffmpegRoot\bin\$ffmpeg.dll -Destination $deployPath
|
||||
}
|
||||
|
||||
Compress-Archive -Path $deployPath -DestinationPath $zipFilePath -Force
|
||||
}
|
||||
|
||||
function Clean() {
|
||||
if (Test-Path $buildPath) {
|
||||
Remove-Item $buildPath -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
function Changelog() {
|
||||
$commit_message = git log -1 --pretty=format:"%B"
|
||||
Write-Output "Latest commit message:"
|
||||
Write-Output $commit_message
|
||||
$commit_message | Out-File -FilePath $changelogPath -Encoding utf8
|
||||
Write-Output "Commit message has been written to $changelogPath"
|
||||
}
|
||||
|
||||
|
||||
switch ($type) {
|
||||
"build" {
|
||||
Build
|
||||
}
|
||||
"deploy" {
|
||||
Deploy
|
||||
}
|
||||
"clean" {
|
||||
Clean
|
||||
}
|
||||
"installer" {
|
||||
Installer
|
||||
}
|
||||
"changelog" {
|
||||
Changelog
|
||||
}
|
||||
"update" {
|
||||
UpdateServer
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user