# Jetwave RC-2000 遥控器应用 — 代码分析报告

**项目路径：** `jetwave-rc-2000/`  
**包名：** `com.szdbi.waverider`  
**审查日期：** 2026-05-25  
**审查视角：** 嵌入式系统、AI 硬件链路、全栈/客户端、产品架构、代码审查（客观严谨，供问题定位）

> **非技术人员请先读：** [交互架构与问题导读（含全流程图）](./CODE_REVIEW_交互架构与问题导读.md)  
> 本文档偏技术细节；下图与口述稿在导读中更完整。

---

## 〇、整体交互架构（RC-2000）

### 这个 App 在系统里扮演什么角色？

遥控器是一块 Android 板子，里面的 **waverider** 应用相当于「驾驶舱屏幕 + 通信中转站」：

- 用 **蓝牙（默认）** 和冲浪板上的 ECU 说话  
- 读手柄 **油门**，告诉板子加减速  
- 航行时 **每秒记一条** 状态（含故障码）  
- 结束后 **上传 txt** 到云端，后台用 `https://manager.jetwave.cn/motion/trajectoryHistory/analysis/{日志id}` 查看  

### 整体架构图（RC-2000：默认蓝牙）

```mermaid
flowchart TB
    subgraph 用户侧
        U[油门/档位/屏幕操作]
    end

    subgraph RC2000_App["RC-2000 App"]
        MA[MainActivity 主界面]
        HF[HomeFragment<br/>航行+记日志+故障弹窗]
        BS[BleService 蓝牙服务]
        DH[DataHandler 协议解析]
        UP[UploadSailingRecordUtil 上传]
    end

    subgraph 板子
        ECU[ECU]
        ESC[ESC 电机控制]
    end

    subgraph 云
        OSS[OSS 明细txt]
        WEB[后台 analysis/id]
    end

    U --> HF
    MA --> HF
    HF <-->|EventBus| DH
    HF -->|约1Hz写库| DB[(SQLite轨迹)]
    BS --> DH
    DH <-->|MAVLink| ECU
    ECU --> ESC
    HF --> UP
    DB --> UP
    UP --> OSS --> WEB
```

### 关键业务逻辑（四条线）

| 业务线 | 做什么 | 主要程序 | 出问题时的表现 |
|--------|--------|----------|----------------|
| **连接** | 搜板子、连蓝牙 | `BleService`、`BluetoothUtil` | 断联、连上又掉 |
| **控制** | 油门 → ECU → 电机 | `CommandHelper`、`msg_throttleandgear` | 有油门无动力（失速 131072） |
| **故障** | 心跳带 esc/ecu 码 → 弹窗+记库 | `HomeFragment`、`EscFaultMask` | 失速/过压/通信故障提示 |
| **上传** | 结束 → txt → OSS → 后台 | `UploadSailingRecordUtil` | 后台看不到日志或数据缺段 |

### 业务流程图 ①：从开机到连上板子

```mermaid
sequenceDiagram
    autonumber
    actor 用户
    participant Main as MainActivity
    participant Ble as BleService
    participant DH as DataHandler
    participant 板子 as ECU

    用户->>Main: 打开 App
    Main->>Ble: 启动蓝牙服务
    Ble->>板子: 扫描/连接 GATT
    板子-->>Ble: 连接成功
    Ble->>DH: 收到字节流
    DH->>DH: Parser 解析 MAVLink
    DH->>Main: EventBus「已连接」
    Main->>板子: 查询版本信息

    rect rgb(255, 230, 230)
    Note over Ble,DH: ⚠️【风险A】Parser 全局唯一<br/>连接抖动时可能解析错乱
    end
```

### 业务流程图 ②：航行中（与飞行日志字段一一对应）

```mermaid
flowchart TB
    T[Timer 每秒触发] --> R1[读油门 sysfs<br/>CommandHelper]
    R1 --> R2[读 ECU 心跳<br/>速度/电流/故障码]
    R2 --> R3[写入 SailingRecordItem<br/>含 escEventCode ecuEventCode]
    R3 --> R4[刷新仪表盘 UI]

    R2 --> F{故障码?}
    F -->|esc=131072| S[失速保护<br/>弹窗+埋点]
    F -->|esc=4194304| O[过压保护<br/>弹窗+埋点]
    F -->|ecu=1073741824| C[ESC通信故障<br/>弹窗+埋点]

    R1 --> OUT[发油门指令到 ECU]

    style S fill:#ffcdd2
    style O fill:#ffe0b2
    style C fill:#ffcdd2
    style R3 fill:#c8e6c9
```

