# MAG160C 真机端到端自检清单(Phase A3) > 用法:把最新 `build-artifacts/mag160c-app-debug.apk` 装到手机,插上 MAG160C > 热像仪,按顺序做一遍。每步的"预期 DebugLog 行"可在应用内 debug 日志文件中 > 对照(DCIM/MAG160C/debug_*.log;若 DCIM 拒收则 Download/MAG160C;文件头 > `sink=` 注明实际落点),也可用 `adb logcat -s MAG160C/*` 实时看。 > > 日志行格式:`HH:mm:ss.SSS [tag] message`。下表消息列为**现有代码中的原文** > (变量处用 <...> 占位)。若某项对不上,把整个日志文件发回分析。 ## 步骤表 | # | 操作 | 预期 DebugLog 行(原文) | 通过标准 | |---|------|--------------------------|----------| | 1 | 插入热像仪,系统弹出 USB 权限对话框,点"允许" | `[usb] requestPermission: no device`(无设备时)/ `[usb] requesting permission (dialog)` → `[usb] permission result: true` | 授予权限后自动开始连接 | | 2 | 等待连接(首次约 1~3 s,首次装机需下载标定文件时更久) | `[vm] connect()` → `[vm] permission ok, ddt bytes, starting session` → `[session] state -> LINKING msg=null` → `[cmd] GetParameter1 write=4/4` → `[cmd] GetParameter1 resp=0x5BB5B55B len=60 head=...` → `[cmd] BasePara1: serial=160043865 devType=3 160x120 @15fps` | 五条全出现;serial/devType 与实际相机一致(devType=3 即 core160) | | 3 | 同上(参数/标定握手) | `[cmd] GetParameter2 resp=0x5BB5B55C len=...` → `[cmd] GetCaliInfo resp=0x5BB5B55E len=...` → `[session] cali info: size= date=` → `[session] device lifetime=ms` | GetParameter2/GetCaliInfo 有响应;lifetime 非 -1(0 或正数均可,首次上电后很小正常) | | 4 | 首次安装运行(无 cali 缓存) | `[session] first run on this host: downloading cali file B (EP 0x84)` → `[session] cali download

