diff --git a/Analyser/Application.cpp b/Analyser/Application.cpp index 59f9a11..d524c74 100644 --- a/Analyser/Application.cpp +++ b/Analyser/Application.cpp @@ -2,6 +2,7 @@ #include "AsyncEvent.h" #include "BoostLog.h" #include "CategoryLogSinkBackend.h" +#include "CdcUpdater.h" #include "Configuration.h" #include "Database.h" #include "DateTime.h" @@ -300,6 +301,9 @@ void Application::onNewImageInfo(ModuleCommunication::MessageId messageId, uint3 m_communication->requestEnrolledImage(0, ImageSliceSize); m_palmYImageBuffer.clear(); m_startUploadTime = system_clock::now(); + if (messageId == ModuleCommunication::Note) { + emit newStatusTip(Error, "活体未通过照片"); + } } void Application::onNewImageSliceData(const std::vector &data) { @@ -312,6 +316,9 @@ void Application::onNewImageSliceData(const std::vector &data) { } else { auto username = m_palmUsername.toStdString(); auto way = (m_palmImageId == ModuleCommunication::VerifyExtended) ? "verify" : "enroll"; + if (m_palmImageId == ModuleCommunication::Note) { + way = "no_alive"; + } LOG(info) << "request finished, username: " << username << ", elapsed: " << duration_cast(system_clock::now() - m_startUploadTime); std::ostringstream oss; @@ -382,3 +389,20 @@ void Application::onVerifyTimeout() { m_communication->verify(120); } } + +void Application::startOta(const QString &path) { + LOG(info) << "start ota, ota path: " << path.toStdString(); + m_updater = std::make_shared(); + connect(m_updater.get(), &CdcUpdater::deviceDiscovered, this, &Application::onCdcDeviceDiscovered); + connect(m_updater.get(), &CdcUpdater::updateFinished, this, &Application::updateFinished); + connect(m_updater.get(), &CdcUpdater::progressChanged, this, &Application::otaProgressChanged); + connect(m_updater.get(), &CdcUpdater::message, this, &Application::otaMessage); + + m_communication->startOta(); + m_updater->start(path); +} + +void Application::onCdcDeviceDiscovered(const QSerialPortInfo &info) { + auto status = m_updater->open(info); + LOG(info) << "open cdc port: " << info.portName().toStdString() << ", status: " << status; +} diff --git a/Analyser/Application.h b/Analyser/Application.h index f99d9a1..1e6db39 100644 --- a/Analyser/Application.h +++ b/Analyser/Application.h @@ -13,6 +13,7 @@ class Database; class VideoPlayer; class VideoFrameProvider; class QTimer; +class CdcUpdater; class Application : public QObject { Q_OBJECT @@ -44,6 +45,7 @@ public: Q_INVOKABLE bool openUVC(const QString &deviceName); Q_INVOKABLE void close(); Q_INVOKABLE void closeUVC(); + Q_INVOKABLE void startOta(const QString &path); Q_INVOKABLE void verify(bool captureImage, 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); @@ -69,6 +71,9 @@ signals: void newVideoFrame(); void newLog(const QString &log); void newStatusTip(TipType type, const QString &tip); + void updateFinished(); + void otaMessage(const QString &text); + void otaProgressChanged(int32_t progress); protected: Application(int &argc, char **argv); @@ -80,10 +85,13 @@ protected: void onCommandStarted(ModuleCommunication::MessageId messageId); void onCommandFinished(ModuleCommunication::MessageId messageId, ModuleCommunication::MessageStatus status); void onVerifyTimeout(); + void onCdcDeviceDiscovered(const QSerialPortInfo &info); + void onUpdateFinished(); private: std::shared_ptr m_app; std::shared_ptr m_communication; + std::shared_ptr m_updater; std::shared_ptr m_database; bool m_persistenceMode = true; // 模组持续识别 diff --git a/Analyser/CMakeLists.txt b/Analyser/CMakeLists.txt index c6208c0..69e0839 100644 --- a/Analyser/CMakeLists.txt +++ b/Analyser/CMakeLists.txt @@ -29,6 +29,7 @@ qt_add_qml_module(Analyser qml/ConnectionItem.qml qml/OperationItem.qml qml/StatusTip.qml + qml/OtaPage.qml RESOURCES resources/successfull.svg resources/warning.svg diff --git a/Analyser/ModuleCommunication.cpp b/Analyser/ModuleCommunication.cpp index 6f22ed0..4c28ead 100644 --- a/Analyser/ModuleCommunication.cpp +++ b/Analyser/ModuleCommunication.cpp @@ -159,6 +159,11 @@ void ModuleCommunication::setDebugEnabled(bool enabled) { m_serialPort->write(reinterpret_cast(frameData), frameSize); } +void ModuleCommunication::startOta() { + auto [frameData, frameSize] = generateFrame(StartOta); + m_serialPort->write(reinterpret_cast(frameData), frameSize); +} + void ModuleCommunication::requestUniqueId() { auto [frameData, frameSize] = generateFrame(GetUniqueID); m_serialPort->write(reinterpret_cast(frameData), frameSize); @@ -346,6 +351,11 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) { LOG_CAT(info, GUI) << "模组日志: " << message; break; } + case NoAliveImage: { + LOG(info) << "no alive image"; + emit newImageInfo(Note, 600 * 800, nullptr); + break; + } default: LOG(warning) << "unknown note command: 0x" << (static_cast(noteId) & 0xff) << ", data: " << protocolDataFormatString(data, size); diff --git a/Analyser/ModuleCommunication.h b/Analyser/ModuleCommunication.h index c1db403..15654e4 100644 --- a/Analyser/ModuleCommunication.h +++ b/Analyser/ModuleCommunication.h @@ -28,6 +28,7 @@ public: GetImage = 0x1F, // 获取图片数据,通过VerifyExtended或EnrollExtended保存的 DeleteUser = 0x20, DeleteAll = 0x21, + StartOta = 0x40, // 模组进入boot模式进行ota升级 EnableDebug = 0x82, GetUniqueID = 0xAC, UploadImageInfo = 0xF6, @@ -41,6 +42,7 @@ public: PalmState = 0x01, UnknownError = 0x02, DebugInfo = 0x55, + NoAliveImage = 0x56, }; enum MessageStatus : uint8_t { Success = 0, @@ -161,6 +163,7 @@ public: void uploadImageData(uint32_t offset, const uint8_t *data, uint32_t size); Q_INVOKABLE void requestCurrentStatus(); Q_INVOKABLE void setDebugEnabled(bool enabled); + void startOta(); MessageId currentMessageId() const; static std::string protocolDataFormatString(const uint8_t *data, int size); diff --git a/Analyser/VideoPlayer.cpp b/Analyser/VideoPlayer.cpp index 196a4b8..2de211b 100644 --- a/Analyser/VideoPlayer.cpp +++ b/Analyser/VideoPlayer.cpp @@ -70,7 +70,6 @@ void VideoPlayer::run() { if (status == 0) { QImage image; image.loadFromData(packet->data, packet->size); - image.mirror(false, true); if (!image.isNull() && m_callback) m_callback(image); } else { char message[256] = {0}; diff --git a/Analyser/qml/OperationItem.qml b/Analyser/qml/OperationItem.qml index d173517..828de6b 100644 --- a/Analyser/qml/OperationItem.qml +++ b/Analyser/qml/OperationItem.qml @@ -160,6 +160,10 @@ ColumnLayout { text: "ID查询" onClicked: App.module.requestUniqueId() } + Button { + text: "OTA升级" + onClicked: loader.active = true + } Row { Text { text: qsTr("日志") @@ -171,4 +175,18 @@ ColumnLayout { } } } + + Loader { + id: loader + source: "OtaPage.qml" + active: false + onLoaded: { + if (loader.item && loader.item.open) { + loader.item.open(); + loader.item.onClose = ()=>{ + loader.active= false + } + } + } + } } diff --git a/Analyser/qml/OtaPage.qml b/Analyser/qml/OtaPage.qml new file mode 100644 index 0000000..ce899a1 --- /dev/null +++ b/Analyser/qml/OtaPage.qml @@ -0,0 +1,115 @@ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import Analyser + +Popup { + id: root + parent: Overlay.overlay + anchors.centerIn: Overlay.overlay + width: 500 + height: 200 + modal: true + focus: true + closePolicy: Popup.CloseOnEscape + property var onClose + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + + RowLayout { + Layout.alignment: Qt.AlignRight + Button { + text: "关闭" + onClicked: root.close() + } + } + + RowLayout { + spacing: 10 + TextField { + id: otaFile + Layout.fillWidth: true + placeholderText: "请选择升级文件或将文件拖入工具中" + } + Button { + text: "选择" + onClicked: fileDialog.open() + } + } + + RowLayout { + spacing: 10 + ProgressBar { + id:progressBar + Layout.fillWidth: true + from: 0 + to:100 + value: 0.0 + } + Text { + id:progressText + text: "0%" + verticalAlignment: Text.AlignVCenter + } + } + + RowLayout { + Text { + id: otaMessage + text: "请选择升级文件,点击开始按钮升级模组" + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + Layout.fillWidth: true + } + Button { + text: "开始" + Layout.alignment: Qt.AlignRight + onClicked: { + otaMessage.color = "black" + App.startOta(otaFile.text) + enabled = false + } + } + } + } + + onClosed: { + if (onClose) + onClose() + } + + FileDialog { + id: fileDialog + nameFilters: ["OTA文件 (*.Pkg)"] + currentFolder: StandardPaths.standardLocations( + StandardPaths.DesktopLocation)[0] + onAccepted: { + var fileUrl = fileDialog.selectedFile.toString() + var localFilePath = fileUrl.startsWith( + "file:///") ? fileUrl.substring(8) : fileUrl + otaFile.text = localFilePath + } + } + + Connections { + target: App + function onUpdateFinished() { + otaMessage.text = "OTA升级完成" + otaMessage.color = "green" + } + function onOtaMessage(message) { + otaMessage.text = message + } + function onOtaProgressChanged(progress){ + progressBar.value = progress; + progressText.text = `${progress}%` + + } + } +} diff --git a/Analyser/qml/main.qml b/Analyser/qml/main.qml index d01d655..fe652e7 100644 --- a/Analyser/qml/main.qml +++ b/Analyser/qml/main.qml @@ -5,7 +5,7 @@ import Analyser Window { width: 1120 - height: 640 + height: 680 visible: true title: qsTr(Qt.application.name + " " + Qt.application.version) diff --git a/OtaUpdate/CMakeLists.txt b/OtaUpdate/CMakeLists.txt index 46732e7..c28609a 100644 --- a/OtaUpdate/CMakeLists.txt +++ b/OtaUpdate/CMakeLists.txt @@ -6,7 +6,6 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets SerialPort) set(PROJECT_SOURCES OtaUpdate.rc main.cpp - CdcUpdater.h CdcUpdater.cpp Widget.cpp Widget.h ) @@ -18,7 +17,6 @@ qt_add_executable(SmartLockerUpdater target_link_libraries(SmartLockerUpdater PRIVATE Peripheral - PRIVATE Encrypt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort ) diff --git a/Peripheral/CMakeLists.txt b/Peripheral/CMakeLists.txt index ef6122f..923b948 100644 --- a/Peripheral/CMakeLists.txt +++ b/Peripheral/CMakeLists.txt @@ -1,5 +1,11 @@ +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS SerialPort) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS SerialPort) + +set(CMAKE_AUTOMOC ON) + add_library(Peripheral DeviceDiscovery.h DeviceDiscovery.cpp + CdcUpdater.h CdcUpdater.cpp ) target_include_directories(Peripheral @@ -8,8 +14,10 @@ target_include_directories(Peripheral target_link_libraries(Peripheral PUBLIC Universal + PRIVATE Encrypt PRIVATE Mfreadwrite PRIVATE Mf PRIVATE mfplat PRIVATE mfuuid + PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort ) diff --git a/OtaUpdate/CdcUpdater.cpp b/Peripheral/CdcUpdater.cpp similarity index 94% rename from OtaUpdate/CdcUpdater.cpp rename to Peripheral/CdcUpdater.cpp index a1ebb5d..7655645 100644 --- a/OtaUpdate/CdcUpdater.cpp +++ b/Peripheral/CdcUpdater.cpp @@ -106,7 +106,8 @@ void CdcUpdater::transferBin() { auto readSize = m_ifs->gcount(); if (readSize > 0) { - m_progress += (99 - m_progressBeforeTranster) * static_cast(m_packetIndex) / m_totalPackageSize; + m_progress = m_progressBeforeTranster + + (99 - m_progressBeforeTranster) * static_cast(m_packetIndex) / m_totalPackageSize; if (m_progress > 99) m_progress = 99; emit progressChanged(m_progress); @@ -138,7 +139,7 @@ void CdcUpdater::onReadyRead() { if (command == EnterUpgradeReply) { write(GetVersion); emit progressChanged(++m_progress); - message("获取模组OTA版本......"); + emit message("获取模组OTA版本......"); } else if (command == GetVersionReply) { LOG(info) << "device ota version: 0x" << std::hex << (static_cast(data[4]) & 0xff); int fileSize = std::filesystem::file_size(m_path); @@ -150,7 +151,7 @@ void CdcUpdater::onReadyRead() { content[2] = 0x14; write(StartUpgrade, content.data(), content.size()); emit progressChanged(++m_progress); - message("模组进入升级状态......"); + emit message("模组进入升级状态......"); } else if (command == StartUpgradeReply) { std::ifstream ifs(m_path, std::ifstream::binary); char buffer[4096] = {0}; diff --git a/OtaUpdate/CdcUpdater.h b/Peripheral/CdcUpdater.h similarity index 100% rename from OtaUpdate/CdcUpdater.h rename to Peripheral/CdcUpdater.h diff --git a/Readme.md b/Readme.md index 367ed10..4565f18 100644 --- a/Readme.md +++ b/Readme.md @@ -56,6 +56,7 @@ HOST_TOOLS := /opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.6.1/bin 上述步骤执行完毕之后,即可编译打包: ```shell +./boot-rebuild.sh # 编译boot ./rebuild-app.sh y L015 V200 R002 # 编译烧录固件 ./rebuild-app-ota.sh y L015 V200 R002 14 # 编译OTA固件,11为OTA版本号 600X800