博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android blueZ HCI(一个):hciconfig实施和经常使用
阅读量:7228 次
发布时间:2019-06-29

本文共 9120 字,大约阅读时间需要 30 分钟。

关键词:hciconfighcitool  hcidump

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


一、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 := optionalLOCAL_MODULE:=hciconfiginclude $(BUILD_EXECUTABLE)

2、hciconfig代码实现

idh.code\external\bluetooth\bluez\tools\hciconfig.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。解析命令參数支持长选项。即一对短横线、一个描写叙述性选项名称,还能够包括一个使用等号连接到选项的參数。

中有具体介绍。

即:hciconfig–all

main_optionsstatic 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.code\external\bluetooth\bluez\tools\hciconfig.c

static void usage(void){	int i;	printf("hciconfig - HCI device configuration utility\n");	printf("Usage:\n"		"\thciconfig\n"		"\thciconfig [-a] hciX [command]\n");	printf("Commands:\n");	for (i=0; command[i].cmd; i++)		printf("\t%-10s %-8s\t%s\n", 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.code\external\bluetooth\bluez\tools\hciconfig.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)\n",						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.code\3rdparty\bluetooth\Trout_BT\special\android\kernel\include\net\bluetooth\bluetooth.h#define AF_BLUETOOTH	31type: SOC_SEQPACKET,以Packet为单位读取。SOC_RAW:原始socketenum 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.code\3rdparty\bluetooth\Trout_BT\special\android\kernel\include\net\bluetooth\hci.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)\n",						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)\n",						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 ? "\t\t ": "\tCommands:", i, cmds[i]);		for (n = 0; n < 8; n++)			if (cmds[i] & (1 << n))				printf(" %d", n);		printf(")\n");	}	str = hci_commandstostr(cmds, "\t", 71);	printf("%s\n", 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 -ahciconfig -ahci0:   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

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

你可能感兴趣的文章
Odoo domain写法及运用
查看>>
JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
查看>>
猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
查看>>
面试题:给你个id,去拿到name,多叉树遍历
查看>>
go append函数以及写入
查看>>
关于Java中分层中遇到的一些问题
查看>>
配置 PM2 实现代码自动发布
查看>>
android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
查看>>
iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
查看>>
诡异!React stopPropagation失灵
查看>>
Python_OOP
查看>>
个人博客开发系列:评论功能之GitHub账号OAuth授权
查看>>
mongodb--安装和初步使用教程
查看>>
ES6简单总结(搭配简单的讲解和小案例)
查看>>
text-decoration与color属性
查看>>
如何使用Mybatis第三方插件--PageHelper实现分页操作
查看>>
PyCharm搭建GO开发环境(GO语言学习第1课)
查看>>
Android交互
查看>>
提醒我喝水chrome插件开发指南
查看>>
列表数据转树形数据
查看>>