# XYParser 数据流与接口时序说明

## 1. 参与角色

- **64导EEG采集设备**
  - 持续输出原始 EEG 字节流。
- **上位机**
  - 负责接收设备数据、调用 XYParser 库、对接算法模块。
- **XYParser 库**
  - 负责帧解析、阻抗计算、算法数据回灌后的 Welch/PSD 计算。
- **算法**
  - 接收上位机送入的算法数据，并输出用于 PSD/Welch 计算的数据。

## 2. 总体链路

当前流程可以分为两个阶段：

- **阶段一：阻抗检测阶段**
  - 设备连接后，首先下发采样率和增益配置命令。
  - 然后下发阻抗开启命令。
  - 在该阶段持续接收设备数据，并通过 `XYParser_ReadImpedance` 读取阻抗结果。
  - 阻抗检测结束后，下发阻抗关闭命令。

- **阶段二：常规采集与算法阶段**
  - 基于 `XYParser_Feed` 解析得到的帧数据继续做常规采集。
  - 帧数据先转换为算法数据，再送入算法模块。
  - Welch/PSD 不再直接基于帧解析结果计算，而是基于算法数据，通过 `XYParser_FeedAlgorithmData` 输入后计算。

## 3. 接口时序图

### 3.1 64导初始化连接阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 64导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库

    Dev-->>Host: 设备连接成功
    Host->>Lib: parser64 = XYParser_CreateParser(64)
    Host->>Lib: XYParser_SetAdcParams(parser64, 4.5, 6.0)
    Host->>Lib: XYParser_SetSampleRate(parser64, 250)
    Host->>Lib: XYParser_SetBypassChecksum(parser64, 0)
    Host->>Lib: gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
    Lib-->>Host: gain_cmd_size
    Host->>Lib: gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(6, 250, gain_cmd_buf, gain_cmd_size)
    Lib-->>Host: gain_cmd_bytes
    Host->>Dev: 下发采样率250、增益6命令
```

### 3.2 64导阻抗阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 64导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库

    Host->>Lib: XYParser_SetImpedanceDetection(parser64, 1)
    Host->>Lib: impedance_gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
    Lib-->>Host: impedance_gain_cmd_size
    Host->>Lib: impedance_gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(24, 250, impedance_gain_cmd_buf, impedance_gain_cmd_size)
    Lib-->>Host: impedance_gain_cmd_bytes
    Host->>Dev: 下发采样率250、增益24命令
    Host->>Lib: impedance_cmd_size = XYParser_Get64ImpedanceCommandSize()
    Lib-->>Host: impedance_cmd_size
    Host->>Lib: open_impedance_bytes = XYParser_Serialize64ImpedanceCommand(1, impedance_cmd_buf, impedance_cmd_size)
    Lib-->>Host: open_impedance_bytes
    Host->>Dev: 下发阻抗开启命令

    loop 持续获取阻抗
        Dev-->>Host: 原始EEG字节流
        Host->>Lib: frame_count = XYParser_Feed(parser64, raw_data, raw_size, frame_summaries, max_frames)
        Lib-->>Host: frame_count + frame_summaries
        Host->>Lib: impedance_count = XYParser_ReadImpedance(parser64, impedance_summaries, max_impedance)
        Lib-->>Host: impedance_count + impedance_summaries
    end

    Host->>Lib: close_impedance_bytes = XYParser_Serialize64ImpedanceCommand(0, impedance_cmd_buf, impedance_cmd_size)
    Lib-->>Host: close_impedance_bytes
    Host->>Dev: 下发阻抗关闭命令
    Host->>Lib: restore_gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
    Lib-->>Host: restore_gain_cmd_size
    Host->>Lib: restore_gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(6, 250, restore_gain_cmd_buf, restore_gain_cmd_size)
    Lib-->>Host: restore_gain_cmd_bytes
    Host->>Dev: 下发采样率250、增益6命令
    Host->>Lib: XYParser_SetImpedanceDetection(parser64, 0)
```

