FAAP/RTD 测试数据传输系统

一、启动顺序与命令

python_grpc 目录下,按以下顺序在 4 个终端中启动:

cd "\PCSW\python_grpc"
顺序 终端 命令 角色
1 终端 1 python -m strict_pipeline.rtd_mbs_server RTD MBS 服务端(数据终点)
2 终端 2 python -m strict_pipeline.faap_proxy_server FaapProxy 中间代理
3 终端 3 python -m strict_pipeline.pc_client PC 客户端(桥接+展示)
4 终端 4 python -m strict_pipeline.dut_client DUT 模拟客户端(数据源)

顺序原因:每个组件启动后会等待上游/下游连接。MBS 最先启动因为 PC 客户端一启动就要向它发 Header;FaapProxy 在 PC 和 DUT 之前启动因为两者都要连它;PC 在 DUT 之前启动因为 PC 要先建立 Server Streaming 流,DUT 发的数据才有消费者。


二、完整工作流程(结合终端输出逐步解读)

以下按时间顺序,将 4 个终端的输出整合为一条时间线,阐述每一步发生了什么。


阶段 0:服务启动(终端 1 + 终端 2)

终端 1 — RTD MBS 服务端启动

2026-06-11 10:28:35 [INFO] SQLite database initialized: rtd_mbs_sessions.db
2026-06-11 10:28:35 [INFO] RTD Cloud Forwarder thread started
============================================================
  RTD MBS Server (Process 4)
  Aligned with: Ericsson.Raptor2.RTDMessageBufferService
  Proto: TestResultMessageService (service_db_result.proto)
  Port: 50053
  SQLite: rtd_mbs_sessions.db
  Waiting for PC client data...
============================================================

发生了什么

  1. 初始化 SQLite 数据库(rtd_mbs_sessions.db),创建 rtd_sessionsrtd_messages 两张表
  2. 启动后台云端转发线程(模拟将数据发往 RTD 云端)
  3. 在端口 50053 开始监听,等待 PC 客户端的 gRPC 调用

终端 2 — FaapProxy 服务端启动

============================================================
  FaapProxy Server (Process 2) - Async gRPC
  Aligned with: Ericsson.Raptor2.MS.FaapProxy
  Services:
    - DutTestDataService (DUT → FaapProxy)
    - CtrlService (DUT → FaapProxy)
    - FaapProxyService (FaapProxy → PC, Server Streaming)
  Port: 50052
  Waiting for connections...
============================================================

发生了什么

  1. 在端口 50052 注册了 3 个 gRPC 服务
  2. 等待 PC 客户端和 DUT 的连接

阶段 1:PC 客户端连接 + 发送 RTD Header(终端 3)

============================================================
  PC Client (Process 3)
  FaapProxy: 127.0.0.1:50052
  RTD MBS:   127.0.0.1:50053
  DUT IP:    127.0.0.1
  Product:   KRC 161 3456/1 R1A
============================================================
2026-06-11 10:30:40 [INFO] Connecting to RTD MBS...
2026-06-11 10:30:40 [INFO] RTD MBS connected: 127.0.0.1:50053
2026-06-11 10:30:40 [INFO] RTD message queue handler started
2026-06-11 10:30:40 [INFO] RTD Header sent: status=0

发生了什么

  1. PC 客户端连接 RTD MBS(localhost:50053)→ 成功
  2. 启动后台 RTD 转发线程(从队列取消息异步发给 MBS)
  3. 发送 RTD HeaderInitiateTestSession)→ 通知 MBS 一次新的测试会话开始

RTD Header 包含

  • SessionId(设备序列号 + 时间戳)
  • FilterAttributes(产品族 AIR5322 + 工厂代码)
  • TestStationId、DutPosition

终端 1 收到 Header

[INFO] FilterAttributes: family=AIR5322, factory=2
[WARNING] Header validation: Serial number format invalid: '127_0_0_1', expected pattern ^[A-Z0-9]{10}$

[RTD HEADER] Session started: 127_0_0_1
    Station:  ts_python_strict
    Position: 1
    Family:   AIR5322
    Factory:  2

发生了什么

  1. MBS 校验 FilterAttributes → 有效(family=AIR5322)
  2. MBS 校验序列号 → Warning127_0_0_1 不符合 ^[A-Z0-9]{10}$ 格式。这是因为模拟环境用 IP 当 device_id,真实环境是 10 位序列号如 C821234567
  3. 数据持久化到 SQLite
  4. 消息写入云端转发队列

:这个 Warning 不影响功能运行,只是提示模拟数据与真实格式不完全一致。


阶段 2:PC 客户端建立 Server Streaming 连接(终端 3 + 终端 2)

