레이블이 Bluetooth인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Bluetooth인 게시물을 표시합니다. 모든 게시물 표시

2019년 7월 9일 화요일

ESP32에서 블루투스(SPP profile) 사용하기

ESP32를 사용하면 아두이노에서처럼 따로 HC-05/06 모듈을 붙일 필요 없이 Bluetooth Classic 뿐 아니라 Bluetooth Low Energy(BLE)를 바로 사용할 수 있다.

여기서는 먼저 Bluetooth Classic 프로파일중에 하나인 SPP(Serial Port Profile)을 사용해 보겠다.

아두이노 IDE를 사용하면 Arduino core for ESP32에 필요한 라이브러리가 이미 들어있어 매우 간단하게 사용할 수 있다.

먼저 헤더파일을 include 해 줘야 한다.

#include "BluetoothSerial.h"

그 다음 BluetoothSeria 클래스의l 오브젝트를 선언해준다.

BluetoothSerial bt;

BluetoothSerial 클래스 오브젝트가 선언되면 시리얼 오브젝트와 거의 동일하게 사용할 수 있다. 일단 setup()에서 오브젝트를 초기화 시켜준다.

void setup()
{
  ...
  bt.begin("ESP32_SPP");    
   ...
}

Serial.begin()에서는 파라미터로 통신속도를 넘겨주는데 여기서는 bluetooth device name을 넘겨준다. 다른 기기에서 블루투스 장치를 검색할 때 이 이름으로 보이게 된다.

초기화가 끝나면 Serial 오브젝트와 동일하게 사용해 주면 된다. 즉 bt.read(), bt.write(), bt.available(), bt.print() 등을 Serial과 동일하게 호출할 수 있다.

여기서는 예제로 13번 핀에 LED가 연결되어 있을 때 블루투스로 '+'를 보내면 LED가 켜지고, '-'를 보내면 LED가 꺼지는 코드를 만들어 보겠다.

#include "BluetoothSerial.h"

BluetoothSerial bt;

void setup() {
  Serial.begin(115200);
  bt.begin("ESP32_SPP");
  Serial.println("Waiting for pairing");

  pinMode(13, OUTPUT);
}

void loop() {
 
  if (bt.available()) {
    ch = bt.read();
    if ('+' == ch) {
      digitalWrite(13, HIGH);
      bt.println("LED(13) turned ON");
    } else if ('-' == ch) {
      digitalWrite(13, LOW);
      bt.println("LED(13) turned OFF");
    }
  }
  delay(50);
}


위의 스케치를 ESP32에 업로드하고 시리얼 포트를 열면 다음과 같은 출력이 나올 것이다.


맨 아랫줄에 Waiting for pairing 이라고 출력을 해 블루투스로 연결할 준비가 되었음을 알 수 있다.

이제 컴퓨터 또는 안드로이드폰에서 블루투스 장치를 검색해보면 ESP32_SPP 라는 이름의 장치가 보일 것이다.


ESP32_SPP 를 연결해 주면 된다.

그 다음 시리얼 터미널 프로그램으로 가서 해달 포트를 오픈한다. 여기서는 맥이어서 'ESP32_SPP-ESP32_SPP_SER이라는 이름의 시리얼 포트가 된다.


포트를 오픈한 다음 '+' 또는 '-'를 입력해주면 각각 LED(13) turned ON 또는 LED(13) turned OFF가 터미널에 출력되며 ESP32의 13번 핀에 연결되어 있는 LED가 켜지거나 꺼지게 된다.
* 위의 화면에서는 입력된 글자를 확인하기 위해 local echo를 켜 놓았다. 즉 +/-는 사용자가 터미널에서 입력한 글자이고 LED(13) turned ON/OFF는 ESP32가 출력한 글자이다.






2016년 11월 14일 월요일

Simblee BLE module

아두이노 등으로 작품을 만들 때 가장 골치아픈 부분중에 하나가 블루투스 통신이다.  블루투스 통신  뿐  아니고 스마트폰으로 무언가를 제어하거나 센서 값을 화면에 표시하려면 아두이노쪽 코드 뿐 아니고 안드로이드 또는 iOS  앱을 따로 만들어 줘야만 한다.
하지만 simblee는 이 문제를 다른 방법으로 접근해 간단하게 해결했다.

디바이스 코드 뿐 아니고 스마트폰에 표시될 UI  관련 코드까지 아두이노 UI에서 한번애  다 작성할 수 있게 만들어 버렸다.  즉 스마트폰 화면에 표시할 UI를 simblee에서 직접 보내주고,  스마트폰에서 이벤트가 발생(버튼 클릭 등)하면 그 이벤트에 대한 처리 코드 역시 simblee에 들어있다.



스마트폰은 일종의 웹 브라우져같이  동작해  스마트폰에서 Simblee for mobile앱을 실행시켜 놓으면 웹서버(즉 여기서는 simblee)에서 웹페이지 내용(여기서는 UI  화면)을 받아 화면에 표시해주고 사용자가 버튼이나 링크를 클릭하는 등의 이벤트가 생기면 웹 서버(여기서는 simblee)에 그 이벤트를 전달해 정해진 동작을 처리하게 한다.

그래서 아두이노 스케치에는 기본적으로 setup(), loop() 이렇게 두개의 함수가 있어야만 하는데 simblee  앱에서는 setup(), loop() 외에 추가로 ui(), ui_event() 함수가 있어야 한다.  Simblee는  자신의 정보를 advertise하고 있다가 스마트폰의 Simblee  for  mobile  앱과 연결되면 ui()  자동으로 ui()  함수가 실행되게 된다.  ui()  함수에서 아래와 같이 스마트폰 화면에 표시될 ui  정보를 보내주게 된다.

void ui()
{
  SimbleeForMobile.beginScreen(WHITE,PORTRAIT);
  SimbleeForMobile.drawSwitch(135, 100);
  SimbleeForMobile.endScreen();
}

UI  정보가 스마트폰으로 전송되면 스마트폰 앱 화면에 다음과 같이 수신된 UI가 표시된다.


사용자가 스위치를 토글하면 이벤트가 발생되어 그 이벤트 정보가 simblee로 전달된다.  Simblee는 이벤트를 받으면 자동으로 ui_event()  함수를 호출해 이벤트에 대한 처리를 수행하게 된다.

#include <SimbleeForMobile.h>

uint_8 switch;

void setup()
{
  Serial.begin(9600);
  SimbleeForMobile.deviceName = "Switch";  // SimbleeForMobile  앱에서 'Switch'라는 이름으로 검색됨
  SimbleeForMobile.begin();
}

void loop()
{
    SimbleeForMobile.process();
}