### 3.3 64导算法阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 64导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库
    participant Algo as 算法

    Host->>Lib: XYParser_SetWelchDetection(parser64, 1)

    loop 持续采集
        Dev-->>Host: 原始EEG字节流
        Host->>Lib: frame_count = XYParser_Feed(parser64, raw_data, raw_size, frame_summaries, max_frames)
        Lib-->>Host: frame_count + frame_summaries
        Host->>Lib: value_count = XYParser_GetAlgorithmDataValueCount()
        Lib-->>Host: value_count
        Host->>Lib: ok = XYParser_ConvertSampleFramesToAlgorithmData(frame_summary, algorithm_input_data)
        Lib-->>Host: ok + algorithm_input_data
        Host->>Algo: 输入算法数据 algorithm_input_data
        Algo-->>Host: 算法输出数据 algorithm_output_bytes
        Host->>Lib: alg_frame_count = XYParser_FeedAlgorithmData(parser64, algorithm_output_bytes, algorithm_output_size, algorithm_frames, max_algorithm_frames)
        Lib-->>Host: alg_frame_count + algorithm_frames
        Host->>Lib: welch_count = XYParser_ReadWelch(parser64, welch_summaries, max_welch)
        Lib-->>Host: welch_count + welch_summaries
    end

    opt 结束时处理尾数据
        Host->>Lib: flushed = XYParser_FlushAlgorithmData(parser64, tail_frame_summary)
        Lib-->>Host: flushed + tail_frame_summary
        Host->>Lib: welch_count = XYParser_ReadWelch(parser64, welch_summaries, max_welch)
        Lib-->>Host: welch_count + welch_summaries
    end

    Host->>Lib: XYParser_DestroyParser(parser64)
```

### 3.4 64导训练打标阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Port as 64导EEG设备串口
    participant Host as 上位机
    participant Lib as XYParser库
    participant Time as 时间

    Host->>Lib: trigger_cmd_size = XYParser_GetTriggerCommandSize()
    Lib-->>Host: trigger_cmd_size
    Host->>Lib: train0_bytes = XYParser_SerializeTriggerCommand(XYPARSER_TRIGGER_TRAIN_0, trigger_cmd_buf, trigger_cmd_size)
    Lib-->>Host: train0_bytes
    Host->>Port: 发送 TRAIN_0 打标
    Host->>Time: 开始训练计时
    Time-->>Host: 训练时间到
    Host->>Lib: train1_bytes = XYParser_SerializeTriggerCommand(XYPARSER_TRIGGER_TRAIN_1, trigger_cmd_buf, trigger_cmd_size)
    Lib-->>Host: train1_bytes
    Host->>Port: 发送 TRAIN_1 打标
```

### 3.5 8导初始化连接阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 8导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库

    Dev-->>Host: 设备连接成功
    Host->>Lib: parser8 = XYParser_CreateParser(8)
    Host->>Lib: XYParser_SetAdcParams(parser8, vref, gain)
    Host->>Lib: XYParser_SetSampleRate(parser8, sample_rate)
    Host->>Lib: XYParser_SetBypassChecksum(parser8, 0)
```

### 3.6 8导阻抗阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 8导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库

    Host->>Lib: XYParser_SetImpedanceDetection(parser8, 1)
    Host->>Lib: impedance_cmd_size = XYParser_Get8ChImpedanceCommandSize()
    Lib-->>Host: impedance_cmd_size
    Host->>Lib: open_impedance_bytes = XYParser_Serialize8ChImpedanceCommand(1, impedance_cmd_buf, impedance_cmd_size)
    Lib-->>Host: open_impedance_bytes
    Host->>Dev: 下发阻抗开启命令

    loop 持续获取阻抗
        Dev-->>Host: 原始EEG字节流
        Host->>Lib: frame_count = XYParser_Feed(parser8, raw_data, raw_size, frame8_summaries, max_frames)
        Lib-->>Host: frame_count + frame8_summaries
        Host->>Lib: impedance_count = XYParser_ReadImpedance(parser8, impedance_summaries, max_impedance)
        Lib-->>Host: impedance_count + impedance_summaries
    end

    Host->>Lib: close_impedance_bytes = XYParser_Serialize8ChImpedanceCommand(0, impedance_cmd_buf, impedance_cmd_size)
    Lib-->>Host: close_impedance_bytes
    Host->>Dev: 下发阻抗关闭命令
    Host->>Lib: XYParser_SetImpedanceDetection(parser8, 0)
```

### 3.7 8导算法阶段

```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
    participant Dev as 8导EEG采集设备
    participant Host as 上位机
    participant Lib as XYParser库
    participant Algo as 算法

    Host->>Lib: XYParser_SetWelchDetection(parser8, 1)

    loop 持续采集
        Dev-->>Host: 原始EEG字节流
        Host->>Lib: frame_count = XYParser_Feed(parser8, raw_data, raw_size, frame8_summaries, max_frames)
        Lib-->>Host: frame_count + frame8_summaries
        Host->>Lib: converted = XYParser_Convert8ChFramesTo64Ch(frame8_summary, 1, frame64_summary, 1)
        Lib-->>Host: converted + frame64_summary
        Host->>Lib: value_count = XYParser_GetAlgorithmDataValueCount()
        Lib-->>Host: value_count
        Host->>Lib: ok = XYParser_ConvertSampleFramesToAlgorithmData(frame64_summary, algorithm_input_data)
        Lib-->>Host: ok + algorithm_input_data
        Host->>Algo: 输入算法数据 algorithm_input_data
        Algo-->>Host: 算法输出数据 algorithm_output_bytes
        Host->>Lib: alg_frame_count = XYParser_FeedAlgorithmData(parser8, algorithm_output_bytes, algorithm_output_size, algorithm_frames, max_algorithm_frames)
        Lib-->>Host: alg_frame_count + algorithm_frames
        Host->>Lib: welch_count = XYParser_ReadWelch(parser8, welch_summaries, max_welch)
        Lib-->>Host: welch_count + welch_summaries
    end

    opt 结束时处理尾数据
        Host->>Lib: flushed = XYParser_FlushAlgorithmData(parser8, tail_frame_summary)
        Lib-->>Host: flushed + tail_frame_summary
        Host->>Lib: welch_count = XYParser_ReadWelch(parser8, welch_summaries, max_welch)
        Lib-->>Host: welch_count + welch_summaries
    end

    Host->>Lib: XYParser_DestroyParser(parser8)
```

