基于BlueZ 的BLE蓝牙开发

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010872301/article/details/80907325

蓝牙,是一种支持设备短距离通信(一般10m内)的无线电技术。工作在全球通用的2.4GHz ISM(即工业、科学、医学)频段。数据速率为1Mb/s。时分双工传输方案被用来实现全双工传输,使用IEEE802 15 .15协议。 蓝牙使用了更稳定和更快的跳频技术,使得蓝牙通信抗干扰能力更强。

 

一、 BlueZ 5.44体系结构

蓝牙技术的系统结构分为三大部分:底层硬件模块、中间协议层和应用层。

(1)底层硬件模块包括:无线跳频( RF)、基带( BB)和链路管理(LM)

  蓝牙的SIG规定了四种与硬件连接的物理总线方式USB、RS232、 UART和PC卡

(2)BlueZCore层包括各种Profile:

GAP:设备连接

SDAP:查询相关信息

SPP:虚拟串口连接

GOEP:数据传输

(3)中间协议层:

HCI接口:设备扫描、配对

L2CAP协议:蓝牙适配

(4)应用层包括BlueZ各种工具集:

hciconfig:配置蓝牙设备,用于打印设备信息和配置设备

hcitool:配置蓝牙连接,执行比如扫描等命令

gatttool:一种直接使用参数对蓝牙设备进行控制,二就是使用-I参数进入interactive模式对蓝牙设备进行控制

sdptool:搜索并管理设备服务

 

二、交叉编译蓝牙协议栈BlueZ 5.44

bin和sbin的编译安装目录下生成的操作蓝牙工具, libs编译安装目录下生成的是蓝牙通信时所依赖的库,其他的都是编译这两个所依赖的库,将bin、sbin和lib移植到板子上的相关文件中,下图是编译BlueZ 5.44所依赖的库。

#!/bin/sh
cd zlib-1.2.8
CC=arm-histbv310-linux-gcc ./configure --prefix=$PWD/../bluetooth-build/zlib-1.2.8-build 
make -j8
make install
cd -

cd libffi-3.0.13
./configure --prefix=$PWD/../bluetooth-build/libffi-3.0.13-build --host=arm-linux CC=arm-histbv310-linux-gcc
make -j8
make install
cd -

cd glib-2.40.0
./configure --prefix=$PWD/../bluetooth-build/glib-2.40.0-build --host=arm-linux CC=arm-histbv310-linux-gcc PKG_CONFIG_PATH=$PWD/../libffi-3.0.13-build/lib/pkgconfig  glib_cv_stack_grows=no glib_cv_uscore=yes ac_cv_func_posix_getpwuid_r=yes ac_cv_func_posix_getgrgid_r=yes CPPFLAGS="-I$PWD/../bluetooth-build/libffi-3.0.13-build/lib/libffi-3.0.13/include -I$PWD/../bluetooth-build/zlib-1.2.8-build/include" LDFLAGS="-L$PWD/../bluetooth-build/libffi-3.0.13-build/lib/ -L$PWD/../bluetooth-build/zlib-1.2.8-build/lib/"
make -j8
make install
cd -

cd expat-2.1.0
./configure --prefix=$PWD/../bluetooth-build/expat-2.1.0-build --host=arm-linux CC=arm-histbv310-linux-gcc
make -j8
make install
cd -

cd dbus-1.9.4
./configure --prefix=$PWD/../bluetooth-build/dbus-1.9.4-build --host=arm-linux --with-x=no --disable-tests --enable-abstract-sockets CC=arm-histbv310-linux-gcc CFLAGS=-I$PWD/../bluetooth-build/expat-2.1.0-build/include LDFLAGS=-L$PWD/../bluetooth-build/expat-2.1.0-build/lib
make -j8
make install
cd -

cd libical-1.0
./bootstrap 
./configure --prefix=$PWD/../bluetooth-build/libical-1.0-build --host=arm-linux CC=arm-histbv310-linux-gcc 
make -j8
make install
cd -

cd ncurses-5.9
./configure --prefix=$PWD/../bluetooth-build/ncurses-5.9-build --host=arm-linux CC=arm-histbv310-linux-gcc --with-shared
make -j8
make install
cd -

cd readline-6.3
./configure --prefix=$PWD/../bluetooth-build/readline-6.3-build --host=arm-linux CC=arm-histbv310-linux-gcc bash_cv_wcwidth_broken=yes
make -j8
make install
cd -

