#include "ModuleCommunication.h" #include "BoostLog.h" #include #include #include #include static inline uint8_t xor_checksum_byte(const uint8_t *data, uint32_t len) { uint8_t sum = 0; for (uint32_t i = 0; i < len; ++i) { sum ^= data[i]; } return sum; } ModuleCommunication::ModuleCommunication(QObject *parent) : QObject{parent} { } bool ModuleCommunication::open(const QString &portName) { bool ret = true; m_serialPort = std::make_shared(portName); m_serialPort->setBaudRate(QSerialPort::Baud115200); connect(m_serialPort.get(), &QSerialPort::readyRead, this, &ModuleCommunication::onReadyRead); ret = m_serialPort->open(QSerialPort::ReadWrite); LOG_CAT(info, GUI) << "打开串口(" << portName.toStdString() << ")" << (ret ? "成功" : "失败") << "。"; LOG_CAT(info, GUI) << Separator; return ret; } void ModuleCommunication::verify(uint8_t timeout) { VerifyInfo data = {0}; data.timeout = timeout; auto [frameData, frameSize] = generateFrame(Verify, reinterpret_cast(&data), sizeof(data)); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送识别指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::reset() { auto [frameData, frameSize] = generateFrame(Reset); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送复位指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::enroll(const std::string &username, uint8_t timeout) { EnrollData data = {0}; data.timeout = timeout; strncpy(reinterpret_cast(data.username), username.c_str(), sizeof(data.username)); auto [frameData, frameSize] = generateFrame(EnrollSingle, reinterpret_cast(&data), sizeof(data)); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送注册指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << "用户名: " << username << ", 超时时间: " << static_cast(timeout) << "s"; LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::deleteUser(uint16_t userid) { uint16_t n = htons(userid); auto [frameData, frameSize] = generateFrame(DeleteUser, reinterpret_cast(&n), sizeof(n)); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送删除用户指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << "删除用户ID: " << userid; LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::deleteAll() { auto [frameData, frameSize] = generateFrame(DeleteAll); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送删除所有指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::requestPalmFeature(uint16_t userid) { uint16_t n = htons(userid); auto [frameData, frameSize] = generateFrame(RequestPalmFeature, reinterpret_cast(&n), sizeof(n)); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送获取掌静脉特征值指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << "获取特征值用户ID: " << userid; LOG_CAT(info, GUI) << Separator; } void ModuleCommunication::enrollPalmFeature(uint16_t userid, const PalmFeature &feature) { auto buffer = new uint8_t[sizeof(PalmFeatureHeader) + feature.feature.size()]; auto header = reinterpret_cast(buffer); header->userid = htons(userid); header->featureTotalSize = htons(feature.feature.size()); strncpy(reinterpret_cast(header->username), feature.username.c_str(), sizeof(header->username)); mbedtls_md5_context context; mbedtls_md5_init(&context); mbedtls_md5_starts(&context); uint8_t md5[16]; mbedtls_md5_update(&context, feature.feature.data(), feature.feature.size()); mbedtls_md5_finish(&context, md5); mbedtls_md5_free(&context); memcpy(header->featureDataMd5, md5, sizeof(header->featureDataMd5)); memcpy(buffer + sizeof(PalmFeatureHeader), feature.feature.data(), feature.feature.size()); auto [frameData, frameSize] = generateFrame(RegisterPalmFeature, buffer, sizeof(PalmFeatureHeader) + feature.feature.size()); m_serialPort->write(reinterpret_cast(frameData), frameSize); LOG_CAT(info, GUI) << "发送注册掌静脉特征指令: " << protocolDataFormatString(frameData, frameSize); LOG_CAT(info, GUI) << Separator; if (buffer != nullptr) delete[] buffer; } void ModuleCommunication::processPackage(const uint8_t *data, uint16_t size) { uint8_t messageId = data[2]; switch (messageId) { case Reply: { uint8_t replyId = data[5]; auto result = data[6]; switch (replyId) { case Reset: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); if (result == Success) { LOG_CAT(info, GUI) << "复位完成。"; } LOG_CAT(info, GUI) << Separator; break; } case Verify: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); if (result == Success) { auto info = reinterpret_cast(data + 7); LOG_CAT(info, GUI) << "用户ID: " << ntohs(info->userid) << ", 用户名: " << std::string_view(reinterpret_cast(info->username)); } else if (result == Failed4Timeout) { LOG_CAT(info, GUI) << "识别超时。"; } else if (result == Failed4UnknownReason) { LOG_CAT(info, GUI) << "未录入用户。"; } else { } LOG_CAT(info, GUI) << Separator; break; } case EnrollSingle: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); if (result == Success) { auto info = reinterpret_cast(data + 7); LOG_CAT(info, GUI) << "注册成功,用户ID: " << ntohs(info->userid); } else if (result == Failed4Timeout) { LOG_CAT(info, GUI) << "识别超时。"; } LOG_CAT(info, GUI) << Separator; break; } case DeleteUser: { if (result == Success) { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); LOG_CAT(info, GUI) << "删除用户成功。"; LOG_CAT(info, GUI) << Separator; } else { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); LOG_CAT(info, GUI) << "删除用户失败。"; LOG_CAT(info, GUI) << Separator; } break; } case DeleteAll: { if (result == Success) { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); LOG_CAT(info, GUI) << "删除所有用户成功。"; LOG_CAT(info, GUI) << Separator; } break; } case RequestPalmFeature: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); if (result == Success) { auto info = reinterpret_cast(data + 7); LOG_CAT(info, GUI) << "用户ID: " << ntohs(info->userid) << ", 用户名: " << std::string_view(reinterpret_cast(info->username)) << ", 特征值长度: " << ntohs(info->featureTotalSize); PalmFeature feature; feature.username = std::string_view(reinterpret_cast(info->username)); const uint8_t *start = data + 7 + sizeof(PalmFeatureHeader); feature.feature = std::vector(start, start + ntohs(info->featureTotalSize)); emit newPalmFeature(feature); } LOG_CAT(info, GUI) << Separator; break; } case RegisterPalmFeature: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); if (result == Success) { LOG_CAT(info, GUI) << "掌静脉特征值注册成功。"; } LOG_CAT(info, GUI) << Separator; break; } default: LOG(warning) << "unknown reply command: 0x" << (static_cast(replyId) & 0xff) << ", data: " << protocolDataFormatString(data, size); break; } break; } case Note: { uint8_t noteId = data[5]; switch (noteId) { case Ready: { LOG_CAT(info, GUI) << "模组: " << protocolDataFormatString(data, size); LOG_CAT(info, GUI) << "模组上电初始化成功。"; LOG_CAT(info, GUI) << Separator; break; } case 0x01: { // 模组返回的数据为当前帧的手掌状态 auto info = reinterpret_cast(data + 7); LOG(info) << info->state; break; } default: LOG(warning) << "unknown note command: 0x" << (static_cast(noteId) & 0xff) << ", data: " << protocolDataFormatString(data, size); break; } break; } default: LOG(warning) << "unknown command: 0x" << (static_cast(data[2]) & 0xff) << ", data: " << protocolDataFormatString(data, size); break; } } void ModuleCommunication::onReadyRead() { m_receivedBuffer.append(m_serialPort->readAll()); while (m_receivedBuffer.size() >= 2) { int beginIndex = -1; for (int i = 0; i < m_receivedBuffer.size() - 1; i++) { if (static_cast(m_receivedBuffer[i]) == 0xEF && static_cast(m_receivedBuffer[i + 1]) == 0xAA) { beginIndex = i; break; } } if (beginIndex < 0) { m_receivedBuffer.clear(); break; } else if (beginIndex != 0) { m_receivedBuffer.remove(0, beginIndex); beginIndex = 0; } if (m_receivedBuffer.size() < 5) break; uint16_t packageSize = *reinterpret_cast(m_receivedBuffer.data() + 3); packageSize = ntohs(packageSize); uint16_t totalSize = 0; if (packageSize == 0) { totalSize = 6; } else { totalSize = packageSize + 6; } if (m_receivedBuffer.size() >= totalSize) { processPackage(reinterpret_cast(m_receivedBuffer.data()), totalSize); m_receivedBuffer.remove(0, totalSize); } else { break; } } } std::pair ModuleCommunication::generateFrame(MessageId command, const uint8_t *data, uint16_t size) { static uint8_t sendBuffer[1024] = {0}; memset(sendBuffer, 0, sizeof(sendBuffer)); sendBuffer[0] = 0xef; sendBuffer[1] = 0xaa; sendBuffer[2] = command; sendBuffer[3] = size >> 8; sendBuffer[4] = size & 0xff; if (size > 0) { memcpy(sendBuffer + 5, data, size); } sendBuffer[5 + size] = xor_checksum_byte(sendBuffer + 2, 3 + size); return std::make_pair(sendBuffer, size + 6); } std::string ModuleCommunication::protocolDataFormatString(const uint8_t *data, int size) { std::ostringstream oss; for (int i = 0; i < size; i++) { oss << "0x" << std::setfill('0') << std::setw(2) << std::hex << (static_cast(data[i]) & 0xff) << " "; } return oss.str(); }