**问题逻辑说明（失速不可控）：**

1. 板子 ESC 进入 **失速保护** → 心跳里 `escEventCode = 131072`  
2. App 原样写入轨迹 → 上传 OSS → 就是我们分析的 JSON  
3. 若此时用户仍推油门（`throttleLeverQuantity > 0`）但 `motorSpeed = 0` → **「有指令无输出」**  
4. 根因可能在 **ESC 固件保护不恢复**，也可能 **ECU 与 ESC 通信断**（ecu=1073741824），App 只负责如实记录  

### 业务流程图 ③：结束航行与上传

```mermaid
flowchart LR
    STOP[用户点停止] --> PACK[打包 SQLite 轨迹点]
    PACK --> TXT[生成 txt 文件<br/>SN_1_用户ID_时间.txt]
    TXT --> OSS[上传阿里云 OSS]
    OSS --> API[调 TrajectoryApi 登记]
    API --> ID[后台生成日志 id]
    ID --> URL[可视化页面]

    PACK -.->|⚠️风险B isUpload 非线程安全| X1[可能重复上传]
    TXT -.->|⚠️风险C 成功即删本地文件| X2[失败难补传]
```

### 问题环节与程序对照表（RC-2000）

| 环节 | 可能问题 | 涉及程序/配置 | 严重度 |
|------|----------|---------------|--------|
| 蓝牙连接 | 断联、重连慢 | `BleService`、`BluetoothUtil` | 高 |
| 协议解析 | 多线程串包、状态错乱 | `DataHandler` 静态 `Parser` | **高** |
| 失速保护 | 131072 长时间不恢复 | 板子 ESC 固件 + `HomeFragment` 只弹窗不控恢复 | **高** |
| 故障判断 | 多个故障只显示一个 | `HomeFragment` 用 `==` 比较 | 中 |
| 轨迹记录 | 漏秒、掉点 | `HomeFragment` Timer | 中 |
| 上传 | 卡死、重复、丢文件 | `UploadSailingRecordUtil` | 中 |
| 性能 | 卡顿、通信延迟 | `ThreadPoolUtil` 最大200线程 | 中 |
| 异常 | 崩溃后状态不明 | `MyApplication` 吞掉未捕获异常 | 中 |

---

## 0. 执行摘要

| 维度 | 评级 | 一句话 |
|------|------|--------|
| 整体结构 | B- | 典型 Android 分层 + EventBus，模块清晰但 `HomeFragment` 过重 |
| 通信设计 | B | MAVLink + BLE/串口 AT 三通道，协议定义完整 |
| 交互逻辑 | B- | 航行状态机分散在 Fragment/Timer/EventBus |
| 运动控制 | B | sysfs 油门 + MAVLink 下发，与 ECU 协同明确 |
| 日志上传 | B | OSS + API 双写，字段与后台轨迹一致 |
| 内存管理 | C+ | largeHeap 掩盖问题，轨迹 SQLite 无上限策略可见 |
| 线程安全 | **C** | 全局 Parser 静态、上传标志非原子、线程池过大 |
| 风险漏洞 | **C** | 明文 HTTP、异常吞没、密钥硬编码 |

**与近一月飞行日志问题的直接关联：** 本仓库 `EscFaultMask` / `EcuFaultMask` 与 OSS 轨迹 JSON 字段 **完全一致**（`escEventCode=131072` 失速、`4194304` 过压、`ecuEventCode=1073741824` ESC 通信故障），问题定位应 **App 展示/埋点 + ECU/ESC 固件 + 通信链路** 联合排查。

---

## 1. 项目概览

| 项 | 内容 |
|----|------|
| 类型 | Android 系统应用（`sharedUserId=android.uid.system`） |
| 工程名 | `waverider-yoyo-rc2000` |
| Java 源文件 | **307** |
| Activity | **23** |
| 默认通信 | **板载蓝牙** `BLUETOOTH`（`MyApplication`） |
| API 环境 | **生产** `https://api.jetwave.ai` |
| 版本 | `versionName 0099` / `versionCode 99` |

