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 枚举值。枚举定义可能包含 EnterDutBootModeInternalEnterDutBootModeExternal 等。

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 对象包含 CodeMessage 字段。

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 对象。
  • 填充 sessiondut_positionboot_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 服务的方法,为跨平台测试工具的开发提供参考。

posted @ 2026-03-16 15:57  mo686  阅读(3)  评论(0)    收藏  举报