如何在Linux上连接到Android蓝牙套接字

3

我正在尝试在树莓派3B(Debian Linux)和Android应用程序之间建立蓝牙连接。我的问题是,Android框架(据我所知)要求使用UUID,例如createRfcommSocketToServiceRecord(UUID)。代码摘录:

// CREATE SPP SOCKET
mSock = device.createRfcommSocketToServiceRecord( uuid );
if( mSock == null ) {
    return( -1 );
}
// TRY TO CONNECT
mSock.connect();

上述代码在安卓之间运行良好。

然而,在Linux上只需要一个“rc通道号”(整数)。以下是来自MIT的一些示例代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

int main(int argc, char **argv)
{
    struct sockaddr_rc addr = { 0 };
    int s, status;
    char dest[18] = "XX:XX:XX:XX:XX:XX"; // android address here

    // 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 );

    // 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;
}

我无法弥合这两个世界之间的差距。
帮忙!


我试图连接从1到31的每个频道号,已经大致找出了答案。在3、4、5、6频道上成功连接。我的Android应用程序显示6频道已连接。因此(显然),每个活动Android服务器的UUID都映射到一个频道号。问题当然是如何确定适当的频道号。我相信答案是使用“服务发现协议”(SDP)。我还没有完全弄清楚如何做到这一点,但至少有希望了。我会尽快发布完整的答案,希望我能找到它。 - DontPanic
1个回答

2

经过长时间的努力,我成功地让SDP工作了。以下是代码。它是根据https://people.csail.mit.edu/albert/bluez-intro/x604.html上的示例设计的。

在我看来,这似乎过于复杂了。这是“计算机科学家疯狂”的一个例子!对于像这样常见而简单的事情,他们应该包含一个便捷的封装。

//  getchan - get channel for specified service

// CONVENIENCE DEFINITIONS TO (IMHO) MAKE CODE MORE READABLE
#define BYTE    uint8_t
#define UUID    uuid_t
#define LIST    sdp_list_t
#define SESSION sdp_session_t
#define RECORD  sdp_record_t
#define DATA    sdp_data_t

#include "stdio.h"
#include "string.h"
#include "ctype.h"
#include "unistd.h"
#include "stdlib.h"
#include "bluetooth/bluetooth.h"
#include "bluetooth/sdp.h"
#include "bluetooth/sdp_lib.h"

#define DEV_ADDR "E4:12:1D:96:10:EF"    // MAC address of service device

main(
  int argc,
  char **argv)
{
    // Server UUID: "d8308c4e-9469-4051-8adc-7a2663e415e2"
    static BYTE uuid[16] = {    // UUID as byte array
      0xd8, 0x30, 0x8c, 0x4e, 0x94, 0x69, 0x40, 0x51,
      0x8a, 0xdc, 0x7a, 0x26, 0x63, 0xe4, 0x15, 0xe2
    };
    int chan;

    chan = GetServiceChannel( uuid );
    if( chan > 0 ) {
      printf( "specified service is on channel %d\n", chan );
    }
    else {
      fprintf( stderr, "  can't find channel\n" );
    }
    exit( 0 );
}

int
GetServiceChannel(
  BYTE *uuid)   // uuid of service as 16 bytes
{
    SESSION *s;
    UUID svc_uuid;
    LIST *response_list,*search_list,*attrid_list,*r;
    RECORD *rec;
    int range;
    int n;
    BYTE addr[6];   // define my own addr type
    int chan=0;

    // CONNECT TO SDP SERVER
    // (Note: device must be ON but server need not be running)
    str2ba( DEV_ADDR, (bdaddr_t *)&addr );
    s = sdp_connect( BDADDR_ANY, (bdaddr_t *)&addr, SDP_RETRY_IF_BUSY );
    if( !s ) {
      fprintf( stderr, "can't connect to sdp server\n" );
      return( 0 );
    }

    // CREATE QUERY LISTS
    sdp_uuid128_create( &svc_uuid, uuid );
    search_list = sdp_list_append( NULL, &svc_uuid );

    range = 0x0000ffff;     // start at 0000, end at ffff
    attrid_list = sdp_list_append( NULL, &range );

    // SEARCH FOR RECORDS
    // (Note: Server must be running)
    n = sdp_service_search_attr_req(
      s, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list );
    if( n ) {
      fprintf( stderr, "search failed.\n" );
      return( 0 );;
    }

    // CHECK IF ANY RESPONSES
    n = sdp_list_len( response_list );
    if( n <= 0 ) {
      fprintf( stderr, "no responses.\n" );
      return( 0 );;
    }

    // PROCESS RESPONSES
    r = response_list;
    while( r ) {            // loop thru all responses
      sdp_record_t *rec;
      LIST *proto_list,*p;
      rec = (RECORD *)r->data;
      n = sdp_get_access_protos( rec, &proto_list );
      if( n ) {
        fprintf( stderr, "can't get access protocols.\n" );
        return( 0 );
      }
      p = proto_list;
      while( p ) {          // loop thru all protocols
        LIST *pds;
        int proto=0;
        pds = (LIST *)p->data;
        while( pds ) {      // loop thru all pds
          DATA *d;
          int dtd;
          d = pds->data;        // get data ptr of pds
          while( d ) {      // loop over all data
            dtd = d->dtd;       // get dtd of data
            switch( dtd ) {     // which dtd?
              case SDP_UUID16:
              case SDP_UUID32:
              case SDP_UUID128:
            proto = sdp_uuid_to_proto( &d->val.uuid ); // get proto #
            break;
              case SDP_UINT8:
            if( proto == RFCOMM_UUID ) { // proto is rfcomm?
              chan = d->val.uint8;   // save chan num
            }
            break;
            }
        d = d->next;        // advance to next data unit
          }

          pds = pds->next;      // advance to next pds
        }
        sdp_list_free( (LIST *)p->data, 0 );

        p = p->next;        // advance to next protocol
      }
      sdp_list_free( proto_list, 0 );

      r = r->next;          // advance to next response
    }

    return( chan );
    // Return chan number [1-30] or 0 if not found
}

要做的事情:
To make:
gcc getchan.c -o getchan -l bluetooth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接