579 lines
24 KiB
Markdown
579 lines
24 KiB
Markdown
# TactileIPC3D 架构说明
|
||
|
||
## UML (Mermaid)
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class AppBackend {
|
||
+bool lightMode
|
||
+string language
|
||
+bool connected
|
||
+SerialBackend* serial
|
||
+DataBackend* data
|
||
+int rangeMin
|
||
+int rangeMax
|
||
+QColor colorLow
|
||
+QColor colorMid
|
||
+QColor colorHigh
|
||
+setLightMode(bool)
|
||
+setLanguage(string)
|
||
+setRangeMin(int)
|
||
+setRangeMax(int)
|
||
+setColorLow(QColor)
|
||
+setColorMid(QColor)
|
||
+setColorHigh(QColor)
|
||
}
|
||
|
||
class SerialConfig {
|
||
+string portName
|
||
+int baudRate
|
||
+int dataBits
|
||
+int stopBits
|
||
+string parity
|
||
+uint8 deviceAddress
|
||
+DeviceMode mode
|
||
+int pollIntervalMs
|
||
}
|
||
|
||
class SensorRequest {
|
||
+uint8 functionCode
|
||
+uint32 startAddress
|
||
+uint16 dataLength
|
||
}
|
||
|
||
class SensorSpec {
|
||
+string model
|
||
+string version
|
||
+int rows
|
||
+int cols
|
||
+float pitch
|
||
+float dotRadius
|
||
+float rangeMin
|
||
+float rangeMax
|
||
}
|
||
|
||
class SerialBackend {
|
||
+string portName
|
||
+int baudRate
|
||
+int pollIntervalMs
|
||
+int deviceAddress
|
||
+string mode
|
||
+int requestFunction
|
||
+int requestStartAddress
|
||
+int requestLength
|
||
+string protocol
|
||
+bool connected
|
||
+open()
|
||
+close()
|
||
+requestOnce()
|
||
+feedBytes(bytes)
|
||
+setTransport(transport)
|
||
}
|
||
class GLWidget {
|
||
+setRange(int, int)
|
||
+setColorLow(QColor)
|
||
+setColorMid(QColor)
|
||
+setColorHigh(QColor)
|
||
+dotClicked(index, row, col, value)
|
||
}
|
||
|
||
class SerialManager {
|
||
+registerProtocol(name, bundle)
|
||
+setActiveProtocol(name)
|
||
+activeBundle()
|
||
}
|
||
|
||
class ISerialTransport {
|
||
<<interface>>
|
||
+open(config, error)
|
||
+close()
|
||
+writeBytes(data, error)
|
||
}
|
||
|
||
class QtSerialTransport {
|
||
+open(config, error)
|
||
+close()
|
||
+writeBytes(data, error)
|
||
}
|
||
|
||
class ISerialFormat {
|
||
<<interface>>
|
||
+tryParse(buffer, packet, error)
|
||
}
|
||
|
||
class ISerialCodec {
|
||
<<interface>>
|
||
+buildRequest(config, request)
|
||
+buildGetVersionRequest(config)
|
||
+buildGetSpecRequest(config)
|
||
}
|
||
|
||
class ISerialDecoder {
|
||
<<interface>>
|
||
+decodeFrame(packet, frame)
|
||
+decodeSpec(packet, spec)
|
||
}
|
||
|
||
class PiezoresistiveAFormat
|
||
class PiezoresistiveACodec
|
||
class PiezoresistiveADecoder
|
||
|
||
class DataBackend {
|
||
+ingestFrame(frame)
|
||
+clear()
|
||
+exportJson(path)
|
||
+exportCsv(path)
|
||
+importJson(path)
|
||
+importCsv(path)
|
||
+startPlayback(intervalMs)
|
||
+stopPlayback()
|
||
+setLiveRenderCallback(cb)
|
||
+setPlaybackRenderCallback(cb)
|
||
}
|
||
|
||
class DataFrame {
|
||
+string pts
|
||
+uint8 functionCode
|
||
+float[] data
|
||
}
|
||
|
||
class PacketQueue {
|
||
+push(packet)
|
||
+pop()
|
||
+clear()
|
||
+stop()
|
||
}
|
||
|
||
class FrameQueue {
|
||
+push(frame)
|
||
+pop()
|
||
+clear()
|
||
+stop()
|
||
}
|
||
|
||
class SerialReadThread {
|
||
+enqueueBytes(bytes)
|
||
+setParseFunc(func)
|
||
+start()
|
||
+stop()
|
||
}
|
||
|
||
class SerialDecodeThread {
|
||
+setDecodeFunc(func)
|
||
+start()
|
||
+stop()
|
||
}
|
||
|
||
class SerialSendWorker {
|
||
+setTransport(transport)
|
||
+setBuildRequestFunc(func)
|
||
+openTransport(config)
|
||
+closeTransport()
|
||
+requestOnce()
|
||
}
|
||
|
||
AppBackend --> SerialBackend
|
||
AppBackend --> DataBackend
|
||
AppBackend ..> GLWidget : render config
|
||
SerialBackend --> SerialConfig
|
||
SerialBackend --> SensorRequest
|
||
SerialBackend --> SensorSpec
|
||
SerialBackend --> SerialManager
|
||
SerialManager --> ISerialFormat
|
||
SerialManager --> ISerialCodec
|
||
SerialManager --> ISerialDecoder
|
||
ISerialFormat <|.. PiezoresistiveAFormat
|
||
ISerialCodec <|.. PiezoresistiveACodec
|
||
ISerialDecoder <|.. PiezoresistiveADecoder
|
||
ISerialTransport <|.. QtSerialTransport
|
||
SerialBackend --> DataFrame
|
||
DataBackend --> DataFrame
|
||
SerialBackend --> PacketQueue
|
||
SerialBackend --> FrameQueue
|
||
SerialBackend --> SerialReadThread
|
||
SerialBackend --> SerialDecodeThread
|
||
SerialBackend --> SerialSendWorker
|
||
SerialSendWorker --> ISerialTransport
|
||
SerialReadThread --> PacketQueue
|
||
SerialDecodeThread --> PacketQueue
|
||
SerialDecodeThread --> FrameQueue
|
||
```
|
||
|
||
说明:线程与队列已实现,队列溢出策略通过 TODO 注释预留后续扩展。
|
||
|
||
## 数据流/线程流程 (Mermaid)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
UI[QML 按钮/配置] -->|open/close| SB[SerialBackend]
|
||
SB -->|openTransport| SW[SerialSendWorker]
|
||
SW -->|open| TP[QtSerialTransport]
|
||
SW -->|slave 模式轮询| REQ[buildRequest]
|
||
REQ -->|writeBytes| TP
|
||
TP -->|bytesReceived| RT[SerialReadThread]
|
||
RT -->|tryParse| PKT[PacketQueue]
|
||
PKT --> DT[SerialDecodeThread]
|
||
DT -->|decodeFrame| FR[FrameQueue]
|
||
FR --> SB
|
||
SB -->|drainFrames| DB[DataBackend]
|
||
DB -->|liveCallback| GL[GLWidget]
|
||
DB -->|TODO| RP[RightPanel 可视化]
|
||
```
|
||
|
||
## 时序/函数调用 (Mermaid)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant UI as QML
|
||
participant SB as SerialBackend
|
||
participant SW as SerialSendWorker
|
||
participant TP as ISerialTransport
|
||
participant RT as SerialReadThread
|
||
participant DT as SerialDecodeThread
|
||
participant DB as DataBackend
|
||
participant GL as GLWidget
|
||
|
||
UI->>SB: open()
|
||
SB->>SW: openTransport(config)
|
||
SW->>TP: open(config)
|
||
Note over SW: slave 模式启动轮询定时器
|
||
SW->>SW: buildRequest()
|
||
SW->>TP: writeBytes(request)
|
||
TP-->>SW: bytesReceived(data)
|
||
SW-->>RT: enqueueBytes(data)
|
||
RT->>RT: tryParse(buffer)
|
||
RT-->>DT: PacketQueue.push(packet)
|
||
DT->>DT: decodeFrame(packet)
|
||
DT-->>SB: frameAvailable()
|
||
SB->>DB: ingestFrame(frame)
|
||
DB-->>GL: liveRenderCallback(frame)
|
||
```
|
||
|
||
## 配置流程 (Mermaid)
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
UI[QML 设置参数] -->|setPortName/ setBaudRate/ setDeviceAddress/ setMode/ setPollIntervalMs| SB[SerialBackend]
|
||
UI -->|setRequestFunction/ setRequestStartAddress/ setRequestLength| SB
|
||
UI -->|setProtocol| SB
|
||
SB -->|syncSendConfig_| SW[SerialSendWorker.setConfig]
|
||
SB -->|syncSendRequest_| SW2[SerialSendWorker.setRequest]
|
||
SB -->|updateProtocolBindings_| RT[SerialReadThread.setParseFunc]
|
||
SB -->|updateProtocolBindings_| DT[SerialDecodeThread.setDecodeFunc]
|
||
SB -->|updateProtocolBindings_| SW3[SerialSendWorker.setBuildRequestFunc]
|
||
```
|
||
|
||
## 渲染/颜色映射流程 (Mermaid)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
UI[LeftPanel 颜色映射] -->|rangeMin/rangeMax<br/>colorLow/Mid/High| AB[AppBackend]
|
||
AB -->|rangeChanged/colorChanged| GL[GLWidget]
|
||
GL -->|uMinV/uMaxV/uColorLow/Mid/High| SH[dots.frag]
|
||
```
|
||
|
||
## 配置接口与步骤说明
|
||
|
||
- 设置协议:
|
||
- `SerialBackend::setProtocol(name)`:切换协议后调用 `updateProtocolBindings_()`,更新 `ParseFunc` / `DecodeFunc` / `BuildRequestFunc`。
|
||
- 设置串口配置(config):
|
||
- `SerialBackend::setPortName(name)`
|
||
- `SerialBackend::setBaudRate(rate)`
|
||
- `SerialBackend::setDeviceAddress(addr)`(0-255)
|
||
- `SerialBackend::setMode("master"/"slave")`
|
||
- `SerialBackend::setPollIntervalMs(intervalMs)`(从站模式轮询周期)
|
||
- 上述接口内部统一调用 `syncSendConfig_()`,将 `SerialConfig` 下发到 `SerialSendWorker::setConfig`。
|
||
- 设置请求参数(request):
|
||
- `SerialBackend::setRequestFunction(func)`
|
||
- `SerialBackend::setRequestStartAddress(addr)`
|
||
- `SerialBackend::setRequestLength(len)`
|
||
- 上述接口内部调用 `syncSendRequest_()`,将 `SensorRequest` 下发到 `SerialSendWorker::setRequest`。
|
||
- 设置解码/解析器:
|
||
- `SerialManager::registerProtocol(name, {codec, decoder, format})`
|
||
- `SerialBackend::setProtocol(name)` 触发 `updateProtocolBindings_()`:
|
||
- `SerialReadThread::setParseFunc(format->tryParse)`
|
||
- `SerialDecodeThread::setDecodeFunc(decoder->decodeFrame)`
|
||
- `SerialSendWorker::setBuildRequestFunc(codec->buildRequest)`
|
||
- 打开串口:
|
||
- `SerialBackend::open()` -> `SerialSendWorker::openTransport(config)`,成功后在从站模式启动轮询发送。
|
||
- 渲染/颜色映射配置:
|
||
- QML 绑定 `AppBackend::rangeMin/rangeMax` 与 `colorLow/Mid/High`(`LeftPanel` 中的颜色映射面板)。
|
||
- `setRangeMin/Max` 发出 `rangeChanged(min, max)`,由 `GLWidget::setRange` 同步到 `uMinV/uMaxV`。
|
||
- `setColorLow/Mid/High` 发出 `color*Changed`,由 `GLWidget::setColor*` 同步到 `uColorLow/Mid/High`。
|
||
- `dots.frag` 归一化公式:`value01 = clamp((v - min) / (max - min))`,并用 low->mid->high 线性插值。
|
||
|
||
## 分层设计概述
|
||
|
||
- AppBackend:统一后端入口,驱动串口层与数据层,供 QML 直接绑定。
|
||
- 串口采集层:`Transport + Format + Codec + Decoder + Manager` 分层,独立于业务逻辑。
|
||
- 串口线程化:读取/解码/发送三线程 + Packet/Frame 队列,降低 UI 卡顿风险。
|
||
- 数据驱动层:负责帧缓存、数据导入导出与回放,提供渲染回调。
|
||
- 渲染配置层:`AppBackend` 提供范围/颜色参数,`GLWidget` 将其转为 shader uniform 进行颜色映射。
|
||
- UI 层:`NavBar + LeftPanel + OpenGL View + RightPanel` 的 1+3 布局。
|
||
|
||
## 类接口与成员说明(C++)
|
||
|
||
### AppBackend (`src/backend.h`)
|
||
- 作用:统一后端入口,串联 `SerialBackend` 与 `DataBackend`。
|
||
- 属性/接口:
|
||
- `lightMode` / `language` / `connected`:UI 基础状态。
|
||
- `serial()` / `data()`:暴露子系统实例给 QML。
|
||
- `setLightMode(bool)` / `setLanguage(string)`。
|
||
- `rangeMin` / `rangeMax`:颜色映射的数值范围。
|
||
- `colorLow` / `colorMid` / `colorHigh`:颜色映射的三个基准颜色。
|
||
- `setRangeMin(int)` / `setRangeMax(int)` / `setColorLow(QColor)` / `setColorMid(QColor)` / `setColorHigh(QColor)`。
|
||
- 成员变量:
|
||
- `m_serial`:串口采集层对象。
|
||
- `m_data`:数据驱动层对象。
|
||
- `m_lightMode` / `m_language`:全局 UI 状态。
|
||
- `m_rangeMin` / `m_rangeMax` / `m_colorLow` / `m_colorMid` / `m_colorHigh`:颜色映射参数。
|
||
- 备注:串口连接成功后会清空历史数据缓存,避免旧数据残留。
|
||
- `rangeChanged(min, max)` 用于驱动 `GLWidget::setRange`,颜色变更通过 `color*Changed` 同步。
|
||
|
||
### SerialBackend (`src/serial/serial_backend.h`)
|
||
- 作用:串口采集层的统一控制器,负责协议选择、三线程调度与数据分发。
|
||
- 属性/接口:
|
||
- `portName` / `baudRate` / `deviceAddress` / `mode` / `pollIntervalMs`:串口与模式配置。
|
||
- `requestFunction` / `requestStartAddress` / `requestLength`:请求参数。
|
||
- `protocol` / `sensorModel` / `sensorGrid`:协议与传感器规格占位。
|
||
- `open()` / `close()` / `requestOnce()` / `feedBytes(bytes)`。
|
||
- `setTransport(transport)`:注入真实串口传输层。
|
||
- `requestBuilt(bytes)`:输出原始请求帧,便于调试。
|
||
- 成员变量:
|
||
- `m_config`:串口参数配置。
|
||
- `m_request`:请求参数。
|
||
- `m_spec`:传感器规格占位。
|
||
- `m_manager`:协议注册与切换。
|
||
- `m_packetQueue` / `m_frameQueue`:包/帧队列。
|
||
- `m_readThread` / `m_decodeThread`:读取与解码线程。
|
||
- `m_sendWorker` / `m_sendThread`:发送线程与 worker。
|
||
- `m_frameCallback`:解码后数据回调。
|
||
- 备注:通过 `ParseFunc` / `DecodeFunc` / `BuildRequestFunc` 绑定协议实现,模拟 “find_decodec 后回调赋值”。
|
||
|
||
### PacketQueue / FrameQueue (`src/serial/serial_queue.h`)
|
||
- 作用:线程安全的阻塞队列,用于 Packet/Frame 的跨线程传递。
|
||
- 接口:
|
||
- `push(item)` / `pop(item)` / `tryPop(item)` / `clear()` / `stop()` / `reset()`
|
||
- `setMaxSize(size)`:配置队列容量。
|
||
- 备注:队列溢出策略已通过 TODO 注释预留,后续可扩展为丢弃最新/阻塞等待。
|
||
|
||
### SerialReadThread (`src/serial/serial_threads.h`)
|
||
- 作用:读取线程,接收原始字节流并根据 `ParseFunc` 解析为 packet。
|
||
- 接口:
|
||
- `enqueueBytes(bytes)`:注入串口字节流。
|
||
- `setParseFunc(func)`:绑定协议解析函数。
|
||
- `start()` / `stop()`:线程控制。
|
||
|
||
### SerialDecodeThread (`src/serial/serial_threads.h`)
|
||
- 作用:解码线程,从 `PacketQueue` 解码 packet 并写入 `FrameQueue`。
|
||
- 接口:
|
||
- `setDecodeFunc(func)`:绑定协议解码函数。
|
||
- `start()` / `stop()`:线程控制。
|
||
|
||
### SerialSendWorker (`src/serial/serial_threads.h`)
|
||
- 作用:发送线程 worker,负责请求编码与发送,并在从站模式下轮询。
|
||
- 接口:
|
||
- `setTransport(transport)`:注入传输层实例。
|
||
- `setBuildRequestFunc(func)`:绑定请求编码函数。
|
||
- `openTransport(config)` / `closeTransport()`:串口打开/关闭。
|
||
- `requestOnce()`:触发一次请求发送。
|
||
|
||
### SerialManager (`src/serial/serial_manager.h`)
|
||
- 作用:协议包管理器,注册 `codec/decoder/format` 组合。
|
||
- 接口:
|
||
- `registerProtocol(name, bundle)`:注册协议。
|
||
- `setActiveProtocol(name)`:切换协议。
|
||
- `activeBundle()`:获取当前协议绑定。
|
||
- 成员变量:
|
||
- `m_protocols`:协议字典。
|
||
- `m_activeName`:当前协议名。
|
||
|
||
### ISerialTransport (`src/serial/serial_transport.h`)
|
||
- 作用:串口传输抽象层,屏蔽不同平台差异。
|
||
- 接口:
|
||
- `open(config, error)` / `close()` / `writeBytes(data, error)`。
|
||
- 备注:实际接收数据通过 `bytesReceived` 信号上报。
|
||
- 实现:
|
||
- `QtSerialTransport`:基于 `QSerialPort` 的默认传输实现。
|
||
- TODO:待实现内容(在传输层支持软/硬件流控配置)
|
||
|
||
### ISerialFormat / ISerialCodec / ISerialDecoder
|
||
- 作用:协议拆分层,类比 FFmpeg 的 `format/codec/decoder`。
|
||
- ISerialFormat 接口:
|
||
- `tryParse(buffer, packet, error)`:从字节流中提取完整包。
|
||
- ISerialCodec 接口:
|
||
- `buildRequest(config, request)`:生成请求帧。
|
||
- `buildGetVersionRequest(config)`:// TODO:待实现内容(构建获取版本号的请求帧)
|
||
- `buildGetSpecRequest(config)`:// TODO:待实现内容(构建获取传感器规格的请求帧)
|
||
- ISerialDecoder 接口:
|
||
- `decodeFrame(packet, frame)`:解码回复帧。
|
||
- `decodeSpec(packet, spec)`:// TODO:待实现内容(解析规格回复帧并填充 SensorSpec)
|
||
|
||
### Piezoresistive A 协议 (`src/serial/piezoresistive_a_protocol.*`)
|
||
- `PiezoresistiveAFormat`:包解析与 CRC-8/ITU 校验。
|
||
- `PiezoresistiveACodec`:构建请求帧。
|
||
- `PiezoresistiveADecoder`:解析回复帧为 `DataFrame`。
|
||
- 备注:数据以小端 `uint16` 解析为 float,若协议变更可在此调整。
|
||
|
||
### DataBackend (`src/data_backend.h`)
|
||
- 作用:数据驱动层,负责帧缓存、导入导出与回放。
|
||
- 接口:
|
||
- `ingestFrame(frame)`:实时采集数据入口。
|
||
- `clear()`:清空缓存。
|
||
- `exportJson(path)` / `exportCsv(path)`。
|
||
- `importJson(path)` / `importCsv(path)`。
|
||
- `startPlayback(intervalMs)` / `stopPlayback()`。
|
||
- `setLiveRenderCallback(cb)` / `setPlaybackRenderCallback(cb)`:渲染回调占位。
|
||
- 成员变量:
|
||
- `m_frames`:帧数据容器。
|
||
- `m_playbackTimer` / `m_playbackIndex`:回放控制。
|
||
|
||
### GLWidget (`src/glwidget.h`)
|
||
- 作用:OpenGL 渲染窗口,显示传感器点阵与背景。
|
||
- 接口:
|
||
- `setRange(int minV, int maxV)`:设置 `uMinV/uMaxV`。
|
||
- `setColorLow(QColor)` / `setColorMid(QColor)` / `setColorHigh(QColor)`:设置 `uColorLow/uColorMid/uColorHigh`。
|
||
- 信号:
|
||
- `dotClicked(index, row, col, value)`:鼠标点击某个点时发出索引与数据值。
|
||
- 备注:
|
||
- 颜色映射在 `dots.frag` 内完成,低/中/高三段线性插值。
|
||
- 拾取使用屏幕投影 + 半径阈值,便于 RightPanel 订阅点击事件做曲线展示。
|
||
|
||
### DataFrame (`src/data_frame.h`)
|
||
- 字段:
|
||
- `pts`:`yyyyMMddhhmmsszzz` 时间戳。
|
||
- `functionCode`:功能码。
|
||
- `data`:传感器数据。
|
||
|
||
### SerialConfig / SensorRequest / SensorSpec (`src/serial/serial_types.h`)
|
||
- `SerialConfig`:串口基础参数配置。
|
||
- `SensorRequest`:请求参数(功能码、起始地址、读取长度)。
|
||
- `SensorSpec`:传感器规格占位(型号/网格/量程等)。
|
||
|
||
## 协议结构说明(压阻 A 型)
|
||
|
||
- Request 起始符:`0x55AA`(小端 -> `AA 55`)。
|
||
- Reply 起始符:`0x55AA`(小端 -> `AA 55`)。
|
||
- 数据长度:从 `data[4]` 到 payload 末尾(不含 CRC)。
|
||
- CRC:CRC-8/ITU(多项式 0x07,初始值 0x00)。
|
||
|
||
## QML 层级与组件职责
|
||
|
||
### 总体布局(`qml/content/App.qml`)
|
||
- 顶部 `NavBar`:标题、连接状态、明暗切换、语言选择。
|
||
- 中部三栏:
|
||
- 左侧 `LeftPanel`:串口连接、采样参数、规格与显示控制。
|
||
- 中间 OpenGL 视图:由 C++ `GLWidget` 挂载显示 3D 传感器数据,并提供点点击信号。
|
||
- 右侧 `RightPanel`:折线趋势、指标卡片、会话信息。
|
||
|
||
### NavBar(`qml/content/NavBar.qml`)
|
||
- Title:软件名称显示。
|
||
- 连接指示:绿/红状态灯 + 文本。
|
||
- `Switch`:Light/Dark 切换。
|
||
- `ComboBox`:语言选择。
|
||
|
||
### LeftPanel(`qml/content/LeftPanel.qml`)
|
||
- 连接设置:
|
||
- COM 端口、波特率。
|
||
- 模式选择(主站/从站)。
|
||
- 设备地址输入(十六进制 `0x01` 形式)。
|
||
- 采样周期(从站模式可用)。
|
||
- 采样参数:功能码、起始地址、读取长度。
|
||
- 传感器规格:协议名、型号、网格规格占位。
|
||
- 颜色映射:
|
||
- 数值范围(min/max)。
|
||
- 低/中/高三色选择(`ColorDialog`)。
|
||
- 显示控制:显示网络/坐标轴、回放与导出入口。
|
||
|
||
### RightPanel(`qml/content/RightPanel.qml`)
|
||
- Live Trend:折线趋势图示例。
|
||
- Metrics:峰值、RMS、均值、Delta 等指标卡片。
|
||
- Session:帧数、回放状态。
|
||
- LiveTrendCard:封装 `SparklinePlot`(C++ QQuickItem)用于趋势绘制,数据接入留有 TODO。
|
||
|
||
## 预留扩展(实现建议)
|
||
|
||
- 串口线程化已落地:
|
||
- `SerialReadThread` 读取字节流 -> `PacketQueue`。
|
||
- `SerialDecodeThread` 解包/解码 -> `FrameQueue`。
|
||
- `SerialSendWorker` 从站模式下定时发送请求。
|
||
- 队列溢出策略:`SerialQueue` 中已预留 TODO 注释,可扩展为阻塞等待或丢弃最新。
|
||
- 回调扩展:
|
||
- `DataBackend` 的渲染回调用于自定义 OpenGL/曲线刷新逻辑。
|
||
- 可视化接入:
|
||
- `main.cpp` 与 `qml/content/RightPanel.qml` 已标注 // TODO:待实现内容(将实时帧推送到右侧曲线/指标)。
|
||
- 协议扩展:
|
||
- `buildGetVersionRequest` / `buildGetSpecRequest` / `decodeSpec` 需实现,已保留 // TODO:待实现内容。
|
||
|
||
|
||
## 数据导出进度
|
||
|
||
- 已完成
|
||
- `DataBackend::exportJson(path)` / `exportCsv(path)` 已实现导出。
|
||
- `DataBackend::importJson(path)` / `importCsv(path)` 已实现导入。
|
||
- `qml/content/SaveAsExportDialog.qml` 提供路径、文件名、格式、方式选择,并通过 `saveTo(...)` 抛出导出参数。
|
||
- 导出对话框以独立 `Window` 方式呈现(ApplicationModal),避免在 `QQuickWidget` 内被裁剪。
|
||
- 待开发
|
||
- 将 `saveTo` 与 `DataBackend` 导出接口打通,并补充失败提示。
|
||
- 覆盖/追加/压缩(zip)策略与文件存在检测流程。
|
||
- `xlsx` 导出实现与导出图标资源补齐(TODO)。
|
||
|
||
## TODO 汇总
|
||
|
||
- 代码/界面
|
||
- `main.cpp:106` 将 frame 数据分发给右侧曲线/指标的 QML 接口。
|
||
- `qml/content/RightPanel.qml:40` 用 DataBackend 输出的帧更新折线图/指标。
|
||
- `src/serial/serial_queue.h:28` 指定队列溢出策略(丢弃最新/丢弃最旧/阻塞等待)。
|
||
- `src/serial/serial_qt_transport.cpp:72` 根据 SerialConfig 扩展软件/硬件流控配置。
|
||
- `src/serial/serial_codec.h:17` 构建获取版本号的请求帧。
|
||
- `src/serial/serial_codec.h:19` 构建获取传感器规格的请求帧。
|
||
- `src/serial/serial_decoder.h:18` 解析规格回复帧并填充 SensorSpec。
|
||
- `src/serial/piezoresistive_a_protocol.cpp:126` 压阻 A 型版本号查询请求帧。
|
||
- `src/serial/piezoresistive_a_protocol.cpp:132` 压阻 A 型规格查询请求帧。
|
||
- `src/serial/piezoresistive_a_protocol.cpp:222` 解析压阻 A 型规格回复并写入 SensorSpec。
|
||
- 文档/流程图标注
|
||
- `docs/ARCHITECTURE.md:187` 队列溢出策略 TODO 预留说明。
|
||
- `docs/ARCHITECTURE.md:205` 数据流图 RightPanel 可视化 TODO。
|
||
- `docs/ARCHITECTURE.md:323` 队列溢出策略 TODO 备注。
|
||
- `docs/ARCHITECTURE.md:363` 传输层软/硬件流控配置 TODO。
|
||
- `docs/ARCHITECTURE.md:371` buildGetVersionRequest TODO。
|
||
- `docs/ARCHITECTURE.md:372` buildGetSpecRequest TODO。
|
||
- `docs/ARCHITECTURE.md:375` decodeSpec TODO。
|
||
- `docs/ARCHITECTURE.md:449` LiveTrendCard 数据接入 TODO。
|
||
- `docs/ARCHITECTURE.md:457` SerialQueue 溢出策略 TODO。
|
||
- `docs/ARCHITECTURE.md:461` main.cpp/RightPanel.qml 实时帧推送 TODO。
|
||
- `docs/ARCHITECTURE.md:463` buildGetVersion/buildGetSpec/decodeSpec TODO。
|
||
- `docs/ARCHITECTURE.md:520` 更新记录提及可视化 TODO。
|
||
- `docs/ARCHITECTURE.md:522` 更新记录提及队列溢出 TODO。
|
||
- 测试/第三方
|
||
- `test/onlygl/stb_image.h:1276` move stbi__convert_format to here.
|
||
- `test/onlygl/stb_image.h:1302` move stbi__convert_format16 to here.
|
||
- `test/onlygl/stb_image.h:1303` special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision.
|
||
- `test/onlygl/stb_image.h:5898` tga_x_origin @TODO。
|
||
- `test/onlygl/stb_image.h:5899` tga_y_origin @TODO。
|
||
- 其他/说明
|
||
- `Prompt.md:60` 可视化部分流出 TODO。
|
||
- `Prompt.md:72` 接口预留位置标注 TODO。
|
||
- `Prompt.md:73` 文档和 TODO 说明。
|
||
- `serial/doc/Doxyfile:603` Doxygen TODO 列表说明。
|
||
- `serial/doc/Doxyfile:607` GENERATE_TODOLIST 开关。
|
||
|
||
## 更新记录
|
||
|
||
- 2026-01-11:新增 `QtSerialTransport`(`QSerialPort` 传输实现)并设为默认传输;补齐点选拾取逻辑;新增数据流/时序图并补充可视化 TODO 说明。
|
||
- 2026-01-12:`LeftPanel` 新增颜色映射参数;`AppBackend`/`GLWidget` 增加颜色与范围接口,shader 使用三色渐变映射数据值。
|
||
- 2026-01-11:补充串口配置流程图与配置接口说明(协议/参数/解码器绑定/打开流程)。
|
||
- 2026-01-05:新增串口三线程流水线(读/解码/发送)与 Packet/Frame 队列,更新协议起始符说明,补充队列溢出 TODO 与线程组件文档。
|
||
- 2026-01-05:CollapsiblePanel 组件改为跟随 `backend.lightMode` 切换暗色主题配色。
|
||
- 2026-01-05:`QSplitter` 句柄配色跟随明暗模式并缩窄,消除 darkmode 下的白色缝隙。
|
||
- 2026-01-05:`QQuickWidget` clearColor 跟随明暗模式,避免面板圆角处漏出白底。
|
||
- 2026-01-05:`QQuickWidget` 在 `setSource` 后重设 `backend` 上下文属性,修复 QML 访问空指针报错。
|
||
- 2026-01-05:`QQuickWidget` 改为通过 `engine()->rootContext()` 注入 `backend`,避免上下文被重建导致为空。
|
||
- 2026-01-05:改为每个 `QQuickWidget` 引擎注入 `Backend` 上下文属性,避免多引擎使用单例导致的报错。
|
||
- 2026-01-05:调整 `SerialSendWorker` 生命周期清理方式,避免跨线程 moveToThread 警告。
|
||
- 2026-01-06:多个 `QQuickWidget` 共享同一个 `QQmlEngine`,统一注入 `Backend/backend` 上下文属性以稳定访问。
|
||
- 2026-01-06:统一 QML 使用 `backend` 上下文属性名称,避免大写标识被当成类型解析导致取值为空。
|
||
- 2026-01-06:为每个 `QQuickWidget` 的 `rootContext()` 重复绑定 `backend`,避免上下文被重建时丢失。
|
||
- 2026-01-06:`QQuickWidget` 改用 `QQmlComponent + QQmlContext` 创建根对象并 `setContent`,确保 `backend` 上下文稳定注入。
|
||
- 2026-01-07:`GLWidget` 增加点阵点击拾取信号 `dotClicked`,文档补充 OpenGL 交互说明。
|