zoukankan      html  css  js  c++  java
  • Android blueZ HCI(一个):hciconfig实施和经常使用

    关键词:hciconfighcitool  hcidump
    笔者:xubin341719(欢迎转载,请明确说明,请尊重版权,谢谢。)
    欢迎指正错误,共同学习、共同进步!



    Android blueZ HCI(一):hciconfig实现及经常用法
    Android blueZ hci(二):hcitool hcidump经常用法

    一、Hciconfig
    1、adb shell 下。hciconfig 运行文件的位
    /system/xbin/hciconfig


    对应文件夹下Android.mk文件,生成hciconfig

    #
    # hciconfig
    #
    include $(CLEAR_VARS)
    LOCAL_SRC_FILES:= 
    	csr.c 
    	csr_h4.c 
    	hciconfig.c
    ………………
    LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
    LOCAL_MODULE_TAGS := optional
    LOCAL_MODULE:=hciconfig
    include $(BUILD_EXECUTABLE)
    

    2、hciconfig代码实现
    idh.codeexternalluetoothluez oolshciconfig.c
    main函数主要有两部分功能:main_options操作。命令的运行;
    以下我们分两部分分析

    int main(int argc, char *argv[])
    {
    	int opt, ctl, i, cmd=0;
    //(1)、hciconfig两个命main_options,help和all两个命令。
    	while ((opt=getopt_long(argc, argv, "ah", main_options, NULL)) != -1) {
    		switch(opt) {
    		case 'a':
    			all = 1;
    			break;
    		case 'h':
    		default:
    			usage();
    			exit(0);
    		}
    	}
    //(2)、命令运行部分
    	argc -= optind;
    	argv += optind;
    	optind = 0;
    
    	/* Open HCI socket  */
    	if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
    		perror("Can't open HCI socket.");
    		exit(1);
    	}
    
    	if (argc < 1) {
    		print_dev_list(ctl, 0);
    		exit(0);
    	}
    
    	di.dev_id = atoi(argv[0] + 3);
    	argc--; argv++;
    
    	if (ioctl(ctl, HCIGETDEVINFO, (void *) &di)) {
    		perror("Can't get device info");
    		exit(1);
    	}
    
    	if (hci_test_bit(HCI_RAW, &di.flags) &&
    			!bacmp(&di.bdaddr, BDADDR_ANY)) {
    		int dd = hci_open_dev(di.dev_id);
    		hci_read_bd_addr(dd, &di.bdaddr, 1000);
    		hci_close_dev(dd);
    	}
    
    	while (argc > 0) {
    		for (i = 0; command[i].cmd; i++) {
    			if (strncmp(command[i].cmd, *argv, 5))
    				continue;
    
    			if (command[i].opt) {
    				argc--; argv++;
    			}
    
    			command[i].func(ctl, di.dev_id, *argv);
    			cmd = 1;
    			break;
    		}
    		argc--; argv++;
    	}
    
    	if (!cmd)
    		print_dev_info(ctl, &di);
    
    	close(ctl);
    	return 0;
    }
    

    (1)、hciconfig两个命main_options,help和all两个命令

    int main(int argc, char *argv[])
    {
    	int opt, ctl, i, cmd=0;
    //1)、hciconfig两个命main_options,help和all两个命令。
    	while ((opt=getopt_long(argc, argv, "ah", main_options, NULL)) != -1) {//1)、main_options。
    		switch(opt) {
    		case 'a':
    			all = 1;
    			break;//2)、假设是all命令运行下去;
    		case 'h':
    		default:
    			usage();//3)、假设是help命令打印出命令用法。
    			exit(0);
    		}
    	}
    ………………
    }
    

    1)、main_options
    while((opt=getopt_long(argc, argv, "ah", main_options, NULL)) != -1) {
    getopt被用来解析命令行选项參数。getopt_long。解析命令參数支持长选项。即一对短横线、一个描写叙述性选项名称,还能够包括一个使用等号连接到选项的參数。

    http://blog.csdn.net/slmmlk2011_2/article/details/7964218中有具体介绍。
    即:hciconfig–all

    main_options
    static struct option main_options[] = {
    	{ "help",	0, 0, 'h' },
    	{ "all",	0, 0, 'a' },
    	{ 0, 0, 0, 0 }
    };
    

    2)、ops 解析出来数据,假设是a,打印出蓝牙相关信息

    	case 'a':
    			all = 1;
    			break;
    

    后面这部分和命令解析一起分析。

    3)、假设是help命令,打印出命令用法。

    		case 'h':
    		default:
    			usage();
    		exit(0);
    

    假设是help 运行usage这个函数。以下分析这个函数
    idh.codeexternalluetoothluez oolshciconfig.c

    static void usage(void)
    {
    	int i;
    	printf("hciconfig - HCI device configuration utility
    ");
    	printf("Usage:
    "
    		"	hciconfig
    "
    		"	hciconfig [-a] hciX [command]
    ");
    	printf("Commands:
    ");
    	for (i=0; command[i].cmd; i++)
    		printf("	%-10s %-8s	%s
    ", command[i].cmd,
    		command[i].opt ?

    command[i].opt : " ", command[i].doc); }

    这个函数比較简单,就是不command[]结构体中的命令字符串打印出来:以下两个截图就一目了然了:

    命令运行结果例如以下:


    static struct {
    	char *cmd;//命令。比方hciconfig up;
    	void (*func)(int ctl, int hdev, char *opt);//命令运行函数。
    	char *opt;//
    	char *doc;//命令描写叙述
    } command[] = {
    	{ "up",		cmd_up,		0,		"Open and initialize HCI device" },
    	{ "down",	cmd_down,	0,		"Close HCI device" },
    	{ "reset",	cmd_reset,	0,		"Reset HCI device" },
    ………………
    }
    
    这部分以:{ "up",           cmd_up,            0,               "Open and initialize HCIdevice" },为例说明

    使用up命令时。会调用到,cmd_up这个函数:
    idh.codeexternalluetoothluez oolshciconfig.c

    static void cmd_up(int ctl, int hdev, char *opt)
    {
    	/* Start HCI device */
    	if (ioctl(ctl, HCIDEVUP, hdev) < 0) {
    		if (errno == EALREADY)
    			return;
    		fprintf(stderr, "Can't init device hci%d: %s (%d)
    ",
    						hdev, strerror(errno), errno);
    		exit(1);
    	}
    }
    

    (2)、命令运行部分

    Main()
    {
    ………………
    	argc -= optind;
    	argv += optind;
    	optind = 0;
    
    	/* Open HCI socket  *///1)、打开HCI socket通信
    	if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {/
    		perror("Can't open HCI socket.");
    		exit(1);
    	}
    
    	if (argc < 1) {
    		print_dev_list(ctl, 0);
    		exit(0);
    	}
    
    	di.dev_id = atoi(argv[0] + 3);
    	argc--; argv++;
    //2)、通过ioctl获取HCI驱动信息
    	if (ioctl(ctl, HCIGETDEVINFO, (void *) &di)) {
    		perror("Can't get device info");
    		exit(1);
    	}
    //3)、hci_test_bit  bacmp
    	if (hci_test_bit(HCI_RAW, &di.flags) &&
    			!bacmp(&di.bdaddr, BDADDR_ANY)) {
    		int dd = hci_open_dev(di.dev_id);
    		hci_read_bd_addr(dd, &di.bdaddr, 1000);
    		hci_close_dev(dd);
    	}
    //4)命令运行
    	while (argc > 0) {
    		for (i = 0; command[i].cmd; i++) {
    			if (strncmp(command[i].cmd, *argv, 5))
    				continue;
    
    			if (command[i].opt) {
    				argc--; argv++;
    			}
    
    			command[i].func(ctl, di.dev_id, *argv);
    			cmd = 1;
    			break;
    		}
    		argc--; argv++;
    	}
    
    	if (!cmd)//没有对应的命令打印出
    		print_dev_info(ctl, &di);
    //5)、关闭ctl,完毕操作
    	close(ctl);
    	return 0;
    }
    

    1)、打开HCI socket通信

    /* Open HCI socket  */
    	if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
    int socket(int domain, int type, int protocol);
    

    參数说明:
      domain:
    指明所使用的协议族,通常为PF_INET,表示TCP/IP协议。
      type:參数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字
      protocol:通常赋值"0"。

    程序中蓝牙建立:

    damain:使用AF_BLUETOOTH;
    idh.code3rdpartyluetoothTrout_BTspecialandroidkernelinclude
    etluetoothluetooth.h
    #define AF_BLUETOOTH	31
    type: SOC_SEQPACKET,以Packet为单位读取。SOC_RAW:原始socket
    enum sock_type {
    	SOCK_STREAM	= 1,
    	SOCK_DGRAM	= 2,
    	SOCK_RAW	= 3,
    	SOCK_RDM	= 4,
    	SOCK_SEQPACKET	= 5,
    	SOCK_DCCP	= 6,
    	SOCK_PACKET	= 10,
    };
    protocol:使用对应建立的Socket的protocol,不同类型的入L2CAP、HCI、SCO……
    #define BTPROTO_L2CAP	0
    #define BTPROTO_HCI	1
    #define BTPROTO_SCO	2
    #define BTPROTO_RFCOMM	3
    #define BTPROTO_BNEP	4
    #define BTPROTO_CMTP	5
    #define BTPROTO_HIDP	6
    #define BTPROTO_AVDTP	7
    
    2)、通过ioctl获取HCI驱动信息,写入struct hci_dev_info di结构体

             if(ioctl(ctl, HCIGETDEVINFO, (void *) &di))
    idh.code3rdpartyluetoothTrout_BTspecialandroidkernelinclude etluetoothhci.h相关命令的定义

    #define HCIGETDEVLIST	_IOR('H', 210, int)
    #define HCIGETDEVINFO	_IOR('H', 211, int)
    #define HCIGETCONNLIST	_IOR('H', 212, int)
    #define HCIGETCONNINFO	_IOR('H', 213, int)
    #define HCIGETAUTHINFO	_IOR('H', 215, int)
    	di对应的数据结构
    static struct hci_dev_info di;
    struct hci_dev_info {
    	__u16 dev_id;
    	char  name[8];
    	bdaddr_t bdaddr;
    	__u32 flags;
    	__u8  type;
    	__u8  features[8];
    	__u32 pkt_type;
    	__u32 link_policy;
    	__u32 link_mode;
    	__u16 acl_mtu;
    	__u16 acl_pkts;
    	__u16 sco_mtu;
    	__u16 sco_pkts;
    	struct hci_dev_stats stat;
    };
    
    3)、hci_test_bit bacmp
    	if (hci_test_bit(HCI_RAW, &di.flags) &&
    			!bacmp(&di.bdaddr, BDADDR_ANY)) {
    		int dd = hci_open_dev(di.dev_id);
    		hci_read_bd_addr(dd, &di.bdaddr, 1000);
    		hci_close_dev(dd);
    	}
    

    推断di中相关參数。


    hci_test_bit检測*addr的第nr位是否为1(*addr右起最低位为第0位)

    static inline int hci_test_bit(int nr, void *addr)
    {
    	return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
    }
    

    4)、命令运行,这部分是命令实现的部分

    	while (argc > 0) {
    		for (i = 0; command[i].cmd; i++) {
    			if (strncmp(command[i].cmd, *argv, 5))//通过for循环比較第二个參数
    				continue;
    
    			if (command[i].opt) {
    				argc--; argv++;
    			}
    
    			command[i].func(ctl, di.dev_id, *argv);//假设參数对应,就运行对应的命令函数
    			cmd = 1;
    			break;
    		}
    		argc--; argv++;
    	}
    	if (!cmd)//没有对应的命令打印出
    		print_dev_info(ctl, &di);
    

    a、如:if (strncmp(command[i].cmd, *argv, 5))// 通过for循环比較第二个參数
    | 如命令:hciconfighci0 commands
    argv 的值就为:commands字符串,假设5个字符相等。



    b、假设对应。就运行对应的命令函数

    command[i].func(ctl, di.dev_id, *argv);
    c、假设是commands命令:对应command[]结构体中的数组
    	{ "commands",	cmd_commands,	0,		"Display supported commands" },

    command[i].func = cmd_commands
    对应commands 的实现函数cmd_commands函数的实现:

    static void cmd_commands(int ctl, int hdev, char *opt)
    {
    	uint8_t cmds[64];
    	char *str;
    	int i, n, dd;
    
    	dd = hci_open_dev(hdev);
    	if (dd < 0) {
    		fprintf(stderr, "Can't open device hci%d: %s (%d)
    ",
    						hdev, strerror(errno), errno);
    		exit(1);
    	}
    
    	if (hci_read_local_commands(dd, cmds, 1000) < 0) {
    		fprintf(stderr, "Can't read support commands on hci%d: %s (%d)
    ",
    						hdev, strerror(errno), errno);
    		exit(1);
    	}
    
    	print_dev_hdr(&di);
    	for (i = 0; i < 64; i++) {
    		if (!cmds[i])
    			continue;
    
    		printf("%s Octet %-2d = 0x%02x (Bit",
    			i ? "		 ": "	Commands:", i, cmds[i]);
    		for (n = 0; n < 8; n++)
    			if (cmds[i] & (1 << n))
    				printf(" %d", n);
    		printf(")
    ");
    	}
    
    	str = hci_commandstostr(cmds, "	", 71);
    	printf("%s
    ", str);
    	bt_free(str);
    
    	hci_close_dev(dd);
    }
    这个是针对每一个命令实现的具体函数。
    //5)、关闭ctl,完毕操作
    	close(ctl);
    	return 0;
    

    3、hciconfig命令经常用法:
    (1)、帮助命令:查看hciconfig支持的命令和用法
    hciconfig –h或者hciconfig  --hlep

    (2)、查看蓝牙相关信息

    hciconfig –a


    root@android:/ # hciconfig -a
    hciconfig -a
    hci0:   Type: BR/EDR  Bus: UART//蓝牙的接口类型。这个是UART的。还有USB、PCI…………
            BD Address: 00:16:53:96:22:53  ACL MTU: 1021:8  SCO MTU: 120:10//蓝牙地址
            UP RUNNING PSCAN//命令状态
            RX bytes:2846 acl:0 sco:0 events:67 errors:0
            TX bytes:2034 acl:0 sco:0 commands:80 errors:0
            Features: 0xff 0xff 0x8d 0xfe 0x9b 0xbf 0x79 0x83
            Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3//支持数据包
            Link policy: RSWITCH HOLD SNIFF PARK
            Link mode: SLAVE ACCEPT//连接的类型。是主设备、从设备
            Name: 'sp8825c1'//蓝牙名称
            Class: 0x5a020c//蓝牙的类型
            Service Classes: Networking, Capturing, Object Transfer, Telephony//支持的类型
            Device Class: Phone, Smart phone
            HCI Version: 2.1 (0x4)  Revision: 0x1250//HCI版本号
            LMP Version: 2.1 (0x4)  Subversion: 0x1250//LMP版本号
            Manufacturer: Ericsson Technology Licensing (0)//作者
    

    (3)、启动蓝牙
    hciconfig hci0 up
    (4)、关闭蓝牙
    hciconfig hci0 down
    (5)、查看hci命令
    hciconfighci0 commands 

    (6)、显示OOB数据
    Hciconfig hci0 oobdata



    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Linux环境下为普通用户添加sudo权限
    【转】在 Ubuntu 中使用 NTP 进行时间同步
    Shell脚本:批量添加用户,并设置随机字符为密码
    【转】Linux目录结构和常用命令
    系统启动流程
    linux系统利用libudev获取USB设备的VID和PID
    cJSON详解
    ajax读取文件内容
    window.location网页URL信息
    html实现网站全局按钮点击后置灰,不允许连续点击
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4668337.html
Copyright © 2011-2022 走看看