终端 3

2026-06-11 10:30:40 [INFO] Connecting to FaapProxy...
2026-06-11 10:30:40 [INFO] Calling FaapProxy.InitializeTestAsync (Server Streaming)...
  Waiting for test data stream...
2026-06-11 10:30:40 [INFO] FaapProxyServerStarted received
  [INFO] FaapProxy server started

终端 2

2026-06-11 10:30:40 [INFO] InitializeTestAsync: DUT IP=127.0.0.1, Position=1, Product=KRC 161 3456/1
2026-06-11 10:30:40 [INFO] Cache updated: DUT IP=127.0.0.1, Position=1

发生了什么

  1. PC 调用 InitializeTestAsync,发送 InitializeTestRequest(包含 DUT IP、产品号、SupportedMessages)
  2. FaapProxy 收到后:
    • 将 DUT 信息写入缓存(key=127.0.0.1,包含 position、filter_attributes、supported_messages)
    • 返回第一条消息 FaapProxyServerStarted(通知 PC 服务端就绪)
    • 进入推送循环:持续从 asyncio.Queue 读取消息推送给 PC
  3. PC 收到 FaapProxyServerStarted → 确认流连接建立

此时状态:PC ← FaapProxy 之间的 Server Streaming 长连接已建立,等待 DUT 发数据。


阶段 3:DUT 开始发送测试数据(终端 4)

终端 4 — DUT 客户端启动

2026-06-11 10:31:15 [INFO] Connected to FaapProxy at 127.0.0.1:50052 (DUT: C821234567)
============================================================
  DUT Client (Process 1) - Strict Pipeline
  Serial: C821234567
  Target: 127.0.0.1:50052
============================================================

发生了什么:DUT 模拟器连接到 FaapProxy 的 50052 端口。


阶段 4:预分配序列号(GetSeqIds)

终端 4

--- GetSeqIds ---
2026-06-11 10:31:15 [INFO] [SEQ] Got range: start=100000, sep=2, stop=100400

终端 2

2026-06-11 10:31:15 [INFO] GetSeqIds: start=100000, sep=2, stop=100400 (count=200)

发生了什么

  1. DUT 请求 200 个序列号
  2. FaapProxy 分配范围:start=100000,sep=2(步长),stop=100400
  3. 实际可用的 ID:100000, 100002, 100004, ..., 100398(共 200 个偶数)

设计原理

  • 步长为 2 是因为偶数给 DUT 使用,奇数预留给 PC 软件(如果它需要插入额外的数据点)
  • 起始值 100000 避免与旧版系统的低值 ID 冲突
  • 预分配而非逐个请求,减少 RPC 调用次数

阶段 5:发送测试前环境数据(Auxiliary)

终端 4

--- Pre-test Environment ---
[INFO] [AUX] board_temperature: 45.200 → status=0
[INFO] [AUX] supply_voltage: 48.100 → status=0
[INFO] [AUX] supply_current: 2.350 → status=0

终端 3(PC 实时显示)

  [AUX ] SeqId:100000 board_temperature 45.200
  [AUX ] SeqId:100002 supply_voltage 48.100
  [AUX ] SeqId:100004 supply_current 2.350

终端 1(RTD MBS 收到)

  [RTD AUX] board_temperature
  [RTD AUX] supply_voltage
  [RTD AUX] supply_current

数据流路径

DUT → AddAuxiliaryData(gRPC Unary) → FaapProxy(补字段+入队)
    → Queue → Server Streaming → PC(控制台显示+RTD转发)
    → AddAuxiliaryData(gRPC Unary) → MBS(持久化+云端队列)

业务含义:测试前先记录环境数据(板卡温度 45.2°C、供电电压 48.1V、电流 2.35A),用于后续分析测试结果是否受环境影响。


阶段 6:发送测试点数据(TestPoint)

终端 4 — 发送 TX Output Power 测试组

--- Test Group: TX Output Power ---
[INFO] [PASS] TP_TX_PWR_001: 23.500 (seqid=100006) → status=0
[INFO] [PASS] TP_TX_PWR_002: 24.100 (seqid=100008) → status=0
[INFO] [FAIL] TP_TX_PWR_003: 21.800 (seqid=100010) → status=0
[INFO] [PASS] TP_TX_PWR_004: 23.900 (seqid=100012) → status=0
[INFO] [GROUP] tx_output_power (children: [100006, 100008, 100010, 100012]) → status=0

