蓝牙编程扫盲 搜索周边的蓝牙设备

程序执行效果:打印出了周围蓝牙设备的MAC地址,和名字

$ ./a.out
34:B2:0A:94:8E:5F  HUAWEI WATCH GT 2e-E5F
A4:50:46:8F:A3:F6  小米手机
E0:DC:FF:FC:21:64  小米手机
7C:B3:7B:29:99:4F  Hisense A5
9C:5F:5A:D4:A8:FE  OPPO A5

代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

int main(int argc, char **argv)
{
    inquiry_info *ii = NULL;
    int max_rsp, num_rsp;
    int dev_id, sock, len, flags;
    int i;
    char addr[19] = { 0 };
    char name[248] = { 0 };

    dev_id = hci_get_route(NULL);
    sock = hci_open_dev( dev_id );
    if (dev_id < 0 || sock < 0) {
        perror("opening socket");
        exit(1);
    }

    len  = 8;
    max_rsp = 255;
    flags = IREQ_CACHE_FLUSH;
    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
    
    num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
    if( num_rsp < 0 ) perror("hci_inquiry");

    for (i = 0; i < num_rsp; i++) {
        ba2str(&(ii+i)->bdaddr, addr);
        memset(name, 0, sizeof(name));
        if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), 
            name, 0) < 0)
        strcpy(name, "[unknown]");
        printf("%s  %s\n", addr, name);
    }

    free( ii );
    close( sock );
    return 0;
}

要提前安装开发库:

Debian-based systems:

$ sudo apt-get install libbluetooth-dev bluez-utils

CentOS system:

$  yum install bluez-devel

编译方法:

$ gcc -o simplescan simplescan.c -lbluetooth

标识蓝牙MAC地址的结构体。

typedef struct {
	uint8_t b[6];
} __attribute__((packed)) bdaddr_t;

bdaddr_t是用来标识蓝牙的MAC地址的,蓝牙的MAC地址格式:"XX:XX:XX:XX:XX:XX ",XX是16进制的数字,所有bluez提供了2个便利函数:

把字符串的MAC地址,转化成bdaddr_t格式。

int str2ba( const char *str, bdaddr_t *ba );

把bdaddr_t格式的MAC地址,转换成字符串格式

int ba2str( const bdaddr_t *ba, char *str );

函数:hci_get_route,参数是蓝牙MAC地址,返回设备id,后续的函数hci_open_dev要使用设备id。由于本电脑只有一个蓝牙适配器,所以参数给的是NULL,也就是0.

Local Bluetooth adapters are assigned identifying numbers starting with 0, and a program must specify which adapter to use when allocating system resources. Usually, there is only one adapter or it doesn't matter which one is used, so passing NULL to hci_get_route will retrieve the resource number of the first available Bluetooth adapter.

Note:It is not a good idea to hard-code the device number 0, because that is not always the id of the first adapter. For example, if there were two adapters on the system and the first adapter (id 0) is disabled, then the first available adapter is the one with id 1.

int hci_get_route( bdaddr_t *bdaddr );

如果知道了字符串格式的MAC地址了的话,可以使用hci_devid函数,来返回设备id。

int dev_id = hci_devid( "01:23:45:67:89:AB" );

函数:int hci_open_dev,根据参数(设备id),和本电脑的蓝牙控制芯片建立连接,也就是返回一个socket。所以此函数内部调用了:

socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)

之后又调用了bind函数。

注意:不是和周围别的蓝牙设备建立连接。

Most Bluetooth operations require the use of an open socket. hci_open_dev is a convenience function that opens a Bluetooth socket with the specified resource number [2]. To be clear, the socket opened by hci_open_dev represents a connection to the microcontroller on the specified local Bluetooth adapter, and not a connection to a remote Bluetooth device. Performing low level Bluetooth operations involves sending commands directly to the microcontroller with this socket, and Section 4.5 discusses this in greater detail.

int hci_open_dev( int dev_id );

和本电脑的蓝牙控制芯片建立连接后,就可以搜索周围的蓝牙设备了,使用函数:hci_inquiry

int hci_inquiry(int dev_id, int len, int max_rsp, const uint8_t *lap, inquiry_info **ii, long flags);

结构体inquiry_info:保存周围蓝牙设备的MAC地址等信息。除了bdaddr和dev_class外,其余的字段都是做低级操作的。

typedef struct {
    bdaddr_t    bdaddr;//MAC地址
    uint8_t     pscan_rep_mode;
    uint8_t     pscan_period_mode;
    uint8_t     pscan_mode;
    uint8_t     dev_class[3];//设备的类型,手机?电脑?PDA?等
    uint16_t    clock_offset;
} __attribute__ ((packed)) inquiry_info;

hci_inquiry函数执行成功后,返回0,并把周围的设备的MAC地址放入inquiry_info **ii里。max_rsp制定了最多可以放多少个。所以提前要开辟足够的内存空间。

flags如果设置成IREQ_CACHE_FLUSH ,则会重新搜索;如果是0,则返回上一次搜索的结果。

如果搜索到了周围的设备,则可以使用hci_read_remote_name,返回周围设备的名字

int hci_read_remote_name(int sock, const bdaddr_t *ba, int len, 
                         char *name, int timeout)

hci_read_remote_name tries for at most timeout milliseconds to use the socket sock to query the user-friendly name of the device with Bluetooth address ba. On success, hci_read_remote_name returns 0 and copies at most the first len bytes of the device's user-friendly name into name. On failure, it returns -1 and sets errno accordingly

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

posted @ 2020-07-24 19:09  小石王  阅读(26)  评论(0编辑  收藏