RTL8723D蓝牙模组使用参考


1. 蓝牙依赖库准备

expat:https://github.com/libexpat/libexpat/releases

dbus:https://dbus.freedesktop.org/releases/dbus/

zlib:http://www.zlib.net/

libffi:https://www.sourceware.org/libffi/

gettext:http://www.gnu.org/software/gettext/

glib:http://ftp.gnome.org/pub/gnome/sources/glib/

libical:https://github.com/libical/libical

readline:http://ftp.gnu.org/gnu/readline/

ncurses:http://ftp.gnu.org/gnu/ncurses/

bluez:https://mirrors.edge.kernel.org/pub/linux/bluetooth/

alsa-lib:http://www.linuxfromscratch.org/blfs/view/svn/multimedia/alsa-lib.html

alsa-utils:http://www.linuxfromscratch.org/blfs/view/stable/multimedia/alsa-utils.html

sndfile:http://www.mega-nerd.com/libsndfile/#Download

sbc:https://mirrors.edge.kernel.org/pub/linux/bluetooth/

bluez-alsa:https://github.com/Arkq/bluez-alsa

bt_lib.tar.bz2的附件为本次用到的源码打包。


2. 蓝牙依赖库编译

下面流程以 arm-linux-gnueabihf- 8.2 为例,下面的INSTALL_PATH为lib install的位置,请自行更改。

设置环境变量INSTALL_PATH作为bluez的编译输出路径

export INSTALL_PATH=/customer/bluetooth/bluez_build

zlib:

export CC=arm-linux-gnueabihf-gcc

export AR=arm-linux-gnueabihf-ar

export RANLIB=arm-linux-gnueabihf-ranlib

./configure --prefix=$INSTALL_PATH/zlib

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/zlib/lib/pkgconfig/:$PKG_CONFIG_PATH

libffi:

./configure --prefix=$INSTALL_PATH/libffi --host=arm-linux --target=arm-linux CC=arm-linux-gnueabihf-gcc

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/libffi/lib/pkgconfig/:$PKG_CONFIG_PATH

gettext:

glib只需要gettext的头文件来协助编译,如果server环境已安装,可以不进行移植

编译命令如下:

./configure --prefix=$INSTALL_PATH/gettext --disable-libasprintf --host=arm-linux --target=arm-linux CC=arm-linux-gnueabihf-gcc

make && make install

PS:上述基于gettext-0.20.1,不知是否该版本的configure有bug,一开始配置--disable-libasprintf会导致configure不过,需要先进行一个configure,make报错后,重新添加--disable-libasprintf再configure一次才行。

Q1:

A:在configure 命令加入--disable-libasprintf

glib:

echo ac_cv_type_long_long=yes>>arm-linux-gnueabihf.cache

echo glib_cv_stack_grows=no>>arm-linux-gnueabihf.cache

echo glib_cv_uscore=no>>arm-linux-gnueabihf.cache

echo ac_cv_func_posix_getpwuid_r=yes>>arm-linux-gnueabihf.cache

echo ac_cv_func_posix_getgrgid_r=yes>>arm-linux-gnueabihf.cache

./configure --prefix=$INSTALL_PATH/glib --host=arm-linux --target=arm-linux CC="arm-linux-gnueabihf-gcc" CFLAGS="-I$INSTALL_PATH/zlib/include -I$INSTALL_PATH/libffi/include" LDFLAGS="-L$INSTALL_PATH/zlib/lib -L$INSTALL_PATH/libffi/lib" LIBS="-lz -lffi" --cache-file=arm-linux-gnueabihf.cache

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/glib/lib/pkgconfig/:$PKG_CONFIG_PATH

Q1:

A:若想自己进行移植可以参考上面gettext的移植参考。不想折腾的话,可以直接在server上安装gettext,apt-get install gettext

Q2:

A:同样不想折腾的话,直接在server上解决环境问题,apt-get install libglib2.0-dev

Q3:

A:请参考https://blog.csdn.net/zmlovelx/article/details/81664043

Q4:编译过程出现c:28:17: fatal error: ffi.h: No such file or directory

A:没有正确指定libffi的安装的头文件目录

Q5:编译过程中出现如下log

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_void'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_double'

./.libs/libgobject-2.0.so: undefined reference to `ffi_prep_cif'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_sint32'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_float'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_uint64'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_sint64'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_pointer'

./.libs/libgobject-2.0.so: undefined reference to `ffi_type_uint32'

./.libs/libgobject-2.0.so: undefined reference to `ffi_call'

A:没有正确指定libffi的lib路径或没有链接该库

Q6:编译过程中出现如下log

./.libs/libgio-2.0.so: undefined reference to `inflateReset'

