189 lines
6.3 KiB
Markdown
189 lines
6.3 KiB
Markdown
# 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功能重构为更可维护和灵活的系统提供了坚实基础。 |