## 4. 关键接口职责

### 4.1 设备参数配置

- `XYParser_SetAdcParams`
  - 设置库内使用的 ADC 参考电压和增益参数。
  - 该参数影响原始采样值到微伏值的换算。

- `XYParser_SetSampleRate`
  - 设置库内处理逻辑使用的采样率。
  - 该参数影响阻抗、Welch/PSD 等后续处理。

- `XYParser_Get64GainSampleRateCommandSize`
  - 获取 64 导设备增益和采样率配置命令所需的缓冲区大小。

- `XYParser_Serialize64GainSampleRateCommand`
  - 根据目标增益和采样率生成下发给 64 导设备的命令字节流。
  - 上位机拿到该命令后发送给 EEG 设备，使设备端采样参数与库内配置保持一致。
  - 当前推荐流程中：
    - `vref` 固定为 `4.5`。
    - 设备连接成功后，先下发 `250Hz + 增益6`。
    - 开启阻抗前，下发 `250Hz + 增益24`，同时调用 `XYParser_SetImpedanceDetection(handle, 1)`，使库内 gain 自动切到 `24`。
    - 关闭阻抗后，再下发 `250Hz + 增益6`，同时调用 `XYParser_SetImpedanceDetection(handle, 0)`，使库内 gain 自动恢复到 `6`。

- `XYParser_Get64ImpedanceCommandSize`
  - 获取 64 导阻抗开关命令所需的缓冲区大小。

- `XYParser_Serialize64ImpedanceCommand`
  - 生成下发给 64 导设备的阻抗开关命令字节流。
  - `open = 1` 表示开启阻抗检测，`open = 0` 表示关闭阻抗检测。

- `XYParser_Get8ChImpedanceCommandSize`
  - 获取 8 导阻抗开关命令所需的缓冲区大小。

- `XYParser_Serialize8ChImpedanceCommand`
  - 生成下发给 8 导设备的阻抗开关命令字节流。
  - `open = 1` 表示开启阻抗检测，`open = 0` 表示关闭阻抗检测。
  - 8 导流程中，设备连接后**不需要**额外下发增益和采样率命令。

### 4.2 原始数据解析

- `XYParser_Feed`
  - 输入设备原始字节流。
  - 输出解析后的 `XYParserFrameSummary` 数组。
  - 该接口当前仍负责驱动阻抗相关计算。
  - 该接口当前**不再驱动 Welch/PSD 计算**。

### 4.3 阻抗读取

- `XYParser_SetImpedanceDetection`
  - 控制是否启用阻抗检测。
  - 启用时，库内 ADC 增益自动切换到 `24`。
  - 关闭时，库内 ADC 增益自动恢复到 `6`。
  - 该接口只修改库内解析参数，不会自动给设备发送控制命令。

- `XYParser_ReadImpedance`
  - 读取当前已经累计完成的阻抗结果。
  - 阻抗结果来源于阻抗检测阶段的帧解析链路。

### 4.4 帧转算法数据

- `XYParser_ConvertSampleFramesToAlgorithmData`
  - 将单帧 `XYParserFrameSummary` 转为算法需要的连续数组。
  - 上位机通常在拿到帧数据后调用此接口，再把结果送入算法模块。

- `XYParser_Convert8ChFramesTo64Ch`
  - 将 8 导帧转换为 64 导帧，未映射导联补 0。
  - 8 导流程中，在送算法数据前，需要先把 8 导帧转换为 64 导帧，再调用 `XYParser_ConvertSampleFramesToAlgorithmData`。

### 4.5 算法数据回灌

- `XYParser_FeedAlgorithmData`
  - 输入算法数据字节流。
  - 内部先按采样缓存，再按每 5 个采样组装为一帧。
  - 同时驱动 Welch/PSD 计算。
  - 可选输出重新组装后的 `XYParserFrameSummary`。

