어떤 개발자들은 무선 기술을 다루기 어려워 하거나 겁을 냅니다. 모든 통신은 무선으로 이루어지므로 그냥 "바라본다"고 해서 1MB의 데이터가 지나가는 것이 눈에 보이지는 않습니다. 또한 모바일 장치에 설치한 무선 애플리케이션은 디버깅하기가 정말 어렵습니다. 애플리케이션을 실행하면서 시스템의 추적 기록이나 로그 파일에 액세스하여 오류를 꼭 집어내기가 불가능하기 때문입니다.

이 기술 기사에서는 다음과 같은 작업에 대해 설명합니다.

  • 블루투스 및 JSR-82 API를 사용하여 몇 가지 무선 개념의 이해를 도움드립니다.
  • 데스크탑 컴퓨터에 자바 ME 블루투스 애플리케이션을 설치하고 디버깅하는 방법을 제시합니다.
  • 블루투스 기능의 GPS 장치에서 데이터를 읽는 방법을 설명합니다.

목차
 
- 중요한 문제: 에뮬레이터 장애
- 환경 설정
- 블루투스와 JSR-82의 몇 가지 미스테리 해결
- 요약
 

저는 CLDC용 썬 무선 툴킷을 아주 좋아합니다. 아주 괜찮은 도구이고, 까다로운 최신 자바 ME JSR 사양에 따라 자바 ME 애플리케이션을 작성해야 할 때 간편하게 사용할 수 있으니까요. 그러나 썬 무선 툴킷의 자바 ME 에뮬레이터에는 블루투스 하드웨어에 액세스하거나 블루투스와 통신하는 기능이 없습니다. 다시 말해, 블루투스 하드웨어에 의존하여 작동하는 API 호출을 시작한 다음에 썬 무선 툴킷으로 애플리케이션을 철저히 테스트할 수가 없다는 뜻입니다. JSR-82 애플리케이션을 개발, 테스트, 디버깅해야 하는 개발자들은 이런 문제로 인해 어려운 상황에 처해 있습니다.

또 간단한 애플리케이션 디버깅을 위해 System.out에 액세스할 수 없으므로 자바 ME 블루투스 애플리케이션을 JSR-82 장치에서 직접 테스트하는 것은 실용적이지도 않습니다. 그 외에도 휴대 전화에서 애플리케이션의 개발, 컴파일, 프로비저닝, 설치하는 반복 사이클에는 상당한 시간이 걸립니다.

이제 여러분은 JSR-82 애플리케이션을 컴퓨터에 설치하여 디버깅하고 테스트할 수 있는 저렴한 솔루션을 제작하는 방법을 배우게 될 것입니다. 제가 소개할 제품은 컴퓨터용 CLDC 에뮬레이터인 Mpowerplayer인데, JSR-82 블루투스 전화기처럼 작동하도록 구성할 수 있습니다. 이렇게 구성된 Mpowerplayer는 JSR-82 블루투스 휴대 전화와 똑같이 작동합니다. 그러나 무선 애플리케이션을 디버깅하려면 System.out에 액세스할 수 있어야 하고 스택 추적 기록을 볼 수 있어야 합니다.

다음 목록에는 이 기사의 후반부에 수록되어 있는 예제 코드를 실행하는 데 필요한 항목이 나와 있습니다.

  • 필수 항목

    • CLDC용 썬 무선 툴킷. 이 도구는 사실상 자바 ME 애플리케이션의 개발 표준입니다.

    • 블루투스 기능의 컴퓨터. PC용 블루투스 모듈은 컴퓨터에 내장되어 있거나 USB 포트를 통해 외부에서 연결하여 사용합니다.

    • Mpowerplayer. 무료로 제공되는 이 데스크탑 애플리케이션은 매우 우수한 모바일 에뮬레이터입니다. 데스크탑 PC의 블루투스 하드웨어에 액세스하여 JSR-82 메소드 호출을 실행할 수 있습니다. 단, 이를 위해서는 실제 블루투스 하드웨어에 대한 액세스 권한이 필요합니다.

    • Mpowerplayer를 지원하는 JSR-82 라이브러리가 꼭 필요합니다. 저는 Mpowerplayer와 무리없이 연동되는 Avetana SDK를 사용합니다.

    • 블루투스 기능의 GPS 장치. 저는 DeLorme Earthmate BT-20을 사용하고 있습니다.

  • 선택 항목

    • JSR-82 API를 지원하는 자바 ME 전화기. 전화기가 JSR-82 API를 지원하는 제품인지 확실하지 않으면 이 목록에서 확인하십시오. 이 목록은 주요 전화기 제조업체에서 지원하는 자바 ME API를 확인하는 데 가장 좋은 자료입니다. 그러나 JSR-82 사양을 만족하는 RIM Blackberry 장치는 하나도 포함되지 않은 것으로 알고 있습니다.