**无 README / 架构文档**，知识依赖代码逆向。

---

## 2. 整体结构

### 2.1 目录与分层

```
app/src/main/java/
├── com.szdbi.waverider/     # 业务层 (~250 文件)
│   ├── activity/            # 23 个页面
│   ├── fragments/           # 主流程 + BLE/BMS/OTA/校准
│   ├── service/             # BleService, SerialPortService, BmsBleService
│   ├── network/             # Retrofit API + DTO/VO
│   ├── helper/              # 业务辅助、OTA、油门
│   ├── utils/               # 串口、BLE、云、上传
│   ├── manager/             # 日志、Activity 栈
│   ├── task/                # 轨迹统计、安全区等
│   ├── dao/entity/          # OrmLite 持久化
│   ├── event/               # EventBus 消息 (~39)
│   └── tracking/            # 阿里云 SLS
└── com.mavlink/             # 协议栈 (~56 文件，生成代码)
```

### 2.2 架构模式

```mermaid
flowchart TB
    UI[Activity / Fragment / 自定义 View]
    EB[EventBus]
    SVC[Service: BLE / SerialPort / BMS]
    DH[DataHandler + Parser]
    DEV[ECU / BMS / ESC 固件]
    CLOUD[api.jetwave.ai + OSS + SLS]

    UI --> EB
    EB --> UI
    SVC --> DH
    DH --> DEV
    DH --> EB
    UI --> CLOUD
```

**特征：** 事件驱动、Service 长连接、单例 Util/Manager、**无清晰 Domain 层**（业务逻辑大量落在 `HomeFragment`）。

### 2.3 与 RC-3000 结构差异

| 对比项 | RC-2000 | RC-3000 |
|--------|---------|---------|
| Java 文件数 | 307 | 361 |
| Activity | 23 | 26 |
| 默认通信 | 蓝牙 | **星闪** |
| API | 生产域名 | **测试域名** |
| 对讲/AI/NFC | 无 | 有 Intercom、SSE、NFC |

**结论：** 两项目为 **同一代码基线的硬件变种**，核心通信/协议/上传链路同源。

---

## 3. 通信设计

### 3.1 三通道模型

`DataCommunicationMethodEnum`：

| 模式 | 实现 | 物理路径 |
|------|------|----------|
| `BLUETOOTH` | `BleService` → `BluetoothUtil` | 板载 BLE GATT |
| `WL_SERIAL_PORT` | `SerialPortService` + AT | `/dev/ttyS1` @ 921600 |
| `STAR_DODGES` | 同上，星闪 AT 集 | 串口模块 |

**关键文件：**

- `utils/SerialPortUtil.java` — 串口读写、AT 命令
- `service/SerialPortService.java` — 扫描/连接状态机（~1400 行）
- `service/BleService.java` / `utils/BluetoothUtil.java`
- `service/DataHandler.java` — MAVLink 统一入口
- `service/BmsDataHandler.java` — BMS 独立解析

### 3.2 MAVLink 协议层

- 解析器：`com.mavlink.Parser`（字节状态机）
- 分发：`DataHandler.handler()` 按 `msgid` switch
- 核心消息：`msg_ecuheatbeatdata`(101)、`msg_throttleandgear`、`msg_deviceinformationresponse`(103)

### 3.3 故障码定义（与飞行日志对齐）

**ESC — `com/mavlink/enums/EscFaultMask.java`：**

| 常量 | 值 | hex | 日志中命中 |
|------|-----|-----|------------|
| `ESC_FAULT_STALL_PROTECTION` | **131072** | 0x20000 | 是（失速不可控主因） |
| `ESC_FAULT_OVERVOLTAGE_PROTECTION` | **4194304** | 0x400000 | 是 |
| `ESC_FAULT_PROPELLER_OUT_OF_WATER` | 33554432 | 0x2000000 | 日志中高频待命名 |

**ECU — `com/mavlink/enums/EcuFaultMask.java`：**

| 常量 | 值 | hex | 日志中命中 |
|------|-----|-----|------------|
| `FAULT_ESC_COMMUNICATION` | **1073741824** | 0x40000000 | 是（断联代理） |
| `FAULT_IMU_COMMUNICATION` | 536870912 | 0x20000000 | — |
| `FAULT_BATTERY_COMMUNICATION` | 2147483648 | — | — |

