aoa2.0を実装してみた
DESCRIPTION
ADK勉強会(東京) BootCamp#2で発表した、AOA2.0実装のお話。ABC2012東北やABC2013Sで展示したもの。TRANSCRIPT
AOA2.0を実装してみた(USB編)
ADK勉強会(東京) BootCamp#22012/10/13
Yuuichi Akagawa
自己紹介
Yuuichi Akagawa (あかがわ ゆういち)– C言語と同い年
本業は某SI企業でインフラ担当
ADKで何かを作るのではなくて、ADKをいろんなマイコンに実装するのがマイブーム
Androidアプリはあんまり作れませんJavaが嫌いなの(ゝω・)
Copyright © 2012 Yuuichi Akagawa 1
今日語る内容
ADK 2012ボードについては語りません。
あくまでもADK2(AOA2.0)に関する部分だけ。
しかもUSBだけ。Bluetoothはナシよ。
Copyright © 2012 Yuuichi Akagawa 2
改めて、ADKとは
Android Open Accessory Development Kit
Android Open Accessoryのリファレンス実装
Android側はUSB Accessory APIを利用
アクセサリ側は Android Open Accessory protocol(AOA)を実装
でもまあ、メンドクサイからもろもろADKということで
Copyright © 2012 Yuuichi Akagawa 3
ADK 2011 / AOA1.0昨年5月のGoogle I/Oで発表されたADKはADK2011 / AOA1.0と呼ぶことになった
マイコンボードはArduino Mega 2560ベース
現時点でADKと呼ばれているものは、ほぼ全てこれ
アクセサリ側がUSBホストとして実装され、USB接続により通信と給電機能が提供される
Copyright © 2012 Yuuichi Akagawa 4
ADK 2012 / AOA2.0 (通称ADK2)
今年6月のGoogle I/Oで発表されたADKはADK2012 / AOA2.0。Android4.1以降で対応
マイコンボードはArduino Dueベース(Cortex‐M3)
新機能
– ADK connection over Bluetooth– USB Audio / Bluetooth Audio(A2DP)– HID
Copyright © 2012 Yuuichi Akagawa 5
ADK2012に関する詳しい情報
@magoroku15さんが横浜Android PF部で発表してます。非常に詳しく解析されています。
回路図やソースコードから解析を進めるアプローチ。必見。Copyright © 2012 Yuuichi Akagawa 6
http://www.slideshare.net/magoroku15/adk2012
ぼくのアプローチ
仕様から攻めます– http://developer.android.com/tools/adk/aoa2.html
そして、動かしながらUSBアナライザで観察
Copyright © 2012 Yuuichi Akagawa 7
ぼくのアプローチ
使うマイコンは
– Arduino UNO + USB Host Shield– GR‐SAKURA
Copyright © 2012 Yuuichi Akagawa 8
Copyright © 2012 Yuuichi Akagawa 9
AOA1.0からの変更点
AOA2.0
AOA1.0とAOA2.0
AOA2.0はAOA1.0の上位互換。USB接続のAccessoryモードという点では同じ。
10Copyright © 2012 Yuuichi Akagawa
Accessory API
AOA1.0
BluetoothUSB
A2DP HIDAudio Play HIDRFCOMM
ADK2012
※ADK over BTはAOAに規定されていない。実際にはAccessoryではない。
コントロール転送一覧
request description
51 (0x33) AOAプロトコルバージョン取得
52(0x34) アクセサリ識別文字列送信
53(0x35) アクセサリモード切り替え
54(0x36) HID デバイスの登録
55(0x37) HIDデバイスの登録解除
56(0x38) HID report descriptorの送信
57(0x39) HID Reportの送信
58(0x40) Audioモードの設定
11Copyright © 2012 Yuuichi Akagawa
AOA2.0では新たに5つ追加
USB Product ID
AOA Protocol Version Product ID Support function
AOA 1.0 0x2D00 accessory
0x2D01 accessory + adb
AOA 2.0 0x2D02 audio
0x2D03 audio + adb
0x2D04 accessory + audio
0x2D05 accessory + audio + adb
Copyright © 2012 Yuuichi Akagawa 12
機能の追加によりProduct IDが追加された
Copyright © 2012 Yuuichi Akagawa 13
Protocol Version
2を返すようになった
フィールド 値
bmRequestType 0b11100000 ・デバイス→ホスト・リクエストタイプ:ベンダ・受信:デバイス
bRequest 51 (0x33)
wValue 0
wIndex 0
wLength 2
デバイスリクエスト
レスポンス
‐ 非対応(STALL応答)
0x0001 AOA1.0
0x0002 AOA2.0 (Android 4.1以上)
Copyright © 2012 Yuuichi Akagawa 14
Protocol Version
古いADK実装だと、JB端末が接続出来ない問題
if (protocol == 1) {Serial.print("device supports protcol 1¥n");
} else {Serial.print("could not read device protocol version¥n");return false;
}
ADK_release_0512
残念!
Microchipのライブラリ等も、古いものは同じような実装になっていたらしい。
if (protocol >= 1) {Serial.print("device supports protocol 1 or higher¥n");
} else {Serial.print("could not read device protocol version¥n");return false;
}
ADK_release_20120606Google I/O前にこっそり修正されていた
Copyright © 2012 Yuuichi Akagawa 15
Protocol Version
ちなみにYaoadkは、6/23に取り込み済み
GR‐SAKURA版は 初から1以上で判定するよう作っておいた
STM32F4‐Discovery版は…直してない (゚o゚;
//get protocolunsigned short protocol = ‐1;protocol = getProtocol();if(protocol < 1 ){tkusbh_disconnect(TIMEOUT_INFINITE);return false;
}#ifdef DEBUGprintf("ADK supportd.(%d)¥n", protocol);
#endif
ACCESSORY_SEND_STRING
アクセサリ識別文字列は変更なし
AOA2.0ではmanufacturerとmodelを省略すると、接続してもアプリを起動をしない
string ID 値 備考
0 manufacturer name accessory_filterマッチング対象
1 model name accessory_filterマッチング対象
2 description 接続時のダイアログに表示される
3 version accessory_filterマッチング対象
4 URI 対応するアプリがインストールされていない場合、当該のURIをブラウザで開く
5 serial number仕様上はそれぞれ256バイトまで
16Copyright © 2012 Yuuichi Akagawa
アプリ自動起動抑止
前述の通りAOA2.0では、以下の2つを送信しないと、アプリ自動起動を抑止できる
manufacturer namemodel name
ただし、これを行うとAccessoryとしては認識しない。Audioモードで使用することが前提→ USB PID=0x2D02 or 0x2D03が返される
Copyright © 2012 Yuuichi Akagawa 17
HIDサポート
Androidアプリは不要
Audio Dockの制御ボタン等を実装可能
もちろん、キーボードやマウスの実装も可能
複数のHIDデバイスを設定可能
本物のHIDと異なり、レポートデータはコントロール転送で行う
AudioやAccessoryとの併用を想定
HID単体ならAndroid側のUSBホスト機能で十分
18Copyright © 2012 Yuuichi Akagawa
ACCESSORY_REGISTER_HIDHIDデバイスの登録
ID番号を指定することで、複数のHIDデバイスを登録することができる
任意のタイミングで実行可能フィールド 値
bmRequestType 0b01100000 ・ホスト→デバイス・リクエストタイプ:ベンダ
bRequest 54 (0x36)
wValue HIDとして登録するID番号
wIndex HID report descriptorのサイズ
Data なし
19Copyright © 2012 Yuuichi Akagawa
ACCESSORY_UNREGISTER_HIDHIDデバイスの登録を解除
任意のタイミングで実行可能
登録していないIDを指定した場合はSTALLが返る
フィールド 値
bmRequestType 0b01100000 ・ホスト→デバイス・リクエストタイプ:ベンダ
bRequest 55 (0x37)
wValue 登録解除したいHIDのID番号
wIndex 0
Data なし
20Copyright © 2012 Yuuichi Akagawa
ACCESSORY_SET_HID_REPORT_DESCHID Report Descriptorを登録する
任意のタイミングで実行可能
登録していないIDを指定した場合はSTALLが返るフィールド 値
bmRequestType 0b01100000 ・ホスト→デバイス・リクエストタイプ:ベンダ
bRequest 56 (0x38)
wValue 登録するHIDのID番号
wIndex ディスクリプタのサイズがエンドポイントのパケットサイズより大きい場合には分割して送信する必要があるため、そのときのインデックス番号を指定する(0スタート)。1パケットで収まる場合は0を指定する。
Data HID Report Descriptor 21Copyright © 2012 Yuuichi Akagawa
ACCESSORY_SEND_HID_EVENTHID Reportデータを送信する
任意のタイミングで実行可能
エラーの場合はSTALLが返る(IDやReport Descriptorが未登録など)
フィールド 値
bmRequestType 0b01100000 ・ホスト→デバイス・リクエストタイプ:ベンダ
bRequest 57 (0x39)
wValue HIDのID番号
wIndex 0
Data HID Reportデータ
22Copyright © 2012 Yuuichi Akagawa
HID実装例
JoyStickをマウスとして動作させてみた
このレベルならArduinoでも楽勝
ソースはこちらで公開中https://github.com/YuuichiAkagawa/Arduino‐AOA2
Copyright © 2012 Yuuichi Akagawa 23
Audioサポート
いわゆるUSB Audio
現時点ではPCM 2ch 16bit 44.1kHzをサポート
Accessoryとは無関係なのでアプリ開発は不要
Android標準のPlayerで音楽再生すると、USB Audio Classに準じたデータがアイソクロナス転
送で送られてくるので、マイコン側でタイミング取って再生すれば良い。
24Copyright © 2012 Yuuichi Akagawa
Audioサポート
ACCESSORY_STARTの前に実行する
AOA2.0のサポート範囲はここまで
フィールド 値
bmRequestType 0b01100000 ・ホスト→デバイス・リクエストタイプ:ベンダ
bRequest 58 (0x40)
wValue 0 : none (デフォルト)1 : PCM 2ch 16bit 44.1kHz
wIndex 0
Data なし
25Copyright © 2012 Yuuichi Akagawa
Audioサポート
Accessoryに切替後、アイソクロナスINトランザクションを発行すると、データが送られてくる
端末側をミュートにしていると、USBに All ‘0’のデータが流れてくる。音量設定には影響されない。(Nexus [email protected]の場合)
26Copyright © 2012 Yuuichi Akagawa
Audioサポート
Interface Descriptor
bLength 9
bDescriptorType INTERFACE
bInterfaceNumber 2
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass Audio
bInterfaceSubClass Audio streaming
bInterfaceProtocol Undefined
iInterface None
27Copyright © 2012 Yuuichi Akagawa
Audio AS Descriptor
bLength 7
bDescriptorType CS_INTERFACE
bDescriptorSubtype AS_GENERAL
bTerminalLink 0x01
bDelay 1
wFormatTag 0x0001
Audio AS Descriptor
bLength 11
bDescriptorType CS_INTERFACE
bDescriptorSubtype FORMAT_TYPE
bFormatType FORMAT_TYPE_I
bNrChannels 2
bSubframeSize 2
bBitResolution 16
bSamFreqType 1
tSamFreq[1] 44100 Hz
Endpoint Descriptor
bLength 9
bDescriptorType ENDPOINT
bEndpointAddress 4 IN
bmAttributes.TransferType Isochronous
bmAttributes.SynchronizationType Synchronous
wMaxPacketSize.PacketSize 256
bInterval 1
bSyncAddress 0 OUT
Audio EP Descriptor
bLength 7
bDescriptorType CS_ENDPOINT
bDescriptorSubtype EP_GENERAL
bmAttributes.SamplingFrequency 1
bmAttributes.Pitch 0
bmAttributes.MaxPacketsOnly 0
bLockDelayUnits Milliseconds
wLockDelay 1
Nexus 7 (4.1.1)のディスクリプタ(Audio Interfaceのみ抜粋)
Audioサポート
28Copyright © 2012 Yuuichi Akagawa
1msインターバルでのアイソクロナス転送
2ch x 16bit x 44100÷1000 = 176.4 bytes /packet割り切れないから、176x9 + 180で 1764bytes/10packets
Audio実装例
Android端末で音楽ファイルを再生すると、シールド上のスピーカーから音が出る
シールド上のボタンで再生/停止、次曲、前曲の操作が可能(HID)
Copyright © 2012 Yuuichi Akagawa 29
Audio実装例
回路は超簡単
Copyright © 2012 Yuuichi Akagawa 30
Audio実装例
GR‐SAKURAに実装
標準のUSBホストライブラリではアイソクロナス転送がサポートされていないので自前で実装。(とりあえず受信のみ)
音声再生処理はmituhiromatuura氏のMP3再生ラ
イブラリに含まれるコードを使用させて頂きました。http://homepage3.nifty.com/fpga/gr/
PCMなので受信したデータをそのまま上記ライブラリに渡せば音が出る。
Copyright © 2012 Yuuichi Akagawa 31
Audio実装例
HIDは「Basic Audio Device」
Copyright © 2012 Yuuichi Akagawa 32
/* Basic Audio Device HID Report Descriptor */const byte _hidReportDescriptor[] = {0x05, 0x0c, //USAGE_PAGE (Consumer Devices)0x09, 0x01, //USAGE (Consumer Remote Control)0xa1, 0x01, //COLLECTION (Application)0x85, 0x01, //Report ID (0x01)0x15, 0x00, //LOGICAL_MINIMUM (0)0x25, 0x01, //LOGICAL_MAXIMUM (1)0x75, 0x01, //REPORT_SIZE (1)0x95, 0x01, //REPORT_COUNT(1)0x09, 0xe9, //USAGE (Volume Up)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xea, //USAGE (Volume Down)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xcd, //USAGE (Play/Pause)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xb5, //USAGE (Scan Next Track)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xb6, //USAGE (Scan Previous Track)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xb7, //USAGE (Stop)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xb3, //USAGE (Fast Foward)0x81, 0x02, //INPUT (Data, Var, Abs)0x09, 0xb4, //USAGE (Rewind)0x81, 0x02, //INPUT (Data, Var, Abs)0xc0 //END_COLLECTION
};
Input D7 D6 D5 D4 D3 D2 D1 D0
Byte0 Report ID (0x01)
Byte1 Rewind FastRewind
STOP ScanPrev
ScanNext
Play VolueDown
VolumeUp
Copyright © 2012 Yuuichi Akagawa 33
おまけ~ Bluetooth ~
ADK connection over Bluetooth
Bluetooth経由でAccessoryが利用できる
USBとはイニシエーションの向きが逆
USBはアクセサリからAndroid端末に接続
BluetoothはAndroid端末からアクセサリに接続
全然AOAじゃない。
ADK用のUUIDが割り振られている
1dd35050‐a437‐11e1‐b3dd‐0800200c9a66
SPPのコードを改変すれば作れるのでは?34Copyright © 2012 Yuuichi Akagawa
USB接続とBluetooth接続の違い
Android側のコード例
35Copyright © 2012 Yuuichi Akagawa
mAdapter = BluetoothAdapter.getDefaultAdapter();BluetoothDevice device = mAdapter.getRemoteDevice(address);mSocket = device.createInsecureRfcommSocketToServiceRecord(ADK_UUID);mSocket.connect();
mInStream = mSocket.getInputStream();mOutStream = mSocket.getOutputStream();
mUSBManager = (UsbManager) getSystemService(Context.USB_SERVICE);UsbAccessory acc = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
ParcelFileDescriptor mFD = mUSBManager.openAccessory(acc);if (mFD != null) {FileDescripter fd = mFD.getFileDescriptor();mInStream = new FileInputStream(fd);mOutStream = new FileOutputStream(fd);}
USB
Bluetooth
どちらも接続確立後は、mInStream, mOutStreamを介してアクセスする。
Intent周りは省略
Intentなんて無い
Bluetooth経由のAudioとかHIDとか
Android側の観点では、元々サポートされているBluetoothのプロファイルを使う。
Audio : A2DPHID : HID
ADK2012ボード側でこれらを実装して見せただけなので、AOAとはなんら関係無い。当たり前だけど、iOSデバイスだって繋がる。
ぼくは全然興味ありません。
36Copyright © 2012 Yuuichi Akagawa
Copyright © 2012 Yuuichi Akagawa 37
おしまい