void ui()
{
  SimbleeForMobile.beginScreen(WHITE, PORTRAIT);
  switch = SimbleeForMobile.drawSwitch(135,100);
  SimbleeForMobile.endScreen();
}


void ui_event(event_t &event)
{
  if (event.id == switch) {
    Serial.println(event.value);
  }
}

위의 코드를 Simblee에 다운로드 하고 스마트폰에서 SimbleeForMobile앱을 실행해 'switch'라는 이름의디바이스를 선택하면 위와 같은 화면이 나오고 스위치를 토글하면 아래와 같이 시리얼 포트로 값이 변화하는걸  볼 수 있다.


 좌표계는 아래  그림처럼 좌측 상단이 (0, 0)이 된다.


 Simblee에 연결되는 디바이스마다 화면 크기는 달라진다.  아이폰 5의 경우 폭은 320픽셀,  높이는 570픽셀이 된다.  각 디바이스의 화면 크기는 스마트폰에 연결되면 SimbleeForMobile.screenWidth 과 SimbleeForMobile.screenHeight 에 자동으로 값이 설정된다.




2016년 9월 7일 수요일

micro:bit 설정하기 (Set up micro:bit)

먼저 스마트폰의 micro:bit 엡을 실행시킨다.


'Connections' 버튼을 선택한다.


기존에 페어링 된 micro:bit이 있으면 가장 최근에 사용된 micro:bit의 이름이 'Most recently used micro:bit' 에 나타날텐데 여기서는 처음 실행했기 때문에 빈 칸이다. 여기서 아래쪽의 노란색 'Pair a new micro:bit'을 선택해 준다.


그러면 어떻게 해야 하는지 알려주는 위와 같은 화면이 나온다.  위의 그림처럼 micro:bit의 'A', 'B' 버튼을 동시에 누르고 있는 상태에서 'RESET' 버튼을 눌렀다가 떼 준다. 그리고 화면에서 녹색 'Next' 버튼을 누른다.


위와 같은 화면이 나오게 된다. 저 위의 가로, 세로 5칸씩의 흰색 상자에 micro:bit 보드에 불빛과 동일하게 코드를 넣어주면 된다.


A, B 버튼을 누르고 있는 상태에서 리셋 버튼을 눌렀다가 놓으면 micro:bit 보드에 위와 같이 불빛이 들어오게 된다. 저 불빛 모양은 랜덤이라 매번 바뀐다.


 micro:bit에  불빛이 켜진 모양대로 흰색 박스를 빨간색으로 만들어 주고 'Next' 버튼을 눌러준다.

 

이제 페어링 할 준비가 된 것이다. 'Next' 버튼을 누르면 스마트폰과 micro:bit간에 페어링이 진행된다.


먼저 micro:bit을 검색한다.
 

원하는 micro:bit을 찾으면 페어링을 위한 코드를 물어본다. 여기서 micro:bit의 'A' 버튼을 누르면 6자리 숫자 코드가 LED에 표시되게 되는데 그 숫자를 넣어주고'Pair' 버튼을 눌러준다.


 위의 동영상을 참조하면 된다.




페어링이 성공화면 micro:bit와 스마트폰 화면은 각각 위의 사긴과 같이 바뀌게 된다.


WiFi & Bluetooth를 모두 지원하는 ESP-3212 발표

ESP-8266을 만든 Espressif사에서 ESP-3212 모듈을 새로 발표했다.

위의 사진처럼 크기나 외형은 ESP-8266과 별 차이가 없지만 가장 큰 차이점은 WiFi뿐 아니고 Bluetooth까지 포함되었다는 점이다.

내부 구조는 위의 그림과 같다.

프로세서는 Xtensa의 32-bit LX6 듀얼코어를 사용하고 있고 롬은 448KB, SRAM은 520KB이고 그와 별도로 RTC에 16KB의 SRAM이 더 들어 있다.

블루투스는 Bluetooth v4.2 BR/EDR, BLE를 모두 지원하고 별도의 외부 앰프 없이 class 1/2/3가 모두 가능하다.

Peripheral도 매우 다양하게 가지고 있다. 특히 ESP-8266에서 가장 아쉬웠던 1채널의 ADC가 18채널로 확장되었고 8-bit DAC도 2채널이 추가되었다. 그리고 심지어 CAN2.0까지 지원해 매우 저가의 OBD-II 장비도 쉽게 구현이 가능하다.
  •       • 12-bit SAR ADC up to 18 channels
  •       • 2 × 8-bit D/A converters
  •       • 10 × touch sensors
  •       • Temperature sensor
  •       • 4 × SPI, 2 × I2S, 2 × I2C, 3 × UART
  •       • 1 host (SD/eMMC/SDIO), 1 slave (SDIO/SPI)
  •       • Ethernet MAC interface with dedicated DMA and IEEE 1588 suppor
  •       • CAN 2.0
  •       • IR (TX/RX)
  •       • Motor PWM, LED PWM up to 16 channels
  •       • Hall sensor
  •       • Ultra low power analog pre-amplifier
IoT 장비에 가장 중요한 요소중에 하나인 보안 문제를 위해서도 다양한 하드웨어 가속기를 추가했다.
 
  • AES-HASH(SHA-2) library - RSA-ECC-RNG



이 정도면 IoT 디바이스를 위한 프로세서 모듈로는 거의 완전체에 가까워 진거 같다.

Pinout은 다음과 같다.

현재 SeeedStudio에서 개당 $6.95에 판매되고 있고 알리에서는 아직 올라오지 않았는데 조만간 알리에서 판매가 시작되면 더 저렴한 가격에 구할 수 있을거 같다.

https://www.seeedstudio.com/ESP3212-Wifi-Bluetooth-Combo-Module-p-2706.html






2015년 2월 10일 화요일

Beacon의 이해



비이컨 기술의 가장 기본적인 사용법은 모바일 디바이스에서 비이컨까지의 거리를 측정하는 것이다. 하지만 비이컨으로 거리를 측정하는걸 해 본 사람들은 누구나 알고 있는 것처럼 거리 추정은 상당히 오차가 크다. 5미터 떨어진 비이컨의 경우 추정 거리는 2미터에서 10미터까지 왔다갔다 한다. 

이렇게 추정 거리가 변하는 이유와 이런 오차를 줄이기 위한 방법은 비이컨에 관해 가장 흔한 질문이다. 추정에 영향을 미치는 요인은 전파 신호의 난반사, 장애물, 휴대폰과 비이컨의 방향등 매우 다양하다. 

하지만 거리 추정에 무었보다 가장 큰 요인은 전파 노이즈이다. 백그라운드 전파 노이즈는 어디에건 존재한다. 강한 전파(즉, SNR이 큰)의 경우 약한전파보다 노이즈는 별로 문제가 되지 않는다. 이런 이유 때문에 비이컨에서 10미터 이상 떨어진 경우보다는 가까운 거리에서는 좀 더 정확한 거리 추정이 가능하다. 