cd bluez-5.44
./configure --prefix=$PWD/../bluetooth-build/bluez-5.44-build --host=arm-linux CC=arm-histbv310-linux-gcc PKG_CONFIG_PATH=$PWD/../libffi-3.0.13-build/lib/pkgconfig CFLAGS="-I$PWD/../bluetooth-build/readline-6.3-build/include -I$PWD/../bluetooth-build/glib-2.40.0-build/include/glib-2.0 -I$PWD/../bluetooth-build/dbus-1.9.4-build/include/dbus-1.0" LDFLAGS="-lncurses  -lreadline -ldbus-1 -lglib-2.0 -lical -L$PWD/../bluetooth-build/readline-6.3-build/lib -L$PWD/../bluetooth-build/dbus-1.9.4-build/lib -L$PWD/../bluetooth-build/ncurses-5.9-build/lib -L$PWD/../bluetooth-build/glib-2.40.0-build/lib -L$PWD/../bluetooth-build/libical-1.0-build/lib" DBUS_CFLAGS="-I$PWD/../bluetooth-build/dbus-1.9.4-build/lib/dbus-1.0/include" DBUS_LIBS="-L$PWD/../bluetooth-build/dbus-1.9.4-build/lib" GLIB_CFLAGS="-I$PWD/../bluetooth-build/glib-2.40.0-build/lib/glib-2.0/include" GLIB_LIBS="-L$PWD/../bluetooth-build/glib-2.40.0-build/lib"  ICAL_CFLAGS="-I$PWD/../bluetooth-build/libical-1.0-build/include" ICAL_LIBS="-L$PWD/../bluetooth-build/libical-1.0-build/lib" --disable-systemd --disable-udev --disable-cups --disable-obex --enable-library --sysconfdir=/etc --localstatedir=/var --enable-experimental --with-systemdsystemunitdir=/lib/systemd/system --with-systemduserunitdir=/usr/lib/system --with-dbusconfdir=$PWD/../bluetooth-build/bluez-5.44-build/etc/dbus-1/system.d
make -j8
make install

#cd bluez-5.25
#./configure --prefix=$PWD/../bluetooth-build/bluez-5.25-build --host=arm-linux CC=arm-histbv310-linux-gcc PKG_CONFIG_PATH=$PWD/../libffi-3.0.13-build/lib/pkgconfig CFLAGS="-I$PWD/../bluetooth-build/readline-6.3-build/include -I$PWD/../bluetooth-build/glib-2.40.0-build/include/glib-2.0 -I$PWD/../bluetooth-build/dbus-1.9.4-build/include/dbus-1.0" LDFLAGS="-lncurses  -lreadline -ldbus-1 -lglib-2.0 -lical -L$PWD/../bluetooth-build/readline-6.3-build/lib -L$PWD/../bluetooth-build/dbus-1.9.4-build/lib -L$PWD/../bluetooth-build/ncurses-5.9-build/lib -L$PWD/../bluetooth-build/glib-2.40.0-build/lib -L$PWD/../bluetooth-build/libical-1.0-build/lib" DBUS_CFLAGS="-I$PWD/../bluetooth-build/dbus-1.9.4-build/lib/dbus-1.0/include" DBUS_LIBS="-L$PWD/../bluetooth-build/dbus-1.9.4-build/lib" GLIB_CFLAGS="-I$PWD/../bluetooth-build/glib-2.40.0-build/lib/glib-2.0/include" GLIB_LIBS="-L$PWD/../bluetooth-build/glib-2.40.0-build/lib"  ICAL_CFLAGS="-I$PWD/../bluetooth-build/libical-1.0-build/include" ICAL_LIBS="-L$PWD/../bluetooth-build/libical-1.0-build/lib" --disable-systemd --disable-udev --disable-cups --disable-obex --enable-library --sysconfdir=/etc --localstatedir=/var --enable-experimental --with-systemdsystemunitdir=/lib/systemd/system --with-systemduserunitdir=/usr/lib/system --with-dbusconfdir=$PWD/../bluetooth-build/bluez-5.25-build/etc/dbus-1/system.d
#make -j8
#make install
#cd -

配置海思的交叉编译工具链,移植linux内核, 创建rootfs根文件系统,实现蓝牙协议栈BlueZ的移植步骤:

移植并安装Realtek rtl8723BU驱动:

(1)进入内核配置界面,配置内核驱动文件:
$make menuconfig
Component  --->  
    [*] Bluetooth Support  --->
          BlueTooth Device Type  --->    
              [*] Realtek rtl8723bu bluetooth driver  
$ cd HiSTBLinuxV100R005C00SPC041\software\HiSTBLinuxV100R005C00SPC041\scripts\kconfig
将Kconfig.bluetooth改为y 编译:
make build -j8

