コールバックの引数で文言を変えたい。このときは、仮引数の宣言をfinalにするとよいようだ。スタック渡しだからダメなんだろうと思っていたんだけど、Javaだから「まだ使います」って言っておけばよいということなのかね。これでようやく、BLEの検索結果を戻せるところまで来た。Java[ble]RC-S390は定期的にAdvertisingしているようだ試していて気付いたのだが、RC-S390をAdvertisingにしなくても、ペアリングをしていなくても、スキャンはできているような気がする。いや、そもそもRC-S390は自分で作ってるわけでもないので、どこでAdvertisingになっているかなんてわかるはずもない。思ったのだけど・・・やっぱり、AdvertisingじゃないとCentralはスキャンできないんじゃないかと思う。他に方法がなさそうだから。miniにインストールしているPaSoRiアプリも、RC-S390のボタンを長押ししなくてもペアリングしにいこうとする。そのときNexus7の設定アプリから見えてるかというと、見えない。RC-S390の青LEDが点滅するモードになると、設定アプリから見える。RC-S390の使い方を把握しておこう。ボタンを2秒長押しすると、電源のON/OFFができる。電源がOFFになった・・・通信状態ランプ(青LED)とバッテリー残量ランプ(橙LED)が1秒点灯だ。2秒長押ししてみよう。うん、両LEDが点灯したから、電源OFFだ。再度2秒長押ししたら・・・あれ、また両LEDが点灯したぞ・・・。長く押したら、青LEDが点滅し始め、LightBlueが検出した。一度ペアリングさせないと電源がONにできないという仕様なんだな。LightBlueが反応したので情報を見てみると、ペアリングを要求された。要求はされたのだが、サービス一覧は取得できたみたいだ。このとき、Nexus7の昨日作ったスキャンアプリは検出できなくなっている(PaSoRiは青LED点滅中)。ペアリング要求をキャンセルしても、Nexus7からは検出できない。BlueLightで「PaSoRi」をタップしてDisconnectすると、Nexus7からも見えるようになった。Nexus7からペアリングすると、青LED点滅は消えた。この状態でボタンを2秒長押しすると、両LEDが点灯。一度2秒長押しすると、青LEDが3回点滅。BlueLightでスキャンすると、PaSoRiが見えている。わかったことをまとめようPaSoRiが誰ともペアリングしていない場合、電源のONだけをすることはできないペアリングしていなくて青LED点滅しているとき、誰もConnectしていなければAdvertisingしている誰かがConnectすると、Advertisingしない(当たり前)Connectionするとペアリングの要求を行う。ペアリングしなくてもサービスとキャラクタリスティックの一覧は取得できるみたいだ(まだBLE仕様をわかってない)ペアリングすると、ボタンで電源のON/OFFができるようになる電源OFFのときは、スキャンしても検出できない(当たり前)電源ONにすると、スキャンして検出できる。ことは、ペアリングして電源ONなら、ConnectionしていないときはAdvertisingしてるってことか。それはUndirectedでやっているので、ペアリングしていない人でもスキャンできてしまうのかな。ペアリングしている人にだけAdvertisingする方がよさそうではあるが、別の端末で使いたいときに面倒になるのかな?いや、それなら5秒長押ししたときにだけUndirectedなAdvertisingにすればよさそうなものだが。ここはまだ私が仕様をよくわかっていないせいかもしれんので、わかってから考えよう。いつだかの推測で、相手がいなくてもConnection状態を維持しているのでは?と書いていたが、そうではなく、Connectionしてない間はAdvertisingしているので、それをアプリが捉まえている、という動作なのだろう。(4)さて、Androidでデバイスのスキャンまでできたので、iOSで同じところまでやってみよう。https://github.com/hirokuma/BleTest_iosこっちは、あれこれ参考にさせていただいた。いうのも、iOSアプリのしくみがよくわからんかったからだ。プロジェクト管理に回るっていうのはこういうことなのね・・・という一抹の寂しさを感じる瞬間である。それはいいとして、今回はまったのはここだ。queue:nil];みんな「self」って書いてるけど、型は「id<CBCentralManagerDelegate>」なのだ。ことは、selfと言ってはいるけれども、なんか継承しているはずだ。結果としては、ここを参考にした。<CBCentralManagerDelegate>のような形にして、selfに持たせた。selfじゃなくてもいいんだけど、さっき書いたAndroid版と同じようにしたかったので、なるべく閉じたファイルにしたかったのだな。しくみがわからんかっただけで、今のところ実装量はiOSの方が少ない。思ったが、まだiOS版はスキャンの停止を組み込んでなかった。(3)Androidのサンプルを見ながら作っていたのだが、私が知らない小技があって(というよりも、私が知らなさすぎるだけだが)、もうちょっとシンプルな作りにしたいと思った。結局こちらを参考にさせていただいた。http://blog.fenrir-inc.com/jp/2013/10/bluetooth-le-android.htmlActivityに突っ込んでしまうと、他のアプリを作るときに持ってくるのが面倒になるので、別のクラスを作ってそこにBLE操作関係を置くようにした。https://github.com/hirokuma/BleTest/blob/master/src/com/blogpost/hiro99ma/bleutils/BleUtils.java動かすと、アプリ起動などと同時にスキャンを行う。スキャンしたデバイス名は、logcatに出てくる。うちにはRC-S390しかないのだが、ちゃんと「PaSoRi」が出てきた。サンプルを見ていてよくわからなかったのが、BluetoothAdapter.isEnabled()を2回呼んでいるところ。なんだろう?絶妙なタイミングで呼び出された場合を警戒しているのか?これで、基本的なスキャンのところまではできたんだけど、スキャン結果をコールバックするところが無い。理由は簡単で、やり方を調べていないからだ。(2)Android4.4のUSBデバッグアイコンが、いつも気になる。キットカットなんだろうとは思うけど、なんか、なかなか、ねぇ。チョーク4本いかだお風呂のふた本の背表紙4.4も、最初はKがつくパイの名前だったと思う。Pieが思いつくんだけど、あれはお菓子じゃなくて料理なのかな?では、サンプルソースもあることだし、まねをしながら同じようなアプリを作ってみよう。作りながらメモを書いていくだけなので、途中で間違ってしまう可能性有りだ。した説明は、以下のページがよさそうだった。機器を使うじゃあ書かんでいいやん、と思われるだろうが、勉強の一環だ。Manifestだろう。uses-featureとuses-permissionを追加するようだ。android.hardware.bluetooth_leandroid.permission.BLUETOOTHandroid.permission.BLUETOOTH_ADMINそれぞれ、通信許可と検索許可らしい。いつも思うのだが、uses-permissionはコンボボックスで選択できるのに、uses-featureはテキスト入力なので、うろ覚えで選択ができない。こっちもコンボボックスにしてくれないものか。サンプルではServiceがあるので、そのための記述があるけど、まあ後で考えよう。peripheralのスキャン(の下調べ)まず、対象の機器を探そう。RC-S390はボタンを長押しすると「私はここよ!」みたいなモードになるらしい。これが「Advertising」という状態なんだろう。Interface誌の説明では、Advertisingとかはリンク層の動作らしい。GATTとかのアプリは絡んでこない。Advertising→Connecting、という流れだそうな。Core_V4.0[zip]を見ると、p.2263に状態の一覧らしきものがあった。StandbyAdvertisingScanningInitiatingConnectionまず最初はStandby。Lists、という過程を経ないとadvertising/scanning/initiatingにできなさそうだ。Bでも同じなのかな?どちらかがCentralで、どちらかがPeripheralになると思うのだが。advertising」とあるので、Standby状態から「advertisingになりたい」という要求を受けないと遷移しないのだろう。RC-S390では、そのトリガがボタンの長押しということか。UndirectedとDirectedの2種類があるらしい。PDFのシーケンス図を見ると、Undirectedでは"Advert"が飛んでいるが、Directedだと"LL_DIRECT_IND"が飛んでいる。PDFのp.1639にGAPと機能の必須/オプションみたいな表がある。Profileの略らしいが、もうこの際細かいことはどうでもよい。PeripheralとかCentralという文字が出てきてるので、この表を見ると何かわかりそうな気がする。StandbyはCentralもPeripheralも必須AdvertisingはPeripheral必須ScanningはCentral必須InitiatingもCentral必須Connectionは、CentralはMaster必須、PeripheralはSlave必須ということらしい(MはMandatoryだろうけど、Eはなんだろう。eventってのが必須)。後で出てくるScannningも、Activeは必須(正確にはC1)で、Passiveはオプショナル。(でも「オプショナル」っていいつつ、普通載せるけど、ってことあるしなぁ。)さて、基礎知識を身につけたところで、再挑戦。Standbyは、CentralもPeripheralも実施する。PeripheralはAdvertisingを開始し、CentralはScanningを開始。CentralがScanningしてPeripheralを見つけたら、Initiatingする。Initiatingは、PeripheralとしてはAdvertに対してCONNECT_REQが返ってくる動作に見えるようだ。そこまで含めて"Advertising"ということか。Initiatingが終わると、接続完了ってことで、たぶんConnection状態になるんだと思う。調べるのが面倒なので推測だが、Connection状態になると、「切断」ってやらない限りは接続が切れないようになってるんじゃなかろうか。miniが電源とか切ってても、アプリを起動したらAdvertisingしなくても使えるようになることの説明がつかない。相手がいなかったら切断するってしくみにすることもできるんだろうけど、プロトコルとして制約がないってことなんじゃなかろうか。ほら、NFCのLLCPだと一定時間内に応答がなかったら切断シーケンスに入るから、それとは違うということをいいたいのだよ。脱線したが、スキャン動作は、ペアリングとは別として「必要」ということだ。なくてもよいのか??これもInterface誌にあった。リンク層の接続はAdvertisingとかでやるが、ペアリングはもう少し上の層での認証接続とのことだ。通信する相手が正しいかどうかの確認を行うということか。ペアリングしなくてもRC-S390は見えたが、サービス取得などができなかったということのは、まだ接続してよい相手として認められていなかったからだろう。Interface誌の説明ではペアリングにも4種類あり、自動で承認するタイプもあるんだって。