我設計的工廠測試載入器是CS結構的,在裝置端會有一個Server,再PC端會有一個Client,兩者進行互動完成測試。
通訊方式選擇:
1.Stocket:優點是不基於ADB,可以自己定義介面,相對穩定,在Android2.3以前似乎多數的測試載入器都是使用這個方式,需要在裝置端跑起來一個S程式,等待接收命令。
2.ADB:優點方便,直接移植過來Android的ADBD的程式即可,加一些傳輸的資訊的D-CODE以及P-CODE即可,在Android2.3以後ADB逐漸穩定,我覺得使用這種方式更加方便。
PC端:視窗設計需要簡明,簡單,按鈕大,方便工廠測試工人的操作;與工廠產線的介面需要開放,擴充性好。(推薦使用VC開發)
裝置端:設計需要擴充性強,穩定,(使用C開發)
我主要做的裝置端,就說說裝置端的設計吧:
先確定你需要測試的模組,在確定你需要測試模組的相關功能,這樣把每個模組分開,可以盡量的模組之間的幹擾。
main.h
- #define CMD(cmd) extern int cmd##_main(char**, int, char*);
- #include<DefineCommand.h>
- #undef CMD
- typedef int (*mode_main_func)(char** argv, int argc, char* send_buff);
- typedef struct _MODE
- {
- char* name;
- mode_main_func main_func;
- } MODE;
- MODE g_ModeTable[] = {
- #define CMD(cmd) { #cmd, cmd##_main },
- #include<DefineCommand.h>
- #undef CMD
- };
DefineCommand.h
- CMD(bt)
- CMD(wifi)
- CMD(nfc)
- CMD(fm)
- CMD(audio)
- CMD(headset)
- CMD(mic)
- CMD(speaker)
- CMD(camera)
- CMD(gps)
- CMD(touch)
- CMD(rtc)
- CMD(vibrator)
- CMD(imei)
- CMD(battery)
- CMD(charging)
- CMD(g_sensors)
- CMD(p_sensors)
- CMD(l_sensors)
- CMD(led)
- CMD(lcd)
- CMD(keypad)
- CMD(modem)
- CMD(sd)
- CMD(hdmi)
- CMD(small_camera)
- CMD(lcd_back_light)
- CMD(camera_flash)
main.c
- MODE* getMode(char* mode);
- int main(int argc, char **argv)
- {
- int ret = 0;
- MODE* tMode = NULL;
- char* mode_name = (char *)malloc(MODE_SIZE); //模組名稱
- char* func_name = (char *)malloc(FUNC_SIZE); //模組測試功能名稱
- char* send_buff = (char *)malloc(MAXBUFF);
- int func_val = -1, func_argc= 0;
- if (argc < ARGC_NUM) {
- //TCMD_LOGE(mode_name, func_name, COMMAND_ARGC_ERROR);
- return COMMAND_ARGC_ERROR;
- }
- stpcpy(mode_name, argv[1]);
- stpcpy(func_name, argv[2]);
- func_argc = argc - 3;
- tMode = getMode(mode_name);
- if (tMode) {
- func_val = tMode->main_func(argv, func_argc, send_buff);
- switch (func_val)
- {
- case COMMAND_UNDEFINE_FUNC:
- //TCMD_LOGE(mode_name, func_name, COMMAND_UNDEFINE_FUNC);
- ret = COMMAND_UNDEFINE_FUNC;
- break;
- case COMMAND_ARGC_ERROR:
- //TCMD_LOGE(mode_name, func_name, COMMAND_ARGC_ERROR);
- ret = COMMAND_ARGC_ERROR;
- break;
- case COMMAND_EXEC_FAILE:
- //TCMD_LOGE(mode_name, func_name, COMMAND_EXEC_FAILE);
- ret = COMMAND_EXEC_FAILE;
- case COMMAND_EXEC_SUCCESSFUL:
- //TCMD_LOGI(mode_name, func_name, "Successful.\n");
- ret = COMMAND_EXEC_SUCCESSFUL;
- break;
- default:
- //TCMD_LOGE(mode_name, func_name, COMMAND_UNKNOWN_ERROR);
- ret = COMMAND_UNKNOWN_ERROR;
- break;
- }
- } else {
- //TCMD_LOGE(mode_name, func_name,COMMAND_UNDEFINE_MODE);
- ret = COMMAND_UNDEFINE_MODE;
- }
- return ret;
- }
- MODE* getMode(char* name)
- {
- MODE* tMode = NULL;
- int i = 0;
- int mode_num = sizeof(g_ModeTable) / sizeof(MODE);
- for (; i < mode_num; ++i) {
- if(!strcmp(name, g_ModeTable[i].name)) {
- tMode = &g_ModeTable[i];
- TCMD_LOGD("Mode_table.name = %s", tMode->name);
- break;
- }
- }
- return tMode == NULL ? NULL : tMode;
- }
然後就進入到各個模組的的main中執行了,例子battery.c
- int battery_main(char** argv, int argc, char* send_buff)
- {
- int ret = 0;
- char* func_name = (char *)malloc(FUNC_SIZE);
- stpcpy(func_name, argv[2]);
- if(!strcmp(func_name, "--info"))
- ret = battery_read_info(argv, argc, send_buff);
- else
- ret = COMMAND_UNDEFINE_FUNC;
- return ret;
- }
分兩種的測試方式,一種是直接操作kernel提供的sys測試節點,比如Touch Sensor Battery Rtc都可以這樣搞,但是像Audio Camera BT/WIFI/GPS Modem這樣的大型模組就不太好這樣測試了,需要調用相關的測試模組,這樣就需要進程之間的通訊,我使用的recovery中recovery與updater之間的方式,pipefd。
舉例子,測試modem的時候:
- int modem_read_imsi(char** argv, int argc, char* send_buff)
- {
- int ret = 1;
- const char* binary = MODEM_ADAPTER;
- TCMD_LOGI(argv[1], argv[2], "Test to start...\n");
- if ( argc != MODEM_READ_IMSI_ARGC)
- ret = COMMAND_ARGC_ERROR;
- else {
- int pipefd[2];
- pipe(pipefd);
- const char** args = (const char**)malloc(sizeof(char*) * 4);
- args[0] = binary;
- args[1] = IMSI;
- char* temp = (char*)malloc(10);
- sprintf(temp, "%d", pipefd[1]);
- args[2] = temp;
- args[3] = NULL;
- ret = exec_binary(binary, args, pipefd[0], pipefd[1], send_buff);
- }
- return ret;
- }
- int modem_main(char** argv, int argc, char* send_buff)
- {
- int ret = 0;
- char* func_name = (char *)malloc(FUNC_SIZE);
- stpcpy(func_name, argv[2]);
- if(!strcmp(func_name, "--imei"))
- ret = modem_read_imei(argv, argc, send_buff);
- else if(!strcmp(func_name, "--ue_version"))
- ret = modem_read_uversion(argv, argc, send_buff);
- else if(!strcmp(func_name, "--imsi"))
- ret = modem_read_imsi(argv, argc, send_buff);
- else if(!strcmp(func_name, "--echo"))
- ret = modem_get_status(argv, argc, send_buff);
- else
- ret = COMMAND_UNDEFINE_FUNC;
- return ret;
- }
- int exec_binary(const char* binary, const char** cmd, int fb_p, int fb_c, char* send_buff)
- {
- pid_t pid = fork();
- if (pid == 0) {
- close(fb_p);
- execv(binary, (char* const*)cmd);
- _exit(-1);
- }
- close(fb_c);
- FILE* from_child = fdopen(fb_p, "r");
- int size = fread(send_buff, 1, MAXBUFF, from_child);
- if ( size <= 0)
- return COMMAND_EXEC_FAILE;
- int status;
- waitpid(pid, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- return COMMAND_EXEC_FAILE;
- return COMMAND_EXEC_SUCCESSFUL;
- }
這樣設計的好處就是如果測試相關模組出現問題,不用修改測試載入器,直接更新模組的binary即可。
這就是我設計的工廠測試載入器,設計與開發大概不到2星期,相關模組的整合在一個月做完,但是由於公司項目黃了,沒有用到,但是我還是從中學習到了好多知識,感謝指導我思路的老宋,大牛!