> **重要：** 日志分析中的「ECU 断联代理」已在代码中命名为 **`FAULT_ESC_COMMUNICATION`（ESC 通信故障）**，非独立「断联」枚举，UI 层在 `HomeFragment` 映射为 `DataTrackingConstant.FAULT_ESC_COMMUNICATION`。

### 3.4 通信设计评审意见

| 优点 | 风险 |
|------|------|
| MAVLink 代码生成，与固件契约一致 | `Parser` 为 **static 单例**，多线程读串口/BLE 时存在竞态 |
| AT + GATT 双路径覆盖增强蓝牙/星闪 | `SerialPortService` 状态机复杂，断线重连边界难测 |
| 组件 ID 区分 ECU/BMS/ESC | 无应用层「连接质量」指标，只有故障码事后记录 |

---

## 4. 交互逻辑

### 4.1 主流程

```
MainActivity (LAUNCHER + HOME)
  → bind YoYo IDmInterface（硬件 SN/IMEI）
  → start BleService 或 SerialPortService
  → ViewPager2: HomeFragment / Stop / Complete
  → Timer 驱动航行采样、上传触发
```

### 4.2 故障处理 UX（`HomeFragment`）

- 订阅 `EcuHeartbeatDataEvent`，解析 `esc_event` / `ecu_event`
- 与 `EscFaultMask` / `EcuFaultMask` **整型相等**比较（非位掩码叠加）
- 失速：弹窗 + `DataTrackingManager.saveFaultLog(ESC_FAULT_STALL_PROTECTION)`
- 过压：同上 `ESC_FAULT_OVERVOLTAGE_PROTECTION`
- ECU 通信类：区分 FLASH/IMU/ESC/BMS 通信故障

**产品侧注意：** 若固件一次上报多个 fault bit，当前 `==` 判断 **只会匹配单一码**，可能漏报或覆盖。

### 4.3 交互逻辑风险

1. **God Fragment：** `HomeFragment` 集成航行、故障、GPS、安全区、商业模式，维护成本高。
2. **EventBus 粘性事件：** 页面重建可能重复消费。
3. **Timer 与线程混用：** 航行定时器在子线程 `run()` 内再 `runOnUiThread`，异常路径需人工梳理。

---

## 5. 运动控制模块

### 5.1 数据流

```
sysfs 霍尔传感器 (CommandHelper 轮询)
  → 油门杆量 throttleLeverQuantity
  → msg_throttleandgear MAVLink 下发 ECU
  → ECU 控制 ESC/电机
  ← msg_ecuheatbeatdata 心跳（速度、故障、电流）
```

### 5.2 关键模块

| 文件 | 职责 |
|------|------|
| `helper/CommandHelper.java` | `cat /sys/class/yyadc/hall_sensor`，定时采样 |
| `helper/throttle/AdvancedThrottleUtil.java` | 油门曲线 |
| `ThrottleCurveView.java` / `ThrottleCurveFragment.java` | UI 配置 |
| `mavlink/JetWave/msg_throttleandgear.java` | 协议下发 |
| `mavlink/JetWave/msg_setmaxspeed.java` | 限速 |
| `utils/GearListener.java` | 档位物理键 |
| `config/DefaultConfig.java` | 默认限速区间 |

### 5.3 与日志字段对应

上传轨迹 JSON 中 `throttleLeverQuantity`、`gear`、`mode`、`motorSpeed`、`hourSpeed` 均在 `HomeFragment` 定时写入 `SailingRecordItem`，与 OSS 分析字段一致。

### 5.4 运动控制风险

| 风险 | 说明 |
|------|------|
| 油门 sysfs 与 MAVLink 双源 | 显示用 sysfs，控制用 MAVLink，不同步时会出现「有油门无输出」 |
| 失速后 UI 可能仍显示油门 | 日志已见 `stall_with_throttle_no_motor`，需在固件或 App 侧限制输出 |
| 校准值开机写入 | RC-3000 有角度校准开机写 sysfs；RC-2000 **无** 此段逻辑 |

---

## 6. 日志上传模块

### 6.1 三层日志

| 层级 | 实现 | 路径 |
|------|------|------|
| 本地 logcat | `SystemLogManager` / `LogFileManager` | 单文件 10MB，总 100MB |
| 埋点 SLS | `DataTrackingManager` + `AlibabaCloudLogUtil` | OrmLite 队列 |
| 航行轨迹 | `UploadSailingRecordUtil` | SQLite → JSON txt → OSS → API |

