- MTU

아래와 같이 set/getsockeopt() 함수를 이용하면 MTU(Maximum Transmission Unit) 값을 변경할 수 있으며

해당 Local socket에서만 적용이 된다. Server or Client 각각 이를 설정해야 값을 지정할 수 있다.

기본 MTU 값은 672 Bytes이며 최소 48  Bytes에서 최대 65,535 Bytes까지 적용하 수 있다.

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


* 용어 정리

PSM : Protocol Service Multiplexer

L2CAP socket에서 사용가능한 Port는 4097~32,767(0x1001-0x7FFF)까지 홀수 번호이다.


ex) L2CAP Server&Client

1) Server

#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 };
//  struct l2cap_options opts;

    char buf[1024] = { 0 };
    int s, client, bytes_read, optlen;
    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));

//  optlen = sizeof(opts);
//  getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
//  printf("before omtu = %d, imtu = %d\n", opts.omtu, opts.imtu);

    // put socket into listening mode
    listen(s, 1);

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

//  optlen = sizeof(opts);
//  getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
//  printf("after omtu = %d, imtu = %d\n", opts.omtu, opts.imtu);

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


2) Client

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>

int set_l2cap_mtu( int sock, uint16_t mtu );

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";

    struct l2cap_options opts;
    int optlen;

    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_l2cap_mtu(s, 65535);

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

    optlen = sizeof(opts);
    getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
    printf("after omtu = %d, imtu = %d\n", opts.omtu, opts.imtu);

    // send a message
    if( status == 0 ) {
        status = write(s, "hello!", 6);
    }

    if( status < 0 ) perror("uh oh");

    close(s);
}

int set_l2cap_mtu( int sock, uint16_t mtu ) {
    struct l2cap_options opts;
    int optlen = sizeof(opts), err;

    err = getsockopt( sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen );
    if( ! err ) {
        printf(" current omtu = %d, imtu = %d\n", opts.omtu, opts.imtu);
        opts.omtu = opts.imtu = mtu;
        err = setsockopt( sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen );
    }

    return err;
}


춮처 : Bluetooth Essentials


Posted by 깍수
,

* 개발 기본 패키지

gcc, manpages-dev


* BlueZ 개발 환경

libblutooth-dev libbluetooth3 libbluetooth3-dbg, bluez-dbg

bluez-alsa bluez-gstreamer

bluez bluetooth

bluez-hcidump (디버깅)


* Old Package

bluez-utils, bluez-audio : 해당 패키지는 4.x 버전 이전에 설치한 Package이지만 이후 부터 bluez Package에 포함되었다.

Posted by 깍수
,

- RFCOMM Channel

RFCOMM의 Channel은 1~30까지 사용할 수 있으나 이상하게 1~13번 채널을 사용하면 Server에 연결 되지 않았다.

테스트 환경은 Server의 경우 PC Ubuntu을 사용하였으며 Client는 Android ICS 4.0.4 번젼의 BlueZ v4.93을 사용

하였다. 현상을 보면 Client에서 Socket 생성까지는 무리 없이 동작하며 connect() 함수를 호출하였을 경우 에러를

리턴 하였다.


- bind 함수

bind() 함수 호출시 커널 2.6.7 버전 이상에서는 Channel값을 0으로 설정하면 자동으로 값을 설정한다고 하는데… 정확히 어떤말을 하는지 모르겠음.

=> kernel source를 보면 rfcomm_sock_getname() 함수를 보면 struct sockaddr을 반환해 주는 함수가 있음.(미검토)


ex) RFCOMM Server&Client

1) Server

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

#define USE_DYNAMIC_BIND    0   

int dynamic_bind_rc(int sock, struct sockaddr_rc *sockaddr, uint8_t *port);

int main(int argc, char **argv)
{
    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char buf[1024] = { 0 };
    int s, client, bytes_read;
    uint8_t ch;
    socklen_t opt = sizeof(rem_addr);

    if (argc != 2) {
        printf("Usage:\n");
        printf("\nrfcomm-server Channel\n");
        exit(1);
    }

    ch = (uint8_t)strtol(argv[1], NULL, 10);

#if(USE_DYNAMIC_BIND == 1)
    uint8_t port;
#endif

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

#if(USE_DYNAMIC_BIND == 1)    
    dynamic_bind_rc(s, &loc_addr, &port);
    printf("Available Ch : %d\n", port);

    // put socket into listening mode
    listen(s, 1);
#else
    loc_addr.rc_channel = (uint8_t) ch;
    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));

    // put socket into listening mode
    listen(s, 1);
#endif

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

    ba2str( &rem_addr.rc_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);
    return 0;
}


int dynamic_bind_rc(int sock, struct sockaddr_rc *sockaddr, uint8_t *port)
{
    int err;
    for( *port = 1; *port <= 31; *port++ ) {
        sockaddr->rc_channel = *port;
        err = bind(sock, (struct sockaddr *)sockaddr, sizeof(sockaddr));
        if( ! err ) break;
    }
    if( *port == 31 ) {
        err = -1;
    }
    return err;
}


2) Client

