技术天地

标准socket编程应用于英创主板的蓝牙接口作者:陈昌龙    发布时间:2017-1-6    被阅览数:

  蓝牙(bluetooth)技术是一种低功耗短距离的无线通信技术,被广泛应用于10米以内的嵌入式设备通信当中。其最高传输速度根据蓝牙协议的版本不同,有1Mbps(BR、LE)、2-3Mbps(EDR)、24Mbps(HS)之分。在工业现场,蓝牙技术可以代替串行线缆,实现无线通信。在智能手机普及的今天,通过蓝牙与手机建立连接,手机作为上位机发送指令给下位机,可以实现低成本的UI控制方案。


  BlueZ是当前比较成熟的蓝牙协议栈,作为Linux系统的官方协议栈,集成在Linux内核之中。英创公司在ESM928x的Linux系统中,又移植了BlueZ用户空间协议栈和相关工具,使得ESM928x Linux平台能够支持蓝牙技术,通过socket编程实现蓝牙无线连接,代替串行线缆进行通信。


ESM928xW上实现蓝牙串口socket应用编程.gif

图1 ESM928xW系列主板+底板


  用户使用蓝牙串口功能主要分为两个步骤:蓝牙功能配置和socket应用程序编写。


1、蓝牙功能配置


  1、加载ap2610蓝牙模块上电驱动

  insmod /lib/modules/4.1.14/ap6210_bt_bcm20710.ko


  2、加载蓝牙固件,设定波特率、蓝牙地址、使能hci等

  brcm_patchram_plus --patchram /lib/firmware/ap6210/bcm20702a.hcd --baudrate 3000000 --enable_hci --bd_addr aa:00:55:44:33:22 --no2bytes --tosleep 5000 /dev/ttyS5 1> /dev/null&


  3、启动dbus后台服务

  dbus-daemon --system --nofork --nopidfile &

  

  4、以兼容模式启动bluetooth后台服务

  /libexec/bluetooth/bluetoothd  -C  &


  5、启动hci0,并设置name和可见属性

  hciconfig hci0 up

  hciconfig hci0 name esm9287

  hciconfig hci0 piscan

  hciconfig hci0 reset


  以上5个步骤已经写成一个shell脚本set_bluetooth.sh,用户也可以直接运行该脚本完成以上设置。至此,完成了对蓝牙的设置,可以通过hciconfig hci0 -a来查看蓝牙信息,如图2。这时,其他蓝牙设备就可以搜索到esm9287,图3所示是android手机搜索到esm9287蓝牙设备,点击即可完成配对。


ESM928xW上实现蓝牙串口socket应用编程.gif

图2 使用hciconfig查看蓝牙信息


标准socket编程应用于英创主板的蓝牙接口.gif

图3 搜索esm9287并配对


2、Socket应用编程


  蓝牙协议栈中的RFCOMM协议实现了对串口RS232的仿真,最多能提供两个蓝牙设备之间60路的连接。应用程序中,可以使用socket进行服务端和客户端的编程,其过程与TCP/IP的socket通信没有太大区别。


  a)环境配置

  开发bluez协议栈的蓝牙应用需要用到libbluetooth.so和相关头文件,需要添加到eclipse对应的蓝牙项目中。libbluetooth.so是编译bluez协议栈生产的动态链接库,提供了头文件bluetooth.h、hci_lib.h、sdp_lib.h中的函数实体,实现蓝牙地址与常用数据类型的转换、hci设备和sdp服务的一系列操作函数。


  1、在项目中新建文件夹include/bluetooth,其中放入蓝牙协议相关头文件;新建文件夹lib,其中放动态链接库libbluetooth.so。


ESM928xW上实现蓝牙串口socket应用编程.gif

图4 新建include和lib文件夹


  2、进入项目Properties设置,添加项目下的include文件夹为GCC C++ Compiler和GCC C Complier编译器的头文件路径(下图是GCC C++ Compiler的设置,GCC C Compiler设置步骤相同)。


ESM928xW上实现蓝牙串口socket应用编程.gif

图5 添加头文件搜索路径


  3、为Sourcery G++ Lite C++ Linker链接器添加libbluetooth.so库文件及搜索路径,如下图。


ESM928xW上实现蓝牙串口socket应用编程.gif

图6 添加编译库及搜索路径


  b)服务端程序

  1、申请蓝牙RFCOMM socket

  s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);


  2、绑定本地适配器,BDADDR_ANY默认为第一个可用蓝牙适配器

  loc_addr.rc_family = AF_BLUETOOTH;

    loc_addr.rc_bdaddr = *BDADDR_ANY;

    loc_addr.rc_channel = (uint8_t) 1;

    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));


  3、设置socket监听模式,这里只允许建立一个连接

  listen(s, 1);


  4、等待连接

  client = accept(s, (struct sockaddr *)&rem_addr, &opt);


  5、select模式读取socket数据流

  while(1)

    {

        FD_ZERO(&working_set);

        max_sd = client;

        FD_SET(client, &working_set);

        timeout.tv_sec  = 3 * 60;

        timeout.tv_usec = 0;

        // Call select() and wait 5 minutes for it to complete.

        printf("Waiting on select() %ld sec...\n", timeout.tv_sec);

        int rc_select = select(max_sd + 1, &working_set, NULL, NULL, &timeout);

        // Check to see if the select call failed.

        if (rc_select < 0)

        {

            perror("  select() failed");

            break;

        }

        else if (rc_select > 0)

        {

            if(FD_ISSET(max_sd,&working_set))

            {

                // read data from the client

                bytes_read = read(client, buf, sizeof(buf));

                if( bytes_read > 0 ) {

                    printf("received: [%s]\n", buf);

                }

                else

                {

                 break;

                }

                write(client,ack,sizeof(ack));

            }

        }

        // Else if rc_select == 0 then the 5 minute time out expired.

        else

        {

            printf("  select() timed out.\n");

            break;

        }

    }


  6、关闭套接字

  close(client);

    close(s);


  c)客户端

  1、申请蓝牙RFCOMM socket

  s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);


  2、设置蓝牙连接服务器的地址

  struct sockaddr_rc addr = { 0 };

    // set the connection parameters (who to connect to)

    addr.rc_family = AF_BLUETOOTH;

    addr.rc_channel = (uint8_t) 1;

    str2ba( dest, &addr.rc_bdaddr );


  3、连接蓝牙服务器

  // connect to server

    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));


  4、读写socket数据流

  for(i = 0; i < 3; i++)

    {

        // send a message

        write(s, message[i], strlen(message[i])+1);

        printf("write \"%s\" to %s\n", message[i],dest);

        bytes_read = read(s, buf, sizeof(buf));

        if( bytes_read > 0 ) {

            printf("received: [%s]\n", buf);

        }

    }

  其中,message[i]为发送内容的地址。


  5、关闭socket

  close(s);


  在一张板子上运行蓝牙rfcomm服务程序,在另一张板子上运行蓝牙rfcomm客户端程序,如图6、图7所示:


ESM928xW上实现蓝牙串口socket应用编程.gif

图7 服务端程序


ESM928xW上实现蓝牙串口socket应用编程.gif

图8 客户端程序


  通过socket编程,蓝牙应用程序可以像tcp/ip的网络编程一样,建立连接,实现无线通信。如果有用户对蓝牙的串口socket编程感兴趣,可以联系我们。我们将提供驱动文件、蓝牙库文件及相应的示例程序。

Go Top