Android平台开发-3G function porting-3G功能移植

来源:互联网 发布:微信霸屏软件 编辑:程序博客网 时间:2024/04/29 16:20
 Android平台开发-3G function porting-3G功能移植 2012-03-19 00:33:00

分类: LINUX

曾几何时在Android2.1下调试3G模块,曾几何时模块厂商提供的库不能用,曾几何时只能用自己的库痛苦地调试...这一切的一切都已成往事,昔日的成功在毫无保留下成为浮云,该忘了忘记了,该记得也跟着忘记了。现如今再次调3G模块,却不知道以前如何调试,看来还是要记下来。
我采用的是华为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. 1.#include <termios.h>

  2. 1.

  3. 2.static int urc_fd = -1; /* fd of the URC channel */

  4. 3.static char s_URCBuffer[MAX_AT_RESPONSE+1];

  5. 4.static char *s_URCBufferCur = s_URCBuffer;

  6. 5.static pthread_t s_tid_reader_urc;
  7. 1.static const char *urc_readline()

  8. 1.{

  9. 2. ssize_t count;

  10. 3. char *p_read = NULL;

  11. 4. char *p_eol = NULL;

  12. 5. char *ret;

  13. 6.7. if (*s_URCBufferCur == '\0') {

  14. 8. s_URCBufferCur = s_URCBuffer;

  15. 9. *s_URCBufferCur = '\0';

  16. 10. p_read = s_URCBuffer;

  17. 11. } else { 

  18. 12. while (*s_URCBufferCur == '\r' || *s_URCBufferCur == '\n')

  19. 13. s_URCBufferCur++;

  20. 14. p_eol = findNextEOL(s_URCBufferCur);

  21. 15. if (p_eol == NULL) {

  22. 16. size_t len;

  23. 17. len = strlen(s_URCBufferCur);

  24. 18. memmove(s_URCBuffer, s_URCBufferCur, len + 1);

  25. 19. p_read = s_URCBuffer + len;

  26. 20. s_URCBufferCur = s_URCBuffer;

  27. 21. }

  28. 22. }

  29. 23. while (p_eol == NULL) {

  30. 24. if (== MAX_AT_RESPONSE - (p_read - s_URCBuffer)) {

  31. 25. LOGE("ERROR: Input line exceeded buffer\n");

  32. 26. s_URCBufferCur = s_URCBuffer;

  33. 27. *s_URCBufferCur = '\0';

  34. 28. p_read = s_URCBuffer;

  35. 29. }

  36. 30. do {

  37. 31. count = read(urc_fd, p_read, MAX_AT_RESPONSE - (p_read - s_URCBuffer));

  38. 32. } while (count < 0 && errno == EINTR);

  39. 33. if (count > 0) {

  40. 34. AT_DUMP( "<< ", p_read, count );

  41. 35. s_readCount += count;

  42. 36. p_read[count] = '\0';

  43. 37. while (*s_URCBufferCur == '\r' || *s_URCBufferCur == '\n')

  44. 38. s_URCBufferCur++;

  45. 39. p_eol = findNextEOL(s_URCBufferCur);

  46. 40. p_read += count;

  47. 41. } else if (count <= 0) {

  48. 42. if(count == 0) {

  49. 43. LOGD("atchannel: EOF reached");

  50. 44. } else {

  51. 45. LOGD("atchannel: read error %s", strerror(errno));

  52. 46. }

  53. 47. return NULL;

  54. 48. }

  55. 49. }

  56. 50. ret = s_URCBufferCur;

  57. 51. *p_eol = '\0';

  58. 52. s_URCBufferCur = p_eol + 1; 
  59. 53. LOGD("AT< %s\n", ret);

  60. 54. return ret;

  61. 55.}

  62. 56.

  63. 57.static void *urc_readerLoop(void *arg)

  64. 58.{

  65. 59. for (;;) {

  66. 60. const char * line;

  67. 61. line = urc_readline();

  68. 62. if (line == NULL) {

  69. 63. break;

  70. 64. }

  71. 65. if(isSMSUnsolicited(line)) {

  72. 66. char *line1;

  73. 67. const char *line2;

  74. 68. line1 = strdup(line);

  75. 69. line2 = readline();

  76. 70. if (line2 == NULL) {

  77. 71. break;

  78. 72. }

  79. 73. if (s_unsolHandler != NULL) {

  80. 74. s_unsolHandler (line1, line2);

  81. 75. }

  82. 76. free(line1);

  83. 77. } else {

  84. 78. processLine(line);

  85. 79. }

  86. 80. }

  87. 81. onReaderClosed();

  88. 82. return NULL;

  89. 83.}

