You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1584 lines
51 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cerrno>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sstream>
#include "MsgHandler.hpp"
#include "DEBUG.hpp"
#include "../common/SerialMsgHandler.hpp"
#include <thread>
#include <fcntl.h>
#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<uint8_t>& bytes)
{
std::ostringstream out;
out << std::hex << std::uppercase << std::setfill('0');
for (uint8_t byte : bytes)
{
out << std::setw(2) << static_cast<int>(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<uint8_t>()),
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<uint8_t>& 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<uint8_t>& 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<uint8_t>& data)
{
std::lock_guard<std::recursive_mutex> 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<size_t>(written);
}
return static_cast<int>(totalWritten);
}
int MsgHandler::RecvMsg(std::vector<uint8_t>& data, int timeoutMs)
{
std::lock_guard<std::recursive_mutex> 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<int>(data.size());
}
const auto remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
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<int>(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);
if (RetryCurrentReadBlock("incomplete frame"))
{
continue;
}
}
return 0;
}
fd_set readfds;
struct timeval tv;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
tv.tv_sec = static_cast<long>(remaining / 1000);
tv.tv_usec = static_cast<long>((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<uint8_t> received(static_cast<size_t>(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<size_t>(bytesRead));
const auto rx_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
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<uint8_t>& data)
{
data.clear();
while (!m_ReceiveBuffer.empty())
{
const size_t expectedSize = static_cast<size_t>(m_ReceiveBuffer.front()) + 1U;
if (expectedSize < 6U || expectedSize > 256U)
{
DEBUG("Discarding invalid device frame length="
<< static_cast<int>(m_ReceiveBuffer.front()));
m_ReceiveBuffer.erase(m_ReceiveBuffer.begin());
continue;
}
if (m_ReceiveBuffer.size() < expectedSize)
{
return false;
}
std::vector<uint8_t> 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));
if (frame.size() >= 4U
&& frame[1] == 0x01U
&& frame[2] == READ_CARD
&& m_PendingCommand == PendingCommand::ReadBlock
&& RetryCurrentReadBlock("CRC validation failure"))
{
return false;
}
continue;
}
data = std::move(frame);
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<int>(m_ReadBlockRetryCount)
<< " max=" << static_cast<int>(READ_BLOCK_MAX_RETRIES));
return false;
}
const uint8_t block = m_PendingBlock;
++m_ReadBlockRetryCount;
DEBUG("Retrying read block=" << static_cast<int>(block)
<< " attempt=" << static_cast<int>(m_ReadBlockRetryCount)
<< "/" << static_cast<int>(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<int>(block));
ReadCard({block});
return true;
}
bool MsgHandler::HasActiveDeviceOperation() const
{
return m_PendingCommand != PendingCommand::None || m_BlockOperationPending;
}
int MsgHandler::HandleFindResponse(const std::vector<uint8_t>& data,
WeighingSystem::ReadCardRsp& rsp)
{
m_PendingCommand = PendingCommand::None;
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);
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 = false;
SetCardState(CardState::WAIT_DDS_READ);
rsp.msg()["find"].insert(rsp.msg()["find"].end(), data.begin() + 4, data.begin() + 8);
{
std::lock_guard<std::mutex> lock(trigger_mtx_);
pending_trigger_card_ = m_CardId;
}
DEBUG("Card found: " << m_CardId << ", ready for DDS read or write command");
return 1;
}
bool MsgHandler::IsValidDeviceFrame(const std::vector<uint8_t>& data)
{
if (data.size() < 6U)
{
return false;
}
const bool shortReadFrame = data.size() >= 21U
&& data[0] != static_cast<uint8_t>(data.size() - 1U)
&& data[1] == 0x01U
&& data[2] == READ_CARD
&& data[3] == 0x00U;
if (!shortReadFrame && data.size() != static_cast<size_t>(data[0]) + 1U)
{
return false;
}
if (data[1] != 0x01)
{
DEBUG("Invalid device fixed byte=" << std::hex << static_cast<int>(data[1]));
return false;
}
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<int>(data[2]));
return true;
}
std::vector<uint8_t> 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<int>(crcData[crcData.size() - 2]) << "/"
<< static_cast<int>(crcData[crcData.size() - 1])
<< " actual(high/low)=" << static_cast<int>(data[data.size() - 2])
<< "/" << static_cast<int>(data[data.size() - 1]));
}
return valid;
}
bool MsgHandler::IsDataBlock(uint8_t block)
{
return block < 64U && (block % 4U) != 3U;
}
void MsgHandler::HandleDdsMsg(const std::map<std::string, std::vector<uint8_t>>& msg,
unsigned long index)
{
std::lock_guard<std::recursive_mutex> 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();
if (m_CardState != CardState::WAIT_DDS_READ)
{
DEBUG("Unexpected read command, current state=" << (int)m_CardState);
return;
}
if (HasActiveDeviceOperation())
{
DEBUG("Rejecting read command: device operation is active");
return;
}
// 解析 read 请求协议:
// 版本(1) | 卡号长度(1) | 卡号ASCII | 块数量(1) | 块号列表
const std::vector<uint8_t>& 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<size_t>(3U + cardIdLen))
{
DEBUG("Invalid read request card ID length=" << static_cast<int>(cardIdLen));
return;
}
std::string reqCardId(data.begin() + 2, data.begin() + 2 + cardIdLen);
uint8_t blockCount = data[2 + cardIdLen];
if (data.size() < static_cast<size_t>(3U + cardIdLen + blockCount))
{
DEBUG("Invalid read request block count=" << static_cast<int>(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<int>(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<uint8_t>(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 操作;写卡不要求先读卡。
if (m_CardState != CardState::WAIT_DDS_READ)
{
DEBUG("Unexpected write command, current state=" << (int)m_CardState);
return;
}
if (HasActiveDeviceOperation())
{
DEBUG("Rejecting write command: device operation is active");
return;
}
// 解析 write 请求协议:
// 版本(1) | 卡号长度(1) | 卡号ASCII | 块号(1) | 16字节块数据
const std::vector<uint8_t>& 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<size_t>(3U + cardIdLen + 16U))
{
DEBUG("Invalid write request length=" << data.size()
<< ", card ID length=" << static_cast<int>(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<int>(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<uint8_t> writeData;
writeData.push_back(blockNum);
writeData.insert(writeData.end(),
data.begin() + 3 + cardIdLen,
data.begin() + 3 + cardIdLen + 16);
DEBUG("Writing block " << (int)blockNum);
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<std::recursive_mutex> lock(mtx_);
std::vector<uint8_t> m_RecvData;
if (RecvDeviceMsg(m_RecvData, 200) > 0)
{
// for (int num : m_RecvData)
// {
// std::cout << std::hex << std::setw(2) << std::setfill('0')
// << num << " ";
// }
// std::cout << std::endl;
return (ParseDeviceMsg(m_RecvData, rsp));
}
return 0;
}
void MsgHandler::CRC16(std::vector<uint8_t>& 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<uint8_t>& 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<int>(data[2])
<< " status=0x" << static_cast<int>(data[3])
<< " state=" << CardStateName(m_CardState)
<< " dds_index=" << std::dec << m_CurrentIndex
<< " pending_block=" << static_cast<int>(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<int>(status));
std::vector<uint8_t> rsp_data;
rsp_data.push_back(1);
const uint16_t error = MapDeviceError(READ_CARD, status);
rsp_data.push_back(static_cast<uint8_t>(error >> 8));
rsp_data.push_back(static_cast<uint8_t>(error & 0xFF));
rsp_data.push_back(static_cast<uint8_t>(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;
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<uint8_t> 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<int>(blockNum)
<< ", actual=" << static_cast<int>(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)
{
DEBUG("ReadCard response block mismatch, expected=" << static_cast<int>(blockNum)
<< ", actual=" << static_cast<int>(responseBlock));
RetryCurrentReadBlock("response block mismatch");
return 0;
}
block16.assign(data.begin() + 5, data.begin() + 21);
}
else
{
DEBUG("ReadCard success payload length invalid, size=" << payloadSize);
RetryCurrentReadBlock("invalid payload length");
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<uint8_t> 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;
// 读卡事务结束后保留当前卡 10 秒,期间可继续接收 DDS 读写命令。
m_AutoFind = false;
SetCardState(CardState::WAIT_DDS_READ);
// 【新增】结束计时并打印
m_ReadEndTime = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
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;
DEBUG("WriteCard OK: block=" << (int)m_PendingWriteBlock);
SetCardState(CardState::WAIT_DDS_READ);
DEBUG("Write complete, card remains ready for next DDS command");
// ★ 与 read 响应同协议1 键 + vector
std::vector<uint8_t> 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);
return 1;
}
else // 写卡失败
{
m_BlockOperationPending = false;
m_PendingCommand = PendingCommand::None;
m_AutoFind = true;
m_FindIntervalMs = 500;
m_LastFindTime = std::chrono::steady_clock::now();
SetCardState(CardState::AUTO_FIND);
DEBUG("WriteCard FAIL: block=" << (int)m_PendingWriteBlock
<< " error code=0x" << std::hex << (int)data[3]);
// ★ 失败也用 1 键 + vector
std::vector<uint8_t> write_rsp;
write_rsp.push_back(1); // 版本
const uint16_t error = MapDeviceError(WRITE_CARD, data[3]);
write_rsp.push_back(static_cast<uint8_t>(error >> 8));
write_rsp.push_back(static_cast<uint8_t>(error & 0xFF)); // 结果码
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(static_cast<uint8_t>(error >> 8));
write_rsp.push_back(static_cast<uint8_t>(error & 0xFF)); // 块结果码
rsp.msg()["write"] = write_rsp;
rsp.index(m_CurrentIndex);
return 1;
}
}
break;
default:
break;
}
return 0;
}
void MsgHandler::StorePasswd(std::map<uint8_t, std::vector<uint8_t>>& data)
{
m_PassWord = data;
}
void MsgHandler::SetPasswd(const std::vector<uint8_t>& data)
{
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 添加延迟
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> m_SendData;
m_PendingCommand = PendingCommand::Find;
++m_OperationSequence;
m_SendData.insert(m_SendData.end(), {0x04, 0x01, 0x02});
CRC16(m_SendData);
SendDeviceMsg(m_SendData);
}
void MsgHandler::ReadCard(const std::vector<uint8_t>& data)
{
std::vector<uint8_t> 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);
SendDeviceMsg(m_SendData);
// 【新增】保护延时:给 RC522 和 STM32 固件留出处理时间
// 原因连续发读块命令时RC522 内部认证状态可能丢失
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void MsgHandler::WriteCard(const std::vector<uint8_t>& 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;
}
m_PendingWriteBlock = data[0];
m_PendingWriteValue.assign(data.begin() + 1, data.end());
DEBUG("WriteCard request block=" << static_cast<int>(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<uint8_t> 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));
SendDeviceMsg(m_SendData);
}
void MsgHandler::BeepCard(const std::vector<uint8_t>& data)
{
std::vector<uint8_t> 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<uint8_t> 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<std::recursive_mutex> lock(mtx_);
if (!m_AutoFind)
return;
if (m_CardState != CardState::AUTO_FIND)
return;
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - m_LastFindTime).count();
if (elapsed >= m_FindIntervalMs)
{
DEBUG("AUTO_FIND tick elapsed_ms=" << elapsed
<< " interval_ms=" << m_FindIntervalMs);
FindCard();
m_FindIntervalMs = 5000; // 发送后5000ms超时保护
m_LastFindTime = now;
}
}
void MsgHandler::SetCardState(CardState state)
{
std::lock_guard<std::recursive_mutex> 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<std::recursive_mutex> lock(mtx_);
return m_CurrentIndex;
}
bool MsgHandler::IsTimeoutRecovery() const
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
return m_IsInTimeoutRecovery;
}
uint64_t MsgHandler::GetOperationSequence() const
{
std::lock_guard<std::recursive_mutex> 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<std::pair<uint8_t, std::vector<uint8_t>>>& 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<std::recursive_mutex> 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<std::chrono::milliseconds>(
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;
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<std::chrono::milliseconds>(
writeNow - m_BlockOpStartTime).count();
if (writeElapsed >= WRITE_BLOCK_OPERATION_TIMEOUT_MS)
{
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);
// 恢复自动寻卡
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<std::chrono::milliseconds>(
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();
// 切换状态
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<std::recursive_mutex> lock(mtx_);
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(
now - m_BlockOpStartTime).count();
}
uint8_t MsgHandler::GetCurrentOperatingBlock() const
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
return m_CurrentOperatingBlock;
}
bool MsgHandler::IsBlockOperationPending() const
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
return m_BlockOperationPending;
}
bool MsgHandler::HasPendingReadResponse() const
{
return !m_PendingReadResponse.empty();
}
std::vector<uint8_t> 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;
if (m_CardState != CardState::WAIT_DDS_READ)
{
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<int>(skipBlock));
// 超时不是成功数据,使用 README 约定的设备超时错误码 0x0015。
std::vector<uint8_t> 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<uint8_t>(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<int>(skipBlock));
return;
}
CardState MsgHandler::GetCardState() const
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
return m_CardState;
}
void MsgHandler::ForceResetToAutoFind()
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
DEBUG("ForceResetToAutoFind: reverting to AUTO_FIND");
m_AutoFind = true;
m_FindIntervalMs = 500;
m_LastFindTime = std::chrono::steady_clock::now();
m_BlockOperationPending = false;
m_PendingCommand = PendingCommand::None;
m_CurrentOperatingBlock = 0;
m_ReadBlockRetryCount = 0;
SetCardState(CardState::AUTO_FIND);
}
void MsgHandler::PauseAutoFind()
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
DEBUG("PauseAutoFind: state=AUTO_FIND, m_AutoFind=false (waiting after QueueTrigger)");
m_AutoFind = false;
SetCardState(CardState::AUTO_FIND);
}
// ========== refreshPort 默认实现 ==========
bool MsgHandler::refreshPort()
{
DEBUG("MsgHandler::refreshPort: base class default implementation, no-op");
return true;
}