android下調試3G之自動撥號
本章簡單講述下android實現自動撥號的功能,該功能利用了系統啟動的rild的服務來實現,因為rild的服務是殺不死的,所以利用這一點,可以使撥號失敗或網路斷掉後自動重撥,來增強上網的可靠性。這裡只實現撥號功能,把ril庫實現的一些功能都去掉了。
一、修改rild程式源碼
把 .../hardware/ril裡面的檔案全部刪掉,建立rild檔案夾,把以下面代碼放到建立的檔案夾下。
1、rild.c
#define LOG_TAG "RILD"#include #include #include #include #include #include "ril_fun.h"int main(int argc, char *argv[]){int opt;int err;pthread_t tid;char buf[PROPERTY_VALUE_MAX];static int device_fd;static char * device_path = NULL;umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); while ( -1 != (opt = getopt(argc, argv, "d:"))) {//用來分析main函數傳遞的命令列參數switch (opt) { case 'd': device_path = optarg; ALOGD("Opening tty device %s\n", device_path); break; default: ALOGD("Not tty device"); goto done; } }device_fd = device_open(device_path);//開啟裝置節點device_init(device_fd);//初始化裝置節點property_set("ctl.stop", PPPD_SERVICE_NAME);//設定pppd_gprs屬性為停止request_setup_datacall(device_fd);//繼續執行撥號pthread_create(&tid,NULL,ip_detection,(void *)device_fd);//建立查詢IP線程,使斷網後重新撥號done:while(1){sleep(0x00ffffff);}return 0;}
2、ril_fun.c
#define LOG_TAG "RIL"#include #include #include #include #include #include #include #include #include "ril_fun.h"#define PPPD_EXIT_CODE "net.gprs.ppp-exit"#define PPP_NET_LOCAL_IP "net.ppp0.local-ip"#define PPP_SYSFS_RETRY 5#define PPP_OPERSTATE_PATH "/sys/class/net/ppp0/operstate"static int pppd_started = 0;int device_open(char *device_path){int device_fd = -1;while (device_fd < 0) { if (device_path != NULL) { device_fd = open (device_path, O_RDWR);//開啟串口AT模組的裝置 } if (device_fd < 0) {ALOGD ("opening AT interface. retrying...");sleep(3);} }return device_fd;}void device_init(int device_fd){struct termios options;tcgetattr(device_fd, &options);//擷取串口屬性cfsetispeed(&options, B115200);//設定接收傳輸速率cfsetospeed(&options, B115200);//設定發送傳輸速率options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|IGNCR|ICRNL|IXON);options.c_cflag &= ~PARENB; //無同位位元options.c_cflag &= ~CSTOPB;//停止位為1位options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;//資料位元為8位options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);tcsetattr(device_fd,TCSANOW,&options);} int at_send_command(int device_fd, char *cmd){int ret;ret = write(device_fd, cmd, strlen(cmd));return ret;}void request_setup_datacall(int device_fd) {const char *apn = "cmnet"; char *cmd = NULL; int err; ALOGD("requesting data connection to APN '%s'", apn); if(pppd_started) {ALOGD("Stop existing PPPd before activating PDP");property_set("ctl.stop", PPPD_SERVICE_NAME);//設定pppd_gprs屬性為停止pppd_started = 0; } err = at_send_command(device_fd, "at$qcpdplt=0"); asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);//設定PDP上下文 err = at_send_command(device_fd, cmd); free(cmd); if (err < 0 ) { ALOGD("AT Send Command error!"); } err = property_set(PPPD_EXIT_CODE, "");//設定net.gprs.ppp-exit為空白 if (err < 0) {ALOGW("Set PPPD_EXIT_CODE failed!");goto ppp_error;} err = property_set(PPP_NET_LOCAL_IP, "");//設定net.ppp0.local-ip為空白 if (err < 0) {ALOGW("Set PPPD_NET_LOCAL_IP failed!");goto ppp_error;} err = property_set("ctl.start", PPPD_SERVICE_NAME);//設定pppd_gprs屬性為啟動 pppd_started = 1; if (err < 0) {ALOGW("Can not start PPPd");goto ppp_error; } ALOGD("PPPd started"); return;ppp_error: at_send_command(device_fd, "AT+CGACT=0,1");//PDP上下文去啟用 if(pppd_started) {property_set("ctl.stop", PPPD_SERVICE_NAME);pppd_started = 0; }}void *ip_detection(void *arg) {int fd;int err;int device_fd = (int)arg; char buffer[20]; char exit_code[PROPERTY_VALUE_MAX]; static char local_ip[PROPERTY_VALUE_MAX];static int pppd_started = 0; sleep(2); while(1){property_get(PPPD_EXIT_CODE, exit_code, "");//擷取pppd的退出狀態if(strcmp(exit_code, "") != 0) {//檢測pppd是否異常退出ALOGW("PPPd exit with code %s", exit_code);request_setup_datacall(device_fd);//繼續執行撥號goto done;} fd = open(PPP_OPERSTATE_PATH, O_RDONLY);//讀取/sys/class/net/ppp0/operstate來監控資料網路資料的狀態 if (fd >= 0) {buffer[0] = 0; read(fd, buffer, sizeof(buffer));close(fd);ALOGW("buffer = %s", buffer);if(!strncmp(buffer, "up", strlen("up")) || !strncmp(buffer, "unknown", strlen("unknown"))) {memset(local_ip,'\0',sizeof(local_ip));err = property_get(PPP_NET_LOCAL_IP, local_ip, "");//擷取IPif (err < 0) {ALOGW("Get PPPD_NET_LOCAL_IP failed!");}if(!strcmp(local_ip, "")) {ALOGW("PPP link is up but no local IP is assigned. Will retry times after %d seconds",PPP_SYSFS_RETRY);property_set("ctl.stop", PPPD_SERVICE_NAME);//如果沒有IP停止pppd} else {ALOGD("PPP link is up with local IP address %s", local_ip);}} else {ALOGW("PPP link status in %s is %s. Will retry times after %d seconds", \PPP_OPERSTATE_PATH, buffer, PPP_SYSFS_RETRY);property_set("ctl.stop", PPPD_SERVICE_NAME);//如果資料網路資料的狀態不對停止pppd}} else { ALOGW("Can not detect PPP state in %s. Will retry times after %d seconds", \ PPP_OPERSTATE_PATH ,PPP_SYSFS_RETRY);request_setup_datacall(device_fd);//繼續執行撥號}done: sleep(PPP_SYSFS_RETRY); } return NULL;}
3、ril_fun.h
#ifndef _RIL_FUN_H_#define _RIL_FUN_H_#include #include //ALOG*()#include //property_set()#definePPPD_SERVICE_NAME "pppd_gprs"/************************************************************** 功能:開啟串口裝置檔案* 參數:device_path: 串口裝置檔案名稱* 傳回值:串口裝置檔案描述符**************************************************************/int device_open(char *device_path);/************************************************************** 功能:初始化裝置節點* 參數:device_fd: 串口裝置檔案描述符 * 傳回值:無**************************************************************/void device_init(int device_fd);/************************************************************** 功能:發送AT指令函數* 參數:device_fd: 串口裝置檔案描述符* cmd:AT命令 * 傳回值:ret:狀態**************************************************************/int at_send_command(int device_fd, char *cmd);/************************************************************** 功能:建立撥號函數* 參數:device_fd: 串口裝置檔案描述符 * 傳回值:無**************************************************************/void request_setup_datacall(int device_fd);/************************************************************** 功能:建立查詢IP線程* 參數:arg: void類型指標 * 傳回值:NULL**************************************************************/void *ip_detection(void *arg);#endif
4、Android.mk
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= \rild.c \ril_fun.cLOCAL_SHARED_LIBRARIES := \libcutils \libdlLOCAL_LDLIBS += -lpthreadLOCAL_MODULE:= rildLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)
上述檔案添加好後,進行編譯,在編譯前如果之前編譯過要進行清理,執行make clean
二、把下面的指令碼放到板子的/etc/ppp下
1、init.gprs-pppd
#!/system/bin/sh# An unforunate wrapper script # so that the exit code of pppd may be retrievedPPPD_PID=/system/bin/setprop "net.gprs.ppp-exit" "" #設定net.gprs.ppp-exit為空白/system/bin/log -t pppd "Starting pppd"/system/bin/pppd connect 'chat -v -s -r "/var/log/chat.log" -f "/etc/ppp/3gdata_call.conf"' disconnect \'chat -r "/var/log/chat.log" -t 30 -e -v "" +++ATH "NO CARRIER"' /dev/ttyUSB3 115200 mru 1280 mtu 1280 \nodetach debug defaultroute usepeerdns crtscts user card password card noipdefault ipcp-accept-local \ipcp-accept-remotePPPD_EXIT=$? #獲得執行命令後的傳回值PPPD_PID=$! #最後啟動並執行後台進程的PID/system/bin/log -t pppd "pppd exited with $PPPD_EXIT" /system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT" #把傳回值設定給net.gprs.ppp-exit
註:指令碼中的/dev/ttyUSB3為模組USB串口的Modem口。
2、3gdata_call.conf
ABORT "NO CARRIER"ABORT "NO DIALTONE"ABORT "ERROR"ABORT "NO ANSWER"ABORT "BUSY"TIMEOUT 120"" atOK atd*99***1#CONNECT
三、修改ini.rc指令碼
再修改init.rc前一定要先編譯好源碼,因為修改的是編譯後產生的檔案,因為改源檔案有點麻煩。
開啟 .../ out/target/product/sabresd_6dq/root/init.rc按照如下紅色框進行修改
添加修改新加入檔案許可權的語句。
註:/dev/ttyUSB2是模組USB串口的AT口。
到此,就可以進行打包 make snod ,燒寫鏡像進行測試了。
可以用命令:logcat -b radio 查看rild 輸出的資訊進行調試。如果一切正常會列印出IP(或用命令 necfg 查看IP),有IP後用命令 ping 202.108.22.5 (百度IP)看下網路是否能ping通。如果能ping通證明自動撥號已經成功。此時用命令 ps查看rild和pppd進程號,用命令kill -9 <進程號> 殺死隨便一個進程,在5s之後看看是不是該進程又運行了。