From f1ae7ae8988d92b82f37e38aa5caf00e9a372212 Mon Sep 17 00:00:00 2001 From: Byons Date: Thu, 23 Jul 2026 08:37:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DRFID=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E5=9B=9E=E6=94=B6=E6=A7=BD=E5=85=B3=E9=97=AD=EF=BC=9B=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=96=B0=E5=BB=BA=E6=96=87=E4=BB=B6=E5=90=8E=E4=B8=8D?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=87=E6=8D=A2=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- InkJetPrinter.cpp | 10 +- docs/项目架构说明文档.md | 626 +++++++++++++++++++++++++++++++++++++++ rfid/rfidmanager.cpp | 192 +++++++----- rfid/rfidmanager.h | 16 +- testprintwidget.cpp | 3 +- 5 files changed, 770 insertions(+), 77 deletions(-) create mode 100644 docs/项目架构说明文档.md diff --git a/InkJetPrinter.cpp b/InkJetPrinter.cpp index e6c1096..fd2eb45 100644 --- a/InkJetPrinter.cpp +++ b/InkJetPrinter.cpp @@ -1522,8 +1522,16 @@ void InkJetPrinter::getMainWidgetButtonClickedSlot(int index) switch (index) { case 1: { // 编辑当前文件 - m_TestPrintWidget->openWorkFile(sysPara->para.lastOpenedFileName); + + // 如果上次打开的文件不存在或者不是xml文件,则创建一个新的作业文件 QFileInfo fileInfo(sysPara->para.lastOpenedFileName); + if(!fileInfo.exists() || fileInfo.suffix() != "xml"){ + createNewJobFile(); + break; + } + + // 如果上次打开的文件存在且是xml文件,则直接打开该文件 + m_TestPrintWidget->openWorkFile(sysPara->para.lastOpenedFileName); ui.label_currEditFile->setText(QString("E: %1").arg(fileInfo.baseName())); m_StackedWidget->setCurrentWidget(m_TestPrintWidget); break; diff --git a/docs/项目架构说明文档.md b/docs/项目架构说明文档.md new file mode 100644 index 0000000..605ad1c --- /dev/null +++ b/docs/项目架构说明文档.md @@ -0,0 +1,626 @@ +# QtUI 喷码机项目架构说明文档 + +> **版本**: V6.7.4 +> **目标平台**: ARM Linux (AM335x) / x86 (模拟调试) +> **Qt 版本**: Qt 4.6.3 (ARM) / Qt 5.x (x86) +> **屏幕分辨率**: 800x600 +> **文档编写日期**: 2026-07-23 + +--- + +## 目录 + +1. [项目概述](#1-项目概述) +2. [技术栈](#2-技术栈) +3. [整体架构](#3-整体架构) +4. [目录结构](#4-目录结构) +5. [核心模块详解](#5-核心模块详解) +6. [数据流与通信机制](#6-数据流与通信机制) +7. [场景与打印渲染系统](#7-场景与打印渲染系统) +8. [RFID刷卡模块](#8-rfid刷卡模块) +9. [编译构建系统](#9-编译构建系统) +10. [关键配置与宏定义](#10-关键配置与宏定义) +11. [新同事上手指南](#11-新同事上手指南) + +--- + +## 1. 项目概述 + +本项目是一个**工业喷码机(CIJ,Continuous Ink Jet)的上位机控制系统**,运行在嵌入式ARM Linux平台上。软件通过串口与FPGA和STM32两块下位机硬件通信,实现喷码内容的编辑、预览、打印控制、设备状态监控、系统参数管理等功能。 + +### 核心功能 + +- **喷码内容编辑**: 支持文本、日期、计数器、图片、条形码(一维码)、二维码(QR/DataMatrix)等图元 +- **打印控制**: 支持时延触发、电眼触发、同步器触发、电眼+同步器等多种触发模式 +- **设备管理**: 墨路控制(阀门、泵、加热器)、粘度检测、相位检测、高压控制 +- **系统管理**: 参数配置、FPGA/STM32固件升级、软件更新、日志管理 +- **文件管理**: 作业文件的创建、保存、导入、导出(U盘) +- **RFID刷卡**: 墨水/溶剂/保养卡的身份验证与消耗管理 +- **多语言支持**: 中文、英文、土耳其语、西班牙语、泰语、越南语、韩语、波斯语等 + +--- + +## 2. 技术栈 + +| 类别 | 技术 | +|------|------| +| 框架 | Qt 4.6.3 (ARM) / Qt 5.x (x86) | +| 语言 | C++ (C++11),部分C | +| 构建工具 | qmake | +| UI设计 | Qt Designer (.ui文件) | +| 序列化 | XML (作业文件)、INI (配置文件) | +| 通信 | QSerialPort (RS232/RS485) | +| 网络 | Qt Network (WiFi) | +| 条码生成 | C语言库 (BarCode目录) | +| 二维码生成 | C语言库 (QtQREnCode目录) | +| DataMatrix | C++库 (Matrix目录) | +| Modbus | 开源FreeModbus库 | +| 加密 | SM3/SM4 国密算法 | +| 日志 | 自定义Logger框架 | + +--- + +## 3. 整体架构 + +项目采用**分层架构**,自上而下分为: + +``` +┌─────────────────────────────────────────────────────────┐ +│ UI 表现层 │ +│ InkJetPrinter (主窗口) + MainWidget (打印主界面) │ +│ 各功能页面: SystemManage, SystemSetting, LogInfo, ... │ +│ 场景编辑器: TestPrintWidget, ItemEditor, PicScene │ +├─────────────────────────────────────────────────────────┤ +│ 业务逻辑层 │ +│ SysPara (系统参数管理) │ +│ DevOp (设备操作) │ +│ RunTimeCtrl (运行时间统计) │ +│ LogInfoCtrl (日志控制) │ +│ RFIDManager (刷卡管理) │ +├─────────────────────────────────────────────────────────┤ +│ 通信层 │ +│ Serial (串口通信封装) │ +│ Modbus (Modbus协议) │ +├─────────────────────────────────────────────────────────┤ +│ 硬件抽象层 │ +│ FPGA (喷印控制、高压、相位检测) │ +│ STM32 (墨路控制、传感器采集) │ +│ RFID读卡器 (IC卡读写) │ +└─────────────────────────────────────────────────────────┘ +``` + +### 模块依赖关系图 + +``` +InkJetPrinter (顶层窗口) + ├── MainWidget (打印主界面) + │ ├── PicScene (场景管理) + │ ├── FileManageWidget (文件管理) + │ └── PrintTextDisplay (打印预览) + ├── TestPrintWidget (编辑界面) + │ ├── PicScene (场景编辑) + │ ├── ItemEditor (图元编辑) + │ ├── ImageLoader (图片加载) + │ ├── BarcodeEditor (条码编辑) + │ └── CounterVarSet (计数器设置) + ├── SystemManage (系统管理) + ├── SystemSetting (系统设置) + ├── SystemUpdate (系统升级) + ├── FontSetWidget (字体设置) + ├── PrintSetting (打印设置) + ├── MainInstruction (主指令) + ├── LogInfo (日志信息) + ├── OtherInfo (其他信息) + ├── DateVarSet (日期变量设置) + ├── CounterVarSet (计数器变量设置) + ├── QBarCode / dlgQrCode (条码/二维码对话框) + ├── DialogFileOperation (文件操作) + └── ScheduleShiftsEditor (班次编辑) + +SysPara (系统参数,贯穿所有模块) +Serial (串口通信,连接FPGA和STM32) +RFIDManager (RFID刷卡管理) +RunTimeCtrl (运行时间控制) +``` + +--- + +## 4. 目录结构 + +``` +项目根目录/ +├── QtUI.pro # 项目文件 (qmake) +├── main.cpp # 程序入口 +├── mainwidget.h/cpp # 打印主界面 (MainWidget) +├── InkJetPrinter.h/cpp # 顶层主窗口 +├── Public.h/cpp # 公共工具类 +├── SysPara.h/cpp # 系统参数管理 (核心) +├── DevOp.h/cpp # 设备操作 (FPGA寄存器读写) +├── myinclude.h # 全局宏定义、枚举 +├── VerBVersion.h # 版本号定义 +├── dump.h/cpp # 崩溃信号处理 +├── runtimectrl.h/cpp # 运行时间统计 +│ +├── scene/ # 场景(喷码内容)编辑系统 +│ ├── picscene.h/cpp # 场景类 (QGraphicsScene) +│ ├── myview.h/cpp # 视图类 (QGraphicsView) +│ ├── PicSceneLoader.h/cpp # 场景XML加载/保存 +│ ├── pictextitem.h/cpp # 文本图元 +│ ├── PicDateItem.h/cpp # 日期图元 +│ ├── PicImageItem.h/cpp # 图片图元 +│ ├── PicCounterItem.h/cpp # 计数器图元 +│ ├── PicScheduleShiftItem.h/cpp # 班次图元 +│ ├── piccodeitem.h/cpp # 条码/二维码图元 +│ ├── ViewModels.h/cpp # 视图模型 (数据结构) +│ ├── ItemCommon.h/cpp # 图元工具函数 +│ ├── ItemGeneralSettings.* # 图元通用设置 +│ ├── BarcodeEditor.* # 条码编辑器 +│ ├── CounterEditor.* # 计数器编辑器 +│ ├── DateFormatEditor.* # 日期格式编辑器 +│ ├── DateReplaceEditor.* # 日期替换编辑器 +│ ├── ScheduleShiftsEditor.* # 班次编辑器 +│ ├── DlgBarcodeFormat.* # 条码格式对话框 +│ ├── DlgQrcodeFormat.* # 二维码格式对话框 +│ └── sceneviewwidget.* # 场景视图封装 +│ +├── rfid/ # RFID刷卡模块 +│ ├── rfidmanager.h/cpp # 刷卡管理核心 +│ ├── rfidfunction.h/cpp # 刷卡功能函数 +│ ├── sm3.h/cpp # SM3 国密哈希 +│ └── sm4.h/cpp # SM4 国密加密 +│ +├── Serial/ # 串口通信封装 +│ └── serial.h/cpp # 串口封装 (FPGA/STM32双通道) +│ +├── fileManage/ # 文件管理 +│ ├── FileManageWidget.* # 文件管理界面 +│ └── UDiskComboBox.* # U盘检测与文件列表 +│ +├── modbus/ # Modbus协议 +│ ├── modbus/ # FreeModbus库 +│ ├── port/ # 移植层 +│ ├── modbusserial.* # Modbus串口 +│ └── modbustcp.* # Modbus TCP +│ +├── Log/ # 日志框架 +│ ├── logger.h/cpp # 日志基类 +│ ├── filelogger.h/cpp # 文件日志 +│ ├── logmessage.h/cpp # 日志消息 +│ └── logglobal.h # 日志全局宏 +│ +├── BarCode/ # 一维条码生成库 (C) +│ ├── barcode.h # 条码头文件 +│ ├── code128.c/code39.c/ # 各类型条码实现 +│ └── ... +│ +├── QtQREnCode/ # 二维码生成库 (C) +│ ├── qrencode.h/c # QR码生成 +│ └── ... +│ +├── Matrix/ # DataMatrix码生成库 (C++) +│ ├── dm200.cpp # DataMatrix实现 +│ └── ... +│ +├── qjson/ # JSON解析库 +│ +├── image.qrc # Qt资源文件 +├── *.ts # 多语言翻译文件 +│ +├── 0/ ~ 101/ # 字库图片资源 (数字位图) +│ └── image/ +│ └── digitalWidth*.bmp +│ +└── conf/ # 运行时配置目录 (部署后) + ├── sysPara.bin # 系统参数二进制文件 + ├── config.ini # 日志配置 + └── ... +``` + +--- + +## 5. 核心模块详解 + +### 5.1 程序入口 (main.cpp) + +[main.cpp](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/main.cpp) + +程序启动流程: +1. 读取键盘类型配置(多语言键盘/普通键盘) +2. 创建 QApplication,配置日志系统 (FileLogger) +3. 加载字体和应用级样式 +4. 根据语言配置加载对应翻译文件 (.qm) +5. 创建 MyInputMethod(自定义输入法) +6. 创建 InkJetPrinter 主窗口并显示 + +### 5.2 主窗口 (InkJetPrinter) + +[InkJetPrinter.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/InkJetPrinter.h) | [InkJetPrinter.cpp](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/InkJetPrinter.cpp) + +**职责**: 顶层窗口,管理所有子页面和核心业务流程。 + +**关键成员**: +- `m_StackedWidget` - 页面容器,通过索引切换不同功能页面 +- `m_MainWidget` - 打印主界面(首页) +- `m_TestPrintWidget` - 编辑界面 +- `serialFPGA` / `serialSTM32` - 两个独立串口线程,分别与FPGA和STM32通信 +- `ctrl_runTime` - 运行时间控制器 +- `manager_rfid` - RFID刷卡管理器 + +**核心定时器**: +- `m_Timer` - 主定时器 (200ms),处理设备状态轮询、自动控制 +- `viscosity_timer` - 粘度检测定时器 (1s) + +**设备自动控制**: +- `autoControlValvePump()` - 阀门/泵自动控制 +- `pressureAdj()` - 压力自动调节(PID算法) +- `autoControlHeater()` - 加热器自动控制 +- `detectAndcontrolReclaimTank()` - 回收槽检测与控制 + +### 5.3 打印主界面 (MainWidget) + +[mainwidget.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/mainwidget.h) | [mainwidget.cpp](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/mainwidget.cpp) + +**职责**: 打印操作的主界面,包含打印预览、打印控制、文件管理。 + +**关键功能**: +- `generatePrintContent()` - 将场景渲染为打印数据并发送到FPGA +- `variableItemsUpdate()` - 更新动态图元(日期、计数器等) +- `imageToPrintData()` - 将QImage转换为FPGA点阵数据 +- `SendPrintDataToFpga()` - 通过串口向FPGA发送打印数据 + +**页面切换**: +- 通过底部导航按钮(编辑、新增、主界面、管理、消息)切换子页面 +- 使用信号槽 `sendButtonClickedSignal(int)` 通知 InkJetPrinter 切换页面 + +### 5.4 系统参数管理 (SysPara) + +[SysPara.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/SysPara.h) + +**职责**: 管理所有系统参数,是系统的数据中枢。所有模块通过 SysPara 读写参数。 + +**核心数据结构**: +- `calandar_and_dat_t` - 日历/计数器数据(发送给FPGA) +- `bcOption_t` - 条形码选项 +- `qrOption_t` - 二维码选项 +- `QRvars_t` - 二维码变量 +- `stepPrint_t` - 分段打印设定 +- `alterPrint_t` - 交替打印设定 +- `Cnt1ByGroup_t` - 分段计米设定 +- `PrintSettingModel` - 打印设置模型(跟随作业文件保存) + +**参数持久化**: +- 二进制文件: `PARA_ROOT_DIR/sysPara.bin` +- XML文件: `PARA_ROOT_DIR/defPrintSet.xml` + +### 5.5 设备操作 (DevOp) + +[DevOp.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/DevOp.h) + +**职责**: 封装FPGA寄存器的读写操作,提供设备控制的高层接口。 + +**关键操作**: +- 阀门控制: `controlInkValve()`, `controlMixValve()`, `controlReleaseValve()` +- 泵控制: `WriteMoterPump()` +- 电压控制: DAC表读写 (`DAC_TABLE_ADDR`, `MATCH_*_DAC_TABLE_ADDR`) +- 打印控制: 启停、回收槽开关、故障恢复 +- 计数器读写: 产品计数、同步计数 + +**FPGA地址空间**: +- `0x0000-0x01FF`: 状态读取区 +- `0xA400-0xA5FF`: 打印控制寄存器 +- `0xB000-0xCFFF`: 数据写入区(DAC表、打印数据、日历数据等) +- `0xE000-0xFFFF`: 数字字符点阵数据 + +### 5.6 串口通信 (Serial) + +[Serial/serial.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/Serial/serial.h) | [Serial/serial.cpp](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/Serial/serial.cpp) + +**职责**: 封装与FPGA和STM32的串口通信。 + +**设计特点**: +- 支持双通道(FPGA和STM32各自独立串口) +- 使用消息队列管理发送数据 +- CRC16校验保证数据完整性 +- 支持STM32固件升级(IAP协议) +- 运行在独立QThread中,不阻塞UI + +**通信协议**: +- 自定义帧格式:命令 + 地址 + 数据 + CRC16 +- 发送队列: `queueFPGA` / `queue` +- 接收解析: 通过信号槽分发到上层(`receivedFromFPGA` / `receivedFromSTM32`) + +### 5.7 日志系统 (Log/) + +**职责**: 提供分级日志记录功能。 + +**类层次**: +- `Logger` - 日志基类,定义日志格式、级别过滤 +- `FileLogger` - 文件日志实现,支持缓冲区批量写入 +- `LogMessage` - 日志消息封装 + +**使用方式**: +```cpp +qInfo() << "message"; // 信息日志 +qWarning() << "warning"; // 警告日志 +qCritical() << "error"; // 错误日志 +``` + +### 5.8 运行时间统计 (RunTimeCtrl) + +[RunTimeCtrl](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/runtimectrl.h) + +**职责**: 统计软件运行时长,用于设备保养提醒。 + +**功能**: +- `getElapsedSeconds()` - 获取本次运行时间 +- `getTotalSeconds()` - 获取总运行时间 +- `sig_alertTimeout()` - 保养提醒信号 +- `sig_updateTimeoutDay()` - 维护到期提醒 + +--- + +## 6. 数据流与通信机制 + +### 6.1 打印数据流 + +``` +用户编辑场景 (PicScene) + └── 图元 (PicTextItem, PicDateItem, PicCodeItem, ...) + └── 渲染为 QImage + └── imageToPrintData() 转换为点阵数据 + └── SendPrintDataToFpga() 通过 Serial 发送 + └── FPGA 接收并驱动喷头喷印 +``` + +### 6.2 设备状态轮询 + +``` +timerHandler() (200ms周期) + ├── serialFPGA->readData() # 读取FPGA状态寄存器 + ├── serialSTM32->readData() # 读取STM32传感器数据 + ├── saveFPGAStatus() # 解析FPGA状态 + │ ├── 墨线开关、高压状态、回收故障 + │ ├── 墨水/溶剂液位警告 + │ └── 相位检测结果 + ├── saveSTM32Status() # 解析STM32状态 + │ ├── 齿轮泵转速 + │ ├── 脉冲计数 + │ └── 压力/粘度值 + ├── MainWidget::updateSysStatusToUI() # 更新界面状态灯 + └── autoControlValvePump() # 自动控制执行 +``` + +### 6.3 信号槽通信概览 + +``` +Serial::receivedFromFPGA ──→ InkJetPrinter::saveFPGAStatus() +Serial::receivedFromSTM32 ──→ InkJetPrinter::saveSTM32Status() +MainWidget::sendButtonClickedSignal ──→ InkJetPrinter::getMainWidgetButtonClickedSlot() +TestPrintWidget::sendButtonClickedSignal ──→ InkJetPrinter::getTestPrintWidgetButtonClickedSlot() +RunTimeCtrl::sig_alertTimeout ──→ InkJetPrinter::slt_warningMaintenance() +RFIDManager::sig_showMsg ──→ InkJetPrinter::slt_showMsg() +``` + +--- + +## 7. 场景与打印渲染系统 + +### 7.1 架构概述 + +场景系统基于 Qt Graphics View 框架,用于编辑和预览喷码内容。 + +``` +PicScene (QGraphicsScene) # 场景,管理所有图元 + └── myView (QGraphicsView) # 视图,提供缩放和交互 + └── 图元基类 + ├── PicTextItem # 普通文本 + ├── PicDateItem # 日期变量 (yyyy-MM-dd HH:mm:ss...) + ├── PicCounterItem # 计数器 (可变数字) + ├── PicImageItem # 图片 (Logo) + ├── PicCodeItem # 条码/二维码 + └── PicScheduleShiftItem # 班次 (班次代码替换) +``` + +### 7.2 作业文件格式 + +作业文件使用XML格式(VBfiles结构),保存场景内容和打印设置: + +```xml + + + + + + + + + + + + + + + + +``` + +### 7.3 关键类说明 + +- **PicSceneLoader** - 场景文件的加载/保存/预览,负责XML序列化/反序列化 +- **ViewModels** - 定义 `DateItemModel`、`CounterViewModel` 等视图模型,用于编辑器与图元之间的数据传递 +- **ItemCommon** - 图元工具函数,如根据日期模型生成文本字符串 +- **ItemEditor** - 图元通用编辑器(字体、颜色、位置等) +- **打印设置** - `PrintSettingModel` 与作业文件绑定,包含触发模式、字宽、同步器参数等 + +--- + +## 8. RFID刷卡模块 + +### 8.1 模块概述 + +[RFIDManager](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/rfid/rfidmanager.h) + +**职责**: 管理IC卡(墨水卡、溶剂卡、保养卡)的读写与验证。 + +**功能**: +- 墨水/溶剂添加验证(刷卡 + 物理添加) +- 保养卡识别与提醒 +- 自动扣减卡内余额 +- 卡片使用标记(防重复使用) + +**加密**: 使用SM3(哈希)+ SM4(对称加密)国密算法保护卡片数据。 + +### 8.2 刷卡流程 + +``` +检测到墨水/溶剂不足 + └── 弹出刷卡提示对话框 + └── 用户刷卡 + ├── RFIDManager 读取卡片数据 + ├── 验证卡片类型和有效性 + ├── 标记卡片为已使用 + └── 通知 InkJetPrinter 更新报警状态 +``` + +--- + +## 9. 编译构建系统 + +### 9.1 编译配置 + +项目使用 qmake 构建系统,主配置文件为 [QtUI.pro](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/QtUI.pro)。 + +**目标平台**: +- ARM Linux: `TARGET = QtUI` +- 交叉编译: 使用 `linux-arm-g++` mkspec +- x86桌面: 使用 `linux-g++` mkspec,用于开发调试 + +**关键宏定义**: +```makefile +DEFINES += ARM # ARM平台 +DEFINES += QTV3 # Qt版本3兼容 +DEFINES += VNLG # 威利品牌 +DEFINES += WARNING # 警告功能 +DEFINES += COUNTER1_BY_GROUP # 分段计米 +DEFINES += PICSCENE # 场景编辑 +DEFINES += MODBUS # Modbus支持 +DEFINES += __CONVERTERWIFI__ # WiFi支持 +DEFINES += TEMPMIMA # 临时密码 +``` + +### 9.2 模块依赖 + +```makefile +QT += core gui network serialport virtualkeyboard sql xml +``` + +### 9.3 编译命令 + +```bash +# ARM交叉编译 +qmake -spec /usr/local/Trolltech/QtEmbedded-4.6.3-arm/mkspecs/qws/linux-arm-g++ \ + "DEFINES+=ARM" "DEFINES+=QTV3" "DEFINES+=VNLG" + +# x86桌面编译(调试) +qmake "DEFINES+=X86TEST" +make +``` + +--- + +## 10. 关键配置与宏定义 + +### 10.1 全局宏 ([myinclude.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/myinclude.h)) + +| 宏 | 说明 | +|-----|------| +| `__RFID_CARD` | 启用刷卡功能 | +| `__RFID_OLD` | 旧加密算法 | +| `__RFID_IND` | 印度二次加密 | +| `MULTILANGUAGE` | 多语言输入法 | +| `EnableArabic` | 阿拉伯语支持 | +| `EnableBangla` | 孟加拉语支持 | +| `TEST_MODE` | 测试模式 | +| `SIMULATE_PRINTING_MODE` | 模拟打印模式 | + +### 10.2 路径定义 ([SysPara.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/SysPara.h)) + +| 路径宏 | 值 | 说明 | +|--------|-----|------| +| `PARA_ROOT_DIR` | `/home/plg/conf/` | 系统参数目录 | +| `DOC_ROOT_DIR` | `/home/plg/doc/` | 作业文件目录 | +| `SYS_ROOT_DIR` | `/home/plg/` | 系统根目录 | +| `UDISK_DOC_ROOT_DIR` | `/udisk/doc/` | U盘文档目录 | + +### 10.3 版本号 ([VerBVersion.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/VerBVersion.h)) + +```cpp +#define UP_PRINTER_MAJOR_VER 6 +#define UP_PRINTER_MINOR_VER 7 +#define UP_PRINTER_RIVISION_VER 4 +#define SUB_VERSION "_KOR" +``` + +--- + +## 11. 新同事上手指南 + +### 11.1 开发环境搭建 + +1. **安装Qt**: 推荐 Qt 5.12+ 用于桌面开发调试 +2. **获取代码**: 通过SVN或Git获取项目源码 +3. **编译运行**: + ```bash + cd 项目目录 + qmake + make + ./QtUI + ``` +4. **注意事项**: x86桌面版仅用于UI调试,硬件相关功能(串口、FPGA通信)不可用 + +### 11.2 代码阅读顺序建议 + +1. **入门**: [main.cpp](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/main.cpp) → [myinclude.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/myinclude.h) → [InkJetPrinter.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/InkJetPrinter.h) +2. **核心数据**: [SysPara.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/SysPara.h) → [DevOp.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/DevOp.h) +3. **UI页面**: [MainWidget](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/mainwidget.h) → [TestPrintWidget](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/testprintwidget.h) +4. **场景系统**: [scene/picscene.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/scene/picscene.h) → [scene/PicSceneLoader.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/scene/PicSceneLoader.h) → [scene/ViewModels.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/scene/ViewModels.h) +5. **通信层**: [Serial/serial.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/Serial/serial.h) +6. **RFID**: [rfid/rfidmanager.h](file:///mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/rfid/rfidmanager.h) + +### 11.3 常见开发任务 + +| 任务 | 涉及文件 | 说明 | +|------|---------|------| +| 添加新图元类型 | `scene/` 目录 | 继承 PicTextItem,实现渲染和序列化 | +| 修改打印设置 | `Printsetting.h/cpp` | 修改 PrintSettingModel 结构体 | +| 添加新语言 | `*.ts` 文件 | 使用 Qt Linguist 编辑翻译 | +| 修改FPGA通信 | `DevOp.h/cpp` + `Serial/` | 注意地址空间分配和CRC校验 | +| 修改UI样式 | `.ui` 文件 | 使用 Qt Designer 编辑 | +| 添加新功能页面 | 仿照现有页面模式 | 创建 .h/.cpp/.ui 三件套 | + +### 11.4 关键设计模式 + +- **单例模式**: `RFIDManager`, `RunTimeCtrl`, `LogInfoCtrl` 使用单例 +- **观察者模式**: 大量使用Qt信号槽进行模块间通信 +- **策略模式**: 打印触发模式(时延/电眼/同步器)通过枚举切换 +- **MVC变体**: 场景系统使用 ViewModel (`ViewModels.h`) 解耦编辑器与图元 + +### 11.5 调试技巧 + +1. **日志**: 使用 `qInfo()/qWarning()/qCritical()` 输出,日志文件位于 `/home/plg/conf/` +2. **崩溃分析**: `dump.h/cpp` 安装了信号处理器,崩溃时会生成core dump +3. **FPGA调试**: 可通过 `SystemManage` 界面手动控制阀门和泵 +4. **模拟模式**: 设置 `SIMULATE_PRINTING_MODE 1` 可在无硬件环境调试打印逻辑 + +### 11.6 注意事项 + +- **不要直接操作硬件寄存器**: 必须通过 `DevOp` 类进行设备操作 +- **参数持久化**: 修改系统参数后需调用 `SysPara` 的保存方法 +- **线程安全**: 串口通信在独立线程中,注意跨线程信号槽的连接方式 +- **版本兼容**: 注意 `#ifdef` 条件编译宏,不同客户可能有不同的功能组合 +- **UI文件**: 项目使用 `.ui` 文件定义界面,编译时通过 `uic` 生成 `ui_*.h` 文件 +- **编码**: 所有源文件使用 UTF-8 编码,字符串使用 `QString::fromUtf8()` 或 `tr()` + +--- + +> **文档维护**: 本文档应随项目迭代持续更新。如有疑问,请联系项目负责人。 \ No newline at end of file diff --git a/rfid/rfidmanager.cpp b/rfid/rfidmanager.cpp index 8a0457b..64fba12 100644 --- a/rfid/rfidmanager.cpp +++ b/rfid/rfidmanager.cpp @@ -15,6 +15,33 @@ constexpr char* SUPER_CARD_ID = "397F4A8E5B9F6CA07D395B28E4A6"; RFIDManager::RFIDManager() { comForRFID_init(); + + m_confirmBox = new QMessageBox(QMessageBox::Warning, tr("警告"), QString(), + QMessageBox::Ok | QMessageBox::Cancel); + m_confirmBox->setWindowModality(Qt::ApplicationModal); + m_confirmTimer = new QTimer(this); + + connect(m_confirmTimer, &QTimer::timeout, this, [this]() { + int count = m_confirmBox->property("rfidCountDown").toInt(); + m_confirmBox->setText(m_confirmBoxTxt.arg(count)); + m_confirmBox->update(); + count--; + m_confirmBox->setProperty("rfidCountDown", count); + if(count == 0) { + m_confirmBox->accept(); + } + }); + + connect(m_confirmBox, &QMessageBox::accepted, this, [this]() { + if(m_confirmCallback) { + m_confirmCallback(); + } + }); + + connect(m_confirmBox, &QMessageBox::finished, this, [this](int result) { + m_confirmTimer->stop(); + m_confirmCallback = nullptr; + }); } void RFIDManager::CheckSumOut(UCHAR *buf, UCHAR len) @@ -531,8 +558,6 @@ void RFIDManager::handleCheck(unsigned int addr) { strRevdata =""; auto res = receiveReadRFID_data(); -// LogInfo::setRunStatusText(tr("receiveReadRFID_data res:%1, data:%2") -// .arg(res).arg(strRevdata)); if(strRevdata.length() > 3) { if((strRevdata.left(3) == QString::number(addr).left(3)) @@ -549,27 +574,11 @@ void RFIDManager::handleCheck(unsigned int addr) if(!sysPara->RFIDPara.needInkCard){ emit sig_showMsg(tr("不需要刷墨水卡!")); } -// else if(sysPara->status.statWarn & WARN_STATUS_INK_WARN){ -// emit sig_showMsg(tr("请先添加墨水再刷墨水卡!")); -// } - else - { - auto ok = cardTouchConfirm(tr("确认要刷墨水卡吗?"), tr("确认要刷墨水卡吗? %1 秒后将自动确认")); - if (!ok){ - LogInfo::setRunStatusText("The user has canceled the operation about marking the ink card."); - } - else { - auto ret = RFIDmarkCardUsedAsync(0, strRevdata); - if(ret >= 0 || ret == -11){ - const QString msg = sysPara->RFIDPara.addedInk ? tr("刷墨水卡成功!") : tr("刷墨水卡成功, 请及时将该墨水卡对应的墨水添加到机器中"); - emit sig_showMsg(msg); - sysPara->RFIDPara.cardInk = true; - sysPara->saveRFIDPara(); - } - else if(ret == -10) { - emit sig_showMsg(tr("刷超级墨水卡失败,请联系厂商。")); - } - } + else { + auto blockData = strRevdata; + cardTouchConfirmAsync(tr("确认要刷墨水卡吗?"), tr("确认要刷墨水卡吗? %1 秒后将自动确认"), [this, blockData]{ + markInkCard(blockData); + }); } } else if(strRevdata.at(3) == 'B') @@ -582,61 +591,20 @@ void RFIDManager::handleCheck(unsigned int addr) if(!sysPara->RFIDPara.needSolventCard){ emit sig_showMsg(tr("不需要刷溶剂卡!")); } -// else if(sysPara->status.statWarn & WARN_STATUS_SOLV_WARN){ -// emit sig_showMsg(tr("请先添加溶剂再刷溶剂卡!")); -// } - else - { - auto ok = cardTouchConfirm(tr("确认要刷溶剂卡吗?"), tr("确认要刷溶剂卡吗? %1 秒后将自动确认")); - if (!ok){ - LogInfo::setRunStatusText("The user has canceled the operation about marking the solvent card."); - } - else { - auto ret = RFIDmarkCardUsedAsync(1, strRevdata); - if(ret >= 0 || ret == -11) { - const QString msg = sysPara->RFIDPara.addedSolvent ? tr("刷溶剂卡成功!") : tr("刷溶剂卡成功, 请及时将该溶剂卡对应的溶剂添加到机器中"); - emit sig_showMsg(msg); - sysPara->RFIDPara.cardSolvent = true; - sysPara->saveRFIDPara(); - } - else if(ret == -10) { - emit sig_showMsg(tr("刷超级溶剂水卡失败,请联系厂商。")); - } - } + else { + auto blockData = strRevdata; + cardTouchConfirmAsync(tr("确认要刷溶剂卡吗?"), tr("确认要刷溶剂卡吗? %1 秒后将自动确认"), [this, blockData](){ + markSolventCard(blockData); + }); } } else if(strRevdata.at(3) == 'C') { - auto ok = cardTouchConfirm(tr("确认要刷保养卡吗?"), tr("确认要刷保养卡吗? %1 秒后将自动确认")); - if (ok){ - auto ret = RFIDmarkCardUsedAsync(2, strRevdata); - if(ret >= 0 || ret == -11) {//把卡数据清零 - - emit sig_maintenanceShow(); - - sysPara->RFIDPara.needMaintenance = false; - sysPara->status.needMaintenanceRemind = false; - - QDate curDate = QDate::currentDate(); - sysPara->RFIDPara.maintenanceDate = curDate.toString("yyMMdd").toInt(); - QDate mtEndDate = curDate.addMonths(sysPara->RFIDPara.maintenanceInterval); - sysPara->RFIDPara.maintenanceEndDate = mtEndDate.toString("yyMMdd").toInt(); - sysPara->RFIDPara.runTime = 0; - RunTimeCtrl::instance()->updatePara(&sysPara->RFIDPara); - sysPara->saveRFIDPara(); - emit sig_showMsg(tr("刷保养卡成功!")); - } - else if(ret == -10) { - emit sig_showMsg(tr("刷超级保养卡失败,请联系厂商。")); - } - else { - LogInfo::setRunStatusText("Failed to mark maintenance card!"); - } - } - else { - qDebug() << "用户取消了刷卡"; - } + auto blockData = strRevdata; + cardTouchConfirmAsync(tr("确认要刷保养卡吗?"), tr("确认要刷保养卡吗? %1 秒后将自动确认"), [this, blockData](){ + markMaintenanceCard(blockData); + }); } else { @@ -1117,6 +1085,82 @@ bool RFIDManager::cardTouchConfirm(QString msgTxt, QString variableMsgTxt) return box.result() == QMessageBox::Ok || box.result() == QMessageBox::Accepted; } +void RFIDManager::cardTouchConfirmAsync(QString msgTxt, QString variableMsgTxt, std::function callback) +{ + if(m_confirmBox->isVisible()) { + qDebug() << "A dialog is already being displayed. Ignoring the new request."; + return; + } + + int rfidCountDown = sysPara->para.rfidCountDown; + m_confirmBoxTxt = variableMsgTxt; + m_confirmCallback = callback; + m_confirmBox->setText(msgTxt); + m_confirmBox->setProperty("rfidCountDown", rfidCountDown); + + if(rfidCountDown > 0) { + m_confirmBox->setText(m_confirmBoxTxt.arg(rfidCountDown)); + m_confirmTimer->start(1000); + } + + m_confirmBox->show(); +} + +void RFIDManager::markInkCard(const QString &blockData) +{ + auto ret = RFIDmarkCardUsedAsync(0, blockData); + if(ret >= 0 || ret == -11){ + const QString msg = sysPara->RFIDPara.addedInk ? tr("刷墨水卡成功!") : tr("刷墨水卡成功, 请及时将该墨水卡对应的墨水添加到机器中"); + emit sig_showMsg(msg); + sysPara->RFIDPara.cardInk = true; + sysPara->saveRFIDPara(); + } + else if(ret == -10) { + emit sig_showMsg(tr("刷超级墨水卡失败,请联系厂商。")); + } +} + +void RFIDManager::markSolventCard(const QString &blockData) +{ + auto ret = RFIDmarkCardUsedAsync(1, blockData); + if(ret >= 0 || ret == -11) { + const QString msg = sysPara->RFIDPara.addedSolvent ? tr("刷溶剂卡成功!") : tr("刷溶剂卡成功, 请及时将该溶剂卡对应的溶剂添加到机器中"); + emit sig_showMsg(msg); + sysPara->RFIDPara.cardSolvent = true; + sysPara->saveRFIDPara(); + } + else if(ret == -10) { + emit sig_showMsg(tr("刷超级溶剂水卡失败,请联系厂商。")); + } +} + +void RFIDManager::markMaintenanceCard(const QString &blockData) +{ + auto ret = RFIDmarkCardUsedAsync(2, blockData); + if(ret >= 0 || ret == -11) {//把卡数据清零 + + emit sig_maintenanceShow(); + + sysPara->RFIDPara.needMaintenance = false; + sysPara->status.needMaintenanceRemind = false; + + QDate curDate = QDate::currentDate(); + sysPara->RFIDPara.maintenanceDate = curDate.toString("yyMMdd").toInt(); + QDate mtEndDate = curDate.addMonths(sysPara->RFIDPara.maintenanceInterval); + sysPara->RFIDPara.maintenanceEndDate = mtEndDate.toString("yyMMdd").toInt(); + sysPara->RFIDPara.runTime = 0; + RunTimeCtrl::instance()->updatePara(&sysPara->RFIDPara); + sysPara->saveRFIDPara(); + emit sig_showMsg(tr("刷保养卡成功!")); + } + else if(ret == -10) { + emit sig_showMsg(tr("刷超级保养卡失败,请联系厂商。")); + } + else { + LogInfo::setRunStatusText("Failed to mark maintenance card!"); + } +} + void RFIDManager::updateStatus() { if (sysPara) { @@ -1381,4 +1425,4 @@ int RFIDManager::RFIDQueryWalletAsync() LogInfo::setRunStatusText(("Failed to query card balance, logic error")); qDebug() << "Failed to query card balance, logic error"; return -1; -} +} \ No newline at end of file diff --git a/rfid/rfidmanager.h b/rfid/rfidmanager.h index c8751e6..c764d1e 100644 --- a/rfid/rfidmanager.h +++ b/rfid/rfidmanager.h @@ -6,8 +6,10 @@ #include #include #include +#include class SysPara; +class QMessageBox; enum CARD_TYPE{ INK = 1, SOLVENT = 2, @@ -102,11 +104,23 @@ private: void initTimer(); bool cardTouchConfirm(QString msgTxt, QString variableMsgTxt); + + void cardTouchConfirmAsync(QString msgTxt, QString variableMsgTxt, std::function callback); + + void markInkCard(const QString &strRevdata = QString()); + + void markSolventCard(const QString &strRevdata = QString()); + + void markMaintenanceCard(const QString &strRevdata = QString()); //刷卡新需求,刷卡和倒溶剂/墨水不分先后,都可以去除报警提示。 StatuStruct status; void updateStatus(); QTimer* warningTimer = nullptr; + QMessageBox* m_confirmBox = nullptr; + QTimer* m_confirmTimer = nullptr; + QString m_confirmBoxTxt; + std::function m_confirmCallback; int waitStatus(); bool waitCard(); signals: @@ -132,4 +146,4 @@ private slots: void slt_intervalTimerHandle(); }; -#endif // RFIDMANAGER_H +#endif // RFIDMANAGER_H \ No newline at end of file diff --git a/testprintwidget.cpp b/testprintwidget.cpp index a919d6e..c93af8c 100644 --- a/testprintwidget.cpp +++ b/testprintwidget.cpp @@ -190,7 +190,7 @@ TestPrintWidget::TestPrintWidget(QWidget* parent) } else { saveFile(); } - + emit sig_updatePrintContent(xmlfileName); } @@ -383,6 +383,7 @@ void TestPrintWidget::on_saveButton_pressed() filename += ".xml"; saveFile(filename); + xmlfileName = filename; } #endif }