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.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,解析命令参数支持长选项。即一对短横线、一个描述性选项名称,还可以包含一个使用等号连接到选项的参数。

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.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	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.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

[email protected]:/ # 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

Android blueZ HCI(一):hciconfig实现及常用方法

时间: 2024-10-11 12:43:23

Android blueZ HCI(一):hciconfig实现及常用方法的相关文章

Android blueZ HCI(一个):hciconfig实施和经常使用

关键词:hciconfighcitool  hcidump笔者:xubin341719(欢迎转载,请明确说明,请尊重版权,谢谢.)欢迎指正错误,共同学习.共同进步! . Android blueZ HCI(一):hciconfig实现及经常用法Android blueZ hci(二):hcitool hcidump经常用法 一.Hciconfig1.adb shell 下.hciconfig 运行文件的位/system/xbin/hciconfig 对应文件夹下Android.mk文件,生成hc

Android 中常见控件的介绍和使用

1 TextView文本框 1.1 TextView类的结构 TextView 是用于显示字符串的组件,对于用户来说就是屏幕中一块用于显示文本的区域.TextView类的层次关系如下: java.lang.Object   ? android.view.View   ? android.widget.TextView 直接子类: Button, CheckedTextView, Chronometer, DigitalClock, EditText 间接子类: AutoCompleteTextV

我的Android进阶之旅------&gt;Android使用AlarmManager全局定时器实现定时更换壁纸

该DEMO将会通过AlarmManager来周期的调用ChangeService,从而让系统实现定时更换壁纸的功能. 更换壁纸的API为android.app.WallpaperManager,它提供了clear()方法来清除壁纸,还提供了如下方法来设置壁纸. setResource(int resid)将壁纸设置为resid资源所代表的图片 setBitmap(Bitmap bitmap)将壁纸设置为bitmap所代表的位图 setStream(InputStream data)将壁纸设置为d

蓝牙Bluez的编程实现

蓝牙的各个协议栈的简介 2 1.1.蓝牙技术 2 1.1.蓝牙协议栈 2 1.2.蓝牙技术的特点 4 1.2.1.蓝牙协议栈体系结构 4 1.2.2.蓝牙协议栈低层模块 5 1.2.3.软件模块 5 1.3.蓝牙的一些Profile 6 2.Bluez和D-Bus 8 2.1.Bluez和D-Bus体系结构 8 2.2.D-Bus介绍 10 2.3.Bluez的安全接口 14 2.4.Bluez适配器接口 19 2.5.Bluez配对 19 2.6.Bluez绑定 20 3.Bluez编程实现 

深入浅出 RecyclerView

常用方法 RecyclerView 与 ListView.GridView 类似,都是可以显示同一种类型 View 的集合的控件. 首先看看最简单的用法,四步走: 0.接入 build.gradle 文件中加入 compile 'com.android.support:recyclerview-v7:24.0.0' 1.创建对象 RecyclerView recyclerview = (RecyclerView) findViewById(R.id.recyclerview); 2.设置显示规则

序列化手段——parcel例子详解

Parcel其翻译为"包袱"."包裹".在Android系统中Binder进程间通信(IPC)中经常使用到Parcel类对象来实现客户端和服务端的数据交互,而AIDL技术也是通过Parcel来实现交互. 查阅Android源码Parcel类,其中常用方法有 obtain() 获得一个新的parcel对象,相当于java中new一个对象 dataSize() 得到当前parcel对象的实际存储空间 dataCapacity() 得到当前parcel对象的已分配的存储空

Android自学笔记之ProgressBar进度条的属性、常用方法及使用

1,属性: android:progress="0"  ----设置第一层进度条的初始值 android:max="100"  ---设置进度条的最大值 android:secondaryProgress="10"  --设置第二层进度条的初始值 2.进度条的常用方法: int getMax():返回这个进度条的最大值 int getProgress():返回进度条当前进度 int getSecondProgress():返回当前次要进度 voi

Android Canvas的常用方法

我们可以把这个Canvas理解成系统提供给我们的一块内存区域(但实际上它只是一套画图的API,真正的内存是下面的Bitmap),而且它还提供了一整套对这个内存区域进行操作的方法,所有的这些操作都是画图API.也就是说在这种方式下我们已经能一笔一划或者使用Graphic来画我们所需要的东西了,要画什么要显示什么都由我们自己控制. 这种方式根据环境还分为两种:一种就是使用普通View的canvas画图,还有一种就是使用专门的SurfaceView的canvas来画图.两种的主要是区别就是可以在Sur

Android View measure (三) 常用方法

ViewGroup.measureChildren() ViewGroup.measureChild() ViewGroup.measureChildWithMargins() /** * Ask one of the children of this view to measure itself, taking into * account both the MeasureSpec requirements for this view and its padding * and margins