关键词:hciconfighcitool hcidump笔者:xubin341719(欢迎转载,请明确说明,请尊重版权,谢谢。)欢迎指正错误,共同学习、共同进步!
。
一、Hciconfig1、adb shell 下。hciconfig 运行文件的位/system/xbin/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–allmain_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;
后面这部分和命令解析一起分析。
case 'h': default: usage(); exit(0);
假设是help 运行usage这个函数。以下分析这个函数
idh.code\external\bluetooth\bluez\tools\hciconfig.cstatic 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.cstatic 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 72)、通过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
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
版权声明:本文博客原创文章,博客,未经同意,不得转载。