Apple의 권장사항




애플이 iOS7에서 iBeacon 기술을 소개했을 때, 애플의 문서는 거리 추정치를 직접 사용하지 않는걸 권장했다. 비이컨 범위 정보를 제공하는 CLBeacon 클래스는 비이컨과의 거리 추정치를 미터 단위로 제공하는 필드를 가지고 있다. 하지만 이 속성을 distance라고 부르는 대신 애플은 accuracy라고 이름붙였다. 권장하는 사용법은 이 값을 여러 비이컨들 중에 어느것이 가장 가까운가 비교하는 용도로만 사용하는 것이다. 또한 CLBeacon 클래스는 proximity라는 속성을 제공해 거리 추정치를 “immediate”, “near”, “far”로 그룹핑 한다. 이 각 그룹의 정의는 명확하지 않지만, 실험 결과 0.5미터 이내의 거리는 “immediate”, 0.5~3m 정도는 “near”, 그 이상은 “far”로 구분한다고 볼 수 있다.



이런 내용이 비이컨을 사용해 직접적으로 거리를 측정할 수 없다는걸 의미하지는 않는다. 단지 비이컨의 동작 원리와 결과값의 품질에 어떤 한계가 있는지를 먼저 이해할 필요가 있다는걸 의미한다.

Reference Transmitter Power


비이컨 전송은 transmitter power 필드를 포함하고 있어 특정 거리에서 신호 세기가 얼마의 세기가 되어야 하는가를 나타낸다. 예를들어 iBeacon 기술을 사용할 때, 표준 측정값은 비이컨에서 1미터 떨어진 곳에서 iPhone 5S(iOS7이 발표되었을 때 최신 모델)이 측정한 것이다. 비이컨은 표준거리에서 신호레벨(RSSI)을 측정한 후 비이컨이 표준값을 송신하도록 calibrate되어야만 한다.  RSSI 값은 dBm 단위를 사용하고 1미터 거리에서 calibrate 된 비이컨의 통상 RSSI 값은 -59 dBm이다. 각 송신기와 안테나는 서로 다른 세기의 전파를 송신하기 때문에 여러 비이컨의 실제 calibration 값은 서로 다르다. Radius Network의 RadBeacon같은 일부 제품은 출력파워를 조정할 수 있다.

How distance estimates work


모바일 디바이스는 비이컨의 신호레벨을 레퍼런스 신호레벨과 비교함으로서 비이컨과의 거리를 추정할 수 있다. 비이컨이 adv한 패킷이 수신될 때 마다 블루투스 칩은 비이컨의 신호레벨 측정값을 RSSI로 제공한다. 각 비이컨 전송은 위에서 언급한 calibration 값을 포함하고 있기 때문에, 실제 시그널 레벨을 1머터에서 기대되는 시그널 레벨과 비교해서 거리를 추정할 수 있다. 예를들어 비이컨 adv 패킷이 -65 dBm 시그널 레벨로 수신되었고 송신기의 출력 calibration값은 -59 dBm이라고 해 보자. -65 dBm은 -59dBm보다 약한 신호레벨이므로, 즉 비이컨은 1미터보다 먼 거리에 있을 가능성이 크다는걸 의미한다.

거리를 추정하기 위해 이 두 숫자를 공식에 집어넣을 수 있다. 아래 공식은 Android Beacon Library에 사용한 것이다. 공식의 3개의 상수(0.89976, 7.7095, 0.111)는 여러 정해진 거리에서 넥서스4를 사용해 측정한 신호 세기에 기반해 best fit으로 계산한 값이다. 


protected static double calculateDistance(int txPower, double rssi) {
  if (rssi == 0) {
    return -1.0; // if we cannot determine distance, return -1.
  }

  double ratio = rssi*1.0/txPower;
  if (ratio < 1.0) {
    return Math.pow(ratio,10);
  }
  else {
    double accuracy =  (0.89976)*Math.pow(ratio,7.7095) + 0.111;    
    return accuracy;
  }
} 


위의 예제의 경우 txPower에 -65를, rssi에 -59를 넣으면 거리 추정치는 2미터가 된다.

Filtering for noise


신호 노이즈때문에 RSSI 측정치만으로 거리를 추정하는것은 좋은 생각이 아니다. 비이컨 패캣의 RSSI 측정값을 보면 신호 레벨은 여러 곳에서 갑자기 점프하는걸 볼 수 있다. 이 노이즈를 제거하는 가장 간단한 방법은 RSSI 측정치의 running average를 사용해서 노이즈를 부드럽게 변하도록 해 주는 것이다. 또한 데이터 셋에서 이상하게 높거나, 이상하게 낮은 값은 제외해 버리는것도 일반적이다. Android Beacon Library에서 사용한 알고리즘은 20초 샘플링 구간 측정치의 상위 및 하위 10%를 버리고 나머지를 평균한다. 

이 방법의 장점은 거리 추정이 좀 더 정확하고 안정적이라는 것이다. 단점은 모바일 디바이스가 움직이면 거리 추정치가 움직인 위치를 정확히 따라잡는데 20초의 시간이 걸린다는 것이다.

20초 샘플링 구간은 iOS에서 사용하는 방법과 유사하다. 아래 그래프는 아이폰4S가 비이컨에서부터 0.5미터 거리에서 3미터로 빠르게 이동했을 때 (빨간선)  CLBeacon 클래스의 accuracy 필드가 어떻게 변하는가를 보여준다. 그래프에서 볼 수 있는것처럼 디바이스가 이동한 후 거리 추정치(파란선)이 안정화되는데 약 20초가 걸린다.


Device Variations


아이폰 4S, 5, 5S, 6 모델들의 블루투스 회로, 안테나, 케이스 디자인은 큰 변동이 없기 때문에 비이컨 거리 추정은 대부분의 iOS 디바이스에서 일관되게 동작한다. 하지만 항상 그런것은 아니다. 아이팟 터치에서의 거리 추정치는 블루투스 신호 수신 감도를 높이기 위해 안테나를 다른 식으로 배치했기 때문에 일반적으로 좀 더 가깝게  추정된다.

디바이스간의 variation은 안드로이드에서 훨씬 더 큰 문제이다. 각 안드로이드 모델은 완전히 다른 블루투스 칩셋, 안테나, 케이스 디자인을 가질 수 있기 때문이다. 이 모든 요인이 신호 수신 레벨에 영향을 미치므로 거리 추정치에도 영향을 미치게 된다. 넥서스4, 넥서스5와 갤럭시S4 모델은 비이컨과 같은 거리에서 상당히 크게 다른 신호 레벨로 받는다. 이런 이유때문에 Radius Networks는 다양한 안드로이드 디바이스에 대해 거리 공식 DB를 구축하기 시작했다.

