多线程技术在数据实时采集分析中的应用
数字接口设备是实现标准422串行总线到自定义串行总线转换的专用通信设备。数字接口测试系统根据数字接口设备的工作原理,输出422串行数据和自定义串行总线的控制信号(YCK,YZM)给数字接口设备,并对其输出的串行数据(YDATA)进行采集、存储、分析和处理,从而达到对被测设备进行检测的目的。本数字接口测试系统共提供了八个测试通道,每个通道的422串行总线和自定义串行总线的相关参数都可由测试人员通过应用软件进行设置。为方便对数据进行分析,同时在软件上约定了发送的数据格式为:AA xx 01 23 45 67 89 AB CD EF 01 23… 10,其中帧头为0xAA,帧尾为0x10,xx为发送计数器值,每发送一次依次加1。应用软件通过相应的算法对自定义串行总线接收数据进行实时分析和处理,如:已经接收的字节数,共接收了多少帧数据,共出错有多少字节……并将结果在测试界面上动态显示,测试人员可以根据这些实时的测试结果来判断被测设备是否正常工作,一旦发现测试数据误码率太高,即可马上断电停止测试,防止被测设备烧坏。
系统实现方案
数字接口测试系统原理框图如图1所示。测试设备通过USB2.0总线与操作控制计算机进行连接,每台测试设备提供了八个通道的数据发送和接收单元,其中数据发送单元用于输出422异步串行数据,其波特率最高可达614.4 kbps,帧长可根据测试要求进行调整,每帧数据最高循环发送帧周期为5ms;数据接收单元用于产生自定义串行总线的控制信号YZM和YCK,并从YDATA读回数据,YCK和YZM最高分别可达1.6384MHz和25.6kHz。
由于测试过程中传输数据量大,且需要对采集回来的数据做实时分析,因此对数据的实时采集和分析采用多线程分别进行处理。应用软件中主界面线程主要负责完成人机界面操作,同时分别打开数据采集和数据分析两个线程来同步协调工作,为保证数据采集和分析过程的连续和数据完整,两个线程之间通过开辟高速内存缓冲区和内存映射文件的方式来实现高速数据流的一、二级缓冲。其中一级缓冲区实现对USB总线上传数据的缓存,用于实现接收的USB数据包按照各个通道进行数据分解;二级缓冲则按照通道号将分解输出的数据分别进行暂存,用于数据分析线程实现数据分析处理。整个方案中,数据包的上传、存储、数据分解、数据分析等操作均是在内存中完成,速度快,正确率高,再加上采用新的线程同步方法,既保证了数据采集线程高速数据吞吐量、数据分析线程的快速响应和实时分析,又保证了整个方案较高的性能和最低的系统开销。数据缓存处理如图2。
数据采集
为了实现USB返回数据的保存,在内存中构建了一个12k的高速内存缓冲区,12k的空间以512字节(一个USB数据包的大小)为单位平均分成24等份。多线程同步中常用信号量来控制访问某一共享资源的线程数,结合操作系统中生产者和消费者的思想可采用扩展信号量的方式来完成线程同步。数据采集线程操作时,12k高速缓冲区分别用读写两个信号量作为状态指示,对数据读入和输出进行控制。写信号量个数初始化为24个(表示有24个数据区间可写入),读信号量个数初始化为0个(表示有0个空间有数据需要读出),数据采集线程等效为生产者,数据分析线程等效为消费者。如图3所示。USB接口每返回一包数据,首先判断写信号量个数,为零则线程阻塞等待,不为零则实现数据写入操作,将USB数据包内容存入当前生产者指针(pWriteIndex)所指向地址的后512字节缓冲区中,完成后生产者指针加512,写信号量减1,读信号量加1,这是生产的过程。当线程切换到数据分析线程后开始消费(对采集回来的数据包分解处理),首先判断读信号量个数,为零(没有可消费的)则线程阻塞等待,不为零则由消费者指针(pReadIndex)来控制读取一包数据。一包数据读取完毕后消费者指针加512,读信号量减1,写信号量加1。由以上分析可知,整个12k的缓冲区在读写两个信号量的协调工作下不仅实现了数据采集和数据分析线程的同步,并且通过互锁机制保证了生产者指针和消费者指针不会指向同一块内存区域,使整个系统的可靠性得到显著提高。
数据分析
由于数字接口测试设备八个通道可同时工作,为了区别USB总线上传的数据包中的数据分别对应哪一个通道的数据,并满足数据传输的实时性要求,每个通道以64字节为单位将测试数据送入USB接口的内部缓冲区,其第一个字节用于标识随后63字节是哪一个通道的数据,分别用01,02……07,08进行标识。当USB接口的内部缓冲区填满512字节后即通过USB总线上传到计算机内存中的高速缓冲区。所以在数据分析时首先需要从USB数据包中提取每个通道回传的测试数据,然后与标准格式数据进行对比分析。可见若在长时间测试时,数据分析线程数据处理量大,任务繁重。为保证整个系统的实时性和数据分析准确性,测试接收回来的数据按照通道号不同分别保存在不同的内存映射文件中。
数据分析线程在读信号量和消费者指针的控制下成功读取一包数据后,根据通道标示号提取此包中每个通道的数据,写入对应的内存映射文件中,再调用数据处理函数对每个通道数据做误码分析。误码分析的结果可由主界面线程调用显示。数据分解流程如图4所示。
为了保证测试效率和数据处理的正确性,pWriteCounter既用于控制内存映射文件写入数据指针的移动,也用于判断已接收的数据字节数,作为数据处理时读内存映射文件指针的参考和是否开始对数据进行分析的条件。数据处理时,并不是内存映射文件中写入数据后就马上开始分析,而是根据pWriteCounter确定已接收的数据字节数,直到接收回来大于一个标准帧长度的数据后才开始对此帧数据的误码率分析,这样既避免了多次分析一帧数据,又保证了数据分析的正确性,而且减少了数据分析线程独占CPU的时间。从最终实际运行结果来看,此方法有效解决了数据实时采集过程中掉数据的问题。
数据经分解写入对应通道内存映射文件后,还需要实时地将每个通道接收回来的测试数据和标准数据进行对比分析,并以误码率形式进行显示,测试人员根据实时变化的误码率即可监测数字接口设备是否工作正常。数据分析处理流程如图5所示。在实际使用中,数字接口设备可能出现的故障现象较多,采集接收回来的数据量相当大且数据出错情况各不相同,不能误判或漏掉任何一种情况,通过反复测试得出以下对固定格式数据处理的方法:
①从每个通道的内存映射文件中逐个字节扫描帧头0xAA,一旦检测到帧头0xAA,进入第②步。
②首先判断此帧数据的帧尾位置是否为0x10,以及帧尾的前一个数据和对应的标准数据(标准数据帧尾的前一个数)是否相同,若同时满足这两个条件,说明此帧数据为标准帧(此帧数据长度和发送的标准帧帧长度相等),若不满足进行第④步操作。
③判断此帧为标准帧后,从此帧数据和标准数据的第二位开始到帧尾一一进行对比判断(跳过第0个帧头数据和第1个计数器数据),不相等则记录出错,每发现一处错误字节,错误字节数加1。进入第⑥步。
④从帧头到帧长度数据范围内查找是否出现0xAA,出现0xAA,首先用第②步操作判断此0xAA是否为下一帧数据的帧头,若是下一帧数据帧头,记录帧头前一个字节为此帧帧尾位置,说明此帧数据有掉数据现象,否则为错误数据,调用非标准帧处理。
⑤从此帧数据和标准数据的第二位开始到确定的该帧长度范围内数据进行一一对比判断 (跳过第0个帧头数据和第1个计数器数据),不相等则记录出错,并判断为错误一个字节。
⑥检查该帧中计数器数据与前后帧的计数器数据是否连续,如果连续则没有帧出错,否则有掉帧现象出现,需要根据前后计数器数据确定掉帧的长度,并转化为对应错误字节数。
同时接上两个被测设备验证整个系统的性能,即使每个通道均选择工作在最高波特率614.4 kbps和最高循环发送帧周期5ms下,仍能保证数据采集实时高速、数据质量稳定且误码率低。
结束语
实时测试与结果显示如图6所示。该技术已经成功应用于某数字接口设备的检测与维修系统,取得了良好的效果。经大量测试验证,此种多线程、内存映射文件和两级缓冲的方法在高速实时数据采集和分析中效果很好。根据生产者和消费者的思想建立的读写信号量有效地实现了采集和分析线程间的同步,内存映射文件的大小在开始测试前申请为100M,当需要更长时间测试时还可以动态申请开辟新的内存空间,既保证了系统的实时性要求,又有效节约了系统内存资源。