(2)安装rtl8723BU驱动: 
#mount -t nfs -o nolock -o tcp 172.17.50.92:/home/gh /mnt
#cd /mnt/zxwork/ngb_w_nw3100/HiSTBLinuxV100R005C00SPC041/software/HiSTBLinuxV100R005C00SPC041/out/hi3798cv200/hi3798cv2dmo/kmod
#insmod rtk_8723btusb.ko 
#./bluez_init
#export LD_LIBRARY_PATH="/mnt/zhy/bluez5/lib:$LD_LIBRARY_PATH" 
#export LD_LIBRARY_PATH="/mnt/zxwork/ngb_w_nw3100/HiSTBLinuxV100R005C00SPC041/software/HiSTBLinuxV100R005C00SPC041/source/component/bluetooth/lib:$LD_LIBRARY_PATH"
#cd HiSTBLinuxV100R005C00SPC041/software/HiSTBLinuxV100R005C00SPC041/source/component/bluetooth/drv/usb_rtl8723bu
# cp rtl8723b* /lib/firmware/ 
修改:
Failed to start message bus:Could not get UID and GID for username "messagebus"
 
# vi /etc/passwd
root:x:0:0:root:/root:/bin/sh
stb:x:1000:1000:Linux User,,,:/home/stb:/bin/sh
sshd::15:50:::/bin/sh
messagebus:x:500:500::/home/messagebus:/bin/sh
 
(3)启动D-bus进程
#cd ngb_w_nw3100/HiSTBLinuxV100R005C00SPC041/software/HiSTBLinuxV100R005C00SPC041/source/component/bluetooth/src/install/usr/
bin/   sbin/  share/

(4)拷贝到板卡的:
# cp src/install/usr/bin/* /usr/bin/
# cp src/install/usr/sbin/* /usr/sbin/
# cp src/install/usr/share/bluetooth/ /usr/share/ -rf

 

三、交互模式和非交互模式命令

(1)交互模式

#./hcitool lescan  //扫描lemac地址

#./gatttool-b80:EA:CA:01:00:56 –I

>connect   //连接低功耗设备

>characteristics   //查看设备特征值

>char-write-cmd 0x0026 0100  //向连接设备中写入数据,发出notify,从而触发连接设备区采集温湿度,Value解释接受到的数据包。

另外还有其他命令,这两个命令,只能接收一次数据。

>char-read-hnd 25(handler)

>char-read-uuid fff8(uuid)

读取notifications里的内容,可以设置listen来开启监听否则每次只读一次,监听读取notifications时需要向该handle写入一个1,在命令行中16进制的表示为0100,若向该handle写入0200的话则改为读取indications的内容Value解释接收到的数据包。


(2)非交互模式

#./gatttool -b 80:EA:CA:01:00:54 --char-write-req    -a 0x0026 -n 0100 --listen

//读取notifications里的内容,监听读取notifications时需要向该handle写入一个1,在命令行中16进制的表示为0100,若向该handle写入0200的话则改为读取indications的内容,可以设置listen来开启监听否则每次只读一次。

四、编译gatttool工具,接受数据包

通过Bluez工具集gatttool接受传输的温湿度数据,通过gatt_connect获取命令行参数,执行低功耗蓝牙连接函数static voidconnect_cb,监听发送数据的事件,当主从蓝牙连接上后调用events_handler函数获取温湿度数据。

修改Bluez 的Makefile文件编译gatttool工具如下

 修改BlueZ 5.44的Makefile:  
 211行打开注释gatttool文件:  
 --am__append_40 = attrib/gatttool  
   
 492行打开注释gatttool文件:  
 am__EXEEXT_8 =  \  
    attrib/gatttool$(EXEEXT)  
       
 714-732行添加sqlite数据库和打开注释gatttool文件:  
 am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \  
     attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \  
     attrib/interactive.c attrib/utils.c src/log.c client/display.c \  
     client/display.h attrib/sqlite_operate.c  
 am_attrib_gatttool_OBJECTS =  \  
     attrib/gatttool.$(OBJEXT) \  
     attrib/att.$(OBJEXT) \  
     attrib/gatt.$(OBJEXT) \  
     attrib/gattrib.$(OBJEXT) \  
     btio/btio.$(OBJEXT) \  
     attrib/interactive.$(OBJEXT) \  
     attrib/utils.$(OBJEXT) \  
     src/log.$(OBJEXT) \  
     client/display.$(OBJEXT) \  
     attrib/sqlite_operate.$(OBJEXT)  
     attrib_gatttool_OBJECTS = $(am_attrib_gatttool_OBJECTS)  
     attrib_gatttool_DEPENDENCIES =  \  
     lib/libbluetooth-internal.la \  
     src/libshared-glib.la  
   
 2066行添加sqlite静态库:  
 -lsqlite3  
   
 2705_2712行打开注释gatttool文件:  
 attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \  
                 attrib/gattrib.c btio/btio.c \  
                 attrib/gatttool.h attrib/interactive.c \  
                 attrib/utils.c src/log.c client/display.c \  
                  client/display.h attrib/sqlite_operate.c  
   
