5.5 KiB
5.5 KiB
数据流转
1. 概念约定
- 物理设备:真实硬件端口(当前主要是串口),由
SerialQtDriver直接读写。 - 设备实例:
SerialDevice,负责单设备生命周期、驱动回调、上下行数据接入。 - 原始总线消息:
RawBusMessage,包含endpoint、protocolHint、payload、traceId、direction等基础字段。 - 流水线上下文:
PipelineContext,继承RawBusMessage,增加frameKind、frameSeq等管道字段。 - 业务消息:经过协议解析和映射后得到
DOMMessage(统一语义数据)。
2. 上行主链路(串口 -> 消息总线)
2.1 设备初始化
SerialDeviceManager 完成以下动作:
- 根据配置创建并配置
SerialQtDriver(波特率、校验、停止位、流控)。 - 创建
SerialDevice并注入DeviceInfo(含协议提示,如modbus_rtu)。 - 通过
bindIngress(...)绑定:IIngressPort(当前实现为DriverIngressAdapter)MemoryPool(用于 payload 内存块分配)
- 调用
start()打开端口并注册读回调/错误回调。
2.2 读回调进入 ingress
当串口收到字节流时,SerialDevice::onRead(...) 执行:
- 从
MemoryPool分配内存块并拷贝原始字节。 - 构造
RawBusMessage:direction = Upstreamendpoint = 串口名protocolHint = DeviceInfo.protocolpayload/payloadSize = 原始字节数据traceId = serial:<endpoint>:<timestamp>
- 调用
m_ingress->push(std::move(ctx))进入统一入口。 - 若内存池不足或 ingress 队列满,通过
reportError(...)记录错误。
2.3 ingress 适配为 PipelineContext
DriverIngressAdapter::push(...) 负责轻量转换:
- 新建
PipelineContext。 pipelineCtx.raw() = std::move(ctx)将原始消息搬运进管道上下文。- 调用
PipelineEngine::enqueueIngress(...)入总线处理队列。
3. PipelineEngine 内部流转
3.1 入口分流
enqueueIngress(...) 分两种模式:
- 并行模式(parallelPipeline=true)
- 按
endpoint创建/复用独立EndpointFramingState(每端点一个分帧线程 + chunk 队列)。 - chunk 先进入端点队列,端点线程负责分帧并赋值
frameSeq。 - 完整帧进入
m_framedQ,由解析线程池处理。
- 按
- 单线程模式(parallelPipeline=false)
- 直接进入
m_ingressQ,由单 worker 串行处理。
- 直接进入
3.2 Stage 1:分帧(Framer)
dispatchFramer(...) 的选择策略:
- 优先根据
protocolHint从插件管理器选择协议分帧插件。 - 按
endpoint + pluginId复用 framer session(保持协议状态机连续性)。 - 若没有可用插件,降级到
PassthroughFramer(透传/整包策略)。
输出:frameKind = CompleteFrame 的帧批次。
3.3 Stage 2/3/4:解析 -> 过滤 -> 校验
runStages234(...) 核心流程:
- Stage2 Parser
- 选择
IProtocolPlugin,复用 parser session。 parse(rawCtx, envelope)产出协议封装ProtocolEnvelope。- 选择 mapper 插件并映射为
std::vector<DOMMessage>。
- 选择
- Stage3 Filter
- 对
DOMMessage执行过滤规则(ProtocolParseFilter::process)。
- 对
- Stage4 Validator
- 最低校验当前为
messageId非空。
- 最低校验当前为
- Transform/Enrich
- 应用动态规则(scale/offset/unit)。
- 写入 trace,补充富化字段。
说明:当前 runStages234 只返回布尔结果,EnrichedMessage 由内部生成,后续可接持久化/发布环节。
3.4 出口与有序保证
- 未开启有序出口:解析成功后直接进入
m_egressQ。 - 开启
orderedEgress:- 解析线程先写入
m_mergeQ。 mergerLoop按endpoint + frameSeq重排。- 使用
nextExpected保证同端点有序输出。 - 超过
maxReorderDepth的乱序缓存上限会丢弃并计数。
- 解析线程先写入
4. 错误与背压点
主要失败点及表现:
- 内存池分配失败:
SerialDevice::onRead直接reportError(memory pool exhausted)。 - 入口队列满:
enqueueIngress返回 false,计入 drop。 - 分帧/解析插件缺失或失败:对应帧在阶段中被丢弃。
- 过滤/校验失败:消息跳过,不进入下游。
- 重排深度超限:
mergeDrop增加并告警。
5. 当前链路时序(上行)
SerialQtDriver(read callback)
-> SerialDevice::onRead
-> MemoryPool::allocate + RawBusMessage
-> IIngressPort::push (DriverIngressAdapter)
-> PipelineEngine::enqueueIngress
-> [Framer] dispatchFramer/feedChunk
-> [Stage2] parse + map -> DOMMessage
-> [Stage3] filter
-> [Stage4] validate
-> transform/enrich
-> egressQ (有序模式下先 merge 再 egress)
6. 下行(现状)
RawBusMessage.direction已支持Downstream语义。SerialDevice已提供writePayload(...)写入能力。- 当前代码中 egress 路由到物理设备的绑定仍预留(
SerialDeviceManager里相关逻辑已注释),后续可补齐:- egress 消息 ->
EgressRouter-> endpoint 设备 ->writePayload。
- egress 消息 ->
7. 维护建议
traceId建议在全链路透传到最终发布侧,便于定位帧级问题。- 为 Stage2/Stage3/Stage4 增加细粒度指标(成功率、耗时、drop 原因)。
- 文档后续可新增“协议插件开发约定”章节(framer/parser/mapper 三类插件接口对照)。