# RFIDManager 实现方案 ## 概述 当前项目中的RFID功能通过`__RFID_CARD`宏控制,该宏通过条件编译启用或禁用RFID相关代码。这种方法在可维护性、测试和运行时灵活性方面存在局限。为了解决这些问题,我们建议引入`RFIDManager`类,该类封装所有RFID操作,提供更清洁、更模块化的设计。 `RFIDManager`将处理RFID初始化、数据读取和验证,仅通过QT信号通知外部卡片检测事件,让外部组件(如InkJetPrinter)负责具体的处理逻辑,替换代码库中分散的`#ifdef __RFID_CARD`块。 ## 目标 - **封装**:将RFID逻辑集中到一个类中。 - **运行时控制**:允许在运行时而不是编译时启用/禁用RFID功能。 - **可维护性**:通过移除预处理器指令简化代码。 - **可扩展性**:更容易添加新RFID功能或修改现有功能。 - **测试**:无需重新编译即可对RFID组件进行单元测试。 ## 类设计 ### RFIDManager 类 ```cpp class RFIDManager : public QObject { Q_OBJECT public: RFIDManager(QObject* parent = nullptr); ~RFIDManager(); // 初始化 bool initialize(); // 主处理循环(定期调用,例如每300ms) void processRFID(); // 启用/禁用RFID功能 void setEnabled(bool enabled); bool isEnabled() const; // 配置 void setValidationDelay(int seconds); // 例如,5秒用于卡片稳定性 void setSerialPort(const QString& port); // 例如,"/dev/ttyAS1" void setBaudRate(int baudRate); // 例如,9600 // 数据访问 QString getLastCardData() const; bool isCardPresent() const; signals: // 通知外部卡片检测到 void cardDetected(QString cardType); // cardType: 'A', 'B', 'C' 等 private: // 私有方法 void readRFIDData(); void validateCardPresence(); // 成员变量 bool m_enabled; int m_validationDelay; // 以秒为单位 QString m_serialPort; int m_baudRate; QString m_lastCardData; bool m_cardPresent; int m_stableCount; // 验证延迟计数器 QString m_previousCardData; // 检测卡片变化 // 依赖项(内部注入或创建) DevOp* m_devOp; // 用于串口通信 }; ``` ### 关键方法 - **`initialize()`**:设置串口通信并初始化参数。固定串口名为"/dev/ttyAS1",比特率9600等 - **`processRFID()`**:主方法,在定时器循环中调用。读取数据、验证卡片存在,如果验证通过则发射`cardDetected`信号。 - **`setEnabled(bool)`**:RFID功能的运行时切换。 - **`setValidationDelay(int)`**:配置卡片验证延迟(例如,5秒)。 - **`readRFIDData()`**:与`DevOp`接口读取串口数据。 - **`validateCardPresence()`**:通过计数连续稳定读取实现延迟逻辑,如果延迟满足则发射信号。 ## 集成计划 ### 步骤1:创建RFIDManager类 - 在项目源目录中创建`RFIDManager.h`和`RFIDManager.cpp`。 - 按照上述大纲实现类。 ### 步骤2:在InkJetPrinter.cpp中替换宏使用 - 在`InkJetPrinter.cpp`中移除`#ifdef __RFID_CARD`块。 - 将`RFIDManager`实例添加为成员变量。 - 在构造函数中初始化`RFIDManager`,并连接信号到槽函数。 - 在`timerHandler()`中,将RFID逻辑替换为调用`rfidManager.processRFID()`。 - 添加槽函数(如`onCardDetected(QString cardType)`)来处理卡片检测逻辑,包括显示对话框和更新参数。 在`InkJetPrinter.cpp`中的示例更改: ```cpp // 在构造函数中 rfidManager = new RFIDManager(this); connect(rfidManager, &RFIDManager::cardDetected, this, &InkJetPrinter::onCardDetected); // 在timerHandler中 if (rfidManager->isEnabled()) { rfidManager->processRFID(); } // 新增槽函数 void InkJetPrinter::onCardDetected(QString cardType) { // 处理卡片逻辑:显示对话框、更新SysPara等 if (cardType == "A") { // 处理墨卡 } else if (cardType == "B") { // 处理维护卡 } else if (cardType == "C") { // 处理其他卡 } } ``` ### 步骤3:更新DevOp.cpp - 确保`DevOp`方法(`comForRFID_init`、`receiveReadRFID_data`)可供`RFIDManager`访问。 - 可能使`DevOp`成为单例,或通过依赖注入将其传递给`RFIDManager`。 ### 步骤4:更新SysPara.h - 确保`RFIDPara_t`可供`RFIDManager`访问以进行参数更新。 ### 步骤5:配置 - 将RFID设置添加到配置文件或UI中,允许运行时更改启用/禁用和设置延迟。 ### 步骤6:移除宏 - 完全集成后,从`myinclude.h`中移除`__RFID_CARD`宏并清理任何剩余的条件代码。 ## 验证延迟实现 为了防止误操作,实现5秒延迟: - 跟踪具有相同卡片数据的连续读取。 - 仅在~17次稳定读取后发射`cardDetected`信号(300ms * 17 ≈ 5.1秒)。 - 如果卡片数据变化或消失,则重置计数器。 ```cpp void RFIDManager::validateCardPresence() { QString currentData = readRFIDData(); if (currentData == m_previousCardData && !currentData.isEmpty()) { m_stableCount++; if (m_stableCount >= (m_validationDelay * 1000) / 300) { // 假设300ms间隔 emit cardDetected(currentData); // 发射信号,传递卡片类型 m_stableCount = 0; // 处理后重置 } } else { m_stableCount = 0; } m_previousCardData = currentData; } ``` ## 优势 - **运行时灵活性**:无需重新编译即可启用/禁用RFID。 - **更清洁的代码**:逻辑中无预处理器指令混乱。 - **更好的测试**:为单元测试模拟`RFIDManager`。 - **模块化**:更容易扩展或修改RFID功能。 - **错误处理**:RFID操作的集中错误处理。 ## 潜在挑战 - **依赖注入**:确保`DevOp`和`SysPara`正确注入或可访问。 - **线程安全**:如果从定时器调用`processRFID()`,确保线程安全。 - **向后兼容性**:彻底测试以确保功能无回归。 ## 测试计划 - `RFIDManager`方法的单元测试。 - 与`InkJetPrinter`的集成测试。 - 使用实际RFID硬件的手动测试,以验证延迟和检测。 ## 时间表 1. **第1周**:设计并实现`RFIDManager`类。 2. **第2周**:集成到`InkJetPrinter.cpp`并测试。 3. **第3周**:更新配置并移除宏。 4. **第4周**:全面测试和文档。 此方案为将RFID功能重构为更可维护和灵活的系统提供了坚实基础。