我們的機器雖然是 linux , 但並非相同 (亂改了很多東西) , 最頭痛的就是 key pad input 介面.這個介面不是使用 linux 的 input 方式, 反而有點像一般 MCU 的 getkey() 方式.
所以就比較難寫 AP. 要不時的檢查有沒有 key input , 導致正個 Test AP 結構混亂.
所以我想了一個方式, 這個方式有點像是 event-driven 方式, 每個測試程式當作一個 Frame (因為有自己的選單, 操作介面 , 所以我暫時稱為 Frame). 每個 Frame 有固定下列幾個 even-driven 介面:
void *frame_data;
int (*init_func)(void *arg);
int (*event_func)(void *arg,int key);
int (*timer_tick)(void *arg);
int (*exit_func)(void *arg);
簡單說明一下:
init_func => initial frame ,當這個 frame 被致能 (active) 的時候會先呼叫這個 initial .
event_func => 當有 key input 的時候會將 key value 透過這個 function 傳到 active 的 frame.
timer_tick => 每 一小段時間 (不是很準) 就會驅動這個 tick function , 可以在這個 function 中作一些 polling , timeout wait 等動作.
exit_func => 當這個 Frame 被 inactive 的時候會呼叫這個 function , 可以釋放 一些 resource .
主題來了, 每個測試 Frame 可能會增加 , 抽換 . 我想要做到每個測試 frame 都獨立, 並可以在 compile 的時候選擇要不要加入.想了想好像 kernel 的 driver init 動作 (module_init() function ). 如果我可以在 AP 中模擬 kernel 的 module_init() 方式 , 或許可以解決我的問題.
網路上google 了很多有關 kernel module_init() 的方式和 Trace 了一下 kernel source code 後, 發現也蠻簡單. 其實就是利用 compiler 的時候將 init 的 function point 放到一個 特定的 section 中, booting 過程由這 section 中取出 function point 然後執行它即可.
首先定義 frame_init() 的 macro function , 如下:
typedef void (*initlist_func)(void);
#define __initlist __attribute__((section("initlist")))
#define frame_init(fn) \
initlist_func __initlist_##fn##__ __initlist = fn
extern initlist_func __start_initlist;
extern initlist_func __stop_initlist;
要使用 __attribute__ + section, section 的名稱最好前面不要有 .xxxx , 通常 .xxxx 為預定的
section , 如 .code .text .data 等.
另外宣告兩個 start & stop point , 一般 GCC 會自動產生這兩個 point, 只要宣告拿來用即可.
使用上就是將init function 用 farme_init() 來宣告, 內容將 event-driven 的 function call 放入即可 , 如下:
void main_frame_register(void)
{
struct frame_function info;
DEBUG_MSG("");
// info.frame_index = -1; // Not need specifity.
info.frame_layer = 0;
info.frame_name = "MAIN_FRAME",
info.frame_item = NULL, // main menu is first frame , not need title.
//---- functions of main frame.
info.frame_data = (void *)&main_menu_data,
info.init_func = main_init,
info.event_func = main_event,
info.timer_tick = NULL,
info.exit_func = main_exit,
Register_Frame(&info);
}
frame_init(main_frame_register);
在程式啟動的時候進行這些 frame_init() code 的執行, code 如下:
for (init_fc_p = &__start_initlist ;
init_fc_p != &__stop_initlist ; init_fc_p ++)
(*init_fc_p)();
這樣就可以模擬 kernel 的 module_init() 的功能了,接下來就是處理如何 切換 frame , 和 派送 event-driven 對應的 function call 了.
沒有留言:
張貼留言