完善升级功能。

This commit is contained in:
luocai 2024-08-08 17:05:32 +08:00
parent 2610c40189
commit 9d495d487d
7 changed files with 251 additions and 198 deletions

View File

@ -12,6 +12,7 @@
#include "VideoFrameProvider.h" #include "VideoFrameProvider.h"
#include "VideoPlayer.h" #include "VideoPlayer.h"
#include <QApplication> #include <QApplication>
#include <QFile>
#include <QFont> #include <QFont>
#include <QImage> #include <QImage>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
@ -408,7 +409,22 @@ void Application::onVerifyTimeout() {
} }
} }
void Application::startOta(const QString &path) { bool Application::startOta(const QString &path) {
if (!QFile::exists(path)) {
emit otaMessage("文件不存在");
return false;
}
auto device = CdcUpdater::searchDevice();
if (device) {
LOG(info) << "device already in ota mode.";
} else {
if (m_communication) {
m_communication->startOta();
} else {
emit otaMessage("请先打开设备");
return false;
}
}
LOG(info) << "start ota, ota path: " << path.toStdString(); LOG(info) << "start ota, ota path: " << path.toStdString();
m_updater = std::make_shared<CdcUpdater>(); m_updater = std::make_shared<CdcUpdater>();
connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Application::onCdcDeviceDiscovered); connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Application::onCdcDeviceDiscovered);
@ -416,8 +432,8 @@ void Application::startOta(const QString &path) {
connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Application::otaProgressChanged); connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Application::otaProgressChanged);
connect(m_updater.get(), &CdcUpdater::message, this, &Application::otaMessage); connect(m_updater.get(), &CdcUpdater::message, this, &Application::otaMessage);
m_communication->startOta(); m_updater->start(path, device ? *device : QSerialPortInfo());
m_updater->start(path); return true;
} }
void Application::onCdcDeviceDiscovered(const QSerialPortInfo &info) { void Application::onCdcDeviceDiscovered(const QSerialPortInfo &info) {

View File

@ -45,7 +45,7 @@ public:
Q_INVOKABLE bool openUVC(const QString &deviceName); Q_INVOKABLE bool openUVC(const QString &deviceName);
Q_INVOKABLE void close(); Q_INVOKABLE void close();
Q_INVOKABLE void closeUVC(); Q_INVOKABLE void closeUVC();
Q_INVOKABLE void startOta(const QString &path); Q_INVOKABLE bool startOta(const QString &path);
Q_INVOKABLE void verify(bool captureImage, uint8_t timeout); Q_INVOKABLE void verify(bool captureImage, uint8_t timeout);
Q_INVOKABLE void enroll(const QString &username, bool persistence, uint8_t timeout); Q_INVOKABLE void enroll(const QString &username, bool persistence, uint8_t timeout);
Q_INVOKABLE void enrollExtended(const QString &username, bool persistence, uint8_t timeout); Q_INVOKABLE void enrollExtended(const QString &username, bool persistence, uint8_t timeout);

View File

@ -5,192 +5,197 @@ import QtQuick.Dialogs
import QtQuick.Layouts import QtQuick.Layouts
import Analyser import Analyser
ColumnLayout { Item {
ConnectionItem {} id: root
ColumnLayout {
anchors.fill: parent
ConnectionItem {}
GroupBox { GroupBox {
title: "命令" id: commandBox
Layout.columnSpan: 2 title: "命令"
enabled: App.connected Layout.columnSpan: 2
GridLayout { enabled: App.connected
columns: 2 GridLayout {
GroupBox { columns: 2
title: "注册用户" GroupBox {
GridLayout { title: "注册用户"
columns: 2 GridLayout {
Text { columns: 2
text: qsTr("用户姓名") Text {
} text: qsTr("用户姓名")
TextField { }
id: enrollName TextField {
implicitWidth: 100 id: enrollName
} implicitWidth: 100
Text { }
text: qsTr("超时时间") Text {
} text: qsTr("超时时间")
TextField { }
id: enrollTimeout TextField {
implicitWidth: 100 id: enrollTimeout
text: "10" implicitWidth: 100
} text: "10"
}
Text { Text {
text: qsTr("持久化") text: qsTr("持久化")
} }
Switch { Switch {
id: persistence id: persistence
checked: true checked: true
} }
Text { Text {
text: qsTr("保存图片") text: qsTr("保存图片")
} }
Switch { Switch {
id: extendedMode id: extendedMode
} }
Button { Button {
property bool enrolling: App.module ? (App.module.currentMessageId === 0x1d) property bool enrolling: App.module ? (App.module.currentMessageId === 0x1d) || (App.module.currentMessageId === 0x1e) : false
|| (App.module.currentMessageId text: enrolling ? "取消" : "注册"
=== 0x1e) : false onClicked: {
text: enrolling ? "取消" : "注册" if (enrolling) {
onClicked: { App.module.reset()
if (enrolling) { } else if (extendedMode.checked) {
App.module.reset() App.enrollExtended(
} else if (extendedMode.checked) { enrollName.text,
App.enrollExtended(enrollName.text, persistence.checked,
persistence.checked, parseInt(enrollTimeout.text))
parseInt(enrollTimeout.text)) } else {
} else { App.enroll(enrollName.text,
App.enroll(enrollName.text, persistence.checked,
persistence.checked, parseInt(enrollTimeout.text))
parseInt(enrollTimeout.text)) }
} }
} }
} }
} }
} GroupBox {
GroupBox { title: "识别用户"
title: "识别用户" GridLayout {
GridLayout { columns: 2
columns: 2 Text {
Text { text: qsTr("超时时间(s)")
text: qsTr("超时时间(s)") }
} TextField {
TextField { id: verifyTimeout
id: verifyTimeout implicitWidth: 80
implicitWidth: 80 text: "10"
text: "10" }
} Text {
Text { text: qsTr("持续识别")
text: qsTr("持续识别") }
} Switch {
Switch { checked: App.persistenceMode
checked: App.persistenceMode onToggled: App.persistenceMode = !App.persistenceMode
onToggled: App.persistenceMode = !App.persistenceMode }
} Text {
Text { text: qsTr("保存图片")
text: qsTr("保存图片") }
} Switch {
Switch { id: extendedVerifyMode
id: extendedVerifyMode }
} Text {
Text { text: qsTr("识别间隔(s)")
text: qsTr("识别间隔(s)") }
} TextField {
TextField { id: verifyIntetval
id: verifyIntetval implicitWidth: 80
implicitWidth: 80 text: App.persistenceVerifyInterval
text: App.persistenceVerifyInterval }
} Item {}
Item {} Button {
Button { text: App.isVerifying ? "停止" : "识别"
text: App.isVerifying ? "停止" : "识别" onClicked: {
onClicked: { if (App.isVerifying) {
if (App.isVerifying) { App.module.reset()
App.module.reset() } else {
} else { App.persistenceVerifyInterval = parseInt(
App.persistenceVerifyInterval = parseInt( verifyIntetval.text)
verifyIntetval.text) App.verify(extendedVerifyMode.checked,
App.verify(extendedVerifyMode.checked, parseInt(verifyTimeout.text))
parseInt(verifyTimeout.text)) }
} }
} }
} }
} }
} GroupBox {
GroupBox { title: "删除用户"
title: "删除用户" GridLayout {
GridLayout { columns: 2
columns: 2 Text {
Text { text: qsTr("用户ID")
text: qsTr("用户ID") }
} TextField {
TextField { id: deleteUserId
id: deleteUserId implicitWidth: 100
implicitWidth: 100 }
} Button {
Button { text: "删除"
text: "删除" onClicked: App.deleteUser(parseInt(
onClicked: App.deleteUser(parseInt(deleteUserId.text)) deleteUserId.text))
} }
Button { Button {
text: "删除所有" text: "删除所有"
onClicked: App.deleteAll() onClicked: App.deleteAll()
}
}
}
GroupBox {
title: "图片注册"
GridLayout {
columns: 2
TextField {
id: imagePath
Layout.columnSpan: 2
implicitWidth: 180
placeholderText: "请选择图片"
onPressed: {
fileDialog.open()
} }
} }
Button { }
text: "注册" GroupBox {
onClicked: App.uploadImage(imagePath.text, 0) title: "图片注册"
} GridLayout {
Button { columns: 2
text: "识别" TextField {
onClicked: App.uploadImage(imagePath.text, 1) id: imagePath
Layout.columnSpan: 2
implicitWidth: 180
placeholderText: "请选择图片"
onPressed: {
fileDialog.open()
}
}
Button {
text: "注册"
onClicked: App.uploadImage(imagePath.text, 0)
}
Button {
text: "识别"
onClicked: App.uploadImage(imagePath.text, 1)
}
} }
} }
} Button {
Button { text: "复位"
text: "复位" onClicked: App.module.reset()
onClicked: App.module.reset()
}
Button {
text: "状态查询"
onClicked: App.module.requestCurrentStatus()
}
Button {
text: "ID查询"
onClicked: App.module.requestUniqueId()
}
Button {
text: "OTA升级"
onClicked: loader.active = true
}
Row {
Text {
text: qsTr("日志")
} }
Switch { Button {
id: debugMode text: "状态查询"
onToggled: App.module.setDebugEnabled(debugMode.checked) onClicked: App.module.requestCurrentStatus()
}
Button {
text: "ID查询"
onClicked: App.module.requestUniqueId()
}
Button {
id: otaButton
text: "OTA升级"
onClicked: loader.active = true
}
Row {
Text {
text: qsTr("日志")
}
Switch {
id: debugMode
onToggled: App.module.setDebugEnabled(debugMode.checked)
}
} }
} }
} }
} }
FileDialog { FileDialog {
id: fileDialog id: fileDialog
nameFilters: ["图片 (*.jpg *.yuv)"] nameFilters: ["图片 (*.jpg *.yuv)"]
@ -204,6 +209,19 @@ ColumnLayout {
} }
} }
MouseArea {
width: otaButton.width
height: otaButton.height
enabled: !commandBox.enabled
onClicked: {
loader.active = true
}
Component.onCompleted: {
x = Qt.binding(() => otaButton.mapToItem(root, 0, 0).x)
y = Qt.binding(() => otaButton.mapToItem(root, 0, 0).y)
}
}
Loader { Loader {
id: loader id: loader
source: "OtaPage.qml" source: "OtaPage.qml"

View File

@ -45,14 +45,14 @@ Popup {
RowLayout { RowLayout {
spacing: 10 spacing: 10
ProgressBar { ProgressBar {
id:progressBar id: progressBar
Layout.fillWidth: true Layout.fillWidth: true
from: 0 from: 0
to:100 to: 100
value: 0.0 value: 0.0
} }
Text { Text {
id:progressText id: progressText
text: "0%" text: "0%"
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
@ -72,8 +72,7 @@ Popup {
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
onClicked: { onClicked: {
otaMessage.color = "black" otaMessage.color = "black"
App.startOta(otaFile.text) enabled = !App.startOta(otaFile.text)
enabled = false
} }
} }
} }
@ -106,10 +105,9 @@ Popup {
function onOtaMessage(message) { function onOtaMessage(message) {
otaMessage.text = message otaMessage.text = message
} }
function onOtaProgressChanged(progress){ function onOtaProgressChanged(progress) {
progressBar.value = progress; progressBar.value = progress
progressText.text = `${progress}%` progressText.text = `${progress}%`
} }
} }
} }

View File

@ -62,23 +62,28 @@ void Widget::start() {
QMessageBox::warning(this, "升级", "升级文件不存在!"); QMessageBox::warning(this, "升级", "升级文件不存在!");
return; return;
} }
auto discovery = std::make_shared<DeviceDiscovery>(); auto device = CdcUpdater::searchDevice();
if (device) {
LOG(info) << "device already in ota mode.";
} else {
auto discovery = std::make_shared<DeviceDiscovery>();
std::error_code error; std::error_code error;
setMessage("尝试发现设备......"); setMessage("尝试发现设备......");
auto device = discovery->find("UVC Camera", error); auto device = discovery->find("UVC Camera", error);
if (!device) { if (!device) {
QMessageBox::warning(this, "升级", "未检测到模组,请尝试重新插入模组!"); QMessageBox::warning(this, "升级", "未检测到模组,请尝试重新插入模组!");
return; return;
}
setMessage("发现设备成功,进入BOOT模式......");
discovery->enterOtaMode(device, error);
} }
setMessage("发现设备成功,进入BOOT模式......");
discovery->enterOtaMode(device, error);
m_updater = std::make_shared<CdcUpdater>(); m_updater = std::make_shared<CdcUpdater>();
connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Widget::onCdcDeviceDiscovered); connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Widget::onCdcDeviceDiscovered);
connect(m_updater.get(), &CdcUpdater::updateFinished, this, &Widget::onUpdateFinished); connect(m_updater.get(), &CdcUpdater::updateFinished, this, &Widget::onUpdateFinished);
connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Widget::setProgress); connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Widget::setProgress);
connect(m_updater.get(), &CdcUpdater::message, this, &Widget::setMessage); connect(m_updater.get(), &CdcUpdater::message, this, &Widget::setMessage);
m_updater->start(filePath); m_updater->start(filePath, device ? *device : QSerialPortInfo());
setControlsEnabled(false); setControlsEnabled(false);
} }

