배우고픈 공돌이

Bluecove 개발 환경 구축 본문

ARM/BBBW

Bluecove 개발 환경 구축

내 마음 아홉수 2017. 12. 4. 17:37

java FX 개발 환경 구축 포스팅에 이어서 디바이스의 블루투스를 java로 제어하는 것을 해보려한다.


이 역할을 하는 라이브러리가 bluecove이다.


여기서 다운 받으면 되지만 FTFP로 옮겨야함으로 SSH커맨드로 받기로 한다.

참조 : https://stackoverflow.com/questions/12597986/my-java-bluetooth-server-on-raspberry-pi-running-debian-wheezy-needs-bluecove-na


위의 과정이 끝나면 ./target 안에 
libbluecove_arm.so파일, bluecove-2.1.1-SNAPSHOT.jar 등이 존재한다.
                          ../../bluecove/target/bluecove-2.1.1-SNAPSHOT.jar가 존재한다.

이들이 모두 라이브러리 파일임으로 잘 간수한다.

   
이제 이클립스에서 만든 실행파일(jar)를 비글본보드로 가져와 확인할 시간이다.

root@beaglebone:/storage/time_task/BlueTooth_JAVA_Example_1205# java -cp bluecove-2.1.1-SNAPSHOT.jar:bluecove-gpl-2.1.1-SNAPSHOT.jar:BBB_bluetooth.jar Main.bBB_java_BT_Main
BlueCove version 2.1.1-SNAPSHOT on bluez
wait for device inquiry to complete...
Device 4827EA8B7669 found
     name Galaxy J5
Device A0C58977258A found
     name KCCISTC-PC
Device A0C589772134 found
     name KCCISTC-PC
Device 508F4C026120 found
     name Redmi
Device Inquiry completed!
4 device(s) found
BlueCove stack shutdown completed
// 갤럭시는 나의 폰이며, 나머지는 강의실에 있는 노트북 이름이 중복되어 뜬다.
// 연속으로 jar를 붙였을 때, 구분자는 :(클론) 이다.

* 자바 실행할 때, 클래스 경로에 2개의 블루투스 라이브러리를 포함해야함으로
java -cp bluecove-2.1.1-SNAPSHOT.jar:bluecove-gpl-2.1.1-SNAPSHOT.jar:MY_JAVA.jar MY_PACKAGE.MY_CLASS
의 형식으로 실행한다.

* 자바 소스는 bluecove의 예제를 돌렸다.

Remote Device Discovery

The LocalDevice class provides method 'getDiscoveryAgent' that returns an instance of the DiscoveryAgent. This DiscoveryAgent can then be used to discover remote bluetooth devices (start HCI inquiry).
import java.io.IOException;
import java.util.Vector;
import javax.bluetooth.*;

/**
 * Minimal Device Discovery example.
 */
public class RemoteDeviceDiscovery {

    public static final Vector/*<RemoteDevice>*/ devicesDiscovered = new Vector();

    public static void main(String[] args) throws IOException, InterruptedException {

        final Object inquiryCompletedEvent = new Object();

        devicesDiscovered.clear();

        DiscoveryListener listener = new DiscoveryListener() {

            public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                System.out.println("Device " + btDevice.getBluetoothAddress() + " found");
                devicesDiscovered.addElement(btDevice);
                try {
                    System.out.println("     name " + btDevice.getFriendlyName(false));
                } catch (IOException cantGetDeviceName) {
                }
            }

            public void inquiryCompleted(int discType) {
                System.out.println("Device Inquiry completed!");
                synchronized(inquiryCompletedEvent){
                    inquiryCompletedEvent.notifyAll();
                }
            }

            public void serviceSearchCompleted(int transID, int respCode) {
            }

            public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
            }
        };

        synchronized(inquiryCompletedEvent) {
            boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, listener);
            if (started) {
                System.out.println("wait for device inquiry to complete...");
                inquiryCompletedEvent.wait();
                System.out.println(devicesDiscovered.size() +  " device(s) found");
            }
        }
    }

}
출처 : http://www.bluecove.org/bluecove/apidocs/overview-summary.html#DeviceDiscovery




============================================================================================
막간 추가

c언어로 bluetooth 에코서버 코드.

컴파일 : -lbluetooth 추가

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


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

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

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


int init_server() {
   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);

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

   return client;
}

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()
{
   int client = init_server();


   while(1)
   {
       char *recv_message = read_server(client);
       if ( recv_message == NULL ){
           printf("client disconnected\n");
           break;
       }

       write_server(client, recv_message);
   }
}


출처 : http://webnautes.tistory.com/1137

'ARM > BBBW' 카테고리의 다른 글

pulseaudio source 설치 시 에러 해결  (0) 2017.12.16
JNA 개발 환경 구축  (0) 2017.11.29
java FX 개발 환경 구축  (0) 2017.11.28
JAVA 개발 환경 구축  (0) 2017.11.13
3. 모니터 사용하기  (0) 2017.10.16
Comments