文献标识码:A
DOI:10.16157/j.issn.0258-7998.2017.02.029
中文引用格式:王嘉骏,杨录,韩志毅,等. 车架号码区域隐藏焊缝检测系统的定位装置[J].电子技术应用,2017,43(2):120-123.
英文引用格式:Wang Jiajun,Yang Lu,Han Zhiyi,et al. The positioning device for the detection system of the frame number area hidden weld[J].Application of Electronic Technique,2017,43(2):120-123.
0 引言
车架号码是由阿拉伯数字和字母组成的17位编码,对车辆具有唯一识别性,因此被称为“汽车身份证”[1]。被盗车辆的车架号码区域通常会被整体抠掉,并重新焊接刻有伪造车架号码的钢板,再通过打腻子和喷漆的方法隐藏焊缝,从而逃避交警的追查[2]。针对这种情况,现常使用超声无损检测技术,通过分析超声回波来判定车架的完整性。但是,这种方法仅可作为一种甄别手段,对于刑事诉讼仍缺少有力的证据。所以,本文将通用鼠标改造成一位置传感器,在检测过程中对隐藏焊缝进行定位,再结合超声回波信号,生成对检测区域内部结构的俯视灰度图,进一步判断车架的完整性并提供有力证据。
在对车架区域检测扫描的过程中,为了获得检测区域内部结构的俯视图,须实时获得超声探头的二维坐标。本文通过将编写的下层过滤驱动程序安装到USB(通用串行总线)鼠标,使其成为一个虚拟的位置传感器来实现定位。最终,检测系统将采集到的超声回波信号和相应的探头位置信息匹配,实现实时计算检测过程中超声探头的运动轨迹和生成检测区域内部结构的俯视图,并使得检测设备具有便携和灵活的特点。
1 USB鼠标驱动模型
1.1 Windows驱动模型概述
Windows驱动程序在Windows主机应用程序和物理设备之间采用了灵活的分层驱动方式。分层式的结构具有很好的可移植性和兼容性,开发者可利用已有的系统驱动程序来开发满足客户需要的驱动程序。
在标准的Windows系统驱动程序分层结构的模型中,功能驱动程序和总线驱动程序是两个最为重要的驱动程序。其中,总线驱动程序负责主机和硬件设备的连接,由操作系统提供,用户无须干预。功能驱动程序是用户根据需要自己开发,一个完整的功能驱动程序包含多个例程,当Windows系统接收到一个IRP(I/O请求包)时,系统就会调用相应的驱动程序例程来执行操作。
有些设备还需要安装过滤驱动程序,过滤驱动程序根据功能的不同分成上层过滤驱动程序和下层过滤驱动程序两种。其中上层过滤驱动程序作用于功能驱动程序之上,为指定设备提供附加的功能支持。下层过滤驱动程序作用于功能驱动程序之下,且数据须经过下层过滤驱动程序处理后再向下传输[3]。
这样下层过滤驱动程序可以对数据进行捕捉、修改或者拦截的操作,进而重新定义硬件行为。本文就是使用这类过滤驱动程序来开发位置传感器。
1.2 HID USB鼠标的驱动程序设备栈模型
图1是USB鼠标在Windows系统环境中的访问流程。在图中,一个HID类应用程序可以调用含有系统HID类驱动程序hidclass.sys的HID类设备栈。HID类驱动程序又调用HID小驱动程序和硬件设备进行USB通信,在访问过程中需要经过下层过滤驱动程序hidparse.sys进行语法分析。
当USB鼠标插入到计算机后会先经过USB栈被识别为USB设备,因为它也是HID类设备,所以系统会同时装入HID类的驱动栈;当HID类驱动程序通过HID小驱动程序hidparse.sys读取到USB鼠标的报告描述符时,系统依据对报告描述符中usage项的判断,识别当前设备为鼠标。因此鼠标驱动程序也会在HID类驱动栈之上的位置装入系统,这样完整的驱动程序栈装入完毕。此时,USB鼠标就可以正常的工作了。随后Windows系统利用Win32函数以光标的形式将USB鼠标的位移信息表现出来,这就完成了对USB鼠标的操作。
2 USB光电鼠标映射为虚拟的位置传感器的开发思路
2.1 USB 鼠标过滤驱动程序的开发思路
本文的目的是利用USB光电鼠标获得精确的位置信息,但光电鼠标作为操作系统的独占设备,只允许Windows系统对其访问,所以需要拦截并改变它的报告描述符使它成为自定义的新设备。HID类驱动程序与USB栈对话会调用小驱动程序,小驱动程序又通过产生内部IOCTL(I/O控制码)来使能USB类驱动程序,进而可获得设备的报告描述符。当设备是鼠标时,报告描述符中的usage项的值是2,如果将它改为0,操作系统就不会再将它识别为鼠标,也就不会再有装入鼠标驱动栈的操作。所此, 本文的工作就是编译一个下层过滤驱动程序usbfilt.sys来拦截USB鼠标的报告描述符并修改其中usage项的返回值,使系统不会将它识别为鼠标, 这样用户态程序就有权利对新定义的设备进行控制和访问。
2.2 I/O请求包和IRP处理
I/O请求包是Windows系统所使用的与内核模式驱动程序通信的一种数据结构,其中带有一组I/O管理器例程且可对I/O请求包进行操作。I/O管理器依据请求内容的不同来选择相应的设备对象和驱动程序对象,同时生成相应的IRP发送到对应的驱动程序中来执行特定的操作,驱动与驱动之间通过IRP进行通信。
IRP是从非分页内存中定义分配的大小可变的结构,它由IRP首部和可变数目的辅助请求栈单元组成。IRP首部由当前拥有IRP的驱动指针、指向IRP输入输出缓冲区的指针等组成。之后是一个IO_STACK_LOCATION结构的栈单元,栈单元中保存着一个I/O请求的参数以及代码、完成函数指针请求、当前对应的设备指针等。当多个驱动程序处理一个IRP时,就会生成多个IRP栈单元。不同驱动程序需从其所指向的IRP栈单元中读取到相应的IRP参数。如果需要把IRP沿当前被访问设备的驱动程序栈继续传递下去,下一个栈单元的参数必须被正确设置。向下传递的IRP所对应的参数必须不同于正在处理的IRP。
当一个I/O请求包生成一个对应的IRP时,IRP首部和第一个IRP栈单元将首先被I/O管理器设置。IRP中含有很多问题需要驱动程序进行处理,所以当一个IRP生成时,就会被传递到当前访问设备的驱动程序栈的栈顶,随即会被从上而下进行相应的处理,如图2所示。
IRP的处理是从最顶层驱动程序1开始,通过调用函数IoGetCurrentIrpStackLocation来使I/O管理器栈单元指针指向当前栈单元。如果IRP需要继续向下传递到驱动程序2,这时驱动程序2的栈单元需驱动程序1设置它的参数,并通过函数IoCallDriver来被调用,同时新生成的栈单元地址会映射到I/O管理器栈单元的指针, 然后过滤到的符合条件的IRP 将会被驱动程序2 处理,之后以同样的方式向下传递直到所用的驱动程序处理完毕。当IRP包含的问题处理完毕,最后的驱动程序4 通过调用函数IoCompleteRequest 来标识当前IRP为已经完成处理, 随后沿着设备栈将IRP向上传递, 最终到达栈顶弹出,回到用户。
3 过滤驱动程序的开发
3.1 过滤驱动程序主框架
DriverStudio是NuMega公司提供的驱动程序开发工具。在DriverWorks中提供一个过滤驱动程序的模板例程usbfilt[4]。在这个过滤驱动程序中,直接把IRP传送下去。本设计重点在于下面这个例程:
NTSTATUS UsbFilterDevice::InternalDeviceControl
(KIrp I)
{
T << "UsbFilterDevice::InternalDeviceControl\n";
if (I.IoctlCode() !=
IOCTL_INTERNAL_USB_SUBMIT_URB)
return DefaultPnp(I);
PURB p = I.Urb(CURRENT);
if(p->UrbHeader.Function!=URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE)
return DefaultPnp(I);
return PassThrough(I,
LinkTo(DeviceControlComplete), this);
}
需要重新定义的IRP会被上面的例程过滤到,并经过下面的完成例程处理,从而构成过滤驱动程序的主框架。
NTSTATUS UsbFilterDevice::DeviceControlComplete(KIrp I)
{
T <<"UsbFilterDevice::DeviceControlComplete\n";
PURB p=I.Urb(CURRENT);
if(p)
{
char* DeseriptorBuffer=
(char*)p->
UrbControlDescriptorRequest.TransferBuffer;
DeseriptorBuffer+=3;
if((*DeseriptorBuffer&0xff)==2)
{
*DeseriptorBuffer=0;
}
}
return I.Status();
}
在这个完成例程中定义了一个指向URB(USB请求块)缓冲区的指针DeseriptorBuffer,其中保存着设计所需要的报告描述符。在这个数组的第3个字节中保存着usage的值,然后需要对此值进行判断,如果是“2”就可以判定当前读取到的设备报告描述符是鼠标的,之后需要将此值改为“0”,这样就把读到的报告描述符改成了自定义设备的报告。重启设备后,当系统再次读到这个报告时就不会把USB鼠标当成标准设备而被系统独占了。相反,USB鼠标会作为自定义设备来使用。驱动程序经过DriverStudio在VC++6.0的编译运行后,生成了设计所需要的过滤驱动程序usbfilt.sys。
3.2 过滤驱动程序的安装
为了通过VC++6.0将过滤驱动程序准确地安装到某个设备上,应该通过GUID(全域唯一标识码)查找指定设备类下的硬件ID来决定是否需要安装过滤驱动。另外,由于该过滤驱动修改了报告描述符,导致最终的设备由原来的鼠标变成了HID兼容设备。所以需要先将原来的驱动卸载掉,然后才能安装过滤驱动;否则系统将还使用以前的驱动,也就不会出现新的硬件。安装过滤驱动的关键是以下几方面:(1)复制过滤驱动文件usbfilt.sys到当前系统的Windows\System32\Drivers目录下;(2)卸载旧的驱动程序,通过查找所有鼠标设备,查看是否有指定硬件ID的设备,如果有,则卸载它;(3)添加服务,调用OpenSCManager()函数打开SCManager数据库,然后调用CreatService()函数增加usbfilt服务;(4)更新设备过滤驱动程序名称列表;(5)重新启动设备,使主机识别新硬件。
3.3 获取信息的用户态应用程序开发
通过安装过滤驱动把一个标准的Windows系统USB鼠标改造成虚拟位置传感设备后,Windows系统就失去了对它独占访问的权利。利用VC++编写用户态应用程序对其进行访问, 读出它的位置信息为系统所用。
光电鼠标芯片是一种内部集成有图像采集系统(IAS)和数字处理器(DSP)的数字图像处理系统,通过图像处理实现二维平面的定位。图像采集系统通过芯片底部的感光眼不断对物体拍照,然后将图像信息发送到数字处理器,数字处理器首先提取每张图像信息中的特征像素,然后对相邻的两幅图像信息中同一特征像素的位置变化进行识别,进而间接计算得到两幅图像在拍摄时间间隔内USB鼠标的移动方向和位移大小,并把这些数值量化封装后,发送到鼠标芯片的固件中,进一步封装得到固定格式的报告描述符,最终通过USB接口送入计算机。
本文采用的鼠标芯片的输入报告描述符有5个字节。其中在第1、第2和第3个字节中储存着X、Y方向的坐标值以及左右键的状态,这3 个字节的具体结构如图3所示。需要注意的是:一方面在输入报告描述符中第2和第3字节是移动的相对坐标值,需在后续的程序中通过累加算法把它转换为鼠标移动的绝对坐标;另一方面,此设备被激励后使用的是右手坐标系。
要实时获得位置传感器的位置信息,需要循环读取位移信息。为了避免读操作时发生访问冲突失去响应,单独创建一个线程来高速读取输入报告。通过调用Windows提供的API函数库来识别并读取USB设备的数据,并定义一个缓冲数组存取输入报告描述符中的坐标值, 最后根据对鼠标设定的分辨率将得到的绝对坐标值转换为实际的位移大小。
4 实验结果及分析
将过滤驱动程序usbfilt.sys准确地安装到目标鼠标上。此时,重新启动设备,使主机识别新硬件。图4所示为在VC环境下编译的简易上位机,上位机可识别改造好的新设备,并显示必要的设备信息。
在车架的完整性检测工程中,超声探头和位置传感器在车架区域同步扫描。通过定义灰度值将超声回波信号可视化显示,即可生成一检测区域内部结构的俯视图。经实验检测,传感器定位精度可达到0.03 mm,完全满足本检测系统对于位置信息的精度要求。
5 结论
本文通过编写HID类下层过滤驱动程序将USB光电鼠标映射为一个位置传感器,实现了车架完整性检测过程中快速、准确定位隐藏焊缝,并进一步结合超声回波信号,生成对检测区域内部结构的俯视灰度图。为公安机关处理走私、盗窃车辆案件的刑事诉讼工作提供了有力证据,同时这种方法充分体现便携式检测设备轻便灵活的特点,具有很好实用价值。
参考文献
[1] 于吉刚,杨录,张艳花.便携式隐藏焊缝超声检测系统设计[J].仪表技术与传感器,2015(12):85-87,96.
[2] 武佳慧,杨录,张艳花.车架VIN码区域超声检测方法研究[J].电子技术应用,2014(8):80-82,86.
[3] 宫闽军.碳纤维复合材料孔隙率超声检测系统定位装置及可视化研究[D].杭州:浙江大学,2005.
[4] 李凌.碳纤维复合材料数字化超声检测系统关键技术研究[D].杭州:浙江大学,2007.
作者信息:
王嘉骏1,杨 录1,韩志毅2,赵 辛2
(1.中北大学 信息与通信工程学院 电子测试技术国家重点实验室,山西 太原030051;
2.太原市公安局,山西 太原030051)