适配模组的strict模式。

This commit is contained in:
luocai 2024-09-05 16:36:54 +08:00
parent 36a5877a0c
commit 2c06e4d1e0
13 changed files with 149 additions and 535 deletions

View File

@ -10,9 +10,9 @@
#include "StringUtility.h" #include "StringUtility.h"
#include "VideoFrameProvider.h" #include "VideoFrameProvider.h"
#include "VideoPlayer.h" #include "VideoPlayer.h"
#include <QApplication>
#include <QFile> #include <QFile>
#include <QFont> #include <QFont>
#include <QGuiApplication>
#include <QImage> #include <QImage>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QSerialPortInfo> #include <QSerialPortInfo>
@ -26,11 +26,11 @@
constexpr uint32_t ImageSliceSize = (4000 - 32); constexpr uint32_t ImageSliceSize = (4000 - 32);
Application::Application(int &argc, char **argv) : m_app(std::make_shared<QApplication>(argc, argv)) { Application::Application(int &argc, char **argv) : m_app(std::make_shared<QGuiApplication>(argc, argv)) {
m_app->setApplicationName(APPLICATION_NAME); m_app->setApplicationName(APPLICATION_NAME);
m_app->setApplicationVersion(QString("v%1_%2 build: %3 %4").arg(APP_VERSION, GIT_COMMIT_ID, __DATE__, __TIME__)); m_app->setApplicationVersion(QString("v%1_%2 build: %3 %4").arg(APP_VERSION, GIT_COMMIT_ID, __DATE__, __TIME__));
QFont font; QFont font;
font.setPointSize(16); font.setPointSize(12);
m_app->setFont(font); m_app->setFont(font);
m_verifyTimer = new QTimer(this); m_verifyTimer = new QTimer(this);
@ -56,7 +56,7 @@ Application::Application(int &argc, char **argv) : m_app(std::make_shared<QAppli
void Application::onNewEnrollResult(uint16_t userid) { void Application::onNewEnrollResult(uint16_t userid) {
m_palmId = userid; m_palmId = userid;
QTimer::singleShot(0, this, [this, userid]() { QTimer::singleShot(0, this, [this, userid]() {
emit newStatusTip(Info, QString("%1,录入成功,ID:%2").arg(m_palmUsername).arg(userid)); emit newStatusTip(Info, "录入成功", QString("用户: %1, ID: %2").arg(m_palmUsername).arg(userid));
}); });
} }
@ -106,6 +106,14 @@ Application *Application::create(QQmlEngine *qmlEngine, QJSEngine *jsEngine) {
QStringList Application::availableSerialPorts() const { QStringList Application::availableSerialPorts() const {
QStringList ret; QStringList ret;
auto ports = QSerialPortInfo::availablePorts(); auto ports = QSerialPortInfo::availablePorts();
auto iterator = std::find_if(ports.cbegin(), ports.cend(), [](const QSerialPortInfo &info) {
return (info.productIdentifier() == ModuleCommunication::ProductIdentifier) &&
(info.vendorIdentifier() == ModuleCommunication::VendorIdentifier);
});
if (iterator != ports.cend()) {
ret << iterator->portName();
ports.erase(iterator);
}
for (auto &port : ports) { for (auto &port : ports) {
if (port.description() == "蓝牙链接上的标准串行") continue; if (port.description() == "蓝牙链接上的标准串行") continue;
ret << port.portName(); ret << port.portName();
@ -200,11 +208,11 @@ void Application::verify(bool captureImage, uint8_t timeout) {
m_verifyExtendedMode = captureImage; m_verifyExtendedMode = captureImage;
} }
void Application::enroll(const QString &username, bool persistence, uint8_t timeout) { void Application::enroll(const QString &username, bool strictMode, bool persistence, uint8_t timeout) {
if (m_communication->currentMessageId() != ModuleCommunication::Idle) { if (m_communication->currentMessageId() != ModuleCommunication::Idle) {
m_communication->reset(); m_communication->reset();
} }
m_communication->enroll(username.toStdString(), persistence, timeout); m_communication->enroll(username.toStdString(), strictMode, persistence, timeout);
m_palmUsername = username; m_palmUsername = username;
} }
@ -222,11 +230,11 @@ void Application::deleteAll() {
m_communication->deleteAll(); m_communication->deleteAll();
} }
void Application::enrollExtended(const QString &username, bool persistence, uint8_t timeout) { void Application::enrollExtended(const QString &username, bool strictMode, bool persistence, uint8_t timeout) {
if (m_communication->currentMessageId() != ModuleCommunication::Idle) { if (m_communication->currentMessageId() != ModuleCommunication::Idle) {
m_communication->reset(); m_communication->reset();
} }
m_communication->enrollExtended(username.toStdString(), persistence, timeout); m_communication->enrollExtended(username.toStdString(), strictMode, persistence, timeout);
m_palmUsername = username; m_palmUsername = username;
} }
@ -341,8 +349,18 @@ void Application::onNewPalmFeature(const PalmFeature &feature) {
} }
} }
void Application::onErrorOccurred(const QString &error) { void Application::onErrorOccurred(ModuleCommunication::NoteId note, const QString &error,
const QString &detailMessage) {
TipType type = Tip;
if (note == ModuleCommunication::NoteId::DeviceError) {
type = Error;
QTimer::singleShot(0, this, [this]() { close(); }); QTimer::singleShot(0, this, [this]() { close(); });
} else if (note == ModuleCommunication::NoteId::InteractWarning) {
type = Warnging;
} else {
type = Warnging;
}
emit newStatusTip(type, error, detailMessage);
} }
void Application::onNewImageInfo(ModuleCommunication::MessageId messageId, uint32_t size, const uint8_t *md5) { void Application::onNewImageInfo(ModuleCommunication::MessageId messageId, uint32_t size, const uint8_t *md5) {
@ -433,11 +451,6 @@ void Application::onCommandFinished(ModuleCommunication::MessageId messageId,
(status == ModuleCommunication::Failed4LivenessCheck))) { (status == ModuleCommunication::Failed4LivenessCheck))) {
m_verifyTimer->start(m_persistenceVerifyInterval * 1000); m_verifyTimer->start(m_persistenceVerifyInterval * 1000);
} }
if (((messageId == ModuleCommunication::EnrollSingle) || (messageId == ModuleCommunication::EnrollExtended)) &&
(status == ModuleCommunication::Success)) {
emit newStatusTip(Info, "录入成功。");
}
emit isVerifyingChanged(); emit isVerifyingChanged();
} }

