New Version: Current Monitor v1.1.0
Current Monitor 发布了 v1.1.0。这个版本的改动集中在一件事上:让 GDDAQ 联动不再依赖”数据有没有被写到磁盘”。为此新增了一整套进程内存读取方式——由一个 root 辅助进程每秒从 GDDAQ 进程里直接读出运行状态、轮次号与数据目录;围绕这条新数据源,轮次跟随、文件落点、断线恢复和手动接管的语义也都重新梳理了一遍。
Current Monitor 是配合”創鴻 DM4D-An-Rs”高精度盘面表的双通道电流实时监控软件:Modbus RTU 读取、电荷积分、双轴绘图、CSV 记录。v1.1.0 于 2026 年 9 月 23 日发布,9 月 24 日补充了 GDDAQ 版本选择项。
v1.1 带来了什么
| v1.0.0 | v1.1.0 | |
|---|---|---|
| GDDAQ 状态来源 | 仅 run.log | run.log + 进程内存(root 辅助进程) |
| 同轮次重启识别 | 依赖数据文件更新,延迟约一个写盘周期 | 内存方式无需等写盘,仍有 1 s 轮询间隔 |
| 轮次选择 | 日志方式取最大编号,另需手动填 Run Number | 全自动,手动 Run Number 项已移除 |
| 电流数据位置 | 数据目录下的 CurrentData/ | 数据目录上一级的 CurrentData/run_XXXXX.csv |
| 轮次切换 | 需先停再启 | 轮次号或目录变化时自动切换到新 CSV |
| 断线判定 | 进程消失即停止 | 连续 3 秒无有效状态才停止;恢复后自动续记 |
| GDDAQ 版本 | 无 | 新增 GDDAQ Version(GDDAQ-CAEN (20260709)) |
| 手动接管 | 直接操作即可 | 需确认后才退出联动 |
| 代码规模 | 3,738 行 | 4,959 行 |
采集内核(Modbus 帧校验、电荷积分、过滤、绘图)在本版保持不变,改动几乎全部落在联动层。
为什么光靠 run.log 不够
run.log 方式的问题不在解析,而在时序:它只能看到已经落盘的东西。
- GDDAQ 在同一轮次文件夹里重新开始取数时,往往不会再写一行
Start:。程序只能退而求其次,用”数据文件比run.log更新”来推断重启。 - 这个推断要等一次数据写盘,识别天然滞后一个写盘周期。
- 如果某段取数很短,还没来得及产生可识别的文件更新,这一段就整段漏记——对以 mC 计量的电荷数据来说,漏记比误记更难事后补救。
内存方式的思路很直接:GDDAQ 自己一定知道”现在在不在取数、是第几轮、存到哪个目录”,那就去问它本人,不绕道磁盘。
内存检测:怎么从别人的进程里读出状态
启用 Process Memory (root) 后,程序会拉起一个辅助进程,每秒读一次 GDDAQ 的内存,把结果原子写成一个 JSON 状态文件,主界面只负责读这个文件。
几个值得说明的设计取舍:
辅助进程就是本程序自身的一个 root 副本。 命令形如 sudo <本程序> --gddaq-mem-helper -o <状态文件> --stop-file <标志文件> -i 1 --gddaq-version ...。这个副本在导入 PyQt5 / numpy 之前就进入了纯标准库的守护循环,好处有三个:root 下运行的代码面最小(最小提权原则);打包后的可执行程序自带解释器,目标机器不需要装 python3;也不需要额外附带任何外部脚本。代价是 onefile 打包时 root 副本要先自解压,首次启动会多花几秒。
只读内存,不 attach。 打开 /proc/<pid>/mem 以 O_RDONLY 读取,不使用 ptrace,因此不会暂停 GDDAQ——取数期间读状态,不会给束流实验塞进一次莫名的停顿。
先找对象,再读字段。 程序优先从目标进程自己的 ELF 符号表里取 vtable 符号地址,在可写内存区(栈、堆、匿名映射)中定位 MainWindow 实例,然后按偏移读出 QString 形式的目录、前缀与轮次号;偏移漂移时还有一层启发式兜底,扫描失败会带原因写进状态文件,同一错误去重,不刷屏。
密码与权限。 sudo 密码只经 sudo -S 的 stdin 传给子进程,不写日志、不保存,用完即释放引用;认证失败允许重试,最多 3 次;取消勾选时先删停止标志让辅助进程自行退出,卡死才用信号兜底。
轮次跟随与数据落点
手动填 Run Number 这一项被彻底移除了。现在轮次是自动跟随的:run.log 方式取编号最大的子文件夹,内存方式直接跟随 GDDAQ 的实际运行号。
电流数据统一追加到数据目录上一级的 CurrentData/ 里:
/home/rnb/Data/202605ams/
├── raw/ ← Data Directory
│ └── 0048/
│ └── run.log
└── CurrentData/
└── run_00048.csv ← 电流数据
旧版日志方式写在 raw/CurrentData/ 里的文件不会自动搬迁或合并,需要的话请手动处理。
轮次号或数据根目录一旦变化,程序会先关掉旧 CSV、再打开新 CSV;日志方式如果发现新轮次还没有有效的 Start:,会停止旧记录并等待。两种方式都采用追加语义,与 DAQ_Master 的行为一致。
由此引出一条使用建议:每轮取数尽量用新的编号。复用同一编号会把多段电流数据追加进同一个 CSV,事后对应数据的成本远高于改一个编号。
断线与恢复的边界
联动最怕两种情况:该停的时候没停,以及不该停的时候停了。v1.1.0 把边界写清楚了:
| 情况 | 行为 |
|---|---|
| 确认 GDDAQ 已退出 | 停止联动记录,状态栏红色提示;辅助进程仍在时可自动继续跟随 |
| 暂时读不到有效状态 | 短暂失败期间继续记录;连续 3 秒无有效状态后,在下一次轮询停止并报警 |
| 有效状态恢复 | 以追加方式自动恢复记录 |
| 辅助进程退出 | 停止记录并提示 memory helper exited,需取消再重新勾选(不反复索取密码) |
这里有个容易被耍花招的细节:重复读到同一份旧状态、或持续收到错误状态,都不会延长这 3 秒等待期。否则一个卡在旧快照上的辅助进程,能让”已经停止的取数”永远看起来还在跑。
日志方式的重启检测也补上了警示:当程序通过”数据文件更新”识别出同轮次重启时,会提示可能存在漏记的短段,并记一条 WARNING。
手动接管
联动期间启停由外部程序控制,但人始终可以接管:手动启动前会请求确认退出联动;手动停止时,如果外部 DAQ 仍在取数,同样会请求确认。确认后程序退出联动模式,取消则保持原状。联动本身仍然只能停止它自己启动的运行,手动跑起来的记录不会被外部信号误杀——这条语义从 v1.0.0 延续下来。
GDDAQ 版本:一句实话
内存读取依赖 GDDAQ 二进制内部的对象布局,所以新增了 GDDAQ Version。目前适配目标是 GDDAQ-CAEN (20260709),其偏移来自对这一版二进制的实测。这个选项只在内存方式、且联动未开启时可改(避免运行中换版本导致读到错位的字段),选择在当前会话内保留。
必须说明的是:同一版本重新编译,内部布局也可能变化,版本名相同不代表一定兼容。若日志里出现内存读取异常,先在源码目录用诊断命令确认偏移是否还成立,再决定要不要用这一模式。
升级与兼容性
- 运行依赖不变(
numpy / matplotlib / PyQt5 / pyserial),Windows 7 兼容版本的依赖钉不变。 - 内存方式需要监控机上
sudo可用;日志方式依旧零额外权限,是默认选项。 - 打包流程照旧可用。内存辅助进程是程序自身的 root 副本,onefile 模式下首轮状态文件约需 2–5 秒就绪,程序最长等待 8 秒。
/tmp/daq_status.txt的对接契约完全不变,DAQ_Master 侧零改动。- 平台支持仍是 Linux(≥ glibc 2.17)与 Windows(≥ 7);GDDAQ 联动仅限 Linux。
获取与参与
- 仓库:github.com/shenmeshisanpao/Current-Monitor
- 协议:GNU GPL v3.0
Releases 页提供 Linux x86-64 单文件可执行程序,兼容 CentOS 7、Ubuntu 18+ 等主流发行版。
本文由AI生成。