基于BlueZ的C语言蓝牙编程

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

 

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

原文出处:
http://people.csail.mit.edu/albert/bluez-intro/c401.html

第四章 基于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 <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;
}


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]http://www.bluez.org/lists.html
  
[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]http://www.bluetooth.org/spec

 

 

 

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

#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>   //蓝牙的3个头文件.
#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 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;
}
最后把这个程序交叉编译了一下,也通过了.但是还没有测试.明天再来传到板子上.
还没有正式在板子上运行过蓝牙,可能还有很多问题.
  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言是一种编程语言,可以用来开发蓝牙控制程序。在Linux操作系统中,蓝牙控制通常使用bluez库来实现。 bluez是一个开源的蓝牙协议栈,提供了一组API(应用程序编程接口)供开发者使用。通过这些API,我们可以使用C语言程序来控制蓝牙设备。 首先,需要使用bluez的API来初始化蓝牙适配器。这可以通过调用bluez库中的函数来完成。接着,我们可以使用bluez提供的函数来搜索蓝牙设备、进行设备配对和连接等操作。 在搜索蓝牙设备时,可以使用bluez的函数来获取设备列表,并通过遍历列表来找到需要的设备。可以获取设备的MAC地址、设备名称等信息。 通过bluez的API,我们可以向蓝牙设备发送命令,如连接、断开连接、发送数据等。可以控制蓝牙设备的功能,如打开、关闭、切换模式等。 在使用bluez进行蓝牙控制时,需要注意一些细节。例如,要确保程序有足够的权限来进行蓝牙操作。还要处理错误和异常情况,以确保程序的稳定性。 总的来说,通过使用C语言结合bluez的API,我们可以实现蓝牙设备的控制。这样,我们就能够使用C语言程序,来实现蓝牙设备的连接、数据传输等功能。 ### 回答2: C语言是一种高级编程语言,它可以用于开发各种应用程序,包括蓝牙控制。Bluez是一个用于在Linux系统上进行蓝牙通信的开源协议栈。 基于Bluez蓝牙控制需要使用C语言程序。首先,我们需要使用C语言蓝牙库来创建一个蓝牙连接。通过调用库函数,我们可以初始化蓝牙控制器,扫描附近的蓝牙设备,连接到特定的设备,并进行数据传输。 在程序中,我们可以使用C语言相应的函数来实现具体的蓝牙控制操作。例如,我们可以创建一个函数来扫描周围的蓝牙设备,并返回设备的名称、地址等信息。另外,我们还可以编函数来连接到蓝牙设备、发送和接收数据等。 在编蓝牙控制程序时,我们需要理解蓝牙协议的相关知识,包括蓝牙设备的配对、连接、数据传输等过程。同时,我们还需要了解Bluez协议栈的API函数和数据结构,以便正确地使用它们。 需要注意的是,基于Bluez蓝牙控制开发通常需要在Linux系统中进行,因为Bluez是为Linux系统设计的。在其他操作系统中,可能需要使用不同的API或协议栈来进行蓝牙控制。 总之,通过使用C语言和基于Bluez蓝牙控制,我们可以实现蓝牙设备的控制和数据传输。这样,我们就可以开发出各种功能丰富的蓝牙应用程序,如蓝牙音频、蓝牙设备控制等。 ### 回答3: C语言是一种程序设计语言,可以用于开发各种应用程序。在蓝牙设备的控制方面,使用BlueZ库可以实现对蓝牙功能的编程控制。 BlueZ是一个开源的蓝牙协议栈,为Linux操作系统提供了完善的蓝牙支持。它提供了一系列的API函数,可以通过C语言进行调用,用于与蓝牙设备进行交互。 通过BlueZ库,我们可以实现蓝牙设备的连接、断开、扫描设备、发送和接收数据等功能。首先,我们需要初始化蓝牙适配器并获取蓝牙设备的句柄。然后,我们可以使用相应的API函数来执行蓝牙设备的操作。例如,使用"hci_open_dev()"函数打开蓝牙适配器,使用"hci_inquiry()"函数进行设备扫描,使用"l2cap_create_channel()"函数创建L2CAP通道等。 在使用C语言蓝牙控制程序时,我们需要熟悉BlueZ库提供的API函数及其参数的使用方法。同时,我们还需要了解蓝牙协议的相关知识,以便正确地进行蓝牙设备的连接和数据交互操作。 总之,通过C语言基于BlueZ蓝牙控制,我们可以实现对蓝牙设备的各种功能进行编程控制,并开发出满足特定需求的蓝牙应用程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值