关键词: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[]结构体中的命令字符串打印出来:以下两个截图就一目了然了:

命令运行结果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHViaW4zNDE3MTk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHViaW4zNDE3MTk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
(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

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

Android blueZ HCI(一个):hciconfig实施和经常使用的更多相关文章

  1. S5PV210之Sate210-F DIY硬件,移植uboot,kernel,android 活动现在已经进入实施阶段吗,欢迎广大网友参与 !

    大家一起来diy 超低价四核的exynos4412或者Cortex A8S5pv210开源开发板 商业版Sate210已经完成了好久了.Sate4412 也已经出来.但是这两个接口非常全,主要是针对企 ...

  2. Android发展的一个重要方面Makefile分析

    Android发展的一个重要方面Makefile分析 随着移动互联网的发展,移动开发也越来越吃香了.眼下最火的莫过于android.android是什么就不用说了,android自从开源以来,就受到非 ...

  3. 二维码合成,将苹果和安卓(ios和android)合成一个二维码,让用户扫描一个二维码就可以分别下载苹果和安卓的应用

    因为公司推广的原因,没有合适的将苹果和安卓(ios和android)合成一个二维码的工具. 因为这个不难,主要是根据浏览器的UA进行判断,所以就自己开发了一个网站 网站名称叫:好推二维码  https ...

  4. Android 如何判断一个应用在运行(转)

    Android 如何判断一个应用在运行  在一个应用中,或一个Service .Receiver中判断一个应用是否正在运行,以便进行一些相关的处理. 这个时候我们需要得到一个ActivityManag ...

  5. android studio 导入一个已有的android studio project作为lib使用

    android studio 导入一个已有的android studio project作为lib使用 新项目来了. 需要搭建框架. android studio对我来说还是很陌生,之前一个项目在同事 ...

  6. Android Studio新建一个HelloWorld 程序(App)

    Android Studio新建一个HelloWorld程序(App) 新建 或者直接启动程序(注:如果已有程序,此方法会直接打开最近一次关闭从程序) 更改App名 选择App运行平台 选择模板 更改 ...

  7. android 自己创建一个凝视模板

    android  自己创建一个凝视模板 作为一名程序猿 不仅要有一个写代码的能力,养成一个良好的编写习惯也是非常重要的. 今天给大家具体介绍一下怎样创建凝视模板,给每一个类和方法都自己手动去凝视信息也 ...

  8. Android下实现一个简单的计算器源码

    下面的内容是关于Android下实现一个简单的计算器的内容. import android.app.Activity; import android.os.Bundle;import android. ...

  9. [android] android下创建一个sqlite数据库

    Sqlite数据库是开源的c语言写的数据库,android和iphone都使用的这个,首先需要创建数据库,然后创建表和字段,android提供了一个api叫SQLiteOpenHelper数据库的打开 ...

随机推荐

  1. 选择标识符(identifier)

    整数通常是标识列最好的选择,因为它们很快并且可以使用auto_increment:千万不要使用enum和set类型作为标识列:尽量避免使用字符串类型作为标识列,因为他们很消耗空间,并且通常比数字类型慢 ...

  2. js获取浏览器和元素对象的尺寸

    1.屏幕尺寸 window.screen.height //屏幕分辨率的高 window.screen.width //屏幕分辨率的宽 window.screen.availHeight //屏幕可用 ...

  3. 多线程之线程通信条件Condition二

    接上一篇,实现Condition三个条件,有这样一个应用: 1. 有三个进程,第一个进程运行1次,第二个进程运行2次,第三个进程运行3次: 2. 先运行第二个进程,然后第一个,然后第三个: 3.  依 ...

  4. java用volatile或AtomicBoolean实现高效并发处理 (只初始化一次的功能要求)

    最近碰到一个这样的功能要求:怎么在一个类里面,实现高效并发处理下只可以初始化一次的方法? 实现方式: 1)volatile方式: /** * Created by Chengrui on 2015/7 ...

  5. [内核编程] 4.5 HOOK分发函数

    4.5 HOOK分发函数 本节开始深入的探讨键盘的过滤与反过滤.有趣的是,无论是过滤还是反过 滤,其原理都是进行过滤.取胜的关键在于:谁将第一个得到信息. 黑客可能会通过修改一个已经存在的驱动对象(比 ...

  6. [CSS] Showing horizontal scrollbar always for the table

    table { display: block; overflow: scroll; width: 200px; height:95vh; }

  7. xv6 gdb

    The "remote" target does not support "run". https://sourceware.org/gdb/onlinedoc ...

  8. 【图解】Web前端实现相似Excel的电子表格

     在本文中,我将用图解的方式用Wijmo(JavaScript库)中的SpreadJS来一步一步实现网页上的电子表格产品SpreadSheet(比如可构建Office 365 Excel产品.Go ...

  9. 1069. The Black Hole of Numbers (20)【模拟】——PAT (Advanced Level) Practise

    题目信息 1069. The Black Hole of Numbers (20) 时间限制100 ms 内存限制65536 kB 代码长度限制16000 B For any 4-digit inte ...

  10. 编写ATL控件的简单做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 ATL并不像MFC库那样提供了很多的控件窗口类,因此要使用ATL的话需要自己去封装.封装的做法很简单.比如现在我需要一 ...