View File

@ -37,6 +37,7 @@ public:
Tip, Tip,
Error, Error,
Info, Info,
Warnging,
}; };
Q_ENUM(TipType) Q_ENUM(TipType)
@ -51,8 +52,8 @@ public:
Q_INVOKABLE void closeUVC(); Q_INVOKABLE void closeUVC();
Q_INVOKABLE bool 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 strictMode, 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 strictMode, bool persistence, uint8_t timeout);
Q_INVOKABLE void deleteUser(uint16_t userid); Q_INVOKABLE void deleteUser(uint16_t userid);
Q_INVOKABLE void deleteAll(); Q_INVOKABLE void deleteAll();
Q_INVOKABLE void uploadImage(const QString &path, const QString &username, int operation); Q_INVOKABLE void uploadImage(const QString &path, const QString &username, int operation);
@ -77,7 +78,7 @@ signals:
void uvcOpenedChanged(); void uvcOpenedChanged();
void newVideoFrame(); void newVideoFrame();
void newLog(const QString &log); void newLog(const QString &log);
void newStatusTip(TipType type, const QString &tip); void newStatusTip(TipType type, const QString &tip, const QString &detailMessage = "");
void updateFinished(); void updateFinished();
void otaMessage(const QString &text); void otaMessage(const QString &text);
void otaProgressChanged(int32_t progress); void otaProgressChanged(int32_t progress);
@ -87,7 +88,7 @@ protected:
void onNewEnrollResult(uint16_t userid); void onNewEnrollResult(uint16_t userid);
void onNewVerifyResult(uint16_t userid, const QString &username, uint16_t elapsed); void onNewVerifyResult(uint16_t userid, const QString &username, uint16_t elapsed);
void onNewPalmFeature(const PalmFeature &feature); void onNewPalmFeature(const PalmFeature &feature);
void onErrorOccurred(const QString &error); void onErrorOccurred(ModuleCommunication::NoteId note, const QString &error, const QString &detailMessage);
void onNewImageInfo(ModuleCommunication::MessageId messageId, uint32_t size, const uint8_t *md5); void onNewImageInfo(ModuleCommunication::MessageId messageId, uint32_t size, const uint8_t *md5);
void onNewImageSliceData(const std::vector<uint8_t> &data); void onNewImageSliceData(const std::vector<uint8_t> &data);
void onCommandStarted(ModuleCommunication::MessageId messageId); void onCommandStarted(ModuleCommunication::MessageId messageId);

View File