Setting Expectations


비이컨에서의 거리를 추정하는게 가능하지만 이 측정치는 말 그대로 ‘추정’치라는걸 잊으면 안된다. 디비아스가 비이컨에서 더 멀어질수록, 이 추정치는 점점 더 정확하지 않게 된다. 비이컨에서 20미터 떨어진 디바이스는 거리 추정치에 +-10미터의 오차를 가지게 된다. 폰이 주머니에 들어있는가 여부, 어느 방향으로 놓여있는가, 간판 뒤쪽에 있는가, 또는 많은 사람들 무리에 막혀있는가등에 따라 비이컨과의 거리 추정치는 크게 영향을 받게 된다. 

그러므로 어떤걸 할 수 없는가를 인식하는게 중요하다.

  • 비이컨이 1미터 떨어져 있는지 아니면 10미터 떨어져 있는지는 쉽게 말할 수 있어도, 10미터 떨어져 있는지 아니면 20미터 떨어져 있는지는 말할 수 있을거라고 기대하면 안된다.
  • 노이즈를 제거하기 위해 running average를 사용하기 때문에 사용자가 움직이면 움직임을 거의 리얼타임으로 추정할 수 있을거라고 생각하면 안된다.
  • 비이컨이 있는 방향을 결정할 수 있을거라고 생각하면 안된다. 비이컨은 보통 전방향 송신기이기 때문에 거리를 추정할 수는 있어도 방향은 추정할 수 없다.
  • 비이컨과의 거리를 추정할 수 있다는것이 모바일 디바이스가 방 안에 정확히 어느 위치에 있는지 결정할 수 없다는걸 이해해야 한다. 비이컨이 실내 위치 시스템에서 구성요소로 사용될 수는 있어도 비이컨 거리 추정만으로는 문제를 해결할 수 없다.
  • 몇개의 비이컨으로 삼각측량법을 사용해 간단한 실내 위치 시스템을 만들수 있을거라고 기대하면 안된다. 거리 추정의 정확도는 거리가 멀어질수록 나뻐지기 때문에 실내에서 위치를 알기 위해 삼각측량을 사용하는건 정확한 위치 추정을 할 수 없다.

하지만 비이컨 거리 추정으로 할 수 있는 유용한 어플리케이션도 많다. 예를 들자면

  • 비이컨이 매우 가까워(5미터 이내)질 때 어떤 동작을 시작
  • 수미터 이내에 있어 신호를 수신할 수 있는 여러 비이컨들중에 어느것이 가장 가까운가를 결정하기 
  • 특정 위치를 찾는 사용자에게 거리 피드백을 제공 (예: 보물찾기)

Best Practices


최대한 정확한 거리 추정치를 얻기 위해서 Radius Networks는 다음의 내용을 권장한다.

  • 비이컨에서 가능한 최대 출력의 송신 레벨을 사용한다. 강한 시그널 레벨은 높은 SNR을 의미하기 때문에 좀 더 정확한 거리 추정이 가능하다.
  • 비이컨의 송신 빈도를 최대한 높여준다. 모바일 디바이스에 advertising 패킷이 더 많이 수신될수록, 노이즈를 제거하기 위해 평균해야 하는 샘플이 많아진다. 
  • 가능한 Radius Networks의 RadBeacon USB같이 외부에서 전원을 공급받는 비이컨을 사용한다. 그래야 배터리 수명을 걱정할 필요 없이 가장 고출력과 빠른 송신 빈도로 패킷을 advertising 할 수 있다.
  • 비이컨을 제대로 보정한다.
  • 명확하게 시야에 들어오는 장소에 비이컨을 설치한다. 사람들이 붐비는 장소라면 바닥보다는 높은 곳에 설치하는게 더 좋다.
  • 특정 안드로이드 모델을 위한 앱을 계획하거나 설치하려고 하면 거리 추정 공식이 해당 모델에 최적화 되어 있는가 확인해야 한다. Radius Networks의 Android Beacon Library는 다양한 안드로이드 모델을 위해 확장 가능한 거리 추정 공식 DB를 제공한다. 

원문은 http://developer.radiusnetworks.com/2014/12/04/fundamentals-of-beacon-ranging.html








2015년 2월 5일 목요일

Blue Basic...CC2540/2541을 쉽게 사용하기

Bluetooth Low Energy (BLE)에서 가장 많이 사용되는 칩들중에 하나가 TI의 CC2540/2541이다. 이 SoC에는 BLE관련 회로 뿐 아니고 8051 코어도 같이 들어있어 단순히 BLE 통신용 모듈로서만 사용하는게 아니고 추가로 자신의 어플리케이션 코드를 집어넣어 별도의 추가 프로세서 없이 standalone으로 사용할수도 있다. 


개발을 위한 툴들도 거의 다 무료로 구할 수 있지만 문제는 개발을 위해 공부해야 하는 것이 상당히 많다는 것이다. 



그래서 이 CC2540/2541 환경에서 개발을 쉽게 할 수 있도록 나온것이 Blue Basic이다. Blue Basic은 CC2540/2541에서 실행되는 BASIC 인터프리터로 별도의 추가 툴 없이 쉽게 프로그램을 만들 수가 있다. 

기본적으로 BASIC 언어를 사용하지만 실제 프로그램을 만들려면 블루투스 스택 뿐 아니고 CC254x 칩의 하드웨어들(UART, SPI, I2C, 타이머 등)을 쉽게 사용할 수 있는게 필수적이다. 그래서 이 목적을 위해 BASIC언어를 약간 확장했고, 가능한 최대로 아두이노의 표기를 따르려고 노력했다. 예를들어 P0(0)을 입력으로 사용하려고 하면 아두이노에서 'pinMode(A0, INPUT)' 을 사용하는것 처럼 BASIC 명령 'PINMODE P(0) INPUT' 을 사용하면 된다. 블루투스 키워드는 쉽게 서비스를 만들어 다른 하드웨어에 쉽게 연결할 수 있게 되어 있다. 

간단한 서비스는 다음과 같이 만들 수 있다.

