Android로 Bluetooth HID 장치(Joystick) 만들기 - 02

첫번째 포스트에서 우리는 Bluetoooth HID 장치를 구현하기 위해 모든 것을 설정했습니다.

해당 소스는 https://github.com/Jung-Max/BleHidJoystick를 참고하시면 됩니다.

앱 다운로드는 https://play.google.com/store/apps/details?id=com.ckbs.blehidjoystick를 참고하세요.

이제 제어 입력을 연결된 장치로 전송하기 만하면됩니다.

설정하는 것보다 훨씬 간단합니다.

Send report

report를 보내기위한 관련 API는 BluetoothHidDevice.sendReport입니다.

입력을 보내는 BluetoothDevice(이전에 연결되어 있어야 함), report ID (report ID를 사용하지 않는 경우 0) 및 실제 report를 가져옵니다.

처음 두 파라미터는 매우 간단합니다. Report 데이터는 report descriptor를 따라야합니다.

예를 들어 HID report descriptor를 살펴 보면 너무 복잡하지 않아야합니다.

Joystick 예제

Joystick의 descriptor를 예로 들겠습니다.

1
2
3
4
0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Game Pad)
(byte) 0xa1, 0x01, // COLLECTION (Application)
(byte) 0xa1, 0x00, // COLLECTION (Physical)

위 예제는 장치가 게임 패드(Joystick)임을 선언하는 상용구입니다.

1
2
3
4
5
6
7
8
0x05, 0x09,        //     USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x04, // USAGE_MAXIMUM (Button 4)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
(byte) 0x95, 0x04, // REPORT_COUNT (4)
(byte) 0x81, 0x02, // INPUT (Data,Var,Abs)

여기에는 4 개의 버튼 세트 (사용 최소 / 최대로 표시)가 설명되어 있습니다.

각각은 (1의 값) 누르거나 (0의 값) 눌러 논리 최대 값 / 최소값을 제공 할 수 있습니다.

각 버튼은 1 비트(보고서 크기)를 차지하며 그 중 4 개(보고서 수)가 있습니다.

입력 명령문은이 블록을 종료합니다.

1
2
3
0x75, 0x04,        //     REPORT_SIZE (4)
(byte) 0x95, 0x01, // REPORT_COUNT (1)
(byte) 0x81, 0x03, // INPUT (Cnst,Var,Abs)

이것은 4 비트의 패딩 (일정)으로 후속 값이 바이트 경계에 정렬되도록합니다.

1
2
3
4
5
6
7
8
0x05, 0x01,        //     USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, (byte) 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
(byte) 0x95, 0x02, // REPORT_COUNT (2)
(byte) 0x81, 0x02, // INPUT (Data,Var,Abs)

X 및 Y 좌표로 설명 된 위치를 가진 조이스틱을 선언합니다.

각 값은 8 비트로 저장되며 그 중 2 개가 있습니다. 이것들은 -127에서 127까지 다양합니다 (1 바이트의 최대 값).

1
2
(byte) 0xc0,       //   END_COLLECTION
(byte) 0xc0 // END_COLLECTION

디스크립터가 완료됩니다.

이를 통해 보고서 형식을 결정할 수 있습니다.

1
2
3
4
byte | bit 7 6 5 4 3 2 1 0
0 [ --pad-- 4 3 2 1 ] - buttons
1 [ X axis ]
2 [ Y axis ]

위 형식에 따라 report를 작성하고 입력이 변경 될 때마다 sendReport()를 보내면 작동합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 private void sendReport() {
// get button state
byte state = 0;
for (int i = 0; i < 4; ++i) {
if ((boolean) buttons[i].getTag(R.id.tag_pressed)) {
state |= (1 << i);
}
}

// get joystick state
Range<Integer> bounds = new Range<>(-127, 127);
int adjX = bounds.clamp((int) ((double) joystick.getTag(R.id.tag_x_pos) * 127));
int adjY = bounds.clamp((int) ((double) joystick.getTag(R.id.tag_y_pos) * -127));

Log.d(TAG, "sendReport(): " + state + " " + adjX + " " + adjY);

for (BluetoothDevice btDev : mBtHidDevice.getConnectedDevices()) {
mBtHidDevice.sendReport(btDev, 0, new byte[]{
state,
(byte) adjX,
(byte) adjY,
});
}
}

다음 포스트는 Joystick의 UI 설정에 관해서 살펴보겠습니다.

공유하기