Mode Select Service
简介
Mode Select 服务是测试接口客户端中用于选择设备启动模式(Boot Mode)的关键功能。通过 gRPC 调用,客户端可以远程设置被测设备(DUT)的启动模式,例如内部启动、外部启动等。本文将通过 C# 和 Python 两种语言的实现代码,详细解析该服务的功能、工作流程和关键技术点。
Mode Select - C#
Select 方法解析
以下 C# 代码片段展示了如何通过 gRPC 客户端调用 Mode Select 服务:
var clientTifModeSelect = new TestInterfaceModeSelectService.TestInterfaceModeSelectServiceClient(Channel);
uint dutPosition = 1;
BootModeSelection bootMode = System.Enum.Parse<BootModeSelection>((sender as Button).Text);
var modeSelectRequest = new ModeSelectRequest()
{
Session = _sessionId,
DutPosition = dutPosition,
BootMode = bootMode
};
_logger.LogInformation("Mode selected: {modeSelectRequest}", modeSelectRequest);
var status = clientTifModeSelect.Select(modeSelectRequest);
if (status.Code != (int) StatusCode.OK)
{
_logger.LogError(failedMessage + ", {code}, {message}", status.Code, status.Message);
textBox.Text = failedMessage;
textBox.BackColor = Color.Red;
}
功能概述
该方法通过 gRPC 向服务器发送模式选择请求,并根据返回状态更新 UI 界面。它通常作为按钮点击事件处理程序的一部分被调用,从按钮文本解析出枚举值,然后执行远程调用。
详细解析
1. 参数准备
dutPosition:被测设备位置,固定为 1。bootMode:从触发事件的按钮文本解析出BootModeSelection枚举值。枚举定义可能包含EnterDutBootModeInternal、EnterDutBootModeExternal等。
2. gRPC 客户端初始化
var clientTifModeSelect = new TestInterfaceModeSelectService.TestInterfaceModeSelectServiceClient(Channel);
- 使用全局
Channel对象创建 Mode Select 服务的 gRPC 客户端。 Channel通常已在应用程序启动时建立,并管理与服务器的连接。
3. 构建请求对象
var modeSelectRequest = new ModeSelectRequest()
{
Session = _sessionId,
DutPosition = dutPosition,
BootMode = bootMode
};
Session:当前会话 ID,用于标识请求的上下文。DutPosition:设备位置。BootMode:要设置的启动模式。
4. 日志记录
_logger.LogInformation("Mode selected: {modeSelectRequest}", modeSelectRequest);
- 记录请求信息,便于调试和追踪。
{modeSelectRequest}占位符会被请求对象的字符串表示替换。
5. 执行 gRPC 调用
var status = clientTifModeSelect.Select(modeSelectRequest);
- 同步调用
Select方法,阻塞直到服务器返回响应。 - 返回的
status对象包含Code和Message字段。
6. 响应处理
if (status.Code != (int) StatusCode.OK)
{
_logger.LogError(failedMessage + ", {code}, {message}", status.Code, status.Message);
textBox.Text = failedMessage;
textBox.BackColor = Color.Red;
}
- 成功:
Code == StatusCode.OK(通常为 0),流程正常结束。 - 失败:记录错误码和错误消息,将文本框背景设为红色并显示失败信息。
7. 异常处理(隐含)
此代码片段未显式包含 try-catch,但在实际应用中,gRPC 调用可能抛出 RpcException 等异常。建议在实际代码中增加异常捕获,以处理网络故障、超时等情况。
技术特点
| 特性 | 说明 |
|---|---|
| 枚举解析 | 使用 Enum.Parse 将按钮文本转换为枚举值,实现了 UI 与业务逻辑的解耦。 |
| 日志记录 | 使用结构化日志记录请求对象,便于调试。 |
| UI 反馈 | 通过改变文本框颜色和文字,向用户直观反馈操作结果。 |
| 错误处理 | 检查 gRPC 返回码,针对失败情况记录错误并更新 UI。 |
使用示例
假设界面上有两个按钮,分别对应“内部启动”和“外部启动”,点击事件中调用上述代码:
// 按钮 "Internal Boot" 的点击事件处理
private void btnInternalBoot_Click(object sender, EventArgs e)
{
SelectMode(); // 内部使用 (sender as Button).Text 解析出 BootModeSelection.EnterDutBootModeInternal
}
Mode Select - Python
Python 实现采用了面向对象的设计,将 Mode Select 客户端封装为 ModeSelectService 类,并提供详细的日志和错误处理。
类定义与初始化
__init__ 方法
def __init__(self, channel: grpc.Channel, session_id: Optional[type_pb2.SessionId] = None,
dut_position: int = 1, verbose: bool = False):
"""
Initialize ModeSelect service with existing gRPC channel
Args:
channel: Existing gRPC channel (already connected)
session_id: Optional session ID for the connection
dut_position: Device under test position (default: 1)
verbose: Enable verbose logging
"""
self.channel = channel
self.mode_select_stub = pb2_grpc.TestInterfaceModeSelectServiceStub(channel)
self.dut_position = dut_position
self.verbose = verbose
if session_id:
self.session_id = session_id
else:
self.session_id = self._create_default_session()
self.logger = logging.getLogger(self.__class__.__name__)
if self.verbose:
self.logger.setLevel(logging.DEBUG)
功能解析
- 存储 gRPC 通道:将传入的
channel保存为实例属性,供后续调用使用。 - 创建 Stub:通过通道实例化 Mode Select 服务的 gRPC Stub(存根),之后的所有 RPC 调用都通过此 Stub 发起。
- 会话 ID 处理:如果调用者提供了
session_id则直接使用,否则调用_create_default_session()生成一个默认会话(包含设备 ID 和时间戳)。 - 日志配置:获取以类名命名的日志记录器,并根据
verbose标志设置日志级别为 DEBUG。
_create_default_session 方法
def _create_default_session(self) -> type_pb2.SessionId:
"""Create a default session ID"""
session = type_pb2.SessionId()
session.device_id = "MMI_ModeSelect"
now = Timestamp()
now.GetCurrentTime()
session.start_time.CopyFrom(now)
return session
- 创建一个默认的会话 ID,设备 ID 固定为 "MMI_ModeSelect",开始时间为当前时间。
Select 方法
def Select(self, mode: str, timeout: float = 10.0) -> bool:
"""
Select a predefined mode.
Args:
mode: The mode to select (e.g., "EnterDutBootModeInternal")
timeout: RPC timeout in seconds
Returns:
bool: True if successful, False otherwise
"""
if not mode or not mode.strip():
self.logger.error(f"Invalid mode: '{mode}'")
return False
try:
# Build ModeSelectRequest
request = pb2.ModeSelectRequest()
request.session.CopyFrom(self.session_id)
request.dut_position = self.dut_position
request.boot_mode = mode.strip()
if self.verbose:
self.logger.debug(f"ModeSelect request; {json.dumps(MessageToDict(request))}")
# Execute gRPC call
response = self.mode_select_stub.Select(request, timeout=timeout)
# Check response code (0 means OK)
if response.code == 0:
self.logger.info(f"Successfully selected mode '{mode}'")
return True
else:
self.logger.error(f"Failed to select mode '{mode}': code={response.code}, message='{response.message}'")
return False
except grpc.RpcError as e:
self.logger.error(f"gRPC error selecting mode '{mode}': {e.details()}")
if self.verbose:
self.logger.debug(f"Error code: {e.code()}")
return False
except Exception as e:
self.logger.error(f"Unexpected error selecting mode '{mode}': {e}")
if self.verbose:
import traceback
traceback.print_exc()
return False
功能解析
Select 方法封装了完整的模式选择流程:参数验证、请求构建、RPC 调用、响应处理和异常捕获。
1. 参数验证
- 检查
mode字符串是否为空或仅包含空格,无效则记录错误并返回False。
2. 构建请求
- 创建
ModeSelectRequest对象。 - 填充
session、dut_position和boot_mode字段。 - 若开启详细日志,将请求对象转换为 JSON 并记录。
3. 执行 gRPC 调用
- 通过 Stub 的
Select方法发送请求,并指定超时时间。 - 同步等待服务器响应。
4. 响应处理
- 成功:
response.code == 0,记录成功日志并返回True。 - 失败:记录错误码和错误消息,返回
False。
5. 异常处理
grpc.RpcError:捕获 gRPC 层错误(如连接失败、超时),记录详细信息。- 通用异常:捕获其他意外错误,确保程序不崩溃。
main 函数示例
def main():
"""
Example usage of ModeSelectService
"""
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s; %(levelname)s; %(name)s; %(message)s')
# Server address
server_addr = "192.168.2.71:50051"
try:
print("Mode Select Service Example")
print("=" * 50)
print(f"Connecting to server: {server_addr}")
# Create channel
channel = grpc.insecure_channel(server_addr)
# Wait for channel to be ready
try:
grpc.channel_ready_future(channel).result(timeout=10)
print("✓ Connection established successfully")
except grpc.FutureTimeoutError:
print("✗ Connection timeout - server may not be running.")
return
# Create ModeSelect service client
mode_select_service = ModeSelectService(channel, verbose=True)
# --- Test Case ---
print("\n1. Testing ModeSelect with 'EnterDutBootModeInternal'")
print("-" * 20)
mode_to_select = "BOOT_MODE_SELECTION_ENTER_DUT_BOOT_MODE_INTERNAL"
success = mode_select_service.Select(mode_to_select)
print(f" Result: {'Success' if success else 'Failed'}")
print("\n2. Testing ModeSelect with 'EnterDutBootModeExternal'")
print("-" * 20)
mode_to_select = "BOOT_MODE_SELECTION_ENTER_DUT_BOOT_MODE_EXTERNAL"
success = mode_select_service.Select(mode_to_select)
print(f" Result: {'Success' if success else 'Failed'}")
print("\n" + "=" * 50)
print("Example completed.")
except Exception as e:
print(f"\n✗ Example failed: {e}")
import traceback
traceback.print_exc()
功能解析
- 环境配置:配置日志格式和级别。
- 连接服务器:创建 gRPC 通道,并等待通道就绪,提供清晰的连接状态反馈。
- 实例化服务:创建
ModeSelectService对象,开启详细日志。 - 执行测试:调用
Select方法测试两种启动模式,并打印结果。 - 异常处理:捕获所有异常并打印堆栈信息。
总结
本文详细解析了 Mode Select 服务的 C# 和 Python 客户端实现。两种语言的实现都遵循了类似的逻辑:构建请求、执行 gRPC 调用、处理响应和异常。C# 版本更侧重于与 UI 的集成,而 Python 版本则提供了更完善的类封装和日志功能。通过对比学习,可以快速掌握在不同语言中调用同一 gRPC 服务的方法,为跨平台测试工具的开发提供参考。

浙公网安备 33010602011771号