终端 3 — PC 实时彩色显示

  [PASS] SeqId:100006 TP_TX_PWR_001 TX Output Power Port 1 23.500
  [PASS] SeqId:100008 TP_TX_PWR_002 TX Output Power Port 2 24.100
  [FAIL] SeqId:100010 TP_TX_PWR_003 TX Output Power Port 3 21.800
  [PASS] SeqId:100012 TP_TX_PWR_004 TX Output Power Port 4 (SBT) 23.900 SBT TX_PWR_GROUP 50% Run
  [GROUP] tx_output_power

终端 1 — RTD MBS 接收

  [RTD TP ✓] #1 TP_TX_PWR_001 TX Output Power Port 1
  [RTD TP ✓] #2 TP_TX_PWR_002 TX Output Power Port 2
  [RTD TP ✗] #3 TP_TX_PWR_003 TX Output Power Port 3
  [RTD TP ✓] #4 TP_TX_PWR_004 TX Output Power Port 4 (SBT)
  [RTD GRP] tx_output_power

逐条解读

测试点 描述 限值 结果 说明
TP_TX_PWR_001 TX Output Power Port 1 23.5 dBm 22.0~25.0 PASS 在限值范围内
TP_TX_PWR_002 TX Output Power Port 2 24.1 dBm 22.0~25.0 PASS 在限值范围内
TP_TX_PWR_003 TX Output Power Port 3 21.8 dBm 22.0~25.0 FAIL 低于下限 22.0
TP_TX_PWR_004 TX Output Power Port 4 (SBT) 23.9 dBm 22.0~25.0 PASS 带 SBT 采样信息

SBT 信息解读(TP_TX_PWR_004):

  • SBT TX_PWR_GROUP 50% Run
  • 含义:该测试点属于 TX_PWR_GROUP 采样组,采样率 50%(即只测一半产品),本次需要执行(Run)

DataPointGroup

  • tx_output_power (children: [100006, 100008, 100010, 100012])
  • 含义:把上面 4 个测试点归为一组 "tx_output_power",通过 seqid 关联

阶段 7:更多测试组(TX EVM + RX Performance)

TX EVM 测试组

DUT:  [PASS] TP_TX_EVM_001: -33.200 (seqid=100014)
DUT:  [PASS] TP_TX_EVM_002: 0.000 (seqid=100016)    ← SBT Skip
PC:   [PASS] SeqId:100014 TP_TX_EVM_001 TX EVM NR100 -33.200
PC:   [PASS] SeqId:100016 TP_TX_EVM_002 TX EVM NR100 (SBT Skip) 0.000 SBT TX_EVM_GROUP 30% Skip
  • TP_TX_EVM_002 标记了 SBT TX_EVM_GROUP 30% Skip:采样率 30%,本次跳过(不实际测量,值为 0)

RX Performance 测试组

DUT:  [PASS] TP_RX_NF_001: 2.800 (seqid=100018)
PC:   [PASS] SeqId:100018 TP_RX_NF_001 RX Noise Figure 2.800
  • 接收噪声系数 2.8 dB,在 0~4 dB 限值内,PASS

阶段 8:测试后环境数据

终端 4

--- Post-test Environment ---
[INFO] [AUX] board_temperature_post: 52.300 → status=0
[INFO] [AUX] power_consumption: 120.500 → status=0

业务含义:测试结束后再记录一次环境。板卡温度从 45.2°C 升至 52.3°C(正常,测试过程中设备发热),功耗 120.5W。


阶段 9:测试结束(FinalizeTestSequence)

终端 4

--- Finalize ---
[INFO] [END] FinalizeTestSequence → status=0

终端 2

2026-06-11 10:31:17 [INFO] FinalizeTestSequence received from 127.0.0.1
2026-06-11 10:31:17 [INFO] InitializeTestAsync stream ended for position 1

终端 3

  [END] Test sequence finalized

发生了什么

  1. DUT 调用 FinalizeTestSequence → 通知 FaapProxy 测试完成
  2. FaapProxy 做两件事:
    • 向队列写入 SequenceFinalized 消息(PC 会收到)
    • 向队列写入 None 哨兵值(信号 Server Streaming 结束)
  3. PC 收到 SequenceFinalized → 知道测试结束
  4. Server Streaming 流结束(因为收到 None)

2026-06-11 10:31:17 [INFO] RTD Footer sent: status=0

============================================================
  PC Client Summary
============================================================
  Test Points:       7
    Pass:            6
    Fail:            1
  Auxiliary Data:    5
  Data Point Groups: 3
  Pass Rate:         85.7%
  All Pass:          NO
============================================================
[RTD FOOTER] Session ended: 127_0_0_1
    Result:      HAS FAILURES
    Test Points: 7 (Pass: 6, Fail: 1)
    Auxiliary:   5
    Groups:      3
    → Data persisted to SQLite + forwarded to RTD cloud (simulated)
    → Cloud forwarded total: 16

