蓝牙编程

简介:

【转】http://people.csail.mit.edu/albert/bluez-intro/x559.html


An Introduction to Bluetooth Programming

Prev Chapter 4. Bluetooth programming in C with BlueZ Next

4.3. L2CAP sockets



As with RFCOMM, L2CAP communications are structured around socket programming. Example 4-4 and Example 4-5 demonstrate how to establish an L2CAP channel and transmit a short string of data. For simplicity, the client is hard-coded to connect to ``01:23:45:67:89:AB".


Example 4-4. l2cap-server.c



#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <bluetooth/bluetooth.h>

#include <bluetooth/l2cap.h>


int main(int argc, char **argv)

{

    struct sockaddr_l2 loc_addr = { 0 }, rem_addr = { 0 };

    char buf[1024] = { 0 };

    int s, client, bytes_read;

    socklen_t opt = sizeof(rem_addr);


    // allocate socket

    s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);


    // bind socket to port 0x1001 of the first available 

    // bluetooth adapter

    loc_addr.l2_family = AF_BLUETOOTH;

    loc_addr.l2_bdaddr = *BDADDR_ANY;

    loc_addr.l2_psm = htobs(0x1001);


    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.l2_bdaddr, buf );

    fprintf(stderr, "accepted connection from %s\n", buf);


    memset(buf, 0, sizeof(buf));


    // read data from the client

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

    if( bytes_read > 0 ) {

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

    }


    // close connection

    close(client);

    close(s);

}


Example 4-5. l2cap-client.c



#include <stdio.h>

#include <string.h>

#include <sys/socket.h>

#include <bluetooth/bluetooth.h>

#include <bluetooth/l2cap.h>


int main(int argc, char **argv)

{

    struct sockaddr_l2 addr = { 0 };

    int s, status;

    char *message = "hello!";

    char dest[18] = "01:23:45:67:89:AB";


    if(argc < 2)

    {

        fprintf(stderr, "usage: %s <bt_addr>\n", argv[0]);

        exit(2);

    }


    strncpy(dest, argv[1], 18);


    // allocate a socket

    s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);


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

    addr.l2_family = AF_BLUETOOTH;

    addr.l2_psm = htobs(0x1001);

    str2ba( dest, &addr.l2_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);

}



For simple usage scenarios, the only differences are the socket type specified, the protocol family, and the addressing structure. By default, L2CAP connections provide reliable datagram-oriented connections with packets delivered in order, so the socket type is SOCK_SEQPACKET, and the protocol is BTPROTO_L2CAP. The addressing structure struct sockaddr_l2 differs slightly from the RFCOMM addressing structure.



struct sockaddr_l2 {

    sa_family_t     l2_family;

    unsigned short  l2_psm;

    bdaddr_t        l2_bdaddr;

};


The l2_psm field specifies the L2CAP port number to use. Since it is a multibyte unsigned integer, byte ordering is significant. The htobs function, described earlier, is used here to convert numbers to Bluetooth byte order.


4.3.1. Maximum Transmission Unit



Occasionally, an application may need to adjust the maximum transmission unit (MTU) for an L2CAP connection and set it to something other than the default of 672 bytes. In BlueZ, this is done with the getsockopt and setsockopt functions.



struct l2cap_options {

    uint16_t    omtu;

    uint16_t    imtu;

    uint16_t    flush_to;

    uint8_t     mode;

};


int set_l2cap_mtu( int sock, uint16_t mtu ) {

struct l2cap_options opts;

    int optlen = sizeof(opts), err;

    err = getsockopt( s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen );

    if( ! err ) {

        opts.omtu = opts.imtu = mtu;

        err = setsockopt( s, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen );

    }

    return err;

};



The omtu and imtu fields of the struct l2cap_options are used to specify the outgoing MTU and incoming MTU, respectively. The other two fields are currently unused and reserved for future use. To adjust the connection-wide MTU, both clients must adjust their outgoing and incoming MTUs. Bluetooth allows the MTU to range from a minimum of 48 bytes to a maximum of 65,535 bytes.


4.3.2. Unreliable sockets



It is slightly misleading to say that L2CAP sockets are reliable by default. Multiple L2CAP and RFCOMM connections between two devices are actually logical connections multiplexed on a single, lower level connection [1] established between them. The only way to adjust delivery semantics is to adjust them for the lower level connection, which in turn affects all L2CAP and RFCOMM connections between the two devices.



As we delve deeper into the more complex aspects of Bluetooth programming, the interface becomes a little harder to manage. Unfortunately, BlueZ does not provide an easy way to change the packet timeout for a connection. A handle to the underlying connection is first needed to make this change, but the only way to obtain a handle to the underlying connection is to query the microcontroller on the local Bluetooth adapter. Once the connection handle has been determined, a command can be issued to the microcontroller instructing it to make the appropriate adjustments. Example 4-6 shows how to do this.


Example 4-6. set-flush-to.c



#include <unistd.h>

#include <errno.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/ioctl.h>

#include <bluetooth/bluetooth.h>

#include <bluetooth/hci.h>

#include <bluetooth/hci_lib.h>


int set_flush_timeout(bdaddr_t *ba, int timeout)