### 6.2 轨迹上传链路（与 `surf_motion_trajectory_history` 对应）

```java
// UploadSailingRecordUtil.java
String fileName = String.format("%s_1_%s_%s.txt",
    remoteSn, userId, startTime);  // 与 OSS object_key 一致
// 内容：SailingRecordDTO JSON，含 trajectoryList
// 每项含 escEventCode, ecuEventCode, bmsEventCode
```

**写入频率：** `HomeFragment` 航行 Timer **约 1Hz** 插入 `SailingRecordItem`（与日志 3384 点/3384 秒吻合）。

### 6.3 上传模块风险

| ID | 风险 | 位置 |
|----|------|------|
| L1 | `private static boolean isUpload` **非 volatile**，并发上传可重入 | `UploadSailingRecordUtil` |
| L2 | 上传在 `new Thread()` 而非统一线程池，生命周期无绑定 | 同上 |
| L3 | 上传失败本地文件已 delete，**无断点续传** | success 回调 |
| L4 | `escEventCode` 原样落库，**无位掩码展开**，后台分析需按位与 | `SailingRecordItem` |
| L5 | 故障埋点与轨迹分离，关联靠时间戳手工对齐 | SLS vs OSS |

---

## 7. 内存管理

| 机制 | 配置/实现 | 评价 |
|------|-----------|------|
| Manifest | `largeHeap=true` | 缓解 OOM，不解决泄漏 |
| Gradle dex | `javaMaxHeapSize 2g` | 构建期 |
| 日志文件 | 10MB × N，上限 100MB | 可控 |
| 地图 | Mapbox 10.16 | 大头，Fragment 需关注 onDestroy |
| 轨迹 DB | OrmLite 全量 item 列表读入内存上传 | 长航线内存 spike |
| 集合 | `CopyOnWriteArrayList`、`ConcurrentLinkedQueue` | 读多写少场景合理 |

**未见：** Native 内存池、对象复用、轨迹采样环形缓冲区。

---

## 8. 线程安全

### 8.1 线程模型

| 组件 | 方式 |
|------|------|
| `ThreadPoolUtil` | 核心 100，最大 **200**，队列 100000 |
| 串口读 | `SerialPortUtil` 独立 `Thread` |
| BLE | `BluetoothUtil` Timer + 连接线程 |
| 上传/埋点 | `new Thread()` |
| UI | `runOnUiThread` / RxJava main |

### 8.2 关键问题

```java
// DataHandler.java — 全局共享 Parser
private final static Parser parser = new Parser();
public static void handler(..., byte[] bytes) {
    for (byte aByte : bytes) {
        MAVLinkPacket mavLinkPacket = parser.mavlink_parse_char(aByte);
```

**风险：** BLE 与串口若并行调用 `handler`（切换通信模式边界），Parser 内部状态 **非线程安全**。

```java
// ThreadPoolUtil — 嵌入式设备上过大
new ThreadPoolExecutor(100, 200, ...);
```

**风险：** 线程爆炸、调度延迟、加剧通信丢包。

```java
// UploadSailingRecordUtil
private static boolean isUpload = false;
```

**风险：** 竞态导致重复上传或永久阻塞。

### 8.3 线程安全建议优先级

1. `Parser` 改为 ThreadLocal 或每连接实例  
2. 缩小线程池（建议 core≤4，max≤8）  
3. `isUpload` 改为 `AtomicBoolean`  
4. DataHandler / DeviceInfoConstant 静态可变字段加同步或收敛到单线程 Looper  

---

## 9. 风险与漏洞

| 等级 | 类别 | 描述 | 位置 |
|------|------|------|------|
| **高** | 稳定性 | 默认异常处理器仅 print，**不退出/不上报完整栈** | `MyApplication.MyUncaughtExceptionHandler` |
| **高** | 并发 | MAVLink Parser 静态共享 | `DataHandler` |
| **中** | 安全 | `cleartextTrafficPermitted=true` | `network_security_config.xml` |
| **中** | 安全 | Bugly AppId 硬编码 | `MyApplication` |
| **中** | 逻辑 | 故障码 `==` 单值比较，不支持多位同时置位 | `HomeFragment` |
| **中** | 运维 | 生产 API 固定，无 flavor 隔离文档 | `RequestManager` |
| **低** | 依赖 | OrmLite/Fastjson 等老旧库 | `build.gradle` |