./.libs/libgio-2.0.so: undefined reference to `inflateEnd'

./.libs/libgio-2.0.so: undefined reference to `inflateGetHeader'

./.libs/libgio-2.0.so: undefined reference to `deflate'

./.libs/libgio-2.0.so: undefined reference to `deflateInit_'

./.libs/libgio-2.0.so: undefined reference to `inflateInit2_'

./.libs/libgio-2.0.so: undefined reference to `inflate'

./.libs/libgio-2.0.so: undefined reference to `deflateSetHeader'

./.libs/libgio-2.0.so: undefined reference to `deflateEnd'

./.libs/libgio-2.0.so: undefined reference to `deflateReset'

./.libs/libgio-2.0.so: undefined reference to `inflateInit_'

./.libs/libgio-2.0.so: undefined reference to `deflateInit2_'

A:没有正确指定zlib的lib路径或没有链接该库

expat:

./configure --prefix=$INSTALL_PATH/expat --host=arm-linux --target=arm-linux CC=arm-linux-gnueabihf-gcc

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/expat/lib/pkgconfig/:$PKG_CONFIG_PATH

dbus:

echo ac_cv_have_abstract_sockets=yes>arm-linux-gnueabihf.cache

./configure --prefix=$INSTALL_PATH/dbus --host=arm-linux --target=arm-linux --disable-tests CC="arm-linux-gnueabihf-gcc -I$INSTALL_PATH/zlib/include -I$INSTALL_PATH/libffi/include -I$INSTALL_PATH/gettext/include -I$INSTALL_PATH/glib/include -I$INSTALL_PATH/expat/include -L$INSTALL_PATH/zlib/lib -L$INSTALL_PATH/libffi/lib -L$INSTALL_PATH/gettext/lib -L$INSTALL_PATH/glib/lib -L$INSTALL_PATH/expat/lib" --cache-file=arm-linux-gnueabihf.cache --with-x=no

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/dbus/lib/pkgconfig/:$PKG_CONFIG_PATH

Q1:

A:没有连接zlib和libffi的库,在configure命令链接这两个库

Q2:

A:这里仅仅dbus的test需要用到glib,我们可以直接不编译test,来解决这个报错,在configure命令添加--disable-tests。同样也可以链接上glib的所有库来修复,

./configure --prefix=$INSTALL_PATH --host=arm-linux --target=arm-linux CC="arm-linux-gnueabihf-gcc" CFLAGS="-I$INSTALL_PATH/include" LDFLAGS="-L$INSTALL_PATH/lib" LIBS="-lz -lffi -lgmodule-2.0 -lglib-2.0 -lgio-2.0 -lgobject-2.0 -lgthread-2.0" --cache-file=arm-linux-gnueabihf.cache --with-x=no

Q3:configure 过程中出现以下log

checking for EXPAT... configure: error: Package requirements (expat) were not met:

No package 'expat' found

A:指定expat库的路径

export EXPAT_LIBS="-lexpat -L$INSTALL_PATH/lib/"

export EXPAT_CFLAGS="-I$INSTALL_PATH/include/"

libical:

export CC=arm-linux-gnueabihf-gcc

export CXX=arm-linux-gnueabihf-g++

cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH/libical

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/libical/lib/pkgconfig/:$PKG_CONFIG_PATH

ncurses:

export CPPFLAGS="-P"

./configure --prefix=$INSTALL_PATH/ncurses --host=arm-linux --target=arm-linux --without-cxx-binding CC="arm-linux-gnueabihf-gcc" --enable-widec --with-shared

make && make install

Q1:

A:这里我们可以使用--without-cxx-binding来跳过C++编译的部分来规避。https://stackoverflow.com/questions/46793314/error-when-compiling-ncurses看起来除了换版本没有其他的办法。

readline:

./configure --prefix=$INSTALL_PATH/readline --host=arm-linux --target=arm-linux bash_cv_wcwidth_broken=yes CC=arm-linux-gnueabihf-gcc

make && make install

bluez:

./configure --prefix=$INSTALL_PATH/bluez --mandir=$INSTALL_PATH/bluez/man --sysconfdir=$INSTALL_PATH/bluez/etc --localstatedir=$INSTALL_PATH/bluez/var --host=arm-linux CC="arm-linux-gnueabihf-gcc -I$INSTALL_PATH/zlib/include -I$INSTALL_PATH/libffi/include -I$INSTALL_PATH/gettext/include -I$INSTALL_PATH/glib/include -I$INSTALL_PATH/expat/include -I$INSTALL_PATH/dbus/include -I$INSTALL_PATH/libical/include -I$INSTALL_PATH/ncurses/include -I$INSTALL_PATH/readline/include -L$INSTALL_PATH/zlib/lib -L$INSTALL_PATH/libffi/lib -L$INSTALL_PATH/gettext/lib -L$INSTALL_PATH/glib/lib -L$INSTALL_PATH/expat/lib -L$INSTALL_PATH/dbus/lib -L$INSTALL_PATH/libical/lib -L$INSTALL_PATH/ncurses/lib -L$INSTALL_PATH/readline/lib -lreadline -lncursesw" --enable-debug --enable-test --enable-shared --enable-testing --disable-udev --disable-systemd --disable-cups --disable-obex --enable-library --enable-tools --enable-deprecated

make && make install

export PKG_CONFIG_PATH=$INSTALL_PATH/bluez/lib/pkgconfig/:$PKG_CONFIG_PATH

Q1:configure过程出现xxx are required

A:pkgconfig没在环境变量PKG_CONFIG_PATH中

为了规范编译出来的文件,这里重新定义一个环境变量BLUEALSA_INSTALL_PATH做为编译bluealsa的输出路径

export BLUEALSA_INSTALL_PATH=/customer/bluetooth/bluealsa_build

export CC=arm-linux-gnueabihf-gcc

export CXX=arm-linux-gnueabihf-g++

alsa-lib:

./configure --prefix=$BLUEALSA_INSTALL_PATH/alsa/ --host=arm-linux --disable-aload --disable-rawmidi --disable-seq --disable-ucm --disable-alisp --disable-old-symbols --disable-python --enable-debug CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ --with-plugindir=$BLUEALSA_INSTALL_PATH/alsa/lib --with-configdir=$BLUEALSA_INSTALL_PATH/alsa/etc

make && make install

export PKG_CONFIG_PATH=$BLUEALSA_INSTALL_PATH/alsa/lib/pkgconfig/:$PKG_CONFIG_PATH

alsa-utils:

./configure --prefix=$BLUEALSA_INSTALL_PATH/alsa-utils --host=arm-linux --with-curses=ncurses CC="arm-linux-gnueabihf-gcc -lasound -I$BLUEALSA_INSTALL_PATH/alsa/include -L$BLUEALSA_INSTALL_PATH/alsa/lib" --disable-xmlto --disable-alsamixer

make && make install

sndfile:

./configure --prefix=$BLUEALSA_INSTALL_PATH/sndfile/ --host=arm-linux-gnueabihf --enable-shared CC=arm-linux-gnueabihf-gcc

make && make install

export PKG_CONFIG_PATH=$BLUEALSA_INSTALL_PATH/sndfile/lib/pkgconfig/:$PKG_CONFIG_PATH

sbc:

./configure --prefix=$BLUEALSA_INSTALL_PATH/sbc/ --host=arm-linux --enable-shared --enable-debug CC=arm-linux-gnueabihf-gcc

make && make install

export PKG_CONFIG_PATH=$BLUEALSA_INSTALL_PATH/sbc/lib/pkgconfig/:$PKG_CONFIG_PATH

bluez-alsa:

autoreconf --install

./configure --prefix=$BLUEALSA_INSTALL_PATH/bluez-alsa --host=arm-linux --enable-debug --enable-shared --enable-pcm-test CFLAGS="-I$INSTALL_PATH/zlib/include -I$INSTALL_PATH/libffi/include -I$INSTALL_PATH/gettext/include -I$INSTALL_PATH/glib/include -I$INSTALL_PATH/expat/include -I$INSTALL_PATH/dbus/include -I$INSTALL_PATH/libical/include -I$INSTALL_PATH/ncurses/include -I$INSTALL_PATH/readline/include -I$INSTALL_PATH/bluez/include -I$BLUEALSA_INSTALL_PATH/alsa/include -I$BLUEALSA_INSTALL_PATH/sndfile/include -I$BLUEALSA_INSTALL_PATH/sbc/include" LDFLAGS="-L$INSTALL_PATH/zlib/lib -L$INSTALL_PATH/libffi/lib -L$INSTALL_PATH/gettext/lib -L$INSTALL_PATH/glib/lib -L$INSTALL_PATH/expat/lib -L$INSTALL_PATH/dbus/lib -L$INSTALL_PATH/libical/lib -L$INSTALL_PATH/ncurses/lib -L$INSTALL_PATH/readline/lib -L$INSTALL_PATH/bluez/lib -L$BLUEALSA_INSTALL_PATH/alsa/lib -L$BLUEALSA_INSTALL_PATH/sndfile/lib -L$BLUEALSA_INSTALL_PATH/sbc/lib" LIBS="-lz -lffi -lglib-2.0 -lgmodule-2.0"

make && make install

export PKG_CONFIG_PATH=$BLUEALSA_INSTALL_PATH/bluez-alsa/lib/pkgconfig/:$PKG_CONFIG_PATH

Q1:

A:sudo apt-get install libtool

到此已经将蓝牙A2DP依赖的库全部编译出来。附件bt_build.tar.bz2为arm-linux-gnueabihf- 8.2工具链按照上述流程编译出来文件的打包。


3. 内核配置

内核中需要打开以下配置:

  1. 打开内核中蓝牙子系统的支持。

    Networking support --->

    Bluetooth subsystem support(此项设置y或m)

  2. 选择所需要的蓝牙功能

    这里比较关注的是标红的两项,这两项和蓝牙芯片控制器息息相关,其中BR/EDR即传统蓝牙,而LE则是低功耗蓝牙,两种协议不一样,需要根据蓝牙芯片的支持的模式来选择。

    这里的蓝牙是传统蓝牙,故对BR/EDR设置为y。第三项顾名思义是蓝牙的自测,第四项为debugfs设置为y。

    按如下图配置,当然也可以设置为m。而没有选上的BNEP和HIDP我们这里没有用到。BNEP:网络封装协议,一般用于作为网卡使用。HIDP则用于蓝牙键鼠等设备。

    后面选择蓝牙是通过什么方式连接到系统,选择下图红框选项选择蓝牙设备的连接方式,这里是uart。

  3. 打开ALSA选项

    Device Drivers --->

    Sound card support -→

  4. 支持在用户空间加载firmware

    Device Drivers --->

    Generic Driver Options -→

  5. 替换内核


4. 文件系统的准备

下面需要将相关的lib和bin档放到板子上。比较方便的办法就是删掉不必要的东西(include、man等目录)后将整个install目录完全拷贝到板端,这样可以避免因路径的问题导致的一些错误。


4.1. 搭建板端的bluez运行环境

下图是bluez及其所依赖的库编译生成的目录

从上图的各个目录下的lib目录下拷贝出相应的库及其符号链接文件,并做strip,拷贝到板端的/lib目录或其他地方并加入到板端的环境变量中。

在bluez和dbus的目录下拷贝出相应的tools并strip,以下只是一些常用的tools,请按实际情况进行拷贝,拷贝到板端的/bin目录或其他地方并加入到板端的环境变量中。

将bluetoothd(bluez的守护进程)拷贝到板端的/bin目录或其他地方并加入到板端的环境变量中。

在板端的INSTALL_PATH目录下新建一个etc/bluetooth目录,并拷贝bluez源码中的src/main.conf到板端的INSTALL_PATH/etc/bluetooth下,此文件为蓝牙的配置文件,存放一些基本信息,如蓝牙的名字等


4.2. 搭建板端的bluez-alsa运行环境

下图为bluez-alsa及其所依赖的库编译生成的目录

从上图的各个目录下的lib目录下拷贝出相应的库及其符号链接文件,并做strip,拷贝到板端的/lib目录或其他地方并加入到板端的环境变量中。

注意,这个alsa-lib里面的库需要拷贝到板端的$BLUEALSA_INSTALL_PATH/alsa/lib下

从各个目录中找出相关的tool,做strip,拷贝到板端的/bin目录或其他地方并加入到板端的环境变量中。

拷贝alsa/share,alsa/etc,拷贝到板端对应的绝对路径下,即在server中该目录的绝对路径要和板端的绝对路径一致。

将bluez-alsa生成的20-bluealsa.conf(bluez-alsa/share/alsa/alsa.conf.d/20-bluealsa.conf)拷贝板端的$BLUEALSA_INSTALL_PATH/alsa/etc/alsa.conf.d/下,没有此文件,bluez-alsa没法去虚拟一个alsa设备

bluetooth.tar.bz2为按照上述流程移植到板端的文件。


5. 功能验证

  1. insmod hci_xxx.ko(build-in请忽略)

  2. 蓝牙模块上电

  3. 加载对应的firmware(由蓝牙厂商提供)

  4. /var/run准备

    mkdir /var/run
    
    mount tmpfs /var/run -t tmpfs
    

    将/var/run挂载到tmpfs,因为bluealsa启动初始化时需要到这个目录去创建一个目录并创建一个socket,故需要该目录可写。

    由于bluealsa运行时需要访问/var/run/dbus,实际上需要访问的是bluez编译生成的var/run/dbus,故在此做了一个软链接来解决此问题。

    ln -s /customer/bluetooth/bluez_build/dbus/var/run/dbus /var/run/dbus
    
  5. 启动dbus的守护进程,dbus-daemon --system &

  6. 启动bluez的守护进程,bluetoothd -n -C &

  7. 启动bluealsa,bluealsa -p a2dp-source &

  8. 使用bluetoothctl或其他tools来查看蓝牙控制器的状态、打开/关闭、修改信息、配置状态、扫描、配对。

    查看蓝牙的状态,可使用bluetoothctl中的show命令或直接运行hciconfig –a。

    这里的Powered表示蓝牙是否开启,Discoverable表示是否可被发现。

    使用hciconfig hci0 up(这里的hci0请根据实际情况做更改)或bluetoothctl中的power on命令来打开蓝牙。

    开启蓝牙

    修改蓝牙名字可以通过hciconfig hci0 name xxx或bluetoothctl中的system-alias xxx以及修改conf来进行修改。

    设置蓝牙的代理能力,请按实际情况进行设置。

    蓝牙的可发现和可连接可以通过hciconfig hci0 piscan或bluetoothctl中的discoverable on来进行设置,但通过bluetoothctl来设置的话默认只有180秒的时间可以发现和连接蓝牙,若要修改时间,可将main.conf的此处#号去掉,即可一直可发现可连接。

    扫描蓝牙开关,使用bluetoothctl中的scan on/off命令。

    配对蓝牙,使用bluetoothctl中的pair + mac地址,来进行匹配。

    将蓝牙音箱添加为信任设备,使用bluetoothctl中的trust + mac地址来进行设置

    连接蓝牙,使用bluetoothctl中的connect + mac地址来进行连接。

    往蓝牙音箱丢数据

    aplay -D bluealsa:HCI=hci0,DEV=49:f5:31:5e:93:c8,PROFILE=a2dp /mnt/music/Wav_File/8K_16bit_STERO_30s.wav
    

    (hci0为板端蓝牙对应的hci控制器,49:f5:31:5e:93:c8为所使用的蓝牙音箱的蓝牙地址, /mnt/music/Wav_File/8K_16bit_STERO_30s.wav为所播完的wav档,以上参数请以实际情况为准。如果需要播放其他的格式如MP3,则bluealsa需要别的依赖,请自行移植)


6. FAQ

Q: dbus-daemon启动后kill掉无法重新启动,出现如下log:

A:删除板端$INSTALL_PATH/dbus/var/run/dbus/pid,也可以修改rcS文件,添加rm $INSTALL_PATH(对应自己板端的install绝对路径)/dbus/var/run/dbus/pid –f,dbus启动后会去创建这个文件,

若上一次开机启动dbus了关机没有删除该文件,会导致dbus没法启动,为省去麻烦修改rcS文件,每次开机都去删除一遍该dbus生成的文件。

Q: dbus-daemon启动后出错打印如下log:

A:编辑板端$INSTALL_PATH/dbus/etc/dbus-1/system.d/bluetooth.conf文件,删除下列”lp”group

Q:dbus-daemon启动后出错打印如下log:

A:往passwd文件中添加messagebus用户。将messagebus:x:500:500::/home/messagebus:/bin/sh添加到passwd中。如果还不行那就可能是/lib下缺少了libnss_files这个so,从toolchain中找到libnss_files.so.2和libnss_files-2.28.so,放到板端/lib下

Q:启动bluetoothd出错,报如下log:

D-Bus setup failed: Connection ":1.0" is not allowed to own the service "org.bluez" due to security policies in the configuration file

bluetoothd[124]: Unable to get on D-Bus

A:缺少bluetoothd所要的配置文件(bluetooth.conf)

Q:bluealsa启动出错,报如下log:

bluealsa: Couldn't initialize controller thread: Bad file descriptor

A:这是bluealsa初始化线程的时候出错,但通过阅读源码,初始化线程失败后打印的都是这个log,建议到bluealsa中加log去定位出错。

Q:aplay执行出现以下log

A:bluez-alsa生成的20-bluealsa.conf配置文件的位置不对,该文件需要放到板端$BLUEALSA_INSTALL_PATH/alsa/etc/alsa.conf.d/目录下

Q:aplay执行出现以下log

A:libasound_module_pcm_bluealsa.so没有放对路径。

以上为在Takoyaki平台上搭建A2DP的流程(蓝牙模组使用的是rtl8723d),至于应用需要如何写还请参考,bluez-alsa的demo