개발자 버전의 Mpowerplayer는 zip 파일 형태로 제공됩니다. 설치할 위치에서 이 파일의 압축을 풀기만 하면 됩니다. 그런 다음, Mpowerplayer가 PC의 블루투스 장치에 액세스할 수 있도록 avetanaBluetoth.jar 파일을 "mpp-sdk\bluetooth" 폴더로 복사합니다. 정말 간단하죠! 나중에 Mpowerplayer가 작동하는 모습의 스냅샷을 보여 드리겠습니다.

원하는 블루투스 서비스의 연결 URL을 일단 파악한 뒤에는 장치 발견 프로세스나 서비스 발견 프로세스를 실행할 필요가 없다는 사실을 알고 계셨습니까? 블루투스 연결 URL이 어떻게 생겼는지 잘 모르시는 분들을 위해 아래의 예제를 준비했습니다.

btspp://001AA3000C19:1;authenticate=false;encrypt=false;master=false

JSR-82 API를 사용하든 사용하지 않든 간에 모든 블루투스 기능 시스템에 적용되는 장치 발견 프로세스 및 서비스 발견 프로세스의 목적을 여기서 간단히 되새겨 보겠습니다. 장치 발견 프로세스는 인근에 있는 블루투스 장치를 파악하는 데 사용됩니다. 위의 연결 URL 예제에 표시된 장치에는 블루투스 주소 001AA3000C19가 있습니다. 이 기사 후반부에서 소개할 예제 코드에서는 BTUtility라는 내부 클래스를 사용했습니다. 이 내부 클래스는 장치 및 서비스 발견을 위해 필요한 모든 JSR-82 블루투스 API 코드를 구현해 줍니다. 아래에서 코드의 일부를 보면 장치 발견의 단계를 알 수 있습니다.

        public BTUtility() {
            try {
                LocalDevice localDevice = LocalDevice.getLocalDevice();
                discoveryAgent = localDevice.getDiscoveryAgent();
                discoveryForm.append(" Searching for Bluetooth devices in the vicinity...\n");
                discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);

            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass cod) {
            try {
 		   discoveryForm.append("found: " + remoteDevice.getFriendlyName(true));
            } catch(Exception e){
               discoveryForm.append("found: " + remoteDevice.getBluetoothAddress());
            } finally{
		   remoteDevices.addElement(remoteDevice);
		}
        }

        public void inquiryCompleted(int discType) {

            if (remoteDevices.size() > 0) {

                // the discovery process was a success
                // so let's out them in a List and display it to the user
                for (int i=0; i<remoteDevices.size(); i++){
                    try{
                       devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getFriendlyName(true), bt_logo);
                    } catch (Exception e){
                       devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getBluetoothAddress(), bt_logo);
                    }
                }
                display.setCurrent(devicesList);
            } else {
			// handle this
		}
 

내부 클래스 자체는 DiscoveryListener 인터페이스를 구현하므로, 원격 블루투스 장치가 발견될 때마다 이 클래스의 deviceDiscovered() 메소드를 호출하게 됩니다. 장치 발견 프로세스가 마침내 종료되면 JVM은 inquiryCompleted() 메소드를 호출할 것입니다. 다행히 여기서는 테스트를 위해 JSR-82 전화기에 이 애플리케이션을 설치할 필요가 없습니다. 앞서 설명한 것처럼 데스크탑 컴퓨터에서 Mpowerplayer를 사용하여 애플리케이션 전체를 테스트할 수 있기 때문입니다.

그림 1은 장치 발견 프로세스 도중 애플리케이션을 실행하는 Mpowerplayer를, 그림 2는 장치 발견 프로세스가 완료된 후 모바일 애플리케이션의 상태를 보여 줍니다.

사용자 삽입 이미지
그림 1. 장치 발견 프로세스 구동 중
 
사용자 삽입 이미지
그림 2. 장치 발견 프로세스 완료
 

지금까지 장치 발견 프로세스에 대해 알아보고 연결할 장치가 사용 가능한 장치 목록에 있는지도 확인했습니다. 이제 정식 연결 URL에 대해 다시 설명하겠습니다.

btspp://001AA3000C19:1;authenticate=false;encrypt=false;master=false

보시다시피, 장치 발견 프로세스를 통해 블루투스 주소(이 경우, 001AA3000C19)와 원격 블루투스 장치의 이름(이 경우, Earthmate BT-20 GPS)을 알 수 있습니다. 그러나 연결 URL을 구성하는 나머지 매개변수가 무엇인지는 아직 모릅니다. 어쨌든 블루투스 장치 하나로 여러 개의 서비스를 실행할 수 있습니다. 예를 들어, 블루투스 액세스 포인트 하나에서 전화 접속 네트워크 연결과 PAN 서비스를 모두 제공할 수 있습니다. 그러므로 선택한 블루투스 장치에서 실행할 적당한 서비스를 먼저 검색해야 합니다.

