ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Raspberry Pi 3 블루투스 페어링 방법(bluetoothctl) 및 C언어 블루투스 서버 예제
    Raspberry Pi/Bluetooth 2019. 9. 8. 08:32



    Bluetooth 모듈이 내장되어 있는 Raspberry Pi 3와  윈도우가 설치된 PC 간에 페어링 및 메시지를 주고 받는 방법을 설명합니다.


    블루투스 통신 테스트는 C언어로 작성된 Bluetooth 서버 예제를 Raspberry PI 3에서 컴파일 및 실행시켜놓고  PC에서 터미널(클라이언트)을 통해 문자열 전송 테스트를 진행 했습니다.




    1. bluetoothctl 명령을 사용하여 페어링하는 방법


    2. Bluetooth 서버 예제 테스트


    3. 블루투스 에코 서버 소스코드




    관련 포스팅


    Raspberry Pi 3와 Android 앱 간에 Bluetooth 통신 테스트

    http://webnautes.tistory.com/995  



    최초작성 - 2017.05.22

    최종작성 - 2019. 9. 8




    bluetoothctl 명령을 사용하여 페어링하는 방법

    라즈베리파이와 윈도우 사이에 페어링하는 방법을 설명합니다.



    1. 윈도우의 작업 표시줄 오른쪽 끝에 있는 블루투스 아이콘을 더블클릭합니다.





    2. 라즈베리파이에서 윈도우가 설치된 PC를 검색할 수 있도록 Bluetooh으로 두고 창을 닫지 않고 유지합니다.


    아래 화면처럼 다른 블루투스 디바이스에서 어떤 이름(여기에선 WEBNAUTES-PC, 윈도우에서 지정한 컴퓨터 이름입니다.)으로 검색되는지 알려줍니다. 





    3. Raspberry Pi 3의 터미널에서 윈도우 설치된 컴퓨터와 페어링을 하기 위해  bluetoothctl  명령을 실행합니다. 


    pi@raspberrypi:~ $ bluetoothctl



    현재 디폴트로 설정되어 있는 Raspberry Pi 3에 내장된 Bluetooth 모듈의 맥어드레스를 출력해줍니다.

    [bluetooth] # 옆에 커서가 깜박이면서  명령 입력 대기모드가 됩니다.


    pi@raspberrypi:~ $ bluetoothctl
    [NEW] Controller B8:27:EB:DA:FA:66 raspberrypi [default]
    [bluetooth]#



     bluetoothctl는 블루투스 디바이스를 검색하고 페어링 및 연결 등의 목적으로 사용할 수 있는 유틸리티입니다.


    대화형 명령 방식이라서  명령을 입력하면 바로 결과를 보여줍니다.




    4. show를 입력하면 Raspberry Pi 3에서 사용중인 모듈의 정보를 보여줍니다.


    블루투스 모듈의 맥어드레스는 B8:27:E8:DA:FA:66입니다.

    Powered: yes 현재 모듈의 전원이 켜져 있습니다.

    Discoverable: no 다른 블루투스 장치에서 검색할 수 없도록 설정되어 있습니다.

    Pairable: yes 페어링이 가능하도록 설정되어 있습니다.

    Discovering: no 현재 다른 블루투스 장치를 검색하고 있지 않습니다.

    UUID 목록은 라즈베리파이에서 제공하는 블루투스 서비스입니다. 


    [bluetooth]# show
    Controller B8:27:EB:DA:FA:66
            Name: raspberrypi
            Alias: raspberrypi
            Class: 0x6c0000
            Powered: yes
            Discoverable: no
            Pairable: yes
            UUID: Headset AG                (00001112-0000-1000-8000-00805f9b34fb)
            UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
            UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
            UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
            UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
            UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
            UUID: Handsfree                 (0000111e-0000-1000-8000-00805f9b34fb)
            UUID: Handsfree Audio Gateway   (0000111f-0000-1000-8000-00805f9b34fb)
            UUID: Headset                   (00001108-0000-1000-8000-00805f9b34fb)
            Modalias: usb:v1D6Bp0246d052B
            Discovering: no




    5. 모듈의 전원이 꺼져있다면(Powered: no) 다음 명령으로 모듈의 전원을 켜줍니다.


    [bluetooth]# power on
    [CHG] Controller B8:27:EB:DA:FA:66 Class: 0x6c0000
    Changing power on succeeded
    [CHG] Controller B8:27:EB:DA:FA:66 Powered: yes




    6. 주변에 있는 블루투스 디바이스를 검색합니다. 사용중인 컴퓨터 이름(노란색)이 보일때까지 대기합니다. 


    [bluetooth]# scan on
    Discovery started
    [CHG] Controller B8:27:EB:DA:FA:66 Discovering: yes
    [NEW] Device 5D:82:50:E3:FC:67 5D-82-50-E3-FC-67
    [NEW] Device 1B:B1:D2:D9:D1:75 1B-B1-D2-D9-D1-75



    잠시 기다리면 컴퓨터 이름(WEBNAUTES-PC)이 검색되며 블루투스 모듈 맥어드레스도 같이 출력됩니다.


    [bluetooth]# scan on
    Discovery started
    [CHG] Controller B8:27:EB:DA:FA:66 Discovering: yes
    [NEW] Device 5D:82:50:E3:FC:67 5D-82-50-E3-FC-67
    [NEW] Device 1B:B1:D2:D9:D1:75 1B-B1-D2-D9-D1-75
    [NEW] Device 4F:20:E9:3B:B8:24 4F-20-E9-3B-B8-24
    [NEW] Device 69:E5:68:7A:8F:8E 69-E5-68-7A-8F-8E
    [CHG] Device 4F:20:E9:3B:B8:24 RSSI: -91
    [NEW] Device 74:A2:23:5C:3A:31 74-A2-23-5C-3A-31
    [NEW] Device F8:63:3F:27:10:E0 WEBNAUTES-PC



     WEBNAUTES-PC의 블루투스 모듈  맥어드레스를 info 명령과 함께 입력해주면 블루투스 모듈 상태 정보를 얻을 수 있습니다. scan on 명령이 실행된 상태에서만 가능한 명령입니다. 


    [bluetooth]# info F8:63:3F:27:10:E0
    Device F8:63:3F:27:10:E0
            Name: WEBNAUTES-PC
            Alias: WEBNAUTES-PC
            Class: 0x0a010c
            Icon: computer
            Paired: no
            Trusted: no
            Blocked: no
            Connected: no
            LegacyPairing: no
            UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
            RSSI: -41
            TxPower: 12




    7. 주변 블루투스 디바이스 검색을 중지합니다.


    [bluetooth]# scan off
    Discovery stopped
    [CHG] Controller B8:27:EB:DA:FA:66 Discovering: no




    8. 에이전트를 활성화하고 기본값으로 설정합니다. 페어링 핀 코드를 요청 및 확인을 하기 위해 필요합니다.


    [bluetooth]# agent on
    Agent registered
    [bluetooth]# default-agent
    Default agent request successful




    9. pair 명령과 앞에서 확인한 컴퓨터 WEBNAUTES-PC의 블루투스 모듈 맥어드레스를 같이 적어주면 페어링이 진행됩니다.


    Raspberry Pi에서 페어링시 확인해야 하는 핀 번호(744950)를 보여주는데 WEBNAUTES-PC에서 보여주는 핀번호와 일치하는지 확인하고  yes를 입력해야 합니다.


    [bluetooth]# pair F8:63:3F:27:10:E0
    Attempting to pair with F8:63:3F:27:10:E0
    [CHG] Device F8:63:3F:27:10:E0 Connected: yes
    Request confirmation
    [agent] Confirm passkey 744950 (yes/no): 




    10. 바로 컴퓨터를 확인하면 오른쪽 아래 시계위에 아래와 같은 메시지가 보입니다.

    탭하여 raspberrypi 설정을 클릭합니다.




    윈도우에서도 핀 번호(744950)를 보여주며 Raspberry Pi의 핀번호와 일치하는지 물어봅니다.

    Raspberry Pi에서 확인한 핀번호와 일치하면를 클릭합니다.





    11. Raspberry Pi에서도 yes를 입력하고 엔터를 누릅니다.


    [bluetooth]# pair F8:63:3F:27:10:E0
    Attempting to pair with F8:63:3F:27:10:E0
    [CHG] Device F8:63:3F:27:10:E0 Connected: yes
    Request confirmation
    [agent] Confirm passkey 744950 (yes/no): yes




    12. 양쪽에서 핀번호가 일치한 걸 확인해야 정상적으로 페어링이 이루어집니다.

    Raspberry Pi와 윈도우에서 각각 페어링이 성공했음을 알려줍니다.


    [bluetooth]# pair F8:63:3F:27:10:E0
    Attempting to pair with F8:63:3F:27:10:E0
    [CHG] Device F8:63:3F:27:10:E0 Connected: yes
    Request confirmation
    [agent] Confirm passkey 744950 (yes/no): yes
    [CHG] Device F8:63:3F:27:10:E0 ServicesResolved: yes
    [CHG] Device F8:63:3F:27:10:E0 Paired: yes
    Pairing successful
    [CHG] Device F8:63:3F:27:10:E0 ServicesResolved: no
    [CHG] Device F8:63:3F:27:10:E0 Connected: no
    [CHG] Device F8:63:3F:27:10:E0 Connected: yes





    잠시 기다리면 윈도우의 블루투스 설정 창에 Raspberry Pi가 페어링됨으로  표시됩니다.

    이제 블루투스 설정 창을 닫아도 됩니다.





    13. Raspberry Pi에서 제공하는 블루투스 서비스를 컴퓨터와 연결할지 물어보려고 다음처럼 보일 수 있습니다.  no를 입력합니다.


    Authorize service
    [agent] Authorize service 0000110d-0000-1000-8000-00805f9b34fb (yes/no): no
    [WEBNAUTES-PC]#




    14. 페어링 완료후, trust 명령을 해줘야 합니다.


    [WEBNAUTES-PC]# trust F8:63:3F:27:10:E0
    [CHG] Device F8:63:3F:27:10:E0 Trusted: yes
    Changing F8:63:3F:27:10:E0 trust succeeded




    15.  info 명령과 블루투스 모듈 맥어드레스를 같이 적어주면 모듈 상태를 보여줍니다.

    6번에서 모듈 상태 확인한 것과 비교해보면 PairedTrusted 항목이 yes로 변경되었습니다.


    [WEBNAUTES-PC]# info F8:63:3F:27:10:E0
    Device F8:63:3F:27:10:E0
            Name: WEBNAUTES-PC
            Alias: WEBNAUTES-PC
            Class: 0x0a010c
            Icon: computer
            Paired: yes
            Trusted: yes
            Blocked: no
            Connected: yes
            LegacyPairing: no
            UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
            UUID: Advanced Audio Distribu.. (0000110d-0000-1000-8000-00805f9b34fb)
            UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)




    16.  페어링을 취소하는 방법을 잠시 설명하겠습니다.  지금 진행하지는 마세요.

    paired-devices 명령으로 현재 페어링된 디바이스 확인을 할 수 있습니다.


    [WEBNAUTES-PC]# paired-devices
    Device F8:63:3F:27:10:E0 WEBNAUTES-PC



    remove 명령과 WEBNAUTES-PC의 블루투스 모듈 맥어드레스를 같이 적어주면 페어링 설정이 Raspberry Pi 에서 삭제됩니다.


    [WEBNAUTES-PC]# remove F8:63:3F:27:10:E0
    Device has been removed
    [CHG] Device F8:63:3F:27:10:E0 Connected: no
    [DEL] Device F8:63:3F:27:10:E0 WEBNAUTES-PC
    [bluetooth]#



    블루투스 특성상 한쪽에서 페어링을 취소했다고 양쪽 모두에 동시에 반영되지 않습니다.

    윈도우의 블루투스 설정 창에서도 장치 제거를 해줘야 합니다.



    다시 페어링을 하려면 6번부터 진행하시면 됩니다.




    17.  connect 명령과 disconnect 명령으로 블루투스 디바이스에 연결 및 연결 해제를 할 수 있습니다.

    여기에서는 테스트 할 수없어서 생략하겠습니다.




    18. quit 명령으로  bluetoothctl를 종료합니다.


    [bluetooth]# quit
    Agent unregistered
    [DEL] Controller B8:27:EB:DA:FA:66 raspberrypi [default]




    Bluetooth 서버 예제 테스트 

    라즈베리파이에서 블루투스 서버를 실행시켜 두고 윈도우의 터미널을 사용하여 테스트하는 방법을 설명합니다. 


    1. C/C++ 컴파일러와 관련 라이브러리, make 같은 도구들이 포함되어 있는 build-essential 패키지를 설치해줍니다. 

    다음처럼 이미 설치되어 있을 수도 있습니다. 


    pi@raspberrypi:~ $ sudo apt-get install build-essential
    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    build-essential is already the newest version (12.3).
    0 upgraded, 0 newly installed, 0 to remove and 73 not upgraded.




    2. 예제 코드를 컴파일 해줍니다. 코드는 포스팅 마지막에 있습니다. 


    pi@raspberrypi:~ $ gcc bluetooth_server.c -o bluetooth_server -lbluetooth  -lpthread



    컴파일시 다음과 같은 에러가 나면  libbluetooth-dev 패키지가 설치 안되어 있어서 입니다.


    pi@raspberrypi:~ $ gcc bluetooth_server.c -o bluetooth_server -lbluetooth  -lpthread
    bluetooth_server.c:6:33: fatal error: bluetooth/bluetooth.h: No such file or directory
    #include <bluetooth/bluetooth.h>
                                    ^
    compilation terminated.



    libbluetooth-dev 패키지에는 블루투스 프로그래밍을 하기 위해 필요한 라이브러리가 포함되어 있습니다. 설치 해주고 나서 ..


    pi@raspberrypi:~ $ sudo apt-get install libbluetooth-dev



    다시 컴파일해보면 문제 없이 완료됩니다.


    pi@raspberrypi:~ $ gcc bluetooth_server.c -o bluetooth_server -lbluetooth  -lpthread
    pi@raspberrypi:~ $




    3. 실행시켜 보면 세그멘테이션 폴트(Segmentation Fault)가 발생합니다. 


    pi@raspberrypi:~ $ ./bluetooth_server
    Registering UUID 00001101-0000-1000-8000-00805f9b34fb
    Segmentation fault




    에러를 해결하기 위해서는 SDP Server를 활성화시켜 줘야합니다.

    dbus-org.bluez.service 파일을 편집기로 열어서 


    pi@raspberrypi:~ $ sudo nano /etc/systemd/system/dbus-org.bluez.service



    아래 부분을 찾아서 빨간색 부분을 추가해줍니다.


    ExecStart=/usr/lib/bluetooth/bluetoothd --compat




    4. 재부팅해줘야 설정이 적용됩니다. (데몬 재시작으로는 반영이 안됩니다.)


    pi@raspberrypi:~ $ sudo reboot




    5. 재부팅 완료 후,  퍼미션 문제를 해결하기 위해 다음 한줄을 실행합니다.

    재부팅할때 마다 실행시켜 주어야 세그멘테이션 폴트가 나지 않습니다. 


    pi@raspberrypi:~ $ sudo chmod 777 /var/run/sdp



    부팅할때 마자 실행되도록   홈디렉토리에 있는 .bashrc 파일 끝에 추가해두어도 됩니다. 


    pi@raspberrypi:~ $ sudo nano ~/.bashrc




    페어링은 한번 해주면  다시 할 필요가 없습니다.




    6. 이제 실행시켜보면 아래처럼 나오면서 대기 상태가 됩니다..

    서버 프로그램 bluetooth_server을 실행시켜 놓고 진행해야 합니다.


    pi@raspberrypi:~ $ ./bluetooth_server




    7. 윈도우의 작업 표시줄 오른쪽 끝에 있는 블루투스 아이콘을 더블클릭합니다.





    8. 블루투스 설정 창에서 추가 Bluetooth 옵션을 선택합니다.





    9. Bluetooth 설정 창의 COM 포트 탭에서 추가를 클릭합니다.





    10. 송신(PC에서 연결 시작)을 선택하고 COM 포트를 사용할 장치 아래에 있는 콤보 박스를 클릭합니다.




    콤보 박스 클릭시 보이는 raspberrypi를 선택합니다.

     Raspberry Pi에서 블루투스 서버 프로그램을 실행시켜놔야 raspberrypi가 보입니다.




    서비스 항목에 자동으로 Armatus Bluetooth server가 입력됩니다. 확인을 클릭합니다.





    11. 잠시 기다리면 송신용으로 포트가 추가됩니다. 수신 포트가 추가되어있다면 제거해주세요.  

    이제 확인을 클릭하여 Bluetooth 설정 창을 닫습니다.





    12. 시리얼 통신을 지원하는 터미널 프로그램을 실행시킵니다.  여기선 MobaXterm를 사용했습니다.


    MobaXterm은 아래 링크에서 다운로드 가능합니다.

    http://mobaxterm.mobatek.net/download-home-edition.html



    MobaXterm을 실행한 후, 왼쪽 위에 있는 Session을 클릭합니다.





    지원하는 연결 서비스 중에 Serial을 클릭합니다.




    별다른 설정없이 바로 OK를 클릭합니다. 




    자동으로 앞에서 추가했던 COM6가 선택됩니다. 


    물리적인 COM 포트가 있는 컴퓨터의 경우 다른 COM 포트가 선택되어 있다면 아래 화면처럼 표준 Bluetooth에서 직렬 링크라고 설명이 되어있는 COM 포트를 선택하세요.

    시리얼 통신을 연결을 하기 위해 OK를 클릭합니다.

     




    13. Raspberry Pi의 터미널을 확인하면 접속했다는 것을 알려줍니다. 





    14. 컴퓨터의 터미널에서 helloworld !라고 입력하면 




    15. Raspberry Pi의 터미널에서 받은 문자들을 보여줍니다.




    16. 한글을 입력하면 다음처럼 에코됩니다.





    또한  컴퓨터에서 Raspberry Pi로의 전송만 가능하도록 구현되어 있습니다.




    블루투스 에코 서버 소스코드

    2017.12.8 - c++에서도 컴파일 가능하도록 수정되었습니다.


    구조체를 #define을 이용해서 정의해놓은 BDADDR_ANY, BDADDR_LOCAL를 그냥 C++코드에서 사용하려하면 다음과 같은 에러가 발생합니다.

    error: taking address of temporary [-fpermissive]


    다음처럼 소스코드 내에서 선언을 해줘서 해결했습니다.(참고 3)

    bdaddr_t bdaddr_any = {0, 0, 0, 0, 0, 0};

    bdaddr_t bdaddr_local = {0, 0, 0, 0xff, 0xff, 0xff};



    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/sdp.h>
    #include <bluetooth/sdp_lib.h>
    #include <bluetooth/rfcomm.h>
    #include <sys/wait.h>
    #include <pthread.h>
    #include <signal.h>


    void *ThreadMain(void *argument);
    bdaddr_t bdaddr_any = {0, 0, 0, 0, 0, 0};
    bdaddr_t bdaddr_local = {0, 0, 0, 0xff, 0xff, 0xff};

    int _str2uuid( const char *uuid_str, uuid_t *uuid ) {
        /* This is from the pybluez stack */

        uint32_t uuid_int[4];
        char *endptr;

        if( strlen( uuid_str ) == 36 ) {
            char buf[9] = { 0 };

            if( uuid_str[8] != '-' && uuid_str[13] != '-' &&
            uuid_str[18] != '-' && uuid_str[23] != '-' ) {
            return 0;
        }
        // first 8-bytes
        strncpy(buf, uuid_str, 8);
        uuid_int[0] = htonl( strtoul( buf, &endptr, 16 ) );
        if( endptr != buf + 8 ) return 0;
            // second 8-bytes
            strncpy(buf, uuid_str+9, 4);
            strncpy(buf+4, uuid_str+14, 4);
            uuid_int[1] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            // third 8-bytes
            strncpy(buf, uuid_str+19, 4);
            strncpy(buf+4, uuid_str+24, 4);
            uuid_int[2] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            // fourth 8-bytes
            strncpy(buf, uuid_str+28, 8);
            uuid_int[3] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            if( uuid != NULL ) sdp_uuid128_create( uuid, uuid_int );
        } else if ( strlen( uuid_str ) == 8 ) {
            // 32-bit reserved UUID
            uint32_t i = strtoul( uuid_str, &endptr, 16 );
            if( endptr != uuid_str + 8 ) return 0;
            if( uuid != NULL ) sdp_uuid32_create( uuid, i );
        } else if( strlen( uuid_str ) == 4 ) {
            // 16-bit reserved UUID
            int i = strtol( uuid_str, &endptr, 16 );
            if( endptr != uuid_str + 4 ) return 0;
            if( uuid != NULL ) sdp_uuid16_create( uuid, i );
        } else {
            return 0;
        }

        return 1;

    }



    sdp_session_t *register_service(uint8_t rfcomm_channel) {

        /* A 128-bit number used to identify this service. The words are ordered from most to least
        * significant, but within each word, the octets are ordered from least to most significant.
        * For example, the UUID represneted by this array is 00001101-0000-1000-8000-00805F9B34FB. (The
        * hyphenation is a convention specified by the Service Discovery Protocol of the Bluetooth Core
        * Specification, but is not particularly important for this program.)
        *
        * This UUID is the Bluetooth Base UUID and is commonly used for simple Bluetooth applications.
        * Regardless of the UUID used, it must match the one that the Armatus Android app is searching
        * for.
        */
        const char *service_name = "Armatus Bluetooth server";
        const char *svc_dsc = "A HERMIT server that interfaces with the Armatus Android app";
        const char *service_prov = "Armatus";

        uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid,
              svc_class_uuid;
        sdp_list_t *l2cap_list = 0,
                    *rfcomm_list = 0,
                    *root_list = 0,
                      *proto_list = 0,
                      *access_proto_list = 0,
                        *svc_class_list = 0,
                        *profile_list = 0;
        sdp_data_t *channel = 0;
        sdp_profile_desc_t profile;
        sdp_record_t record = { 0 };
        sdp_session_t *session = 0;

        // set the general service ID
        //sdp_uuid128_create(&svc_uuid, &svc_uuid_int);
        _str2uuid("00001101-0000-1000-8000-00805F9B34FB",&svc_uuid);
        sdp_set_service_id(&record, svc_uuid);

        char str[256] = "";
        sdp_uuid2strn(&svc_uuid, str, 256);
        printf("Registering UUID %s\n", str);

        // set the service class
        sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
        svc_class_list = sdp_list_append(0, &svc_class_uuid);
        sdp_set_service_classes(&record, svc_class_list);

        // set the Bluetooth profile information
        sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
        profile.version = 0x0100;
        profile_list = sdp_list_append(0, &profile);
        sdp_set_profile_descs(&record, profile_list);

        // make the service record publicly browsable
        sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
        root_list = sdp_list_append(0, &root_uuid);
        sdp_set_browse_groups(&record, root_list);

        // set l2cap information
        sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
        l2cap_list = sdp_list_append(0, &l2cap_uuid);
        proto_list = sdp_list_append(0, l2cap_list);

        // register the RFCOMM channel for RFCOMM sockets
        sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
        channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
        rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
        sdp_list_append(rfcomm_list, channel);
        sdp_list_append(proto_list, rfcomm_list);

        access_proto_list = sdp_list_append(0, proto_list);
        sdp_set_access_protos(&record, access_proto_list);

        // set the name, provider, and description
        sdp_set_info_attr(&record, service_name, service_prov, svc_dsc);

        // connect to the local SDP server, register the service record,
        // and disconnect
        session = sdp_connect(&bdaddr_any, &bdaddr_local, SDP_RETRY_IF_BUSY);
        sdp_record_register(session, &record, 0);

        // cleanup
        sdp_data_free(channel);
        sdp_list_free(l2cap_list, 0);
        sdp_list_free(rfcomm_list, 0);
        sdp_list_free(root_list, 0);
        sdp_list_free(access_proto_list, 0);
        sdp_list_free(svc_class_list, 0);
        sdp_list_free(profile_list, 0);

        return session;
    }



    char input[1024] = { 0 };
    char *read_server(int client) {
        // read data from the client
        int bytes_read;
        bytes_read = read(client, input, sizeof(input));
        if (bytes_read > 0) {
            printf("received [%s]\n", input);
            return input;
        } else {
            return NULL;
        }
    }

    void write_server(int client, char *message) {
        // send data to the client
        char messageArr[1024] = { 0 };
        int bytes_sent;
        strcpy(messageArr, message);

        bytes_sent = write(client, messageArr, strlen(messageArr));
        if (bytes_sent > 0) {
            printf("sent [%s] %d\n", messageArr, bytes_sent);
        }
    }

    int main()
    {

        pthread_t thread_id; 
     
        signal( SIGPIPE, SIG_IGN ); 
       
       
        int port = 3, result, sock, client, bytes_read, bytes_sent;
        struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
        char buffer[1024] = { 0 };
        socklen_t opt = sizeof(rem_addr);

        // local bluetooth adapter
        loc_addr.rc_family = AF_BLUETOOTH;
        loc_addr.rc_bdaddr = bdaddr_any;
        loc_addr.rc_channel = (uint8_t) port;

        // register service
        sdp_session_t *session = register_service(port);
        // allocate socket
        sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
        printf("socket() returned %d\n", sock);

        // bind socket to port 3 of the first available
        result = bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
        printf("bind() on channel %d returned %d\n", port, result);

        // put socket into listening mode
        result = listen(sock, 1);
        printf("listen() returned %d\n", result);

        //sdpRegisterL2cap(port);
       
       
        while(1)
        {
            // accept one connection
            printf("calling accept()\n");
            client = accept(sock, (struct sockaddr *)&rem_addr, &opt);
            printf("accept() returned %d\n", client);
       
            ba2str(&rem_addr.rc_bdaddr, buffer);
            fprintf(stderr, "accepted connection from %s\n", buffer);
            memset(buffer, 0, sizeof(buffer));
           
            pthread_create( &thread_id, NULL, ThreadMain, (void*)client);  
        }
       
    }


    void *ThreadMain(void *argument) 

        char buf[1024]; 
     
        pthread_detach(pthread_self()); 
        int client = (int)argument; 

     
        while(1
        {
            char *recv_message = read_server(client);
            if ( recv_message == NULL ){
                printf("client disconnected\n");
                break;
            }
           
            printf("%s\n", recv_message);
           
            write_server(client, recv_message);
        }
     
        printf("disconnected\n" ); 
        close(client); 
     
        return 0;    
    }  





    2019. 9. 8

    라즈베리파이에서 키보드 입력을 받아 안드로이드로 문자열 전송하도록 수정했습니다.

    안드로이드에서 보내는 문자열은 출력되거나 에코되지 않습니다. 


    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/sdp.h>
    #include <bluetooth/sdp_lib.h>
    #include <bluetooth/rfcomm.h>
    #include <sys/wait.h>
    #include <pthread.h>
    #include <signal.h>


    void *ThreadMain(void *argument);
    bdaddr_t bdaddr_any = {0, 0, 0, 0, 0, 0};
    bdaddr_t bdaddr_local = {0, 0, 0, 0xff, 0xff, 0xff};

    int _str2uuid( const char *uuid_str, uuid_t *uuid ) {
        /* This is from the pybluez stack */

        uint32_t uuid_int[4];
        char *endptr;

        if( strlen( uuid_str ) == 36 ) {
            char buf[9] = { 0 };

            if( uuid_str[8] != '-' && uuid_str[13] != '-' &&
            uuid_str[18] != '-' && uuid_str[23] != '-' ) {
            return 0;
        }
        // first 8-bytes
        strncpy(buf, uuid_str, 8);
        uuid_int[0] = htonl( strtoul( buf, &endptr, 16 ) );
        if( endptr != buf + 8 ) return 0;
            // second 8-bytes
            strncpy(buf, uuid_str+9, 4);
            strncpy(buf+4, uuid_str+14, 4);
            uuid_int[1] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            // third 8-bytes
            strncpy(buf, uuid_str+19, 4);
            strncpy(buf+4, uuid_str+24, 4);
            uuid_int[2] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            // fourth 8-bytes
            strncpy(buf, uuid_str+28, 8);
            uuid_int[3] = htonl( strtoul( buf, &endptr, 16 ) );
            if( endptr != buf + 8 ) return 0;

            if( uuid != NULL ) sdp_uuid128_create( uuid, uuid_int );
        } else if ( strlen( uuid_str ) == 8 ) {
            // 32-bit reserved UUID
            uint32_t i = strtoul( uuid_str, &endptr, 16 );
            if( endptr != uuid_str + 8 ) return 0;
            if( uuid != NULL ) sdp_uuid32_create( uuid, i );
        } else if( strlen( uuid_str ) == 4 ) {
            // 16-bit reserved UUID
            int i = strtol( uuid_str, &endptr, 16 );
            if( endptr != uuid_str + 4 ) return 0;
            if( uuid != NULL ) sdp_uuid16_create( uuid, i );
        } else {
            return 0;
        }

        return 1;

    }



    sdp_session_t *register_service(uint8_t rfcomm_channel) {

        /* A 128-bit number used to identify this service. The words are ordered from most to least
        * significant, but within each word, the octets are ordered from least to most significant.
        * For example, the UUID represneted by this array is 00001101-0000-1000-8000-00805F9B34FB. (The
        * hyphenation is a convention specified by the Service Discovery Protocol of the Bluetooth Core
        * Specification, but is not particularly important for this program.)
        *
        * This UUID is the Bluetooth Base UUID and is commonly used for simple Bluetooth applications.
        * Regardless of the UUID used, it must match the one that the Armatus Android app is searching
        * for.
        */
        const char *service_name = "Armatus Bluetooth server";
        const char *svc_dsc = "A HERMIT server that interfaces with the Armatus Android app";
        const char *service_prov = "Armatus";

        uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid,
              svc_class_uuid;
        sdp_list_t *l2cap_list = 0,
                    *rfcomm_list = 0,
                    *root_list = 0,
                      *proto_list = 0,
                      *access_proto_list = 0,
                        *svc_class_list = 0,
                        *profile_list = 0;
        sdp_data_t *channel = 0;
        sdp_profile_desc_t profile;
        sdp_record_t record = { 0 };
        sdp_session_t *session = 0;

        // set the general service ID
        //sdp_uuid128_create(&svc_uuid, &svc_uuid_int);
        _str2uuid("00001101-0000-1000-8000-00805F9B34FB",&svc_uuid);
        sdp_set_service_id(&record, svc_uuid);

        char str[256] = "";
        sdp_uuid2strn(&svc_uuid, str, 256);
        printf("Registering UUID %s\n", str);

        // set the service class
        sdp_uuid16_create(&svc_class_uuid, SERIAL_PORT_SVCLASS_ID);
        svc_class_list = sdp_list_append(0, &svc_class_uuid);
        sdp_set_service_classes(&record, svc_class_list);

        // set the Bluetooth profile information
        sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
        profile.version = 0x0100;
        profile_list = sdp_list_append(0, &profile);
        sdp_set_profile_descs(&record, profile_list);

        // make the service record publicly browsable
        sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
        root_list = sdp_list_append(0, &root_uuid);
        sdp_set_browse_groups(&record, root_list);

        // set l2cap information
        sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
        l2cap_list = sdp_list_append(0, &l2cap_uuid);
        proto_list = sdp_list_append(0, l2cap_list);

        // register the RFCOMM channel for RFCOMM sockets
        sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
        channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
        rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
        sdp_list_append(rfcomm_list, channel);
        sdp_list_append(proto_list, rfcomm_list);

        access_proto_list = sdp_list_append(0, proto_list);
        sdp_set_access_protos(&record, access_proto_list);

        // set the name, provider, and description
        sdp_set_info_attr(&record, service_name, service_prov, svc_dsc);

        // connect to the local SDP server, register the service record,
        // and disconnect
        session = sdp_connect(&bdaddr_any, &bdaddr_local, SDP_RETRY_IF_BUSY);
        sdp_record_register(session, &record, 0);

        // cleanup
        sdp_data_free(channel);
        sdp_list_free(l2cap_list, 0);
        sdp_list_free(rfcomm_list, 0);
        sdp_list_free(root_list, 0);
        sdp_list_free(access_proto_list, 0);
        sdp_list_free(svc_class_list, 0);
        sdp_list_free(profile_list, 0);

        return session;
    }



    char input[1024] = { 0 };
    char *read_server(int client) {
        // read data from the client
        int bytes_read;
        bytes_read = read(client, input, sizeof(input));
        if (bytes_read > 0) {
            printf("received [%s]\n", input);
            return input;
        } else {
            return NULL;
        }
    }

    void write_server(int client, char *message) {
        // send data to the client
        char messageArr[1024] = { 0 };
        int bytes_sent;
        strcpy(messageArr, message);

        bytes_sent = write(client, messageArr, strlen(messageArr));
        if (bytes_sent > 0) {
            printf("sent [%s] %d\n", messageArr, bytes_sent);
        }
    }

    int main()
    {

        pthread_t thread_id; 
     
        signal( SIGPIPE, SIG_IGN ); 
       
       
        int port = 3, result, sock, client, bytes_read, bytes_sent;
        struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
        char buffer[1024] = { 0 };
        socklen_t opt = sizeof(rem_addr);

        // local bluetooth adapter
        loc_addr.rc_family = AF_BLUETOOTH;
        loc_addr.rc_bdaddr = bdaddr_any;
        loc_addr.rc_channel = (uint8_t) port;

        // register service
        sdp_session_t *session = register_service(port);
        // allocate socket
        sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
        printf("socket() returned %d\n", sock);

        // bind socket to port 3 of the first available
        result = bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
        printf("bind() on channel %d returned %d\n", port, result);

        // put socket into listening mode
        result = listen(sock, 1);
        printf("listen() returned %d\n", result);

        //sdpRegisterL2cap(port);
       
       
        while(1)
        {
            // accept one connection
            printf("calling accept()\n");
            client = accept(sock, (struct sockaddr *)&rem_addr, &opt);
            printf("accept() returned %d\n", client);
       
            ba2str(&rem_addr.rc_bdaddr, buffer);
            fprintf(stderr, "accepted connection from %s\n", buffer);
            memset(buffer, 0, sizeof(buffer));
           
            pthread_create( &thread_id, NULL, ThreadMain, (void*)client);  
        }
       
    }


    void *ThreadMain(void *argument) 

        char buf[1024]; 
     
        pthread_detach(pthread_self()); 
        int client = (int)argument; 

     
        while(1
        {
            //char *recv_message = read_server(client);
            //if ( recv_message == NULL ){
            //    printf("client disconnected\n");
            //    break;
            //}
    char buf[1024];
    scanf("%s", buf);
    int size = strlen(buf);
    buf[size] = '\n';
           
            printf("%s\n", buf);
           
            write_server(client, buf);
        }
     
        printf("disconnected\n" ); 
        close(client); 
     
        return 0;    





    참고

    1.https://raspberrypi.stackexchange.com/questions/41776/failed-to-connect-to-sdp-server-on-ffffff000000-no-such-file-or-directory/42262#42262


    2. https://github.com/RyanGlScott/BluetoothTest/blob/master/C%20BlueZ%20Server/bluez_server.c


    3.https://www.experts-exchange.com/questions/27636818/C-C-BlueZ-Bluetooth-BDADDR-ANY-warning-for-address-of-temporary.html




    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구독하기


    댓글 111

    • 이전 댓글 더보기
    • 변기통속물고기 2018.07.17 09:05


      /home/pi/.bashrco 에 맨 마지막 fi 아래에 sudo chmod 777 /var/run/sdp 를 추가하면 재부팅시 명령어를 실행해주지 않아도 되네요!

    • KSG 2018.09.07 05:51


      안녕하세요 늘 도움받고 있습니다!

      이번에는 시도한것들이 다 잘 동작했습니다.
      지금은 bluetooth 를 통해서 라즈베리파이에서 PC로 메세지가 전달될 수 있도록 하는 소스코드를 짜고 있는데요..
      소스코드를 보여드리겠습니다.

      #include "Bluetooth.h"

      int Bluetooth::s, status;

      void Bluetooth::setBluetooth()
      {
      struct sockaddr_rc addr = {0};

      //char dest[18] = "98:D3:32:21:2E:EA"; //bluetooth module
      char dest[18] = "F8:63:3F:1D:EF:5B"; //PC

      s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

      addr.rc_family = AF_BLUETOOTH;
      addr.rc_channel = (uint8_t) 1;
      str2ba(dest, &addr.rc_bdaddr);

      status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
      }
      void Bluetooth::transmitting(unsigned char* _data, int size)
      {
      unsigned char tx_data[size+1];
      for(int i=0; i<size; i++)
      tx_data[i] = _data[i];
      tx_data[size] = END_BIT;

      status = write(s, tx_data, size+1);

      if(status<0) perror("ERROR");
      }
      void Bluetooth::closeBluetooth()
      {
      close(s);
      }

      보통 bluetooth를 통해 메세지 전달에 오류가 생기면 Error transmitting 이라는 메세지가 뜨는데 안 뜨는것을 보아하니,
      라즈베리파이에서 메세지가 PC로 잘 전달된다고 생각이 드는데요,
      문제는 PC에서 teraterm을 통해서든 무슨 방법을 통해서든 메세지를 받고 싶은데요.. teraterm을 이용했을때는 webnautes님께서 제공해주신 bluetooth_server.c 를 꼭 실행시켜야지만 teraterm과 연결이 됩니다.

      제 소스에 teraterm과 bluetooth 포트 연결을 시킬 수 있는 소스를 추가해야 할 것 같은데 어떤것을 추가해야 하나요?

      답변 기다리겠습니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.09.07 07:06 신고


        서비스를 등록하는 부분이 빠진듯합니다..

        register_service 함수 호출관련 코드를 포스팅에서 확인해보세요.

      • KSG 2018.09.07 23:40


        그 부분만 넣으면 되나요..?
        서비스 등록은 한번만 하면 되는게 아니라 프로그램을 실행할 때마다 register_service가 동작하도록 해야한다는 말씀이신건가요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.09.08 09:46 신고


        기기간 페어링은 한번하면 되지만 접속시 자기가 사용할 서비스를 선택해주는 작업이 필요합니다. 기기에서 여러개의 서비스를 제공하기도 하거든요..

        포스팅의 코드와 비교하며 빠진점을 체크하며 진행하세요.

    • jun 2018.09.27 10:25


      Registering UUID 00001101-0000-1000-8000-00805f9b34fb
      socket() returned 4
      bind() on channel 3 returned -1
      listen() returned -1
      calling accept()
      accept() returned -1
      accepted connection from 00:00:00:00:00:00
      client disconnected

      why hannening error code?

    • 조병 2018.10.31 10:56


      안녕하세요! 라즈베리파이3와 블루투스동글과 연결된 윈도우7을 통신하려고 하는데..
      페어링이 진행되고나서 등록까지는 되는데 연결이 안됩니다ㅠㅠ
      페어링 되었다는 메세지가 나오고나서 trust하기전에 끊기면서
      라즈베리파이에서 등록된 pc에 블루투스를 연결하려고하면 "Connection failed - Use the audio menu to connect to this device"라는 문구가 나오면서
      연결이 되지않습니다!
      해결방안이 있나요?

    • gogo 2019.02.15 13:16


      안녕하세요.
      라즈베리파이3 b+와 파이캠을 통해 얻은 실시간 영상을 스마트폰으로 받아 영상처리를 하는 프로젝트를 해보려 하는데
      블루투스 통신으로 할 수 있을까요? 퍼포먼스가 잘 안나올거 같긴한데...

    • 와글이 2019.03.10 01:38


      3 B+ 입니다.
      버젼따라 적용이 쉽지 않네요.

      불루투스 콘트롤을 구현하고 있는 중인데, 자료가 많지 않군요.
      블루투스 게임패드를 리모콘으로 6W 포크레인을 조정하려는데, 무리하는거 아닌지! ^^

      C가 쉬운데, 파이썬으로 하려니 골아퍼요. ^^

      자주 들르겠습니다.

    • 안녕하세요 2019.03.26 14:22


      안녕하세요 안드로이드에서 라즈베리파이로 전송하는 부분은 작동이 잘 되는데 반대로 라즈베리에서 안드로이드로 전송하는 부분에서 어떤 부분을 수정해야 할지 잘 모르겠습니다. main문과 write문을 수정하면 된다고 하셨는데 정확하게 잘 모르겠네요,, 쉽게 설명해 주실 수 있으신가요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.03.26 15:18 신고


        select 함수를 사용하여 수신이 있으면 받은 문자열을 보여주고 키보드 입력이 있으면 전송하도록 하면 됩니다.

        GUI 구현 없이는 키보드 입력과 수신된 메시지를 동시에 보여주기가 애매합니다.

    • 라즈베리파이 2019.03.31 13:46


      라즈베리파이에 연결되어있는 센서의 값을 안드로이드로 전송하고 싶은데
      센서의 값을 어떻게 서버에 보내며 서버에서 어떻게 전송해야 하나요,,?
      이렇게 전송하는것이 어려운 방법인가요?

    • nom3354 2019.04.16 01:11


      안녕하세요 라즈베리파이와 안드로이드 블루투스 통신 앱을 개발하고있는 학생입니다. 다름이아니라 앱을 종료하고 다시 실행하였을 때 블루투스 연결을 새로하기 위해서는 쓰레드를 사용하라고 밑에 댓글을 확인하였습니다. 제가 쓰레드사용법을 잘몰라서 메인부분을 어떠한 방식으로 수정해야되는지 알려주실 수 있으신가 해서 댓글 남깁니다. 블로그가 저에게 큰 힘이 되고있습니다!! 도와주시면 감사하겠습니다.

    • 도와주세요 2019.05.07 16:15


      안녕하세요.
      질문이 있어 이렇게 남깁니다.
      서버 코드 그대로 쓰고 있는데 블루투스 페어링을 앱과 하고 서버컴파일 한 후 에 실행시키면
      while(1)
      {
      // accept one connection
      printf("calling accept()\n");
      client = accept(sock, (struct sockaddr *)&rem_addr, &opt);
      printf("accept() returned %d\n", client);

      ba2str(&rem_addr.rc_bdaddr, buffer);
      fprintf(stderr, "accepted connection from %s\n", buffer);
      memset(buffer, 0, sizeof(buffer));

      pthread_create( &thread_id, NULL, ThreadMain, (void*)client);
      }

      }
      이 while문이 계속 돌아가면서 void *ThreadMain(void *argument) 이 함수가 계속 돌아갑니다.
      혹시 어떤문제인지 알 수 있을까요?

    • Help_me!!!!!!!!!!!!!!!plzㅜㅜㅜㅜㅜ 2019.05.15 17:29


      안녕하세요! 이번에 포스팅 따라하고 있는 초보자입니다 ㅜㅜㅜ
      다름이 아니라 PC JAVA 서버와 예제 어플이랑 연동은 되는데 라즈베리파이에서 연동이 안됩니다.
      PC 랑 페어링 해논 후, 서버를 키고 어플에서 블루투스 연결하면 에코 서버 연결이 됩니다.
      하지만 라즈베리파이에서는 오디오로 연결이 되고 연결 시켜논 것을 어플이랑 연동 시킬려는데 어플에서 UNABLE 에러가 나옵니다....
      C언어 서버 킨 후 연동 시킨겁니다!

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.15 17:51 신고


        라즈베리파이와 페어링후 포스트의 13번처럼 블루투스 서비스를 연결할지 물어볼때 yes를 하면 안되는데 어떻게 하셨나요?

        다시 페어링하면서 No로 해보세요.

    • 토리 2019.05.21 16:15


      라즈베리파이와 스마트폰 블루쿠스 페어링중 위와 같이 진향하였는데 connect 부분에서 no라고 떠 connect 명령어로 입력했더니 Failed to connect: org.bluez.Error.Failed라고 뜨는데 무슨 문제인지 아시나요??

    • help me 2019.05.21 17:26


      안녕하세요 포스팅을 보고 라즈베리파이와 노트북 블루투스 통신을 구현하려고 하는데 cmd창에 gcc bluetooth_server.c -o bluetooth_server -lbluetooth -lpthread 를 쳤을 때 gcc: error: bluetooth_server.c: No such file or directory 라고 뜹니다ㅠㅠ 해결방법을 아시나요ㅠㅠ?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.21 17:28 신고


        포스트에 있는 코드를 파일로 저장했나요?

      • help me 2019.05.21 18:49


        네! 바탕화면에 우클릭 후 빈파일로 만들어 코드를 붙여넣기하고 bluetooth_server.c로 저장하였습니다. 이렇게 하는 것이 아닌가요ㅠㅠ?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.21 20:07 신고


        다음 포스트를 참고하여 라즈베리파이에 작성하세요..


        Raspberry Pi에서 쉽게 코드 작성하는 방법(Sublime Text 3 사용)
        https://webnautes.tistory.com/1327

      • help me 2019.05.28 15:04


        정말 감사합니다! 덕분에 gcc bluetooth_server.c -o bluetooth_server -lbluetooth -lpthread 를 실행할수 있었습니다. 그러나 또 문제가 생겼습니다. bashrc파일에 chmod 777 /var/run/sdp를 추가하는 것까진 하였습니다. 그런데 ./bluetooth_server 을 치면 No such file or directory라고 뜹니다ㅠ 혹시 해결 방법을 아시나요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.28 15:20 신고


        ls 해서 해당 파일이 있나보세요

      • help me 2019.05.28 16:29


        파일이름을 잘못친거 같습니다. ./bluetooth_server.c라고 쳤더니 이번엔 Permission denied라고 뜹니다. 허가가 거부되었다는데 어떻게 해야 할까요ㅠㅠ?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.28 16:49 신고


        ./bluetooth_server.c가 아니라 ./bluetooth_server 가 실행파일입니다.

        혹 안되면 컴파일시 오타가 있나 확인해보세요.

      • help me 2019.05.28 17:27


        리부트도 해보고 cmd창 여러번띄워서 ./bluetooth_server 쳐보고 했더니 실행이 되네요 흑흑 그러나 라즈베리와 노트북 pc가 페어링도 되었고 connect가 되었음에도 불구하고 bluetooth 설정창의 COM포트 추가에 송신장치에 raspberrypi가 안뜹니다ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.28 18:10 신고


        라즈베리파이에서 서버 프로그램을 실행한 상태에서 해야 송신에서 라즈베리파이가 보입니다.

      • help me 2019.05.28 18:45


        서버프로그램을 실행한 상태에서 하였는데도 되지 않습니다ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.28 18:56 신고


        라즈베리파이의 전원을 다시 연결한다음 포스트 7번부터 다시해보세요.



      • help me 2019.05.29 11:23


        라즈베리파이를 몇번씩이고 다시껐다가 켜서 해봤는데도 안되네요....

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.29 12:37 신고


        페어링을 다시 해 볼 필요가 있을듯합니다.

    • 2525kih 2019.08.16 23:51


      안녕하세요. 블로그 내용 도움되었습니다. 감사합니다.
      missing braces around initializer Warnning이 발생합니다.
      괄호추가하여 아래와 같이 수정하였습니다.
      bdaddr_t bdaddr_any = {{0, 0, 0, 0, 0, 0}};
      bdaddr_t bdaddr_local = {{0, 0, 0, 0xff, 0xff, 0xff}};

    • phil 2019.08.27 22:22


      안녕하세요 늦었지만 질문 남깁니다.. 답변해주시면 정말 감사하겠습니다 ㅠ
      노르딕보드 nrf52840과 연결을 하려합니다.
      bluetoothctl로 페어링과 trust 부분 완료 후, connect를 했을 때 연결이 잘됩니다.
      다만, 실행파일을 실행했을 때 calling accept() 이후에 진행이 되지 않습니다.
      노르딕보드에서도 advertising만 진행되고 connect는 안되구요.

      1. connect가 안되는 이유가 무엇일까요? 혹시 노르딕 보드에서 메세지를 송신해야지 connect가 되는것인가요?
      2. 혹시 특정 맥어드레스에 직접 connect를 하는 방식으로 코드를 짜고싶다면, mac어드레스를 어느 부분에다가 입력하면 될까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.27 23:29 신고


        1. 먼가를 보내야 서로 연결이 될듯합니다.


        2. 다음 부분에서 맥어드레스를 확인해서 특정 맥어드레스를 가진 경우에만 접속을 허용하면 될듯합니다.

        ba2str(&rem_addr.rc_bdaddr, buffer);
        fprintf(stderr, "accepted connection from %s\n", buffer);

      • phil 2019.08.28 21:36


        답변해주셔서 정말 감사합니다! 그런데 nrf에서 uart로 메세지 입력해 ble로 쏴도 연결이 안되네요 ㅜㅜ..

        혹시 uuid가 안맞아서 그런걸까요?
        임베디드 보드사이의 uuid는 다른것을 써야하는걸까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.28 22:43 신고


        현재 사용중인 uuid는 시리얼 통신을 위한것입니다. 양쪽 장비에서 지원해야 사용할수 있습니다

    • 3R 2019.09.05 20:42


      안녕하세요? 저는 이 게시물을 통해 라즈베리파이에서 앱으로 데이터를 송신하려고 합니다

      제가 구현한 함수에서는

      1.read_server함수변경

      read_server함수에서는 라즈베리파이 콘솔창에 입력된 문자열을 읽어오는 함수로 변경 하였습니다.

      코드는 다음과 같습니다.
      char *read_server(int client) {
      // read data from the client
      int bytes_read;
      char *pt_string;
      char string[1024];
      //bytes_read = read(client, input, sizeof(input));

      //printf("%s\n", recv_message);
      printf("String:");
      scanf("%s",string);
      pt_string=&string[0];

      if (bytes_read > 0) {
      printf("sent message : [%s]\n", pt_string);
      return pt_string;
      } else {
      return NULL;
      }
      }

      2. write_server함수 변경

      write_server함수는 라즈베리 파이 콘솔에서 입력된 문자열을 앱으로 송신합니다.(블루투스 를 이용해서)

      void write_server(int client, char *message) {
      // send data to the client
      printf("This message is message : %s \n",message);

      char messageArr[1024];
      int bytes_sent;
      int string_length = strlen(message);
      //strcpy(messageArr, message);

      for(int i=0;i<(string_length+1);i++){ //NULL을 달아주기 위한 for
      *(messageArr+i)=*(message+i);
      }

      printf("This message is messageArr : %s \n",messageArr);

      bytes_sent = write(client, messageArr, strlen(messageArr));

      if (bytes_sent > 0) {
      printf("write [%s] %d\n", messageArr, bytes_sent);
      }
      }

      이때, read_server함수에서 콘솔의 문자열을 제대로 받는 것을 확인 하였고
      그 문자열을 write_server함수 내의 messageArr에 복사하였습니다.
      이것까지는 확인이 되었습니다.

      ***하지만 wirte함수를 사용하여 messageArr를 블루투스를 사용해 앱으로 전송하였으나
      안드로이드의 로그 창에서는 messageArr를 받았다는 반응이 없었습니다.

      혹시, 제가 알고있는 write함수의 정의(블루투스로 라즈베리파이에서 앱으로 문자열 송신하기)가 잘못된것인가요
      혹은 앱에서 제가 따로 수정해야할 부분이 있는것인가요(앱은 올려주신 파일 그대로 입니다.)? ***

      • 3R 2019.09.05 20:44


        void *ThreadMain(void *argument)
        {
        char buf[1024];

        pthread_detach(pthread_self());
        int client = (int)argument;


        while(1)
        {
        char *recv_message = read_server(client);

        if ( recv_message == NULL ){
        printf("client disconnected\n");
        break;
        }

        printf("%s\n", recv_message);
        //printf("Answer:");
        //scanf("%s",string);
        //pt_string=&string[0];

        write_server(client,recv_message);
        }

        printf("disconnected\n" );
        close(client);

        return 0;
        }

        **참고 사항으로 ThreadMain함수를 변경 하지 않기 위해 위의 두 함수를 변경한 것입니다. main함수또한 변경 사항이 없습니다.**

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.05 20:51 신고


        라즈베리파이와 앱이 서로 연결된 것을 확인하셨나요?

        앱에서 전송한 문자열을 라즈베리파이 서버에서 바로 에코해서 앱에서 출력되는지 먼저 확인해보세요.

    • 3R 2019.09.05 20:54


      라즈베리와 앱은 연결이 됩니다 에코해서 앱에서 출력되는 것 까지 확인이 된 후 코드만 변경한 상태입니다

      • 3R 2019.09.05 20:55


        위의 게시문 대댓글입니다ㅠㅠㅠ 잘못 적었네요ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.05 21:02 신고


        ThreadMain에서 앱에서 문자열을 보내줄때까지 대기했다가 받으면 에코하도록 되어있습니다. 쓰레드를 주석처리하고 write 하는걸 테스트해보세요. 블루투스라도 write 사용방법은 동일하고 앱은 수정할 필요가 없습니다.

      • 3R 2019.09.05 21:41


        1. "ThreadMain에서 앱에서 문자열을 보내줄때까지 대기했다가 받으면 에코하도록 되어있습니다" 라는 말씀이

        ThreadMain함수내의
        char *recv_message = read_server(client);

        if ( recv_message == NULL ){
        printf("client disconnected\n");
        break;
        }
        라는 코드때문인것 맞나요?


        2. 쓰레드를 주석 처리 하라는 말씀은 ThreadMain함수를 주석 처리 하라는 말씀이신건가요...?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.05 21:53 신고


        다시 생각해보니 쓰레드에서 문자열을 수신받는 부분을 키보드 입력을 대기하는 부분으로 바꾸면 될 듯합니다.

        키보드로부터 입력이 되고나면 write_server를 사용하여 문자열을 전송하면 될듯합니다.

      • 3R 2019.09.05 23:39


        저희도 그렇게 생각해서

        void *ThreadMain(void *argument)
        {
        char buf[1024];

        char string[1024]; //**새로 추가된 부분**
        char *pt_string; //**새로 추가된 부분**

        pthread_detach(pthread_self());
        int client = (int)argument;


        while(1)
        {

        /*새로 추가된 부분*/
        printf("앱으로 송신할 메세지:");
        scanf("%s",string);
        pt_string=string;

        //write_server함수는 포인터로 넘겨 줘야 해서 pt_string을 정의 하였습니다.

        write_server(client,pt_string);
        }

        printf("disconnected\n" );
        close(client);

        return 0;
        }


        이렇게도 돌려 보았는데 앱으로 데이터가 전송되지 않습니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.05 23:48 신고


        쓰레드 생성 전후에 변수 client값이 동일한가 출력해보세요.

      • 3R 2019.09.07 00:41


        쓰레드 생성 전후에 client값은 동일한 것을 확인 했습니다. 라즈베리 파이에서는 보냈다는 send 도 확실히 나옵니다! 안드로이드에서 보여지지는 않습니다. 받았다는 기록이 없습니다.ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.07 23:07 신고


        에코할땐 동작한 것이 키보드 입력시에는 동작 안하다니 이상하네요. 확인해봐야 할듯합니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.08 08:37 신고


        확인해보니 안드로이드 코드에서 \n문자를 기준으로 문자열이 수신되었음을 확인하네요.

        라즈베리파이에서 문자열 끝에 \n을 추가하여 전송하니 해결되었습니다.

        테스트에 사용한 코드를 포스트에 추가해두었습니다. 참고하세요.

    • 김종설 2019.10.28 02:05


      안녕하세요! 페어링 YES,NO가 반복적으로 나타나는 문제 해결을 못 하고 있었는데, 이 글을 처음부터 따라하고 연결 끊김 현상이 해결되었어요ㅠㅠ 정말 감사합니다!!
      그런데 12번에서 표준 직렬 링크 (COM4)에 연결하였는데 "Unable to open connection to COM4 / Unable to open serial port" 라는 경고창이 뜨고 그 이후로 진행이 되지 않습니다ㅜㅠ 혹시 어느부분의 문제인지 아실까요...!!?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.28 20:08 신고


        포스트의 아래 부분처럼 진행했을때

        10. 송신(PC에서 연결 시작)을 선택하고..


        서비스에 아래 항목이 보였나요?

        Armatus Bluetooth server

      • 김종설 2019.10.30 22:09


        네! 포스팅과 똑같이 Armatus Bluetooth server 로 선택했습니다ㅠㅠ 표준 bluetooth 에서 직렬링크 선택 하면 MobaXterm의 Com4창에 “AT+VGM=15” 가 뜨고 그 이후로 진행이되지않습니다ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.30 22:44 신고


        Raspberry Pi로 했는데 AT+VGM=15 메시지가 보이나요?

    • jebalblue 2019.11.15 12:39


      저도 Raspberry Pi로 했는데 앱에 AT+VGM=15 랑 AT+VGS=7이 뜨고 저희가 send한 문자열이 라즈베리파이에 출력이 되지는 않는데 무슨 문제일까요??

    • 2019.12.09 15:40


      비밀댓글입니다

Designed by Tistory.