---

## 10. 与飞行日志故障数据的映射

| 日志现象 | 代码侧对应 | 建议排查 |
|----------|------------|----------|
| escEventCode=131072 主导 | `EscFaultMask.ESC_FAULT_STALL_PROTECTION` | ESC 固件失速保护阈值与恢复 |
| escEventCode=4194304 | `ESC_FAULT_OVERVOLTAGE_PROTECTION` | 母线电压采样、电池内阻 |
| ecuEventCode=1073741824 | `EcuFaultMask.FAULT_ESC_COMMUNICATION` | ECU-ESC 通信超时/CAN |
| 油门有、电机 0 | `throttleLeverQuantity` + `motorSpeed` 分源 | `CommandHelper` vs 心跳 |
| 文件命名 `SN_1_userId_time.txt` | `UploadSailingRecordUtil` | 与 CSV `object_key` 一致 |

**后台可视化：** `https://manager.jetwave.cn/motion/trajectoryHistory/analysis/{id}`

---

## 11. 快速优化改进建议（RC-2000）

> 原则：**先止血（连接/解析/故障判断）→ 再提质（上传/架构）→ 并行固件验证**。下列方案按「改动量小、见效快」排序。

### 11.1 改进路线图（建议 4 周）

```mermaid
gantt
    title RC-2000 快速改进节奏
    dateFormat  YYYY-MM-DD
    section 第1周止血
    Parser单线程化           :a1, 2026-05-26, 3d
    故障码改位运算           :a2, 2026-05-26, 2d
    上传AtomicBoolean       :a3, 2026-05-29, 2d
    section 第2周可观测
    连接质量埋点             :b1, 2026-06-02, 4d
    失速会话现场日志包       :b2, 2026-06-02, 3d
    section 第3-4周结构
    通信层抽离+线程池缩容    :c1, 2026-06-09, 7d
    HomeFragment拆分一期     :c2, 2026-06-16, 7d
```

### 11.2 快速赢（1～3 天可落地，建议立即做）

| # | 改进项 | 怎么做 | 改哪里 | 预期效果 |
|---|--------|--------|--------|----------|
| **Q1** | **MAVLink 解析单线程化** | 所有 `DataHandler.handler()` 投递到 **单线程 SerialExecutor**；禁止 BLE/串口回调线程直接解析 | `DataHandler.java` | 消除串包/错乱，降低「假断联」 |
| **Q2** | **故障码改为位判断** | `if ((escEvent & EscFaultMask.ESC_FAULT_STALL_PROTECTION) != 0)`；ECU 同理；弹窗可显示 **主故障+次故障** | `HomeFragment.java` | 复合故障不漏报，与日志分析一致 |
| **Q3** | **上传互斥改原子变量** | `AtomicBoolean` + `compareAndSet`；失败 **不删** 本地 txt，标记 `upload_pending` | `UploadSailingRecordUtil.java` | 避免重复上传/永久卡死/丢数据 |
| **Q4** | **线程池缩容** | `core=2, max=4, queue=500`；禁止 100～200 线程 | `ThreadPoolUtil.java` | 减轻调度延迟，通信更稳 |
| **Q5** | **连接切换时强制复位** | 切换蓝牙/星闪前：`DataHandler.disconnect()` + 停旧 Service + 500ms 后再启新 Service | `CommunicationSettingsActivity`、各 Service | 减少僵尸连接 |

**Q2 示例（便于研发直接改）：**

```java
// 原：if (escEvent == EscFaultMask.ESC_FAULT_STALL_PROTECTION)
// 改：
if ((escEvent & EscFaultMask.ESC_FAULT_STALL_PROTECTION) != 0) {
    handleStall(escEvent);
}
if ((ecuEvent & EcuFaultMask.FAULT_ESC_COMMUNICATION) != 0) {
    handleEscCommFault(ecuEvent);
}
```

### 11.3 短期改进（1～2 周，针对「失速/断联」）

