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...
============================================================
发生了什么:
- 初始化 SQLite 数据库(
rtd_mbs_sessions.db),创建rtd_sessions和rtd_messages两张表 - 启动后台云端转发线程(模拟将数据发往 RTD 云端)
- 在端口 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...
============================================================
发生了什么:
- 在端口 50052 注册了 3 个 gRPC 服务
- 等待 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
发生了什么:
- PC 客户端连接 RTD MBS(localhost:50053)→ 成功
- 启动后台 RTD 转发线程(从队列取消息异步发给 MBS)
- 发送 RTD Header(
InitiateTestSession)→ 通知 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
发生了什么:
- MBS 校验 FilterAttributes → 有效(family=AIR5322)
- MBS 校验序列号 → Warning:
127_0_0_1不符合^[A-Z0-9]{10}$格式。这是因为模拟环境用 IP 当 device_id,真实环境是 10 位序列号如C821234567 - 数据持久化到 SQLite
- 消息写入云端转发队列
注:这个 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
发生了什么:
- PC 调用
InitializeTestAsync,发送InitializeTestRequest(包含 DUT IP、产品号、SupportedMessages) - FaapProxy 收到后:
- 将 DUT 信息写入缓存(key=127.0.0.1,包含 position、filter_attributes、supported_messages)
- 返回第一条消息
FaapProxyServerStarted(通知 PC 服务端就绪) - 进入推送循环:持续从 asyncio.Queue 读取消息推送给 PC
- 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)
发生了什么:
- DUT 请求 200 个序列号
- FaapProxy 分配范围:start=100000,sep=2(步长),stop=100400
- 实际可用的 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
发生了什么:
- DUT 调用
FinalizeTestSequence→ 通知 FaapProxy 测试完成 - FaapProxy 做两件事:
- 向队列写入
SequenceFinalized消息(PC 会收到) - 向队列写入
None哨兵值(信号 Server Streaming 结束)
- 向队列写入
- PC 收到
SequenceFinalized→ 知道测试结束 - Server Streaming 流结束(因为收到 None)
阶段 10:发送 RTD Footer + 打印汇总
终端 3 — PC 客户端发送 Footer 并汇总
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
============================================================
终端 1 — RTD MBS 收到 Footer
[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
发生了什么:
- PC 发送
FinalizeTestSession(RTD Footer)给 MBS,包含:- pass=false(因为有 1 个 FAIL)
- 测试点计数(7)、辅助数据计数(5)
- 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


浙公网安备 33010602011771号