서비스 검색 프로세스의 성공은 원하는 서비스 유형을 아느냐 모르느냐에 달려 있습니다. 저는 블루투스 기능의 GPS 장치에서 가져온 직렬 데이터를 사용하려고 합니다. 무선 직렬 서비스의 고유 ID는 0x1101입니다. 앞서 설명한 내부 클래스 BTUtility도 서비스 검색에 필요한 코드를 모두 구현해 줍니다. 다음 코드의 일부에서 해당 부분이 나와 있습니다.

        public void run(){

            try {
                RemoteDevice remoteDevice = (RemoteDevice)remoteDevices.elementAt(devicesList.getSelectedIndex());
                discoveryAgent.searchServices(attrSet, uuidSet, remoteDevice , this);

            } catch(Exception e) {
                e.printStackTrace();
            }
        }

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

            for(int i = 0; i < servRecord.length; i++) {

                DataElement serviceNameElement = servRecord[i].getAttributeValue(0x0100);
                String _serviceName = (String)serviceNameElement.getValue();
                String serviceName = _serviceName.trim();
                btConnectionURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);

            }
            display.setCurrent(readyToConnectForm);
		readyToConnectForm.append("\n\nNote: the connection URL is: " + btConnectionURL);
		System.out.println("Note: the connection URL is: " + btConnectionURL);

        }

        public void serviceSearchCompleted(int transID, int respCode) {

            if (respCode == DiscoveryListener.SERVICE_SEARCH_COMPLETED) {
                // the service search process was successful

            } else {
                // the service search process has failed
            }

        }
 

여기서 서비스 검색은 I/O 작업 차단을 의미하므로 애플리케이션이 제대로 작동할 수 있도록 스레드의 run() 메소드 부분에 특히 신경을 많이 썼습니다. 원격 장치에서 조건에 맞는 서비스가 발견될 때마다 JVM은 저의 servicesDiscovered() 메소드를 호출하여 조치를 취하도록 알려줄 것입니다. 아래 그림에서 보듯이, 저는 원하는 서비스를 찾아냈으며 연결 URL을 확인하는 데 필요한 것도 모두 갖추고 있습니다.

사용자 삽입 이미지
그림 3. 직렬 포트 서비스 발견
 

이전의 포인트를 다시 반복하려면 어떻게 해야 할까요? 원하는 장치의 연결 URL을 알아냈으므로 다음 번 이 원격 블루투스 장치를 사용할 때부터는 장치 발견 프로세스나 서비스 발견 프로세스를 거치지 않아도 됩니다. 그 URL로 연결하기만 하면 됩니다. 결국 원격 블루투스 장치와 통신하는 데 필요한 수단을 모두 갖추고 있는 셈입니다.

그림 4는 URL에 연결한 뒤 무선 직렬 포트에서 데이터를 읽어오는 또 다른 스레드 방식의 내부 클래스가 작동하는 모습을 보여 줍니다.

사용자 삽입 이미지
그림 4. 블루투스 GPS 장치에서 데이터 읽기
 

잠깐만요. 지금 GPS 장치에서 직렬 데이터를 읽어오는 것이라면, 위도나 경도 같은 글로벌 위치 지정 정보는 어디에 있을까요? 데이터가 손상된 것일까요?

사실 그림 4에서 본 직렬 데이터는 모든 GPS 장치의 공통 형식인 NMEA(미국해상전자통신위원회) 형식으로 인코딩되어 있습니다. 이 기술 기사의 2부에서 NMEA 데이터를 해독하고 전화기에 위치를 플롯하는 방법에 대해 다루겠습니다.

지금까지 알아본 바와 같이, Mpowerplayer는 썬 무선 툴킷처럼 PC에서 실행되는 CLDC/MIDP 환경입니다. MPowerplayer는 블루투스 하드웨어를 사용하도록 구성할 수 있으므로 JSR-82 애플리케이션을 모바일 장치에 직접 설치하지 않고도 애플리케이션 테스트가 가능하다는 장점이 있습니다.

이 기사가 여러분이 블루투스 장치 및 서비스 발견 프로세스에 대해 이해하는 계기가 되었으면 합니다. 말씀드린 것처럼, 연결 URL을 확보하면 그 뒤부터는 장치 및 서비스 발견 프로세스를 구현하지 않아도 되므로 애플리케이션 성능을 획기적으로 높일 수 있습니다. 다음 기사에서는 이 애플리케이션을 계속 제작하면서 NMEA 데이터 스트림을 구문 분석하는 방법과 사용자의 위치를 지도에 플롯하는 방법에 대해 설명하겠습니다. 지켜봐 주십시오!


자세한 정보

- 이 기사의 소스 코드
- JSR 82 - 블루투스 API 1.1
- CLDC용 썬 자바 무선 툴킷
- CLDC용 썬 자바 무선 툴킷 다운로드


이 글의 영문 원본은
Working with Bluetooth and GPS: Part 1 - Reading Wireless Serial Port Data
에서 보실 수 있습니다.

"Java ME" 카테고리의 다른 글

2008/08/11 10:38 2008/08/11 10:38

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/635

댓글을 달아 주세요

[로그인][오픈아이디란?]

◀ Prev 1  ... 217 218 219 220 221 222 223 224 225  ... 806  Next ▶