3G上网卡2_编程自动切换模式学习笔记

来源:互联网 发布:淘宝删除评论 编辑:程序博客网 时间:2024/05/18 21:41

为什么要切换模式:

3G上网卡自带程序,接到PC后先作为移动硬盘使用,安装程序后切换为modem

如何自动切换模式



1. 编写控制程序自动使用各种型号3G上网卡
a. usb_modeswitch -c /etc/...  // 1. 对于不同的3G上网卡配置信息不一样
b. insmod ...              //装载驱动程序
c. pppd call wcdma-dailer   联通   // 2. 对于不同的3G上网卡使用不的/dev/ttyUSB
   pppd call evdo-dailer   电信    //对应不同的运营商调用不同的脚本文件
   pppd call td-dailer     移动      //从而确定使用哪一个usb串口拨号


写一个控制程序:(功能描述)
a. 接上3G上网卡后它会调用usb_modeswitch并提供对应的配置信息
b. 当识别出/dev/ttyUSB...后, 它创建一个链接文件/dev/gsmmodem指向拨号时要用的/dev/ttyUSB


参考PC上对3G上网卡的识别过程:
在PC上编译、安装: libusb-1.0.9.tar.bz2, usb-modeswitch-2.0.1.tar.bz2, usb-modeswitch-data-20131113.tar.bz2,ppp-2.4.5.tar.gz

直接在PC上编译安装,./configure后面不需指定运行环境和安装目录


重启电脑
接上USB 3G上网卡(下面点击connect)



查看切换情况,gsmmodem指向了最终要使用的串口,以后修改配置文件,只需使用/dev/gsmmodem


分析PC操作过程:(使用的是udev)
a.
从/lib/udev/rules.d/40-usb_modeswitch.rules可知

   接上3G上网卡后将执行: usb_modeswitch '%b/%k'


   执行的是:/lib/udev/usb_modeswitch
   它又会调用/usr/sbin/usb_modeswitch_dispatcher
b. /usr/sbin/usb_modeswitch_dispatcher会调用usb_modeswitch进行模式切换
   它调用:/usr/sbin/usb_modeswitch -W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct)-f "$configBuffer"
   它并不使用配置文件,而是使用-f参数, 这些参数来自/usr/share/usb_modeswitch
   在/usr/share/usb_modeswitch里有众多文件,已"vid:pid"为名



   /usr/sbin/usb_modeswitch_dispatcher根据3G上网卡的vid,pid找到/usr/share/usb_modeswitch里的文件,
   然后执行:usb_modeswitch -V vid -P pid -f "文件里的内容"
c. 怎么创建接文件/dev/gsmmodem:(确定指向哪一个串口)
# The facility to add a symbolic link pointing to the
# ttyUSB port which provides interrupt transfer, i.e.
# the port to connect through.
# Will check for interrupt endpoint in ttyUSB port (lowest if
# there is more than one); if found, return "gsmmodem[n]" name
# to udev for symlink creation
/dev/gsmmodem是指向一个/dev/ttyUSBX, 这个/dev/ttyUSBX所对应的interface含有"中断类型的端点"
如果有多个/dev/ttyUSBX有中断类型端点, 则/dev/gsmmodem指向最小的/dev/ttyUSBX



怎么判断ttyUSB有无中断类型端点:

# In case the device path is returned as /sys/class/tty/ttyUSB,
# get the USB device path from linked tree "device"
/* 1. 对于每一个/dev/ttyUSBX
 *    都有一个对应的/sys/class/tty/ttyUSBX
 * 2. 它是一个链接文件, 指向: /sys/......../1-1:1.0/ttyUSB0/tty/ttyUSB0
 * 3. 进入/sys/......../1-1:1.0/目录,
 *    里面有多个"ep_"的子目录
 * 4. 子目录里有名为type的文件
 * 5. 如果这个文件的内容为Interrupt, 则返回1
 *    
 */


2、控制程序编写

(1) 在电脑上接上3G上网卡,出现设备usbdev1.17


(2) 根据usbdevM.N找出它的VID,PID *; M表示总线, N表示设备地址    如usbdev1.17表示在第1条总线上,地址为17的USB设备;可以仿照lsusb


具体程序(3g_manager.c)

#define USB_MODESWITCH_ETC_DIR "/usr/share/usb_modeswitch"

###########################

/* 进行usb模式切换: 调用usb_modeswitch
 */

##########################
int do_switch(int argc, char **argv)
{
libusb_device **devs;
int r;
ssize_t cnt;
libusb_device *dev;
int i = 0;
struct libusb_device_descriptor desc;
    int bus;
    int address;
    int vid;
    int pid;
    char tmpBuf[1024];
    char *cmdBuf;
    DIR *dir;
    struct dirent *entry;
    int fd;
    struct stat stat;
    /* 在使用mdev的嵌入式系统中, 接上一个USB设备后, 
     * 在/dev/目录下将出现/dev/usbdevM.N设备 
     * M表示总线, N表示设备地址    如usbdev1.17表示在第1条总线上,地址为17的USB设备
     */

/* 用法:
 * 3g_manager switch usbdev1.17   
 * 3g_manager link   ttyUSB1
 */

//接收输入的参数
    sscanf(argv[2]+6, "%d.%d", &bus, &address);//第二个参数向右移动6位,把1赋值给bus,把17赋值到address
    /* 根据usbdevM.N找出它的VID,PID */
r = libusb_init(NULL);//初始化libusb
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);//计算usb设备数目
if (cnt < 0)
return (int) cnt;


