自己编写wince的校准程序

2009-12-22 22:32

http://hi.baidu.com/lihuanhai1943/blog/item/2ccc99fa599d3e14a9d3117f.html

众所周知,wince有自带的校准程序,只调用一个TouchCalibrate()函数就OK了,正是因为这种方便性,高度的封装性,引出了我今天的话题,高度的封装,预示着开发者修改的空间非常的少。

         项目的需求,需要改写校准时的语言显示,例如我的程序中现在是中文,那么校准时必须显示的提示就是中文,同样的是西班牙语,那么提示也必须是西班牙语。但是在TouchCalibrate()是不会有参数来供用户调用和修改的,所以校准时的提示都是在内核中编译好的, 他是通过资源文件来调用的,校准提示,都会编译到GWES.exe(在你的编译内核的目录下)文件中,大家可以通过PB打开GWES.exe,可以在string table里看到。当然这里显示的语言种类是根据你设置的系统默认语言是什么有关了,例如你在编译内核时默认的语言是西班牙语,那么你的校准提示就是西班牙语了。但是如果应用中选择了别的语言,应用中的显示改了,但是校准时调用的还是西班牙语,所以出现了冲突的问题。

      下面的流程是根据我接到此工作后,考虑流程来写的:

       首先看到MSDN中有篇帮助“how to replace Calibrate Moudle”,从文章中可以看出来,微软没有提供校准程序的源码,而只提供了校准时的UI界面的代码,即:CalibrateUI ,大家可以根据MSDN,step by step,最终克隆出一个CalibrateUI的文件,供大家修改,可是灾难性的东西来了,每次修改都需要重新“Sysgen”,哪怕只是在CalibrateUI.cpp中加一句打印函数,并且你要想修改它中的那个.rc文件,更是苦不堪言啊。在这里如果通过自己编写资源文件的方式,然后只是修改CalibrateUI.cpp可能能做到上述项目的需求,没有实验,供大家讨论吧。(大家若不想一遍一遍的Sysgen,可以自己编个小程序先试,成功了,直接移植过来,在Sysgen一下,应该高效点,否则...)。如果想用此种方法,跟大家提供一篇被转烂了的帖子,http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece763104e8a3a5254826136c0d0622f8ace1dd2260607506694ea7a7d0d1096983c310efe1a02b1a076356c1421c78ccffc5ddccbc37672d47023716c914165c418df8b1164d620e10bb4ed52f0bb8025e5aec5a3af4352ba44757f9786fd4d0164dd1ff7034195b19838025f17adec4020a405267e982142a14689f732691081879f0c099e6a892053c4fe62f12912c404a4180c2534fd0da6082031379458268f126a45c9be01f02b091c70e91fa4b8b1a1eb4f9bdc9b60cba490ff6f&p=8065c64adc8816e008e291371e&user=baidu

但里面好像有个错误“再提醒一点,如果改了CalibrUi_clone.rc,要再次手动将上面两文件夹中的CalibrUi_clone.rc替换。”两个文件夹中根本就没有.rc文件啊,只有.res文件,是不是写错了,不知道转载的人们是不是也这样觉得。不管了,进行下种方法的考虑,自己编写校准程序。

。。。。。。。。。。。。。。。。。。。(搜集资料中)

          大家可以通过MSDN搜索“Touch Screen Driver Development Concepts”,里面有校准的步骤:

         The following steps detail the basic algorithm that you, the driver developer, can use to sample and calibrate the screen with the touch screen driver:

  1. Call the TouchPanelEnable function to start the screen sampling.
  2. Call the TouchPanelGetDeviceCaps function to request the number of sampling points.
  3. For every calibration point, perform the following steps:
    1. Call TouchPanelGetDeviceCaps to get a calibration coordinate.
    2. Draw a crosshair at the returned coordinate.
    3. Call the TouchPanelReadCalibrationPoint function to get calibration data.
  4. Call the TouchPanelSetCalibration function to calculate the calibration coefficients.

   这是你用微软提供的函数,自己写一个校准程序的基本流程,感觉问题忽然变的简单了,于是照着这个流程,自己实现了一个小程序,但是很快问题出现了,每次等待校准时都失败,于是到TouchPanelReadCalibrationPoint()函数中,探索究竟,此函数一般放在tchmain.cpp文件中。

     通过读这段代码,发现了一些问题,校验失败的原因是WaitForSingleObject( hCalibrationSampleAvailable, 10000 );等待超时,(微软实现的这个地方原先是INFINITE ,会无限制的等待,项目需求改为等待十秒钟),经过查找分析激活hCalibrationSampleAvailable事件的地方应该是TouchPanelpISR()函数,即触摸屏中断服务线程, 最终通过打印发现,CalibrationState 变量问题,