{

    int err = 0, dd;

    struct hci_conn_info_req *cr = 0;

    struct hci_request rq = { 0 };


    struct {

        uint16_t handle;

        uint16_t flush_timeout;

    } cmd_param;


    struct {

        uint8_t  status;

        uint16_t handle;

    } cmd_response;


    // find the connection handle to the specified bluetooth device

    cr = (struct hci_conn_info_req*) malloc(

            sizeof(struct hci_conn_info_req) + 

            sizeof(struct hci_conn_info));

    bacpy( &cr->bdaddr, ba );

    cr->type = ACL_LINK;

    dd = hci_open_dev( hci_get_route( &cr->bdaddr ) );

    if( dd < 0 ) {

        err = dd;

        goto cleanup;

    }

    err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr );

    if( err ) goto cleanup;


    // build a command packet to send to the bluetooth microcontroller

    cmd_param.handle = cr->conn_info->handle;

    cmd_param.flush_timeout = htobs(timeout);

    rq.ogf = OGF_HOST_CTL;

    rq.ocf = 0x28;

    rq.cparam = &cmd_param;

    rq.clen = sizeof(cmd_param);

    rq.rparam = &cmd_response;

    rq.rlen = sizeof(cmd_response);

    rq.event = EVT_CMD_COMPLETE;


    // send the command and wait for the response

    err = hci_send_req( dd, &rq, 0 );

    if( err ) goto cleanup;


    if( cmd_response.status ) {

        err = -1;

        errno = bt_error(cmd_response.status);

    }


cleanup:

    free(cr);

    if( dd >= 0) close(dd);

    return err;

}



On success, the packet timeout for the low level connection to the specified device is set to timeout * 0.625 milliseconds. A timeout of 0 is used to indicate infinity, and is how to revert back to a reliable connection. The bulk of this function is comprised of code to construct the command packets and response packets used in communicating with the Bluetooth controller. The Bluetooth Specification defines the structure of these packets and the magic number 0x28. In most cases, BlueZ provides convenience functions to construct the packets, send them, and wait for the response. Setting the packet timeout, however, seems to be so rarely used that no convenience function for it currently exists.


Notes


[1]


Bluetooth terminology refers to this as the ACL connection


Prev Home Next

RFCOMM sockets Up Service Discovery Protocol













本文转自fatshi51CTO博客,原文链接:http://blog.51cto.com/duallay/1760318 ,如需转载请自行联系原作者



相关文章
H8
|
物联网 数据安全/隐私保护 智能硬件
女朋友问: 你知道蓝牙耳机的原理吗?
蓝牙是一种无线通讯技术标准,用来让固定与移动设备,在短距离间交换资料,以形成个人局域网(PAN)。其使用短波特高频(UHF)无线电波,经由2.4至2.485GHz的ISM频段来进行通信。1994年由电信商(Ericsson)发展出这个技术。它最初的设计,是希望创建一个RS-232数据线的无线通信替代版本。
H8
454 0
|
2月前
|
物联网 C#
【C#】简单的蓝牙通讯功能实现
【C#】简单的蓝牙通讯功能实现
55 0
|
7月前
|
小程序 API
uniapp 蓝牙小程序
uniapp 蓝牙小程序
326 0
|
编解码 缓存 物联网
一个蓝牙实战项目的掏肺总结
一个蓝牙实战项目的掏肺总结
|
IDE 物联网 开发工具
CH573第一篇:实现自拍杆蓝牙遥控器1
CH573第一篇:实现自拍杆蓝牙遥控器1
|
传感器 存储 缓存
基于51单片机的蓝牙电子秤设计
基于51单片机的蓝牙电子秤设计
蓝牙技术简介(英语演讲)
蓝牙技术简介(英语演讲)
257 0
|
编解码 算法 数据格式
【经典蓝牙】蓝牙 A2DP协议分析
A2DP(Advanced Audio Distribution Profile)是蓝牙高音质音频传输协议, 用于传输单声道, 双声道音乐(一般在 A2DP 中用于 stereo 双声道) , 典型应用为蓝牙耳机。         A2DP旨在通过蓝牙连接传输高质量的立体声音频流。它使用的基本压缩算法是SBC(Sub-Band Coding)来减小音频数据的大小,同时保持高音质,SBC压缩虽然效率较低,但是是必须支持的基本备用方案。A2DP还支持其他高级编解码器,例如AAC、aptX和LDAC,这些编解码器比SBC提供更好的音质,但这些编解码器的支持取决于设备本身的支持情况。
2471 0
【经典蓝牙】蓝牙 A2DP协议分析
|
编解码
【经典蓝牙】蓝牙AVRCP协议分析
蓝牙AVRCP协议是蓝牙设备之间音视频的控制协议。定义了音频/视频的控制、浏览、查询、通知等一系列的命令集。常用来蓝牙耳机对手机的音乐进行控制,以及获取手机的音乐信息等场景。AVRCP协议有两个角色,分别是controller(CT)和 target(TG)。CT: 发送控制命令到对端,控制对端媒体播放器的设备,例如蓝牙耳机,蓝牙遥控器等。TG:接收对端的控制命令,并执行操作,进行回复的设备,例如手机,电脑等。
3003 0
【经典蓝牙】蓝牙AVRCP协议分析
|
网络协议 安全 物联网
蓝牙基础知识(一)
最近刚好一直在研究蓝牙相关的内容,所以想来和大家一起分享。首先我们依然以基础概念开始,因为一头扎进代码,只会让你不知所措!