(3)修改ril/reference-ril/atchannel.c中的at_open函数,增加HUAWEI_EM770W宏控制的代码

点击(此处)折叠或打开

  1. pthread_attr_init (&attr);

  2. 1. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  3. 2.

  4. 3.#ifdef HUAWEI_EM770W 

  5. 4. int fd2 = -1;

  6. 5. while(fd2 < 0) {

  7. 6. fd2 = open ("/dev/ttyUSB2", O_RDWR);

  8. 7. if (fd2 < 0) {

  9. 8. perror ("opening URC interface. retrying...");

  10. 9. sleep(10);

  11. 10. }

  12. 11. }

  13. 12. if(fd2 > 0) {

  14. 13. urc_fd = fd2;

  15. 14. struct termios ios;

  16. 15. tcgetattr( fd2, &ios );

  17. 16. ios.c_lflag = 0; 
  18. 17. tcsetattr( fd2, TCSANOW, &ios );

  19. 18. }

  20. 19. ret = pthread_create(&s_tid_reader_urc, &attr, urc_readerLoop, &attr);

  21. 20. if (ret < 0) {

  22. 21. perror ("pthread_create");

  23. 22. return -1;

  24. 23. }

  25. 24.#endif

  26. 25.

  27. 26. ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
  28. (4)在ril/reference-ril/reference-ril.c中修改的代码

  29. 1.+#include <cutils/properties.h>

  30. 1.

  31. 2.-#define PPP_TTY_PATH "/dev/omap_csmi_tty1"

  32. 3.+#define PPP_TTY_PATH "/dev/ppp0"

  33. 4.

  34. 5.- /* Not muted */

  35. 6.- at_send_command("AT+CMUT=0", NULL);

  36. 7.+ /* Set muted */

  37. 8.+ at_send_command("AT+CMUT=1", NULL);

  38. 9.

  39. 10.- if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {

  40. 11.+ if ( fd >= 0) {

  41. 12.

  42. 13. /* 

  43. 1. asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);

  44. 2. //FIXME check for error here

  45. 3. err = at_send_command(cmd, NULL);

  46. 4. free(cmd);

  47. 5. // Set required QoS params to default

  48. 6. err = at_send_command("AT+CGQREQ=1", NULL);

  49. 7. // Set minimum QoS params to default

  50. 8. err = at_send_command("AT+CGQMIN=1", NULL);

  51. 9. // packet-domain event reporting

  52. 10. err = at_send_command("AT+CGEREP=1,0", NULL);

  53. 11. // Hangup anything that's happening there now

  54. 12. err = at_send_command("AT+CGACT=1,0", NULL);

  55. 13. // Start data on PDP context 1

  56. 14. err = at_send_command("ATD*99***1#", &p_response);

  57. 15. if (err < 0 || p_response->success == 0) {

  58. 16. goto error;

  59. 17. } 
  60. 18. */ 
  61. 19.15. + property_set("ctl.start","pppd_gprs");

  62. 16. RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));

  63. 17. at_response_free(p_response);
  64. (5)在ril/rild/rild.c中修改的代码 
  65. 1.+#if 0

  66. 1. /* special override when in the emulator */

  67. 2.-#if 1

  68. 3. {

  69. 4. static char* arg_overrides[3];

  70. 5. static char arg_device[32];

  71. 6.

  72. 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
1.# An unforunate wrapper script
2.PPPD_PID=
3./system/bin/setprop "net.gprs.ppp-exit" ""
4./system/bin/log -t pppd "Starting pppd"
5./system/bin/pppd call gprs $*
6.PPPD_EXIT=$?
7.PPPD_PID=$!
8./system/bin/log -t pppd "pppd exited with $PPPD_EXIT"
9./system/bin/setprop "net.gprs.ppp-exit" "$PPPD_EXIT"
10.exit $PPPD_EXIT
2.gprs-connect-chat
1.ABORT 'BUSY'
1.ABORT 'NO CARRIER'
2.ABORT 'ERROR'
3.ABORT '+CME ERROR: 100'
4."" AT
5.OK AT+CGDCONT=1,"IP","CMNET"
6.OK AT+CGEQREQ=1,2,128,384,0,0,0,0,"0E0","0E0",,0,0
7.OK AT
8.OK AT
9.OK ATS0=0
10.OK AT
11.OK AT
12.OK ATDT*98*1#
13.CONNECT
3.gprs-disconnect-chat 
1.ABORT OK
1.ABORT BUSY
2.ABORT DELAYED
3.ABORT "NO ANSWER"
4.ABORT "NO CARRIER"
5.ABORT "NO DIALTONE"
6.ABORT VOICE
7.ABORT ERROR
8.ABORT RINGING
9.TIMEOUT 12
10."" \\k\\k\\k\\d+++ATH
11."NO CARRIER-AT-OK" ""
4.ip-up 
1.#!/system/bin/sh
1./system/bin/setprop "net.interfaces.defaultroute" "gprs"
2./system/bin/setprop "net.gprs.dns1" "$DNS1"
3./system/bin/setprop "net.gprs.dns2" "$DNS2"
4./system/bin/setprop "net.gprs.local-ip" "$IPLOCAL"
5./system/bin/setprop "net.gprs.remote-ip" "$IPREMOTE"
6.exit 0
5.ip-down 
1.#!/system/bin/sh
1.case $1 in
2.    ppp1)
3.  echo 0 > /proc/sys/net/ipv4/ip_forward;
4.  ;;
5.esac
6.rm /etc/ppp/ppp*.pid
7.# Use interface name if linkname is not available
8.NAME=${LINKNAME:-"$1"}
9.#/system/bin/setprop "net.dns1" ""
10.#/system/bin/setprop "net.dns2" ""
11./system/bin/setprop "net.$NAME.local-ip" ""
12./system/bin/setprop "net.$NAME.remote-ip" ""
6.peers/gprs
1.# This is pppd script, used Huawei EM770W3G Module
1.# Usage: root>pppd call gprs
2./dev/ttyUSB0
3.115200
4.crtscts
5.modem
6.debug
7.nodetach
8.usepeerdns
9.noipdefault
10.defaultroute
11.user "cmnet"
12.0.0.0.0:0.0.0.0
13.connect '/system/bin/chat -s -v -f /etc/ppp/gprs-connect-chat'
14.#disconnect '/bin/chat -v -f /etc/ppp/gprs-disconnect-chat'
文件创建好后只要在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

   添加如下:

 service ril-daemon /system/bin/rild -l /system/lib/libhuawei-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 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--->拨号
 
 
 
#######################################################################
 
 
一、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。
        <apns version="6">
           <apn carrier="Android"
                mcc="310"
                mnc="995"
                apn="internet"
                user="*"
                server="*"
                password="*"
                mmsc="null"
           />
           <apn carrier="TelKila" 
                mcc="310"
                mnc="260"
                apn="internet"
                user="*"
                server="*"
                password="*"
                mmsc="null"
           />
           <apn carrier="CMCC"
                mcc="460"
                mnc="00"
                apn="cmnet"
                user="*"
                server="*"
                password="*"
                mmsc="null"
           />
           <apn carrier="CHINA MOBILE"
                mcc="460"
                mnc="07"
                apn="cmnet"
                user="*"
                server="*"
                password="*"
                mmsc="null"
           />
       </apns>
  
  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通网络的。
原创粉丝点击