发生了什么

  1. PC 发送 FinalizeTestSession(RTD Footer)给 MBS,包含:
    • pass=false(因为有 1 个 FAIL)
    • 测试点计数(7)、辅助数据计数(5)
  2. MBS 收到 Footer:
    • 持久化到 SQLite
    • 打印会话汇总
    • 统计:共 16 条消息被转发到云端队列(3 aux前 + 4 tp + 1 grp + 2 tp + 1 grp + 1 tp + 1 grp + 2 aux后 + 1 header = 实际是 header + 5 aux + 7 tp + 3 grp + footer = 17,其中 footer 最后到)

三、数据流总结图

时间线:
10:28:35  [MBS] 启动,监听 50053
10:30:40  [PC]  连接 MBS → 发送 Header → 连接 FaapProxy → 建立 Streaming
10:31:15  [DUT] 连接 FaapProxy → GetSeqIds
10:31:16  [DUT] 发送 5 条 Auxiliary + 7 条 TestPoint + 3 条 Group
10:31:17  [DUT] FinalizeTestSequence → 流结束 → PC 发 Footer → 会话结束

每条消息的完整旅程(以一个 TestPoint 为例)

1. DUT 调用 AddTestPoint(payload)                     → gRPC Unary → FaapProxy
2. FaapProxy 校验 SessionId + 补 FilterAttributes      → 内部处理
3. FaapProxy 包装为 FaapProxyReturnMessage(test_point_v1) → 写入 asyncio.Queue
4. Queue 被 InitializeTestAsync 读取                   → gRPC Server Streaming → PC
5. PC 控制台彩色输出                                    → 用户可见
6. PC 写入本地 TestResult 文件                          → 本地持久化
7. PC 写入 RTD 转发队列                                → queue.Queue
8. 后台线程从队列读取,调用 AddTestPointData             → gRPC Unary → MBS
9. MBS 持久化到 SQLite                                 → 断网保护
10. MBS 后台线程模拟转发到 RTD 云端                     → 最终目的地

四、各终端输出中的关键标记解读

4.1 PC 客户端(终端 3)输出标记

标记 颜色 含义
[PASS] 绿色 测试点通过(在限值范围内)
[FAIL] 红色 测试点失败(超出限值)
[AUX ] 青色 辅助数据(环境参数)
[GROUP] 黄色 数据点分组
[INFO] 蓝色 信息性消息
[END] 紫色 测试序列结束
[ERROR] 红色 运行时错误

4.2 RTD MBS(终端 1)输出标记

标记 含义
[RTD HEADER] 收到会话开始消息
[RTD TP ✓] 收到测试点数据(通过)
[RTD TP ✗] 收到测试点数据(失败)
[RTD AUX] 收到辅助数据
[RTD GRP] 收到数据点分组
[RTD FOOTER] 收到会话结束消息

4.3 DUT 客户端(终端 4)输出标记

标记 含义
[SEQ] 序列号分配结果
[AUX] 发送辅助数据
[PASS] 发送通过的测试点
[FAIL] 发送失败的测试点
[GROUP] 发送数据点分组
[END] 发送结束信号

4.4 FaapProxy(终端 2)输出标记

日志 含义
InitializeTestAsync: ... PC 客户端建立了 Streaming 连接
Cache updated: ... DUT 信息已缓存
GetSeqIds: ... 给 DUT 分配了序列号
FinalizeTestSequence received DUT 发送了结束信号
stream ended for position X Streaming 流正常结束

五、输出中的警告解释

[WARNING] Header validation: Serial number format invalid: '127_0_0_1', expected pattern ^[A-Z0-9]{10}$

原因:模拟环境中 PC 客户端用 DUT IP(127.0.0.1 → 转为 127_0_0_1)作为 SessionId 的 device_id。真实生产环境中这个字段是设备的 10 位序列号(如 C821234567)。

影响:无。这只是校验提示,不阻断流程。真实部署时 DUT 会提供正确格式的序列号。


六、测试数据统计

本次模拟运行的数据统计:

指标 数量
预分配序列号 200 个
辅助数据(Auxiliary) 5 条(3 前 + 2 后)
测试点(TestPoint) 7 个
数据点分组(Group) 3 个
通过 6 个
失败 1 个(TP_TX_PWR_003 低于下限)
通过率 85.7%
MBS 云端转发总数 16 条
整体结论 HAS FAILURES

七、依赖安装

pip install grpcio grpcio-tools protobuf googleapis-common-protos

如果 grpcio 版本不够新(需要 >=1.78.0):

pip install --upgrade grpcio grpcio-tools

image

posted @ 2026-06-12 17:13  mo686  阅读(1)  评论(0)    收藏  举报