原文出处:

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

}

最后把这个程序交叉编译了一下,也通过了.但是还没有测试.明天再来传到板子上.

还没有正式在板子上运行过蓝牙,可能还有很多问题.

linux c 蓝牙开发环境,基于BlueZ的C语言蓝牙编程相关推荐

  1. 基于BlueZ的C语言蓝牙编程

    hci_inquiry()   //查询周围蓝牙设备并获取其地址 sdp_connect()   //链接到蓝牙设备的sdp服务器 sdp_list_append()  //添加sdp查询列表项 sd ...

  2. 华山服务器安装linux系统,RHEL7/Centos7下使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境(2018...

    目录 1交叉编译环境搭建 交叉编译器下载链接: 1.1交叉编译器下载 将其下载到/usr目录下并解压. 解压命令: tar -xvf gcc-linaro-7.2.1-2017.11-i686_arm ...

  3. spring boot 与 iview 前后端分离架构之开发环境基于docker的部署的实现(三十六)

    spring boot 与 iview 前后端分离架构之开发环境基于docker的后端的部署的实现(三十六) 公众号 基于docker的后端的部署 安装mysql数据库 创建数据库 安装redis 安 ...

  4. Linux的C开发环境

    Linux的C开发环境 Linux的操作系统内核主要是由C编写,Linux下的很多软件也是由C编写的,比如MySQL.Apache等.初学者在编译这样的软件时,会遇到过各种错误,只要初步了解了Linu ...

  5. Linux搭建Kafka开发环境

    Linux搭建Kafka开发环境 Kafka是最初由Linkedin公司开发,是一个分布式.支持分区的(partition).多副本的(replica),基于zookeeper协调的分布式消息系统,它 ...

  6. win10下用Linux搭建pythonnodejs开发环境

    Win10下用自带Linux系统搭建开发环境 Win10下用自带Linux系统搭建开发环境 启用Linux 老版本(win10 1709之前): 新版本(win10 1709之后) 卸载linux 老 ...

  7. Linux下Java开发环境的搭建Tomcat6+jdk6+eclipse3.5.2+Myeclipse9.0+mysql5.1.47

    Tomcat6+jdk6+eclipse3.5.2+Myeclipse9.0+mysql5.1.47 1.JDK的安装:usr/java/jdk1.6.0_25 下载:jdk-6u25-linux-i ...

  8. 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)

    构建一个基本的前端自动化开发环境 -- 基于 Gulp 的前端集成解决方案(四) 参考文章: (1)构建一个基本的前端自动化开发环境 -- 基于 Gulp 的前端集成解决方案(四) (2)https: ...

  9. Linux下C开发环境的构成和安装

    本文介绍了Linux的C开发环境的构成和安装,使读者对Linux的C开发环境能有初步的了解. 你了解Linux吗?相信现在越来越多的人会说"是"的.那么你了解到何种程度呢?不可否认 ...

最新文章

  1. 求捐“一杯奶茶钱”,西北大学真成“最穷211”?
  2. 《Verilog HDL那些事儿》PDF 3.0版本发布
  3. 英特尔软件学院与中国一起迎接2008
  4. Lync Server 2010标准版系列PART6:启用Lync
  5. 实锤!Python 真没你想的那么简单…
  6. NTA告警引发的dll劫持思考(溯源)
  7. Android 之神 Jake Wharton 从 Square 离职!
  8. c语言中代码中的作用,C语言中#的神奇作用
  9. Dojo学习2 dojo快速安装
  10. hdfs中与file数组类似的数组_Java中的数组
  11. Python飞机大战代码
  12. steam一键授权工具_Sam Haynor的100个STEAM项目
  13. 马哥SRE第七周课程作业
  14. 将xlsx转换为xls格式
  15. 主角把异能开发计算机,不容错过的超能力游戏,最厉害的甚至能操控时间!
  16. 其他:鼠标滚轴坏了如何修?
  17. CSAPP buflab 实验报告
  18. matlab直角坐标方程,MATLAB 笛卡尔坐标系制图
  19. linux串口文件传输工具
  20. ...weights already exists, disallowed. Did you mean to set reuse=True...(解决办法)

热门文章

  1. 理论力学单自由度小阻尼受迫振动阻尼系数近似公式的推到
  2. qt修改linux波特率,Qt串口传输波特率问题。
  3. xss-labs/level4
  4. 复杂系统构建之——从人的极因说到《细胞叛逆者》
  5. windows重装系统后没有word、PPT、Excel?
  6. 调整Word字与字之间距离
  7. The desired archetype does not exist (org.apache.maven.archetypes:maven-archetype-quickstart:RELEASE
  8. ubuntu apt update hit get
  9. 痔疮需要用php吗,长了痔疮,一定要做手术根除?辟谣:2种情况才考虑切除
  10. 自卸汽车土方运输合同