CalibrationState 在tchmai.cpp中是全局变量,在TouchPanelReadCalibrationPoint()等待之前,会把CalibrationState 置为CalibrationWaiting状态,然而在中断服务线程中CalibrationState 的值仍然为初始化的CalibrationInactive(0),所以TouchPanelpISR()一直不能进入校准状态更不用谈校准事件hCalibrationSampleAvailable的激活了,搜遍所有的地方,CalibrationState 的改变绝对应该是在TouchPanelReadCalibrationPoint()这里改的。去网上搜索发现了两个人跟我遇到了同样的问题,一个没有解决,另一个认为是静态映射中断和动态映射中断的问题,说静态映射中断就不会出现此问题,但是我试过这种方法最后还是不行,(不知道他是在做什么应用,当时是可行的),通过这篇帖子坚定了我的信心,至少这种奇怪的问题不是个案,有同盟了,呵呵,并且进一步分析到,既然是触摸屏的中断,在系统启动的时候就已经启动了,并且是动态映射的中断,猛然间发现,刚才根据MSDN写的校准流程有个TouchPanelEnable,跟进函数发现,它的里面重新动态映射了触摸屏中断,并且重新启动了中断服务线程,所以会产生一个物理中断号会有两个逻辑中断号,这样程序肯定会乱掉,所以拿我的程序跟系统自带的校准程序,打印做一下对比,发现,自带的校准程序果然没有调用TouchPanelEnable

       终于发现了个问题,动身去砍掉TouchPanelEnable,再试,狂晕,校准时,根本就没有等待十秒钟,一下子就失败。打印WaitForSingleObject( hCalibrationSampleAvailable, 10000 );的错误处理信息,发现,返回值是WAIT_FAILED,失败了,怎么会,再打印hCalibrationSampleAvailable的事件值(用到的地方都打出来),结果类似于CalibrateState的问题出现了,中断服务线程函数中的时间值,跟TouchPanel

ReadCalibrationPoint()函数中的hCalibrationSampleAvailable不一样,为什么会出现不一样的可能行呢,难道不在一个地址空间,根本就是风马牛不相及的两家,而不是一家人。最后事实证明这个猜测是正确的。

。。。。。。。。。。。。。。。。(极度痛苦的探索之旅)

      最终还是从对比入手,那我的程序跟自带的校准对比,非对出点东西来,最终打印和load 库的信息发现,我的程序比标准的地方多打印了两个地方一个时加载了touch.dll,另一个是”Touchpanel DRV :LCD Size= X*X ,I2C Channel Num(X)“,通过第二个打印发现,就是在加载touch.dll的时候出现的打印。

       这个问题需要考虑一下了,为什么他不需要加载,而我的程序要加载,GWES.exe在启动的时候已经加载了touch.dll,通过remote process viewer(Pb自带的工具),就可以看到,那么系统自带的校准是不是就是用的GWES.exe来调用的,所以就不用加载了,而我的.exe程序是需要加载才可以利用。那么GWES.exe和我的.exe程序是完全不同的两个进程,而只是用到了一个动态库touch.dll,每个进程有单独的地址空间,所以说以上的猜想是正确的,他们确实是风马牛不相及的两个空间。这样遇到的所有怪事都可以解释的通了。

。。。。。。。。。。。。。。。。。。。。。。。

     问题找到了,解决的办法呢,棘手的问题,这怎么办呢,大家都知道,每个进程加载.dll的时候都会单独给他Copy一份,考虑到两个进程如何共享.dll的部分变量呢,如果可以的话,就把CalibrateState和那个事件等用到的变量作为共享变量,然后在我的程序中负责,填写和得到变量的值达到控制GWES.exe中校准流程的目的,问题就解决了。所以两个进程共享动态链接库中变量的问题摆在了我的面前,别无他法,网上搜吧,功夫不负有心人真让我搜到一种方法,下面介绍给大家:

           #pragma data_seg("sharename")
          int count=0;
            #pragma data_seg()
            #pragma comment(linker,"/SECTION:sharename,RWS")

上面的count就是在.dll文件中共享的变量了,这里必须注意,count一定要初始化,原因不说了,但是切记。另外sharename一定要与comment中的sharename一致,才使得时候不会用,上面的要修改的地方,有两个地方:

        1:变量换成你要共享的变量,当然可以有多个变量,我的例子中就可以把事件和那个校准状态放到里面。

        2.sharename改成你任意喜欢的英文名字。注意有两个sharename,当然你也可以直接用sharename而不用修改。

       抓紧试试,果然OK!!!狂喜。校验成功。

       然而革命还没有成功,看一下注册表,狂晕,CalibrationData,没有写上,本来认为TouchPanelSetCalibration之后会自动给填上,后来在网上狂搜CalibrationData的数据如何通过校准得到,得到了之后才可以写到注册表啊,但是没有这方面的东西,看着像五个采样点的A/D 数据,网上的一个网友证实了我的想法,问题太简单了,大家都不愿意说了呵呵。这是经过我公司大牛的指点,让我打印一下AD值,看一下,我发现在系统自带的校准程序,打印出的五个点的AD值正是CalibrationData中的五个值,分别为:中、左上、左下、右上、右下。TouchPanelReadCalibrationPoint 函数得到的点就是五个AD采样值,惭愧,废话少说,写入注册表。这时才明白TouchPanelSetCalibration函数是为了这次校准生效,每次开机时,系统都会读取注册表中的CalibrationData数据,然后TouchPanelSetCalibration进行校准操作,使生效不用每次再进行校准。

       帖子到此为止了,竟然披着被子写了近两三个小时,希望大家能把一些网上少见的开发方面的东西,开发出来后,写一下,为后人能少走一些弯路,大家都是同道中人,何必为了一点小小的利益,而形成恶性循环,导致做一些重复性的错误处理。

      忙中可能出错,欢迎大家批评指正!!!!!!!!!!!!!!!!!!!

posted on 2010-04-22 10:51  xilentz  阅读(1155)  评论(0编辑  收藏  举报