#ifndef _MSGHANDLER_HPP_ #define _MSGHANDLER_HPP_ #include #include #include #include #include #include #include #include #include "WeighingDDSType.hpp" #include #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> m_PassWord; MsgHandler(); ~MsgHandler() = default; void HandleDdsMsg(const std::map>& 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>& data); void SetPasswd(const std::vector& data); void FindCard(void); void ReadCard(const std::vector& data); void WriteCard(const std::vector& data); void StopCard(void); void BeepCard(const std::vector& data); void ResetCard(void); int ParseDeviceMsg(std::vector& 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& data); virtual int RecvDeviceMsg(std::vector& data, int timeoutMs); int SendMsg(const std::vector& data); int RecvMsg(std::vector& data, int timeoutMs); bool isOpen() const { return fd != -1; } void ClosePort(); // 【新增】内部版本,不加锁,供 ParseDeviceMsg 的 drain 循环使用 int RecvMsgInternal(std::vector& 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>>& blockData); void SetWriteResult(uint8_t resultCode, const std::string& cardId, uint8_t blockNum); int CheckDdsTimeout(); void ResetWriteTimeout(); std::function OnCardDetected; // ========== 单块操作超时控制 ========== int GetBlockOpElapsed() const; static constexpr int BLOCK_OPERATION_TIMEOUT_MS = 3000; static constexpr bool VERIFY_DEVICE_CRC = true; // 现场部分设备的写应答偶尔只返回 LEN、命令、状态和一个 CRC 字节。 // 允许兼容该固定 5 字节残帧,但仍必须检查状态码。 static constexpr bool ALLOW_SHORT_WRITE_ACK = 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 GetPendingReadResponse(); CardState GetCardState() const; // 【新增】标记:是否正在执行超时恢复序列 // 原因:SkipCurrentBlock 发的恢复命令可能和 HandleDdsMsg 的新命令冲突 bool m_IsInTimeoutRecovery = false; // 【新增】重置串口并重新初始化 RC522(用于块操作超时后的恢复) bool ResetSerialAndReinit(); // 【新增】刷新串口配置(供 SkipCurrentBlock 使用) bool refreshPort(); // 【新增】保存串口参数,供 ResetSerialAndReinit 使用 std::string m_Port; // 端口名,如 "ttyS1" speed_t m_Baudrate; // 波特率(speed_t 类型) // 【新增】AUTO_FIND 重置标志的读取+清零接口 // 语义:返回 m_AutoFindNeedsReset 的当前值,并立刻置为 false(只触发一次)。 bool ConsumeAutoFindNeedsReset(); // 【新增】AUTO_FIND 恢复用的细粒度访问器 // 原因:m_AutoFind / m_FindIntervalMs / m_LastFindTime / m_PendingCommand 都是 private, // Publisher 主循环里的恢复块必须走这些 setter 才能编译通过。 void SetAutoFind(bool on); void SetFindIntervalMs(int interval_ms); void SetLastFindTimeToNow(); void ClearPendingCommand(); // ========== 新增:写卡块重试配置 ========== static constexpr uint8_t WRITE_BLOCK_MAX_RETRIES = 2; // 写卡失败最多重试 2 次 static constexpr int WRITE_BLOCK_RETRY_DELAY_MS = 150; // 重试前等待 150ms(>MIFARE 写后忙窗口) uint8_t m_WriteBlockRetryCount = 0; // 当前写块重试计数 void SendRfFeedFind(); // ★ 新增:RF 喂送专用寻卡(不动 m_PendingCommand) private: bool TryExtractDeviceFrame(std::vector& data); bool IsValidDeviceFrame(const std::vector& data); bool RetryCurrentReadBlock(const char* reason); bool RetryCurrentWriteBlock(const char* reason); bool HasActiveDeviceOperation() const; int HandleFindResponse(const std::vector& 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 m_LastReadCardRsp; //std::mutex mtx_; // 添加这行 - 保护串口访问 mutable std::recursive_mutex mtx_; std::vector 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 = 5000; // 读卡结果缓存 uint8_t m_ResultCode; // 结果码 std::string m_CardId; // 当前操作的卡号 uint8_t m_BlockCount; // 当前读取的块数量 std::vector>> m_BlockData; // 块数据 std::vector 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 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 m_PendingReadResponse; // 超时跳转时准备的响应 std::vector m_SkippedBlocks; // 【新增】记录跳过的超时块号 // AUTO_FIND 状态下检测到 CRC/length 异常或超时后, // 通知主循环走 ResetSerialAndReinit() 重置 RC522(与 WAIT_DDS_WRITE 超时恢复并联)。 bool m_AutoFindNeedsReset = false; 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& data); }; #endif