1. 程式人生 > >tslib 程式碼分析1

tslib 程式碼分析1

------------------------------------------------------------
author: hjjdebug
date: 2015年 10月 19日 星期一 17:21:49 CST
------------------------------------------------------------
tslib 程式碼分析

序言1:tslib 是開源軟體,c 語言寫成,架構完美,值得閱讀。
序言2:程式是用來處理資料的, 那麼,tslib 也不會例外,它處理的資料,就是ts裝置
讀出的資料,那麼我們看它怎麼處理。

分析例項: 本篇先分析ts_print_raw, ts_print 應用程式
************************************************************
一: ts_print_raw  例子
************************************************************
程式非常簡短,就是
struct tsdev *ts_open(char *devname),
tsconfig(struct tsdev *ts),
ts_read_raw(struct tsdev *ts, struct ts_sample *sample int nr),

後面就要分別解釋這三句了。
1. 開啟一個ts裝置,
分配一個tsdev 結構,開啟傳遞的裝置名稱就可以了。

************************************************************
2. 配置這個ts裝置
************************************************************
----------------------------------------
2.1:開啟ts的配置檔案,
----------------------------------------
2.1.1: 這個檔案的名稱是由環境變數TSLIB_CONFILE 提供
    如果環境變數為空,就用程式預設的。
2.1.2: 配置檔案有特定的格式,有空格和tab 分割為域,
    第一個域只能是module,或module_raw 關鍵字,後面的為名稱和引數。
2.1.3:分析配置檔案,
    然後通過ts_load_module(ts,module_name,param) 或者ts_load_module_raw 來把模組載入到記憶體,
    並配置ts 結構變數
    其中module_raw 是必須要有的。

----------------------------------------
2.2: 細看 static int __ts_load_module(struct tsdev *ts, const char *module, const char *params, int raw)
----------------------------------------
2.2.1: 目的,ts_load_module 還是為了構建ts裝置結構,
    它首先是進行靜態構建,若不成功再進行動態構建,
    成功後,將module資訊與ts裝置相關聯。
2.2.2: 靜態構建module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.1: 什麼是module,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
每一個module,是由一個module 名稱和module 初始化函式構成的,
靜態構建就是預先定義好了modules 變數,現在根據傳來的module 名稱,搜尋這個表,找到對應的初始化函式,
呼叫這個初始化函式,初始化函式會返回module結構指標。
static const struct {
    const char *name;
    tslib_module_init mod_init;
} tslib_modules[] = {};

具體的module 是由tslib_modules來定義的, 可惜,我們一個module 都沒有定義。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.2: module初始化函式是什麼?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
現在即沒有具體的module, 也沒有具體的初始化函式,但它們必須符合一定規範。初始化函式是這樣的一個函式原型.
typedef struct tslib_module_info *(*tslib_module_init)(struct tsdev *dev, const char *params);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.3: module_info 是什麼?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
module_info 被定義為一個連結串列,有next 指標,保留有ts裝置地址,動態載入庫handle,還有一項為option 指標
struct tslib_module_info {
    struct tsdev *dev;
    struct tslib_module_info *next; /* next module in chain */
    void *handle;           /* dl handle        */
    const struct tslib_ops *ops;
};

該option 指標指向2個函式指標,一個read, 一個finishi
struct tslib_ops {
    int (*read)(struct tslib_module_info *inf, struct ts_sample *samp, int nr);
    int (*fini)(struct tslib_module_info *inf);
};



----------------------------------------
2.2.3: 動態構建module.
----------------------------------------
動態構建module 是通過載入動態連結庫來完成的,它有很多優點,例如可以只加載所需要的module, 不使用的不載入。
要不怎麼叫動態載入呢!
2.2.3.1: 動態載入module 到記憶體。
是的,傳來的模組的名字就是要載入的動態庫的名字,通過dlopen來載入。通過dlsym找到module 初始化入口函式,
執行它,返回module 指標。

