Communicating with a Remote Device
리모컨과 통신 중
Once you’re successfully connected to a remote device, the BleWrapper will automatically start service discovery (as described in “Service and Characteristic Discovery” on page 69) for the new device.
원격 장치에 성공적으로 연결되면 BleWrapper는 새 장치에 대한 서비스 검색 (69페이지의 "서비스 및 특성 검색"에 설명된 대로)을 자동으로 시작합니다.
This means that it will request the new device to list all the services and characteristics from the device and store them in a list.
이는 장치의 모든 서비스와 특성을 나열하고 이를 목록에 저장하도록 새 장치에 요청한다는 의미입니다.
If the connection to the GATT server and service discovery is successful, another callback is issued.
GATT 서버와 서비스 검색에 성공하면 다른 콜백이 발행됩니다.
This time, the callback is uiAvailableServices() and one of the arguments is the service list, which lists all the Bluetooth GATT services (see “Services” on page 58 for further information on services and characteristics) available on the remote device.
이번 콜백은 uiAvailableServices()이고 인수 중 하나는 원격 장치에서 사용 가능한 모든 Bluetooth GATT 서비스 (서비스 및 특성에 대한 자세한 내용은 58페이지의 "서비스" 참조)를 나열하는 서비스 목록입니다.
In order to communicate with the device, we’ll need to access the services and then the characteristics inside the services.
장치와 통신하려면 서비스에 액세스한 다음 서비스 내부의 특성에 액세스해야 합니다.
At this time, you could just cycle through the list and print out the services, but they’re not in a human-readable format.
이때는 목록을 순환하면서 서비스를 인쇄할 수 있지만 사람이 읽을 수 있는 형식은 아닙니다.
The services are all listed by 128-bit UUID (see “UUIDs” on page 52).
서비스는 모두 128비트 UUID로 나열됩니다 (52페이지의 "UUID" 참조).
The class library files you copied over earlier form the Bluetooth Application Accelerator included a class called BleNamesResolver.
이전에 Bluetooth 애플리케이션 가속기에서 복사한 클래스 라이브러리 파일에는 BleNamesResolver라는 클래스가 포함되어 있습니다.
This class has various methods to resolve UUIDs into BLE names.
이 클래스에는 UUID를 BLE 이름으로 확인하는 다양한 방법이 있습니다.
It can resolve both services and characteristics, so this library is quite useful.
서비스와 특성을 모두 해결할 수 있어서 이 라이브러리는 꽤 유용합니다.
The list of known UUIDs is located in the BleDefinedUUIDs.java file, which you’ll need to add some proprietary service UUIDs to list later on.
알려진 UUID 목록은 BleDefinedUUIDs.java 파일에 있습니다. 나중에 나열하려면 일부 독점 서비스 UUID를 추가해야 합니다.
For now, rather than simply scrolling through the service list and printing out the service UUIDs, you’ll be resolving them into human-readable names and printing those out (just to logcat for now).
지금은 단순히 서비스 목록을 스크롤하고 서비스 UUID를 인쇄하는 대신 이를 사람이 읽을 수 있는 이름으로 확인하고 인쇄합니다 (지금은 logcat에만 해당).
The code is another callback override and goes in the onCreate method and inside the mBleWrapper constructor:
이 코드는 다른 콜백 오버라이딩이고 onCreate 메서드와 mBleWrapper 생성자 내부로 들어간다.
This code cycles through each element in the service list.
이 코드는 서비스 목록의 각 요소를 순환합니다.
For each service, it then converts the UUID to a string value and passes it into the BleNamesResolver.resol veUuid() method.
그런 다음 각 서비스에 대해 UUID를 문자열 값으로 변환하고 이를 BleNamesResolver.resol veUuid() 메서드에 전달합니다.
This method looks through the list of known UUIDs and, when it finds a match for the UUID, returns the associated human-readable UUID name.
이 메서드는 알려진 UUID 목록을 조사하고 UUID와 일치하는 항목을 찾으면 사람이 읽을 수 있는 연관된 UUID 이름을 반환합니다.
It prints that name out to logcat in the Eclipse IDE, as shown in Figure 8-9.
그림 8-9와 같이 Eclipse IDE의 logcat에 해당 이름을 인쇄합니다.
It’s also possible to dump these directly into a textbox for viewing, but that’s slightly more complicated.
보기 위해 텍스트 상자에 직접 덤프할 수도 있지만 이는 약간 더 복잡합니다.
You’ll notice that some UUIDs are unknown.
일부 UUID는 알 수 없음을 알 수 있습니다.
That usually means that vendor specific 128-bit UUIDs are present and you’ll have to add them to the UUID list if you want them to be resolved properly.
이는 일반적으로 공급업체별 128비트 UUID가 존재하며 이를 올바르게 해결하려면 UUID 목록에 추가해야 함을 의미합니다.
In this case, TI uses some vendor-specific service UUIDs for its device, because it doesn’t fit into a standard device profile.
이 경우, TI는 표준 장치 프로필에 맞지 않기 때문에 해당 장치에 일부 공급업체별 서비스 UUID를 사용합니다.
There is a huge UUID address space, so you’ll likely encounter many vendor specific UUIDs while working with different BLE devices.
거대한 UUID 주소 공간이 있으므로 다양한 BLE 장치를 사용하는 동안 많은 공급업체별 UUID를 접하게 될 가능성이 높습니다.
You’ll need to add the TI vendor specific UUIDs to the list and then run the code again.
TI 공급업체별 UUID를 목록에 추가한 다음 코드를 다시 실행해야 합니다.
So far, you’ve gone most of the way to getting your BLE app up and running.
지금까지 BLE 앱을 시작하고 실행하는 데 거의 모든 단계를 완료했습니다.
You’ve detected the remote device, connected to it, and printed the services that it has available.
원격 장치를 감지하고 연결했으며 사용 가능한 서비스를 인쇄했습니다.
The next step is to read the characteristic values (introduced in “Characteristics” on page 59) associated with its sensors.
다음 단계는 센서와 관련된 특성 값 (59페이지의 "특성"에 소개됨)을 읽는 것입니다.
The characteristics that belong to the sensors carry the sensor data, so by reading these out, you can get the sensor data.
센서에 속한 특성들은 센서 데이터를 담고 있기 때문에 이를 읽어내면 센서 데이터를 얻을 수 있습니다.
Once you have the data from the sensors, it’s just a matter of formatting and processing the data, then presenting it to the user in an Communicating with a Remote Device appealing way.
센서에서 데이터를 얻은 후에는 데이터 형식을 지정하고 처리한 다음 원격 장치와 통신하는 방식으로 사용자에게 표시하기만 하면 됩니다.
In this case, we’ll focus on getting the data and leave it up to the user to determine how to process and present it.
이 경우 데이터를 얻는 데 중점을 두고 데이터를 처리하고 표시하는 방법은 사용자에게 맡깁니다.
One thing to be aware of when working with the SensorTag is that it’s a mobile device.
SensorTag를 사용할 때 주의할 점 중 하나는 그것이 모바일 장치라는 것입니다.
It was designed to be low power, so the sensors are powered off by default.
저전력으로 설계되어 기본적으로 센서의 전원이 꺼져있습니다.
To read each sensor, you have to write to a characteristic to turn it on.
각 센서를 읽으려면 특성을 작성하여 켜야 합니다.
Once the sensor is enabled, you can then read the data from it.
센서가 활성화되면 센서에서 데이터를 읽을 수 있습니다.
As discussed in “Characteristics” on page 59, all operations related to user data are effectuated through characteristics.
59페이지의 "특성"에서 설명한 대로 사용자 데이터와 관련된 모든 작업은 특성을 통해 수행됩니다.
To enable a sensor, you’re first going to need to find the service that contains the corresponding characteristic and the characteristic itself (see “Service and Characteristic Discovery” on page 69), and then retrieve its value (as described in “Reading Characteristics and Descriptors” on page 70).
센서를 활성화하려면 먼저 해당 특성이 포함된 서비스와 특성 자체를 찾아야 합니다 (69페이지의 "서비스 및 특성 검색" 참조). 그런 다음 해당 값을 검색해야 합니다 (70페이지의 "특성 및 설명자 읽기"에서 설명).
You then need to modify the characteristic value to one that will enable the sensor and then write it back to the device in the manner described in “Writing Characteristics and Descriptors” on page 71.
그런 다음 특성 값을 센서를 활성화하는 값으로 수정한 다음 71페이지의 "특성 및 설명자 쓰기"에 설명된 방식으로 장치에 다시 써야 합니다.
This is called a read-modify-write operation.
이를 읽기-수정-쓰기 작업이라고 합니다.
You’ve already connected to the peripheral device and have the BluetoothGatt object available to you.
이미 주변 장치에 연결되어 있고 BluetoothGatt 개체를 사용할 수 있습니다.
To retrieve the service, you’re going to use a method inside the gatt object called getService().
서비스를 검색하려면 getService()라는 gatt 객체 내부의 메서드를 사용합니다.
It takes a UUID argument, which means that you’ll have to provide the particular service UUID.
UUID 인수가 필요합니다. 즉, 특정 서비스 UUID를 제공해야 함을 의미합니다.
These are all TI-specific UUIDs, but luckily, TI provides the full list of service and characteristic UUIDs in Java source format in their SensorTag source code.
이것들은 모두 TI 관련 UUID이지만 다행히도 TI는 SensorTag 소스 코드에서 Java 소스 형식의 전체 서비스 및 특성 UUID 목록을 제공합니다.
You’ll want to copy and paste the full UUID listing into your source code and make them constants in your app.
전체 UUID 목록을 소스 코드에 복사하여 붙여넣고 앱에서 상수로 만드는 것이 좋습니다.
Here’s an example of what it should look like:
다음은 이것이 어떻게 보여야 하는지에 대한 예입니다:
The service UUIDs have SERV suffix.
서비스 UUID에는 SERV 접미사가 있습니다.
Otherwise, the other UUIDs are characteristics.
그렇지 않으면 다른 UUID가 특성입니다.
Once you have these defined, you can write code to access the particular sensor’s service and characteristics.
이를 정의한 후에는 특정 센서의 서비스 및 특성에 액세스하는 코드를 작성할 수 있습니다.
Communicating with a remote device isn’t quite as simple as reading a characteristic and having the method return a value.
원격 장치와 통신하는 것은 특성을 읽고 메서드가 값을 반환하도록 하는 것만큼 간단하지 않습니다.
You actually need to send ATT read and write requests to the device, and the GATT server will then send responses to the requests (these concepts are further explained in “ATT operations” on page 26).
실제로 ATT 읽기 및 쓰기 요청을 장치에 보내야 하며, 그러면 GATT 서버가 요청에 대한 응답을 보냅니다 (이러한 개념은 26페이지의 "ATT 작업"에서 자세히 설명합니다).
Only one request can be handled at one time, and any other request that comes in while a request is being processed gets silently dropped.
한 번에 하나의 요청만 처리할 수 있으며 요청이 처리되는 동안 들어오는 다른 요청은 자동으로 삭제됩니다.
This can be a source of frustration because it simply looks like a device is not responding.
이는 단순히 장치가 응답하지 않는 것처럼 보이기 때문에 불만의 원인이 될 수 있습니다.
The correct sequence of operations is to send a request and wait for the appropriate callback.
올바른 작업 순서는 요청을 보내고 적절한 콜백을 기다리는 것입니다.
For example, you would send a read request to the remote device to read a particular characteristic.
예를 들어 특정 특성을 읽으려면 원격 장치에 읽기 요청을 보냅니다.
After the device responds, the BleWrapper will issue a callback to uiNewValueForCharacteristic with the characteristic information.
장치가 응답한 후 BleWrapper는 특성 정보와 함께 uiNewValueForCharacteristic에 대한 콜백을 발행합니다.
By doing so, you are implementing the Read chacteristic value GATT feature explained in “Reading Characteristics and Descriptors” on page 70.
이렇게 하면 70페이지의 "읽기 특성 및 설명자"에 설명된 읽기 특성 값 GATT 기능을 구현하게 됩니다.
This code requests a read of the accelerometer’s configuration characteristic:
이 코드는 가속도계의 구성 특성 읽기를 요청합니다:
Once the the request is issued, the device will respond with the characteristic’s data.
요청이 발행되면 장치는 특성의 데이터로 응답합니다.
In this case, you’re going to dump each byte of the characteristic’s raw value to logcat:
이 경우에는 특성의 원시 값의 각 바이트를 logcat에 버립니다.
It’s important to remember that each read or write must be requested.
각 읽기 또는 쓰기는 요청되어야 한다는 점을 기억하는 것이 중요합니다.
There are functions in Android’s BLE library to get and set a value for characteristics.
Android의 BLE 라이브러리에는 특성 값을 가져오고 설정하는 함수가 있습니다.
These operate only on the locally stored values and not on the remote device.
이는 원격 장치가 아닌 로컬에 저장된 값에서만 작동합니다.
In most cases, any interaction with the remote device will require the use of callbacks.
대부분의 경우, 원격 장치와의 상호 작용에는 콜백을 사용해야 합니다.
Before you read any of the sensor’s data, you first need to enable them.
센서의 데이터를 읽기 전에 먼저 활성화해야 합니다.
To do this, you have to write a value to their configuration characteristic (those are proprietary characteristics to enable sensors, not to be confused with CCCDs).
이렇게 하려면 해당 구성 특성에 값을 써야 합니다 (이는 센서를 활성화하는 독점 특성이며 CCCD와 혼동하지 마십시오).
In most cases, you’d just Communicating with a Remote Device write a 0x01 to this characteristic to enable them.
대부분의 경우 원격 장치와 통신할 때 이 특성에 0x01을 써서 활성화합니다.
As mentioned before, you actually send a write request (Write characteristic value in “Writing Characteristics and Descriptors” on page 71, with the operation listed in “ATT operations” on page 26) to the peer device and then wait for the callback.
앞에서 언급한 것처럼 실제로 쓰기 요청 (26페이지의 "ATT 작업"에 나열된 작업과 함께 71페이지의 "특성 및 설명자 쓰기"의 쓰기 특성 값)을 피어 장치에 보낸 다음 콜백을 기다립니다.
This code enables the accelerometer by writing 0x01 to the accelerometer configuration characteristic on the remote device:
이 코드는 원격 장치의 가속도계 구성 특성에 0x01을 기록하여 가속도계를 활성화합니다.
As before, you need to wait for the callback to know if the write operation was successful.
이전과 마찬가지로 콜백이 쓰기 작업의 성공 여부를 알 때까지 기다려야 합니다.
In cases where you have to wait for things to happen, it’s best to use a separate thread or a state machine.
어떤 일이 일어날 때까지 기다려야 하는 경우에는 별도의 스레드나 상태 머신을 사용하는 것이 가장 좋습니다.
A separate thread would allow you to block the thread as you wait for callback without holding up the rest of the system.
별도의 스레드를 사용하면 시스템의 나머지 부분을 방해하지 않고 콜백을 기다리는 동안 스레드를 차단할 수 있습니다.
The state machine allows you to remain in the same thread and keep track of the current context for the operation being performed.
상태 머신을 사용하면 동일한 스레드에 남아 수행 중인 작업에 대한 현재 컨텍스트를 추적할 수 있습니다.
For a write operation, Application Accelerator has two useful callbacks:
쓰기 작업의 경우 애플리케이션 가속기에는 다음과 같은 두 가지 유용한 콜백이 있습니다:
To enable all of the sensors, you would basically extend the case of enabling one sensor to all of the sensors.
모든 센서를 활성화하려면 기본적으로 하나의 센서를 모든 센서에 활성화하는 사례를 확장합니다.
After the write operation to enable the first sensor, you would enable each of the other sensors in the callback:
첫 번째 센서를 활성화하기 위한 쓰기 작업 후에는 콜백의 다른 각 센서를 활성화하게 됩니다:
Once the sensors are enabled, it’s possible to read the sensor.
센서가 활성화되면 센서를 읽을 수 있습니다.
To manually read the sensor, you’ll issue a read request to the characteristic you want to read and wait for the response in the callback (see “ATT operations” on page 26 and “Reading Characteristics and Descriptors” on page 70 for further details).
센서를 수동으로 읽으려면 읽으려는 특성에 대한 읽기 요청을 발행하고 콜백에서 응답을 기다립니다 (자세한 내용은 26페이지의 "ATT 작업" 및 70페이지의 "특성 및 설명자 읽기" 참조).
The read can be triggered by an event, such as the push of a button or a timer that periodically polls the sensor.
읽기는 버튼 누르기 또는 주기적으로 센서를 폴링하는 타이머와 같은 이벤트에 의해 트리거될 수 있습니다.
In this case, a test button created in the Options menu triggers events.
이 경우, 옵션 메뉴에서 만든 테스트 버튼이 이벤트를 트리거합니다.
That button’s onClick method calls the following function to generate a read request:
해당 버튼의 onClick 메서드는 다음 함수를 호출하여 읽기 요청을 생성합니다:
Once the sensor’s data is acquired, a few steps are still needed to process the data.
센서의 데이터를 획득한 후에도 데이터를 처리하려면 몇 가지 단계가 필요합니다.
The code for the data processing of each sensor can be found in the SensorTag example Android library or in the SensorTag Online User Guide.
각 센서의 데이터 처리를 위한 코드는 SensorTag 예제 Android 라이브러리 또는 SensorTag 온라인 사용자 가이드에서 찾을 수 있습니다.
You can copy/paste the processing algorithm for the accelerometer into the previous code snippet, usually in the ACC_READ state part of the decoder.
가속도계의 처리 알고리즘을 이전 코드 조각 (일반적으로 디코더의 ACC_READ 상태 부분)에 복사하여 붙여넣을 수 있습니다.
The same goes for the data processing for all the other sensors.
다른 모든 센서의 데이터 처리도 마찬가지입니다.
Polling the remote sensor is one way to periodically extract data from it, but it’s not power efficient for both devices.
원격 센서를 폴링하는 것은 주기적으로 데이터를 추출하는 한 가지 방법이지만 두 장치 모두에 전력 효율적이지는 않습니다.
The remote device needs to stay on constantly to catch the read requests and the phone needs to stay awake to send the polling requests.
원격 장치는 읽기 요청을 잡기 위해 지속적으로 켜져 있어야 하고, 전화기는 폴링 요청을 보내기 위해 깨어 있어야 합니다.
A more efficient way to do things is to have the device send notifications (thoroughly described in “Server-Initiated Updates” on page 72) instead.
작업을 수행하는 보다 효율적인 방법은 대신 장치에서 알림을 보내도록 하는 것입니다 (72페이지의 "서버에서 시작하는 업데이트"에 자세히 설명되어 있음).
You can set the period for the notifications manually for some of the sensors.
일부 센서의 경우 알림 기간을 수동으로 설정할 수 있습니다.
Application Accelerator has a special method for enabling notifications.
애플리케이션 가속기에는 알림을 활성화하는 특별한 방법이 있습니다.
To enable notifications on Android, you normally have to locally enable the notification for the characteristic you are interested in.
Android에서 알림을 활성화하려면 일반적으로 관심 있는 특성에 대한 알림을 로컬에서 활성화해야 합니다.
Once that’s done, you also have to enable notifications on the peer device by writing to the device’s client characteristic configuration descriptor (CCCD), as described in “Client Characteristic Configuration Descriptor” on page 62.
이 작업이 완료되면 62페이지의 "클라이언트 특성 구성 설명자"에 설명된 대로 장치의 CCCD (클라이언트 특성 구성 설명자)에 기록하여 피어 장치에서 알림을 활성화해야 합니다.
Luckily, this is abstracted out and both operations can be handled by a single method call.
다행히도 이는 추상화되어 있으며 두 작업 모두 단일 메서드 호출로 처리할 수 있습니다.
The following code enables notifications for the accelerometer when the test button is pushed:
다음 코드는 테스트 버튼을 눌렀을 때 가속도계에 대한 알림을 활성화합니다.
One issue to look out for in the Application Accelerator is it doesn’t implement the onDescriptorWrite() callback available in the Android Bluetooth library.
애플리케이션 가속기에서 주의해야 할 한 가지 문제는 Android Bluetooth 라이브러리에서 사용할 수 있는 onDescriptorWrite() 콜백을 구현하지 않는다는 것입니다.
The most Communicating with a Remote Device reliable way to know when notifications have been successfully enabled on the peer device is to get the onDescriptorWrite() callback after the CCCD has been modified and the GATT server has acknowledged the write operation.
원격 장치와 통신하는 가장 안정적인 방법은 피어 장치에서 알림이 성공적으로 활성화되었는지 확인하는 것이며, CCCD가 수정되고 GATT 서버가 쓰기 작업을 확인한 후 onDescriptorWrite() 콜백을 받는 것입니다.
This example adds the onDescriptorWrite() callback to this implementation of Application Accelerator in the BleWrapper class, where it implements the BluetoothGattCallback code:
이 예제는 BluetoothGattCallback 코드를 구현하는 BleWrapper 클래스의 이 애플리케이션 가속기 구현에 onDescriptorWrite() 콜백을 추가합니다.
The onDescriptorWrite() method will then call Application Accelerator’s uiSuccessfulWrite() method if the notification was written properly.
알림이 올바르게 작성된 경우 onDescriptorWrite() 메서드는 애플리케이션 가속기의 uiSuccessfulWrite() 메서드를 호출합니다.
You can enable notifications for all of the sensor characteristics in the same way you enabled the sensors themselves, using a state machine to sequentially process one after the other.
상태 머신을 사용하여 순차적으로 처리함으로써 센서 자체를 활성화한 것과 동일한 방식으로 모든 센서 특성에 대한 알림을 활성화할 수 있습니다.
For notifications, keep in mind that, for Android 4.4 (KitKat), only four characteristics can have enabled notifications at one time.
알림의 경우 Android 4.4 (KitKat)의 경우 한 번에 4가지 특성만 알림을 활성화할 수 있다는 점을 명심하세요.
This is a limitation of the current Android BLE library implementation, although it will probably be changed in future versions.
이는 현재 Android BLE 라이브러리 구현의 제한사항이지만 향후 버전에서는 변경될 수도 있습니다.
The code in this chapter is mostly presented in fragments, but you can pick up the full source code from the GitHub repository for this book.
이 장의 코드는 대부분 단편으로 제공되지만 이 책의 GitHub 저장소에서 전체 소스 코드를 선택할 수 있습니다.