#ifndef MODULECOMMUNICATION_H #define MODULECOMMUNICATION_H #include "DataStructure.h" #include #include #include #include class ModuleCommunication : public QObject { Q_OBJECT QML_ELEMENT QML_UNCREATABLE("Only created in C++...") static constexpr uint32_t UsernameSize = 32; static constexpr uint32_t VersionSize = 32; static constexpr const char *Separator = "----------"; Q_PROPERTY(MessageId currentMessageId READ currentMessageId NOTIFY currentMessageIdChanged) Q_PROPERTY(QString verison MEMBER m_verison NOTIFY verisonChanged) Q_PROPERTY(int otaVerison MEMBER m_otaVerison NOTIFY verisonChanged) public: constexpr static uint16_t VendorIdentifier = 0x3346; constexpr static uint16_t ProductIdentifier = 0x0001; constexpr static uint16_t MaxUserCount = 4000; constexpr static uint16_t InvalidUserId = std::numeric_limits::max(); enum MessageId : uint8_t { Reply = 0, Note = 0x01, Reset = 0x10, GetCurrentStatus = 0x11, Verify = 0x12, VerifyExtended = 0x16, EnrollSingle = 0x1D, EnrollExtended = 0x1E, GetImage = 0x1F, // 获取图片数据,通过VerifyExtended或EnrollExtended保存的 DeleteUser = 0x20, DeleteAll = 0x21, GetVersion = 0x30, StartOta = 0x40, // 模组进入boot模式进行ota升级 EnableDebug = 0x82, GetUniqueID = 0xAC, UploadImageInfo = 0xF6, UploadImageData = 0xF7, Idle = 0xFF, }; Q_ENUM(MessageId) enum class NoteId : uint8_t { Ready = 0x00, PalmState = 0x01, UnknownError = 0x02, DebugInfo = 0x55, NoAliveImage = 0x56, DeviceError = 0xF0, // 系统设备出现的错误,例如 QSerialPort InteractWarning, }; enum PalmState { NoPalm = 1, TooFar = 6, NeedMoveToCenter = 15, ManyPalm = 101, // 太多掌静脉 NoAlive = 122, }; enum MessageStatus : uint8_t { Success = 0, Rejected = 1, Aborted = 2, Failed4Camera = 4, Failed4UnknownReason = 5, Failed4InvalidParam = 6, Failed4NoMemory = 7, Failed4UnknownUser = 8, Failed4MaxUser = 9, Failed4PalmEnrolled = 10, Failed4LivenessCheck = 12, Failed4Timeout = 13, Failed4Authorization = 14, Failed4ReadFile = 19, Failed4WriteFile = 20, Failed4NoEncrypt = 21, PalmNotDetected = 23, Needmore = 25, }; #pragma pack(1) struct VerifyRequest { uint8_t reserved; uint8_t timeout; }; struct PalmStateNote { uint16_t state; // position uint16_t left; // in pixel uint16_t top; uint16_t right; uint16_t bottom; }; struct EnrollRequest { uint8_t username[32]; uint8_t reserved1[3]; uint8_t timeout; uint8_t reserved2[4]; }; struct EnrollReply { uint16_t userid; uint8_t reserved; }; struct PalmVeinInformation { uint16_t x1; uint16_t y1; uint16_t x2; uint16_t y2; uint16_t detectionProbability; uint16_t quality; }; struct EnrollExtendedReply { uint16_t userid; uint16_t imageWidth; uint16_t imageHeight; uint8_t imageFormat; // 0: 只有Y分量,灰度图 uint8_t md5[16]; uint8_t enrolledUsername[32]; uint16_t enrolledId; // 掌静脉库里已经存在的id PalmVeinInformation palmVeinInformation; uint8_t reserved[4]; }; struct ImageSliceRequest { uint32_t offset; uint32_t size; }; struct ImageSliceReply { uint32_t size; uint8_t data[0]; }; struct VerifyReply { uint16_t userid; uint8_t username[UsernameSize]; // 32Bytes uint8_t reserved[2]; }; struct VerifyExtendReply : public VerifyReply { uint16_t image_width; uint16_t image_height; uint8_t image_format; // 0: 只有Y分量,灰度图 uint8_t md5[16]; PalmVeinInformation palmVeinInformation; }; struct UploadImageInformation { uint8_t operation; // 0:图片录入掌静脉 uint8_t format; // 0: 灰度图(纯Y分量) uint16_t width; uint16_t height; uint32_t size; uint8_t md5[16]; // 图片内容 md5 值 char username[32]; }; struct UploadImageDataSlice { uint32_t offset; uint32_t size; uint8_t reserved[4]; // 预留 uint8_t data[0]; }; struct UploadImageReply : public EnrollReply {}; struct UploadImageVerifyReply : public UploadImageReply { VerifyReply result; }; struct ModuleVersion { char version[VersionSize]; uint32_t otaVersion; }; struct ModuleId { char id[32]; uint8_t userids[512]; // bit位 }; #pragma pack() explicit ModuleCommunication(QObject *parent = nullptr); bool open(const QString &portName, int baudRate); void verify(uint8_t timeout); Q_INVOKABLE void reset(); void enroll(const std::string &username, uint8_t timeout); Q_INVOKABLE void deleteUser(uint16_t userid); Q_INVOKABLE void deleteAll(); Q_INVOKABLE void requestUniqueId(); Q_INVOKABLE void requestVersion(); void requestEnrolledImage(uint32_t offset, uint32_t size); void uploadImageInfo(const UploadImageInformation &info); 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); signals: /** * @brief newVerifyResult * @param userid * @param username * @param elapsed ms毫秒 */ void newVerifyResult(uint16_t userid, const QString &username); void newEnrollResult(uint16_t userid); void newPalmFeature(const PalmFeature &feature); void newImageInfo(MessageId id, uint32_t size, const uint8_t *md5); void newImageSliceData(const std::vector &data); void errorOccurred(NoteId note, const QString &error, const QString &detailMessage = ""); void commandStarted(ModuleCommunication::MessageId messageId); void commandFinished(MessageId messageId, MessageStatus status); void currentMessageIdChanged(); void verisonChanged(); protected: void processPackage(const uint8_t *data, uint16_t size); void onReadyRead(); void onErrorOccurred(QSerialPort::SerialPortError error); std::pair generateFrame(MessageId command, const uint8_t *data = nullptr, uint16_t size = 0); void setCurrentMessageIdStatus(ModuleCommunication::MessageId messageId); private: std::shared_ptr m_serialPort; QByteArray m_receivedBuffer; MessageId m_currentMessageId = ModuleCommunication::Idle; QString m_verison; int m_otaVerison; }; namespace std { std::ostream &operator<<(std::ostream &stream, const ModuleCommunication::PalmState &element); } // namespace std #endif // MODULECOMMUNICATION_H