2.2.3.2: 什麼是架構
現在一個具體的module 都沒有,怎麼就開始寫出程式碼了(ts_load_module.c), 是的,這就叫架構,它要求將來要寫的程式碼
必須符合一定的規範,才能被已經生成的程式碼所認識。併為先前的程式碼所管理。
tslib模組的架構要求, 每個模組要有一個初始化函式,動態庫的匯出函式叫:mod_int
這就叫介面,是程式碼控制與實現的剝離。

----------------------------------------
2.2.4: 看一個具體的module, input.so.
----------------------------------------
對應的程式碼plugin下input-raw.c

2.2.4.1: 定義mod_init 符號
typedef struct tslib_module_info *(*tslib_module_init)(struct tsdev *dev, const char *params);
#define TSLIB_MODULE_INIT(f) TSAPI tslib_module_init mod_init = &f
TSLIB_MODULE_INIT(input_mod_init);
2.2.4.2: input_mod_init.
架構在load module 後執行input_mod_init 函式,該函式申請了一塊記憶體
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.4.2.1: 申請tslib_input 記憶體
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i = malloc(sizeof(struct tslib_input));
i->module.ops = &__ts_input_ops;
    
其中tslib_input 是包含 tslib_module_info 的結構, 它還有自己專有的屬性,開始均初始化為0

struct tslib_input {
    struct tslib_module_info module;

    int    current_x;
    int    current_y;
    int    current_p;

    int    sane_fd;
    int    using_syn;
    int    grab_events;
};

static const struct tslib_ops __ts_input_ops = {
    .read    = ts_input_read,
    .fini    = ts_input_fini,
};

module.ops 也已賦值,這樣以後可以通過結構指標呼叫到ts_input_read, ts_input_fini函式

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.4.2.2: 儲存tslib_input 專有屬性的數值
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ts_lib 庫還提供了一個功能,分析變數函式
庫: tslib_parse_vars(&i->module, raw_vars, NR_VARS, params)
它負責
把param賦值語句分割為左部和右部,然後
搜尋給定的表,與左部匹配,呼叫表的對應函式,為該函式傳遞右部資料
查詢的函式可能把配置的資料,儲存到模組子類的屬性中。
plugin:
static const struct tslib_vars raw_vars[] =
{
    { "grab_events", (void *)1, parse_raw_grab },
};
庫:
struct tslib_vars {
    const char *name;
    void *data;
    int (*fn)(struct tslib_module_info *inf, char *str, void *data);
};
plugin:
static int parse_raw_grab(struct tslib_module_info *inf, char *str, void *data)
{
    struct tslib_input *i = (struct tslib_input *)inf; //指標強制轉化為子型別
    根據字串和資料,將資料存入module 的擴充套件屬性中。

}

2.2.4.3: ts_input_read
就是從裝置讀取一個完整事件資料,然後根據ev.type,ev.code,ev.value 來儲存其資料
2.2.4.4: ts_input_fini
fini 就是釋放記憶體.


----------------------------------------
2.2.5: 具體的module, pthres.so
----------------------------------------
對應的程式碼plugin下pthres.c
看來程式碼我才知道,這是壓力閾值的意思。
直接看pthres_read 函式, 壓力比設定最小值小,或比設定最大值大,忽略之

----------------------------------------
2.2.6: 具體的module, variance.so
----------------------------------------
方差判定上次移動是否為噪聲的依據是,兩次的移動距離超過了delta,可能是噪聲
如果兩次都超過,則不是噪聲,而是快速移動。
----------------------------------------
2.2.7: 具體的module, degitter.so
----------------------------------------
去抖動是把最多4個取值按照一定的權重重新計算來返回結果
引數delta 的含義:
----------------------------------------
2.2.8: 具體的module, linear.so
----------------------------------------
它吧讀到的資料,與螢幕矯正的值進行了縮放
samp->x = samp->x * info->dev->res_x / lin->cal_res_x;

************************************************************
二: ts_print  程式碼
************************************************************
與 ts_print_raw 是一樣的分析
只是一個呼叫ts_read_raw, 一個呼叫ts_read.
ts_read_raw 只有一層,不會返回給其他module.
ts_read,則是->linear->degitter->variance->pthres->read_raw 這個鏈來處理資料