%`(若干行)→ `[session] cali downloaded+cached: .. ( B)`;第二次运行改为 `[session] cali cache hit: ` + `[session] cali cache vs bundled DDT: identical`(或 `differ`,两者都不算失败) | 缓存命中或下载成功二者之一 | | 5 | 等待 DDT 加载 + 出流 | `[session] ddt bytes ` → `[session] state -> STREAMING msg=null` → `[cmd] StartTransferImg write=4/4` → `[cmd] StartTransferImg ack=0x...` → `[stream] reader loop start: sync bulkTransfer (800 ms) + halt recovery` → `[stream] first reads [0] n= head=...` → `[vm] first rendered frame -> UI` | 出现 `first rendered frame -> UI` 即画面已出(实时页显示热像,不再黑屏) | | 6 | 观察实时页 5 s 以上 | 每 2 s:`[stream] stats: reads= frames= rendered= timeouts= fps=15.0 renderState= ref=true lifetime=`;每 ~5 s:`[vm] hb: state=streaming streaming=true uiFrames= latest=true` | `frames`/`rendered` 持续递增,fps≈15,ref=true;timeouts 偶发可接受,不应持续增长而 frames 不涨 | | 7 | 顶栏点 FFC 两次(每次间隔 ~1 s) | 每次:`[cmd] FFC(0) write=8/8` → `[cmd] FFC(0) ack=0x... len=...`(ack 读不到时日志为 `[cmd] FFC(0) ack= bytes`,相机仍会执行校正,不算失败) | 画面出现一次快门校正(短暂黑/停顿后恢复) | | 8 | 点底部大圆快门拍照 | `[vm] hb: state=saved ...`(下一次 5 s 心跳即可看到 status=saved);UI 上状态文案短暂显示 | 相册/文件管理器 DCIM/MAG160C 出现 `MAG160C_yyyyMMdd_HHmmss.jpg`(实际为 MDT 容器,扩展名 .jpg) | | 9 | 点录像,录 10 s,再点停止 | `[vm] hb: state=recording ...` → 停止后 `[vm] hb: state=rec_done ...` | 状态回到 rec_done,无崩溃 | | 10 | 切到"相册"页 | (无 DebugLog;纯 UI) | 列表出现步骤 8 的照片缩略图(MDT 尾部校验通过才显示) | | 11 | 点该照片进入分析页 | (无 DebugLog;纯 UI) | 图片可缩放/平移;调色板重渲染可用;**图像顶部出现温度条**(`中心 x.x℃ 最低 x.x℃ 最高 x.x℃`);点图任意位置出现白色圆点+温度标签,再点同一点可清除;备注可编辑保存 | | 12 | 分析页生成 PDF 报告 | (无 DebugLog;纯 UI) | 报告文件在 DCIM/MAG160C 或 Download/MAG160C 生成,可打开 | | 13 | 实时页顶栏第 5 项点"画中画"(首次会弹相机权限,点允许) | `[pip] camera opened id=` → `[pip] repeating preview started` | 右上角(色标条左侧)出现 128×96dp 白框小窗,显示可见光画面;顶栏该项高亮为"画中画·开" | | 14 | 拖动 PIP 小窗到其它角落;单击小窗(循环 96/128/160dp);双击小窗关闭 | `[pip] released`(双击关闭时) | 小窗跟手移动且不出界;单击在三档宽度间循环;双击后小窗消失,顶栏恢复"画中画"未开启态;日志有 `released` | | 15 | PIP 开启时按 Home 回到桌面再返回 | `[pip] released`(进入后台时) | 返回后若 PIP 仍为开启态,画面重新出现(重新 open);无崩溃 | ## 远程预览(Phase F,需要两台设备) 两台安卓设备(或一台手机 + 一个模拟器)连**同一个 Wi-Fi**。以下称 A=插热像仪的 主机手机,B=远程查看的手机。 | # | 操作 | 预期 DebugLog 行(原文) | 通过标准 | |---|------|--------------------------|----------| | 16 | A:插热像仪,确认实时页已出图(清单前 6 步) | `[session] state -> STREAMING` | A 本地画面正常 | | 17 | A:设置页 → "远程预览服务端"(点一下) | `[remote] host started (name=<机型> serial=0)` | 该行文案变为"已开启" | | 18 | A:若第 17 步弹"先连接热像仪" | (无日志) | 说明 USB 会话不活跃:先回到实时页确认出流 | | 19 | B:设置页 → "远程预览客户端" → "查找主机" | (B 端)列表出现 A 的主机名 | 10 秒内列出 A(卡片显示 `<主机名>` 与 `:47511`);未列出可用"手动添加"填 A 的 IP | | 20 | B:点该卡片(或手动 IP 后点"连接") | A 端:`[remote] client connected from `;B 端:`[remote] client connected to :47511` → `[remote] line: {"type":"welcome",...}` → `[remote] line: {"type":"stream-start"}` → `[remote] first remote frame` | B 显示 A 的热像实时画面,**温度读数与 A 端一致**(同一场景下中心温/最高最低相差应在 1℃ 内);画面朝向与 A 端相同(两机握持姿态不同时,各自按自己的姿态补偿) | | 20b | B 端确认温度不再是 -161℃、画面不是满屏噪声 | B 端 `[remote] first remote frame` 之后读数正常 | 这是 2026-09-11 修复项:协议改为随帧传 FFC 阶段+相机温度(`[flags][ffcPhase][shutter]`,帧记录 38424B)。若仍异常,检查两端 APK 是否同版本(新旧协议不兼容) | | 20c | 第三台设备(或 A 本机再连一次)尝试连接同一主机 | A 端:`[remote] rejecting : already serving a client` | 后到者立即收到 `{"type":"busy"}`,B 端弹"主机正忙(已有客户端连接)"并返回列表;**已在流的那台不受影响** | | 21 | B:顶栏点变倍/追踪/调色板 | (无日志,全部本地) | 立即生效、无卡顿(调色板/变倍不下发到 A) | | 22 | B:顶栏点 FFC | A 端出现一次快门校正;B 画面随之更新 | FFC 经 A 的热像仪执行 | | 23 | B:点底部红色"断开"圆钮 | A 端:`[remote] client disconnected (frames=)` | B 返回主机列表并弹出"已断开"提示;A 服务端保持"已开启"待重连 | | 24 | A:设置页再点"远程预览服务端"关闭 | `[remote] host stopped` | 文案变回"已关闭";A 本地热像画面不受影响 | 远程预览失败时的表现(设计如此):连不上主机时 B 显示"无法连接主机"并返回列表; 中途断网/主机退出时 B 显示"连接已断开";A 端相机与本地画面**始终不受网络影响**; 日志中 `frames=…` 每 300 帧记一次。 ## 方向与温度(2026-09-11 修复项,重点验证) | # | 操作 | 预期 | 通过标准 | |---|------|------|----------| | 25 | 竖屏正持,观察画面 | (无日志) | 画面正常;中心温读数与手摸/环境常识一致(**不是 -161℃、不是 108℃ 这类离谱值**) | | 26 | 手持手机转四个方向(0/90/180/270),观察画面内容 | (无日志) | **画面内容始终不动**(图像锁定在竖屏框架,与第四/五轮约定一致);顶栏/底栏文字仍随持机朝向保持可读 | | 27 | 点"追踪"关闭 | (无日志) | **最高温和最低温两个标记同时消失**;再点开→两个都出现(此前最低温标记关不掉) | | 28 | 点 FFC,紧盯最高/最低温读数 | `[cmd] FFC(0) write=8/8` | 读数**不出现 ~150℃ 的瞬时跳变**(可短暂保持不变,但不得跳到离谱值) | | 29 | 设置页"旋转USB画面"依次选 0/90/180/270° | (无日志) | 画面按所选角度整体旋转(在锁定基准 90° 之上叠加),用于修正传感器安装方向 | | 29b | 设置页开"竖直翻转",同时"旋转USB画面"设为 90° | (无日志) | 这是用户实测能把画面转到另一方向的组合;**它等价于"水平翻转 + 旋转270°"**(只差一次水平镜像)——若 90°+竖直翻转 看着左右是反的,改用 270°+水平翻转 | | 30 | 设置页"水平翻转"/"竖直翻转"开关 | (无日志) | 画面镜像;与官方 app 的同名设置表现一致 | | 31 | 横屏持机时观察色标条 | (无日志) | 色标条**两端**的最高/最低温数字紧贴色条两端,**不与色条重叠**、不偏移 | | 32 | 分析页打开一张 MDT,观察顶部温度条 | (无日志) | 温度条显示"中心/最低/最高",数值与拍照时实时页读数接近 | | 33 | 设置页**从上往下滑动**,看能否滚到最底部("关于") | (无日志) | 页面可以滚动,**11 行设置项全部可达**(此前无滚动,下方几行点不到) | | 34 | 设置页依次点每一行,确认都有反应 | 调色板/发射率/报警温度/语言/旋转USB画面/云同步/关于 → 弹对话框;水平翻转/竖直翻转 → 文案在"已开启/已关闭"间切换;远程预览服务端 → 切换或弹"先连接热像仪";远程预览客户端 → 进入主机列表 | **没有点了没反应的行**(此前"语言"和"关于"是死行) | | 35 | 在**设置页**改"竖直翻转"或"旋转USB画面",然后切回实时页 | (无日志) | 画面**立即**按新设置显示(设置变更即时下发;此前靠实时页 400ms 轮询,仅在实时页处于打开状态时才生效) | ## 第二轮真机修复项(2026-09-11,重点验证) | # | 操作 | 预期 | 通过标准 | |---|------|------|----------| | 36 | 实时页点"录像",等 10 秒,再点"停止" | `[rec] stopped: frames= dropped= file=<字节>`,随后实时页出现"录像已保存到相册"提示 | **不闪退**(此前停止即崩溃);相册/文件管理器 DCIM/MAG160C 出现 `MAG160C_V_*.mp4` 且**能播放**;日志 `frames` 应为几百(15fps×10s≈150) | | 36b | 若录像仍失败 | `[rec] start failed: …` 或 `[rec] frame dropped (…) dropped=` / `[rec] video publish failed: …` | 日志会指出是编码启动、丢帧还是入库失败;**不再有未捕获异常** | | 37 | 相册页点任意一张照片 | (无日志) | **立即进入查看页**(此前点了没反应);按返回键**回到相册列表**,不是退出软件 | | 38 | 分析页点图像任意位置 | (无日志) | 该处出现白点+圆环+`Pt* 温度`标签;侧边栏"测温点"列表同步新增一行;**再点同一点可删除** | | 39 | 分析页点"保存" | 提示"已保存为新照片" | 相册出现一张 `MAG160C_*_edit.jpg`(**原照片仍在**);打开新照片能看到烧录的测温点标记 | | 40 | 关掉 APP 完全重开,进设置页 | (无日志) | 之前改过的**旋转USB画面/水平翻转/竖直翻转/追踪/默认调色板**都还在(此前会变回默认) | | 41 | 设置页改"追踪"为"最低温",回实时页 | (无日志) | 顶栏显示"追低",画面上**只标最低温**;改成"最高+最低"→ 两个都标;"关闭"→ 都不标 | | 42 | 设置"竖直翻转"开启后拍照 | (无日志) | **照片方向与屏幕一致**(此前保存的是传感器原始朝向,与屏幕不符) | | 43 | 拍照前先在实时页点几个测温点,再拍照 | (无日志) | 照片上带这些测温点与温度;进分析页打开该照片,**测温点仍在**且可继续编辑 | ## 第三轮真机修复项(2026-09-11,重点验证) | # | 操作 | 预期 | 通过标准 | |---|------|------|----------| | 44 | 拍照后在分析页打开该照片 | 日志 `[vm] capture: nuc=yes probes= rot=90 saved=true` | 顶部显示的照片与实时页看到的一致(方向、标注) | | 45 | 看分析页底部数据面板 | (无日志) | 最高/最低/中心温度**与拍照瞬间实时页读数一致**(同一数据源);**不再是 145℃ / -161℃ / 76℃ 这类错误值**;数据在屏幕**底部**(不是右侧竖栏) | | 46 | 分析页对照实时页的测温点位置 | (无日志) | 照片上测温点的**位置与拍照时屏幕上的一致**(此前会偏移/错位) | | 47 | 观察分析页与照片上的测温点标记大小 | (无日志) | 圆点/圆环**小而不遮挡画面**(此前环直径约占图宽 1/9,盖住内容);与实时页观感接近 | | 48 | 分析页点图像新增一个测温点,再点"保存" | 提示"已保存为新照片" | 新照片的测温点位置正确、标记大小正常、温度合理;**原照片仍在** | | 49 | 相册 tab 点一张照片 | (无日志) | 进入**全屏查看**:双指可缩放(1–8×)、拖动可平移、双击复位;**不是**直接进测温分析页 | | 50 | 相册查看页点"删除" | (无日志) | 弹确认对话框;确认后照片消失、返回网格 | | 51 | 相册 tab 与 分析 tab 对比 | (无日志) | **两个界面明显不同**:相册是浏览/缩放/删除;分析只列出可测温的照片并进入测温页(此前两个 tab 渲染同一个网格) | | 52 | 分析页打开一张**本轮之前拍的**旧照片 | (无日志) | 显示"无温度数据",**不显示编造的温度**(旧照片没有 NUC 数据块,这是预期行为) | ## 相机(PIP)失败时的表现(设计如此,不算 bug) PIP 的相机是可选功能,任何相机异常都只记日志并关闭小窗,**不影响热像主画面**: - 无相机硬件 / 权限被拒 → `[pip] no camera available` / `[pip] camera permission not granted`, 小窗空白或未出现; - 相机被其它应用占用 → `[pip] camera error=` + `[pip] released`; - 上述情况下主画面、拍照、录像、分析全部照常工作。 ## 失败时的快速定位(沿用第 11 轮起的诊断路径) - `reads=0` 且 `timeouts` 持续上涨 → 相机没出流:查第 5 步 START 前后的 `[cmd]` 行与 `[usb] ep 0x81 fail#... halted=...`(halt 会自动清除并重试)。 - `frames>0 rendered=0` → 管线在暖机/FFC/参考窗口:看 `ref=false` 是否长期持续 (持续 false → BasePara2/66c 响应异常)。 - `GetParameter1 resp=` 超时 → `[session] parameter1 handshake failed -> abort`, 屏显"相机无应答,请拔插热像仪重试"。 - 相机中途重新枚举(`[vm] usb detached vid=0x833C` + 再次弹权限)→ 多为 OTG 供电/线材问题,换短线或带供电 OTG 再试(第 13 轮结论)。 - 任何闪退:日志文件开头 `[crash]` 行有完整堆栈(DebugLog 崩溃钩子)。