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.

1875 lines
64 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());
}
// 兼容现场设备偶发的写应答短帧:
// 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<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);
// 【新增】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<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));
// ★ 移除重试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<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::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<int>(m_WriteBlockRetryCount)
<< " max=" << static_cast<int>(WRITE_BLOCK_MAX_RETRIES));
return false;
}
const uint8_t block = m_PendingWriteBlock;
++m_WriteBlockRetryCount;
DEBUG("Retrying write block=" << static_cast<int>(block)
<< " attempt=" << static_cast<int>(m_WriteBlockRetryCount)
<< "/" << static_cast<int>(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<uint8_t> 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<uint8_t>& 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<uint8_t>& 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<uint8_t>(data.size() - 1U)
&& data[1] == 0x01U
&& data[2] == READ_CARD
&& data[3] == 0x00U;
if (!shortReadFrame && !shortWriteAck
&& 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 (shortWriteAck)
{
DEBUG("Accepting short WRITE_BLOCK ACK without final CRC byte, size="
<< data.size() << " status=0x" << std::hex << static_cast<int>(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<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();
// ★ 修改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<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 操作;写卡不要求先读卡。
// ★ 修改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<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);
// ★ 修复:每次新 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<std::recursive_mutex> lock(mtx_);
std::vector<uint8_t> 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<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;
// ★ 新增:读卡 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<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)
{
// ★ 移除重试:块号不匹配直接回 AUTO_FIND
DEBUG("ReadCard response block mismatch, expected=" << static_cast<int>(blockNum)
<< ", actual=" << static_cast<int>(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<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;
// ★ 修改:读卡成功后切到 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<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;
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<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);
// ★ 新增:清理敏感数据,避免长期驻留内存
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<uint8_t> write_rsp;
write_rsp.push_back(1); // 版本
write_rsp.push_back(static_cast<uint8_t>(error >> 8));
write_rsp.push_back(static_cast<uint8_t>(error & 0xFF)); // 结果码
write_rsp.push_back(static_cast<uint8_t>(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<uint8_t>(error >> 8));
write_rsp.push_back(static_cast<uint8_t>(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<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);
}
// ★ 新增RF 喂送专用寻卡 —— 只发字节,不修改 m_PendingCommand、不动 m_OperationSequence
// 响应回来时 ParseDeviceMsg 会因为 m_PendingCommand != Find 直接丢弃return 0
// 不会触发 HandleFindResponse 改状态,不会污染 HasActiveDeviceOperation() 判断。
void MsgHandler::SendRfFeedFind(void)
{
std::vector<uint8_t> m_SendData;
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);
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<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;
}
// ★ 新增:发命令前延时,让 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<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));
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<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
&& m_CardState != CardState::WAIT_DDS_READ)
return;
const auto now = std::chrono::steady_clock::now();
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
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<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;
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<std::chrono::milliseconds>(
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<int>(m_WriteBlockRetryCount) << "/"
// << static_cast<int>(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<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();
// ★ 新增:触发完整 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<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;
// ★ 修改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<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;
}
bool MsgHandler::ConsumeAutoFindNeedsReset()
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
if (!m_AutoFindNeedsReset)
{
return false;
}
m_AutoFindNeedsReset = false;
return true;
}
// 【新增】AUTO_FIND 恢复用的细粒度访问器
void MsgHandler::SetAutoFind(bool on)
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
m_AutoFind = on;
}
void MsgHandler::SetFindIntervalMs(int interval_ms)
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
m_FindIntervalMs = interval_ms;
}
void MsgHandler::SetLastFindTimeToNow()
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
m_LastFindTime = std::chrono::steady_clock::now();
}
void MsgHandler::ClearPendingCommand()
{
std::lock_guard<std::recursive_mutex> lock(mtx_);
m_PendingCommand = PendingCommand::None;
}
// ========== refreshPort 默认实现 ==========
bool MsgHandler::refreshPort()
{
DEBUG("MsgHandler::refreshPort: base class default implementation, no-op");
return true;
}