10 ADVERT GENERAL
20 ADVERT "25FB9E91-1616-448D-B5A3-F70A64BDA73A"
30 ADVERT END
40 GATT SERVICE "25FB9E91-1616-448D-B5A3-F70A64BDA73A"
50 GATT CHARACTERISTIC "D8ABBBE7-F10B-4EC3-B781-DBCBD2334400" "On/Off"
60 GATT READ WRITE A ONWRITE GOSUB 200
70 GATT END
80 PINMODE P0(0) OUTPUT
90 GOSUB 200
100 END
200 P0(0) = A
210 RETURN
BASIC을 처음 보는 사람이라고 해도 대강의 내용은 이해가 될 것이다. 물론 설명해야 할 부분은 많이 있지만 기본적으로 한개의 컨트롤을 on/off하는 서비스를 advertise하고, 이 서비스 값을 출력해 외부 장치를 제어한다. 예제 보드에서는 이 출력이 LED에 연결되어 있다.

Blue Basic을 사용하려면 CC254x를 사용한 BLE 모듈의 펌웨어를 교체해야 한다. 모듈은 aliexpress에서 $5~7정도에 구할 수 있고, 펌웨어를 업데이트 하기 위해서는 TI CC Debugger가 필요하다. 


일단 Blue Basic 펌웨어가 올라가면 그 이후는 PC/Mac/iPhone/Android용 콘솔 프로그램을 사용해 코드를 입력하면서 바로 실행시켜 볼 수가 있다.



Blue Basic을 이용해 iBeacon을 만드는 코드 예제이다.

10 // "A Simple iBeacon service"
20 DIM M(5)
30 // "Major (0-65535)"
40 M(0) = 0
41 M(1) = 2
50 // "Minor (0-65535)"
60 M(2) = 0
61 M(3) = 4
70 // "Power"
80 M(4) = 0xC8
90 ADVERT GENERAL
100 ADVERT CUSTOM "FF 4C 00 02 15" "74 27 8B DA B6 44 45 20 8F 0C 72 0E AF 05 99 35" M "00"
110 ADVERT END
120 // SET A NAME IN THE SCAN RESPONSE
130 SCAN NAME "iBeacon"
140 SCAN END
AUTORUN ON

좀 더 상세한 설명은 github를 참조하면 된다.


2015년 1월 30일 금요일

HM-10 iBeacon 제작

이전 포스트(HM-10 Bluetooth 모듈을 iBeacon으로 사용하기)에서 소개한대로 CR2032 배터리를 사용해 소형 iBeacon 모듈을 제작해 보았다.



만능기판 위에 HM-10 모듈을 약간 두께가 있는 양면테입으로 붙여주고 뒷면에 배터리 홀더를 붙여 주었다. 위쪽 사진 우측 상단의 커넥터는 모듈에 명령을 주기 위해 USB-to-Serial 컨버터를 연결하기 위한 것이고 설정이 끝나면 케이블은 분리하고 모듈 자체적으로 동작하게 된다.


제작한 iBeacon의 크기 비교이다. 위의 사진처럼 500원짜리 동전보다 조금 큰 정도의 크기이다. 이렇게 만든 경우 배터리 한개로 대략 55일 정도 동작하게 된다.

커넥터를 연결하고 컴퓨터에서 시리얼 터미널 에뮬레이터를 동작시켜 명령을 내려준다. (통신 파라미터는 9600-N81)


이전 포스트에서 이야기 했던것처럼 명령어 입력이 끝난걸 엔터키로 확인하는게 아니고 타이밍을 가지고 하기 때문에 위와 같이 줄바꿈이 되지 않고 명령어, 응답이 계속 붙어 보이게 된다.

AT+VERR?HMSoft V533AT+RENEWOK+RENEWAT+RESETOK+RESETATOKAT+MARJ0x1234OK+Set:0x1234AT+MINO0xFA01OK+Set:0xFA01AT+ADVI5OK+Set:5AT+NAMEARSVIATOROK+Set:ARSVIATORAT+ADTY3OK+Set:3AT+IBEA1OK+Set:1AT+DELO2OK+DELO2AT+PWRM0OK+Set:0AT+RESETOK+RESET

쉽게 볼 수 있게 색깔로 구분해 놓은 것이다. 빨간색 볼드는 입력한 명령어, 파란색 이태릭체는 모듈의 응답이다. 

명령 입력이 끝났으면 이제 케이블을 분리해도 된다. 

실제로 정상 동작하는지 확인해 보겠다.



 아이폰에서 Locate 앱을 실행시켜 본 결과이다. 디폴트 UUID는 변경하지 않았으므로 Apple AirLocate로 보인다. 모듈에 설정해 준 대로의 Major 0x1234 (십진수로 4660), Minor 0xFA01 (십진수로 64001)를 확인할 수 있다.


Apple AirLocate.... 부분을 클릭하면 상세정보를 볼 수 있다. 


2015년 1월 28일 수요일

HM-10 Bluetooth 모듈을 iBeacon으로 사용하기

Aliexpress등에서 매우 저렴하게 구입할 수 있는 Bluetooth 4.0 Low Energy (BLE) 모듈인 HM-10을 iBeacon으로 사용할 수 있다. 물론 HM-10은 데이터 통신 또는 단독 센서, 디바이스 제어등의 용도로 사용할수도 있지만 여기서는 그것들에 대한 설명은 생략한다. 

HM-10은 TI의 CC2540 또는 CC2541 BLE SoC 기반의 Bluetooth 4.0 모듈이다. 개당 약$6~7 정도의 가격이다. 펌웨어 버젼은 2014년 9월 기준으로 펌웨어 버젼 531이 나와있다.



모듈은 위의 사진에서 볼 수 있는것처럼 매우 작다. 접촉패드 간격은 1.5mm이라 일반 브레드보드나 만능기판등에서 바로 사용하기는 힘들다. 전원에 연결하거나, 모듈을 iBeacon으로 설정하기 위해 PC에 연결된 USB-to-Serial 케이블에 납땜을 할 때 매우 주의해야만 한다. HM-10은 2.0~3.7V에서 동작하고 I/O핀은 3.3V tolerant이다.

Hardware Connections


모듈에 전원을 공급하기 위해 두가닥의 선이 필요하고, USB-to-Serial adapter를 통해 모듈을 설정하기 위해 임시로 3개의 선이 필요하다. 



위의 사진은 모듈이 3개의 NiMH 충전 배터리가 들어있는 배터리 팩(1.2V * 3 = 3.6V) 과 USB-to-Serial adapter에 연결되어 있는걸 보여준다. Arduino를 사용하고 있다면 아마도 이런 류의 adapter를 이미 가지고 있을것이고, 그렇지 않다면 약 $15정도로 구입할 수 있을 것이다. 만일 구입해야 한다면 3.3V/5V 점퍼나 선택 스위치가 있는 것으로 구입하길 권한다. 



HM-10은 평균적으로 약 0.18mA의 전류를 사용한다. 사진의 배터리팩은 약 1800mAh의 용량을 가지고 있으므로 약 10000시간(즉 1년 이상) 지속될 수 있다. 만일 매우 작은 iBeacon을 만든다면 240mAh 용량의 CR2032 코인셀을 사용할 수도 있고, 이 경우 약 55일정도 사용할 수 있다. 



