Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3121051
  • 博文数量: 396
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4209
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(396)

文章存档

2022年(1)

2021年(2)

2020年(8)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: 嵌入式

2017-11-01 14:53:42

hci_inquiry()   //查询周围蓝牙设备并获取其地址
sdp_connect()   //链接到蓝牙设备的sdp服务器
sdp_list_append()  //添加sdp查询列表项
sdp_service_search_attr_req() //带服务属性的服务查询请求,查询蓝牙设备,有那些服务及每个服务的属性
sdp_uuid16_create()  //为sdp查询创建通用唯一标识(UUID)
rfcomm_read_config()  //创建串口练级,链接好后,在/dev/bluetooth/rfcomm/目录下会出现以程序给定的本地信道号命名的串口设备名/dev/bluetooth/rfcomm/0

ioctl()    //
open()    //
termios()   //
write()    //
read()    //
ioctl()    //
 

//main.c  line;136

static int create_dev(int ctl, int dev, uint32_t flags, bdaddr_t *bdaddr, int argc, char **argv)
{
     struct rfcomm_dev_req req;
     int err;

     memset(&req, 0, sizeof(req));
     req.dev_id = dev;
     req.flags = flags;
     bacpy(&req.src, bdaddr);

     if (argc < 2) {
         if ((err = rfcomm_read_config(rfcomm_config_file)) < 0) {
             perror("Can't open RFCOMM config file");
             return err;
         }

         bacpy(&req.dst, &rfcomm_opts[dev].bdaddr);
         req.channel = rfcomm_opts[dev].channel;

         if (bacmp(&req.dst, BDADDR_ANY) == 0) {
             fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
             return -EFAULT;
         }

     } else {
         str2ba(argv[1], &req.dst);

         if (argc > 2)
             req.channel = atoi(argv[2]);
         else
             req.channel = 1;
     }

     if ((err = ioctl(ctl, RFCOMMCREATEDEV, &req)) < 0 )
         perror("Can't create device");

     return err;
}

 
 
 

//parser.c  line: 1705

int rfcomm_read_config(char *filename)
{
     extern FILE *yyin;
     char file[MAXPATHLEN + 1];
     int i;

     for (i = 0; i < RFCOMM_MAX_DEV; i++) {
         rfcomm_opts[i].bind = 0;
         bacpy(&rfcomm_opts[i].bdaddr, BDADDR_ANY);
         rfcomm_opts[i].channel = 1;
     }

     if (filename) {
         snprintf(file, MAXPATHLEN, "%s", filename);
     } else {
         snprintf(file, MAXPATHLEN, "%s/.bluetooth/rfcomm.conf", getenv("HOME"));

         if ((getuid() == 0) || (access(file, R_OK) < 0))
             snprintf(file, MAXPATHLEN, "%s/rfcomm.conf", CONFIGDIR);
     }

     if (!(yyin = fopen(file, "r")))
         return -1;

     lineno = 1;
     yyparse();

     fclose(yyin);

     return 0;
}

 

 
 
###########################################################
 
 

原文出处:


第四章 基于BlueZ的C语言蓝牙编程

    有很多理由促使我们选用C替代其他高级语言来例如Python来开发蓝牙应用程序。Python环境可能并不适合于嵌入式系统。因为嵌入式系统对程序的大 小,运行速度,和占用的存储空间有严格的限制,这些都使得像Python之类的解释性语言无法在嵌入式系统上应用。程序员需要对本地的蓝牙适配器进行更好 的控制,或者需要建立一套动态链接库以便于其他应用程序的链接以取代单一的应用程序。就像上述描述的这些,BlueZ是一款强大的蓝牙通信协议栈,它扩展 的API使得用户方便操纵大量的蓝牙资源。但是BlueZ没有官方的描述文档,甚至非官方的文档也寥寥无几。初学者在BlueZ的官方邮件列表上请求相关 的文档,通常的得到的回复是被告知请通过仔细阅读源代码来了解API的功能。阅读BlueZ的源代码对于初学者来说是一项相当费时的,在短期内取得的进展是相当有限的,很可能成为很多蓝牙编程初学者的拦路虎。
    本章简要叙述了基于BlueZ的C语言蓝牙编程的方法。本章为C程序员进一步阐述了第二章中涉及的知识点。

4.1 选择一个通信的对象
    Example 4-1是一个查找周边蓝牙设备的简单应用程序。程序首先获取系统的蓝牙设备号,扫描周边的蓝牙设备,然后查找每一个被搜索到的蓝牙设备的名称。后边有对数据结构和函数的详细描述。

Example 4-1. simplescan.c

#include
#include
#include
#include
#include
#include
#include

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;
}


4.1.1 编译

     编译需要使用gcc链接libbluetooth这个库。

gcc -o simplescan simplescan.c -lbluetooth


4.1.2. 解释

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


