從校正方法來看,Android系統觸控式螢幕的校正一般分兩種:線性校準與三點(一般用五點)校準;從校正的位置來看,也分兩種,驅動層校準和android層校準。一般來講,從android層校正由應用軟體配合android層完成,靈活度比較高,也比較智慧化。隨時不准隨時校正。在這裡,詳細介紹android層的校正過程。



為了更好的瞭解校正的詳細過程,有必要瞭解一下觸控式螢幕資料的運動過程,至少校正的原則,由於涉及到特定的演算法,因此不在此報告中提及。



觸控式螢幕資料產生于Linux內核,在觸控式螢幕驅動中,通過AD轉換,把觸摸點記錄為一組組資料(觸控式螢幕座標),這個資料我們稱之為原始資料。這個原始資料非常的重要,畢竟我們的目標就是把這樣的一組組觸控式螢幕座標轉換為LCD座標。原始資料產生後,通過input_report_abs上報到android層。在android層會能過getX和getY捕捉到這一資料,再將捕捉到的資料通過reportData分發到視窗。



從資料的運動過程,我們大概知道校正要從哪入手了吧。校正的過程其它就是資料的截獲-修改過程。因為這裡介紹的是android層的校正,因此,我們需要在android層資料將資料截取。android層觸控式螢幕的資料是在/frameworks/base/services/java/com/android/server/目錄中的檔InputDevice.java截取的,因此需要在這個檔中增加一些代碼,用於截取原始資料並將原始資料進行校正。

到這裡,我們一直有一個大前提,那就是:1、Linux驅動層上報的是原始資料;2、對原始資料進行校正的校正係數已經產生。因此,在InputDevice.java中增加代碼之前,我們應該解決掉這兩個問題。



校正過程分四步完成:

1、觸控式螢幕驅動的修改

對第一個問題,我們需要對Linux層的觸控式螢幕驅動進行改動,以保證report的資料是原汁原味沒有進行過任何修改的資料

如果你使用的是進行過校正的觸控式螢幕驅動,需要注意兩個地方的修改:

第一處是:

if(xtmp < 0)

xtmp = 0;

else if(xtmp > TS_RESOLUTION_X-1)

xtmp = TS_RESOLUTION_X-1;



if(ytmp < 0)

ytmp = 0;

else if(ytmp > TS_RESOLUTION_Y-1)

ytmp =TS_RESOLUTION_Y-1;


以上代碼需要全部注釋掉,不注掉的結果就是當你用五點校準時,不管你怎麼點擊觸控式螢幕,觸控式螢幕都不會有反應。仔細看看這段代碼就知道了,這段代碼保證上報的資料在LCD座標範圍之內,這是在驅動層校正必寫的一段代碼,卻是我們進行軟體校正的綁腳石呵。

第二處是__init s3c_ts_probe中的一段代碼代碼:

if (s3c_ts_cfg->resol_bit= =12) {

input_set_abs_params(ts->dev, ABS_X, 0, TS_RESOLUTION_X, 0, 0);

input_set_abs_params(ts->dev, ABS_Y, 0, TS_RESOLUTION_Y, 0, 0);

}




需要修改成如下:()

if (s3c_ts_cfg->resol_bit= =12) {

input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);

input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);

}


道理跟上一段代碼一樣。如,我調試的6410板子採用的是12位轉換的,在系統啟動過程中,會看到這個的列印資訊:

I/KeyInputQueue( 58): X: min=0 max=4095 flat=0 fuzz=0

I/KeyInputQueue( 58): Y: min=0 max=4095 flat=0 fuzz=0


由此我們可以看出,對驅動進行修改的原則就是:保證驅動上報的資料是原汁原味沒有進行過任何修改的資料。



2、校正係數的產生

核下係數的產生是靠軟體來實現的,由於觸控式螢幕的校正演算法特定,因此校正應用程式是通用的。在這個應用程式裡要修改的地方有兩個,一是別忘了把螢幕的解析度改成需要的解析度。二是根據驅動層採用的轉換精度調整一下資料:

final int UI_SCREEN_WIDTH = TS_RESOLUTION_X;

final int UI_SCREEN_HEIGHT = TS_RESOLUTION_Y;



x1 = (int)(( event.getX() * 4095 ) / (TS_RESOLUTION_X-1)); //2^12-1=4095

y1 = (int)(( event.getY() * 4095 ) / (TS_RESOLUTION_Y-1));






這個部分需要注意的問題就是校正係數檔pointercal許可權的問題,需要在init.rc中給該檔的生成提供許可權:

chmod 0777 /data/etc

chmod 0644 /data/etc/pointercal




第一句是允許中/data/etc中生成pointercal檔,第二句是保證pointercal檔能被讀取。







現在可以在InputDevice.java中增加代碼了:

3、讀取校正檔

static void ReadPointercalFile(){

TransformInfo t = null;

try {

FileInputStream is;

if(custom_file_exist) {

Log.i("TS_DBG", "InputDevice.ReadPointercalFile:read CALIBRATION_FILE from /data/etc");

is = new FileInputStream(CALIBRATION_FILE2);

} else {

Log.i("TS_DBG", "InputDevice.ReadPointercalFile:read CALIBRATION_FILE from /system/etc");

is = new FileInputStream(CALIBRATION_FILE1);

}

byte[] mBuffer = new byte[64];

int len = is.read(mBuffer);

is.close();



if (len > 0) {

int i;

for (i = 0 ; i < len ; i++) {

if (mBuffer[i] == '\n' || mBuffer[i] == 0) {

break;

}

}

len = i;

}



StringTokenizer st = new StringTokenizer( new String(mBuffer, 0, 0, len) );



t = new TransformInfo ();

t.x1 = Integer.parseInt( st.nextToken() );

t.y1 = Integer.parseInt( st.nextToken() );

t.z1 = Integer.parseInt( st.nextToken() );

t.x2 = Integer.parseInt( st.nextToken() );

t.y2 = Integer.parseInt( st.nextToken() );

t.z2 = Integer.parseInt( st.nextToken() );

t.s = Integer.parseInt( st.nextToken() );

Log.i("InputDevice.ReadPointercalFile: ",

"t.x1=" + t.x1 + " t.y1=" + t.y1 + " t.z1=" + t.z1

+ "t.x2=" + t.x2 + " t.y2=" + t.y2 + " t.z2=" + t.z2 + "t.s=" + t.s);

} catch (java.io.FileNotFoundException e) {

custom_file_exist = false;

Log.i("TS_DBG", "FileNotFound!");

} catch (java.io.IOException e) {

Log.i("TS_DBG", "IOException");

}

tInfo = t;



4、截取原始資料,用校正係數進行校準

if (device.tInfo != null)

reportData[j + MotionEvent.SAMPLE_X] =

(device.tInfo.x1 * x_tmp +

device.tInfo.y1 * y_tmp +

device.tInfo.z1) / device.tInfo.s;

else

reportData[j + MotionEvent.SAMPLE_X] =

((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)

/ absX.range) * w;





if (device.tInfo != null)

reportData[j + MotionEvent.SAMPLE_Y] =

(device.tInfo.x2 * x_tmp +

device.tInfo.y2 * y_tmp +

device.tInfo.z2) / device.tInfo.s;

else

reportData[j + MotionEvent.SAMPLE_Y] =

((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)

/ absY.range) * h;








備註:為了保證pointercal順便的生成,還要保證鍵盤的正常工作。因為第一次用軟體校正,觸控式螢幕不好使,至少要有方向鍵我確定鍵保證能順利進行校正程式(當然第二次和以後就不需要了)。除此之外,還要保證MENU鍵的正常工作,因為校正程式最後一步需要MEUN鍵確認,只有觸認後才會生成pointercal檔。當然,如果你的按鍵本來就不夠用,確認的按鍵可以通過修改校正應用程式換成其它鍵。

Posted by shadow at 痞客邦 PIXNET 留言(0) 引用(0) 人氣()