Files
VX5_KRO_GearPump/m_RightBtn_availability_truth_table.md
2026-07-22 11:47:13 +08:00

217 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# m_RightBtn(喷嘴开启)可用性真值表
## 0) 你要的重点:只整理“上层可点(E=true)”
这一节只看上层传给 `setReclaimOpenBtnStatus(E)` 的 E,不包含底层拦截(airPushing / RFID)。
关键调用位置:
- [mainwidget.cpp](mainwidget.cpp#L863)
- [InkJetPrinter.cpp](InkJetPrinter.cpp#L1094)
- [InkJetPrinter.cpp](InkJetPrinter.cpp#L2555)
- [InkJetPrinter.cpp](InkJetPrinter.cpp#L2581)
上层 E=true 的来源只有 4 类:
- 停止打印后:`currReclaimTankPos == 0` 时传 true。
- 自检完成瞬间:直接传 true。
- 回收槽状态机:`reclaimTankstatus == 2` 时传 true。
- 回收槽状态机:`reclaimTankstatus == 4` 时传 true。
## 0.1) 上层 E=true 精简真值表(不含 A/R)
定义四个上层布尔量:
- S:自检完成事件(self check done edge)
- T:停止打印事件且 `currReclaimTankPos == 0`
- R2:`reclaimTankstatus == 2`
- R4:`reclaimTankstatus == 4`
则上层可点条件:
E = S OR T OR R2 OR R4
只看 E=true 的最小真值表(命中任一来源即可):
| S | T | R2 | R4 | E |
|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 0 | 1 |
| 0 | 0 | 1 | 0 | 1 |
| 0 | 0 | 0 | 1 | 1 |
说明:
- 这 4 行是“最小命中表”。多项同时为 1(例如 T=1 且 R2=1)也仍然是 E=1。
## 0.2) 上层 E=false 的主要覆盖路径(帮助你理解为何看起来复杂)
下面这些路径会频繁把 E 拉回 false:
- 开始打印后立即置 false:[mainwidget.cpp](mainwidget.cpp#L824)
- 打印中周期置 false:[mainwidget.cpp](mainwidget.cpp#L2594)
- 自检启动/进行中置 false:[InkJetPrinter.cpp](InkJetPrinter.cpp#L1059)
- 排气过程周期置 false:[mainwidget.cpp](mainwidget.cpp#L1034)
- 齿轮泵未进入运行态时置 false:[InkJetPrinter.cpp](InkJetPrinter.cpp#L710)
- 关机流程置 false:[mainwidget.cpp](mainwidget.cpp#L219)
所以“上层 E=true”通常是阶段性信号,可能很快被其他流程覆盖为 false。
## 0.3) 我建议的上层简化口径(先统一 E,再叠加底层拦截)
你可以把现有分散调用统一理解为两步:
1) 先算上层意图 E:
```cpp
bool upperEnable = selfCheckDoneEdge
|| (stopPrint && currReclaimTankPos == 0)
|| (reclaimTankstatus == 2)
|| (reclaimTankstatus == 4);
```
2) 再算最终可点:
```cpp
bool finalEnable = upperEnable && !airPushing && !rfidBlocked;
```
这样分层后,排查会非常直接:
- 先问“上层想不想给点”(E)
- 再问“底层有没有拦截”(A/R)
## 1) 最终判定公式
m_RightBtn 最终是否可用,不只看调用处传入的 enable,还会在 MainWidget 内再次过滤。
关键实现位置:
- [setReclaimOpenBtnStatus 定义](mainwidget.cpp#L959)
- [RFID 条件过滤](mainwidget.cpp#L961)
- [airPushing 条件过滤](mainwidget.cpp#L968)
- [最终 setEnabled](mainwidget.cpp#L971)
可用公式:
FinalEnabled = E AND (NOT A) AND (NOT R)
变量定义:
- E:上层调用 setReclaimOpenBtnStatus(E) 时传入的 enable
- A:sysPara->status.airPushing(是否正在排气)
- R:RFID 层拦截(仅在编译启用 __RFID_CARD 时有效)
- inkCardTimeOut 或 solventCardTimeOut 或 needMaintenance 任一为真,则 R=1
说明:
- 若未启用 __RFID_CARD,R 恒为 0。
## 2) 最终可用真值表(硬条件)
| E | A | R | FinalEnabled |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 0 |
| 1 | 1 | 1 | 0 |
结论:
- 唯一能点的组合是 E=1、A=0、R=0。
## 2.1) 只看“按钮可用=true”的最小真值表
如果你只关心“什么时候能点”,那真值表可以压缩成 1 行:
| E | A | R | FinalEnabled |
|---|---|---|---|
| 1 | 0 | 0 | 1 |
反向速记(现场排查更快):
- 只要满足以下任一条件,按钮就一定不可用:
- E=0(上层当前不允许)
- A=1(正在排气)
- R=1(RFID 拦截)
## 2.2) 工程化简化版(建议你按这个理解)
把复杂条件改写成一个“守卫函数”,先算出 3 个阻塞原因,再统一决定可用性。
建议逻辑:
```cpp
// 只表达逻辑,不改变现有业务行为
bool blockedByRFID = hasRFIDGuard && (inkCardTimeOut || solventCardTimeOut || needMaintenance);
bool blockedByAirPush = airPushing;
bool blockedByUpperLayer = !upperEnable;
bool finalEnabled = !blockedByRFID && !blockedByAirPush && !blockedByUpperLayer;
```
对应到 UI 语义:
- 可用态:Ready
- 不可用态:BlockedByUpperLayer / BlockedByAirPush / BlockedByRFID
这样简化后的好处:
- 读代码时从“多处 setReclaimOpenBtnStatus(true/false)”切换为“先看谁在设置阻塞原因”。
- 打日志更清晰:可直接输出第一个阻塞原因,而不是只看到按钮被置灰。
- 后续扩展更稳:新增条件只需新增一个 blockedByX,不会到处散落 if。
建议落地步骤(不改行为,只提可维护性):
- 第一步:在 MainWidget 内新增一个 `computeReclaimOpenBtnEnabled()`,所有按钮状态更新都走它。
- 第二步:在 `setReclaimOpenBtnStatus` 里补充调试日志(仅 debug),打印 E/A/R。
- 第三步:把状态机处的“直接 true/false”改成“设置上层意图 upperEnable”,统一在一个点算最终值。
## 3) E(上层 enable)常见取值来源表
| 场景 | 调用代码 | 传入 E |
|---|---|---|
| 开始打印后 | [mainwidget.cpp](mainwidget.cpp#L824) | 0 |
| 停止打印后,按回收槽位置决定 | [mainwidget.cpp](mainwidget.cpp#L863) | currReclaimTankPos == 0 |
| 关机流程(回收槽未关) | [mainwidget.cpp](mainwidget.cpp#L219) | 0 |
| 排气进行中(周期) | [mainwidget.cpp](mainwidget.cpp#L1034) | 0 |
| 打印中且自检完成(周期) | [mainwidget.cpp](mainwidget.cpp#L2594) | 0 |
| 自检开始 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L1059) | 0 |
| 自检完成 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L1094) | 1 |
| 回收槽状态机:状态=1或2 时 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2555) | reclaimTankstatus == 2 |
| 回收槽状态机:状态=4(保持) | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2581) | 1 |
| 齿轮泵未进入运行态 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L710) | 0 |
## 4) 按回收槽状态机的可用性(忽略 A/R 时的 E)
这张表只表示状态机“想给”的 E,最终仍需经过第 2 节硬条件过滤。
| reclaimTankstatus | 语义 | E(状态机给值) | 代码位置 |
|---|---|---|---|
| 1 | 开槽中 | 0 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2555) |
| 2 | 关槽中 | 1 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2555) |
| 4 | 保持 | 1 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2581) |
| 5 | 开到位 | 未在该分支直接设置 E(通常由其他逻辑接管) | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2520) |
| 6 | 关到位 | 未在该分支直接设置 E(通常随后可再次开槽) | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2561) |
| 0x11/0x12 | 卡滞/异常 | 不会给出稳定可用态,偏禁用与告警处理 | [InkJetPrinter.cpp](InkJetPrinter.cpp#L2546) |
## 5) 点击行为补充(按钮可用后点下去会发生什么)
入口:
- [on_m_RightBtn_clicked](mainwidget.cpp#L1266)
行为分支:
- 若 reclaimTankBlockedAppending 为真:先弹告警确认,不直接开槽。
- [mainwidget.cpp](mainwidget.cpp#L1300)
- 若 canRunAirPushing 为真 且 currReclaimTankPos==0:先排气,再开槽。
- [mainwidget.cpp](mainwidget.cpp#L1270)
- 其他情况:直接调用 reclaimTanOpen。
- [mainwidget.cpp](mainwidget.cpp#L1298)
补充状态位来源:
- canRunAirPushing 在开槽动作中会被置为 false。
- [mainwidget.cpp](mainwidget.cpp#L1135)
- 自检完成、关槽完成后会恢复为 true。
- [InkJetPrinter.cpp](InkJetPrinter.cpp#L1098)
- [InkJetPrinter.cpp](InkJetPrinter.cpp#L2571)
## 6) 一句话版本
m_RightBtn 可用的必要且充分条件是:上层当前允许开启(E=1)+ 不在排气(A=0)+ RFID 不拦截(R=0)。在实际运行中,E 主要由“自检状态、打印状态、回收槽状态机、故障流程”共同驱动。
## 7) 给现场同事的超短口令
先看 E,再看 A,再看 R:
- E 由业务状态机决定“想不想让你点”。
- A/R 决定“即使想让你点,也要不要强制拦截”。
- 只有 E=1 且 A=0 且 R=0,m_RightBtn 才会真的可点。