1.实现掌静脉注册时保存图片的实现。
This commit is contained in:
parent
e588d4abdf
commit
59281e3a75
@ -4,7 +4,10 @@
|
|||||||
#include "CategoryLogSinkBackend.h"
|
#include "CategoryLogSinkBackend.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
#include "DateTime.h"
|
||||||
#include "DeviceDiscovery.h"
|
#include "DeviceDiscovery.h"
|
||||||
|
#include "ImageDecoder.h"
|
||||||
|
#include "StringUtility.h"
|
||||||
#include "VideoFrameProvider.h"
|
#include "VideoFrameProvider.h"
|
||||||
#include "VideoPlayer.h"
|
#include "VideoPlayer.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@ -13,6 +16,7 @@
|
|||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QSerialPortInfo>
|
#include <QSerialPortInfo>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
|
|
||||||
@ -39,6 +43,12 @@ Application::Application(int &argc, char **argv) : m_app(std::make_shared<QAppli
|
|||||||
m_videoFrameProvider = new VideoFrameProvider();
|
m_videoFrameProvider = new VideoFrameProvider();
|
||||||
|
|
||||||
qmlRegisterSingletonInstance("Analyser", 1, 0, "App", this);
|
qmlRegisterSingletonInstance("Analyser", 1, 0, "App", this);
|
||||||
|
if (!std::filesystem::exists(JpgPath)) {
|
||||||
|
std::filesystem::create_directory(JpgPath);
|
||||||
|
}
|
||||||
|
if (!std::filesystem::exists(YuvPath)) {
|
||||||
|
std::filesystem::create_directory(YuvPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::onNewVerifyResult(uint16_t userid, const QString &username, uint16_t elapsed) {
|
void Application::onNewVerifyResult(uint16_t userid, const QString &username, uint16_t elapsed) {
|
||||||
@ -157,11 +167,12 @@ void Application::verify(uint8_t timeout) {
|
|||||||
m_communication->verify(timeout);
|
m_communication->verify(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::enroll(const QString &username, uint8_t timeout) {
|
void Application::enroll(const QString &username, 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(), timeout);
|
m_communication->enroll(username.toStdString(), persistence, timeout);
|
||||||
|
m_enrollUsername = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::deleteUser(uint16_t userid) {
|
void Application::deleteUser(uint16_t userid) {
|
||||||
@ -178,23 +189,32 @@ void Application::deleteAll() {
|
|||||||
m_communication->deleteAll();
|
m_communication->deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::getEnrolledImage(const QString &username, uint8_t timeout) {
|
void Application::enrollExtended(const QString &username, 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->enrollEx(username.toStdString(), timeout);
|
m_communication->enrollExtended(username.toStdString(), persistence, timeout);
|
||||||
|
m_enrollUsername = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::uploadImage() {
|
void Application::uploadImage() {
|
||||||
m_uploadImageSendedSize = 0;
|
m_uploadImageSendedSize = 0;
|
||||||
std::ifstream ifs("palm.yuv", std::ofstream::binary);
|
|
||||||
m_uploadBuffer = std::vector<char>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
// std::ifstream ifs("palm.yuv", std::ofstream::binary);
|
||||||
|
// m_uploadBuffer = std::vector<char>((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
|
auto image = ImageDecoder::extractJpegYComponent("E:/Downloads/7207002051849490432.jpg");
|
||||||
|
if (!image) {
|
||||||
|
LOG(error) << "decode failed.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_uploadBuffer = image->data;
|
||||||
|
LOG(info) << "width: " << image->width << ", height: " << image->height;
|
||||||
|
|
||||||
ModuleCommunication::UploadImageInformation request;
|
ModuleCommunication::UploadImageInformation request;
|
||||||
mbedtls_md5_context context;
|
mbedtls_md5_context context;
|
||||||
mbedtls_md5_init(&context);
|
mbedtls_md5_init(&context);
|
||||||
mbedtls_md5_starts(&context);
|
mbedtls_md5_starts(&context);
|
||||||
mbedtls_md5_update(&context, reinterpret_cast<const uint8_t *>(m_uploadBuffer.data()), m_uploadBuffer.size());
|
mbedtls_md5_update(&context, m_uploadBuffer.data(), m_uploadBuffer.size());
|
||||||
mbedtls_md5_finish(&context, request.md5);
|
mbedtls_md5_finish(&context, request.md5);
|
||||||
mbedtls_md5_free(&context);
|
mbedtls_md5_free(&context);
|
||||||
|
|
||||||
@ -283,14 +303,21 @@ void Application::onNewImageSliceData(const std::vector<uint8_t> &data) {
|
|||||||
if (m_enrollYImageBuffer.size() < m_enrolledImageSize) {
|
if (m_enrollYImageBuffer.size() < m_enrolledImageSize) {
|
||||||
m_communication->requestEnrolledImage(m_enrollYImageBuffer.size(), ImageSliceSize);
|
m_communication->requestEnrolledImage(m_enrollYImageBuffer.size(), ImageSliceSize);
|
||||||
} else {
|
} else {
|
||||||
LOG(info) << "request finished, elapsed: "
|
auto username = m_enrollUsername.toStdString();
|
||||||
<< duration_cast<milliseconds>(system_clock::now() - m_startUploadTime);
|
LOG(info) << "request finished, username: " << username
|
||||||
|
<< ", elapsed: " << duration_cast<milliseconds>(system_clock::now() - m_startUploadTime);
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << YuvPath << "/" << username << "_" << DateTime::toString(std::chrono::system_clock::now(), "%Y%m%d%H%M%S")
|
||||||
|
<< ".yuv";
|
||||||
|
std::ofstream ofs(Amass::StringUtility::UTF8ToGBK(oss.str()), std::ofstream::binary);
|
||||||
|
ofs.write(m_enrollYImageBuffer.data(), m_enrollYImageBuffer.size());
|
||||||
|
|
||||||
QImage image(reinterpret_cast<const uint8_t *>(m_enrollYImageBuffer.data()), 600, 800,
|
QImage image(reinterpret_cast<const uint8_t *>(m_enrollYImageBuffer.data()), 600, 800,
|
||||||
QImage::Format_Grayscale8);
|
QImage::Format_Grayscale8);
|
||||||
image.save("test.jpg");
|
oss.str("");
|
||||||
|
oss << JpgPath << "/" << username << "_" << DateTime::toString(std::chrono::system_clock::now(), "%Y%m%d%H%M%S")
|
||||||
std::ofstream ofs("palm.yuv", std::ofstream::binary);
|
<< ".jpg";
|
||||||
ofs.write(m_enrollYImageBuffer.data(), m_enrollYImageBuffer.size());
|
image.save(QString::fromStdString(oss.str()), "jpg", 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +331,8 @@ void Application::onCommandFinished(ModuleCommunication::MessageId messageId,
|
|||||||
// LOG(info) << m_persistenceMode << " " << m_persistenceModeStarted << " " << m_persistenceVerifyInterval;
|
// LOG(info) << m_persistenceMode << " " << m_persistenceModeStarted << " " << m_persistenceVerifyInterval;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
if (messageId == ModuleCommunication::UploadImageInfo) {
|
if (messageId == ModuleCommunication::UploadImageInfo) {
|
||||||
m_communication->uploadImageData(
|
m_communication->uploadImageData(m_uploadImageSendedSize, m_uploadBuffer.data() + m_uploadImageSendedSize,
|
||||||
m_uploadImageSendedSize, (const uint8_t *)m_uploadBuffer.data() + m_uploadImageSendedSize, ImageSliceSize);
|
ImageSliceSize);
|
||||||
} else if (messageId == ModuleCommunication::UploadImageData) {
|
} else if (messageId == ModuleCommunication::UploadImageData) {
|
||||||
m_uploadImageSendedSize += ImageSliceSize;
|
m_uploadImageSendedSize += ImageSliceSize;
|
||||||
if (m_uploadImageSendedSize < m_uploadBuffer.size()) {
|
if (m_uploadImageSendedSize < m_uploadBuffer.size()) {
|
||||||
@ -332,7 +359,8 @@ void Application::onCommandFinished(ModuleCommunication::MessageId messageId,
|
|||||||
m_verifyTimer->start(m_persistenceVerifyInterval * 1000);
|
m_verifyTimer->start(m_persistenceVerifyInterval * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((messageId == ModuleCommunication::EnrollSingle) && (status == ModuleCommunication::Success)) {
|
if (((messageId == ModuleCommunication::EnrollSingle) || (messageId == ModuleCommunication::EnrollExtended)) &&
|
||||||
|
(status == ModuleCommunication::Success)) {
|
||||||
emit newStatusTip(Info, "录入成功。");
|
emit newStatusTip(Info, "录入成功。");
|
||||||
}
|
}
|
||||||
emit isVerifyingChanged();
|
emit isVerifyingChanged();
|
||||||
|
@ -25,6 +25,8 @@ class Application : public QObject {
|
|||||||
persistenceVerifyIntervalChanged)
|
persistenceVerifyIntervalChanged)
|
||||||
Q_PROPERTY(bool isVerifying READ isVerifying NOTIFY isVerifyingChanged)
|
Q_PROPERTY(bool isVerifying READ isVerifying NOTIFY isVerifyingChanged)
|
||||||
friend class Amass::Singleton<Application>;
|
friend class Amass::Singleton<Application>;
|
||||||
|
static constexpr auto JpgPath = "jpg";
|
||||||
|
static constexpr auto YuvPath = "yuv";
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum TipType {
|
enum TipType {
|
||||||
@ -43,10 +45,10 @@ public:
|
|||||||
Q_INVOKABLE void close();
|
Q_INVOKABLE void close();
|
||||||
Q_INVOKABLE void closeUVC();
|
Q_INVOKABLE void closeUVC();
|
||||||
Q_INVOKABLE void verify(uint8_t timeout);
|
Q_INVOKABLE void verify(uint8_t timeout);
|
||||||
Q_INVOKABLE void enroll(const QString &username, 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 deleteUser(uint16_t userid);
|
Q_INVOKABLE void deleteUser(uint16_t userid);
|
||||||
Q_INVOKABLE void deleteAll();
|
Q_INVOKABLE void deleteAll();
|
||||||
Q_INVOKABLE void getEnrolledImage(const QString &username, uint8_t timeout);
|
|
||||||
Q_INVOKABLE void uploadImage();
|
Q_INVOKABLE void uploadImage();
|
||||||
ModuleCommunication *module() const;
|
ModuleCommunication *module() const;
|
||||||
bool connected() const;
|
bool connected() const;
|
||||||
@ -90,11 +92,12 @@ private:
|
|||||||
QTimer *m_verifyTimer = nullptr;
|
QTimer *m_verifyTimer = nullptr;
|
||||||
|
|
||||||
uint32_t m_enrolledImageSize = 0;
|
uint32_t m_enrolledImageSize = 0;
|
||||||
|
QString m_enrollUsername;
|
||||||
QByteArray m_enrollYImageBuffer;
|
QByteArray m_enrollYImageBuffer;
|
||||||
std::chrono::system_clock::time_point m_startUploadTime;
|
std::chrono::system_clock::time_point m_startUploadTime;
|
||||||
|
|
||||||
uint32_t m_uploadImageSendedSize;
|
uint32_t m_uploadImageSendedSize;
|
||||||
std::vector<char> m_uploadBuffer;
|
std::vector<uint8_t> m_uploadBuffer;
|
||||||
|
|
||||||
std::shared_ptr<VideoPlayer> m_videoPlayer;
|
std::shared_ptr<VideoPlayer> m_videoPlayer;
|
||||||
VideoFrameProvider *m_videoFrameProvider;
|
VideoFrameProvider *m_videoFrameProvider;
|
||||||
|
@ -4,8 +4,8 @@ set(APPLICATION_NAME "掌静脉测试工具")
|
|||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort)
|
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort JpegPrivate BundledLibjpeg)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick QuickTemplates2 Widgets SerialPort JpegPrivate BundledLibjpeg)
|
||||||
|
|
||||||
configure_file(Configuration.h.in Configuration.h)
|
configure_file(Configuration.h.in Configuration.h)
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ add_executable(Analyser Analyser.rc
|
|||||||
main.cpp
|
main.cpp
|
||||||
Application.h Application.cpp
|
Application.h Application.cpp
|
||||||
CategoryLogSinkBackend.h CategoryLogSinkBackend.cpp
|
CategoryLogSinkBackend.h CategoryLogSinkBackend.cpp
|
||||||
|
ImageDecoder.h ImageDecoder.cpp
|
||||||
Widget.h Widget.cpp
|
Widget.h Widget.cpp
|
||||||
ModuleCommunication.h ModuleCommunication.cpp
|
ModuleCommunication.h ModuleCommunication.cpp
|
||||||
PalmFeatureTableModel.h PalmFeatureTableModel.cpp
|
PalmFeatureTableModel.h PalmFeatureTableModel.cpp
|
||||||
@ -67,4 +68,6 @@ target_link_libraries(Analyser
|
|||||||
PRIVATE Qt${QT_VERSION_MAJOR}::QuickTemplates2
|
PRIVATE Qt${QT_VERSION_MAJOR}::QuickTemplates2
|
||||||
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
|
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}::BundledLibjpeg
|
||||||
)
|
)
|
||||||
|
41
Analyser/ImageDecoder.cpp
Normal file
41
Analyser/ImageDecoder.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "ImageDecoder.h"
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
std::optional<ImageDecoder::Image> ImageDecoder::extractJpegYComponent(const std::string &filename) {
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
struct jpeg_error_mgr jerr;
|
||||||
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
|
jpeg_create_decompress(&cinfo);
|
||||||
|
|
||||||
|
FILE *infile = fopen(filename.c_str(), "rb");
|
||||||
|
if (infile == NULL) {
|
||||||
|
LOG(error) << "cannot open " << filename;
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
ImageDecoder::Image ret;
|
||||||
|
jpeg_stdio_src(&cinfo, infile);
|
||||||
|
jpeg_read_header(&cinfo, TRUE);
|
||||||
|
cinfo.out_color_space = JCS_YCbCr; // We want YCbCr color space
|
||||||
|
jpeg_start_decompress(&cinfo);
|
||||||
|
|
||||||
|
int row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
|
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||||
|
|
||||||
|
ret.width = cinfo.output_width;
|
||||||
|
ret.height = cinfo.output_height;
|
||||||
|
ret.data.resize(ret.width * ret.height);
|
||||||
|
while (cinfo.output_scanline < cinfo.output_height) {
|
||||||
|
jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||||
|
for (unsigned int i = 0; i < cinfo.output_width; ++i) {
|
||||||
|
ret.data[(cinfo.output_scanline - 1) * cinfo.output_width + i] =
|
||||||
|
buffer[0][i * 3]; // Y component is the first byte in YCbCr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_finish_decompress(&cinfo);
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
return std::make_optional(ret);
|
||||||
|
}
|
18
Analyser/ImageDecoder.h
Normal file
18
Analyser/ImageDecoder.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __IMAGEDECODER_H__
|
||||||
|
#define __IMAGEDECODER_H__
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ImageDecoder {
|
||||||
|
public:
|
||||||
|
struct Image {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
};
|
||||||
|
static std::optional<Image> extractJpegYComponent(const std::string &filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __IMAGEDECODER_H__
|
@ -53,9 +53,10 @@ void ModuleCommunication::reset() {
|
|||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleCommunication::enroll(const std::string &username, uint8_t timeout) {
|
void ModuleCommunication::enroll(const std::string &username, bool persistence, uint8_t timeout) {
|
||||||
EnrollData data = {0};
|
EnrollData data = {0};
|
||||||
data.timeout = timeout;
|
data.timeout = timeout;
|
||||||
|
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));
|
||||||
auto [frameData, frameSize] = generateFrame(EnrollSingle, reinterpret_cast<const uint8_t *>(&data), sizeof(data));
|
auto [frameData, frameSize] = generateFrame(EnrollSingle, reinterpret_cast<const uint8_t *>(&data), sizeof(data));
|
||||||
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
@ -66,11 +67,12 @@ void ModuleCommunication::enroll(const std::string &username, uint8_t timeout) {
|
|||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleCommunication::enrollEx(const std::string &username, uint8_t timeout) {
|
void ModuleCommunication::enrollExtended(const std::string &username, bool persistence, uint8_t timeout) {
|
||||||
EnrollData data = {0};
|
EnrollData data = {0};
|
||||||
data.timeout = timeout;
|
data.timeout = timeout;
|
||||||
|
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));
|
||||||
auto [frameData, frameSize] = generateFrame(EnrollGetImage, reinterpret_cast<const uint8_t *>(&data), sizeof(data));
|
auto [frameData, frameSize] = generateFrame(EnrollExtended, reinterpret_cast<const uint8_t *>(&data), sizeof(data));
|
||||||
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
|
|
||||||
LOG_CAT(info, GUI) << "发送获取注册照片指令: " << protocolDataFormatString(frameData, frameSize);
|
LOG_CAT(info, GUI) << "发送获取注册照片指令: " << protocolDataFormatString(frameData, frameSize);
|
||||||
@ -176,6 +178,13 @@ void ModuleCommunication::requestCurrentStatus() {
|
|||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleCommunication::requestUniqueId() {
|
||||||
|
auto [frameData, frameSize] = generateFrame(GetUniqueID);
|
||||||
|
m_serialPort->write(reinterpret_cast<const char *>(frameData), frameSize);
|
||||||
|
LOG_CAT(info, GUI) << "发送获取ID指令: " << protocolDataFormatString(frameData, frameSize);
|
||||||
|
LOG_CAT(info, GUI) << Separator;
|
||||||
|
}
|
||||||
|
|
||||||
ModuleCommunication::MessageId ModuleCommunication::currentMessageId() const {
|
ModuleCommunication::MessageId ModuleCommunication::currentMessageId() const {
|
||||||
return m_currentMessageId;
|
return m_currentMessageId;
|
||||||
}
|
}
|
||||||
@ -236,13 +245,14 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) {
|
|||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EnrollGetImage: {
|
case EnrollExtended: {
|
||||||
LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size);
|
LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size);
|
||||||
if (result == Success) {
|
if (result == Success) {
|
||||||
auto info = reinterpret_cast<const EnrolledImageReply *>(data + 7);
|
auto info = reinterpret_cast<const EnrollExtendedReply *>(data + 7);
|
||||||
uint16_t width = ntohs(info->width);
|
uint16_t width = ntohs(info->image_width);
|
||||||
uint16_t height = ntohs(info->height);
|
uint16_t height = ntohs(info->image_height);
|
||||||
LOG_CAT(info, GUI) << "图片大小: " << width << "x" << height;
|
LOG_CAT(info, GUI) << "注册成功,用户ID: " << ntohs(info->userid) << ", 图片大小: " << width << "x"
|
||||||
|
<< height;
|
||||||
emit newEnrolledImageInfo(width * height, info->md5);
|
emit newEnrolledImageInfo(width * height, info->md5);
|
||||||
}
|
}
|
||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
@ -309,6 +319,9 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) {
|
|||||||
auto info = reinterpret_cast<const EnrollDataReply *>(data + 7);
|
auto info = reinterpret_cast<const EnrollDataReply *>(data + 7);
|
||||||
LOG_CAT(info, GUI) << "图片下发注册成功,用户ID: " << ntohs(info->userid);
|
LOG_CAT(info, GUI) << "图片下发注册成功,用户ID: " << ntohs(info->userid);
|
||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
|
} else if (result == Needmore) {
|
||||||
|
} else {
|
||||||
|
LOG(info) << "UploadImageData status: " << static_cast<uint16_t>(result);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -318,6 +331,13 @@ void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) {
|
|||||||
LOG_CAT(info, GUI) << Separator;
|
LOG_CAT(info, GUI) << Separator;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GetUniqueID: {
|
||||||
|
LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size);
|
||||||
|
auto id = reinterpret_cast<const ModuleId *>(data + 7);
|
||||||
|
LOG_CAT(info, GUI) << "模组ID: " << std::string_view(id->id, sizeof(id->id));
|
||||||
|
LOG_CAT(info, GUI) << Separator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG(warning) << "unknown reply command: 0x" << (static_cast<int>(replyId) & 0xff)
|
LOG(warning) << "unknown reply command: 0x" << (static_cast<int>(replyId) & 0xff)
|
||||||
<< ", data: " << protocolDataFormatString(data, size);
|
<< ", data: " << protocolDataFormatString(data, size);
|
||||||
|
@ -23,10 +23,11 @@ public:
|
|||||||
GetCurrentStatus = 0x11,
|
GetCurrentStatus = 0x11,
|
||||||
Verify = 0x12,
|
Verify = 0x12,
|
||||||
EnrollSingle = 0x1D,
|
EnrollSingle = 0x1D,
|
||||||
EnrollGetImage = 0x1E,
|
EnrollExtended = 0x1E,
|
||||||
GetEnrolledImage = 0x1F,
|
GetEnrolledImage = 0x1F,
|
||||||
DeleteUser = 0x20,
|
DeleteUser = 0x20,
|
||||||
DeleteAll = 0x21,
|
DeleteAll = 0x21,
|
||||||
|
GetUniqueID = 0xAC,
|
||||||
UploadImageInfo = 0xF6,
|
UploadImageInfo = 0xF6,
|
||||||
UploadImageData = 0xF7,
|
UploadImageData = 0xF7,
|
||||||
RegisterPalmFeature = 0xF9,
|
RegisterPalmFeature = 0xF9,
|
||||||
@ -57,6 +58,7 @@ public:
|
|||||||
Failed4ReadFile = 19,
|
Failed4ReadFile = 19,
|
||||||
Failed4WriteFile = 20,
|
Failed4WriteFile = 20,
|
||||||
Failed4NoEncrypt = 21,
|
Failed4NoEncrypt = 21,
|
||||||
|
Needmore = 25,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
@ -80,7 +82,7 @@ public:
|
|||||||
struct EnrollData {
|
struct EnrollData {
|
||||||
uint8_t admin = 0;
|
uint8_t admin = 0;
|
||||||
uint8_t username[32];
|
uint8_t username[32];
|
||||||
uint8_t palmDirection;
|
uint8_t skipSave = 0;
|
||||||
uint8_t timeout;
|
uint8_t timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,10 +91,11 @@ public:
|
|||||||
uint8_t face_direction; // depleted, user ignore this field
|
uint8_t face_direction; // depleted, user ignore this field
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EnrolledImageReply {
|
struct EnrollExtendedReply {
|
||||||
|
uint16_t userid;
|
||||||
|
uint16_t image_width;
|
||||||
|
uint16_t image_height;
|
||||||
uint8_t image_format; // 0: 只有Y分量,灰度图
|
uint8_t image_format; // 0: 只有Y分量,灰度图
|
||||||
uint16_t width;
|
|
||||||
uint16_t height;
|
|
||||||
uint8_t md5[16];
|
uint8_t md5[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,16 +142,21 @@ public:
|
|||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ModuleId {
|
||||||
|
char id[32];
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
explicit ModuleCommunication(QObject *parent = nullptr);
|
explicit ModuleCommunication(QObject *parent = nullptr);
|
||||||
bool open(const QString &portName, int baudRate);
|
bool open(const QString &portName, int baudRate);
|
||||||
Q_INVOKABLE void verify(uint8_t timeout);
|
Q_INVOKABLE void verify(uint8_t timeout);
|
||||||
Q_INVOKABLE void reset();
|
Q_INVOKABLE void reset();
|
||||||
|
|
||||||
void enroll(const std::string &username, uint8_t timeout);
|
void enroll(const std::string &username, bool persistence, uint8_t timeout);
|
||||||
void enrollEx(const std::string &username, uint8_t timeout);
|
void enrollExtended(const std::string &username, 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();
|
||||||
void requestEnrolledImage(uint32_t offset, uint32_t size);
|
void requestEnrolledImage(uint32_t offset, uint32_t size);
|
||||||
|
|
||||||
void requestPalmFeature(uint16_t userid);
|
void requestPalmFeature(uint16_t userid);
|
||||||
|
@ -229,7 +229,7 @@ void Widget::onEnrollButtonClicked() {
|
|||||||
if (!module) return;
|
if (!module) return;
|
||||||
auto name = m_enrollNameEdit->text();
|
auto name = m_enrollNameEdit->text();
|
||||||
auto timeout = m_enrollTimeoutEdit->text().toInt();
|
auto timeout = m_enrollTimeoutEdit->text().toInt();
|
||||||
module->enroll(name.toStdString(), timeout);
|
module->enroll(name.toStdString(), true, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onEnrollExButtonClicked() {
|
void Widget::onEnrollExButtonClicked() {
|
||||||
@ -237,7 +237,7 @@ void Widget::onEnrollExButtonClicked() {
|
|||||||
if (!module) return;
|
if (!module) return;
|
||||||
auto name = m_enrollNameEdit->text();
|
auto name = m_enrollNameEdit->text();
|
||||||
auto timeout = m_enrollTimeoutEdit->text().toInt();
|
auto timeout = m_enrollTimeoutEdit->text().toInt();
|
||||||
module->enrollEx(name.toStdString(), timeout);
|
module->enrollExtended(name.toStdString(), true, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::onVerifyButtonClicked() {
|
void Widget::onVerifyButtonClicked() {
|
||||||
|
@ -31,13 +31,40 @@ ColumnLayout {
|
|||||||
implicitWidth: 100
|
implicitWidth: 100
|
||||||
text: "10"
|
text: "10"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("持久化")
|
||||||
|
}
|
||||||
|
Switch {
|
||||||
|
id: persistence
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("保存图片")
|
||||||
|
}
|
||||||
|
Switch {
|
||||||
|
id: extendedMode
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: !App.module ? "注册" : App.module.currentMessageId
|
property bool enrolling: App.module ? (App.module.currentMessageId === 0x1d)
|
||||||
=== 0x1d ? "取消" : "注册"
|
|| (App.module.currentMessageId
|
||||||
onClicked: App.module.currentMessageId
|
=== 0x1e) : false
|
||||||
=== 0x1d ? App.module.reset() : App.enroll(
|
text: enrolling ? "取消" : "注册"
|
||||||
enrollName.text,
|
onClicked: {
|
||||||
parseInt(enrollTimeout.text))
|
if (enrolling) {
|
||||||
|
App.module.reset()
|
||||||
|
} else if (extendedMode.checked) {
|
||||||
|
App.enrollExtended(enrollName.text,
|
||||||
|
persistence.checked,
|
||||||
|
parseInt(enrollTimeout.text))
|
||||||
|
} else {
|
||||||
|
App.enroll(enrollName.text,
|
||||||
|
persistence.checked,
|
||||||
|
parseInt(enrollTimeout.text))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,10 +135,6 @@ ColumnLayout {
|
|||||||
title: "图片注册"
|
title: "图片注册"
|
||||||
GridLayout {
|
GridLayout {
|
||||||
columns: 1
|
columns: 1
|
||||||
Button {
|
|
||||||
text: "录入图片上报"
|
|
||||||
onClicked: App.getEnrolledImage("", 60)
|
|
||||||
}
|
|
||||||
Button {
|
Button {
|
||||||
text: "图片下发注册"
|
text: "图片下发注册"
|
||||||
onClicked: App.uploadImage()
|
onClicked: App.uploadImage()
|
||||||
@ -126,6 +149,10 @@ ColumnLayout {
|
|||||||
text: "状态查询"
|
text: "状态查询"
|
||||||
onClicked: App.module.requestCurrentStatus()
|
onClicked: App.module.requestCurrentStatus()
|
||||||
}
|
}
|
||||||
|
Button {
|
||||||
|
text: "ID查询"
|
||||||
|
onClicked: App.module.requestUniqueId()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ HOST_TOOLS := /opt/Xuantie-900-gcc-elf-newlib-x86_64-V2.6.1/bin
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
./rebuild-app.sh y L015 V200 R002 # 编译烧录固件
|
./rebuild-app.sh y L015 V200 R002 # 编译烧录固件
|
||||||
./rebuild-app-ota.sh y L015 V200 R002 12 # 编译OTA固件,11为OTA版本号
|
./rebuild-app-ota.sh y L015 V200 R002 13 # 编译OTA固件,11为OTA版本号
|
||||||
600X800
|
600X800
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user