View File

@ -3,7 +3,6 @@
#include "StringUtility.h" #include "StringUtility.h"
#include <QDebug> #include <QDebug>
#include <QSerialPort> #include <QSerialPort>
#include <QSerialPortInfo>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <mbedtls/md5.h> #include <mbedtls/md5.h>
@ -41,10 +40,15 @@ CdcUpdater::CdcUpdater(QObject *parent) : QObject(parent) {
CdcUpdater::~CdcUpdater() { CdcUpdater::~CdcUpdater() {
} }
void CdcUpdater::start(const QString &path) { void CdcUpdater::start(const QString &path, const QSerialPortInfo &info) {
if (m_timerId < 0) { if (info.isNull()) {
m_timerId = startTimer(1000); if (m_timerId < 0) {
m_timerId = startTimer(1000);
}
} else {
open(info);
} }
m_path = Amass::StringUtility::UTF8ToGBK(path.toStdString()); m_path = Amass::StringUtility::UTF8ToGBK(path.toStdString());
LOG(info) << "ota file: " << m_path; LOG(info) << "ota file: " << m_path;
emit progressChanged(++m_progress); emit progressChanged(++m_progress);
@ -84,20 +88,29 @@ bool CdcUpdater::write(Command command, const uint8_t *data, uint32_t size) {
return m_serialPort->write(reinterpret_cast<const char *>(packet.data()), packet.size()); return m_serialPort->write(reinterpret_cast<const char *>(packet.data()), packet.size());
} }
void CdcUpdater::timerEvent(QTimerEvent *event) { std::optional<QSerialPortInfo> CdcUpdater::searchDevice() {
std::optional<QSerialPortInfo> ret = std::nullopt;
const auto serialPortInfos = QSerialPortInfo::availablePorts(); const auto serialPortInfos = QSerialPortInfo::availablePorts();
for (const QSerialPortInfo &portInfo : serialPortInfos) { for (const QSerialPortInfo &portInfo : serialPortInfos) {
LOG(info) << "portName:" << portInfo.portName().toStdString() LOG(info) << "portName:" << portInfo.portName().toStdString()
<< ", vendorIdentifier: " << portInfo.vendorIdentifier() << ", vendorIdentifier: " << portInfo.vendorIdentifier()
<< ", productIdentifier: " << portInfo.productIdentifier(); << ", productIdentifier: " << portInfo.productIdentifier();
if (portInfo.vendorIdentifier() == 0xffff) { if (portInfo.vendorIdentifier() == 0xffff) {
LOG(info) << "founded device: " << portInfo.portName().toStdString(); ret = portInfo;
emit deviceDiscovered(portInfo);
killTimer(m_timerId);
m_timerId = -1;
break; break;
} }
} }
return ret;
}
void CdcUpdater::timerEvent(QTimerEvent *event) {
auto device = searchDevice();
if (device) {
LOG(info) << "founded device: " << device->portName().toStdString();
emit deviceDiscovered(*device);
killTimer(m_timerId);
m_timerId = -1;
}
LOG(info) << "----------"; LOG(info) << "----------";
} }

View File

@ -2,9 +2,10 @@
#define __CDCUPDATER_H__ #define __CDCUPDATER_H__
#include <QObject> #include <QObject>
#include <QSerialPortInfo>
#include <optional>
class QSerialPort; class QSerialPort;
class QSerialPortInfo;
class CdcUpdater : public QObject { class CdcUpdater : public QObject {
Q_OBJECT Q_OBJECT
@ -35,8 +36,10 @@ public:
}; };
CdcUpdater(QObject *parent = nullptr); CdcUpdater(QObject *parent = nullptr);
~CdcUpdater(); ~CdcUpdater();
void start(const QString &path); void start(const QString &path, const QSerialPortInfo &info = QSerialPortInfo());
bool open(const QSerialPortInfo &info); bool open(const QSerialPortInfo &info);
static std::optional<QSerialPortInfo> searchDevice();
signals: signals:
void deviceDiscovered(const QSerialPortInfo &info); void deviceDiscovered(const QSerialPortInfo &info);
void updateFinished(); void updateFinished();