#include #include #include #include #include #include #include #include #include "MsgHandler.hpp" #include "DEBUG.hpp" #include "../common/SerialMsgHandler.hpp" #include #include #define BEEP_CARD 1 #define FIND_CARD 2 #define SET_PWD 3 #define READ_CARD 4 #define WRITE_CARD 5 #define STOP_CARD 8 #define WRITE_BLOCK_ID 0x04 // 写数据的块号 namespace { const char* PendingCommandName(PendingCommand command) { switch (command) { case PendingCommand::Find: return "FIND"; case PendingCommand::SetPassword: return "SET_PASSWORD"; case PendingCommand::ReadBlock: return "READ_BLOCK"; case PendingCommand::WriteBlock: return "WRITE_BLOCK"; case PendingCommand::Stop: return "STOP"; case PendingCommand::Beep: return "BEEP"; default: return "NONE"; } } uint16_t MapDeviceError(uint8_t command, uint8_t status) { if (status == 0) return 0; if (status == 0x0B) return 0x0012; // authentication failure if (status == 0x0C) return command == READ_CARD ? 0x0013 : 0x0014; if (status == 0x0A) return 0x001A; // invalid block return command == WRITE_CARD ? 0x0014 : 0x0013; } std::string CardStateName(CardState state) { switch (state) { case CardState::AUTO_FIND: return "AUTO_FIND"; case CardState::WAIT_DDS_READ: return "WAIT_DDS_READ"; case CardState::WAIT_DDS_WRITE: return "WAIT_DDS_WRITE"; case CardState::WAIT_DDS_DECISION: return "WAIT_DDS_DECISION"; case CardState::WAIT_DDS_WRITE_NEXT: return "WAIT_DDS_WRITE_NEXT"; } return "UNKNOWN"; } std::string HexBytes(const std::vector& bytes) { std::ostringstream out; out << std::hex << std::uppercase << std::setfill('0'); for (uint8_t byte : bytes) { out << std::setw(2) << static_cast(byte) << ' '; } return out.str(); } } MsgHandler::MsgHandler() : fd(-1), m_CardState(CardState::AUTO_FIND), m_CurrentIndex(0), m_ResultCode(0), m_BlockCount(0), m_BlockOpStartTime(std::chrono::steady_clock::now()), m_CurrentOperatingBlock(0), m_PendingReadResponse(std::vector()), OnCardDetected(nullptr) { } bool MsgHandler::OpenPort(const std::string& port, const std::string& baudrate) { return true; } void MsgHandler::ClosePort() { if (fd != -1) { close(fd); fd = -1; } } bool MsgHandler::SetDevice(const std::string& device) { this->device = device; return true; } int MsgHandler::SendDeviceMsg(const std::vector& data) { DEBUG("SERIAL TX device=" << this->device << " size=" << data.size() << " bytes=" << HexBytes(data)); int bytesWritten = SendMsg(data); DEBUG("SERIAL TX result=" << bytesWritten << "/" << data.size()); return bytesWritten; } int MsgHandler::RecvDeviceMsg(std::vector& data, int timeoutMs) { int bytesRead = RecvMsg(data, timeoutMs); if (bytesRead > 0) { DEBUG("SERIAL RX device=" << this->device << " size=" << data.size() << " bytes=" << HexBytes(data)); } return bytesRead; } int MsgHandler::SendMsg(const std::vector& data) { std::lock_guard lock(mtx_); if (fd == -1) { perror("设备未打开"); return -1; } size_t totalWritten = 0; while (totalWritten < data.size()) { const ssize_t written = write(fd, data.data() + totalWritten, data.size() - totalWritten); if (written < 0) { perror("发送数据失败"); return -1; } if (written == 0) { break; } totalWritten += static_cast(written); } return static_cast(totalWritten); } int MsgHandler::RecvMsg(std::vector& data, int timeoutMs) { std::lock_guard lock(mtx_); if (fd == -1) { perror("设备未打开\n"); return -1; } const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(std::max(0, timeoutMs)); while (true) { if (TryExtractDeviceFrame(data)) { return static_cast(data.size()); } const auto remaining = std::chrono::duration_cast( deadline - std::chrono::steady_clock::now()).count(); if (remaining <= 0) { // 兼容现场设备短读帧:只要块号和 16 字节数据已经到齐, // 即 LEN + header + block + data 至少 21 字节,就交给读卡解析。 if (m_ReceiveBuffer.size() >= 21U && m_ReceiveBuffer[1] == 0x01U && m_ReceiveBuffer[2] == READ_CARD && m_ReceiveBuffer[3] == 0x00U) { data = m_ReceiveBuffer; m_ReceiveBuffer.clear(); DEBUG("SERIAL RX short READ_BLOCK frame accepted for data extraction, size=" << data.size() << " bytes=" << HexBytes(data)); return static_cast(data.size()); } // 兼容现场设备偶发的写应答短帧: // 05 01 05 status crc_hi(缺少最后一个 CRC 字节)。 // 只放行固定 5 字节写应答,ParseDeviceMsg 仍会检查 status。 if (ALLOW_SHORT_WRITE_ACK && m_ReceiveBuffer.size() == 5U && m_ReceiveBuffer[0] == 0x05U && m_ReceiveBuffer[1] == 0x01U && m_ReceiveBuffer[2] == WRITE_CARD) { data = m_ReceiveBuffer; m_ReceiveBuffer.clear(); DEBUG("SERIAL RX short WRITE_BLOCK ACK accepted without final CRC byte, size=" << data.size() << " bytes=" << HexBytes(data)); return static_cast(data.size()); } if (!m_ReceiveBuffer.empty()) { const std::string incomplete = HexBytes(m_ReceiveBuffer); const size_t bufferedSize = m_ReceiveBuffer.size(); m_ReceiveBuffer.clear(); DEBUG("SERIAL RX incomplete frame timeout buffered=" << bufferedSize << " bytes=" << incomplete); // 【新增】AUTO_FIND 下收不满一帧超时 → 直接触发重置 if (m_CardState == CardState::AUTO_FIND) { DEBUG("AUTO_FIND: incomplete frame timeout — scheduling ResetSerialAndReinit"); m_AutoFindNeedsReset = true; } bool retried = false; if (m_PendingCommand == PendingCommand::WriteBlock) { DEBUG("Write incomplete frame, reverting to AUTO_FIND without retry"); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now() - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); if (fd != -1) tcflush(fd, TCIFLUSH); } else { // ★ 移除重试:读卡失败直接回 AUTO_FIND DEBUG("Read incomplete frame, reverting to AUTO_FIND"); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now() - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); if (fd != -1) tcflush(fd, TCIFLUSH); } } return 0; } fd_set readfds; struct timeval tv; FD_ZERO(&readfds); FD_SET(fd, &readfds); tv.tv_sec = static_cast(remaining / 1000); tv.tv_usec = static_cast((remaining % 1000) * 1000); const int ret = select(fd + 1, &readfds, nullptr, nullptr, &tv); if (ret < 0) { if (errno == EINTR) { continue; } perror("select错误"); return -1; } if (ret == 0) { continue; } int available = 0; if (ioctl(fd, FIONREAD, &available) < 0) { perror("ioctl FIONREAD失败"); return -1; } if (available <= 0) { continue; } std::vector received(static_cast(available)); const ssize_t bytesRead = read(fd, received.data(), received.size()); if (bytesRead < 0) { if (errno == EINTR) { continue; } perror("读取数据失败"); return -1; } if (bytesRead == 0) { continue; } received.resize(static_cast(bytesRead)); const auto rx_ms = std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()).count(); DEBUG("SERIAL RX RAW t_ms=" << rx_ms << " available=" << available << " read=" << bytesRead << " buffered_before=" << m_ReceiveBuffer.size() << " bytes=" << HexBytes(received)); m_ReceiveBuffer.insert(m_ReceiveBuffer.end(), received.begin(), received.end()); } } bool MsgHandler::TryExtractDeviceFrame(std::vector& data) { data.clear(); while (!m_ReceiveBuffer.empty()) { const size_t expectedSize = static_cast(m_ReceiveBuffer.front()) + 1U; if (expectedSize < 6U || expectedSize > 256U) { DEBUG("Discarding invalid device frame length=" << static_cast(m_ReceiveBuffer.front())); m_ReceiveBuffer.erase(m_ReceiveBuffer.begin()); continue; } if (m_ReceiveBuffer.size() < expectedSize) { return false; } std::vector frame(m_ReceiveBuffer.begin(), m_ReceiveBuffer.begin() + expectedSize); m_ReceiveBuffer.erase(m_ReceiveBuffer.begin(), m_ReceiveBuffer.begin() + expectedSize); if (!IsValidDeviceFrame(frame)) { DEBUG("Discarding invalid device frame, length=" << frame.size() << " bytes=" << HexBytes(frame)); // ★ 移除重试:CRC 校验失败直接回 AUTO_FIND(与写卡 incomplete frame 处理一致) if (frame.size() >= 4U && frame[1] == 0x01U && frame[2] == READ_CARD && m_PendingCommand == PendingCommand::ReadBlock) { DEBUG("ReadCard CRC validation failure, reverting to AUTO_FIND"); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now() - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); if (fd != -1) tcflush(fd, TCIFLUSH); return false; } // 【新增】AUTO_FIND 状态下任意一帧 CRC/length 失败 → 直接触发重置 if (m_CardState == CardState::AUTO_FIND) { DEBUG("AUTO_FIND: frame validation failure — scheduling ResetSerialAndReinit"); m_AutoFindNeedsReset = true; } continue; } data = std::move(frame); m_AutoFindNeedsReset = false; // 【新增】成功后清除重置标志 return true; } return false; } bool MsgHandler::RetryCurrentReadBlock(const char* reason) { if (m_PendingCommand != PendingCommand::ReadBlock || !m_BlockOperationPending || m_ReadBlockRetryCount >= READ_BLOCK_MAX_RETRIES) { DEBUG("Read block retry unavailable: reason=" << reason << " attempts=" << static_cast(m_ReadBlockRetryCount) << " max=" << static_cast(READ_BLOCK_MAX_RETRIES)); return false; } const uint8_t block = m_PendingBlock; ++m_ReadBlockRetryCount; DEBUG("Retrying read block=" << static_cast(block) << " attempt=" << static_cast(m_ReadBlockRetryCount) << "/" << static_cast(READ_BLOCK_MAX_RETRIES) << " reason=" << reason); std::this_thread::sleep_for(std::chrono::milliseconds(READ_BLOCK_RETRY_DELAY_MS)); m_ReceiveBuffer.clear(); if (fd != -1) { tcflush(fd, TCIFLUSH); } DEBUG("Read block retry buffer cleared, block=" << static_cast(block)); ReadCard({block}); return true; } // ========== 新增:写卡失败重试 ========== bool MsgHandler::RetryCurrentWriteBlock(const char* reason) { if (m_PendingCommand != PendingCommand::WriteBlock || !m_BlockOperationPending || m_WriteBlockRetryCount >= WRITE_BLOCK_MAX_RETRIES) { DEBUG("Write block retry unavailable: reason=" << reason << " attempts=" << static_cast(m_WriteBlockRetryCount) << " max=" << static_cast(WRITE_BLOCK_MAX_RETRIES)); return false; } const uint8_t block = m_PendingWriteBlock; ++m_WriteBlockRetryCount; DEBUG("Retrying write block=" << static_cast(block) << " attempt=" << static_cast(m_WriteBlockRetryCount) << "/" << static_cast(WRITE_BLOCK_MAX_RETRIES) << " reason=" << reason); std::this_thread::sleep_for(std::chrono::milliseconds(WRITE_BLOCK_RETRY_DELAY_MS)); m_ReceiveBuffer.clear(); if (fd != -1) { tcflush(fd, TCIFLUSH); } // ★ 用保存的 block + value 重新构造数据帧并发送 std::vector data; data.push_back(m_PendingWriteBlock); data.insert(data.end(), m_PendingWriteValue.begin(), m_PendingWriteValue.end()); WriteCard(data); return true; } bool MsgHandler::HasActiveDeviceOperation() const { return m_PendingCommand != PendingCommand::None || m_BlockOperationPending; } int MsgHandler::HandleFindResponse(const std::vector& data, WeighingSystem::ReadCardRsp& rsp) { m_PendingCommand = PendingCommand::None; // ========== 新增:WAIT_DDS_READ 期间的 RF 喂送响应:不修改状态 ========== if (m_CardState == CardState::WAIT_DDS_READ) { DEBUG("RF-feed FIND response ignored (card already selected, cardId=" << m_CardId << ")"); return 0; } if (data[3] != 0) { m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); rsp.msg()["find"].push_back(data[3]); return 1; } if (data.size() < 10U) { DEBUG("FindCard success frame too short, size=" << data.size()); m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); m_AutoFindNeedsReset = true; return 0; } const uint32_t cardIdValue = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]; std::stringstream ss; ss << std::hex << std::uppercase << std::setw(8) << std::setfill('0') << cardIdValue; m_CardId = ss.str(); m_AutoFind = true; // ★ 改成 true,让 AutoFindTick 在等重量时继续喂 RF m_FindIntervalMs = 2000; // ★ 显式设成 5 秒间隔(用现有逻辑) m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::WAIT_DDS_READ); rsp.msg()["find"].insert(rsp.msg()["find"].end(), data.begin() + 4, data.begin() + 8); if (OnCardDetected) { OnCardDetected(m_CardId); } DEBUG("Card found: " << m_CardId << ", ready for DDS read or write command"); return 1; } bool MsgHandler::IsValidDeviceFrame(const std::vector& data) { const bool shortWriteAck = ALLOW_SHORT_WRITE_ACK && data.size() == 5U && data[0] == 0x05U && data[1] == 0x01U && data[2] == WRITE_CARD; if (data.size() < 6U && !shortWriteAck) { return false; } const bool shortReadFrame = data.size() >= 21U && data[0] != static_cast(data.size() - 1U) && data[1] == 0x01U && data[2] == READ_CARD && data[3] == 0x00U; if (!shortReadFrame && !shortWriteAck && data.size() != static_cast(data[0]) + 1U) { return false; } if (data[1] != 0x01) { DEBUG("Invalid device fixed byte=" << std::hex << static_cast(data[1])); return false; } if (shortWriteAck) { DEBUG("Accepting short WRITE_BLOCK ACK without final CRC byte, size=" << data.size() << " status=0x" << std::hex << static_cast(data[3])); return true; } if (shortReadFrame) { DEBUG("Accepting short READ_BLOCK frame without length/CRC enforcement, size=" << data.size()); return true; } if (!VERIFY_DEVICE_CRC) { DEBUG("CRC_BYPASS device frame accepted, size=" << std::dec << data.size() << " cmd=0x" << std::hex << static_cast(data[2])); return true; } std::vector crcData(data.begin(), data.end() - 2); CRC16(crcData); // 现场实帧确认:响应 CRC 与本地发送方向一致,高字节在前、低字节在后。 const bool valid = crcData[crcData.size() - 2] == data[data.size() - 2] && crcData[crcData.size() - 1] == data[data.size() - 1]; if (!valid) { DEBUG("Invalid device CRC expected(high/low)=" << std::hex << static_cast(crcData[crcData.size() - 2]) << "/" << static_cast(crcData[crcData.size() - 1]) << " actual(high/low)=" << static_cast(data[data.size() - 2]) << "/" << static_cast(data[data.size() - 1])); } return valid; } bool MsgHandler::IsDataBlock(uint8_t block) { return block < 64U && (block % 4U) != 3U; } void MsgHandler::HandleDdsMsg(const std::map>& msg, unsigned long index) { std::lock_guard lock(mtx_); if (msg.size() != 1U) { DEBUG("Rejecting DDS command: expected exactly one msg key, actual=" << msg.size()); return; } auto cmd = msg.begin(); DEBUG("HandleDdsMsg: cmd=" << cmd->first << ", index=" << index); DEBUG("COMMAND state=" << CardStateName(m_CardState) << " auto_find=" << m_AutoFind << " payload_size=" << cmd->second.size()); // ========== read 命令处理 ========== if (cmd->first == "read") { // 【新增】如果在恢复序列执行期间收到了新命令,说明恢复被新命令打断 // 此时要:1)停止旧恢复,2)清空旧状态,3)开始新命令 if (m_IsInTimeoutRecovery) { DEBUG("HandleDdsMsg: new read command arrived during timeout recovery, aborting old recovery"); // 清除旧的恢复标志(让 SkipCurrentBlock 不要再发了) m_IsInTimeoutRecovery = false; } // 【新增】开始计时 m_ReadStartTime = std::chrono::steady_clock::now(); // ★ 修改:WAIT_DDS_DECISION / WAIT_DDS_WRITE_NEXT 也可以接收 read 命令 if (m_CardState != CardState::WAIT_DDS_READ && m_CardState != CardState::WAIT_DDS_DECISION && m_CardState != CardState::WAIT_DDS_WRITE_NEXT) { DEBUG("Unexpected read command, current state=" << (int)m_CardState); if (m_CardState == CardState::AUTO_FIND) { DEBUG("read cmd during AUTO_FIND → scheduling reset"); m_AutoFindNeedsReset = true; } return; } if (HasActiveDeviceOperation()) { DEBUG("Rejecting read command: device operation is active"); return; } // 解析 read 请求协议: // 版本(1) | 卡号长度(1) | 卡号ASCII | 块数量(1) | 块号列表 const std::vector& data = cmd->second; DEBUG("DDS raw data: size=" << data.size()); for (size_t i = 0; i < data.size() && i < 20; i++) { std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)data[i] << " "; } std::cout << std::endl; if (data.size() < 3) { DEBUG("Invalid read request, size=" << data.size()); return; } uint8_t version = data[0]; uint8_t cardIdLen = data[1]; if (data.size() < static_cast(3U + cardIdLen)) { DEBUG("Invalid read request card ID length=" << static_cast(cardIdLen)); return; } std::string reqCardId(data.begin() + 2, data.begin() + 2 + cardIdLen); uint8_t blockCount = data[2 + cardIdLen]; if (data.size() < static_cast(3U + cardIdLen + blockCount)) { DEBUG("Invalid read request block count=" << static_cast(blockCount)); return; } DEBUG("Read req: version=" << (int)version << ", cardId=" << reqCardId << ", blockCount=" << (int)blockCount); // 验证卡号(与检测到的卡号匹配) if (reqCardId != m_CardId) { DEBUG("Card ID mismatch: req=" << reqCardId << ", found=" << m_CardId); return; } // 清空读卡缓冲区 ClearReadBuffer(); m_CardId = reqCardId; // 保存请求的块号列表。块 4、5 是扇区 1 的数据块,不能特殊跳过。 m_RequestedBlocks.clear(); for (int i = 0; i < blockCount; i++) { uint8_t blockNum = data[3 + cardIdLen + i]; if (!IsDataBlock(blockNum)) { DEBUG("Rejecting sector trailer/control block " << static_cast(blockNum)); ClearReadBuffer(); m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); return; } m_RequestedBlocks.push_back(blockNum); DEBUG("Queuing block " << (int)blockNum << " for reading"); } m_BlockCount = static_cast(m_RequestedBlocks.size()); if (m_RequestedBlocks.empty()) { DEBUG("Read request contains no blocks"); return; } // 【修改】只发送第一个读卡命令 m_CurrentReadIndex = 0; m_ReadBlockRetryCount = 0; m_CurrentIndex = index; if (!m_RequestedBlocks.empty()) { ReadCard({m_RequestedBlocks[0]}); DEBUG("Sent first read command for block " << (int)m_RequestedBlocks[0]); } // 切换到等待读卡完成状态 SetCardState(CardState::WAIT_DDS_READ); m_StateEnterTime = std::chrono::steady_clock::now(); // 保存 index 以便后续使用 m_CurrentIndex = index; return; } // ========== write 命令处理 ========== if (cmd->first == "write") { // 已寻到并验证卡号后,读和写都是独立 DDS 操作;写卡不要求先读卡。 // ★ 修改:WAIT_DDS_DECISION / WAIT_DDS_WRITE_NEXT 也可以接收 write 命令 if (m_CardState != CardState::WAIT_DDS_READ && m_CardState != CardState::WAIT_DDS_DECISION && m_CardState != CardState::WAIT_DDS_WRITE_NEXT) { DEBUG("Unexpected write command, current state=" << (int)m_CardState); if (m_CardState == CardState::AUTO_FIND) { DEBUG("write cmd during AUTO_FIND → scheduling reset"); m_AutoFindNeedsReset = true; } return; } if (HasActiveDeviceOperation()) { DEBUG("Rejecting write command: device operation is active"); return; } // 解析 write 请求协议: // 版本(1) | 卡号长度(1) | 卡号ASCII | 块号(1) | 16字节块数据 const std::vector& data = cmd->second; if (data.size() < 3) { DEBUG("Invalid write request, size=" << data.size()); return; } uint8_t version = data[0]; uint8_t cardIdLen = data[1]; if (data.size() < static_cast(3U + cardIdLen + 16U)) { DEBUG("Invalid write request length=" << data.size() << ", card ID length=" << static_cast(cardIdLen)); return; } std::string reqCardId(data.begin() + 2, data.begin() + 2 + cardIdLen); uint8_t blockNum = data[2 + cardIdLen]; if (!IsDataBlock(blockNum)) { DEBUG("Rejecting sector trailer/control block " << static_cast(blockNum)); m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); return; } DEBUG("Write req: version=" << (int)version << ", cardId=" << reqCardId << ", block=" << (int)blockNum); // 验证卡号(先校验,校验通过再切状态) if (reqCardId != m_CardId) { DEBUG("Card ID mismatch: req=" << reqCardId << ", found=" << m_CardId); return; // ← 此时还是 WAIT_DDS_DECISION,状态不会卡死 } // 校验通过,进入"等 RC522 写卡响应"状态 m_CurrentIndex = index; SetCardState(CardState::WAIT_DDS_WRITE); // 构造写卡数据(块号 + 16字节数据) std::vector writeData; writeData.push_back(blockNum); writeData.insert(writeData.end(), data.begin() + 3 + cardIdLen, data.begin() + 3 + cardIdLen + 16); DEBUG("Writing block " << (int)blockNum); // ★ 修复:每次新 WRITE 命令入口清零(这是"新会话"的起点) m_WriteBlockRetryCount = 0; WriteCard(writeData); return; } // ========== 其他命令保持不变 ========== if (cmd->first == "find") { if (HasActiveDeviceOperation()) { DEBUG("Ignoring find command while a device operation is active"); return; } m_AutoFind = true; m_PreCard.clear(); m_CardId.clear(); SetCardState(CardState::AUTO_FIND); FindCard(); m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now(); } else if (cmd->first == "stop") { if (HasActiveDeviceOperation()) { DEBUG("Ignoring stop command while a device operation is active"); return; } m_AutoFind = false; SetCardState(CardState::AUTO_FIND); StopCard(); } else if (cmd->first == "beep") { if (HasActiveDeviceOperation()) { DEBUG("Ignoring beep command while a device operation is active"); return; } m_AutoFind = false; BeepCard(cmd->second); } else if (cmd->first == "reset") { if (HasActiveDeviceOperation()) { DEBUG("Ignoring reset command while a device operation is active"); return; } m_AutoFind = false; SetCardState(CardState::AUTO_FIND); ResetCard(); } } int MsgHandler::HandleDeviceMsg(WeighingSystem::ReadCardRsp& rsp) { std::lock_guard lock(mtx_); std::vector m_RecvData; // ★ 新增:写操作给更长的读窗口,覆盖 RC522 auth fail 时清理 Crypto1 的延迟 int timeout_ms = 200; if (m_PendingCommand == PendingCommand::WriteBlock || m_PendingCommand == PendingCommand::SetPassword) { timeout_ms = 500; // 或 800,根据 RC522 固件实测调 } if (RecvDeviceMsg(m_RecvData, timeout_ms) > 0) { return (ParseDeviceMsg(m_RecvData, rsp)); } return 0; } void MsgHandler::CRC16(std::vector& data) { uint8_t chCRCHi = 0xFF; uint8_t chCRCLo = 0xFF; for (size_t i = 0; i < data.size(); i++) { uint8_t wIndex = chCRCLo ^ data[i]; chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex]; chCRCHi = chCRCLTalbe[wIndex]; } // 保持当前运行环境既有 CRC 字节序:高字节在前、低字节在后。 data.insert(data.end(), {chCRCHi, chCRCLo}); } int MsgHandler::ParseDeviceMsg(std::vector& data, WeighingSystem::ReadCardRsp& rsp) { // 【新增】清理之前的响应消息,避免键累积 rsp.msg().clear(); // 仅接受已完整接收且通过协议校验的帧。 if (!IsValidDeviceFrame(data)) { DEBUG("ParseDeviceMsg: invalid device frame, size=" << data.size()); return 0; } DEBUG("DEVICE FRAME seq=" << std::dec << m_OperationSequence << " expected=" << PendingCommandName(m_PendingCommand) << " cmd=0x" << std::hex << static_cast(data[2]) << " status=0x" << static_cast(data[3]) << " state=" << CardStateName(m_CardState) << " dds_index=" << std::dec << m_CurrentIndex << " pending_block=" << static_cast(m_CurrentOperatingBlock) << " pending=" << m_BlockOperationPending); switch (data[2]) { case BEEP_CARD: if (m_PendingCommand != PendingCommand::Beep) return 0; m_PendingCommand = PendingCommand::None; rsp.msg()["beep"].insert(rsp.msg()["beep"].end(), data[3]); break; case STOP_CARD: // if (m_PendingCommand == PendingCommand::Find) // { // return HandleFindResponse(data, rsp); // } if (m_PendingCommand != PendingCommand::Stop) return 0; m_PendingCommand = PendingCommand::None; rsp.msg()["stop"].insert(rsp.msg()["stop"].end(), data[3]); break; case FIND_CARD: if (m_PendingCommand != PendingCommand::Find) return 0; return HandleFindResponse(data, rsp); case READ_CARD: { if (m_PendingCommand != PendingCommand::ReadBlock) { DEBUG("Ignoring unmatched READ_CARD response"); return 0; } const uint8_t status = data[3]; if (status != 0) { DEBUG("ReadCard FAIL: error code=0x" << std::hex << static_cast(status)); std::vector rsp_data; rsp_data.push_back(1); const uint16_t error = MapDeviceError(READ_CARD, status); rsp_data.push_back(static_cast(error >> 8)); rsp_data.push_back(static_cast(error & 0xFF)); rsp_data.push_back(static_cast(m_CardId.length())); rsp_data.insert(rsp_data.end(), m_CardId.begin(), m_CardId.end()); rsp_data.push_back(0); rsp.msg()["read"] = rsp_data; ClearReadBuffer(); m_CurrentOperatingBlock = 0; m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; // ★ 新增:读卡 NACK 也走统一的 AUTO_FIND 异常恢复流程 m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); return 1; } if (m_RequestedBlocks.empty() || m_CurrentReadIndex >= m_RequestedBlocks.size()) { DEBUG("ReadCard success without a pending requested block"); return 0; } const size_t payloadSize = data.size() - 6U; uint8_t blockNum = m_RequestedBlocks[m_CurrentReadIndex]; std::vector block16; if (data.size() >= 21U) { // 兼容参考驱动的固定偏移:data[4] 为块号,data[5..20] 为 16 字节数据。 const uint8_t responseBlock = data[4]; if (responseBlock != blockNum) { DEBUG("ReadCard response block mismatch, expected=" << static_cast(blockNum) << ", actual=" << static_cast(responseBlock)); return 0; } block16.assign(data.begin() + 5, data.begin() + 21); } else if (payloadSize == 16U) { block16.assign(data.begin() + 4, data.begin() + 20); } else if (payloadSize == 17U) { const uint8_t responseBlock = data[4]; if (responseBlock != blockNum) { // ★ 移除重试:块号不匹配直接回 AUTO_FIND DEBUG("ReadCard response block mismatch, expected=" << static_cast(blockNum) << ", actual=" << static_cast(responseBlock) << " — reverting to AUTO_FIND"); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now() - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); return 0; } block16.assign(data.begin() + 5, data.begin() + 21); } else { // ★ 移除重试:payload 长度无效直接回 AUTO_FIND DEBUG("ReadCard success payload length invalid, size=" << payloadSize << " — reverting to AUTO_FIND"); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = std::chrono::steady_clock::now() - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); return 0; } m_BlockOpStartTime = std::chrono::steady_clock::now(); m_CurrentOperatingBlock = 0; m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_ReadBlockRetryCount = 0; DEBUG("ReadCard OK, block=" << (int)blockNum); m_BlockData.push_back({blockNum, block16}); if (m_BlockData.size() >= m_RequestedBlocks.size()) { // 所有块读取完成,构建完整 DDS 响应 DEBUG("All blocks read, building complete DDS response"); std::vector rsp_data; rsp_data.push_back(1); // 版本 rsp_data.push_back(0x00); // 结果码高 rsp_data.push_back(0x00); // 结果码低 rsp_data.push_back(m_CardId.length()); // 卡号长度 rsp_data.insert(rsp_data.end(), m_CardId.begin(), m_CardId.end()); // 卡号 rsp_data.push_back(m_BlockData.size()); // 块数量 // 添加所有块的数据 for (const auto& block : m_BlockData) { rsp_data.push_back(block.first); // 块号 rsp_data.insert(rsp_data.end(), block.second.begin(), block.second.end()); // 16字节 } rsp.msg()["read"] = rsp_data; // 清理并恢复状态 m_BlockData.clear(); m_RequestedBlocks.clear(); m_CurrentReadIndex = 0; // ★ 修改:读卡成功后切到 WAIT_DDS_DECISION,等待下一个 DDS 命令(20秒超时) // SetCardState 会自动重置 m_StateEnterTime,超时重新计时 m_AutoFind = false; // RF 保持关闭(前面 SummaryUpdate 后已经停掉了) m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::WAIT_DDS_READ); // 【新增】结束计时并打印 m_ReadEndTime = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast( m_ReadEndTime - m_ReadStartTime).count(); DEBUG("Read card elapsed: " << elapsed << " ms (" << elapsed / 1000.0 << " seconds)"); return 1; // ← 返回1表示需要发布 DDS 响应 } m_CurrentReadIndex++; if (m_CurrentReadIndex < m_RequestedBlocks.size()) { uint8_t nextBlock = m_RequestedBlocks[m_CurrentReadIndex]; DEBUG("Sending next read command for block " << (int)nextBlock); m_ReadBlockRetryCount = 0; ReadCard({nextBlock}); std::this_thread::sleep_for(std::chrono::milliseconds(30)); } return 0; // ← 未全部完成,不发布响应 } break; case WRITE_CARD: { if (m_PendingCommand != PendingCommand::WriteBlock) { DEBUG("Ignoring unmatched WRITE_CARD response"); return 0; } if (data[3] == 0) // 写卡成功 { m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_WriteBlockRetryCount = 0; // ★ 新增:写卡成功后清零,给下次操作 DEBUG("WriteCard OK: block=" << (int)m_PendingWriteBlock); // ★ 修改:写卡成功后切到 WAIT_DDS_WRITE_NEXT,等待下一个 DDS 命令(10秒超时) // SetCardState 会自动重置 m_StateEnterTime,超时重新计时 m_AutoFind = false; // RF 保持关闭 SetCardState(CardState::WAIT_DDS_WRITE_NEXT); DEBUG("Write complete, waiting for next DDS command"); // ★ 与 read 响应同协议:1 键 + vector std::vector write_rsp; write_rsp.push_back(1); // 版本 write_rsp.push_back(0x00); // 结果码高 write_rsp.push_back(0x00); // 结果码低(成功) write_rsp.push_back((uint8_t)m_CardId.size()); // 卡号长度 write_rsp.insert(write_rsp.end(), m_CardId.begin(), m_CardId.end()); // 卡号 write_rsp.push_back(1); // 块数量 = 1 write_rsp.push_back(m_PendingWriteBlock); // 块号 write_rsp.push_back(0x00); // 块结果码高 = 0(成功) write_rsp.push_back(0x00); // 块结果码低 = 0(成功) // 块数量 = 0 rsp.msg()["write"] = write_rsp; rsp.index(m_CurrentIndex); // ★ 新增:清理敏感数据,避免长期驻留内存 std::fill(m_PendingWriteValue.begin(), m_PendingWriteValue.end(), 0); m_PendingWriteValue.clear(); m_PendingWriteBlock = 0; return 1; } else // 写卡失败 { DEBUG("WriteCard FAIL: block=" << (int)m_PendingWriteBlock << " error code=0x" << std::hex << (int)data[3]); // ========== 回 AUTO_FIND ========== m_WriteBlockRetryCount = 0; // ★ 新增:清掉计数,给下次扫描用 m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; m_AutoFindNeedsReset = true; // ★ 加这行 m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); // ========== 修复:失败响应包用与成功完全一致的格式 ========== const uint16_t error = MapDeviceError(WRITE_CARD, data[3]); std::vector write_rsp; write_rsp.push_back(1); // 版本 write_rsp.push_back(static_cast(error >> 8)); write_rsp.push_back(static_cast(error & 0xFF)); // 结果码 write_rsp.push_back(static_cast(m_CardId.size())); // ★ 新增:卡号长度(与成功分支一致) write_rsp.insert(write_rsp.end(), m_CardId.begin(), m_CardId.end()); // ★ 卡号:与成功分支一致(直接拼 8 字节,不带长度前缀) write_rsp.push_back(1); // 块数量 = 1 write_rsp.push_back(m_PendingWriteBlock); // 块号 write_rsp.push_back(static_cast(error >> 8)); write_rsp.push_back(static_cast(error & 0xFF)); // 块结果码 rsp.msg()["write"] = write_rsp; rsp.index(m_CurrentIndex); // ★ 新增:清理敏感数据,避免长期驻留内存 std::fill(m_PendingWriteValue.begin(), m_PendingWriteValue.end(), 0); m_PendingWriteValue.clear(); m_PendingWriteBlock = 0; return 1; } } break; default: break; } return 0; } void MsgHandler::StorePasswd(std::map>& data) { m_PassWord = data; } void MsgHandler::SetPasswd(const std::vector& data) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 添加延迟 std::vector m_SendData; m_PendingCommand = PendingCommand::SetPassword; ++m_OperationSequence; m_SendData.insert(m_SendData.end(), {0x0C, 0x01, 0x03, 60, data[0]}); auto it = m_PassWord.find(data[0]); if (it != m_PassWord.end()) { m_SendData.insert(m_SendData.end(), it->second.begin(), it->second.end()); } CRC16(m_SendData); SendDeviceMsg(m_SendData); } void MsgHandler::StopCard(void) { std::vector m_SendData; m_PendingCommand = PendingCommand::Stop; ++m_OperationSequence; m_SendData.insert(m_SendData.end(), {0x04, 0x01, 0x08}); CRC16(m_SendData); SendDeviceMsg(m_SendData); } void MsgHandler::FindCard(void) { std::vector m_SendData; m_PendingCommand = PendingCommand::Find; ++m_OperationSequence; m_SendData.insert(m_SendData.end(), {0x04, 0x01, 0x02}); CRC16(m_SendData); SendDeviceMsg(m_SendData); } // ★ 新增:RF 喂送专用寻卡 —— 只发字节,不修改 m_PendingCommand、不动 m_OperationSequence // 响应回来时 ParseDeviceMsg 会因为 m_PendingCommand != Find 直接丢弃(return 0), // 不会触发 HandleFindResponse 改状态,不会污染 HasActiveDeviceOperation() 判断。 void MsgHandler::SendRfFeedFind(void) { std::vector m_SendData; m_SendData.insert(m_SendData.end(), {0x04, 0x01, 0x02}); CRC16(m_SendData); SendDeviceMsg(m_SendData); } void MsgHandler::ReadCard(const std::vector& data) { std::vector m_SendData; std::this_thread::sleep_for(std::chrono::milliseconds(100)); m_SendData.insert(m_SendData.end(), {0x05, 0x01, 0x04, data[0]}); // ========== 新增:记录当前块操作开始时间 ========== m_CurrentOperatingBlock = data[0]; m_BlockOpStartTime = std::chrono::steady_clock::now(); m_BlockOperationPending = true; m_PendingCommand = PendingCommand::ReadBlock; m_PendingBlock = data[0]; ++m_OperationSequence; CRC16(m_SendData); m_AutoFind = false; // ★ 关闭 RF-feed,防止 FindCard 响应干扰 SendDeviceMsg(m_SendData); // 【新增】保护延时:给 RC522 和 STM32 固件留出处理时间 // 原因:连续发读块命令时,RC522 内部认证状态可能丢失 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } void MsgHandler::WriteCard(const std::vector& data) { // ★ 在调串口之前先存请求参数(响应时要用) // data = [blockNum(1)] + [16 字节块数据] if (data.size() != 17U) { DEBUG("WriteCard rejected: expected block plus 16 data bytes, size=" << data.size()); m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; return; } // ★ 新增:发命令前延时,让 RC522 处理完上一条命令 std::this_thread::sleep_for(std::chrono::milliseconds(100)); m_PendingWriteBlock = data[0]; m_PendingWriteValue.assign(data.begin() + 1, data.end()); DEBUG("WriteCard request block=" << static_cast(m_PendingWriteBlock) << " data_size=" << m_PendingWriteValue.size() << " data=" << HexBytes(m_PendingWriteValue)); // ========== 新增:记录当前块操作开始时间 ========== m_CurrentOperatingBlock = data[0]; m_BlockOpStartTime = std::chrono::steady_clock::now(); m_BlockOperationPending = true; m_PendingCommand = PendingCommand::WriteBlock; m_PendingBlock = data[0]; ++m_OperationSequence; std::vector m_SendData; m_SendData.insert(m_SendData.end(), {0x15, 0x01, 0x05}); m_SendData.insert(m_SendData.end(), data.begin(), data.end()); DEBUG("WriteCard frame_without_crc size=" << m_SendData.size() << " bytes=" << HexBytes(m_SendData)); CRC16(m_SendData); DEBUG("WriteCard frame_with_crc size=" << m_SendData.size() << " bytes=" << HexBytes(m_SendData)); m_AutoFind = false; // ★ 关闭 RF-feed,防止 FindCard 响应干扰 SendDeviceMsg(m_SendData); // ★ 新增:发命令后延时,让 RC522 完成 Crypto1 重建(如果固件会重建) std::this_thread::sleep_for(std::chrono::milliseconds(100)); } void MsgHandler::BeepCard(const std::vector& data) { std::vector m_SendData; m_PendingCommand = PendingCommand::Beep; ++m_OperationSequence; uint8_t duration = data.empty() ? 0x0F : data[0]; m_SendData.insert(m_SendData.end(), {0x05, 0x01, 0x01, duration}); CRC16(m_SendData); SendDeviceMsg(m_SendData); } void MsgHandler::ResetCard(void) { if (fd != -1) { tcflush(fd, TCIOFLUSH); } m_ReceiveBuffer.clear(); DEBUG("ResetCard: serial buffer flushed"); } // ========== 重置串口并重新初始化 RC522 ========== // 用于块操作超时后的恢复,因为 RC522 可能在某些情况下完全无响应 bool MsgHandler::ResetSerialAndReinit() { DEBUG("ResetSerialAndReinit: resetting serial port and RC522"); m_ReceiveBuffer.clear(); // 第一步:关闭当前串口 ClosePort(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 第二步:重新打开串口(使用保存的端口) if (m_Port.empty()) { DEBUG("ResetSerialAndReinit: m_Port is empty, cannot reopen"); return false; } std::string tty = "/dev/" + m_Port; DEBUG("ResetSerialAndReinit: reopening " << tty << " with baudrate " << (int)m_Baudrate); fd = open(tty.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { DEBUG("ResetSerialAndReinit: failed to reopen serial port " << tty); return false; } // 第三步:重新配置串口参数(使用保存的波特率) struct termios options; if (tcgetattr(fd, &options) != 0) { DEBUG("ResetSerialAndReinit: failed to get serial attributes"); close(fd); fd = -1; return false; } cfmakeraw(&options); cfsetispeed(&options, m_Baudrate); cfsetospeed(&options, m_Baudrate); options.c_cflag |= CS8; options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CRTSCTS; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; tcflush(fd, TCIOFLUSH); if (tcsetattr(fd, TCSANOW, &options) != 0) { DEBUG("ResetSerialAndReinit: failed to set serial attributes"); close(fd); fd = -1; return false; } DEBUG("ResetSerialAndReinit: serial port reopened successfully"); // 第四步:等待 RC522 准备好 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 第五步:清空 RC522 内部状态(直接发命令,不等待响应) StopCard(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 第六步:重新下载所有扇区密码(直接发命令,不等待响应) for (auto& kv : m_PassWord) { SetPasswd({kv.first}); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } // 第七步:启动寻卡(直接发命令,不等待响应) FindCard(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); DEBUG("ResetSerialAndReinit: commands sent, waiting for RC522 to recover..."); DEBUG("ResetSerialAndReinit: RC522 reinitialized successfully"); return true; } bool MsgHandler::WaitForResponse(uint8_t expected_cmd, int timeout_ms) { int elapsed = 0; const int poll_interval = 100; while (elapsed < timeout_ms) { std::vector data; if (RecvDeviceMsg(data, poll_interval) > 0) { if (data.size() >= 4 && data[2] == expected_cmd && data[3] == 0x00) { return true; } } elapsed += poll_interval; } DEBUG("WaitForResponse timeout, expected_cmd=0x" << std::hex << (int)expected_cmd); return false; } bool MsgHandler::InitSequence(void) { // 第一步:停止寻卡 StopCard(); if (!WaitForResponse(STOP_CARD)) { DEBUG("InitSequence: StopCard failed"); return false; } DEBUG("InitSequence: StopCard OK"); // 第二步:逐扇区下载密码(升序) for (auto& kv : m_PassWord) { SetPasswd({kv.first}); if (!WaitForResponse(SET_PWD)) { DEBUG("InitSequence: SetPasswd sector " << (int)kv.first << " failed"); return false; } DEBUG("InitSequence: SetPasswd sector " << (int)kv.first << " OK"); } // 第三步:启动寻卡 FindCard(); m_AutoFind = true; m_FindIntervalMs = 5000; // 发送后5000ms超时保护 m_LastFindTime = std::chrono::steady_clock::now(); DEBUG("InitSequence: complete, auto-find enabled"); return true; } void MsgHandler::AutoFindTick(void) { std::lock_guard lock(mtx_); if (!m_AutoFind) return; if (m_CardState != CardState::AUTO_FIND && m_CardState != CardState::WAIT_DDS_READ) return; const auto now = std::chrono::steady_clock::now(); const auto elapsed = std::chrono::duration_cast( now - m_LastFindTime).count(); if (elapsed >= m_FindIntervalMs) { if (m_CardState == CardState::AUTO_FIND) { DEBUG("AUTO_FIND tick elapsed_ms=" << elapsed << " interval_ms=" << m_FindIntervalMs); // AUTO_FIND 状态:响应回来后要切到 WAIT_DDS_READ,用普通 FindCard FindCard(); } else { DEBUG("WAIT_DDS_READ RF-feed tick elapsed_ms=" << elapsed << " interval_ms=" << m_FindIntervalMs); // ★ WAIT_DDS_READ 状态:用 RF 喂送专用函数,m_PendingCommand 不动 // 这样不会被 ParseDeviceMsg 当成 Find 响应,也不会被 HandleDdsMsg 当成设备忙拒掉 SendRfFeedFind(); } m_FindIntervalMs = (m_CardState == CardState::WAIT_DDS_READ) ? 2000 : 5000; m_LastFindTime = now; } } void MsgHandler::SetCardState(CardState state) { std::lock_guard lock(mtx_); const CardState oldState = m_CardState; m_CardState = state; m_StateEnterTime = std::chrono::steady_clock::now(); DEBUG("STATE " << CardStateName(oldState) << " -> " << CardStateName(state)); } unsigned long MsgHandler::GetCurrentIndex() const { std::lock_guard lock(mtx_); return m_CurrentIndex; } bool MsgHandler::IsTimeoutRecovery() const { std::lock_guard lock(mtx_); return m_IsInTimeoutRecovery; } uint64_t MsgHandler::GetOperationSequence() const { std::lock_guard lock(mtx_); return m_OperationSequence; } bool MsgHandler::IsReadResponseReady() const { // 检查读卡响应是否准备好(块数据已累积完成) return (m_CardState == CardState::WAIT_DDS_WRITE) && (m_BlockCount > 0); } bool MsgHandler::IsWriteResponseReady() const { // 写卡响应在每次写成功后立即可用 return false; // 由 ParseDeviceMsg 实时处理 } void MsgHandler::ClearReadBuffer() { m_BlockData.clear(); m_BlockCount = 0; m_ResultCode = 0; m_RequestedBlocks.clear(); // 【新增】清空块号列表 m_SkippedBlocks.clear(); // 【新增】清空跳过的块记录 } void MsgHandler::SetReadResult(uint8_t resultCode, const std::string& cardId, uint8_t blockCount, const std::vector>>& blockData) { m_ResultCode = resultCode; m_CardId = cardId; m_BlockCount = blockCount; m_BlockData = blockData; } void MsgHandler::SetWriteResult(uint8_t resultCode, const std::string& cardId, uint8_t blockNum) { m_ResultCode = resultCode; m_CardId = cardId; // blockNum 已在写卡命令中处理 } int MsgHandler::CheckDdsTimeout() { std::lock_guard lock(mtx_); // 设备读写事务期间不使用空闲超时,避免中断块序列。 if (m_CardState == CardState::WAIT_DDS_READ) { if (m_BlockOperationPending || m_PendingCommand != PendingCommand::None) return 0; const auto now = std::chrono::steady_clock::now(); const auto elapsed = std::chrono::duration_cast( now - m_StateEnterTime).count(); if (elapsed >= CARD_READY_IDLE_TIMEOUT_MS) { DEBUG("Card ready idle timeout (" << CARD_READY_IDLE_TIMEOUT_MS << "ms), reverting to AUTO_FIND"); m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = now; m_AutoFindNeedsReset = true; // ★ 与写卡超时路径保持一致 SetCardState(CardState::AUTO_FIND); return 1; } return 0; } // 【新增】WAIT_DDS_WRITE 写卡块操作超时:等 RC522 响应超过 2s 视为失败,回 AUTO_FIND if (m_CardState == CardState::WAIT_DDS_WRITE) { if (!m_BlockOperationPending) return 0; const auto writeNow = std::chrono::steady_clock::now(); const auto writeElapsed = std::chrono::duration_cast( writeNow - m_BlockOpStartTime).count(); if (writeElapsed >= WRITE_BLOCK_OPERATION_TIMEOUT_MS) { // 【关键修复】:如果写块还有重试额度,交给 RecvMsg 的截断帧分支处理, // 不要在 CheckDdsTimeout 里提前清掉 m_PendingCommand,导致 retry 失效。 // if (m_WriteBlockRetryCount < WRITE_BLOCK_MAX_RETRIES) // { // DEBUG("CheckDdsTimeout: WAIT_DDS_WRITE timeout but retries remain (" // << static_cast(m_WriteBlockRetryCount) << "/" // << static_cast(WRITE_BLOCK_MAX_RETRIES) // << "), skipping AUTO_FIND — RecvMsg incomplete handler will retry"); // return 0; // ← 关键:不清状态,让截断帧处理分支优先 // } DEBUG("Write block operation timeout (" << WRITE_BLOCK_OPERATION_TIMEOUT_MS << "ms), reverting to AUTO_FIND"); // 清理 pending 标志 m_BlockOperationPending = false; m_PendingCommand = PendingCommand::None; // 清串口残留帧(避免下个循环再拿到那 5 字节尾巴) m_ReceiveBuffer.clear(); if (fd != -1) tcflush(fd, TCIFLUSH); // ★ 新增:标记需要 reset RC522,由 Publisher 主循环里的 // ConsumeAutoFindNeedsReset() 统一触发 ResetSerialAndReinit() // 与 RecvMsg 截断帧 / TryExtractDeviceFrame CRC 失败的处理路径一致。 m_AutoFindNeedsReset = true; // 恢复自动寻卡 m_AutoFindNeedsReset = true; // ★ 加这行 m_AutoFind = true; m_FindIntervalMs = 5000; //m_LastFindTime = writeNow; m_LastFindTime = writeNow - std::chrono::milliseconds(m_FindIntervalMs); SetCardState(CardState::AUTO_FIND); return 1; } return 0; } if (m_CardState != CardState::WAIT_DDS_DECISION && m_CardState != CardState::WAIT_DDS_WRITE_NEXT) return 0; auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast( now - m_StateEnterTime).count(); // ★ 不同状态用不同的超时阈值 int timeout_ms = DDS_TIMEOUT_MS; if (m_CardState == CardState::WAIT_DDS_DECISION) { timeout_ms = DDS_DECISION_TIMEOUT_MS; } else if (m_CardState == CardState::WAIT_DDS_WRITE_NEXT) // 【新增】 { timeout_ms = DDS_WRITE_TIMEOUT_MS; // 【新增】10秒 } if (elapsed >= timeout_ms) { DEBUG("DDS timeout (" << timeout_ms << "ms), reverting to AUTO_FIND"); // 恢复自动寻卡 m_AutoFind = true; m_FindIntervalMs = 5000; m_LastFindTime = now; // 清空读卡缓冲区 ClearReadBuffer(); // ★ 新增:触发完整 RC522 重置路径,与 WAIT_DDS_READ / WAIT_DDS_WRITE 超时保持一致 m_AutoFindNeedsReset = true; // 切换状态 SetCardState(CardState::AUTO_FIND); return 1; // 返回1表示触发了超时 } return 0; } void MsgHandler::ResetWriteTimeout() { if (m_CardState == CardState::WAIT_DDS_WRITE_NEXT) m_StateEnterTime = std::chrono::steady_clock::now(); } // ========== 单块操作超时控制实现 ========== int MsgHandler::GetBlockOpElapsed() const { std::lock_guard lock(mtx_); auto now = std::chrono::steady_clock::now(); return std::chrono::duration_cast( now - m_BlockOpStartTime).count(); } uint8_t MsgHandler::GetCurrentOperatingBlock() const { std::lock_guard lock(mtx_); return m_CurrentOperatingBlock; } bool MsgHandler::IsBlockOperationPending() const { std::lock_guard lock(mtx_); return m_BlockOperationPending; } bool MsgHandler::HasPendingReadResponse() const { return !m_PendingReadResponse.empty(); } std::vector MsgHandler::GetPendingReadResponse() { auto tmp = m_PendingReadResponse; m_PendingReadResponse.clear(); return tmp; } void MsgHandler::SkipCurrentBlock() { DEBUG("SkipCurrentBlock: state=" << (int)m_CardState << ", index=" << (int)m_CurrentReadIndex << ", total=" << (int)m_RequestedBlocks.size()); // 【新增】标记正在恢复,防止 HandleDdsMsg 在此期间发新命令 m_IsInTimeoutRecovery = true; // ★ 修改:WAIT_DDS_DECISION / WAIT_DDS_WRITE_NEXT 也可以调用 SkipCurrentBlock if (m_CardState != CardState::WAIT_DDS_READ && m_CardState != CardState::WAIT_DDS_DECISION && m_CardState != CardState::WAIT_DDS_WRITE_NEXT) { DEBUG("SkipCurrentBlock: not in WAIT_DDS_READ state, ignored"); m_IsInTimeoutRecovery = false; return; } if (m_RequestedBlocks.empty() || m_CurrentReadIndex >= m_RequestedBlocks.size()) { DEBUG("SkipCurrentBlock: no more blocks to skip"); m_IsInTimeoutRecovery = false; return; } uint8_t skipBlock = m_RequestedBlocks[m_CurrentReadIndex]; DEBUG("Read block timeout, block=" << static_cast(skipBlock)); // 超时不是成功数据,使用 README 约定的设备超时错误码 0x0015。 std::vector rsp_data; rsp_data.push_back(1); // README 约定:设备超时使用大端结果码 0x0015。 rsp_data.push_back(0x00); rsp_data.push_back(0x15); rsp_data.push_back(static_cast(m_CardId.size())); rsp_data.insert(rsp_data.end(), m_CardId.begin(), m_CardId.end()); rsp_data.push_back(0); m_PendingReadResponse = rsp_data; ClearReadBuffer(); m_CurrentOperatingBlock = 0; m_BlockOperationPending = false; m_IsInTimeoutRecovery = false; m_AutoFind = true; m_FindIntervalMs = 500; m_LastFindTime = std::chrono::steady_clock::now(); SetCardState(CardState::AUTO_FIND); DEBUG("Read block timeout response ready, block=" << static_cast(skipBlock)); return; } CardState MsgHandler::GetCardState() const { std::lock_guard lock(mtx_); return m_CardState; } bool MsgHandler::ConsumeAutoFindNeedsReset() { std::lock_guard lock(mtx_); if (!m_AutoFindNeedsReset) { return false; } m_AutoFindNeedsReset = false; return true; } // 【新增】AUTO_FIND 恢复用的细粒度访问器 void MsgHandler::SetAutoFind(bool on) { std::lock_guard lock(mtx_); m_AutoFind = on; } void MsgHandler::SetFindIntervalMs(int interval_ms) { std::lock_guard lock(mtx_); m_FindIntervalMs = interval_ms; } void MsgHandler::SetLastFindTimeToNow() { std::lock_guard lock(mtx_); m_LastFindTime = std::chrono::steady_clock::now(); } void MsgHandler::ClearPendingCommand() { std::lock_guard lock(mtx_); m_PendingCommand = PendingCommand::None; } // ========== refreshPort 默认实现 ========== bool MsgHandler::refreshPort() { DEBUG("MsgHandler::refreshPort: base class default implementation, no-op"); return true; }