蓝牙设备的地址采用结构体bdaddr_t来描述,BlueZ中队蓝牙地址的存储和操纵都使用bdaddr_t结构体,BlueZ提供两个函数来进行字符串到蓝牙地址的转换。
int str2ba( const char *str, bdaddr_t *ba );
int ba2str( const bdaddr_t *ba, char *str );

str2ba把形如XX:XX:XX:XX:XX:XX(XX标识48位蓝牙地址的16进制的一个字节)的字符串转化6字节的bdaddr_t结构, ba2str完成相反的功能。

本地蓝牙适配器被分配一个从0开始的识别号码。程序在分配系统资源时必须指定使用那一个蓝牙适配器,通常的话系统只有一个蓝牙适配器,把参数NULL传给hci_get_route可以获得第一个有效的蓝牙适配器识别号。

int hci_get_route( bdaddr_t *bdaddr );
int hci_open_dev( int dev_id );


[note]将适配器的设备号指定为0是不恰当的,因为它并不总代表第一个可用的蓝牙适配器。例如系统有两个蓝牙适配器,第一个被disable掉了,那么第一个有效的设备号就是2。

如果存在多个蓝牙适配器,选择"01:23:45:67:89:AB"作为蓝牙适配器的地址, 将指示这个地址的指针char *representation传给hci_devid函数,用这个函数替代hci_get_route。

很 多蓝牙操作都需要打开一个套接口, hci_open_dev函数可以打开特定资源号的一个套接口,确切的说hci_open_dev打开的套接字建立了一条和本地蓝牙适配器控制器的连接, 而不是和远端蓝牙设备的连接。使用这个套接口发送命令到蓝牙控制器可以实现底层的蓝牙操作,这部分在4.5中有详细的讨论。

选择好本地蓝牙适配器并进行系统资源分配后,程序就可以开始扫描周边的蓝牙设备了,在这个例程中,hci_inquiry函数完成对蓝牙设备的搜寻,并将返回的设备信息数据记录在变量ii中。遇到错误时,它将返回-1并设置errno变量。

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


hci_inquiry 的参数需要使用设备资源号而非套接口,所以我们使用hci_get_route函数的返回值dev_id传递给它。查询时间最长持续1.28 * len秒。max_rsp个设别返回的信息都被存储在变量ii中,这个变量必须有足够的空间来存储max_rsp返回的结果。我们推荐max_rsp取值 255来完成标准10.24秒的查询工作。

如果标志位flag设置为IREQ_CACHE_FLUSH,那么在进行查询操作时会把先前一次查询记录的cache刷新,否则flag设置为0的话,即便先前查询的设备已经不处于有效范围内,先前查询的记录也将被返回。
inquiry_info结构体定义如下

typedef struct {
     bdaddr_t bdaddr;
     uint8_t pscan_rep_mode;
     uint8_t pscan_period_mode;
     uint8_t pscan_mode;
     uint8_t dev_class[3];
     uint16_t clock_offset;
} __attribute__ ((packed)) inquiry_info;


在 大多数场合,我们仅用到成员bdaddr,它标识了设备的蓝牙地址。有些场合我们也会用到成员dev_class, 它标识了被检测到的蓝牙设备的一些信息(例如,识别这个设备是打印设备,电话,个人电脑等),详细地对应关系可以参见蓝牙设备分配号[3]。其余的成员在 用于底层通信,一般情况并不常用。感兴趣的读者可以阅读蓝牙内核规范[4]获取更多的信息。一旦周围的蓝牙设备和其蓝牙地址被检测到,程序可以将此设备的 名称提供给用户,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函数在规定的超时时间内使用套接口通过蓝牙地址ba去获取蓝牙设备的名称,成功返回0,并将获取的蓝牙设备名称存入name中;失败时返回-1并设置相应的errno。

Notes
[1]
  
[2] for the curious, it makes a call to socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI), followed by a call to bind with the specified resource number.
  
[3]https://www.bluetooth.org/foundry/assignnumb/document/baseband
  
[4]

 

 

 

###########################################################
今天用bluez的lib写了个小程序调试,运行通过.对linux下蓝牙编程有了点初步的认识.
功能就是检索周围是否有其它蓝牙设备,并得到他们的友好设备名.

#include
#include
#include

#include    //蓝牙的3个头文件.
#include
#include

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 error") ;
       exit(1) ;
   }
   len = 8 ;
   max_rsp = 255 ;
   flags = IREQ_CACHE_FLUSH;
   ii = (inquiry_info*)malloc (max_rsp* sizeof ( inquiry_info)) ;
   
   printf("start search...\n");
   num_rsp = hci_inquiry(dev_id , len , max_rsp , NULL, &ii , flags) ;   //检索周围是否有设备
   if ( num_rsp < 0 ) perror ("hci_inquiry error") ;
   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 ) ;
   }
   printf("end search.\n");
   free(ii);
   close(sock);
   return 0;
}
最后把这个程序交叉编译了一下,也通过了.但是还没有测试.明天再来传到板子上.
还没有正式在板子上运行过蓝牙,可能还有很多问题.
阅读(7216) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~