위의 다이어그램은 케이브블을 어떻게 연결해야 하는지 보여준다. 배터리는 모듈의 12(+), 13(-)번 핀에 연결되어 있다. RS232 adapter의 RxD는 1번핀에, TxD는 2번핀에 연결한다. Adapter의 그라운드 핀은 모듈의 14번 핀에 연결한다. 

Using a Terminal Emulator to talk to the HM-10


하드웨어가 준비되었으면 HM-10이 동작하는지 확인할 수 있다. 배터리와 serial adapter가 HM-10에 연결되었으면 adapter의 USB케이블을 PC에 연결한다. 처음으로 adapter를 사용하는 것이면 adapter의 디바이스 드라이버를 설치하도록 요구받을 수도 있다. 대부분의 경우 OS가 자동으로 드라이버를 찾아준다. 

HM-10은 AT 명령셋을 사용하는데 매우 특이한 타이밍을 요구한다. 명령은 CR이나 LF로 끝나는것이 아니고, 명령이 완전히 다 입력된 다음의 매우 짧은 딜레이에 의존한다. 그러므로 arduino 소프트웨어의 시리얼 모니터를 이용하기를 권장한다. 이 글을 읽는 대다수는 arduino IDE가 이미 설치되어 있을것이라고 생각한다.



Tools 메뉴에서 Serial Port를 선택하고 거기에서 자신의 serial adapter에 해당하는 COM 포트를 선택한다. 대부분의 경우 가장 아래쪽의 COM포트이다. 위의 스크린샷에서는 COM3이다. 

그 다음에 Tools 메뉴에서 Serial Monitor를 실행한다. 아래 메뉴에서 “9600 Baud”와 “No line ending”을 선택한다. 이제 HM-10과 이야기 할 수 있다. “AT” 뒤에 엔터키를 타이핑 해 본다. HM-10이 “OK”라고 응답해야 한다. HM-10은 출력하는 내용 뒤에 LF로 끝나지 않기 때문에 모든 응답 메시지는 뒤에 계속 추가된다.



다음으로 HM-10의 펌웨어 버젼을 확인한다. “AT+VERR?”를 입력한다. 최근에 HM-10을 구입했으면 버젼은 526 또는 그 이후 버젼일것이다. 그렇다면 아래의 Firmware Update 부분은 건너 뛰고 iBeacon Configuration을 가도 된다.

Firmware update

펌웨어 업데이트가 필요하면, 먼저 JNHuaMao 사이트에서 적합한 버젼을 다운로드 받아야 한다. 자신이 가지고 있는 HM-10 모듈이 어떤 칩(2540인지 2541인지)을 사용하는가를 확인한다.  초기모듈은 CC2540을 사용했고 신형 모듈은 CC2541을 사용한다. (최근에 구입했다면 대부분은 CC2541을 사용했을 것이다.)


위의 링크에서 펌웨어를 다운받으면 된다. 다운받았으면 압축을 해제해준다. 최소 3개의 파일이 있을 것이다. readme.txt 파일에는 업데이트 하는 설명이 들어있다. .bin으로 끝나는 파일이 업데이트 할 실제 펌웨어이다. 그리고 .exe로 끝나는 실행파일은 펌웨어를 업데이트 해 주는 프로그램이다. 

1. Arduino 시리얼 모니터에서 ‘AT+SBLUP’를 입력해 준다. 그러면 ‘OK+SBLUP’라고 응답할 것이다. 이제 HM-10은 펌웨어 업데이트를 할 준비가 된 것이다.
2. 시리얼 모니터를 종료한다.
3. 펌웨어 업데이트 프로그램을 실행한다. 
4. COM 포트에 HM-10이 연결되어 있는 시리얼 포트 번호를 설정한다.
5. ‘…’ 버튼을 클릭해 다운로드 한 .bin 파일을 선택한다.
6. 마지막으로 ‘Load Image’ 버튼을 클릭한다.
7. 펌웨어 업데이트는 몇분이 걸린다. 업데이트 하는 도중에는 중단하면 안된다. 
8. Verification이 끝나면 ‘Download completed successfully’라는 메시지가 나올 것이다.



이제 업데이트가 끝났으니 펌웨어 업데이트 프로그램을 종료하면 된다.

iBeacon Configuration


HM-10을 iBeacon으로 설정하려면 몇가지 명령을 입력해 줘야 한다. Arduino Serial Monitor 프로그램을 사용해 명령을 입력해 준다. 아래 리스트에서 볼드로 되어 있는 부분이 실제 입력해줘야 하는 명령이고 그 뒷부분은 각 명령이 어떤 동작을 하는지에 대한 설명으로 입력하면 안된다. 각 명령은 “OK …”으로 ack 되어야 한다. 

1.  AT+RENEW       Factory default로 복구
2.  AT+RESET       Reboot
3.  AT             OK를 기다림
4.  AT+MARJ0X1234  Major no.를 0x1234로 설정
5.  AT+MINO0XFA01  Minor no.를 0xfa01로 설정
6.  AT+ADVI5       Advertising interval을 5(546.25 ms)로 설정
7.  AT+NAMEDOPEY   HM-10 모듈 이름을 DOPEY로 설정
8.  AT+ADTY3       non-connectable로 설정 (전원 절약)
9.  AT+IBEA1       iBeacon 모드 활성화
10. AT+DELO2       iBeacon broadcast-only로 설정 (전원 절약)
11. AT+PWRM0       Auto-sleep 활성화. 8에서 0.18mA로 전력소비를 줄여줌
12. AT+RESET       Reboot

위의 명령들을 다 입력했다면 HM-10은 아이폰이나 안드로이드에서 iBeacon으로 보여야 한다. 4~5단계에서 적절한 major와 minor no.를 선택할 수 있다. Major no.는 특정 범위(스토어 또는 빌딩)내에서 동일하고, minor no.가 iBeacon을 유일하게 식별한다. 위의 프로시져는 HM-10의 디폴트 UUID(표준 proximity UUID)는 변경하지 않는다. UUID를 변경하고 싶으면 AT+IBE0, AT+IBE1, AT+IBE2, AT+IBE3 명령을 사용할 수 있다. 16버이트 UUID는 4바이트 단위로 나뉘어 각각은 다른 명령으로 바꿀 수 있다. 아래 테이블은 UUID를 4개의 명령으로 각각 어느 부분을 변경할 수 있는지 보여준다. 



Removing the Programming Cable


HM-10이 정상적으로 iBeacon으로 동작하는게 확인되었으면 serial adapter에 납땜질 된 케이블을 제거하고, 전원 케이블만 연결해 놓으면 된다. 



