我采用的是华为EM770W模块,支持WCDMA网络,由于华为提供的库只支持Android2.2,所以用Android2.1就需要自己修改库源码。
1.修改linux内核
(1)make menuconfig:
Device Drivers --->
<*> OHCI HCD support
[*] Network device support --->
<*> PPP (point-to-point protocol) support
[*] PPP multilink support (EXPERIMENTAL)
[*] PPP filtering
<*> PPP support for async serial ports
<*> PPP support for sync tty ports
<*> PPP Deflate compression
<*> PPP BSD-Compress compression
<*> PPP MPPE compression (encryption) (EXPERIMENTAL)
<*> PPP over Ethernet (EXPERIMENTAL)
<*> PPP over L2TP (EXPERIMENTAL)
[*] USB support --->
<*> USB Serial Converter support --->
<*> USB driver for GSM and CDMA modems
(2)增加EM770W的VID和PID
修改驱动文件drivers/usb/serial/option.c,增加以下代码
#define EM770W_OPTION_VENDOR_ID 0x12d1
#define EM770W_OPTION_PRODUCT_COLT 0x1001
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
…
{ USB_DEVICE(EM770W_OPTION_VENDOR_ID , EM770W_ OPTION_PRODUCT_COLT) },
}
驱动修改后插上3G模块,kernel运行后可在/dev下出现ttyUSB0、ttyUSB1 、ttyUSB2、ttyUSB3、ttyUSB4、ttyUSB5和ppp设备文件
2.修改RIL代码
(1)在ril/reference-ril/Android.mk添加一行:
LOCAL_CFLAGS += -DHUAWEI_EM770W
(2)在ril/reference-ril/atchannel.c中增加的代码
点击(此处)折叠或打开
- 1.#include <termios.h>
- 1.
- 2.static int urc_fd = -1; /* fd of the URC channel */
- 3.static char s_URCBuffer[MAX_AT_RESPONSE+1];
- 4.static char *s_URCBufferCur = s_URCBuffer;
- 5.static pthread_t s_tid_reader_urc;
- 1.static const char *urc_readline()
- 1.{
- 2. ssize_t count;
- 3. char *p_read = NULL;
- 4. char *p_eol = NULL;
- 5. char *ret;
- 6.7. if (*s_URCBufferCur == '\0') {
- 8. s_URCBufferCur = s_URCBuffer;
- 9. *s_URCBufferCur = '\0';
- 10. p_read = s_URCBuffer;
- 11. } else {
- 12. while (*s_URCBufferCur == '\r' || *s_URCBufferCur == '\n')
- 13. s_URCBufferCur++;
- 14. p_eol = findNextEOL(s_URCBufferCur);
- 15. if (p_eol == NULL) {
- 16. size_t len;
- 17. len = strlen(s_URCBufferCur);
- 18. memmove(s_URCBuffer, s_URCBufferCur, len + 1);
- 19. p_read = s_URCBuffer + len;
- 20. s_URCBufferCur = s_URCBuffer;
- 21. }
- 22. }
- 23. while (p_eol == NULL) {
- 24. if (0 == MAX_AT_RESPONSE - (p_read - s_URCBuffer)) {
- 25. LOGE("ERROR: Input line exceeded buffer\n");
- 26. s_URCBufferCur = s_URCBuffer;
- 27. *s_URCBufferCur = '\0';
- 28. p_read = s_URCBuffer;
- 29. }
- 30. do {
- 31. count = read(urc_fd, p_read, MAX_AT_RESPONSE - (p_read - s_URCBuffer));
- 32. } while (count < 0 && errno == EINTR);
- 33. if (count > 0) {
- 34. AT_DUMP( "<< ", p_read, count );
- 35. s_readCount += count;
- 36. p_read[count] = '\0';
- 37. while (*s_URCBufferCur == '\r' || *s_URCBufferCur == '\n')
- 38. s_URCBufferCur++;
- 39. p_eol = findNextEOL(s_URCBufferCur);
- 40. p_read += count;
- 41. } else if (count <= 0) {
- 42. if(count == 0) {
- 43. LOGD("atchannel: EOF reached");
- 44. } else {
- 45. LOGD("atchannel: read error %s", strerror(errno));
- 46. }
- 47. return NULL;
- 48. }
- 49. }
- 50. ret = s_URCBufferCur;
- 51. *p_eol = '\0';
- 52. s_URCBufferCur = p_eol + 1;
- 53. LOGD("AT< %s\n", ret);
- 54. return ret;
- 55.}
- 56.
- 57.static void *urc_readerLoop(void *arg)
- 58.{
- 59. for (;;) {
- 60. const char * line;
- 61. line = urc_readline();
- 62. if (line == NULL) {
- 63. break;
- 64. }
- 65. if(isSMSUnsolicited(line)) {
- 66. char *line1;
- 67. const char *line2;
- 68. line1 = strdup(line);
- 69. line2 = readline();
- 70. if (line2 == NULL) {
- 71. break;
- 72. }
- 73. if (s_unsolHandler != NULL) {
- 74. s_unsolHandler (line1, line2);
- 75. }
- 76. free(line1);
- 77. } else {
- 78. processLine(line);
- 79. }
- 80. }
- 81. onReaderClosed();
- 82. return NULL;
- 83.}
(3)修改ril/reference-ril/atchannel.c中的at_open函数,增加HUAWEI_EM770W宏控制的代码
点击(此处)折叠或打开
- pthread_attr_init (&attr);
- 1. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- 2.
- 3.#ifdef HUAWEI_EM770W
- 4. int fd2 = -1;
- 5. while(fd2 < 0) {
- 6. fd2 = open ("/dev/ttyUSB2", O_RDWR);
- 7. if (fd2 < 0) {
- 8. perror ("opening URC interface. retrying...");
- 9. sleep(10);
- 10. }
- 11. }
- 12. if(fd2 > 0) {
- 13. urc_fd = fd2;
- 14. struct termios ios;
- 15. tcgetattr( fd2, &ios );
- 16. ios.c_lflag = 0;
- 17. tcsetattr( fd2, TCSANOW, &ios );
- 18. }
- 19. ret = pthread_create(&s_tid_reader_urc, &attr, urc_readerLoop, &attr);
- 20. if (ret < 0) {
- 21. perror ("pthread_create");
- 22. return -1;
- 23. }
- 24.#endif
- 25.
- 26. ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
- (4)在ril/reference-ril/reference-ril.c中修改的代码
- 1.+#include <cutils/properties.h>
- 1.
- 2.-#define PPP_TTY_PATH "/dev/omap_csmi_tty1"
- 3.+#define PPP_TTY_PATH "/dev/ppp0"
- 4.
- 5.- /* Not muted */
- 6.- at_send_command("AT+CMUT=0", NULL);
- 7.+ /* Set muted */
- 8.+ at_send_command("AT+CMUT=1", NULL);
- 9.
- 10.- if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
- 11.+ if ( fd >= 0) {
- 12.
- 13. /*
- 1. asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
- 2. //FIXME check for error here
- 3. err = at_send_command(cmd, NULL);
- 4. free(cmd);
- 5. // Set required QoS params to default
- 6. err = at_send_command("AT+CGQREQ=1", NULL);
- 7. // Set minimum QoS params to default
- 8. err = at_send_command("AT+CGQMIN=1", NULL);
- 9. // packet-domain event reporting
- 10. err = at_send_command("AT+CGEREP=1,0", NULL);
- 11. // Hangup anything that's happening there now
- 12. err = at_send_command("AT+CGACT=1,0", NULL);
- 13. // Start data on PDP context 1
- 14. err = at_send_command("ATD*99***1#", &p_response);
- 15. if (err < 0 || p_response->success == 0) {
- 16. goto error;
- 17. }
- 18. */
- 19.15. + property_set("ctl.start","pppd_gprs");
- 16. RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
- 17. at_response_free(p_response);
- (5)在ril/rild/rild.c中修改的代码
- 1.+#if 0
- 1. /* special override when in the emulator */
- 2.-#if 1
- 3. {
- 4. static char* arg_overrides[3];
- 5. static char arg_device[32];
- 6.
- 7. //switchUser();
前面讲到了如何让修改kernel驱动和ril层代码,接下来还需要增加ppp拨号以及设备文件和服务属性。
1.修改init.gprs-pppd属性
对应文件:system/core/include/private/android_filesystem_config.h
在static struct fs_path_config android_files[]中增加:
+ { 00777, AID_ROOT, AID_SHELL, "system/etc/init.gprs-pppd" },
2.修改ttyUSB设备属性
对应文件:system/core/init/devices.c
在static struct perms_ devperms[]中增加:
+ { "/dev/ttyUSB0", 0777, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ttyUSB1", 0777, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ttyUSB2", 0777, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ttyUSB3", 0777, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ttyUSB4", 0777, AID_RADIO, AID_RADIO, 0 },
+ { "/dev/ttyUSB5", 0777, AID_RADIO, AID_RADIO, 0 },
3.修改pppd_gprs服务属性
对应文件:system/core/init/property_service.c
在property_perms[]中增加:
+ { "net.ppp0.", AID_RADIO, 0 },
在control_perms[]中增加:
+ { "pppd_gprs",AID_RADIO, AID_LOG },
4.修改init.rc文件
service ril-daemon /system/bin/rild -l libreference-ril.so -- -d /dev/ttyUSB2
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc
service pppd_gprs /etc/ppp/init.gprs-pppd /dev/ttyUSB0
user root
group radio cache inet misc
disabled
现在3G模块上电后就可以注册上网络,并能实现电话功能,接下来还要实现gprs拨号上网功能。
现在开始介绍如何实现ppp拨号上网。在/system/etc下创建ppp目录,并在ppp目录下创建以下文件:
1.init.gprs-pppd
1.#!/system/bin/sh
2.gprs-connect-chat
3.gprs-disconnect-chat
1.ABORT OK
4.ip-up
1.#!/system/bin/sh
5.ip-down
1.#!/system/bin/sh
6.peers/gprs
文件创建好后只要在Android启动后进入"Settings(设置)"->"Wireless controls(无线网络)"->"Mobile networks(移动网络)"->"Access Points Name(接入点)",按Menu键弹出界面选择"New APN(新接入点)",一般情况下只要填写"Name(名称)"和"APN"两项即可,"MCC"和"MNC"会随着运行商网络注册成功后自动生成,最后保存。现在就可以通过gprs上网了。
1. 硬件检查电路;确保参考电压值正确
关键点: RST_IN、WAKE_UP_IN、PWR_ON_OFF 、PWR_SIM..
2.USB-HUB调试:
一般的3G模块都用USB传输数据, 很少用serial..
1>.hub 电压都OK
2>.hub驱动... // 三星A8采用 S5PV210_ehci
3>.make menuconfig 对USB 驱动部分进行配置.. hub驱动..// ehci跟ohci
usb-serial驱动// 由于3G模块的特殊性 必须映射为虚拟串口 即ttyUSB*
3.3G模块上电时序..
根据datasheet 修改3G模块的上电时序.../
主要有POWER、wakeup_in、reset、power_on_off
MU509模块的上电时序为:
power-->power_on_off(下拉0.5s--1s时间间隔==>开机)-->wake_up_in(高电位为唤醒模式)-->延时1s---3s 再reset(拉低0.3--1s);
// 时序正常 hub驱动OK 电压OK ===>模块启动(可以看mode_led 与status_led两灯的工作状态)
4. 3g模块的在kenel层的驱动一贯是很成熟的... usb_modem 开源驱动..
usb_serial 成熟的驱动..
需要增加的就是添加模块号.. 让USB能识别模块...// 供应商会提供相关的资料
5. make menuconfig 添加pppd 服务支持... // 用于拨号上网 android系统会调用到
##做完上面5点 kernel层基本完事.. // 不过3G电源管理依然是个头大的问题.. 需要仔细的修改调试.. 对于这个耗电大户得谨慎
6. android层之init.rc
添加如下:
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio
##以上只是针对于华为libhuawei-ril.so库里面包含pppd shell 脚本
##对于没有pppdshell脚本以及chat 的需额外增加:
service pppd_gprs /etc/init.gprs-pppd //添加一shell脚本用来运行 pppd
user root
group radio cache inet misc
同时:
chmod 777 /dev/ttyUSB0
chmod 777 /dev/ttyUSB2
7.android层之rild.c
这块修改调用的lib库路劲即可...
8. android层之lib
在samsung平台中直接将libhuawei-ril.so copy到 out/target/product/smdkc11o/system/lib路劲下是不可行的 不会参与编译系统..
需要在 vendor/sec/sec_proprietary/smdkc110/libril 添加libhuawei-ril.so
再修改vendor/sec/smdkc110 目录下的AndroidBoard.mk
添加:PRODUCT_COPY_FILES += $(LOCAL_PATH)/../sec_proprietary/libril/libhuawei-ril.so:system/lib/ibhuawei-ril.so
9. android层之ip-up,ip-down // 拨号
ip-up与ip-down的操作与添加华为libhuawei-ril.so类似...
3G通信过程...
ril进程服务...
pppd_pid==>pppd服务===>chat===>拨号 拨号OK 网络连接.....
##以上主要是针对MU509 带libhuawei-ril.so
对于没有带libhuawei-ril.so的 需要写init.gprs-pppd(pppd服务脚本) options.3gnet 脚本、wcdma.chatscripts // shell 脚本
实现pppd--->拨号
Android ril相关的代码和脚本主要有:
android/hardware/ril/reference_ril/ (reference_ril.c)
android/hardware/ril/rild
android/extern/ppp/pppd
android/extern/ppp/chat
android/data/etc/apn-conf-sdk.xml
android/system/core/rootdir/etc/ppp/init.gprs-pppd
android/system/core/rootdir/etc/ppp/peers/cmnet
android/system/core/rootdir/etc/ppp/chat/cmtc-isp
android/vendor/xxxxx/xxxx/system.prop
1、reference_ril.c: RIL的一些AT命令操作,通过一些onRequest接口操作,对不同的硬件,需作一
些修改调整。
2、apn-conf-sdk.xml: 以下是一个例子,有些不支持的APN,需要自己加上去,否则在log中会出现类
似:No APN found for carrier: 46xxx, 的错误。一般移动的TD USIM是46007, 有些是
46000。
mnc="995"
apn="internet"
user="*"
server="*"
password="*"
mmsc="null"
/>
mnc="260"
apn="internet"
user="*"
server="*"
password="*"
mmsc="null"
/>
mnc="00"
apn="cmnet"
user="*"
server="*"
password="*"
mmsc="null"
/>
mnc="07"
apn="cmnet"
user="*"
server="*"
password="*"
mmsc="null"
/>
3、init.gprs-pppd: 调用pppd GPRS拨号的初始化脚本。
PPPD_PID=
/system/bin/setprop "net.gprs.ppp-exit" ""
/system/bin/log -t pppd "Starting pppd"
/system/xbin/pppd call cmnet $* //调用脚本/system/etc/peers/cmnet
或
/system/xbin/pppd connect 'chat -v "" "AT" "ATDT#777 CONNECT"' user \
CARD password CARD /dev/ttyUSB2 115200 nodetach crtscts \
debug usepeerdns defaultroute
//直接用参数,其中/dev/USB2是控制端口。
PPPD_EXIT=$?
PPPD_PID=$!
/system/bin/log -t pppd "pppd exited with $PPPD_EXIT"
/system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
4、cmnet:pppd拨号option脚本:
/dev/ttyUSB3
921600
nocrtscts
nocdtrcts
local
usepeerdns
defaultroute
noipdefault
ipcp-accept-local
ipcp-accept-remote
user cmnet
password cmnet
lock
nodetach
connect "/system/xbin/chat -v -t 50 -f /system/etc/ppp/chat/cmtc-isp"
5、cmtc-isp:
ABORT 'BUSY'
ABORT 'NO CARRIER'
ABORT 'ERROR'
ABORT '+CME ERROR: 100'
"" AT
OK AT+CGDCONT=1,"IP","CMNET"
OK AT+CGEQREQ=1,2,128,384,0,0,0,0,"0E0","0E0",,0,0
OK AT
OK AT
OK ATS0=0
OK AT
OK AT
OK ATDT*98*1#
CONNECT
如果要连联通的WCDMA,就用
OK AT+CGDCONT=1,"IP","3GNET"
OK ATDT*99# //拨号命令
6、system.prop:
rild.libpath=/system/lib/libreference-ril.so
rild.libargs=-d /dev/ttyS0
wifi.interface=eth1
二、RIL配置支持
在Android中RIL是通过pppd实现的,要启动pppd,需要在init.rc中添加:
service pppd_gprs /system/etc/init.gprs-pppd
user root
group radio cache inet misc
disabled
oneshot
service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so --
-d /dev/ttyUSB3 -u /dev/ttyUSB0
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio
Modem插入USB口模拟串口,驱动会检测到两个serial端口的,一个是控制的,一个是数据的。
这里/dev/ttyUSB3表示控制端口。
三、RIL流程分析
一开机启动pppd后,如果检测到Modem(通过/dev/ttyUSB*设备来判断),pppd_gprs daemon就调用
init.gprs-pppd连接,
正常通信后,会显示连接到3G网络标志。
然后设置APN,保存好之后重启,就会自动连接到internet。
四、手动测试3G modem
1、加载驱动
如果驱动加载成功,会出现/dev/ttyUSB*设备的。
2、进入/etc/ppp/peers目录,执行
pppd call cmnet &
这里cmnet是一个包含拨号命令的文件。
3、设置DNS
把由pppd自动产生的/etc/ppp/resolv.conf复制到/etc/resolv.conf。
4、前面都成功的话,这是应该能ping通网络的。