# Bug 排查方案：Radio valid 字段始终为 0

## 问题摘要

下发搜台指令后，`onFreqChanged` 回调中 `valid` 和 `signal` 始终为 0，即便频率在持续变化。

---

## 排查策略：按数据流从下往上逐层排查

### 第 0 层：环境信号确认

**目的**：排除"测试环境确实没有电台信号"的可能。

**方法**：
- 用一台普通收音机在同一位置扫描 FM 波段（87-108 MHz）
- 确认是否有已知的强信号电台（如本地交通台、音乐台等）
- 记录已知电台的大致频率，作为后续 MCU 搜台的参照

**判断标准**：
- 有已知电台 → 信号环境 OK，进入第 1 层
- 没有电台（地下室/屏蔽室）→ 换到有信号的场地重新测试

---

### 第 1 层：串口原始数据抓取

**目的**：确认 MCU 发出的原始字节到底是什么，这是区分"MCU 没发"还是"上层解析错"的根本手段。

**方法**（按优先级排列）：

**方案 A — 软件层面加日志**（最快）：
- 在 `mcu_protocol.c` 的帧解析完成后，加一条 hex dump 日志
- 打印完整的 FREQ 帧（Byte8~Byte14 的 7 个字节），格式如：
  ```
  FREQ raw: 27 82 00 22 00 00 00
  ```
- 对照协议文档逐字节解读，确认 Byte12 bit7 是否确实为 0

**方案 B — 串口抓包工具**（更可靠）：
- 使用 `socat` 或自编程序在 `/dev/ttyS7` 上做软件抓包
- 或者用硬件串口分析仪抓取物理层信号
- 将抓取的二进制帧对照 Radio.xlsx 协议逐字节解析

**方案 C — 使用已有的 C 测试工具**：
- 项目中 `test_Serial/` 目录下有独立的 C 串口测试程序
- 可直接用这些工具连接 MCU，发送搜台命令，打印原始回复

**判断标准**：
- Byte12 bit7 = 1 出现在某个频率上 → MCU 侧正常，问题在 Java 解析层
- Byte12 bit7 始终 = 0，且 Byte14 (signal) 也始终 = 0 → MCU 固件问题
- Byte12 bit7 始终 = 0，但 Byte14 有变化 → MCU 搜到了信号但没有正确设置 valid 位

---

### 第 2 层：JNI 边界数据校验

**目的**：确认从 C 层到 Java 层的字节数组传递没有发生截断或错位。

**方法**：
- 在 `jni_bridge.cpp` 中，在回调 Java `onFrame()` 方法之前，打印 `body` 数组的完整内容
- 与第 1 层 C 侧的日志对比，确认数据一致

**关键检查点**：
- body 数组的长度是否 >= 7
- body[4]（Byte12）的值
- body[6]（Byte14）的值

---

### 第 3 层：RadioFeature 解析逻辑走查

**目的**：确认 `handleFreq()` 中的字节索引和位操作与协议文档一致。

**对照协议文档逐一核对**：

| 字段 | 代码位置 | 协议定义 | 是否一致 |
|------|---------|---------|---------|
| freq | `p[0]<<8 \| p[1]` | Byte8 High + Byte9 Low | 待验证 |
| band | `p[2] & 0x0F` | Byte10 bits3-0 | 待验证 |
| seekMode | `p[3] & 0x0F` | Byte11 bits3-0 | 待验证 |
| switchTa | `(p[3]>>4) & 1` | Byte11 bit4 | 待验证 |
| switchAf | `(p[3]>>5) & 1` | Byte11 bit5 | 待验证 |
| flagStereo | `p[4] & 1` | Byte12 bit0 | 待验证 |
| flagTp | `(p[4]>>1) & 1` | Byte12 bit1 | 待验证 |
| flagTa | `(p[4]>>2) & 1` | Byte12 bit2 | 待验证 |
| afBlink | `(p[4]>>3) & 1` | Byte12 bit3 | 待验证 |
| bandSwitching | `(p[4]>>4) & 1` | Byte12 bit4 | 待验证 |
| **valid** | `(p[4]>>7) & 1` | **Byte12 bit7** | **待验证** |
| pty | `p[5] & 0xFF` | Byte13 | 待验证 |
| signal | `p[6] & 0xFF` | Byte14 | 待验证 |

**重点排查假设**：

1. **body 数组起始偏移是否正确？** body 的第 0 个字节是否真的对应协议中的 Byte8（P0）？
   如果帧解析时多跳或少跳了字节，整个 body 数组会整体偏移。

2. **p[4] (Byte12) 的 bit7 在 MCU 实际回复中是否被使用？**
   检查协议版本——V1.0 协议中 bit7 是否已经定义？MCU 固件是否支持？

3. **p[6] (Byte14 signal) 始终为 0 也是一个重要线索。**
   如果 signal 也不对，可能说明 body 数组的后半段（P4-P6）整体有问题——要么 body 长度不够（实际只有 5 字节被传过来），要么 MCU 没有填充这些字节。

---

### 第 4 层：AIDL 传输校验

**目的**：确认 `RadioState` 通过 AIDL/Parcelable 序列化后，valid 字段没有丢失。

**方法**：
- 在 `RadioFeature.broadcast()` 中，`snapshot()` 之后立即打印 `snap.valid` 的值
- 在 SDK 侧 `onFreqChanged()` 回调中，打印接收到的 `RadioState.valid`
- 对比两边的值是否一致

**判断标准**：
- 值不一致 → Parcelable 序列化/反序列化有问题
- 值一致 → 问题不在 AIDL 层

---

### 第 5 层：MCU 固件排查

**目的**：确认 MCU 固件（`swVersion=0302_20260520`）的搜台行为是否正确。

**方法**：
- 联系 MCU 供应商，确认该固件版本的 FREQ 帧定义是否与 V1.0 协议一致
- 询问是否有其他客户反馈过类似问题
- 如果可能，用不同版本的 MCU 固件做对比测试
- 确认 Byte12 bit7 在 MCU 固件中是否已实现（协议中标了，但固件可能未支持）

---

## 排查优先级

```
优先级 1: 第 0 层（环境确认）— 5 分钟，最基础的前提条件
优先级 2: 第 1 层（串口原始数据）— 关键分水岭，决定问题在 MCU 侧还是上层
优先级 3: 第 3 层（RadioFeature 解析）— 如果原始数据正确但解析后丢失
优先级 4: 第 5 层（MCU 固件）— 如果原始数据本身就缺 valid 位
优先级 5: 第 2 层（JNI 边界）— 数据传递校验
优先级 6: 第 4 层（AIDL 传输）— 序列化校验
```

## 关键排查线索

日志中 `signal=0` 与 `valid=0` 同时出现，这是一个重要突破口：
- 如果只是 valid 为 0，可能是 bit7 解析问题
- **valid 和 signal 同时为 0 全程不变**，更可能指向 body 数组的 P4~P6 段整体异常，或者 MCU 固件未填充这些字段
- 建议优先用串口抓包确认原始数据，这一个步骤就能排除掉一半的可能性
