Files
softbus_daemon/docs/数据流转.md
flower_linux 4f2ada08c8 modbus rtu 1.2
2026-04-14 15:39:04 +08:00

5.5 KiB
Raw Blame History

数据流转

1. 概念约定

  • 物理设备:真实硬件端口(当前主要是串口),由 SerialQtDriver 直接读写。
  • 设备实例SerialDevice,负责单设备生命周期、驱动回调、上下行数据接入。
  • 原始总线消息RawBusMessage,包含 endpointprotocolHintpayloadtraceIddirection 等基础字段。
  • 流水线上下文PipelineContext,继承 RawBusMessage,增加 frameKindframeSeq 等管道字段。
  • 业务消息:经过协议解析和映射后得到 DOMMessage(统一语义数据)。

2. 上行主链路(串口 -> 消息总线)

2.1 设备初始化

SerialDeviceManager 完成以下动作:

  1. 根据配置创建并配置 SerialQtDriver(波特率、校验、停止位、流控)。
  2. 创建 SerialDevice 并注入 DeviceInfo(含协议提示,如 modbus_rtu)。
  3. 通过 bindIngress(...) 绑定:
    • IIngressPort(当前实现为 DriverIngressAdapter
    • MemoryPool(用于 payload 内存块分配)
  4. 调用 start() 打开端口并注册读回调/错误回调。

2.2 读回调进入 ingress

当串口收到字节流时,SerialDevice::onRead(...) 执行:

  1. MemoryPool 分配内存块并拷贝原始字节。
  2. 构造 RawBusMessage
    • direction = Upstream
    • endpoint = 串口名
    • protocolHint = DeviceInfo.protocol
    • payload/payloadSize = 原始字节数据
    • traceId = serial:<endpoint>:<timestamp>
  3. 调用 m_ingress->push(std::move(ctx)) 进入统一入口。
  4. 若内存池不足或 ingress 队列满,通过 reportError(...) 记录错误。

2.3 ingress 适配为 PipelineContext

DriverIngressAdapter::push(...) 负责轻量转换:

  1. 新建 PipelineContext
  2. pipelineCtx.raw() = std::move(ctx) 将原始消息搬运进管道上下文。
  3. 调用 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(...) 的选择策略:

  1. 优先根据 protocolHint 从插件管理器选择协议分帧插件。
  2. endpoint + pluginId 复用 framer session保持协议状态机连续性
  3. 若没有可用插件,降级到 PassthroughFramer(透传/整包策略)。

输出:frameKind = CompleteFrame 的帧批次。

3.3 Stage 2/3/4解析 -> 过滤 -> 校验

runStages234(...) 核心流程:

  1. Stage2 Parser
    • 选择 IProtocolPlugin,复用 parser session。
    • parse(rawCtx, envelope) 产出协议封装 ProtocolEnvelope
    • 选择 mapper 插件并映射为 std::vector<DOMMessage>
  2. Stage3 Filter
    • DOMMessage 执行过滤规则(ProtocolParseFilter::process)。
  3. Stage4 Validator
    • 最低校验当前为 messageId 非空。
  4. Transform/Enrich
    • 应用动态规则scale/offset/unit
    • 写入 trace补充富化字段。

说明:当前 runStages234 只返回布尔结果,EnrichedMessage 由内部生成,后续可接持久化/发布环节。

3.4 出口与有序保证

  • 未开启有序出口:解析成功后直接进入 m_egressQ
  • 开启 orderedEgress
    • 解析线程先写入 m_mergeQ
    • mergerLoopendpoint + frameSeq 重排。
    • 使用 nextExpected 保证同端点有序输出。
    • 超过 maxReorderDepth 的乱序缓存上限会丢弃并计数。

4. 错误与背压点

主要失败点及表现:

  1. 内存池分配失败SerialDevice::onRead 直接 reportError(memory pool exhausted)
  2. 入口队列满enqueueIngress 返回 false计入 drop。
  3. 分帧/解析插件缺失或失败:对应帧在阶段中被丢弃。
  4. 过滤/校验失败:消息跳过,不进入下游。
  5. 重排深度超限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

7. 维护建议

  1. traceId 建议在全链路透传到最终发布侧,便于定位帧级问题。
  2. 为 Stage2/Stage3/Stage4 增加细粒度指标成功率、耗时、drop 原因)。
  3. 文档后续可新增“协议插件开发约定”章节framer/parser/mapper 三类插件接口对照)。