• Examples


    最近需要在某个开发板上面通过蓝牙和手机蓝牙连接,并通过RFCOMM通信。还没有做过蓝牙RFCOMM相关工作,因此先在linux PC上面调试一下流程,并在此记录调试过程。

    一、说明

    RFCOMM协议基于L2CAP协议的串行(9针RS-232)仿真。

    本文中实现了RFCOMM server和client通信。

    二、设备

    linux主机(Ubuntu-14.04)、linux虚拟机(Ubuntu-14.04)、Android手机一台、不知名蓝牙dongle_1(controller)、CSR 蓝牙dongle_2(controller)。

    Linux主机+dongle_1作为server端; linux虚拟机+dongle_2作为client端;Android手机作为client端。

    三、环境搭建

    Server端:

     1. 安装bluez协议栈

     2. 查看bluetoothd进程是否启动:ps -ef|grep blue

    root      1891     1  0  5月19 ?      00:00:00 /usr/sbin/bluetoothd

     

    如果没有启动,执行:/usr/sbin/bluetoothd -C &

    注:开始测试,如果把bluetoothd进程kill了,也能进行连接成功。后来发现如果不启动bluetoothd,就连接不成功。理论上说server端程序使用socket通信,应该不需要bluetoothd。

    至今没有搞清楚原因。

     

     

     3. 查看bluetooth service是否存在:service --status-all | grep blue

    如果不存在,执行:service bluetooth start

     

     

     

    4. 将dongle_1插入linux主机端;并配置。

    1> 执行:hciconfig,观察dongle状态是否为UP RUNNING,如果不为UP RUNNING,则执行:hciconfig hci0 UP

    注:hci0是根据hciconfig打印的BD Address来确定的。如果有两个dongle,有可能是hci1。

     

    2> 使蓝牙设备可见(可被其他蓝牙设备扫描到,如手机)

    执行命令:hciconfig piscan

    然后执行hciconfig,观察状态是否为UP RUNNING PSCAN ISCAN

     

    3> 添加SPP服务

    sdptool add SP

    也可以执行添加所有服务:

    sdptool add --channel=1 DID SP DUN LAN FAX OPUSH FTP HS HF SAP NAP GN PANU HID CIP CTP A2SRC A2SNK SYNCML NOKID PCSUITE SR1

     

    4> 关闭pin码验证

    hciconfig hci0 noauth;

     

    5. 编写并编译测试程序

    gcc -o rfcomm_server rfcomm_server.c

     

    Client端(linux虚拟机):

    1. 安装bluez协议栈

    2. 查看bluetoothd进程是否启动:ps -ef|grep blue,如果没有启动,则启动该进程。

    3. 查看bluetooth service是否存在:service --status-all | grep blue  

    如果不存在,执行:service bluetooth start

    4. 添加SPP服务,关闭pin码验证。

    5. 创建RFCOMM设备节点:mknod /dev/rfcomm0 c 216 0

    chmod 666 /dev/rfcomm0

    6. 绑定server端蓝牙mac地址

    rfcomm bind 0 00:19:86:00:2B:BD 1 //0表示rfcomm0, 00:19:86:00:2B:BD为server端的蓝牙地址,1为通道

    7. 编写并编译rfcomm_client

    Client端(Android手机)

    1. 下载蓝牙串口SPP应用程序

    四、测试

    1. Server + client(linux虚拟机)

    1> 在server端执行rfcomm_server

    2> 在client端执行rfcomm_client

    可以在两端观察到写入和读出的数据

     

    2. Server + Android手机

    1> 在server端执行rfcomm_server

    2> Client端,打开蓝牙SPP应用,扫描到server端的蓝牙设备,连接。即可和server端进行通信

    rfcomm_server.c

    #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/rfcomm.h> int str2ba(const char *str, bdaddr_t *ba) { uint8_t b[6]; const char *ptr = str; int i; for (i = 0; i < 6; i++) { b[i] = (uint8_t) strtol(ptr, NULL, 16); if (i != 5 && !(ptr = strchr(ptr, ':'))) ptr = ":00:00:00:00:00"; ptr++; } } void baswap(bdaddr_t *dst, const bdaddr_t *src) { unsigned char *d = (unsigned char *) dst; const unsigned char *s = (const unsigned char *) src; int i; for (i = 0; i < 6; i++) d[i] = s[5-i]; } int ba2str(const bdaddr_t *ba, char *str) { uint8_t b[6]; baswap((bdaddr_t *) b, ba); return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", b[0], b[1], b[2], b[3], b[4], b[5]); } int main(int argc, char **argv) { struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 }; char buf[1024] = { 0 }; int s, client, bytes_read; socklen_t opt = sizeof(rem_addr); char write_buf[1204]="hello world"; char flag = 1; char count=0; // allocate socket s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); // bind socket to port 1 of the first available // local bluetooth adapter 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)); // put socket into listening mode listen(s, 1); // accept one connection client = accept(s, (struct sockaddr *)&rem_addr, &opt); ba2str( &rem_addr.rc_bdaddr, buf ); fprintf(stderr, "accepted connection from %s ", buf); while( flag ) { memset(buf, 0, sizeof(buf)); #if 0 // read data from the client bytes_read = read(client, buf, sizeof(buf)); if( bytes_read > 0 ) { printf("[rcv]:%s ", buf); if(!strcmp(buf,"exit")) { flag = 0; } // write( client,write_buf,16 ); } usleep(5000); #endif #if 1 //write data to client strcpy( buf, "abcdefgh" ); bytes_read = 9; write( client,buf,bytes_read ); usleep(50000); #endif } // close connection close(client); close(s); return 0; }
    rfcomm_client.c
    
    #include <stdio.h>
    #include <sys/types.h>
     #include <sys/stat.h>
     #include <fcntl.h>
     #include <unistd.h>
     #include <string.h>
    int main( int argc, char **argv ) 
    {
        int fd ;
        unsigned char buff[64] = "hello";
        char read_buff[128] = {0};
        int read_n;
        int write_n;
        fd = open( "/dev/rfcomm0",O_RDWR);
        
        if( fd<0 )
            printf( "open rfcomm0 error
    " );
            
        while(1)
        {
    #if 0
        //    printf( "write hello to rfcomm
    " );    
            write_n = write( fd, buff, 64 );
            if( write_n<0)
                printf( "write error
    " );
            else if(write_n==0)
                printf( "write nothing
    " );
            else
                printf( "write %d byte
    ",write_n );
        //    sleep(1);
    #endif
    #if 1
            memset( read_buff, 0, sizeof(read_buff) );
            read_n = read( fd, read_buff, sizeof(read_buff) );
            if( read_n > 0 )
                {
                    printf( "[receive]:%s
    ",read_buff );
                }
                
                usleep(50000);
                #endif
        }
        close(fd);
    }

    在网上查了一下资料,有rfcomm_client.c是创建socket,并bind、connect,但是我调试的时候执行该程序,会报错。原因没有找到。下面将代码贴出来,以后可以找一下原因。


    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/rfcomm.h>
    
    
    int str2ba(const char *str, bdaddr_t *ba)
    {
        uint8_t b[6];
        const char *ptr = str;
        int i;
    
        for (i = 0; i < 6; i++) 
        {
              b[i] = (uint8_t) strtol(ptr, NULL, 16);
              if (i != 5 && !(ptr = strchr(ptr, ':')))
               ptr = ":00:00:00:00:00";
              ptr++;
          }
    }
    
    
    
    int main(int argc, char **argv)
    {
        struct sockaddr_rc addr = { 0 };
        int s, status;
        char dest[18] = "00:19:86:00:2B:BD";
    
        // allocate a socket
        s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    
        // set the connection parameters (who to connect to)
        addr.rc_family = AF_BLUETOOTH;
        addr.rc_channel = (uint8_t) 1;
        str2ba( dest, &addr.rc_bdaddr );
        printf( "connect device
    " );
        // connect to server
        status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
    
        // send a message
        if( status == 0 ) {
            status = write(s, "hello!", 6);
        }
    
        if( status < 0 ) perror("uh oh");
    
        close(s);
        return 0;
    }



    网上资料,有文章介绍需要设置rfcomm.conf, 个人以为如果需要client上电自动连接,可以用此方法进行设置(还需要进行其他配置),和用命令设置效果一样。

     

    其中:不知名蓝牙dongle ,hciconfig -a信息如下:

    root@localhost:bin# hciconfig -a

    hci0:   Type: BR/EDR  Bus: USB

            BD Address: 00:19:86:00:2B:BD  ACL MTU: 1021:8  SCO MTU: 64:1

            UP RUNNING PSCAN

            RX bytes:66976 acl:1214 sco:0 events:1729 errors:0

            TX bytes:67686 acl:1976 sco:0 commands:203 errors:0

            Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87

            Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3

            Link policy: RSWITCH SNIFF

            Link mode: SLAVE ACCEPT

            Name: 'localhost-0'

            Class: 0x600100

            Service Classes: Audio, Telephony

            Device Class: Computer, Uncategorized

            HCI Version: 4.0 (0x6)  Revision: 0x1000

            LMP Version: 4.0 (0x6)  Subversion: 0x220e

  • 相关阅读:
    软件测试之功能测试简单介绍
    如果编程语言是女孩,你猜C语言是萝莉还是御姐?
    C++ C、C++、C#、VC、VC.net以及VC++有什么区别和联系?
    程序员如何避免陷入内卷?从以下三个方面着手
    懒惰使人进步,UNIX 和 Linux 新系统的诞生只是意外
    编程学习必备:C++ 学习的 11 本经典书籍推荐
    初入职场,菜鸟程序员如何才能成为业界大牛,给你提供思路方法。
    TIOBE 12月编程语言: Python、Java战况激烈, C语言:我自岿然不动
    C++基础知识篇:C++ 数字
    二本毕业程序员鄙视清北毕业生,嘲笑水货一抓一大把,你怎么看?
  • 原文地址:https://www.cnblogs.com/hjj801006/p/12930290.html
Copyright © 2020-2023  润新知