ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Pelco KBD300A模拟器重构后键盘测试实操指南

Pelco KBD300A模拟器重构后键盘测试实操指南 1. 这次重构动了哪些东西测试才不至于瞎忙做安防视频监控项目的人对 Pelco KBD300A 这种老牌控制键盘应该都不陌生。前些年做平台联调、云台控制、矩阵切换现场几乎都离不开它。后来项目里要对接的子系统越来越多硬件键盘又不可能人手一台我们就在内部搞了一个 Pelco KBD300A 模拟器把键盘面板、摇杆、协议编码全部搬到软件里既能给开发自测用也能给售前演示用。上一版模拟器功能算是能跑但代码结构比较乱按键事件、协议编码、UI刷新全都揉在一起加一个功能就要动好几个地方。于是就有了这次重构目标很明确把键盘输入、业务逻辑、协议输出彻底分层。重构完成后进入了 TEST02 阶段这一轮专门盯键盘部分标题里写得也很直白——这是重构后键盘部分的测试操作一步一步详细指导。先说结论重构后的代码看起来清爽了但键盘这种交互密集的模块重构完最容易翻车。按键抖动、组合键时序错乱、摇杆松开不停止、协议帧多字节少字节这些我都实测遇到过。所以 TEST02 不能凭感觉点点看得先把测试范围和检查项列清楚再一步一步操作。1.1 旧架构与新架构的差别旧版的键盘模块是典型的事件驱动揉成一团的做法鼠标点击键盘上的某个按键直接在回调里同时做界面高亮、拼协议、发数据。摇杆更麻烦一个定时器同时负责采集位置、计算速度、组帧发送。好处是写起来快坏处是任何一环出问题排查时根本不知道是 UI 的问题还是编码的问题还是网络发送的问题。这次重构之后键盘部分的链路变成了三层输入层负责捕获键盘按键和摇杆动作转换成内部事件比如 KEY_DOWN_CAM、JOYSTICK_MOVE、KEY_UP_PRESET。这一层不再碰协议和 UI。业务层维护按键状态机处理组合键逻辑比如按住 CAM 再按数字键才进入相机选择状态。这一层只更新状态不直接发帧。输出层根据业务层给出的“意图”调用协议编码器生成 Pelco-D 或 Pelco-P 帧再通过可插拔的通信通道发出去。UI 层现在只干一件事监听输入层和业务层的状态变化刷新界面。这样拆完之后测试最大的好处是可以分层验证键盘按下有没有产生正确事件、组合键状态机有没有走对、协议帧编码对不对。1.2 键盘功能与检查项映射表测试前我先把 KBD300A 模拟器的键盘功能梳理成了映射表。每一行就是一条测试用例对应着物理键盘操作、内部事件、输出协议帧、预期界面反馈四个维度。下面这张表是简化版实际测试时我会按这张表逐条过编号键盘操作内部事件期望协议帧期望界面反馈期望K01按下 CAM 键KEY_DOWN_CAM无帧输出进入组合键待命状态CAM 键高亮K02CAM 数字键 2CAM_SELECT(2)输出选相机指令具体指令由对接设备决定状态栏显示当前相机为 02K03推动摇杆向右JOYSTICK_MOVE(水平偏移0)Pan Right 指令含速度值摇杆控件偏移云台方向标识亮K04松开摇杆JOYSTICK_UP发送停止帧或速度归零帧摇杆回中方向标识熄灭K05按下 ZOOM TELEZOOM_TELE_DOWNZoom Tele 指令镜头标识显示 TELEK06退出组合键状态KEY_TIMEOUT无残留帧CAM 高亮自动熄灭这张表看着简单实际测的时候能筛掉一大批重构引入的问题。我特别提醒一点组合键状态机一定要单独列用例因为重构后事件顺序一旦不对组合键就会偶发失效而这种问题在界面上很难复现。2. 测试前准备环境、工具和一条靠谱的验收链路键盘测试不像普通界面测试只盯着模拟器窗口看是远远不够的。KBD300A 模拟器的核心价值在于输出和真实设备一致的协议帧所以测试时必须有一条能“看到帧内容”的链路否则按了摇杆也不知道发出来的 Pan 指令对不对。2.1 模拟器构建与启动我们模拟器是基于桌面端框架做的构建环境主要依赖系统开发库和串口、网络相关模块。构建命令很简单测试人员拿到代码后三步就能拉起来git clone repository_url cd pelco-kbd300a-emu ./build.sh ./run.sh启动之后首先检查主窗口是否能正常加载键盘面板。这里我要专门说一句启动后先别急着点按键先在设置界面确认通信参数。KBD300A 模拟器的配置项包括协议类型Pelco-D 或 Pelco-P、设备地址1-255、通信方式串口/TCP/UDP、波特率、数据位/校验位等。参数不对后面所有测试都是白测。2.2 抓协议帧的三种方式TEST02 测试过程中我用了三种方式验证输出帧按可信度从高到低排第一种是模拟器内置的协议日志面板。日志面板记录每一帧发出的完整字节流和对应时间戳测试时勾选“显示协议日志”所有按键动作的协议输出一目了然。这个方式最简单适合先快速过一遍功能。第二种是外部抓包验证。如果模拟器输出走 TCP 或 UDP可以直接用 Wireshark 抓包或者用下面的 Python 脚本监听某个端口把收到的帧解析出来。这样能验证模拟器对外发送的数据是否完整不受模拟器自身日志逻辑的影响。第三种是串口回环。如果你手头有虚拟串口软件比如 com0com可以创建一对虚拟串口模拟器连到 COM1调试助手连到 COM2把模拟器发的帧原样读出来。这种方式最接近真实设备的接收场景我之前排查过一个“日志面板显示正常但设备不动作”的问题就是用串口回环发现真实输出字节和日志显示不一致原因是输出层和日志层共用了同一个缓冲区读取时没加同步保护。2.3 一个轻量的 Pelco-D 帧解析脚本为了不在一轮测试里来回切窗口我写了一个简单的 Pelco-D 帧解析脚本监听 UDP 端口并实时打印解析结果。核心代码在这里你复制就能用import socket def parse_pelco_d(frame_bytes): if len(frame_bytes) ! 7: return f长度异常: {len(frame_bytes)} 字节 - {frame_bytes.hex()} sync, addr, cmd1, cmd2, pan_spd, tilt_spd, checksum frame_bytes if sync ! 0xFF: return f同步字错误: {sync:#x} calc_checksum (addr cmd1 cmd2 pan_spd tilt_spd) 0xFF if calc_checksum ! checksum: return f校验和错误: 期望 {calc_checksum:#x}, 实际 {checksum:#x} actions [] if cmd1 0x80: actions.append(TILT_UP) if cmd1 0x40: actions.append(TILT_DOWN) if cmd1 0x20: actions.append(ZOOM_WIDE) if cmd1 0x10: actions.append(ZOOM_TELE) if cmd2 0x02: actions.append(PAN_RIGHT) if cmd2 0x01: actions.append(PAN_LEFT) if not actions: actions.append(空指令/停止) result f[地址 {addr}] {.join(actions)} result f | 水平速度 {pan_spd} 垂直速度 {tilt_spd} return result sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((127.0.0.1, 9000)) print(监听 UDP 9000 端口等待模拟器输出...) while True: data, addr sock.recvfrom(1024) print(f收到 {len(data)} 字节: {data.hex()} - {parse_pelco_d(data)})这个脚本虽然只解析了核心指令但已经够用了。测试摇杆、镜头键、预置位调用时判断“收到什么动作、速度值是多少”这两件事脚本一眼就能看出来。测试前记得把模拟器的 TCP/UDP 输出地址改成 127.0.0.1:9000。3. TEST02 键盘测试操作一步一步来环境准备好、链路打通之后就可以正式进入键盘部分的测试了。我是按键盘面板的物理分区来测的从基础按键逐步推进到组合逻辑每测完一个分区就在测试用例表格上打个勾。下面每个小节都是一组完整操作你跟着做就行。3.1 基础按键与界面反馈测试第一步先测键盘面板上每一个物理按键包括数字键 0-9、CAM、MON、AUX、PRESET、PATTERN、TOUR、MENU、ENTER、F1/F2 等。操作方式很简单依次点击每个按键观察界面颜色变化是否跟随按下状态。但这里有个关键点不只是测“亮不亮”还要测“松手灭不灭”。我这次重构后踩的第一个坑就在这里。旧版按键按下时直接修改按键背景色松开时恢复重构后改为事件驱动界面更新结果按下事件和松开事件走了两条不同的处理链导致快速点击时界面偶发卡在“按下”状态。后来在输入层加了事件序号校验才解决。基础按键测试时重点关注三点单击一次只产生一次按下事件和一次松开事件不能有重复触发。按住不放界面应保持按下状态松开后才恢复。快速连续点击时界面状态不能错乱不能出现上一个按键的松开事件导致下一个按键高亮消失。我建议测试时把模拟器窗口放到最大顺便开启“按键事件显示”调试面板每按一个键面板上会实时显示事件流。看到下面这种事件序列基本就正常[EVT] key_down code0x11 label1 [EVT] key_up code0x11 label1 [EVT] key_down code0x12 label2 [EVT] key_up code0x12 label2如果看到同一次点击出现两次 key_down输入层防抖就没做好。重构后这里特别容易出问题因为新框架里按键按下判定用了平台事件队列抖动信号也被当作有效按键事件接收了。3.2 摇杆和云台方向控制测试摇杆是 KBD300A 模拟器最核心的交互组件测试优先级最高。实体键盘上摇杆控制云台的水平垂直运动模拟器里通常用鼠标拖拽或用滑杆模拟摇杆位置。我按下面几个步骤测把摇杆往右推观察协议帧。期望输出 Pan Right 指令水平速度值和摇杆偏移量成正比。摇杆推到一半时速度大约是 0x20推到底时接近 0x3F。把摇杆往左推同理验证 Pan Left。往上推验证 Tilt Up往下推验证 Tilt Down。推到斜向角度比如右上期望同时输出 Pan Right 和 Tilt Up 两个动作位。松手期望立即输出停止帧也就是所有运动动作为空、速度为 0 的帧。测试时对照 2.3 小节的解析脚本正常情况应该是摇杆向右拉满时输出[地址 1] PAN_RIGHT | 水平速度 63 垂直速度 0松手后输出[地址 1] 空指令/停止 | 水平速度 0 垂直速度 0。这里我要重点讲一个经验摇杆停止帧的判定条件是速度字段同时归零还是动作位清零。两个条件都必须满足才能算真正的停止。重构时我只清空了动作位速度字段却保留上次值结果对端设备收到后仍然按旧速度继续运动了 1-2 秒现场表现就是“云台抖了一下才停”。所以测停止帧时必须检查速度值是否也归零。另外摇杆灵敏度参数也要测。把灵敏度调到最低和最高各测一轮确认速度映射曲线符合预期。我们模拟器里速度映射不是纯线性而是接近指数曲线低速区更细腻。你测试时先确认自己项目的映射关系再判断对错。3.3 镜头控制与辅助功能测试镜头控制区包含 ZOOM、FOCUS、IRIS 三类按键以及对应的远/近、大/小方向。测试方法和云台方向类似按下按键时输出对应的镜头指令松手后输出停止。实际操作中我发现镜头控制测试最容易被遗漏的是“按住持续输出”的行为。实体 KBD300A 键盘按住 ZOOM TELE 不松应该持续输出 Zoom Tele 指令直到松手才停止。模拟器里如果用鼠标点击要区分单击和长按。重构后业务层加了按下持续时间判断结果长按事件和持续输出在定时器里打架导致长按时只发了一帧就停了。测试时故意按住 ZOOM TELE 不松 5 秒用解析脚本统计这一时间段内收到的帧数。如果只有 1 帧说明持续输出逻辑有问题。正常情况应该每隔 100ms 一帧5 秒大约 50 帧左右。AUX 辅助功能键也要挨个测。AUX 键配合数字键可以输出辅助设备开关指令对应的协议帧是 Byte4 里的 AUX 位。测试时用数字键 1-8 逐个组合一遍确认每个 AUX 序号对应的指令位正确。我们模拟器对接的球机支持 AUX1 开雨刷、AUX2 开灯光测试时就拿这两个典型场景验证。3.4 预置位、巡航和菜单组合键测试组合键是重构后键盘模块最脆弱的部分因为涉及事件顺序和状态机切换测试要格外仔细。预置位的标准操作流程是先按 PRESET 键再按数字键选择预置位号最后按 ENTER 确认。实体键盘上这三步之间有时间间隔模拟器里也实现了超时机制超过 3 秒没有下一步操作就自动退出组合状态。测试预置位设置和调用我按以下步骤操作把摇杆推到一个非零位置模拟当前云台位置。按 PRESET按数字键 1按 ENTER期望输出预置位 1 的设置指令。改变摇杆位置制造一个和步骤 1 不同的位置。按 PRESET按数字键 1按 ENTER期望输出调用预置位 1 的指令对端设备回到步骤 1 的位置。如果模拟器对接的不是真实设备而是另一个模拟球机可以通过球机的状态回读确认预置位是否设置成功。我们内部自测时搭了一套“模拟器 虚拟球机”的环境虚拟球机收到预置位设置指令后会打印当前位置收到调用指令后会把位置状态改成预置位保存的值这样就能闭环验证。巡航功能类似先定义巡航路线再调用巡航启动。PATTERN 键是记录轨迹操作时先按 PATTERN 再按数字键然后拖动摇杆移动一段路径最后按 ENTER 结束录制。测试时留意录制轨迹是否完整回放如果回放速度和录制时不一致多半是轨迹点采样间隔在重构时被改了。MENU 键测试相对简单按 MENU 进入菜单界面按方向键导航按 ENTER 确认按 MENU 退出。重点检查菜单界面弹出和关闭时键盘事件会不会穿透到主界面导致底层云台被误操作。3.5 协议参数切换与边界值测试键盘测试的最后一块是协议和参数切换。KBD300A 模拟器支持 Pelco-D 和 Pelco-P 两种协议测试时要在设置界面切换协议再重复前面的核心操作确认编码器输出的帧格式跟着变了。边界值测试是这次重构后我特意加的。具体检查以下几个点设备地址设为 1 和 255 时协议帧地址字段是否正确。地址 0 在多数 Pelco 设备里是广播或无效地址模拟器应该弹出提示而不是发出错误帧。摇杆速度推到最大值时速度字段不能溢出。Pelco-D 的速度字段是 6 位最大 63如果映射计算错误很容易输出 64 以上导致高位污染。组合键超时边界。按 PRESET 后故意等待 2 秒、3 秒、4 秒确认只有超过 3 秒才退出组合状态恰好 3 秒时行为要符合文档定义我们定义为 3 秒整不退出超过才退出。通信通道切换。串口和 TCP 之间切换时之前未发送完的缓冲区要正确刷新不能把半个帧发到新通道上。这些边界值看着不起眼但都是重构时最容易改出 bug 的地方。我记得很清楚重构后第一次测试地址 255 的帧就出了问题——地址字段是拼接生成的只留了 7 位空间255 放进去变成了 127字节直接错了。4. 测试现场实录与问题排查TEST02 期间我把遇到的问题都记了日志有些是纯实现 bug有些是重构前就存在的老问题这次暴露出来了。下面整理成速查表再挑三个有代表性的排查案例详细说。4.1 高频问题速查表现象可能原因排查方法解决方案按键偶发重复触发输入层未做防抖或事件去重开启事件调试面板观察 key_down 是否出现两次在输入层增加时间窗口去重同一按键 50ms 内忽略第二次事件摇杆松手后云台仍在动停止帧速度字段未归零用协议解析脚本看停止帧内容停止时同时清空动作位和速度字段组合键偶尔失效事件处理顺序被重构打乱松开事件先于按下事件到达复现后查看事件时间戳业务层增加事件序号排序或按下事件先入队列协议帧校验和错误校验和计算范围错误或字节序问题用解析脚本逐字节比对按协议文档重新核对校验范围和溢出处理长按按键只发一帧定时器在重构后被误停按住按键统计帧数定时器启动条件改为按下持续状态而不是单次事件切换通信通道后首帧乱码发送缓冲区未清空串口回环抓取切换后的第一帧通道切换时重置缓冲区状态地址 255 显示为 127地址字段位数溢出打印地址字段二进制地址拼组时先做掩码处理4.2 三个有代表性的排查案例案例一是摇杆停止帧的问题。现象很典型界面日志里显示松手后发出了停止帧但对接的虚拟球机仍然继续旋转 1 秒多。一开始怀疑是网络延迟抓包后发现模拟器发出的停止帧是FF 01 00 00 00 00 01动作位全空但水平速度字段是 0x3F。虚拟球机按协议解析出“Pan 动作不存在但速度字段有值”部分固件会把这种情况当作恢复上次速度处理所以继续转。修复方式很简单停止帧强制把速度字段也清零。案例二是预置位组合偶发失效。操作流程是 PRESET、1、ENTER但有时按完 1 之后数字 1 的事件没被业务层收到界面停在“等待预置位编号”状态直到超时退出。排查了很久最后发现是重构后数字键和功能键的事件映射没统一PRESET 键的 key_up 事件和数字 1 的 key_down 事件之间存在一个未锁定的共享状态快速操作时状态被覆盖。修复后给组合键状态机加了事务处理一组按键序列执行完之前不接受新事件。案例三是长按 ZOOM 只输出一帧。这个问题的根子不在键盘模块而在于重构时把镜头持续输出逻辑从 UI 层挪到了业务层但定时器启动条件没有跟着改。旧版是按下时启动定时器新逻辑要求按下并保持 200ms 后启动定时器结果有人把定时器一次性的 flag 当成持续运行的 flag。这个案例再次说明重构后单测覆盖长按事件有多重要单纯点按测试根本发现不了。4.3 关于自动化回归的一点体会TEST02 后半段我把核心的键盘操作写成了一批接口级测试绕开界面直接模拟事件流然后断言输出帧。类似下面这段import pytest from keyboard_engine import KeyboardEngine pytest.mark.parametrize(protocol,address, [ (PELCO_D, 1), (PELCO_D, 255), (PELCO_P, 1), ]) def test_joystick_pan_right_then_stop(protocol, address): engine KeyboardEngine(protocolprotocol, addressaddress) frames [] engine.on_event(JOYSTICK_MOVE, {pan: 63, tilt: 0}) frames engine.poll_frames() engine.on_event(JOYSTICK_UP, {}) frames engine.poll_frames() assert len(frames) 1 assert frames[0][0] 0xFF assert frames[-1][-1] 0x00 # 停止帧速度归零有了这批自动化用例后续再重构键盘模块时至少能保证核心路径不再被破坏。我个人的建议是手工测试负责探索性问题比如界面反馈、手感、异常操作自动化负责回归底线保证每次代码合并后核心功能不挂。两条腿走路键盘模块才能越改越稳。这次 TEST02 做完最大的体会是键盘模拟器测试别只看界面一定要从“协议输出对不对”倒推回来看问题。很多界面看起来正常的操作协议帧其实已经错了这种错在演示现场特别致命。下一篇我打算把 TEST03 的内容放到通信压力和异常恢复上比如长时间连续摇杆操作、断线重连、缓冲区溢出这些都是重构后还没充分验证的区域。
返回列表