初步实现网络修改。

This commit is contained in:
luocai 2024-08-16 16:24:15 +08:00
parent 0f24d95eee
commit f59645700a
11 changed files with 703 additions and 108 deletions

View File

@ -1,7 +1,6 @@
#include "Application.h"
#include "BoostLog.h"
#include "Configuration.h"
#include "DeviceConnection.h"
#include "H264Palyer.h"
#include "VideoFrameProvider.h"
#include <QFont>
@ -10,7 +9,7 @@
Application::Application(int &argc, char **argv)
: m_app(std::make_shared<QGuiApplication>(argc, argv)), m_videoFrameProvider(new VideoFrameProvider()),
m_player(std::make_shared<H264Palyer>()) {
m_player(std::make_shared<H264Palyer>()), m_devices(new DeviceListModel(this)) {
QFont font;
font.setPointSize(16);
m_app->setFont(font);
@ -19,20 +18,30 @@ Application::Application(int &argc, char **argv)
m_player->open();
}
bool Application::currentOpenDoorAreaEnabled() const {
return m_currentOpenDoorAreaEnabled;
DeviceConnection::AreaWay Application::currentOpenDoorAreaWay() const {
return m_currentOpenDoorAreaWay;
}
void Application::setCurrentOpenDoorAreaEnabled(bool enabled) {
if (m_currentOpenDoorAreaEnabled != enabled) {
m_currentOpenDoorAreaEnabled = enabled;
emit currentOpenDoorAreaEnabledChanged();
void Application::setCurrentOpenDoorAreaWay(DeviceConnection::AreaWay way) {
if (m_currentOpenDoorAreaWay == way) return;
m_currentOpenDoorAreaWay = way;
if (m_currentOpenDoorAreaWay == DeviceConnection::Quadrangle) {
if ((m_currentOpenDoorAreaPoints.size() < 4) || (m_currentOpenDoorAreaPoints == FullArea)) {
m_currentOpenDoorAreaPoints.clear();
m_currentOpenDoorAreaPoints << QPointF(68, 6) << QPointF(570, 6) << QPointF(570, 354) << QPointF(68, 354);
emit currentOpenDoorAreaPointsChanged();
}
} else if (m_currentOpenDoorAreaWay == DeviceConnection::FullArea) {
m_currentOpenDoorAreaPoints.clear();
m_currentOpenDoorAreaPoints = FullArea;
emit currentOpenDoorAreaPointsChanged();
}
emit currentOpenDoorAreaWayChanged();
if (m_device != nullptr) {
m_device->updateOpenDoorAreaPoints(m_currentOpenDoorAreaEnabled, m_currentOpenDoorAreaPoints);
m_device->updateOpenDoorAreaPoints(m_currentOpenDoorAreaWay, m_currentOpenDoorAreaPoints);
}
}
LOG(info) << "setCurrentOpenDoorAreaEnabled " << enabled;
}
QList<QPointF> Application::currentOpenDoorAreaPoints() const {
return m_currentOpenDoorAreaPoints;
@ -45,6 +54,10 @@ void Application::setCurrentOpenDoorAreaPoints(const QList<QPointF> &points) {
}
}
NetworkInfomation Application::currentNetworkInfomation() const {
return m_currentNetworkInfomation;
}
bool Application::currentShieldedAreaEnabled() const {
return m_currentShieldedAreaEnabled;
}
@ -53,6 +66,13 @@ void Application::setCurrentShieldedAreaEnabled(bool enabled) {
if (m_currentShieldedAreaEnabled != enabled) {
m_currentShieldedAreaEnabled = enabled;
emit currentShieldedAreaEnabledChanged();
if (m_currentShieldedAreaPoints.size() < 4) {
m_currentShieldedAreaPoints.clear();
m_currentShieldedAreaPoints << QPointF(6, 6) << QPointF(40, 60) << QPointF(590, 6) << QPointF(630, 60);
emit currentShieldedAreaPointsChanged();
}
if (m_device != nullptr) {
m_device->updateShieldedAreaPoints(m_currentShieldedAreaEnabled, m_currentShieldedAreaPoints);
}
@ -96,8 +116,9 @@ void Application::setCurrentAntiClipAreaPoints(const QList<QPointF> &points) {
}
void Application::updateOpenDoorAreaPoints(const QList<QPointF> &points) {
LOG(info) << "updateOpenDoorAreaPoints: " << points.size();
m_device->updateOpenDoorAreaPoints(m_currentOpenDoorAreaEnabled, points);
if (m_device != nullptr) {
m_device->updateOpenDoorAreaPoints(m_currentOpenDoorAreaWay, points);
}
}
void Application::updateAntiClipAreaPoints(const QList<QPointF> &points) {
@ -108,10 +129,39 @@ void Application::updateShieldedAreaPoints(const QList<QPointF> &points) {
m_device->updateShieldedAreaPoints(m_currentShieldedAreaEnabled, points);
}
void Application::onDeviceOpenDoorArea(bool enabled, const QList<QPointF> &points) {
setCurrentOpenDoorAreaEnabled(enabled);
void Application::updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask,
const QString &gateway) {
LOG(info) << dhcp;
LOG(info) << ip.toStdString();
if (m_device != nullptr) {
m_device->updateNetworkInfomation(dhcp, ip, netmask, gateway);
}
}
void Application::connectToDevice(const QString &address) {
if (m_device != nullptr) {
m_device->deleteLater();
}
m_device = new DeviceConnection();
connect(m_device, &DeviceConnection::currentOpenDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
connect(m_device, &DeviceConnection::currentShieldedAreaChanged, this, &Application::onDeviceShieldedArea);
connect(m_device, &DeviceConnection::currentAntiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
connect(m_device, &DeviceConnection::currentNetworkInfomationChanged, this,
&Application::onDeviceNetworkInfomation);
m_device->connect(address);
m_device->setH264FrameCallback([this](const char *data, uint32_t size) {
auto image = m_player->decode((const uint8_t *)data, size);
if (image) {
m_videoFrameProvider->setImage(*image);
emit newVideoFrame();
}
});
}
void Application::onDeviceOpenDoorArea(DeviceConnection::AreaWay way, const QList<QPointF> &points) {
setCurrentOpenDoorAreaWay(way);
setCurrentOpenDoorAreaPoints(points);
LOG(info) << "onDeviceOpenDoorAreaPoints: " << points.size();
}
void Application::onDeviceShieldedArea(bool enabled, const QList<QPointF> &points) {
@ -125,6 +175,11 @@ void Application::onDeviceAntiClipArea(bool enabled, const QList<QPointF> &point
setCurrentAntiClipAreaPoints(points);
}
void Application::onDeviceNetworkInfomation(const NetworkInfomation &info) {
m_currentNetworkInfomation = info;
emit currentNetworkInfomationChanged();
}
int Application::exec() {
QQmlApplicationEngine engine;
engine.addImageProvider("videoframe", m_videoFrameProvider);
@ -135,28 +190,6 @@ int Application::exec() {
return m_app->exec();
}
void Application::open() {
LOG(info) << "Application::start";
m_device = new DeviceConnection();
connect(m_device, &DeviceConnection::currentOpenDoorAreaChanged, this, &Application::onDeviceOpenDoorArea);
connect(m_device, &DeviceConnection::currentShieldedAreaChanged, this, &Application::onDeviceShieldedArea);
connect(m_device, &DeviceConnection::currentAntiClipAreaChanged, this, &Application::onDeviceAntiClipArea);
m_device->connect();
m_device->setH264FrameCallback([this](const char *data, uint32_t size) {
auto image = m_player->decode((const uint8_t *)data, size);
if (image) {
m_videoFrameProvider->setImage(*image);
emit newVideoFrame();
}
});
}
void Application::start() {
if (m_device != nullptr) {
m_device->start();
}
}
Application *Application::create(QQmlEngine *qmlEngine, QJSEngine *jsEngine) {
Application *ret = nullptr;
auto app = Amass::Singleton<Application>::instance();

View File

@ -1,13 +1,15 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include "DataStructure.h"
#include "DeviceConnection.h"
#include "DeviceListModel.h"
#include "Singleton.h"
#include <QObject>
#include <QPoint>
#include <QQmlEngine>
class QGuiApplication;
class DeviceConnection;
class VideoFrameProvider;
class H264Palyer;
@ -16,8 +18,10 @@ class Application : public QObject {
QML_NAMED_ELEMENT(App)
QML_SINGLETON
Q_PROPERTY(int DeviceWidth MEMBER DeviceWidth CONSTANT FINAL)
Q_PROPERTY(bool currentOpenDoorAreaEnabled READ currentOpenDoorAreaEnabled WRITE setCurrentOpenDoorAreaEnabled
NOTIFY currentOpenDoorAreaEnabledChanged)
Q_PROPERTY(int DeviceHeight MEMBER DeviceHeight CONSTANT FINAL)
Q_PROPERTY(DeviceListModel *devices MEMBER m_devices CONSTANT FINAL);
Q_PROPERTY(DeviceConnection::AreaWay currentOpenDoorAreaWay READ currentOpenDoorAreaWay WRITE
setCurrentOpenDoorAreaWay NOTIFY currentOpenDoorAreaWayChanged)
Q_PROPERTY(QList<QPointF> currentOpenDoorAreaPoints READ currentOpenDoorAreaPoints WRITE
setCurrentOpenDoorAreaPoints NOTIFY currentOpenDoorAreaPointsChanged)
Q_PROPERTY(bool currentShieldedAreaEnabled READ currentShieldedAreaEnabled WRITE setCurrentShieldedAreaEnabled
@ -28,15 +32,22 @@ class Application : public QObject {
NOTIFY currentAntiClipAreaEnabledChanged)
Q_PROPERTY(QList<QPointF> currentAntiClipAreaPoints READ currentAntiClipAreaPoints WRITE
setCurrentAntiClipAreaPoints NOTIFY currentAntiClipAreaPointsChanged)
Q_PROPERTY(
NetworkInfomation currentNetworkInfomation READ currentNetworkInfomation NOTIFY currentNetworkInfomationChanged)
friend class Amass::Singleton<Application>;
public:
constexpr static int DeviceWidth = 640;
bool currentOpenDoorAreaEnabled() const;
void setCurrentOpenDoorAreaEnabled(bool enabled);
constexpr static int DeviceHeight = 360;
inline static const QList<QPointF> FullArea = {QPointF(0, 0), QPointF(DeviceWidth, 0),
QPointF(DeviceWidth, DeviceHeight), QPointF(0, DeviceHeight)};
DeviceConnection::AreaWay currentOpenDoorAreaWay() const;
void setCurrentOpenDoorAreaWay(DeviceConnection::AreaWay way);
QList<QPointF> currentOpenDoorAreaPoints() const;
void setCurrentOpenDoorAreaPoints(const QList<QPointF> &points);
NetworkInfomation currentNetworkInfomation() const;
bool currentShieldedAreaEnabled() const;
void setCurrentShieldedAreaEnabled(bool enabled);
QList<QPointF> currentShieldedAreaPoints() const;
@ -50,10 +61,11 @@ public:
Q_INVOKABLE void updateOpenDoorAreaPoints(const QList<QPointF> &points);
Q_INVOKABLE void updateAntiClipAreaPoints(const QList<QPointF> &points);
Q_INVOKABLE void updateShieldedAreaPoints(const QList<QPointF> &points);
Q_INVOKABLE void updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask,
const QString &gateway);
Q_INVOKABLE void connectToDevice(const QString &address);
int exec();
Q_INVOKABLE void open();
Q_INVOKABLE void start();
static Application *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
signals:
@ -61,28 +73,32 @@ signals:
void currentOpenDoorAreaPointsChanged();
void currentShieldedAreaPointsChanged();
void currentAntiClipAreaPointsChanged();
void currentOpenDoorAreaEnabledChanged();
void currentOpenDoorAreaWayChanged();
void currentShieldedAreaEnabledChanged();
void currentAntiClipAreaEnabledChanged();
void currentNetworkInfomationChanged();
protected:
Application(int &argc, char **argv);
void onDeviceOpenDoorArea(bool enabled, const QList<QPointF> &points);
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 onDeviceNetworkInfomation(const NetworkInfomation &info);
private:
std::shared_ptr<QGuiApplication> m_app;
VideoFrameProvider *m_videoFrameProvider = nullptr;
std::shared_ptr<H264Palyer> m_player;
DeviceConnection *m_device = nullptr;
DeviceListModel *m_devices = nullptr;
bool m_currentOpenDoorAreaEnabled = false;
DeviceConnection::AreaWay m_currentOpenDoorAreaWay = DeviceConnection::Diabled;
QList<QPointF> m_currentOpenDoorAreaPoints;
bool m_currentShieldedAreaEnabled = false;
QList<QPointF> m_currentShieldedAreaPoints;
bool m_currentAntiClipAreaEnabled = false;
QList<QPointF> m_currentAntiClipAreaPoints;
NetworkInfomation m_currentNetworkInfomation;
};
#endif // APPLICATION_H

View File

@ -9,8 +9,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(Projects_ROOT E:/Projects)
set(Libraries_ROOT ${Projects_ROOT}/Libraries)
set(BOOST_ROOT ${Libraries_ROOT}/boost_1_85_0_msvc2022_64bit)
set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_85)
set(BOOST_ROOT ${Libraries_ROOT}/boost_1_86_0_msvc2022_64bit)
set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_86)
option(Boost_USE_STATIC_LIBS OFF)
add_compile_definitions(
BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WIN10
@ -21,7 +21,7 @@ set(FFmpeg_INCLUDE_DIR ${FFmpeg_ROOT}/include)
set(FFmpeg_LIB_DIR ${FFmpeg_ROOT}/lib)
find_package(Boost REQUIRED COMPONENTS json)
find_package(Qt6 REQUIRED COMPONENTS Qml Quick)
find_package(Qt6 REQUIRED COMPONENTS Qml Quick Network)
qt_standard_project_setup(REQUIRES 6.5)
@ -36,7 +36,9 @@ qt_add_executable(AntiClipSettings
AntiClipSettings.rc
main.cpp
Application.h Application.cpp
DataStructure.h
DeviceConnection.h DeviceConnection.cpp
DeviceListModel.h DeviceListModel.cpp
H264Palyer.h H264Palyer.cpp
VideoFrameProvider.h VideoFrameProvider.cpp
)
@ -46,6 +48,7 @@ qt_add_qml_module(AntiClipSettings
QML_FILES
Main.qml
DeviceView.qml
NetworkSettingPopup.qml
)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
@ -73,6 +76,7 @@ target_link_directories(AntiClipSettings
target_link_libraries(AntiClipSettings
PRIVATE Qt6::Qml
PRIVATE Qt6::Quick
PRIVATE Qt6::Network
PRIVATE Boost::json
PRIVATE avcodec
PRIVATE swscale

22
DataStructure.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __DATASTRUCTURE_H__
#define __DATASTRUCTURE_H__
#include <QObject>
#include <QQmlEngine>
struct NetworkInfomation {
Q_GADGET
QML_NAMED_ELEMENT(networkInfomation)
Q_PROPERTY(bool dhcp MEMBER dhcp)
Q_PROPERTY(QString ip MEMBER ip)
Q_PROPERTY(QString netmask MEMBER netmask)
Q_PROPERTY(QString gateway MEMBER gateway)
public:
bool dhcp;
QString ip = "127.0..1";
QString netmask;
QString gateway;
};
Q_DECLARE_METATYPE(NetworkInfomation)
#endif // __DATASTRUCTURE_H__

View File

@ -1,7 +1,6 @@
#include "DeviceConnection.h"
#include "BoostLog.h"
#include <QPointF>
#include <QTcpSocket>
#include <WinSock2.h>
#include <boost/json/object.hpp>
#include <boost/json/parse.hpp>
@ -10,7 +9,7 @@
DeviceConnection::DeviceConnection(QObject *parent) : QObject{parent} {
}
void DeviceConnection::connect() {
void DeviceConnection::connect(const QString &address) {
m_commandSocket = new QTcpSocket(this);
m_h264Socket = new QTcpSocket(this);
@ -20,8 +19,8 @@ void DeviceConnection::connect() {
QObject::connect(m_h264Socket, &QTcpSocket::readyRead, this, &DeviceConnection::onH264ReadyRead);
QObject::connect(m_commandSocket, &QTcpSocket::readyRead, this, &DeviceConnection::onCommandReadyRead);
m_commandSocket->connectToHost("192.168.10.2", 8000);
m_h264Socket->connectToHost("192.168.10.2", 8000);
m_commandSocket->connectToHost(address, 8000);
m_h264Socket->connectToHost(address, 8000);
}
void DeviceConnection::start() {
@ -53,13 +52,19 @@ void DeviceConnection::requestOpenDoorArea() {
m_requests.push(task);
}
void DeviceConnection::updateOpenDoorAreaPoints(bool enabled, const QList<QPointF> &points) {
auto task = [this, enabled, points]() {
void DeviceConnection::updateOpenDoorAreaPoints(AreaWay way, const QList<QPointF> &points) {
auto task = [this, way, points]() {
boost::json::object request;
request["func"] = "a03opendoor1_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["value"] = enabled ? "1" : "0";
const char *value = "0";
if (way == FullArea) {
value = "1";
} else if (way == Quadrangle) {
value = "2";
}
data["value"] = value;
boost::json::array pointArray;
for (auto &p : points) {
boost::json::object point;
@ -186,6 +191,46 @@ void DeviceConnection::requestResolution(Resolution resolution) {
m_requests.push(task);
}
void DeviceConnection::requestNetworkInfomation() {
auto task = [this]() {
boost::json::object request;
request["func"] = "netconfig_getdata";
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());
LOG(info) << "requestNetworkInfomation";
};
if (m_requests.empty()) {
task();
}
m_requests.push(task);
}
void DeviceConnection::updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask,
const QString &gateway) {
auto task = [this, dhcp, ip, netmask, gateway]() {
boost::json::object request;
request["func"] = "netconfig_setdata";
request["deviceid"] = "0";
boost::json::object data;
data["type"] = dhcp ? "dhcp" : "static";
data["ip"] = ip.toStdString();
data["netmask"] = netmask.toStdString();
data["gateway"] = gateway.toStdString();
request["data"] = std::move(data);
auto text = boost::json::serialize(request);
m_commandSocket->write(text.data(), text.size());
LOG(info) << "requestUpdateNetworkInfomation";
};
if (m_requests.empty()) {
task();
}
m_requests.push(task);
}
void DeviceConnection::handleCommand(const std::string_view &replyText) {
boost::system::error_code error;
auto replyValue = boost::json::parse(replyText, error);
@ -207,7 +252,13 @@ void DeviceConnection::handleCommand(const std::string_view &replyText) {
point.setY(obj.at("y").as_double());
points.push_back(point);
}
emit currentOpenDoorAreaChanged(value == "1", points);
AreaWay way = Diabled;
if (value == "1") {
way = FullArea;
} else if (value == "2") {
way = Quadrangle;
}
emit currentOpenDoorAreaChanged(way, points);
} else if (function == "a03opendoor4_getdata") {
auto &data = reply.at("data").as_object();
auto &value = data.at("value").as_string();
@ -234,6 +285,14 @@ void DeviceConnection::handleCommand(const std::string_view &replyText) {
points.push_back(point);
}
emit currentAntiClipAreaChanged(value == "1", points);
} else if (function == "netconfig_getdata") {
auto &data = reply.at("data").as_object();
NetworkInfomation info;
info.dhcp = data.at("type").as_string() == "dhcp";
info.ip = data.at("ip").as_string().c_str();
info.gateway = data.at("gateway").as_string().c_str();
info.netmask = data.at("netmask").as_string().c_str();
emit currentNetworkInfomationChanged(info);
}
}
@ -244,6 +303,9 @@ void DeviceConnection::onConnected() {
requestOpenDoorArea();
requestShieldedArea();
requestAntiClipArea();
requestNetworkInfomation();
} else if (socket == m_h264Socket) {
start();
}
}

View File

@ -1,16 +1,19 @@
#ifndef DEVICECONNECTION_H
#define DEVICECONNECTION_H
#include "DataStructure.h"
#include <QObject>
#include <QQmlEngine>
#include <QTcpSocket>
#include <queue>
#include <string_view>
class QTcpSocket;
class NetworkInfomation;
class DeviceConnection : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Only used in C++...")
QML_UNCREATABLE("Only created in C++...")
public:
enum Resolution {
@ -19,33 +22,37 @@ public:
};
enum AreaWay {
Diabled = 0,
FullScreen,
FullArea,
Quadrangle, // 四边形
};
Q_ENUM(AreaWay)
using H264FrameCallback = std::function<void(const char *data, uint32_t size)>;
explicit DeviceConnection(QObject *parent = nullptr);
void setH264FrameCallback(H264FrameCallback &&callback);
void connect();
void connect(const QString &address);
void start();
void requestOpenDoorArea();
void updateOpenDoorAreaPoints(bool enabled, const QList<QPointF> &points);
void 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 requestResolution(Resolution resolution);
void requestNetworkInfomation();
void updateNetworkInfomation(bool dhcp, const QString &ip, const QString &netmask, const QString &gateway);
signals:
void currentOpenDoorAreaChanged(bool enabled, const QList<QPointF> &points);
void currentOpenDoorAreaChanged(AreaWay way, const QList<QPointF> &points);
void currentShieldedAreaChanged(bool enabled, const QList<QPointF> &points);
void currentAntiClipAreaChanged(bool enabled, const QList<QPointF> &points);
void currentNetworkInfomationChanged(const NetworkInfomation &info);
protected:
void onConnected();
void onH264ReadyRead();
void onCommandReadyRead();
void handleCommand(const std::string_view &replyText);
void onErrorOccurred(QAbstractSocket::SocketError socketError);
private:
QTcpSocket *m_commandSocket = nullptr;

161
DeviceListModel.cpp Normal file
View File

@ -0,0 +1,161 @@
#include "DeviceListModel.h"
#include "BoostLog.h"
#include <QNetworkDatagram>
#include <QNetworkInterface>
#include <QTimer>
#include <QUdpSocket>
#include <boost/json/parse.hpp>
DeviceListModel::DeviceListModel(QObject *parent) : QAbstractListModel{parent} {
m_broadcastSocket = new QUdpSocket(this);
}
int DeviceListModel::rowCount(const QModelIndex &parent) const {
return m_devices.size();
}
QVariant DeviceListModel::data(const QModelIndex &index, int role) const {
QVariant ret;
auto row = index.row();
if (role == DeviceIdRole) {
ret = m_devices.at(row).deviceId;
} else if (role == FirmwareVersionRole) {
ret = m_devices.at(row).firmwareVersion;
} else if (role == SoftwareVersionRole) {
ret = m_devices.at(row).softwareVersion;
} else if (role == IpRole) {
ret = m_devices.at(row).ip;
}
return ret;
}
QHash<int, QByteArray> DeviceListModel::roleNames() const {
QHash<int, QByteArray> roleNames;
roleNames.insert(DeviceIdRole, "deviceId");
roleNames.insert(FirmwareVersionRole, "firmwareVersion");
roleNames.insert(SoftwareVersionRole, "softwareVersion");
roleNames.insert(IpRole, "ip");
return roleNames;
}
QVariantMap DeviceListModel::get(int index) const {
QVariantMap map;
if (index >= 0 && index < m_devices.size()) {
map["firmwareVersion"] = m_devices[index].firmwareVersion;
map["softwareVersion"] = m_devices[index].softwareVersion;
map["deviceId"] = m_devices[index].deviceId;
map["ip"] = m_devices[index].ip;
}
return map;
}
void DeviceListModel::startSearchDevice() {
if (m_timerId >= 0) {
LOG(error) << "app is searching device.";
return;
}
beginResetModel();
m_devices.clear();
endResetModel();
auto interfaces = QNetworkInterface::allInterfaces();
for (auto &interface : interfaces) {
if (interface.flags() & QNetworkInterface::IsLoopBack) continue;
if (interface.flags() & QNetworkInterface::IsUp && interface.flags() & QNetworkInterface::IsRunning) {
const QList<QNetworkAddressEntry> entries = interface.addressEntries();
for (const QNetworkAddressEntry &entry : entries) {
if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) continue;
QUdpSocket *socket = new QUdpSocket(this);
if (socket->bind(entry.ip(), ListenPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
connect(socket, &QUdpSocket::readyRead, this, &DeviceListModel::onDeviceReplyReadyRead);
m_udpSockets.push_back(socket);
LOG(info) << "Listening on " << entry.ip().toString().toStdString() << ":" << ListenPort;
} else {
LOG(error) << "Failed to bind UDP socket on" << entry.ip().toString().toStdString() << ":"
<< ListenPort;
delete socket;
}
}
}
}
if (!m_udpSockets.empty()) {
m_retries = 0;
emit searchProgressChanged();
m_timerId = startTimer(1000);
emit isSearchingChanged();
}
}
bool DeviceListModel::isSearching() const {
return m_timerId >= 0;
}
float DeviceListModel::searchProgress() const {
return static_cast<float>(m_retries) * 100 / RetryCount;
}
void DeviceListModel::onDeviceReplyReadyRead() {
auto udp = dynamic_cast<QUdpSocket *>(sender());
while (udp->hasPendingDatagrams()) {
QNetworkDatagram datagram = udp->receiveDatagram();
auto replyVale = boost::json::parse(datagram.data().toStdString());
auto &reply = replyVale.as_object();
DeviceInfomation device;
device.deviceId = QString::fromStdString(std::string(reply.at("devid").as_string()));
device.firmwareVersion = QString::fromStdString(std::string(reply.at("fw_ver").as_string()));
device.softwareVersion = QString::fromStdString(std::string(reply.at("sw_ver").as_string()));
device.ip = datagram.senderAddress().toString();
auto iterator = std::find_if(m_devices.cbegin(), m_devices.cend(), [&device](const DeviceInfomation &item) {
return item.deviceId == device.deviceId;
});
if (iterator == m_devices.cend()) {
beginInsertRows(QModelIndex(), m_devices.size(), m_devices.size());
m_devices.push_back(device);
endInsertRows();
}
LOG(info) << "Received datagram from " << datagram.senderAddress().toString().toStdString() << ":"
<< datagram.senderPort() << ", Data: " << datagram.data().toStdString();
}
}
void DeviceListModel::broadcast() {
if (m_udpSockets.empty()) return;
QByteArray datagram = "FACEPASS_V2";
auto interfaces = QNetworkInterface::allInterfaces();
for (auto &interface : interfaces) {
if (interface.flags() & QNetworkInterface::IsLoopBack) continue;
if (interface.flags() & QNetworkInterface::IsUp && interface.flags() & QNetworkInterface::IsRunning) {
const QList<QNetworkAddressEntry> entries = interface.addressEntries();
for (const QNetworkAddressEntry &entry : entries) {
if (entry.broadcast().toIPv4Address()) {
m_broadcastSocket->writeDatagram(datagram, entry.broadcast(), BroadcastPort);
LOG(info) << "Broadcasted datagram: " << datagram.toStdString() << " to "
<< entry.broadcast().toString().toStdString() << ":" << BroadcastPort;
}
}
}
}
}
void DeviceListModel::stopSearchDevice() {
if (m_timerId >= 0) {
killTimer(m_timerId);
m_timerId = -1;
}
if (!m_udpSockets.empty()) {
for (auto &socket : m_udpSockets) {
socket->deleteLater();
}
m_udpSockets.clear();
}
emit isSearchingChanged();
}
void DeviceListModel::timerEvent(QTimerEvent *event) {
broadcast();
m_retries++;
emit searchProgressChanged();
if (m_retries >= RetryCount) {
QTimer::singleShot(0, this, &DeviceListModel::stopSearchDevice);
}
}

61
DeviceListModel.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef DEVICELISTMODEL_H
#define DEVICELISTMODEL_H
#include <QAbstractListModel>
#include <QQmlEngine>
class QUdpSocket;
class DeviceInfomation {
public:
QString deviceId;
QString softwareVersion;
QString firmwareVersion;
QString ip;
};
class DeviceListModel : public QAbstractListModel {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Only used in C++...")
Q_PROPERTY(bool isSearching READ isSearching NOTIFY isSearchingChanged)
Q_PROPERTY(float searchProgress READ searchProgress NOTIFY searchProgressChanged)
public:
static constexpr uint16_t BroadcastPort = 40000;
static constexpr uint16_t ListenPort = 40001;
static constexpr int RetryCount = 10;
enum InfoRoles {
DeviceIdRole = Qt::UserRole + 1,
FirmwareVersionRole,
SoftwareVersionRole,
IpRole,
};
DeviceListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const final;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final;
QHash<int, QByteArray> roleNames() const final;
Q_INVOKABLE QVariantMap get(int index) const;
Q_INVOKABLE void startSearchDevice();
bool isSearching() const;
float searchProgress() const;
signals:
void isSearchingChanged();
void searchProgressChanged();
protected:
void onDeviceReplyReadyRead();
void broadcast();
void stopSearchDevice();
void timerEvent(QTimerEvent *event);
private:
std::vector<DeviceInfomation> m_devices;
std::list<QUdpSocket *> m_udpSockets;
QUdpSocket *m_broadcastSocket = nullptr;
int m_timerId = -1;
int m_retries = 0;
};
#endif // DEVICELISTMODEL_H

View File

@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import AntiClipSettings
Item {
@ -7,14 +8,13 @@ Item {
property int dargWidth: 12
property color openDoorAreaColor: "green"
property var openDoorAreaPoints: []
property bool openDoorAreaEnabled: false
property int openDoorAreaWay: 0
property color shieldedAreaColor: "yellow"
property var shieldedAreaPoints: []
property bool shieldedAreaEnabled: false
property color antiClipAreaColor: "blue"
property var antiClipAreaPoints: []
property bool antiClipAreaEnabled: false
property var defaultShieldedAreaPoints: [Qt.point(6, 6), Qt.point(40, 60),
Qt.point(598, 6), Qt.point(633, 60)]
Item {
anchors.left: parent.left
anchors.right: parent.right
@ -36,7 +36,13 @@ Item {
onPaint: {
var ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
if (openDoorAreaEnabled &&(openDoorAreaPoints.length > 0)) {
if(openDoorAreaWay == DeviceConnection.FullArea){
ctx.strokeStyle = openDoorAreaColor
ctx.lineWidth = 8
ctx.strokeRect(0,0, canvas.width,
canvas.height)
} else if ((openDoorAreaWay>=DeviceConnection.Quadrangle) &&(openDoorAreaPoints.length > 0)) {
ctx.strokeStyle = openDoorAreaColor
ctx.lineWidth = 2
@ -69,7 +75,8 @@ Item {
ctx.stroke()
}
if (shieldedAreaEnabled &&(shieldedAreaPoints.length > 0)) {
ctx.strokeStyle = "green"
ctx.lineWidth = 2
ctx.strokeStyle = shieldedAreaColor
let point0 = scaledPoint(shieldedAreaPoints[0],
width, height)
let point1 = scaledPoint(shieldedAreaPoints[1],
@ -88,12 +95,12 @@ Item {
Repeater {
id: repeater
visible: openDoorAreaEnabled
visible: openDoorAreaWay>=DeviceConnection.Quadrangle
model: openDoorAreaPoints
delegate: Rectangle {
width: dargWidth
height: dargWidth
visible: openDoorAreaEnabled
visible: openDoorAreaWay>=DeviceConnection.Quadrangle
color: openDoorAreaColor
x: scaledPoint(modelData, canvas.width,
canvas.height).x - width / 2
@ -110,7 +117,7 @@ Item {
width: dargWidth
height: dargWidth
visible: shieldedAreaEnabled
color: "green"
color: shieldedAreaColor
x: scaledPoint(modelData, canvas.width,
canvas.height).x - width / 2
y: scaledPoint(modelData, canvas.width,
@ -140,7 +147,7 @@ Item {
property int draggedShieldedAreaPointIndex: -1
property int draggedAntiAreaPointIndex: -1
onPressed: mouse => {
if(openDoorAreaEnabled){
if(openDoorAreaWay == DeviceConnection.Quadrangle){
for (var i = 0; i < openDoorAreaPoints.length; i++) {
let point = scaledPoint(
openDoorAreaPoints[i], canvas.width,
@ -226,38 +233,91 @@ Item {
}
}
}
Row {
Grid {
id: controlBar
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Switch {
text: "开门区域"
checked: openDoorAreaEnabled
onToggled: App.currentOpenDoorAreaEnabled = checked
columns: 2
spacing: 10
Text {text: qsTr("开门区域: ")}
Row {
RadioButton {
text: "关闭"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Diabled
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.Diabled
}
Switch {
text: "防夹区域"
checked: antiClipAreaEnabled
onToggled: App.currentAntiClipAreaEnabled = checked
}
Switch {
text: "屏蔽区域"
RadioButton {
text: "全区域"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.FullArea
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.FullArea
}
}
RadioButton {
text: "四边形"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Quadrangle
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.Quadrangle
}
}
}
Text {text: qsTr("防夹区域: ")}
Row {
RadioButton {
text: "关闭"
checked: !App.currentAntiClipAreaEnabled
onToggled: {
App.currentAntiClipAreaEnabled=false
}
}
RadioButton {
text: "四边形"
checked: App.currentAntiClipAreaEnabled
onToggled: {
App.currentAntiClipAreaEnabled=true
}
}
}
Text {text: qsTr("屏蔽区域: ")}
Row {
id: shieldedRow
RadioButton {
checked: !shieldedAreaEnabled
text: "关闭"
onToggled: {
App.currentShieldedAreaEnabled = false
}
}
RadioButton {
checked: shieldedAreaEnabled
onToggled: App.currentShieldedAreaEnabled = checked
text: "开启"
onToggled: {
App.currentShieldedAreaEnabled = true
}
}
}
}
//
function scaledPoint(point, width, height) {
let x = point.x * width / 640
let y = point.y * height / 360
let x = point.x * width / App.DeviceWidth
let y = point.y * height / App.DeviceHeight
return Qt.point(x, y)
}
// (640x360)
function standardPoint(point, width, height) {
let x = point.x * 640 / width
let y = point.y * 360 / height
let x = point.x * App.DeviceWidth / width
let y = point.y * App.DeviceHeight / height
return Qt.point(x, y)
}
@ -269,6 +329,7 @@ Item {
}
function onCurrentOpenDoorAreaPointsChanged() {
canvas.requestPaint()
repeater.model = openDoorAreaPoints
}
function onCurrentShieldedAreaPointsChanged() {
canvas.requestPaint()
@ -276,7 +337,7 @@ Item {
function onCurrentAntiClipAreaPointsChanged() {
canvas.requestPaint()
}
function onCurrentOpenDoorAreaEnabledChanged(){
function onCurrentOpenDoorAreaWayChanged(){
canvas.requestPaint()
}
function onCurrentShieldedAreaEnabledChanged(){

View File

@ -4,8 +4,8 @@ import QtQuick.Layouts
import AntiClipSettings
ApplicationWindow {
width: 680
height: 480
width: 1000
height: 640
visible: true
title: qsTr("Hello World")
@ -14,29 +14,73 @@ ApplicationWindow {
anchors.fill: parent
Button {
text: "搜索设备"
onClicked: {
deviceList.currentIndex = -1
App.devices.startSearchDevice()
}
Button {
text: "连接"
onClicked: App.open()
}
Button {
text: "开始"
onClicked: App.start()
Row {
Layout.alignment: Qt.AlignRight
Text {
text: qsTr("当前设备版本号: ")
}
Text {
Layout.alignment: Qt.AlignRight
text: qsTr("当前设备版本号: RD_T009_V02R001B001")
}
id: deviceVersion
text: qsTr("RD_T009_V02R001B001")
}
}
Rectangle {
}
}
ListView {
id: deviceList
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 250
color: "red"
width: 420
clip: true
model: App.devices
delegate: Rectangle {
width: deviceList.width
height: 40
color: ListView.isCurrentItem ? "#aaddff" : (index % 2 == 0 ? "#ffffff" : "#eeeeee")
Row {
anchors.fill: parent
spacing: 10
Text {
text: deviceId
}
Item {}
Text {
text: ip
}
}
MouseArea {
anchors.fill: parent
onClicked: {
deviceList.currentIndex = index
}
onDoubleClicked: {
networkPopup.open()
}
}
}
onCurrentIndexChanged: {
deviceVersion.text = App.devices.get(deviceList.currentIndex).softwareVersion;
App.connectToDevice(App.devices.get(deviceList.currentIndex).ip)
}
ProgressBar {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
visible: App.devices.isSearching
from: 0
to: 100
value: App.devices.searchProgress
height: 25
}
}
DeviceView {
@ -44,7 +88,7 @@ ApplicationWindow {
anchors.bottom: parent.bottom
anchors.left: deviceList.right
anchors.right: parent.right
openDoorAreaEnabled: App.currentOpenDoorAreaEnabled
openDoorAreaWay: App.currentOpenDoorAreaWay
openDoorAreaPoints: App.currentOpenDoorAreaPoints
shieldedAreaEnabled: App.currentShieldedAreaEnabled
shieldedAreaPoints: App.currentShieldedAreaPoints
@ -52,6 +96,13 @@ ApplicationWindow {
antiClipAreaPoints: App.currentAntiClipAreaPoints
}
NetworkSettingPopup {
id: networkPopup
visible: false
width: 500
height: 240
}
footer: RowLayout {
width: parent.width
Item {}

117
NetworkSettingPopup.qml Normal file
View File

@ -0,0 +1,117 @@
import QtQuick
import QtQuick.Controls
import AntiClipSettings
Popup {
id: root
parent: Overlay.overlay
anchors.centerIn: Overlay.overlay
Rectangle {
width: parent.width
height: parent.height
color: "white"
border.color: "lightgray"
radius: 10
Column {
anchors.centerIn: parent
spacing: 10
padding: 20
Row {
spacing: 10
Text {
text: "模式"
font.pointSize: 14
width: 100
}
RadioButton {
id: dhcpMode
text: "DHCP"
checked: App.currentNetworkInfomation.dhcp
}
RadioButton {
id: staticMode
text: "静态IP"
checked: !App.currentNetworkInfomation.dhcp
}
}
Row {
spacing: 5
Text {
text: "设备IP"
font.pointSize: 14
width: 100
}
TextField {
id: ipInput
width: 350
height: 30
text: App.currentNetworkInfomation.ip
}
}
Row {
spacing: 5
Text {
width: 100
text: "子网掩码"
font.pointSize: 14
}
TextField {
id: netmaskInput
width: 350
height: 30
text: App.currentNetworkInfomation.netmask
}
}
Row {
spacing: 5
Row {
spacing: 5
Text {
text: "设备网关"
font.pointSize: 14
width: 100
}
}
TextField {
id: gatewayInput
width: 350
height: 30
text: App.currentNetworkInfomation.gateway
}
}
Row {
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
Button {
text: "保存"
onClicked: {
App.updateNetworkInfomation(dhcpMode.checked,ipInput.text,netmaskInput.text,gatewayInput.text);
networkPopup.close()
}
}
Button {
text: "取消"
onClicked: root.close()
}
}
}
}
}