スマホをPCに接続するとdialogが出て、ストレージ接続しますか? カメラ接続しますか? 充電だけですか? などと用途を訊かれるのはお馴染みだろう.こちらに書いた.
AOAがLinux hostと繋がるためには、一度USB接続して、一旦切断して別のVID/PIDでAndroidを再起動させ、二度目のUSB接続で化物Androidになるのである.
#define MANUFACTURER "bangflat"
#define MODEL "aoatest"
EP番号はスマホのdescriptorから動的に決定するのが作法だけど、ここでは決め打ちにしてる.あらかじめ
こちらでdescriptorを調査した.スマホによって83だったり01だったりするのでスマホに合わせて変更する必要があります.
#define IN 0x81 // end point in
#define OUT 0x02 // end point out
現在使っているスマホのADB debug mode時のVID/PID.
事前調査で知った情報.1度目接続ではこの値である.スマホが変わればPIDは違うと思う.
#define VID 0x18D1 // VID
#define PID 0x4EE7 // PID 1st phase
化物Android接続ではVID/PIDが変わる.AOA仕様のPIDは2D01または2D00と決まっている(と思って差し支えないと言っても過言ではないと思う)
#define ACCESSORY_VID 0x18D1 // VID 2nd phase
#define ACCESSORY_PID 0x2D01 // PID 2nd phase
#define ACCESSORY_PID_ALT 0x2D00 // PID 2nd phase alternative
最初に、化物Android接続を試みる.成功すればBULK通信へjumpする.
handle = libusb_open_device_with_vid_pid(NULL, ACCESSORY_VID, ACCESSORY_PID);
NULLだったら化物Androidではないので、通常の(1度目の)VID/PIDで接続を試みる.
if(handle == NULL)
handle = libusb_open_device_with_vid_pid(NULL, VID, PID);
1度目の接続に成功したら、化物Android接続への移行を試みる.
if( setupAccessory() < 0) { エラー処理は略 }
化物Androidに成れたら、、、BULK通信の開始だ!
while(1){
sprintf(buffer,"bulk transfer test %d----------",N++);
if(libusb_bulk_transfer(handle, OUT, buffer, strlen(buffer),\
&transferred, 0) < 0) {}
}
やってる事は、文字列をチロチロとBULK送信するloopでしかない.
main()はこれだけで終了.
なのだが、1度目接続→化物移行させるsetupAccessory()が混迷している.見ていこう.
スマホがAOAをサポートしているかどうかを、USBのcontrol transferで確認する.
libusb_control_transfer( handle, 0xC0, 51, 0, 0, buf, 2, 0)
control transferはEP0を使って行われ、主にUSB制御に使われる.
C0,51,0,0,2,0 という謎の数列は、AOA独自のコマンドだと思われる.AOAをサポートしているなら2byteで返信せよ、とでも言いたいのだろう.
buf[]に入った返信が非ゼロならAOAサポートしているとの判断をする.
さらにAOA独自の謎コマンドが続く.
bangflat,aoatestのような文字列を照合することによって、hostプログラムと、化物Androidのペアリングを検証している.
6行あるのは6種類の情報でもって化物チェックするためだが、実際にやってみると2つしか照合してなく見える.なので4つは” ”を送ってるだけで済ませた.
libusb_control_transfer(handle,0x40,52,0,0,MANUFACTURER,\
strlen(MANUFACTURER),0)
libusb_control_transfer(handle,0x40,52,0,1,MODEL,strlen(MODEL),0)
libusb_control_transfer(handle,0x40,52,0,2," ",1,0)
libusb_control_transfer(handle,0x40,52,0,3," ",1,0)
libusb_control_transfer(handle,0x40,52,0,4," ",1,0)
libusb_control_transfer(handle,0x40,52,0,5," ",1,0)
とりあえず6種の照合データを送信して、結果は知らないままで、スマホに次の命令を送る.命令:化物になって再起動せよ!
libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0)
化物Androidが再接続してくる事を期して、hostは一旦USB接続を切断する.
libusb_close(handle); // close 1st phase handler
化物AndroidのためのVID/PIDで接続を試みる.5回やる.
handle = libusb_open_device_with_vid_pid(NULL, ACCESSORY_VID, ACCESSORY_PID);
化物Androidが繋がったら、Interface0をセレクト.
libusb_claim_interface(handle, 0)
以上で化物Androidとの通信ができるようになった.BULK通信も可能なはずだ.
【スマホのアプリ】
readボタンを押す度にBULK受信し、受信内容が表示されるというもの.
project folder詰め合わせ(Kotlin)を
こちらに置いとく.使っているAndroid Studioのversionはこれ.
MainActivity.ktのonCreate()で、ボタンが押されたらUSBをrecieve()して表示するだけ.
IDreadBTN.setOnClickListener {
try {
val rmsg: String = usbDriver!!.receive()
IDreadTXT.setText(rmsg)
}
}
これのキモの部分はusbDriver.receive()ですが、定義はこうなってる.usbInが気になる.
fun receive(): String {
val buff = ByteArray(1024)
val len = usbIn!!.read(buff)
return String(buff)
}
usbInの正体はこうなってる.つまりOS直結部分ではusbInはただのfile streamになっていて、usbIn.readすればシーケンシャルに受信dataがポロポロと吐き出されるみたいだ.ならばこれを呼び出すのは誰なのか?
fun openAccessory(accessory: UsbAccessory?) {
fileDescriptor = usbManager.openAccessory(accessory)
val fd = fileDescriptor!!.fileDescriptor
usbIn = FileInputStream(fd)
}
openAccessory()を呼び出すのは、元を辿ればonReceive()だ.つまり、USBから受信した時、Intentの中にどのUsbAccessoryなのかの情報が含まれており、それをopenAccessory()に与えることでusbInに紐づける仕組み.
fun onReceive(context: Context, intent: Intent) {
open(intent)
}
fun open(intent: Intent) {
val accessory = intent...... as UsbAccessory?
driver.openAccessory(accessory)
}
判ってしまえばそんなもんかだけど、こんなのスクラッチから書けるわけがないわー
ーーーー
ともあれこれで、hostから任意の波形データをスマホに送信するルートは確保できた.
次は波形を描画させてみるかね?
かしこ