while ((dev = devs[i++]) != NULL) { //比较每一个设备的总线号和设备地址
        if ((bus == libusb_get_bus_number(dev)) && (address == libusb_get_device_address(dev)))
        {
   r = libusb_get_device_descriptor(dev, &desc);//获取他的设备描述符
    if (r < 0) {
    printf("failed to get device descriptor");
    return -1;
    }
vid = desc.idVendor;//取其VID
            pid = desc.idProduct;取其PID
            break;
        }
}

//设备被拔掉
    if (!dev)
    {
        printf("there is not this usbdev!\n");
        return -1;
    }


    /* 根据VID,PID在/usr/share/usb_modeswitch找到名中含有"VID:PID"的文件(因为可能还有后缀) */
    sprintf(tmpBuf, "%04x:%04x", vid, pid);//打印出其VID和PID并存在tmpBuf
    dir = opendir(USB_MODESWITCH_ETC_DIR);//打开目录/usr/share/usb_modeswitch
    if (!dir)
    {
        printf("can not open %s\n", USB_MODESWITCH_ETC_DIR);
        return -1;
    }
    while((entry = readdir(dir)))//读取目录里面的文件名
    {

//以VID和PID进行匹配文件名


        //entry->d_name是文件的名字

if (strncasecmp(entry->d_name, tmpBuf, 9) == 0)//匹配文件名(9个字节)
        {
            break;
        }
    }

//文件为空
    if (!entry)
    {
        printf("there is cfg file for %04x:%04x\n", vid, pid);
        return -1;
    }

//找到后
    sprintf(tmpBuf, "%s/%s", USB_MODESWITCH_ETC_DIR, entry->d_name);//打印出文件目录和文件名,并吧路径存在tmpBuf里


    /* 把配置文件打开读出内容 */
    fd = open(tmpBuf, O_RDONLY);//打开文件
    if (fd < 0)
    {
        printf("can not open %s\n", tmpBuf);
        return -1;
    }
    r = fstat(fd, &stat);//获取文件状态,放到stat结构体
    if (r == -1)
    {

//出错打印信息
        printf("can not get stat for %s\n", tmpBuf);
        return -1;
    }
    
    /* 调用"usb_modeswitch -v VID -p PID -f "文件内容"" */
    cmdBuf = malloc(stat.st_size + 1024);//分配大小为文件的大小,1024是用于存储usb_modeswitch -vVID -p PID -f(-v,-p是默认的厂家ID和设备ID,刚接上时以硬盘形式出现的ID)
    sprintf(cmdBuf, "usb_modeswitch -v %x -p %x -f \"", vid, pid);//打印用法,"是把文件的内容引进来
    cnt = strlen(cmdBuf);//长度是usb_modeswitch -v %x -p %x -f \"的大小
    read(fd, cmdBuf+cnt, stat.st_size);//把文件内容读取到buf偏移cnt的地方
    cnt += stat.st_size;//cnt增加
    cmdBuf[cnt++] = '\"';//存储\",这里\是转义字符,要用引号括起来
    cmdBuf[cnt++] = '\0';//存储结束符


    printf("Cmd: %s\n", cmdBuf);//打印buf内容
    r = system(cmdBuf);//运行buf里面的内容
    free(cmdBuf);
    close(fd);
    return r;
}




/* 进行usb模式切换: 调用usb_modeswitch
 * 创建/dev/gsmmodem链接, 指向某个/dev/ttyUSBX
 */



/* 用法:
 * 3g_manager switch usbdev1.17   
 * 3g_manager link   ttyUSB1
 */

关于热拔插参考
http://write.blog.csdn.net/postedit/53349521

/*3g_manager.c由mdev.conf调用,当接上3G上网卡*/

int main(int argc, char **argv)
{
    if ((argc != 3) || \                //如果输入参数不为3,或者第2个参数既不等于switch也不等于link

//判断是切换还是连接
        ((strcmp(argv[1], "switch") && strcmp(argv[1], "link"))))  
    {
        printf("Usage:\n");      //出错,打印用法
        printf("%s switch <usbdevM.N> : switch 3G Modem\n", argv[0]);//这里argv[0]是3g_manager
        printf("%s link   <ttyUSBX>   : Create Link to /dev/ttyUSBX if it has interrupt endpoint\n", argv[0]);//如果有中断类型端点就创建链接
        return -1;
    }


    if (strcmp(argv[1], "switch") == 0) //如果第二个参数是switch
        return do_switch(argc, argv);   //调用函数do_switch
    else if (strcmp(argv[1], "link") == 0) //如果第二个参数是link
        return do_link(argc, argv);      //调用函数do_link
    return -1;
}






3、实验

修改Makefile,进行编译后拷贝到网络文件系统 


执行,查看用法,没有ttyusb设备


但是我们接有usb上网卡,证明还没有切换模式


查看我们的设备,进行命令切换


-f后的内容来自于对应的/usr/share/usb_modeswitch目录下的文件,文件名为12d1:1505


切换成功



想让系统一接上usb 3G上网卡后自动执行模式切换,修改/etc/mdev.conf

下面意思是当接上usb 设备后 ,就会执行3g_manager switch $MDEV,这里 $MDEV代表对应的usb设备

当出现usbdev1.17的时候执行3g_manager switch usbdev1.17   


shell 的环境变量 $MDEV 会被设置成设备名

接上另外一个3G上网卡,提示发现usb设备,然后自动切换模式



0 0