attrib_gatttool_LDADD = lib/libbluetooth-internal.la \  
              src/libshared-glib.la -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluez-5.44/../bluetooth-build/glib-2.40.0-build/lib –lreadline

或者直接编译gatttool命令:
arm-histbv310-linux-gcc -o gatttool59 gatttool.c att.c gatt.c gattrib.c ../btio/btio.c sqlite_operate.c interactive.c utils.c ../src/log.c ../client/display.c -I../ -I../attrib/include  -I../../bluetooth-build/readline-6.3-build/include/ -L../lib/.libs/ -L../src/.libs -L./ -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluetooth-build/glib-2.40.0-build/lib -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluetooth-build/ncurses-5.9-build/lib -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluetooth-build/readline-6.3-build/lib -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluetooth-build/dbus-1.9.4-build/lib -L/work/gaohui/0421/HiSTBLinuxV100R005C00SPC041/cdrom/bluetooth/bluetooth-build/libical-1.0-build/lib -lglib-2.0 -lreadline -lncurses -lbluetooth-internal -lshared-glib -lsqlite3 -ldbus-1 -lical -DHAVE_CONFIG_H -DGAOHUI

温湿度数据包由10个16进制数据组成。第1-4位是第一个传感器的数据,这其中第一二位代表温度,三四位代表湿度。第5-8位是第二个传感器的数据,这其中第5-6位代表温度,7-8位代表湿度。第9-10位代表蓝牙设备的电量。

 

由DA14580温湿度传感器计算公式:

unsigned char rTempL = 0, rTempH = 0, rHumiL = 0, rHumiH = 0;

uint16_t tmp;

当前温度:

tmp = rTempH<<8 | rTempL;

temp1 = (int)(-46.85 + ((175.72 * tmp) /65536));

相对湿度:

tmp = rHumiH<<8 | rHumiL;

humi1 = (int)(-6 + ((125*tmp) /65536));

static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
    GAttrib *attrib = user_data;
	uint8_t *opdu;
	uint16_t handle, i, olen;
	size_t plen;
	GString *s;
	unsigned char rTempL = 0, rTempH = 0, rHumiL = 0, rHumiH = 0;
	char temp[4];
	long arr[4];
    int index=0;
	char* str;      
	long j;
	int tmp = 0;
	static int temp2 = 0,humi2 = 0;
	int temp1,humi1;
 
	FILE *out,*out_time;
	handle = get_le16(&pdu[1]);	
		
	switch (pdu[0]) {
	case ATT_OP_HANDLE_NOTIFY:
		s = g_string_new(NULL);
		g_string_printf(s, "", handle);
		break;
	case ATT_OP_HANDLE_IND:
		s = g_string_new(NULL);
		g_string_printf(s, "Indication   handle = 0x%04x value: ",handle);						
		break;
	default:
		error("Invalid opcode\n");
		return;
	}

	for (i = 3; i < len; i++)
		g_string_append_printf(s, "%02x ", pdu[i]);
	//printf("s1=%s\n", (char *)s->str);	
	 //rl_printf("%s\n", s->str);
	if(pdu[0] == ATT_OP_HANDLE_NOTIFY)
	 {
		    char *t=strtok((char *)s->str, " ");
			while(t!=NULL){
			switch(index){
				case 0:
				case 1:
				case 2:
				case 3:
					j = strtol(t, &str, 16);
					arr[index]=j;
					break;
			             }
			t=strtok(NULL," ");
			index++;		
		  }
#if 0
		int i=0;	
		for(i=0; i<4; i++){
			printf("arr[index]=%ld\n",arr[i]);
		}
#endif
		//温度:		
	       tmp = arr[0]*256 + arr[1];
	       temp1 = (int)(-46.85 + ((175.72 * tmp) /65536));
		//湿度:
	       tmp = arr[2]*256 + arr[3];
	       humi1 = (int)(-6 + ((125*tmp) /65536));					
		   //printf("temp1=%d, humi1=%d\n",temp1, humi1);		 		  

		 if((temp2 != temp1) ||(humi2 != humi1))
		 {
		     printf("temp1=%d, humi1=%d\n",temp1, humi1);
		  	 sqlite_update_tmd(temp1,humi1);
			 temp2 = temp1;
			 humi2 = humi1;
			 			     		     	     	
		 }
		
		fflush(NULL);   
	}

	g_string_free(s, TRUE);
	if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
		return;
	opdu = g_attrib_get_buffer(attrib, &plen);
	olen = enc_confirmation(opdu, plen);
	if (olen > 0)
		g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
}

 

展开阅读全文

没有更多推荐了,返回首页