| # | 改进项 | 方案说明 | 负责 |
|---|--------|----------|------|
| **S1** | **连接质量可观测** | 每秒记：`rssi`、距上次心跳间隔 `heartbeat_gap_ms`、重连次数；写入 SLS 与轨迹扩展字段 | App |
| **S2** | **失速后会话标记** | 轨迹内首次出现 131072 时打标 `stall_session=true`；上传后后台可直接筛 | App + 后台 |
| **S3** | **「有油门无电机」规则** | 当 `throttle>0 && motorSpeed==0 && esc含131072` 连续 N 秒 → 弹 **明确文案** + 引导松油门/重启 | App 产品 |
| **S4** | **固件联合回归** | 对 Top 设备 `5G002872`、`6A000193` 做：蓝牙直连 vs 星闪（若可切换）对比 + CAN 抓包 | 固件+硬件 |
| **S5** | **异常不再静默** | `MyUncaughtExceptionHandler` 上报 Bugly 完整栈，通信线程异常触发 **安全降级**（停发油门） | App |

### 11.4 中期架构改进（2～4 周）

| # | 改进项 | 建议方案 |
|---|--------|----------|
| **M1** | **拆分 HomeFragment** | `SailingController`（Timer/记库）、`FaultPresenter`（故障 UI）、`GaugeBinder`（仪表） |
| **M2** | **通信层接口化** | `ILinkChannel`：`BleChannel` / `SerialChannel`；`DataHandler` 只依赖接口 |
| **M3** | **轨迹写入环形缓冲** | 内存固定容量，上传时批量落库，避免长航线 OOM |
| **M4** | **Build Flavor** | `prod` → api.jetwave.ai；`staging` → surfdev；避免环境混用 |
| **M5** | **上传断点续传** | OSS 成功后删文件；失败保留并按 `sailing_record_id` 重试 |

### 11.5 固件 / 硬件侧（与 App 并行，不可省）

| 问题现象 | 建议固件动作 | 验证标准 |
|----------|--------------|----------|
| 131072 占会话 80%+ | 审查失速触发条件、恢复条件、是否需用户松油门才恢复 | 保护后 10s 内可恢复驱动，或明确不可恢复原因 |
| 1073741824 与 stall 同现 | 查 ECU↔ESC 超时、线缆、干扰；蓝牙直连对比 | 通信故障率下降 50%+ |
| 4194304 仅 6 条 | 母线电压滤波、再生制动策略 | 大电流工况不频繁误触发 |

### 11.6 验证清单（改完必测）

| 场景 | 步骤 | 通过标准 |
|------|------|----------|
| 蓝牙连接 | 开机 → 连板 → 航行 10min | 无 Parser 错乱；心跳连续 |
| 失速复现 | 用问题 SN 或模拟故障码 | 弹窗正确；轨迹 esc=131072；位判断可叠加 |
| 上传 | 结束航行 → 断网 → 恢复网络 | 不丢 txt；不重复上传；后台 id 可查 |
| 切换通信 | 设置里切换模式（若支持） | 旧连接释放；新连接可用 |
| 压力 | 连续航行 30min + 地图/对讲关 | 无 ANR；内存不持续增长 |

### 11.7 RC-2000 专属注意

- **默认蓝牙**：优先在 RC-2000 上验证 Q1～Q5，作为「通信基线」对照组。  
- 若 RC-2000 失速率 **明显低于** RC-3000，则问题更偏向 **星闪链路**；若两项目接近，则偏向 **Parser/固件/ESC 共性**。

---

## 12. 关键文件索引

| 模块 | 路径 |
|------|------|
| Application | `app/.../MyApplication.java` |
| 主界面 | `app/.../activity/MainActivity.java` |
| 航行与采样 | `app/.../fragments/HomeFragment.java` |
| MAVLink 分发 | `app/.../service/DataHandler.java` |
| 故障枚举 ESC | `app/.../mavlink/enums/EscFaultMask.java` |
| 故障枚举 ECU | `app/.../mavlink/enums/EcuFaultMask.java` |
| 轨迹上传 | `app/.../utils/UploadSailingRecordUtil.java` |
| 轨迹实体 | `app/.../entity/sql/SailingRecordItem.java` |
| 线程池 | `app/.../utils/ThreadPoolUtil.java` |
| API | `app/.../network/RequestManager.java` |

---

*本报告基于静态代码审查，未执行运行时插桩；结论需结合 RC2000 实机日志与固件版本验证。*