#include <stdio.h>
#include <stdlib.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] = "00:15:83:6A:02:F2";
    uint8_t ch;

    if (argc != 2) {
        printf("Usage:\n");
        printf("\nrfcomm-client Channel\n");
        exit(1);
    }

    ch = (uint8_t)strtol(argv[1], NULL, 10);

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

    // connect to server
    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
    printf("status %d \n", status);

    // send a message
    if( status == 0 ) {
        status = write(s, "hello!", 6);
    }

    if( status < 0 ) perror("uh oh");

    close(s);
    return 0;
}


춮처 : Bluetooth Essentials




Posted by 깍수
,

int hci_get_route(bdaddr_t *bdaddr)

: bdaddr의 값으로 NULL값을 주면 사용가능한 Local의 첫 번째 Adapter의 Index값을 반환해 준다.

: local에 2개 이상의 Adapter가 존재하며 해당 bdaddr의 값을 알고 있을 경우 다음과 같은 함수를 사용하여 ID값을 반환 받을 수 있다.


ex) int dev_id = hci_devid("01:23:45:67:89:AB")


typedef struct {
    uint8_t b[ 6 ];
} --attribute--( (packed) ) bdaddr_t;


int hci_devid ( const char *addr ) ;


int hci_open_dev(int dev_id)

: socket을 생성하고 성공시 device descriptor를 리턴하게 된다. Error일 경우 -1을 리턴하게 된다.


int hci_inquiry(int dev_id, int len, int max_rsp, const uint8_t *lap, inquiry_info **ii, long flags)

 #2 len : inquiry 동작 시간을 설정하는 것이며 약 1.28s * len 이 된다.

 #6 flags : IREQ_CACHE_FLUSH(1)의 값이 들어가면 기존의 cache에 있는 값을 flush한 다음 다시 inquiry 하게

    되며 0의 값을 가지게 되면 Remote Device가 범위내에 없더라도 cache에 그 정보가 있다면 출력하게 된다.


typedef struct {
    bdaddr_t bdaddr;
    uint8_t pscan_rep_mode;
    uint8_t pscan_period_mode;
    uint8_t pscan_mode;
    uint8_t dev_class[3];
    uint16_t clock_offset;
} --attribute-- ( (packed) ) inquiry_info;



int hci_read_remote(int dd, const bdaddr_t *bdaddr, int len, char *name, int timout)

마지막 Paramter인 timeout의 단위는 ms 이다.


* Compile

arm-none-linux-gnueabi-gcc -o simplescan simplescan.c --static -lbluetooth


* simplescan.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

int main(int argc, char **argv)
{
    inquiry_info *ii = NULL;
    int max_rsp, num_rsp;
    int dev_id, sock, len, flags;
    int i;
    char addr[19] = { 0 };
    char name[248] = { 0 };

    dev_id = hci_get_route(NULL);
    if (dev_id < 0) {
        fprintf(stderr, "error code %d: %s\n", errno, strerror(errno));
        exit(1);
    }

    sock = hci_open_dev( dev_id );
    if (dev_id < 0 || sock < 0) {
        perror("opening socket");
        exit(1);
    }

    len  = 8;
    max_rsp = 255;
    flags = IREQ_CACHE_FLUSH;
    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));

    num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
    if( num_rsp < 0 ) perror("hci_inquiry");

    for (i = 0; i < num_rsp; i++) {
        ba2str(&(ii+i)->bdaddr, addr);
        memset(name, 0, sizeof(name));
        if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name), name, 0) < 0)
            strcpy(name, "[unknown]");

        printf("%s  %s\n", addr, name);
    }

    free( ii );
    close( sock );
    return 0;
}


춮처 : Bluetooth Essentials

Posted by 깍수
,

============ BlueZ ============

Bluetooth (package, service&JNI)

ㄴlibbluetooth_jni (slib) : Bluetooth JNI


* Executable

bluetoothd(bluetoothd-main) (exec) : Android BlueZ daemon, user mode일 경우 bluetoothd-main아니면 bluetoothd로 빌드 됨

bluetoothd (exec) : daemon의 wrapper로 user mode로 빌드시 생성

bluetoothd-snoop (exec)

hciattach, (exec) => vendro에 따른 코드가 따로 있음.


* Shared Lib

bluetooth.default (slib)

audio.a2dp.default (slib)

audio.sco.default (slib)

libsbc (slib)


* Debug

halttest, dbg (exec) 

mcaptest, dbg (exec)

btmon, dbg (exec)

btproxy, dbg (exec)

l2test, dbg (exec)

btmgmt, dbg (exec)

hcitool, dbg (exec)

l2ping, dbg (exec)

avtest, dbg (exec)

avinfo, dbg (exec)


* Etc

init.bluetooth.rc


============ Bluedroid ============

libbt-vendor (slib) : vendor에 따른 HW 설정관련된 코드들이 있다.


Bluetooth (package, service&JNI)

ㄴlibbluetooth_jni (slib) : Bluetooth JNI


* Bluedroid

audio.a2dp.default (slib)

libbt-hci (slib)

bluetooth.default (slib)

libbt-utils (slib)

libbt-brcm_bta (static_lib)

libbt-brcm_gki (static_lib)

libbt-brcm_stack (static_lib)


* Debug

bdt, eng (exec)


* Etc

bt_stack.conf

bt_did.conf

auto_pair_devlist.conf

Posted by 깍수
,

Bluetooth를 이용하여 파일을 수신할 경우 수신된 위치는 sdcard/downloads/bluetooth 위치에 수신된 

파일이 있다.

Posted by 깍수
,