- `XYParser_ResetAlgorithmDataCache`
  - 清空算法数据缓存。
  - 适合在切换任务、重置状态时调用。

- `XYParser_FlushAlgorithmData`
  - 将缓存中不足 5 个采样的尾数据补齐为 1 帧输出。
  - 用于结束阶段处理残留数据。

### 4.6 Welch/PSD 读取

- `XYParser_SetWelchDetection`
  - 控制是否启用基于算法数据的 Welch 检测。

- `XYParser_ReadWelch`
  - 读取当前已累计完成的 Welch/PSD 结果。
  - Welch 结果当前仅来源于 `XYParser_FeedAlgorithmData`。

## 5. 当前设计结论

### 5.1 阻抗数据来源

- 阻抗在独立的阻抗检测阶段获取。
- 即：
  - 设备连接成功
  - 下发采样率250和增益6命令
  - `XYParser_SetImpedanceDetection(handle, 1)`
  - 下发采样率250和增益24命令
  - 下发阻抗开启命令
  - 设备原始字节流
  - `XYParser_Feed`
  - `XYParser_ReadImpedance`
  - `XYParser_SetImpedanceDetection(handle, 0)`
  - 下发阻抗关闭命令
  - 下发采样率250和增益6命令

### 5.2 PSD 数据来源

- PSD/Welch 不再直接使用 `XYParser_Feed` 解析出来的帧数据。
- 当前流程为：
  - 设备原始字节流
  - `XYParser_Feed`
  - `XYParser_ConvertSampleFramesToAlgorithmData`
  - 算法处理
  - `XYParser_FeedAlgorithmData`
  - `XYParser_ReadWelch`

### 5.3 8导算法数据来源

- 8 导流程中，算法输入和 Welch/PSD 仍然按 64 导数据格式处理。
- 当前流程为：
  - 8 导设备原始字节流
  - `XYParser_Feed`
  - `XYParser_Convert8ChFramesTo64Ch`
  - `XYParser_ConvertSampleFramesToAlgorithmData`
  - 算法处理
  - `XYParser_FeedAlgorithmData`
  - `XYParser_ReadWelch`

## 6. 推荐调用顺序

### 6.1 64导推荐调用顺序

```text
1. EEG 设备连接成功
2. CreateParser
3. SetAdcParams(4.5, 6) / SetSampleRate(250) / SetBypassChecksum
4. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(6, 250)
5. 上位机向设备下发采样率250、增益6命令
6. SetImpedanceDetection(1)
7. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(24, 250)
8. 上位机向设备下发采样率250、增益24命令
9. Get64ImpedanceCommandSize / Serialize64ImpedanceCommand(1)
10. 上位机向设备下发阻抗开启命令
11. 阻抗检测阶段循环:
   11.1 Feed 原始字节流，拿到帧
   11.2 ReadImpedance 读取阻抗
12. Serialize64ImpedanceCommand(0)
13. 上位机向设备下发阻抗关闭命令
14. SetImpedanceDetection(0)
15. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(6, 250)
16. 上位机向设备下发采样率250、增益6命令
17. SetWelchDetection
18. 常规采集阶段循环:
   18.1 Feed 原始字节流，拿到帧
   18.2 将帧转换为算法数据
   18.3 将算法数据送入算法模块
   18.4 将算法输出数据通过 FeedAlgorithmData 回灌
   18.5 ReadWelch 读取 PSD/Welch 结果
19. 必要时 FlushAlgorithmData
20. DestroyParser
```

### 6.2 8导推荐调用顺序

```text
1. EEG 设备连接成功
2. CreateParser
3. SetAdcParams(vref, gain) / SetSampleRate(sample_rate) / SetBypassChecksum
4. SetImpedanceDetection(1)
5. Get8ChImpedanceCommandSize / Serialize8ChImpedanceCommand(1)
6. 上位机向设备下发阻抗开启命令
7. 阻抗检测阶段循环:
   7.1 Feed 原始字节流，拿到8导帧
   7.2 ReadImpedance 读取阻抗
8. Serialize8ChImpedanceCommand(0)
9. 上位机向设备下发阻抗关闭命令
10. SetImpedanceDetection(0)
11. SetWelchDetection
12. 常规采集阶段循环:
   12.1 Feed 原始字节流，拿到8导帧
   12.2 将8导帧转换为64导帧
   12.3 将64导帧转换为算法数据
   12.4 将算法数据送入算法模块
   12.5 将算法输出数据通过 FeedAlgorithmData 回灌
   12.6 ReadWelch 读取 PSD/Welch 结果
13. 必要时 FlushAlgorithmData
14. DestroyParser
```

## 7. 一句话总结

- **阻抗是独立阶段，先开阻抗、持续读取、再关阻抗。**
- **Welch/PSD 走算法数据链路。**
- **8导送算法前，先转成64导数据。**