배터리 팩과 모듈을 보호하기 위해 케이스에 집어넣어 준다.



Simple iBeacon Scan

아이폰이나 안드로이드 폰에서 iBeacon 스캔을 할 수 있는 앱을 실행시켜 본 결과이다. 위와 같이 정상 동작하고 있음을 확인할 수 있다. 단 iBeacon과의 거리는 RSSI값을 가지고 계산한 것이기 때문에 상대적인 거리이지 정확한 거리는 아님을 주의해야 한다. 

Using the HM-10 as an iBeacon Proximity Device


다음의 8개 UUID는 Apple AirLocate에 proximity device로 들어있다. AirLocate를 사용하는 iOS app과 호환성을 보장하기 위해 이 값을 사용한다.




Waking Up the HM-10


HM-10이 auto-sleep 모드로 설정되어 있으면 전원이 들어오거나 리부팅 될 때 빨리 sleep모드로 갈 수 있다. AT+PWRM0 명령을 보낸 뒤에 재시작하면 MH-10은 더이상 AT 명령에 응답하지 않는다. 디바이스를 깨우려면 80글자 이상의 랜덤 알파벳을 보내면 된다. 그러면 모듈이 깨어나 OK+WAKE라고 응답한다. 한동안 디바이스에 명령을 내려야 하면 잠들지 않게 하기 위해 먼저 AT+PWRM1 명령을 보내준다. 명령이 끝나면 전력소비를 줄이기 위해 AT+PWRM0을 보내면 된다. 


To be continued....   HM-10 iBeacon 제작

2014년 6월 4일 수요일

Bluetooth Programming in Android (2/2)

이전 포스트(Bluetooth Programming in Android (1/2))에 이어 이제부터는 실제로 블루투스 디바이스와 연결해 데이터를 보내는 방법에 대해 이야기하겠다.

Profile and UUID


블루투스 표준은 블루투스 디바이스들이 제공하는 기능들에 대한 몇가지 프로파일을 정의하고 있다.

간단하게 말하자면 블루투스 프로파일은 디바이스가 무엇을 할 수 있는가에 대응한다. 예를 들어 블루투스 헤드셋은 오디오 스트림을 어떻게 주고 받고, 페어링 된 휴대폰에 기본적인 명령(응답, 볼륨 조절 등)을 어떻게 보내는가를 정의한 HSP(Handset Service Profile)을 구현한다. 일부 고급 헤드셋은 A2DP(Advanced Audio Distribution Profile)도 구현해서 사용자가 휴대폰에서 스트리밍하는 음악도 고음질 스테레오로 들을 수 있게 해 준다.



연결을 설정할 때, 연결을 시작하는 디바이스는 SDP(Service Discovery Protocol) 프로토콜을 사용해서 상대방 디바이스가 어떤 서비스를 제공하는가, 즉 어떤 프로파일을 구현했는가를 알아낼 수도 있다.

각 서비스는 128비트 숫자 식별자(UUID)를 사용해 정의되어 있다. 일반적으로는 이 식별자의 짧은 형태가 사용된다.

  • 0x00000000-0000-1000-8000-00805f9b34fb같은 128비트 베이스 UUID가 정의되어 있다.
  • 서비스 UUID의 짧은 형태는 앞쪽의 8개 0을 대치한다.
  • 이것이 완전한 서비스 UUID이다.
예를 들어 HSP 서비스의 짧은 형태 UUID는 0x1108이므로 완전한 UUID는 0x00001108-0000-1000-8000-00805f9b34fb가 된다.

SPP


가장 간단하고 임베디드 디바이스와 통신하는데 가장 많이 사용되는 것이 Serial Port Profile(SPP)로 짧은 UUID는 0x1101이다.

이 프로파일은 두 디바이스간 시리얼 링크를 에뮬레이션 한다.

Android


이전 예제에서 스마트폰에 페어링 된 디바이스들을 어떻게 나열하는가를 배웠다. 각 디바이스는 BluetoothDevice 오브젝트의 인스턴스에 대응한다. 이 오브젝트는 통신채널을 열기 위해 두 가지 메소드를 제공한다.

  • createRfcommSocketToServiceRecord(UUID)
  • createInsecureRfcommSocketToServiceRecord(UUID)
두 메소드는 프로파일의 UUID를 요구하고, 첫번째 메소드는 암호화 된 커넥션을 만드는것만 다르다.
메소드가 성공하면 스마트폰과 페어링 된 디바이스간 통신 채널에 대응하는 BluetoothSocket 오브젝트를 리턴한다.

SPP 프로파일을 구현한 디바이스에 어떻게 데이터를 보내는 지 보도록 하자.

먼저 프로파일의 UUID를 정의한다.

UUID SPP_UUID = java.util.UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");

그리고 나서 디바이스와의 통신 채널을 가져온다.

BluetoothSocket btSocket = null;
try {
  btSocket = targetDevice.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
  Toast.makeText(this, "Unable to open a serial socket with the device", Toast.LENGTH_SHORT).show();
}

이 지점은 아직 채널이 열리지 않았으니 connect() 메소드를 사용해 디바이스와 연결한다.

 try {
  btSocket.connect();
} catch (IOException e) {
  Toast.makeText(this, "Unable to connect to the device", Toast.LENGTH_SHORT).show();
}

연결되면 BluetoothSocket 오브젝트는 두 개의 Stream을 제공한다. 하나는 데이터를 보내기 위한 것(OutputStream)이고 나머지는 데이터를 받기 위한 스트림(InputStream)이다. 편하게 사용하기 위해 스트림을 통해 글자들을 쉽게 보낼 수 있게 해 주는 OutputStreamWriter 오브젝트를 사용할 수 있다.

try {
  OutputStreamWriter writer = new OutputStreamWriter(btSocket.getOutputStream());
  writer.write("Hello World!\r\n");
  writer.flush();
} catch (IOException e) {
  Toast.makeText(this, "Unable to send message to the device.", Toast.LENGTH_SHORT).show();
}

StreamWriter는 로컬 버퍼를 가지고 있다. 모든 데이터가 보내졌는지 확실하게 하기 위해 마지막에 flush()를 호출하는걸 잊지 말자.

마지막에 소켓을 닫는걸 잊으면 안된다.

try {
  btSocket.close();
} catch (IOException e) {
  Toast.makeText(this, "Unable to close the connection to the device", Toast.LENGTH_SHORT).show();
}

Say hello to...


이 앱은 첫번째 코드를 확장했다. 소스코드는 역시 저자의 github에서 다운받을 수 있다.
  • 폰에 페어링 된 디바이스를 가져온다.
  • 한 디바이스를 클릭하면 SPP를 사용해 연결한 다음 "Hello World!" 문자열을 보낸다.

