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.

253 lines
11 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.

#ifndef _MSGHANDLER_HPP_
#define _MSGHANDLER_HPP_
#include <chrono>
#include <cstdint>
#include <queue>
#include <mutex>
#include <vector>
#include <map>
#include <mutex>
#include <functional>
#include "WeighingDDSType.hpp"
#include <termios.h>
#define BEEP_CARD 1
#define FIND_CARD 2 // 发送命令号
#define FIND_CARD_RSP 0x08 // FindCard 响应命令号固件返回0x08
#define SET_PWD 3
#define READ_CARD 4
#define WRITE_CARD 5
#define STOP_CARD 8 // 发送/响应命令号Pause
enum class CardState {
AUTO_FIND, // 自动寻卡状态
WAIT_DDS_READ, // 等待 DDS read 命令
WAIT_DDS_WRITE, // 等待 DDS write 命令
WAIT_DDS_DECISION, // 读卡完成,等待 DDS 决定write / stop / ack
WAIT_DDS_WRITE_NEXT // 写卡成功,等待下一个 write 命令10秒超时
};
enum class PendingCommand : uint8_t { None, Find, SetPassword, ReadBlock, WriteBlock, Stop, Beep };
class MsgHandler {
public:
int fd;
std::string device;
std::map<uint8_t, std::vector<uint8_t>> m_PassWord;
MsgHandler();
~MsgHandler() = default;
void HandleDdsMsg(const std::map<std::string, std::vector<uint8_t>>& msg, unsigned long index);
int HandleDeviceMsg(WeighingSystem::ReadCardRsp& rsp);
bool SetDevice(const std::string& device);
bool InitSequence(void);
void AutoFindTick(void);
void StorePasswd(std::map<uint8_t, std::vector<uint8_t>>& data);
void SetPasswd(const std::vector<uint8_t>& data);
void FindCard(void);
void ReadCard(const std::vector<uint8_t>& data);
void WriteCard(const std::vector<uint8_t>& data);
void StopCard(void);
void BeepCard(const std::vector<uint8_t>& data);
void ResetCard(void);
int ParseDeviceMsg(std::vector<uint8_t>& data, WeighingSystem::ReadCardRsp& rsp);
bool WaitForResponse(uint8_t expected_cmd, int timeout_ms = 3000);
virtual bool OpenPort(const std::string& port, const std::string& baudrate);
virtual int SendDeviceMsg(const std::vector<uint8_t>& data);
virtual int RecvDeviceMsg(std::vector<uint8_t>& data, int timeoutMs);
int SendMsg(const std::vector<uint8_t>& data);
int RecvMsg(std::vector<uint8_t>& data, int timeoutMs);
bool isOpen() const {
return fd != -1;
}
void ClosePort();
// 【新增】内部版本,不加锁,供 ParseDeviceMsg 的 drain 循环使用
int RecvMsgInternal(std::vector<uint8_t>& data, int timeoutMs);
void SetCardState(CardState state);
unsigned long GetCurrentIndex() const;
bool IsTimeoutRecovery() const;
uint64_t GetOperationSequence() const;
bool IsReadResponseReady() const;
bool IsWriteResponseReady() const;
void ClearReadBuffer();
void SetReadResult(uint8_t resultCode, const std::string& cardId, uint8_t blockCount,
const std::vector<std::pair<uint8_t, std::vector<uint8_t>>>& blockData);
void SetWriteResult(uint8_t resultCode, const std::string& cardId, uint8_t blockNum);
int CheckDdsTimeout();
void ResetWriteTimeout();
std::function<void(const std::string& cardId)> OnCardDetected;
// 【新增】由业务层填充HandleDeviceMsg 检测到卡后写入,主循环读取并发送 QueueTrigger
std::string pending_trigger_card_;
std::mutex trigger_mtx_;
// ========== 单块操作超时控制 ==========
int GetBlockOpElapsed() const;
static constexpr int BLOCK_OPERATION_TIMEOUT_MS = 3000;
static constexpr bool VERIFY_DEVICE_CRC = true;
// 通信帧不完整或 CRC/数据校验失败时,同一读块允许额外重发的次数。
static constexpr uint8_t READ_BLOCK_MAX_RETRIES = 1;
static constexpr int READ_BLOCK_RETRY_DELAY_MS = 100;
uint8_t GetCurrentOperatingBlock() const;
bool IsBlockOperationPending() const;
void SkipCurrentBlock();
bool HasPendingReadResponse() const;
std::vector<uint8_t> GetPendingReadResponse();
CardState GetCardState() const;
// 【新增】业务层主动取消等待、立即回到自动寻卡
void ForceResetToAutoFind();
// 【新增】业务层暂停自动寻卡state 切到 AUTO_FINDm_AutoFind=false
// 用于刚发完 QueueTrigger 后的 3 秒等待期:阻止 HandleDdsMsg 接收 read/write。
void PauseAutoFind();
// 【新增】标记:是否正在执行超时恢复序列
// 原因SkipCurrentBlock 发的恢复命令可能和 HandleDdsMsg 的新命令冲突
bool m_IsInTimeoutRecovery = false;
// 【新增】重置串口并重新初始化 RC522用于块操作超时后的恢复
bool ResetSerialAndReinit();
// 【新增】刷新串口配置(供 SkipCurrentBlock 使用)
bool refreshPort();
// 【新增】保存串口参数,供 ResetSerialAndReinit 使用
std::string m_Port; // 端口名,如 "ttyS1"
speed_t m_Baudrate; // 波特率speed_t 类型)
private:
bool TryExtractDeviceFrame(std::vector<uint8_t>& data);
bool IsValidDeviceFrame(const std::vector<uint8_t>& data);
bool RetryCurrentReadBlock(const char* reason);
bool HasActiveDeviceOperation() const;
int HandleFindResponse(const std::vector<uint8_t>& data,
WeighingSystem::ReadCardRsp& rsp);
static bool IsDataBlock(uint8_t block);
bool m_AutoFind = false;
int m_FindIntervalMs = 500;
std::chrono::steady_clock::time_point m_LastFindTime;
std::string m_PreCard;
// 【新增】保存 WaitForResponse 接收到的 ReadCard 响应数据
std::vector<uint8_t> m_LastReadCardRsp;
//std::mutex mtx_; // 添加这行 - 保护串口访问
mutable std::recursive_mutex mtx_;
std::vector<uint8_t> m_ReceiveBuffer;
CardState m_CardState; // 当前状态
unsigned long m_CurrentIndex; // 保存收到的 index
std::chrono::steady_clock::time_point m_StateEnterTime; // 状态进入时间
static constexpr int DDS_TIMEOUT_MS = 20000; // DDS 命令 10 秒超时
static constexpr int DDS_DECISION_TIMEOUT_MS = 20000; // WAIT_DDS_DECISION 超时
static constexpr int DDS_WRITE_TIMEOUT_MS = 10000; // 写卡序列 10 秒超时
static constexpr int CARD_READY_IDLE_TIMEOUT_MS = 20000; // 卡就绪无任务后恢复寻卡
static constexpr int WRITE_BLOCK_OPERATION_TIMEOUT_MS = 2000;
// 读卡结果缓存
uint8_t m_ResultCode; // 结果码
std::string m_CardId; // 当前操作的卡号
uint8_t m_BlockCount; // 当前读取的块数量
std::vector<std::pair<uint8_t, std::vector<uint8_t>>> m_BlockData; // 块数据
std::vector<uint8_t> m_RequestedBlocks; // 【新增】请求的块号列表
uint8_t m_CurrentReadIndex = 0; // 【新增】当前正在读取的块索引
std::chrono::steady_clock::time_point m_ReadStartTime;
std::chrono::steady_clock::time_point m_ReadEndTime;
// 写卡请求的 pending 信息(响应时用)
uint8_t m_PendingWriteBlock = 0;
std::vector<uint8_t> m_PendingWriteValue;
std::string m_WriteCardId;
// ========== 单块操作超时控制 ==========
std::chrono::steady_clock::time_point m_BlockOpStartTime; // 当前块操作开始时间
uint8_t m_CurrentOperatingBlock = 0; // 当前正在操作的块号
bool m_BlockOperationPending = false; // 当前是否存在待读写响应
PendingCommand m_PendingCommand = PendingCommand::None;
uint8_t m_PendingBlock = 0;
uint8_t m_ReadBlockRetryCount = 0;
uint64_t m_OperationSequence = 0;
std::vector<uint8_t> m_PendingReadResponse; // 超时跳转时准备的响应
std::vector<uint8_t> m_SkippedBlocks; // 【新增】记录跳过的超时块号
uint8_t chCRCHTalbe[256] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40
};
uint8_t chCRCLTalbe[256] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
0x41, 0x81, 0x80, 0x40
};
void CRC16(std::vector<uint8_t>& data);
};
#endif