編輯:關於Android編程
關鍵詞: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 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、如果對應<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqOsvs3WtNDQz+DTprXEw/zB7rqvyv08YnIgLz48cHJlIGNsYXNzPQ=="brush:java;">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 -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
碰到幾個問題,記錄一下,方便其他網友查詢 我是win7,64位系統,JAVA以前裝過,所以沒有安裝JDK直接下載Android Studio進行安裝,結果提示沒有安裝
package com.dchan.myweather;import java.io.UnsupportedEncodingException;import java.n
穿插一篇自定義view 的動畫效果,偶然看到的一個gif刷新齒輪效果圖片,原圖如下:感覺挺有意思的,就想自己也做一個,發費了一番功夫,算是做出了基本效果,但原諒我使其美觀
關於布局動畫是針對ViewGroup而言的,意指ViewGroup在增加子View或者刪除子View時其子View的過渡動畫,在android官網有這麼一個簡單的例子,其