앱을 테스트 해 보려면 블루투스가 장착된 PC가 필요하고 incoming connection을 허용하도록 설정 해 줘야 한다.

윈도우 트레이에 있는 블루투스 아이콘 위에서 마우스 오른쪽 버튼을 클릭한 다음 Open Settings를 선택한다.


COM Ports 탭을 선택한 다음 Add...을 클릭한다.


Incoming을 선택한다.


새 시리얼 포트의 이름을 기록해 둔다. 여기서는 COM56 이다.


터미널 에뮬레이터(여기서는 PuTTY를 사용)를 사용해서 시리얼 포트에 연결한다.


모든게 문제 없이 잘 되었으면 스마트폰에서 앱을 실행하고 PC를 클릭하면 앱이 블루투스를 통해 메시지를 보내고 전송 확인 메시지가 표시된다.

그리고 PC를 확인해 보면 전송된 메시지가 화면에 표시된다.





위의 앱을 테스트 해 보면 한가지 작은 문제점을 발견할 수 있었을 것이다. 커넥션이 연결되고 “Hello World” 메시지가 보내질 때 까지 앱의 GUI가 응답하지 않는다. 이유는 간단하다. 대부분의 메소드는 “blocking”을 사용한다. 즉 결과를 얻을 때 까지 (또는 타임아웃이 될 때 까지) 프로세스의 실행을 중단한다.

데이터를 예를 들어 만일 소켓에서 데이터를 가져오기 위해 read() 메소드를 호출하면 읽어 올 데이터가 들어올 때 까지 메소드는 실행을 중단한다.

이 문제를 해결하기 위해서 멀티태스킹 앱, 즉 앱이 다른 프로세스를 가지고 있어 각각이 서로 독립적으로 실행되는 앱을 작성하는 법을 배워야만 한다. 


스레드와 GUI


간단하게 하기 위해 앱은 한개 또는 그 이상의 프로세스(스레드)로 구성될 수 있고, 이 프로세스들은 안드로이드 OS에 의해 병렬로 실행된다. 이전 예제와 같이 간단한 앱은 메인 스레드라 불리는 하나의 스레드만 가지고 있다. 이 스레드는 앱의 GUI를 구성하는 컴포넌트들(텍스트 박스, 이미지, 버튼 등)을 관리한다.

멀티스레드 앱을 작성할 때 고려해야만 하는 첫번째 규칙은 “메인 스레드만이 GUI를 업데이트 할 수 있다”는 것이다.


이 규칙은 종종 프로그래머를 골치아프게 만든다. 별도 스레드가 블루투스 소켓에서 데이터를 받는 때를 생각해보자. 일반적으로 명령을 받으면 그에 따라 GUI를 업데이트 해야 한다…

보통 권장되는 해결책은 메인스레드에게 GUI를 업데이트 해 주도록 요구하는 것이다. 여기서는 AsyncTask 오브젝트를 사용하는 다른 방법을 소개하겠다.

AsyncTask


AsyncTask 오브젝트는 안드로이드에 포함되어 백그라운드에서 실행되면서 앱의 GUI와 상호작용을 해야만 하는 태스크들을 쉽게 관리할 수 있게 해 준다.

장점으로는 일부 메소드는 GUI(메인) 스레드에서 실행되고 나머지는 독립된 전용 스레드에서 실행된다는 것이다.

그러므로 개발자는 인터페이스를 업데이트 하기 위해서는 GUI 스레드에서 실행되는 메소드를 사용하고, (예를 들어, 소켓을 통해 데이터를 전송/수신하는것 같이) 메인 스레드를 블럭하면 안되는 백그라운드 동작은 두번째 스레드에서 실행되게 할 수 있다.


메소드들을 좀 더 자세히 보도록 하겠다.

  • onPreExecution() - GUI - 백그라운드 액티비티를 시작하기 바로 전에 실행. 사용자에게 애니메이션이나 메시지 등으로 요구한 동작이 시작된다는 것을 알려주는데 사용할 수 있음
  • doInBackground() - background - 백그라운드 태스크를 수행하는 메인 메소드
  • publishProgress() - background - 보통 doInBackground()에서 호출되어 테스크가 실행되는 중에 “progress”를 알려주는데 사용
  • onProgressUpdate() - GUI -  pubilshProgress()에 의해 호출되 GUI가 실행의 “progress”를 업데이트 할 수 있게 함
  • onPostExecute() & onCancelled() - GUI -  태스크의 끝에 (테스크가 캔슬될 때) 실행되는 메소드 
  • Android application

이 튜토리얼을 위해 개발한 안드로이드 앱은 블루투스를 통해 데이터를 송수신하는 것이다.

소스코드는 저자의github에서 다운받을 수 있다.

  • 사용자가 툴바에 있는 버튼으로 디바이스와 연결/연결해제를 할 수 있음
  • 사용자가 두 버튼중에 하나를 클릭하면 각각 “BUTTON1”, “BUTTON2” 명령을 보냄
  • 수신한것을 TextView에 표시

블루투스를 통한 통신은 BTAsyncTask라는 AsyncTask를 사용해 수행된다. 이것이 어떻게 동작하는지 확인해보자.

Connection


사용자가 페어링 된 디바이스를 선택하면 앱은 그 디바이스로 소켓을 오픈하고 BTAsyncTask 오브젝트의 새 인스턴스를 만들어 BluetoothAdapter에서 얻은 소켓을 넘겨준다.

그리고 나면 앱은 BTAsyncTask의 doInBackground 메소드를 시작시키는 execute() 메소드를 호출해서, 페어링 된 디바이스에서 새 데이터가 들어오기를 기다린다.



Data In


BTAsyncTask가 새 데이터를 받으면 publishProgress()를 호출하면서 데이터를 넘겨준다. 위에서 본 것 처럼 publishProgress() 메소드는 내부적으로 GUI 스레드레서 실행되고 있는 onProgressUpdate() 메소드를 호출해 수신한 데이터를 가지고 GUI를 업데이트 할 수 있다. 



Data Out


사용자가 버튼을 클릭하면 메인 스레드는 BTAsyncTask의 sendCommand() 메소드를 호출해 해당되는 명령을 보낸다.



데모


안드로이드 앱에 응답하기 위한 간단한 .Net 어플리케이션을 만들었다. 다음은 앱이 어떻게 동작하는가를 보여주는 짧은 비디오이다.





* 이 글은 Luca Dentella의 튜토리얼 시리즈 Android e Bluetooth 를 저자의 승락을 받고 번역한 글입니다. 흔쾌히 허락해 준 저자 Luca에게 감사드리며...



Un enorme grazie a Luca~