@ -1,8 +1,8 @@
project(Analyser VERSION 0.3 LANGUAGES C CXX) project(Analyser VERSION 0.3 LANGUAGES C CXX)
set(APPLICATION_NAME "掌静脉测试工具") set(APPLICATION_NAME "掌静脉测试工具")
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort JpegPrivate BundledLibjpeg) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick QuickTemplates2 SerialPort JpegPrivate BundledLibjpeg)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort JpegPrivate BundledLibjpeg) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick QuickTemplates2 SerialPort JpegPrivate BundledLibjpeg)
qt_standard_project_setup(REQUIRES 6.5) qt_standard_project_setup(REQUIRES 6.5)
@ -13,7 +13,6 @@ add_executable(Analyser Analyser.rc
Application.h Application.cpp Application.h Application.cpp
CategoryLogSinkBackend.h CategoryLogSinkBackend.cpp CategoryLogSinkBackend.h CategoryLogSinkBackend.cpp
ImageDecoder.h ImageDecoder.cpp ImageDecoder.h ImageDecoder.cpp
Widget.h Widget.cpp
ModuleCommunication.h ModuleCommunication.cpp ModuleCommunication.h ModuleCommunication.cpp
PalmFeatureTableModel.h PalmFeatureTableModel.cpp PalmFeatureTableModel.h PalmFeatureTableModel.cpp
VideoFrameProvider.h VideoFrameProvider.cpp VideoFrameProvider.h VideoFrameProvider.cpp
@ -27,7 +26,6 @@ qt_add_qml_module(Analyser
qml/Main.qml qml/Main.qml
qml/ConnectionItem.qml qml/ConnectionItem.qml
qml/OperationItem.qml qml/OperationItem.qml
qml/StatusTip.qml
qml/OtaPage.qml qml/OtaPage.qml
RESOURCES RESOURCES
resources/successfull.svg resources/successfull.svg
@ -67,7 +65,6 @@ target_link_libraries(Analyser
PRIVATE avformat PRIVATE avformat
PRIVATE Qt${QT_VERSION_MAJOR}::Quick PRIVATE Qt${QT_VERSION_MAJOR}::Quick
PRIVATE Qt${QT_VERSION_MAJOR}::QuickTemplates2 PRIVATE Qt${QT_VERSION_MAJOR}::QuickTemplates2
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort
PRIVATE Qt${QT_VERSION_MAJOR}::JpegPrivate PRIVATE Qt${QT_VERSION_MAJOR}::JpegPrivate
PRIVATE Qt${QT_VERSION_MAJOR}::BundledLibjpeg PRIVATE Qt${QT_VERSION_MAJOR}::BundledLibjpeg

View File

@ -67,8 +67,9 @@ void ModuleCommunication::reset() {
LOG_CAT(info, GUI) << Separator; LOG_CAT(info, GUI) << Separator;
} }
void ModuleCommunication::enroll(const std::string &username, bool persistence, uint8_t timeout) { void ModuleCommunication::enroll(const std::string &username, bool strictMode, bool persistence, uint8_t timeout) {
EnrollData data = {0}; EnrollData data = {0};
data.strictMode = strictMode ? 1 : 0;
data.timeout = timeout; data.timeout = timeout;
data.skipSave = persistence ? 0 : 1; data.skipSave = persistence ? 0 : 1;
strncpy(reinterpret_cast<char *>(data.username), username.c_str(), sizeof(data.username)); strncpy(reinterpret_cast<char *>(data.username), username.c_str(), sizeof(data.username));
@ -81,8 +82,10 @@ void ModuleCommunication::enroll(const std::string &username, bool persistence,
LOG_CAT(info, GUI) << Separator; LOG_CAT(info, GUI) << Separator;
} }
void ModuleCommunication::enrollExtended(const std::string &username, bool persistence, uint8_t timeout) { void ModuleCommunication::enrollExtended(const std::string &username, bool strictMode, bool persistence,
uint8_t timeout) {
EnrollData data = {}; EnrollData data = {};
data.strictMode = strictMode ? 1 : 0;
data.timeout = timeout; data.timeout = timeout;
data.skipSave = persistence ? 0 : 1; data.skipSave = persistence ? 0 : 1;
strncpy(reinterpret_cast<char *>(data.username), username.c_str(), sizeof(data.username)); strncpy(reinterpret_cast<char *>(data.username), username.c_str(), sizeof(data.username));
@ -372,7 +375,11 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) {
} }
case NoteId::PalmState: { // 模组返回的数据为当前帧的手掌状态 case NoteId::PalmState: { // 模组返回的数据为当前帧的手掌状态
auto state = reinterpret_cast<const PalmStateNote *>(data + 6); auto state = reinterpret_cast<const PalmStateNote *>(data + 6);
LOG(info) << "palm state: " << (int)ntohs(state->state); uint16_t palmState = ntohs(state->state);
if (palmState == NeedMoveToCenter) {
emit errorOccurred(NoteId::InteractWarning, "录入提示", "请将手掌置于画面中心");
}
LOG(info) << "palm state: " << palmState;
break; break;
} }
case NoteId::UnknownError: { case NoteId::UnknownError: {
@ -448,7 +455,7 @@ void ModuleCommunication::onReadyRead() {
void ModuleCommunication::onErrorOccurred(QSerialPort::SerialPortError error) { void ModuleCommunication::onErrorOccurred(QSerialPort::SerialPortError error) {
if (error == QSerialPort::NoError) return; if (error == QSerialPort::NoError) return;
LOG_CAT(info, GUI) << m_serialPort->portName().toStdString() << ": " << m_serialPort->errorString().toStdString(); LOG_CAT(info, GUI) << m_serialPort->portName().toStdString() << ": " << m_serialPort->errorString().toStdString();
emit errorOccurred(m_serialPort->errorString()); emit errorOccurred(NoteId::DeviceError, m_serialPort->errorString());
} }
std::pair<uint8_t *, uint32_t> ModuleCommunication::generateFrame(MessageId command, const uint8_t *data, std::pair<uint8_t *, uint32_t> ModuleCommunication::generateFrame(MessageId command, const uint8_t *data,

View File

@ -19,6 +19,8 @@ class ModuleCommunication : public QObject {
Q_PROPERTY(int otaVerison MEMBER m_otaVerison NOTIFY verisonChanged) Q_PROPERTY(int otaVerison MEMBER m_otaVerison NOTIFY verisonChanged)
public: public:
constexpr static uint16_t VendorIdentifier = 0x3346;
constexpr static uint16_t ProductIdentifier = 0x0001;
constexpr static uint16_t InvalidUserId = std::numeric_limits<uint16_t>::max(); constexpr static uint16_t InvalidUserId = std::numeric_limits<uint16_t>::max();
enum MessageId : uint8_t { enum MessageId : uint8_t {
Reply = 0, Reply = 0,
@ -48,6 +50,9 @@ public:
UnknownError = 0x02, UnknownError = 0x02,
DebugInfo = 0x55, DebugInfo = 0x55,
NoAliveImage = 0x56, NoAliveImage = 0x56,
DeviceError = 0xF0, // 系统设备出现的错误,例如 QSerialPort
InteractWarning,
}; };
enum PalmState { enum PalmState {
@ -94,6 +99,7 @@ public:
struct EnrollData { struct EnrollData {
uint8_t username[32]; uint8_t username[32];
uint8_t strictMode = 0;
uint8_t skipSave = 0; uint8_t skipSave = 0;
uint8_t timeout; uint8_t timeout;
}; };
@ -172,8 +178,8 @@ public:
void verifyExtended(bool captureImage, uint8_t timeout); void verifyExtended(bool captureImage, uint8_t timeout);
Q_INVOKABLE void reset(); Q_INVOKABLE void reset();
void enroll(const std::string &username, bool persistence, uint8_t timeout); void enroll(const std::string &username, bool strictMode, bool persistence, uint8_t timeout);
void enrollExtended(const std::string &username, bool persistence, uint8_t timeout); void enrollExtended(const std::string &username, bool strictMode, bool persistence, uint8_t timeout);
Q_INVOKABLE void deleteUser(uint16_t userid); Q_INVOKABLE void deleteUser(uint16_t userid);
Q_INVOKABLE void deleteAll(); Q_INVOKABLE void deleteAll();
Q_INVOKABLE void requestUniqueId(); Q_INVOKABLE void requestUniqueId();
@ -200,7 +206,7 @@ signals:
void newPalmFeature(const PalmFeature &feature); void newPalmFeature(const PalmFeature &feature);
void newImageInfo(MessageId id, uint32_t size, const uint8_t *md5); void newImageInfo(MessageId id, uint32_t size, const uint8_t *md5);
void newImageSliceData(const std::vector<uint8_t> &data); void newImageSliceData(const std::vector<uint8_t> &data);
void errorOccurred(const QString &error); void errorOccurred(NoteId note, const QString &error, const QString &detailMessage = "");
void commandStarted(ModuleCommunication::MessageId messageId); void commandStarted(ModuleCommunication::MessageId messageId);
void commandFinished(MessageId messageId, MessageStatus status); void commandFinished(MessageId messageId, MessageStatus status);
void currentMessageIdChanged(); void currentMessageIdChanged();

View File

@ -1,287 +0,0 @@
#include "Widget.h"
#include "Application.h"
#include "BoostLog.h"
#include "CategoryLogSinkBackend.h"
#include "Database.h"
#include "ModuleCommunication.h"
#include "PalmFeatureTableModel.h"
#include <QComboBox>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSerialPortInfo>
#include <QTabWidget>
#include <QTableView>
#include <QTextBrowser>
#include <QTimer>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent) : QWidget{parent} {
auto serialGroupBox = new QGroupBox("串口设置");
auto serialLayout = new QGridLayout();
auto label = new QLabel("端口");
serialLayout->addWidget(label, 0, 0);
m_serialComboBox = new QComboBox();
serialLayout->addWidget(m_serialComboBox, 0, 1);
label = new QLabel("波特率");
serialLayout->addWidget(label, 1, 0);
label = new QLabel("115200");
serialLayout->addWidget(label, 1, 1);
auto refreshButton = new QPushButton("刷新");
connect(refreshButton, &QPushButton::clicked, this, &Widget::onSerialRefreshButtonClicked);
m_serialConnectButton = new QPushButton("连接");
connect(m_serialConnectButton, &QPushButton::clicked, this, &Widget::onSerialConnectButtonClicked);
serialLayout->addWidget(refreshButton, 2, 0);
serialLayout->addWidget(m_serialConnectButton, 2, 1);
serialGroupBox->setLayout(serialLayout);
auto connectLayout = new QHBoxLayout();
connectLayout->addWidget(serialGroupBox);
connectLayout->addWidget(initializeUvcGroupBox());
m_logBrowser = new QTextBrowser();
m_logBrowser->setReadOnly(true);
auto logLayout = new QVBoxLayout();
m_logBrowser->setLayout(logLayout);
auto btn = new QPushButton("清空");
connect(btn, &QPushButton::clicked, this, &Widget::onClearLogButtonClicked);
logLayout->addWidget(btn, 0, Qt::AlignBottom | Qt::AlignRight);
m_featureTableView = new QTableView();
auto tabWidget = new QTabWidget();
tabWidget->addTab(m_logBrowser, "日志");
tabWidget->addTab(new QWidget(), "视频流");
tabWidget->addTab(m_featureTableView, "本地特征值列表");
m_commandGroupBox = initializeCommandGroupBox();
auto operatorLayout = new QVBoxLayout();
operatorLayout->addLayout(connectLayout);
operatorLayout->addWidget(m_commandGroupBox);
operatorLayout->addStretch(2);
auto layout = new QHBoxLayout(this);
layout->addLayout(operatorLayout, 1);
layout->addWidget(tabWidget, 3);
m_featureModel = new PalmFeatureTableModel(this);
m_featureTableView->setModel(m_featureModel);
QTimer::singleShot(0, this, [this]() {
onSerialRefreshButtonClicked();
m_commandGroupBox->setEnabled(false);
});
}
QGroupBox *Widget::initializeCommandGroupBox() {
auto ret = new QGroupBox("命令");
auto layout = new QGridLayout();
layout->addWidget(initializeEnrollGroupBox(), 0, 0);
layout->addWidget(initializeVerifyGroupBox(), 0, 1);
layout->addWidget(initializeDeleteGroupBox(), 1, 0);
layout->addWidget(initializePalmFeatureGroupBox(), 1, 1);
auto resetButton = new QPushButton("复位");
connect(resetButton, &QPushButton::clicked, this, &Widget::onResetButtonClicked);
layout->addWidget(resetButton, 2, 0);
ret->setLayout(layout);
return ret;
}
void Widget::onClearLogButtonClicked() {
m_logBrowser->clear();
}
QGroupBox *Widget::initializeEnrollGroupBox() {
auto ret = new QGroupBox("注册用户");
auto layout = new QFormLayout();
m_enrollNameEdit = new QLineEdit();
layout->addRow("用户姓名:", m_enrollNameEdit);
m_enrollTimeoutEdit = new QLineEdit("10");
layout->addRow("超时时间:", m_enrollTimeoutEdit);
m_enrollButton = new QPushButton("注册");
connect(m_enrollButton, &QPushButton::clicked, this, &Widget::onEnrollButtonClicked);
layout->addRow("", m_enrollButton);
auto enrollExButton = new QPushButton("注册(EX)");
connect(enrollExButton, &QPushButton::clicked, this, &Widget::onEnrollExButtonClicked);
layout->addRow("", enrollExButton);
ret->setLayout(layout);
return ret;
}
QGroupBox *Widget::initializeVerifyGroupBox() {
auto ret = new QGroupBox("识别用户");
auto layout = new QFormLayout();
m_verifyTimeoutEdit = new QLineEdit("10");
layout->addRow("超时时间:", m_verifyTimeoutEdit);
m_verifyButton = new QPushButton("识别");
connect(m_verifyButton, &QPushButton::clicked, this, &Widget::onVerifyButtonClicked);
layout->addRow("", m_verifyButton);
ret->setLayout(layout);
return ret;
}
QGroupBox *Widget::initializeDeleteGroupBox() {
auto ret = new QGroupBox("删除用户");
auto layout = new QFormLayout();
m_deleteIdEdit = new QLineEdit("");
layout->addRow("用户ID:", m_deleteIdEdit);
m_deleteButton = new QPushButton("删除");
connect(m_deleteButton, &QPushButton::clicked, this, &Widget::onDeleteButtonClicked);
layout->addRow("", m_deleteButton);
m_deleteAllButton = new QPushButton("删除所有");
connect(m_deleteAllButton, &QPushButton::clicked, this, &Widget::onDeleteAllButtonClicked);
layout->addRow("", m_deleteAllButton);
ret->setLayout(layout);
return ret;
}
QGroupBox *Widget::initializePalmFeatureGroupBox() {
auto ret = new QGroupBox("特征值下发/上报");
auto layout = new QFormLayout();
m_palmFeatureEdit = new QLineEdit("");
layout->addRow("用户ID:", m_palmFeatureEdit);
auto button1 = new QPushButton("特征值上报");
layout->addRow("", button1);
connect(button1, &QPushButton::clicked, this, &Widget::onRequestPalmFeatureButtonClicked);
auto button = new QPushButton("特征值下发");
connect(button, &QPushButton::clicked, this, &Widget::onRegisterPalmFeatureButtonClicked);
layout->addRow("", button);
ret->setLayout(layout);
return ret;
}
QGroupBox *Widget::initializeUvcGroupBox() {
auto ret = new QGroupBox("UVC设置");
auto uvcLayout = new QGridLayout();
auto label = new QLabel("设备名");
uvcLayout->addWidget(label, 0, 0);
auto comboBox = new QComboBox();
uvcLayout->addWidget(comboBox, 0, 1);
auto uvcRefreshButton = new QPushButton("刷新");
auto uvcConnectButton = new QPushButton("连接");
uvcLayout->addWidget(uvcRefreshButton, 1, 0);
uvcLayout->addWidget(uvcConnectButton, 1, 1);
ret->setLayout(uvcLayout);
return ret;
}
void Widget::onSerialConnectButtonClicked() {
auto button = dynamic_cast<QPushButton *>(sender());
if (button == nullptr) return;
auto text = button->text();
if (text == "连接") {
auto portName = m_serialComboBox->currentText();
auto status = Amass::Singleton<Application>::instance()->open(portName, 2000000);
if (status) {
m_commandGroupBox->setEnabled(true);
button->setText("关闭");
}
} else if (text == "关闭") {
Amass::Singleton<Application>::instance()->close();
m_commandGroupBox->setEnabled(false);
button->setText("连接");
}
}
void Widget::onSerialRefreshButtonClicked() {
m_serialComboBox->clear();
auto ports = QSerialPortInfo::availablePorts();
for (auto &port : ports) {
if (port.description() == "蓝牙链接上的标准串行") continue;
m_serialComboBox->addItem(port.portName());
}
}
void Widget::onUvcRefreshButtonClicked() {
}
void Widget::onEnrollButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
auto name = m_enrollNameEdit->text();
auto timeout = m_enrollTimeoutEdit->text().toInt();
module->enroll(name.toStdString(), true, timeout);
}
void Widget::onEnrollExButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
auto name = m_enrollNameEdit->text();
auto timeout = m_enrollTimeoutEdit->text().toInt();
module->enrollExtended(name.toStdString(), true, timeout);
}
void Widget::onVerifyButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
auto timeout = m_verifyTimeoutEdit->text().toInt();
module->verify(timeout);
}
void Widget::onDeleteAllButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
module->deleteAll();
}
void Widget::onDeleteButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
auto id = m_deleteIdEdit->text().toInt();
module->deleteUser(id);
}
void Widget::onRequestPalmFeatureButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
auto id = m_palmFeatureEdit->text().toInt();
}
void Widget::onRegisterPalmFeatureButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
// auto features = m_database->palmFeatures();
// if (features.empty()) {
// LOG(error) << "feature is empty.";
// return;
// }
}
void Widget::onResetButtonClicked() {
auto module = Amass::Singleton<Application>::instance()->module();
if (!module) return;
module->reset();
}
void Widget::onNewLog(const QString &log) {
m_logBrowser->append(log);
}

View File

@ -1,70 +0,0 @@
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <fstream>
class QPushButton;
class QTextBrowser;
class QComboBox;
class QLineEdit;
class QGroupBox;
class QTableView;
class ModuleCommunication;
class PalmFeatureTableModel;
class Database;
class Widget : public QWidget {
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
void onNewLog(const QString &log);
protected:
QGroupBox *initializeCommandGroupBox();
void onClearLogButtonClicked();
void onSerialConnectButtonClicked();
void onSerialRefreshButtonClicked();
void onUvcRefreshButtonClicked();
void onEnrollButtonClicked();
void onEnrollExButtonClicked();
void onVerifyButtonClicked();
void onDeleteAllButtonClicked();
void onDeleteButtonClicked();
void onRequestPalmFeatureButtonClicked();
void onRegisterPalmFeatureButtonClicked();
void onResetButtonClicked();
QGroupBox *initializeEnrollGroupBox();
QGroupBox *initializeVerifyGroupBox();
QGroupBox *initializeDeleteGroupBox();
QGroupBox *initializePalmFeatureGroupBox();
QGroupBox *initializeUvcGroupBox();
private:
QComboBox *m_serialComboBox = nullptr;
QPushButton *m_serialConnectButton = nullptr;
QTextBrowser *m_logBrowser = nullptr;
QGroupBox *m_commandGroupBox = nullptr;
QLineEdit *m_enrollNameEdit = nullptr;
QLineEdit *m_enrollTimeoutEdit = nullptr;
QPushButton *m_enrollButton = nullptr;
QLineEdit *m_verifyTimeoutEdit = nullptr;
QPushButton *m_verifyButton = nullptr;
QLineEdit *m_deleteIdEdit = nullptr;
QPushButton *m_deleteButton = nullptr;
QPushButton *m_deleteAllButton = nullptr;
QLineEdit *m_palmFeatureEdit = nullptr;
PalmFeatureTableModel *m_featureModel = nullptr;
QTableView *m_featureTableView = nullptr;
};
#endif // WIDGET_H

View File

@ -2,7 +2,7 @@
#include "BoostLog.h" #include "BoostLog.h"
#include "Configuration.h" #include "Configuration.h"
#include "DeviceDiscovery.h" #include "DeviceDiscovery.h"
#include "Widget.h" #include <QQuickStyle>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
using namespace Amass; using namespace Amass;
@ -10,16 +10,8 @@ int main(int argc, char *argv[]) {
LOG(info) << "Compiled on: " << __DATE__ << " " << __TIME__ << std::endl; LOG(info) << "Compiled on: " << __DATE__ << " " << __TIME__ << std::endl;
LOG(info) << "Git commit ID: " << GIT_COMMIT_ID << std::endl; LOG(info) << "Git commit ID: " << GIT_COMMIT_ID << std::endl;
LOG(info) << "Program version: " << APP_VERSION << std::endl; LOG(info) << "Program version: " << APP_VERSION << std::endl;
QQuickStyle::setStyle("Basic"); // Basic Material
auto app = Singleton<Application>::instance<Construct>(argc, argv); auto app = Singleton<Application>::instance<Construct>(argc, argv);
app->initializeLogger(); app->initializeLogger();
// Widget w;
// w.setWindowTitle("L015上位机工具");
// w.setMinimumWidth(1120);
// w.setMinimumHeight(640);
// w.show();
// QObject::connect(app.get(), &Application::newLog, &w, &Widget::onNewLog);
return app->exec(); return app->exec();
} }

View File

@ -15,7 +15,7 @@ RowLayout {
ComboBox { ComboBox {
id: serialPort id: serialPort
enabled: !App.connected enabled: !App.connected
implicitWidth: 100 implicitWidth: 116
} }
Text { Text {
@ -25,7 +25,7 @@ RowLayout {
ComboBox { ComboBox {
id: baudrate id: baudrate
enabled: !App.connected enabled: !App.connected
implicitWidth: 110 implicitWidth: 116
model: ["2000000", "115200"] model: ["2000000", "115200"]
} }

View File

@ -1,17 +1,19 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Fluent as Fluent
import Analyser import Analyser
Window { Window {
width: 1120 id: window
height: 770 width: 1220
height: 890
visible: true visible: true
title: qsTr(Qt.application.name + " " + Qt.application.version) title: qsTr(Qt.application.name + " " + Qt.application.version)
OperationItem { OperationItem {
id: operationItem id: operationItem
width: 450 width: 510
anchors.top: parent.top anchors.top: parent.top
} }
@ -98,22 +100,29 @@ Window {
} }
} }
Fluent.InfoBar{
id:info_bar
root: window
layoutY: 10
}
Connections { Connections {
target: App target: App
function onNewLog(text) { function onNewLog(text) {
logBrowser.append(text) logBrowser.append(text)
} }
function onNewStatusTip(level, tip) { function onNewStatusTip(level, tip, detailMessage) {
if (level === 0) { if (level === App.Tip) {
statusTip.icon = "../resources/successfull.svg" info_bar.showSuccess(tip,2000,detailMessage)
statusTip.color = "#EBF8ED" } else if (level === App.Warnging) {
statusTip.show(tip, 2000) info_bar.showWarning(tip,2000,detailMessage)
} else if (level === 1) { } else if (level === 1) {
statusTip.icon = "../resources/warning.svg" statusTip.icon = "../resources/warning.svg"
statusTip.color = "#FAFAD2" statusTip.color = "#FAFAD2"
statusTip.show(tip, 2000) statusTip.show(tip, 2000)
} else if (level === 2) { } else if (level === 2) {
resultBrowser.append(tip) info_bar.showInfo(tip,2000,detailMessage)
resultBrowser.append(tip+":"+detailMessage)
} }
} }
function onNewVideoFrame() { function onNewVideoFrame() {
@ -121,11 +130,4 @@ Window {
image.source = "image://videoframe/" image.source = "image://videoframe/"
} }
} }
StatusTip {
id: statusTip
width: 200
height: 50
icon: "../resources/successfull.svg"
}
} }

View File

@ -32,23 +32,29 @@ Item {
title: "注册用户" title: "注册用户"
GridLayout { GridLayout {
columns: 2 columns: 2
Text { Label {
text: qsTr("用户姓名") text: qsTr("用户姓名")
} }
TextField { TextField {
id: enrollName id: enrollName
implicitWidth: 100 implicitWidth: 100
} }
Text { Label {
text: qsTr("严格模式")
}
Switch {
id: strictMode
}
Label {
text: qsTr("超时时间") text: qsTr("超时时间")
} }
TextField { TextField {
id: enrollTimeout id: enrollTimeout
implicitWidth: 100 implicitWidth: 100
text: "10" text: "30"
} }
Text { Label {
text: qsTr("持久化") text: qsTr("持久化")
} }
Switch { Switch {
@ -56,7 +62,7 @@ Item {
checked: true checked: true
} }
Text { Label {
text: qsTr("保存图片") text: qsTr("保存图片")
} }
Switch { Switch {
@ -70,14 +76,9 @@ Item {
if (enrolling) { if (enrolling) {
App.module.reset() App.module.reset()
} else if (extendedMode.checked) { } else if (extendedMode.checked) {
App.enrollExtended( App.enrollExtended(enrollName.text, strictMode.checked, persistence.checked, parseInt(enrollTimeout.text))
enrollName.text,
persistence.checked,
parseInt(enrollTimeout.text))
} else { } else {
App.enroll(enrollName.text, App.enroll(enrollName.text, strictMode.checked, persistence.checked, parseInt(enrollTimeout.text))
persistence.checked,
parseInt(enrollTimeout.text))
} }
} }
} }
@ -87,7 +88,7 @@ Item {
title: "识别用户" title: "识别用户"
GridLayout { GridLayout {
columns: 2 columns: 2
Text { Label {
text: qsTr("超时时间(s)") text: qsTr("超时时间(s)")
} }
TextField { TextField {
@ -95,20 +96,20 @@ Item {
implicitWidth: 80 implicitWidth: 80
text: "10" text: "10"
} }
Text { Label {
text: qsTr("持续识别") text: qsTr("持续识别")
} }
Switch { Switch {
checked: App.persistenceMode checked: App.persistenceMode
onToggled: App.persistenceMode = !App.persistenceMode onToggled: App.persistenceMode = !App.persistenceMode
} }
Text { Label {
text: qsTr("保存图片") text: qsTr("保存图片")
} }
Switch { Switch {
id: extendedVerifyMode id: extendedVerifyMode
} }
Text { Label {
text: qsTr("识别间隔(s)") text: qsTr("识别间隔(s)")
} }
TextField { TextField {
@ -132,11 +133,13 @@ Item {
} }
} }
} }
Column {
GroupBox { GroupBox {
title: "删除用户" title: "删除用户"
GridLayout { GridLayout {
columns: 2 columns: 2
Text { Label {
text: qsTr("用户ID") text: qsTr("用户ID")
} }
TextField { TextField {
@ -155,46 +158,8 @@ Item {
} }
} }
GroupBox { GroupBox {
title: "图片注册"
visible: true
GridLayout { GridLayout {
columns: 2 columns: 2
TextField {
id: imagePath
Layout.columnSpan: 2
implicitWidth: 200
placeholderText: "请选择图片"
onPressed: {
fileDialog.open()
}
}
Text {
text: qsTr("用户姓名")
}
TextField {
id: imageEnrollName
implicitWidth: 100
text: "测试下发"
}
Text {
text: qsTr("循环")
}
Switch {
checked: App.imageUploadPersistenceMode
onToggled: {
App.imageUploadPersistenceMode = checked
}
}
Button {
text: "注册"
onClicked: App.uploadImage(imagePath.text,imageEnrollName.text, 0)
}
Button {
text: "识别"
onClicked: App.uploadImage(imagePath.text,imageEnrollName.text, 1)
}
}
}
Button { Button {
text: "复位" text: "复位"
onClicked: App.module.reset() onClicked: App.module.reset()
@ -213,7 +178,7 @@ Item {
onClicked: loader.active = true onClicked: loader.active = true
} }
Row { Row {
Text { Label {
text: qsTr("日志") text: qsTr("日志")
} }
Switch { Switch {
@ -224,6 +189,50 @@ Item {
} }
} }
} }
GroupBox {
title: "图片注册"
visible: true
GridLayout {
columns: 2
TextField {
id: imagePath
Layout.columnSpan: 2
implicitWidth: 200
placeholderText: "请选择图片"
onPressed: {
fileDialog.open()
}
}
Label {
text: qsTr("用户姓名")
}
TextField {
id: imageEnrollName
implicitWidth: 100
text: "测试下发"
}
Label {
text: qsTr("循环")
}
Switch {
checked: App.imageUploadPersistenceMode
onToggled: {
App.imageUploadPersistenceMode = checked
}
}
Button {
text: "注册"
onClicked: App.uploadImage(imagePath.text,imageEnrollName.text, 0)
}
Button {
text: "识别"
onClicked: App.uploadImage(imagePath.text,imageEnrollName.text, 1)
}
}
}
}
}
}
FileDialog { FileDialog {
id: fileDialog id: fileDialog
nameFilters: ["图片 (*.jpg *.yuv)"] nameFilters: ["图片 (*.jpg *.yuv)"]

View File

@ -1,56 +0,0 @@
import QtQuick
import QtQuick.Controls
Popup{
id: control
property alias text: textItem.text
property alias icon: image.source
property alias color: back.color
property string borderColor
x: (parent.width-200)/2
y: 40
width: 200
height: 32
font.pixelSize: 16
contentItem: Row{
leftPadding: 4
spacing: 9.6
Image {
id: image
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: textItem
anchors.verticalCenter: parent.verticalCenter
text: control.text
font: control.font
color: "#666666"
}
}
background: Rectangle {
id:back
anchors.fill: parent
color: "#EBF8ED"
radius: 3.2
border.width: 1
border.color: control.borderColor
layer.enabled: true
}
Timer {
id: timer
repeat: false
onTriggered: control.visible=false
}
function show(text,timeout){
control.text = text
timer.interval = timeout
timer.restart();
control.visible=true
}
}

View File

@ -61,7 +61,7 @@ HOST_TOOLS := /opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.6.1/bin
# 编译OTA固件11为OTA版本号,这个版本号只做固件文件名显示。 # 编译OTA固件11为OTA版本号,这个版本号只做固件文件名显示。
# 实际的版本设置在 cv181x_alios/solutions/smart_doorbell/package.yaml.L015_V200R002 # 实际的版本设置在 cv181x_alios/solutions/smart_doorbell/package.yaml.L015_V200R002
./rebuild-app-ota.sh y L015 V200 R002 02 ./rebuild-app-ota.sh y L015 V200 R002 03
600X800 600X800
``` ```