基于HID的开关控制系统设计
2021-12-10谭汝浩韦红录黄冬梅
谭汝浩 韦红录 黄冬梅
一、概述
广播电视发射系统中信号源子系统设备繁多,有卫星信号接收机、光纤信号解码器、信号源切换器等重要设备。若这些设备发生故障,很可能致使广播电视节目信号中断,导致频点静音静帧等现象,造成停播事故。台站原有的电源复位器功能单一,自动化程度低,通道数量少,很多设备电源接入到同一通道上。若某个设备故障需要复位重启,对该设备接入的通道复位时,整个通道的设备都会被复位重启,这样就有可能导致其他设备工作异常,造成停播现象。因此,可以采用一个新的解决方案,即采用USB-HID控制信号源系统设备电源。USB-HID是基于USB通信的,与电源复位器通信方式不同,后者采用网络通信,两者互不影响,因此还可以串联组合运行。
USB-HID是Universal Serial Bus-Human Interface Device的缩写,HID设备通常是鼠标、键盘、游戏手柄等,不过HID设备并不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。HID通信相对简单,响应快,所以比较适合用作控制设备。交换的数据需要存储在称为报表(report)的结构内,设备固件必须支持HID报表格式。相对其他USB设备,HID主要由控制传输和中断传输来传送与接收数据。报表的格式非常有弹性,可以处理任何类别的数据。HID类别设备的规范是Device Class Definition for Human Interface Devices①。另外还有一份文件 HID Usage Tables②,用来定义让主机了解以及使用HID数据的数值。
二、HID底层通信
现有资源为一块HID继电器控制板,配套资料是一份DLL及其头文件,没有源码,根据现有资源进行反汇编学习HID通信原理。使用OllyDbg对该DLL进行调试。图1是OllyDbg调试界面,区域1是反汇编指令窗口,第一列是地址栏,第二列是机器码,第三列是汇编代码,第四列是注释,汇编指令众多但是常用的很少,这点服从二八定律,少量的指令完成大部分功能。区域2是CPU寄存器窗口,最重要的是前面9个寄存器,这9个寄存器保存着当前程序段的运行参数、结果等重要信息,各个寄存器的说明详见参考文献③。区域3是数据窗口,在这里查看内存数据,常量数据一般都存放在此处,例如常用数值、字符串等。在区域1和2中,右键一个地址指针即可跟随转存到这里查看该地址的内存数据。区域4是栈窗口,栈通常用于保存临时变量,栈操作push是将目标压栈,pop将栈顶弹出到目标。除了这两个操作还有栈对齐,保证栈顶指针为某字节的整数倍;升栈,分配局部变量空间;降栈,删除栈部分数据。
图1 OllyDbg调试界面
根据头文件分析DLL的导出函数及其传入参数类型和返回参数类型。调试过程中DLL所用到的Win32Api会被OllyDbg标示出来,可以从注释中看到是什么Api,而所用到的HIDDLL的Api没有标记,要手动添加注释信息。整个通信的建立过程都是基于Win32Api和HIDDLL的Api完成的。
经过耐心的跟踪调试得到如图2的通信流程图。其中SetupDiGetDeviceInterfaceDetailA函数连续调用两次,第一次获得required_size参数,第二次将required_size传入获得设备详细信息。CreateFile函数也是连续调用两次,第一次ShareMode参数为空,如果是鼠标、键盘等独占设备是不能通过CreateFile打开的,将会在此返回失败,相当于在此过滤鼠标、键盘等独占设备;第二次ShareMode参数为3,函数成功返回HID设备句柄,设备句柄是与设备通信的唯一标识。通信阶段使用DeviceIoControl函数向HID设备发起查询请求,获得特征报告(Feature Report),该设备自定义的序列号就在特征报告里面,继电器状态也包含在特征报告里。HidD_SetFeature函数用于发送特征报告,设置继电器状态。
图2 流程图
三、固件
固件开发过程需要用到Bus Hound。Bus Hound是一个USB通用的强大的调试工具,类似于网络抓包工具,用于抓取电脑总线数据,还可以模拟发送请求数据。图3是Bus Hound调试界面。21.0表示21号设备端点0,CTL表示主机发送控制请求,请求内容为其后的Data,GET DESCRIPTOR表示该请求为获取描述符。IN表示设备发送数据到主机。图中的数据是设备上电枚举阶段发生的数据交换。共四条GET DESCRIPTOR,第一条描述符为设备描述符,第二条获取配置描述符长度,第三条根据长度再次请求配置描述符,第四条获取报告描述符。设备描述符和配置描述符为USB通用,报告描述符为HID传输的数据用途(usage)上的说明。至此,获得了HID固件关键的三个描述符。报告描述符的用法和修改参照HID Usage Tables。官网还有报告描述符工具提供使用。
图3 Bus Hound调试界面
MCU采用stm32f407vet6,从stc官网获取HID固件库④。使用固件库参照HID协议进行修改调试。这里的主要问题是我们沿用旧设备的数据交换方式,即特征报告(Feature Report),上位机发送请求特征报告失败返回0xC0000004,查询HID协议找到7.2 Class-Specific Requests(特殊请求),7.2.2 Set_Report Request有说明“A device might choose to ignore input Set_Report requests as meaningless.”,由此得知固件默认不处理特征报告。因此要添加对特征报告的处理,7.2 Class-Specific Requests查找发现7.2.4 Set_Idle Request这一请求是处理成功的。于是在固件库找到Set_Idle Request的处理,在其同级增加条件分支完成添加特征报告的处理,使用端点0收发特征报告数据。
四、数据库
台站主控电脑使用SQL Server处理数据,各个设备状态被相应的上位机实时更新到数据库,通过查询数据库获取设备状态,相当于借助数据库与其他上位机进行进程间通信。
为模拟相关环境在自己电脑上安装SQL Server和SSMS。添加数据库和数据表,添加数据元组示例。客户端对数据库的操作只有读取,因此采用sqlcmd命令行获取数据比较简便,使用popen函数执行命令行获取返回的数据。sqlcmd的使用比较简单,需要的参数有-S服务器、-U用户名、-P密码、-d使用数据库名称、-Q查询命令(sql查询语句)。图4为在我的电脑的模拟环境中进行查询得到的结果。
图4 命令行查询数据
五、端口拓展
为了获得更多的控制通道,以及预留IO口做其他用途,使用74HC595进行端口拓展。74HC595是8位串行输入/输出或者并行输出移位寄存器,具有高阻、关、断状态。图5是其真值表。通过将串行数据输出管脚SQH级联到下一个74HC595的SI输入管脚达到加长拓展。OE拉低SCLR拉高,需要控制的有时钟输入SCK、锁存信号RCK和数据源SI,只需要三个MCU IO口即可控制数位寄存器状态。最后通过ULN2803驱动继电器。
图5 74HC595真值表
六、客户端
客户端工作流程如图6所示,实现自动控制和接管控制。综合考虑数据库查询压力和信号快速恢复,设定每秒查询一次设备状态。使用MFC对话框设计一个简单的界面,添加接管按钮、各个设备开关按钮,在初始化函数中链接底层通信DLL,完成客户端的开发工作。
图6 客户端工作流程
七、总结
自动控制只开发了信号源部分,实现发现切换器故障无输出关闭切换器电源,发现设备通信异常重启复位恢复通信等功能。手动控制支持更多端口,可以控制其他设备,例如,乡镇熊猫数字电视发射机无输出,控制其复位。
注释:
①Device Class Definition for Human Interface Devices.
②HID Usage Tables.
③刘颖东.揭秘数据解密的关键技术[M].北京:人民邮电出版社,2009.
④STM32F10xxx USB-FS-Device firmware library.