2015/05/31

[ble]Advertisingまで

SlideShareに、もう1つスライドを追加した。
Advertisingするまでだ。

Nordic nRF51822でBLEしてみました 2

こんな感じですよ、程度なので、詳細はBLEにせよnRF51822にせよ調べ直してもらうことになるだろうが、まあとっかかりになるくらいの資料にはなったんじゃなかろうか。
自分が数ヶ月後に見て「ああ、そういえばそうだった」みたいな資料になればよいのだが。

2015/05/30

[ble]サンプルを動かすまで

ブログを書けないなら書けないなりに、資料でもまとめようかと思った。
が、入門資料はあふれているし、nRF51822はバージョンアップが激しくて数ヶ月も経つと風化どころか役に立たなくなるので、さらっとしたものを作ることにした。

Nordic nRF51822でBLEしてみました

まあ、しっかり書く気力がなかった言い訳なんだけどね。

Windows Live Writeで投稿できなくなった

技術系の話じゃないが、ちょっと困ったことになった。
このブログはBloggerなのだが、いつも使っているWindows Live Writerでの投稿が出来なくなった。

Blogger側の問題かと思っていたのだが、こちらを読むとそうではないようだ。

bloggerでWindows Live Writerが使えなくなりました。[blogger] | ブログ改善のネタ帳

Bloggerの認証が変わったが、Live Writerはそれに対応していないから使えない、ということらしい。
うーむ。

今のままではダメですよ、というのは事前にアナウンスされていたようだ。
まあ、そりゃそうだよな。私が知らんかっただけだ。
OAuth 2 または OpenID Connect への移行期限まであと 1 ヶ月 - Google Developer Japan Blog



画像の埋め込みと、ソースの埋め込みさえ簡単にできれば特にこだわらないのだが、なかなかねぇ。
またZoundry Ravenに戻すか。


Zoundry Ravenでもダメみたいだ。
がーん。
A Tinkerer's Blog: Unable To Access Blogger/Blogspot From Raven/RavenPlus

どうしよう・・・。

あまりここに時間を掛けたくないので、Live Writerが使えるようになるか、他のブログエディタが見つかるまでは更新をお休みしよう。



2015/05/27

[ble]ATTテーブルの参考にSensorTagがよさそうだ

Peripheralは、なんとなくわかった気がする。
Centralも、とりあえずなんとかなりそうな気がする。
じゃあ、作ってみよう!

・・・なんだけど・・・どう作ればいいんだろう?

BLEのインターフェース仕様書にあたるものは、ATTテーブルだろうと思っている。
このアトリビュートは、こんな動作しますよ、というやつだ。
それさえ決めれば、アクセス方法がだいたい決まるだろう。

・・・だが・・・どういうテーブルにするのがよいのだろう?

いや、よいとか悪いとかじゃなくて、どんな感じにするものなのかという基礎がわかってない。
例えるなら、「シュークリームというのは、焼いた薄い皮の中に甘いクリームが入ってますよ」という情報だけを知って、そこから甘い餃子を作ってしまうような感じを避けたいというところだ。
「だいたいシュークリームというのはこんなもの」というのがわかれば、まったく意図しないものになってしまうことだけは避けられるだろう(使い勝手とかは、また別のことだ)。

 

ネットで入手でき、手元に装置もあるATTテーブルとなると、SensorTagのものしか思いつかない。
なので、まずはこれをお手本にしようとしている。
見ただけだと身につかないタイプなので、わざわざExcelに書き写しながら考えたりなど。

2015/05/25

[ble]TxAdd=1はrandom address

SensorTagはBlueZのgatttoolでつながることがわかったので、手持ちのBVMCNDT52(Braveridge社、nRF51822)に載せたアプリで試してみた。
が、connectできず・・・。

しばらく悩んだが、パケットモニタで確認するとわかった。
SensorTagはpublic addressなのだが、私はrandom addressでやってたのだ。
hiro99ma blog: [ble]Device Addressのpublicとrandom

image

上が自作、下がSensorTagだ。
gatttoolはデフォルトでpublicとしてconnectするようになっているので、指定が必要。

[F1:78:92:42:17:BF][LE]> connect F1:78:92:42:17:BF random

これで接続できた。
primaryコマンドでも、自作サービスのUUID(128bit)が載っている。

載っているのだが、ハンドル値の意味がよくわからない。
まあ、ハンドル値はSoftDeviceが返してくるから管理対象ではないのだけど、有効範囲は知っておきたい。
Core_V4.2.pdfのVol.3 Part GにGATTのことが書いてあり、その2.5章 ATTRIBUTE PROTOCOLの2.5.1節に「0x0001~0xFFFF」と書かれていた。
最初が0x0001で、追加するごとにインクリメントしているようだ。

2015/05/17

汝の名はBlueZ - (11) : githubに置いた

BlueZ特集の最後だ。
初回が4月21日だから、1ヶ月近くやってたんだ・・・。

SensorTagに少し対応したgatttoolをgithubに置いた。
確認環境は、Raspberry Pi(2011.12) + BT-Micro4だ。
https://github.com/hirokuma/bluez-gatttool-sensortag

ソースはBlueZのattribフォルダがほぼそのまま。
違うのは、gatttool.cとinteractive.cくらい。
gatttool.cは、引数を打ち込むのが面倒なのでデフォルト値を付けただけ。
主にinteractive.cを変更している。

対応と言っても大したことはしておらず、以下を自動的にやるだけだ。

  • connect
  • primary
  • ボタンとIR TemperatureへのNotify許可
  • ボタンのNotificationを受けたら、ボタンがS2なのかS3なのかをコンソール出力

 

makeは、BlueZ 5.30で行っている。
BlueZのソースファイルからビルドしておかないと、makeできない。
というのも、BlueZのビルド時に生成される内部用ライブラリを2つほど使っているからだ。
makefile自体は、nRF51822で使われているものを流用した。
私はMakefile書くのが上手じゃないし、nRF51822のはクロスコンパイルもセルフコンパイルもどっちでもいけそうなので、テンプレートに仕立てたのだ。

makeすると、"gatttool"ではなく"gatool"ができる。
一応名前を分けておかないと、紛らわしいだろうと思ってね。
実行は、普通のgatttoolと同じようにできる。
引数を省略すると、gatttool.cのmain()に書いたデフォルト値が使われるので、書き換えると良いだろう。
インタラクティブモードで"st"というコマンドを追加していて、これを実行すると上記の自動でやることをやってくれる。

少々だったら、こんな感じで作っていけばCentral側として相手になってくれそうだ。
画面を出したいとか思ったら、やはりAndroidみたいなスマートフォンが手軽になりそうだけど、コンソールにいろいろ出せるとデバッグがしやすいので、これはこれでよいと思うのだよ。

汝の名はBlueZ - (10) : gatttoolをいじる

GLibのイベントループのことを調べたけど、gatttoolで状態を持ってるのは接続のことだけで、primaryとかの非同期コマンドの実行状態などは管理していない。
なので、これが終わったらこれしたい、というようなことをやりたいのであれば、実行状態を持つように書き換えがいる。
追加するのは、コマンドの開始時と、完了コールバックのところになるだろう。

それを全部に対してやるくらいだったら、コールバック関数のところに自分の関数を呼ぶように作り替えてしまえば、わざわざ何も無いときにポーリングするような作りにしなくても済みそうだ。
だが、処理は1箇所にまとめたいので、ポーリングするようにしようかとも思っている。


まずはサンプルとして、TIのSensorTag向けに作ってみよう。
SensorTagはいろいろとセンサーが付いているので、題材として使いやすい。

Characteristicを読んだり書いたりするだけだったら、別にコードを作り込まずともコマンドを入力すれば良い。
今回の目指すところは、こんなところにしよう。

  • ボタンを押したらNotifyを受け取り、押されたのがS2かS3かをコンソールに出力する
  • インタラクティブモードで起動し、開始コマンド(自作)を打ち込んだら、後は勝手にやってくれる

たったこれだけ?と思われそうだが、準備運動せずに海に飛び込んではだめなのだ。


connectやCharacteristicへの操作はコマンドを打ち込むが、Notificationはどうなってるのか知らなかった。
調べたところ、受けとったらコンソールに出力されるようだ。
SensorTagで試してみた。0x6CはボタンのNotificationを許可設定するCCCDで、01:00で許可になる。

[34:B1:F7:D4:FA:33][LE]> char-write-req 6c 0100
Characteristic value was written successfully
Notification handle = 0x006b value: 01
Notification handle = 0x006b value: 00

この辺を受け付けられるところがGLibを使った強みか。
受けとっているのは、interactive.cのevents_handler()。
コンソール出力からソースをgrepできるのがありがたい。

events_handler()は、connectが完了したコールバックで登録されている。
なので、connectの動作をgatttoolのルートでやってしまうなら、そのまま流用できる。
ただ、Characteristic操作と違って開始-終了がCentral側ではわからず通知だけになるので、ここはコールバック時に処理をした方がよいだろう。

2015/05/16

GLibのイベントループ

BlueZのgatttoolを変更して、Central側の動作確認ツールを作ろうとしている。
まずはconnectさせて、connectしたらprimaryを見るだけのところを作っているのだが、これがなかなかうまくいかない。

connect実行後に接続状態を監視するスレッドを作って、本体はjoinで待たせている。
しかし、接続状態が変化しないのだ。
Peripheralは接続が完了しているので、connect自体は動いている。
volatileつけてなかったから最適化されてしまったのかと思ったが、そもそもconnect完了のコールバックが呼ばれていない。

おそらく、joinで待たせているためGLibのイベントループが動かず、コールバックが呼ばれないのだと思っている。
なので、状態監視しているスレッドの中でイベントループを回す関数でも呼び出してやればよいと思うのだが、それに該当するAPIが見つけられていない。

軽く調べておこう。


GLibの本家資料は、たぶんここだろう。
GNUかGNOME。

今回やりたイベントループのことは、ここになるか。
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#glib-The-Main-Event-Loop.description
イベントはファイルディスクリプタとタイムアウトとなっている。
Wikipediaの説明でもそう書いてあるので、そうなんだろう。

なので、今回やりたいような「この変数がこの値になったら」みたいなのはイベントにできなさそうだ。
そういうことをしたければ、自分でfdつくって値の変更タイミングで書込むイベントにするか、タイマで監視するようなしくみにするか・・・。

 

APIを見てると、g_idle_add()というのがあった。
優先度の高いイベントが無いときに呼ばれるそうだ。
試しにやってみると、確かにそういう動きをする。
何かイベントが発生し終わったときに呼ばれるのではなく、アイドル状態だったら呼び出され続けるようだ。
"add"なので、BlueZでアイドル状態を監視するようになっていたとしても追加できる。

g_idle_add()で気になったのは、g_idle_source_new()。
このAPIは呼び出していないのだが、g_idle_add()は使えた。
BlueZをgrepしても出てこないので、たぶん誰も呼び出していないのだが、それでよいのだろうか?

 

こちらを見て気付いたのだが、g_main_context_iteration()を呼ぶことでイベントループを1回だけ回せるようだ。
PyGTKで重い処理をしているときにGUIを固まらせないための手法をまとめる - 試験運用中なLinux備忘録


そういう視点でGLib Referenceを読むと、Descriptionにアイドルのこともシングルなイベントループ呼び出しのことも書いてあった。
英語を読む力が弱いのは課題だな・・・。

callとinvoke

英語の話になるが、callとinvokeの違いがよくわからない。
なんとなく、callだと直接呼び出し、invokeだと別コンテキストから呼び出すような感じを受ける。

invokeの意味 - 英和辞書 - 英語辞書 - goo辞書
たぶんラテン語が語源になってるのだろうが、「上に呼びかける」ということで、お祈りする意味があったようだ。
なので、OSとかフレームワークとかにお願いしておく、みたいなとらえ方で良いのかな。

2015/05/11

[bluez]gatttoolを切り離してビルド

直接BlueZとは関係が無いので、タイトルはいつものとは別にした。

pythonで書こうかと思っていたのだが、gatttoolのコンソール出力を使って判断する、というのがどうもしっくりこない。
ツールが出力するログが変わったら、ソースの修正が必要になるので、そうそう変わるものではないとわかってはいるのだが、やる気が出なくなってしまった。
お仕事だったらあきらめてやるのだけど、せっかく趣味でやってるだけなんだから、やりたくないことはやらないようにしよう。

gatttoolはinteractiveじゃないモードもあるから、それでやるならpythonでもよいかと思ったのだが、1回実行するごとにconnect→操作→disconnect、となるようなので、ちょっと期待と異なる。
connectしたら、しばらくはdisconnectしたくないのだ。
だからinteractiveモードを使うんだろうけど、今回はそれを使いたくない。
だったら、自分で作るしかない。

BlueZのtestディレクトリにpythonで書かれたものがあったが、あれはD-Busを使っているようだ。
D-Busがよくわかっていないから何とも言えないが、軽く調べた範囲ではC言語から使うのはめんどくさそうだ。
じゃあpythonでやろうかとも思ったのだが、Characteristicを操作するようなサンプルがない・・・。
ドキュメントにはgatt-api.txtというのがあり、API仕様っぽいものが書かれているのだけど、D-Busがわかっていないためか見てもさっぱりわからない。
ネットで検索しても、これを使っていそうなサンプルを見つけることが出来なかった。
「なら私が!」と思えれば良いのだけど、ちょっと厳しい。

じゃあ、やっぱりC言語でやるか。


どうせ個人用のツールなので、gatttoolを変更するだけで済ませようと思う。
まずは準備として、gatttoolをBlueZのmakeではなく自分のmakeで行えるようにする。

attribディレクトリを別の場所にコピーし、Makefileを自作して、makeするだけ。
Makefileを作るのに時間がかかったのと、gatt.cがbluetooth.hをうまくincludeしないようだったので明示的に書いた(書く場所を上の方にしておかないと、なぜか読み込んでいなかったようだ)。

ソースとbluetooth、readline、GLibのリンクだけで済むかと思ったら、BlueZビルド時にできるbluetool-internalとshared-glibもリンクしないといかんようだった。
できればBlueZをインストールするときにコピーされるライブラリだけで構成したいのだが、知識が足りないので今回はこのままにしておこう。

2015/05/10

[ble]Device Addressのpublicとrandom

BLEのAdvertisingを見ていると、当然ながらPeripheralのアドレスが拾える。
そういえば、アドレスには種類があったよなあ、と思って調べた。


Device Address

Core_v4.2.pdfのVol.6 Part B "1.3 Device Address"

  • Public Device Address
  • Random Device Address
    • Static Device Address
    • Private Device Address
      • non-resolvable private address
      • resolvable private address

種類としては、publicが1つ、randomが3つになる。
randomのアドレスは、下位の2bitがどういう値かで見分けられる。

が、publicとrandomを見分ける方法が書かれていない。
そもそも、randomだったら偶然publicと同じアドレスになることもありうるだろうし・・・。

と思ったら、違うところで見分けるようになっていた。


Advertising PDUs

Core_v4.2.pdfのVol.6 Part B "2.3.1 Advertising PDUs"

Advertisingで投げるアドレスのAdvAだけ見てもpublicかrandomかはわからず、ヘッダにあるTxAddで表しているということが書かれている。

 

  • publicアドレス
    • TxAddかRxAddが0(AdvAだとTxAdd、InitAだとRxAddだったが、他にもあるかも)
  • randomアドレス
    • TxAddかRxAddが1(AdvAだとTxAdd、InitAだとRxAddだったが、他にもあるかも)
      • staticアドレス
        1. 下位2bitが1
        2. 残りのビットが全部0じゃないこと(0x000000000003はダメ)
        3. 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFFはダメ)
      • privateアドレス(non-resolvable)
        1. 下位2bitが0
        2. 残りのビットが全部0じゃないこと(0x000000000000はダメ)
        3. 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFCはダメ
      • privateアドレス(resolvable)
        1. 下位2bitがb10
        2. 残りのビットが全部0じゃないこと(0x000000000002はダメ)
        3. 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFEはダメ)

汝の名はBlueZ - (9) : hcitoolの(unknown)

うちのSensorTagがAdvertisingしているところをBlueZのhcitoolでスキャンすると、こう出てくる。

pi@raspberrypi ~ $ sudo hcitool lescan
LE Scan ...
34:B1:F7:D4:FA:33 (unknown)
34:B1:F7:D4:FA:33 (unknown)
34:B1:F7:D4:FA:33 SensorTag
34:B1:F7:D4:FA:33 (unknown)
34:B1:F7:D4:FA:33 (unknown)

「(unknown)」はなんだろう?


TIのBLEモニタで見ると、こうなっていた。

image

SensorTagがADV_INDがいくつか送信し、それをhcitoolが読んだらADV_SCAN_REQし、SensorTagがADV_SCAN_RSPを返す、という流れだろう。

 

ADV_INDのAdvDataと、ADV_SCAN_RSPのScanRspDataのデータ構造は同じで、「PDU長、AD Type、AD Data」が複数あるだけだ(Core_v4.2.pdf Vol.3, Part C 11:"Advertising and Scan Response Data Format")。

AD Typeの値がどういう意味なのかは、Core_v4.2にもCSS_v5にもなく、ネット上だけのようだ(たぶん)。
ネット上にあるのはAD Typeの値が何というデータタイプ名なのかが書いてあるだけで、そのデータタイプ名がどういう値を持っているのかはCSS_v5を見ないとわからない。
PDFに載っていてもおかしくないと思うんだけどなぁ・・・。


ADV_INDで投げているのは、こういうデータ。

02 : データ長
01 : <<Flags>>
05 : "LE Limited Discoverable Mode", "BR/EDR Not Supported"

ADV_SCAN_RSPで返しているのは、こういうデータ。

0A : データ長
09 : <<Complete Local Name>>
xx : "SensorTag"

05 : データ長
12 : <<Slave Connection Interval Range>>
xx : connInterval_min = 100msec, connInterval_max = 1000msec

02 : データ長
0A : <<Tx Power Level>>
00 : 0x00

 

hcitoolが(unknown)としているのは、hcitool.cのeir_parse_name()。
深く追わないけど、ADV_INDを拾って解析したけど、Local Nameのデータが入ってないから(unknown)と出力しただけだろう。

2015/05/02

[py]ハードタブは1~8スペース扱い

pythonがインデント単位で処理する(C系の閉じる記号がない)というのは、なんとなく知っていた。
nfcpyとか見て、なんとなくわかった気になっていた。

で、今回BlueZのgatttoolを動かすpythonスクリプトを見ると、スペースのインデントとハードタブのインデントが混ざっていた。
これ、ありなの??

ありだった・・・。
検索するとすぐに出てきて、ハードタブは8スペース扱い、とのこと。
でも、言語仕様としてはわかったんだけど、いっそのことハードタブを禁止するとかの方がよかったんじゃないだろうか。
コーディングスタイルは人それぞれだから好みがあると思うけど、ハードタブの設定はテキストエディタで可変になるんで、ちょっと危険なような。
COBOLだかFORTRANだか忘れたけど、何桁目に書くとなんとか、みたいなタイプは、スペースだけの方がよいと思う。

まあ、こういうのは現場でやってる人からすると「わかってるから現場で回避するんだよ」という類のものだろう。
知っていれば回避できるし、個人で気に入らないコーディングをしなければ済むし、いざとなればastyleで見るときは書き換えてしまうとかもありだろう(astyleにpythonがあるか知らんが)。


2.1.8 インデント

まず、タブは (左から右の方向に) 1 つから 8 つのスペースで置き換えられ、置き換え後の文字列の終わりの位置までの文字数が 8 の倍数になるように調整されます (Unixで使われている規則と同じになるよう意図されています)。

  • タブは、コンパイラというか実行時というかのときにスペースに変換される。
  • そのスペースの数は、1~8。
  • 終わりが8の倍数になるように調整

ということだ。
だから、

  • スペース6個+タブ1個=スペース8個
  • スペース7個+タブ1個=スペース8個
  • スペース8個+タブ1個=スペース16個
  • スペース9個+タブ1個=スペース16個

となるはずだし、

  • タブ1個+スペース5個=スペース13個
  • タブ1個+スペース6個=スペース14個

となるだろう。

タブの前にスペースがなければ、あるいはちょうど8の倍数であれば8スペース扱い。
タブの前にスペースがあれば、それを含めて8の倍数になるよう調整。
式にするとめんどくさそうだ。

まあ、検索するとだいたい「混ぜるな危険」になってる。
私も混ぜないように気をつけよう。

汝の名はBlueZ - (8) : pythonで試す

数字ばかりだと何をやってるかわからないので、サブタイトルを付けました。
今回は、SensorTagを操作するpythonスクリプトをもらってきて、Raspberry Piで動かしてみます。

スクリプトは、こちら。
msaunby/ble-sensor-pi

pythonはわからないので、書いてある通りにやる。
SensorTagのアドレスは34:B1:F7:D4:FA:33とわかっているので、スキャンは省略する。

$ sudo apt-get install python-pip
$ sudo pip install pexpect
$ git clone https://github.com/msaunby/ble-sensor-pi.git
$ sudo hciconfig hci0 up
$ cd ble-sensor-pi/sensortag
$ python sensortag.py 34:B1:F7:D4:FA:33
[re]starting..
Preparing to connect. You might need to press the side button...
(ここでSensorTagの横ボタンを押してAdvertising開始)
char-write-cmd 0x29 01
char-write-cmd 0x26 0100
char-write-cmd 0x31 01
char-write-cmd 0x2e 0100
char-write-cmd 0x3c 01
char-write-cmd 0x39 0100
char-write-cmd 0x44 01
char-write-cmd 0x41 0100
char-write-cmd 0x5b 07
char-write-cmd 0x58 0100
char-write-cmd 0x4f 02
[re]starting..
Preparing to connect. You might need to press the side button...

何やってるのかわからないが、何か動いていることはわかった。
Ctrl+CでもDでも終わらなかったので、Ctrl+Zしてpythonとgatttoolのプロセスを手動でkillしてやらんといかんかった。


さて、ログだけ見るとCharacteristicへの書き込みを行っているようだ。
センサーを有効にして、Notificationも有効にしているようだ。
が、その通知を待ってか待たずか、また再接続しに行っている。
でもSensorTagは接続が切れたと思ってない。
どこか、意思の疎通が取れていないようだ。

スクリプトは、gatttoolのコンソール出力で結果を判断しているようだ。
「前は[CON]だったけど、今はないからスルー」みたいなコメントもある。

BLEモニタで見ても、ちゃんとCONNECTして、Characteristicへの書き込みもソース通りに行っているし、SensorTagもNotifyを返している。
なのにー、なーぜー・・・・。

よくわからんが、barometerのコンストラクタでで例外が発生してNotification待ちに達しないようだ。
その原因は、char_read_hnd()がよろしくないためのようで、とりあえずコメントアウトすると、IR Temperature Serviceの値が取得できるようになった。

 

まあ、このpythonスクリプトはサンプルですよ、と書かれているし、メンテナンスとかも期待しちゃいかんとあるので、こういう感じでやればいいんだ、と感じ取るのがよさそうだ。
だったらpythonでやる必要は無いんだけど、これをC/C++でやるのは、めんどくさそうだ。
このサンプルの書き換えくらいであれば、そんなにpythonを勉強せずともやれるんじゃないかなぁ、と自分に期待している。

汝の名はBlueZ - (7)

あらすじ

hiro99ma blog: 汝の名はBlueZ - (1) : BlueZはあまり情報がない、ということを書いただけ
hiro99ma blog: 汝の名はBlueZ - (2) : なんでBlueZをやろうと思ったか、ということを書いただけ
hiro99ma blog: 汝の名はBlueZ - (3) : Raspberry PiでBLEのスキャンをするサンプルを動かした
hiro99ma blog: 汝の名はBlueZ - (4) : スキャンするサンプルの概要
hiro99ma blog: 汝の名はBlueZ - (5) : Raspberry PiのBlueZを最新にしようとしたことを書いただけ
hiro99ma blog: 汝の名はBlueZ - (6) : hcitoolとgatttoolに特に連携は無いことがわかった

今回は、gatttoolのconnectについて調べようと思っていたのだが、そう簡単には進まない。
gatttoolはいくつかライブラリを組み合わせて作られているのだが、その辺を知らないので読み進まないのだ。
なので、まずは周辺のことから調べていく。


まずMakefileから。

if READLINE
noinst_PROGRAMS += attrib/gatttool \
            tools/obex-client-tool tools/obex-server-tool \
            tools/bluetooth-player tools/obexctl
attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
                attrib/gattrib.c btio/btio.c \
                attrib/gatttool.h attrib/interactive.c \
                attrib/utils.c src/log.c client/display.c \
                client/display.h
attrib_gatttool_LDADD = lib/libbluetooth-internal.la \
            src/libshared-glib.la @GLIB_LIBS@ -lreadline
・・・(以下略)

まず、READLINEが定義されているときしかビルドされない。
そして、noinst_PROGRAMSとあるから、インストール対象外になってるのだろう。

リンクしているのは、自分の以外ではGLIB_LIBSと-lreadline。

ソースファイルは、こう。

  • attrib/gatttool.c
  • attrib/att.c
  • attrib/gatt.c
  • attrib/gattrib.c
  • attrib/interactive.c
  • attrib/utils.c
  • btio/btio.c
  • src/log.c
  • client/display.c

gatttoolでconnectするところだけだとinteractive.cで、gatttoolのmainがgatttool.cにある。
困ったことにatt.cはプレフィクスが不定なのだが、gatt.cやgattlib.c、utils.cはプレフィクスがついているから、そこまで見分けるのは大変ではないのかもしれない。btio.cもプレフィクスがついてるし。

log.cはデバッグマクロだけなのでよいとして、display.cだ。
これのプレフィクスが「rl_」になっている。
rlが付くのは、どうもReadLineライブラリ関係のようで、標準入力をさばいてくれるライブラリのようだ。
読みやすかったのは、こちらのサイト。
GNU Readlineを使ってみる


interactive.cで、プロンプトの出力はget_prompt()が行っている。
入力文字列の解析は、parse_line()が行っているようだ。
これらをrl_callback_handler_install()で登録しているから、入力が完了(Enter押したとき)に

  • parse_line()
    • 入力コマンドに応じた処理
  • get_prompt()

の順で動いているようだ。

connectしたとき、入力を確定させてから出力が終わるまでにしばらく時間がかかったので、同期でconnect処理をしているはず。
connectに対応する処理はcmd_connect()で、そこでgatt_connect()を呼んでいる。
これが接続要求ということで間違いないだろう。
その戻り値はGIOChannel*型。だから、BlueZのgatt系APIを使うのなら、GLibは使うことが前提になるようだ。
ただ、gatt_connect()はutils.cの関数で、そのヘッダファイルはgatttool.hにある(utils.cには独自のヘッダファイルがない)。
そういう意味では、gatt_connect()はBlueZの一部ではないと割り切って、自前で何かしてしまえるのかもしれない。

けど、btioがglib.hをincludeしてるので、結局はGLibに頼るのが正解のような気がしている。


そこで気になるのが、D-Busだ。
D-BusはAndroidのsystemとかが使ってるなー、というイメージしかなかったのだが、BlueZでも使われている。
BlueZ » Blog Archive » BlueZ 5 API introduction and porting guide

そもそもD-Busは何かというと、オーバーヘッドが少ないプロセス間通信(IPC)だそうな。
D-Bus Specification

こちらを読むと、BlueZはデーモンとGUIアプレットがD-BUS I/Fで通信するようになっている。
Bluetoothのはなし(4)|Wireless・のおと|サイレックス・テクノロジー株式会社

じゃあCUIはどうなってるかというと、図を見るとlibbluetooth.soがドライバをたたいているようだ。
なので、CUIで使う分にはD-Busは気にしなくてよいというか、libbluetoothを使うのであればD-Busは気にしなくてよいということになるだろう。


なんというか・・・思っていたよりも大ごとなので、尻込みし始めている。
gatttoolを「interactive」で動かすオプションがあるということは、そうじゃない動作が普通ということになる。
bluez/testの中を見ても、pythonで書かれたコードばかりだ。
C/C++でごりごり書くのを調べるより、pythonを覚えてサンプルをいじった方が早いのかも。
うぅ・・・。

汝の名はBlueZ - (6)

前回の続きから。
hiro99ma blog: 汝の名はBlueZ - (5)


前回は、BlueZの新しいソースを持ってきて、Raspberry Piでビルドしていて、眠たくて中断させたところまでだ。
Raspberry Piでのセルフビルドは進めるとして、クロスコンパイルも出来た方がよいだろう。
BlueZをgitで落としてきて、まずはconfigureのhelpを確認。
・・・configureがない。

$ aclocal
$ autoconf
configure.ac:32: error: possibly undefined macro: AC_DISABLE_STATIC
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
configure.ac:33: error: possibly undefined macro: AC_PROG_LIBTOOL

怒られた(私はxubuntu14.04でやってる)。
検索すると、以下が出てきた。
Karuraの日記: autoconf automake の失敗 (undefind macro)
書いてあるようにdpkg-reconfigureすると、直った。ありがたい。

というところで、Raspberry Piでのセルフビルドが終わってしまった。
クロスコンパイルは、そのうちやろう(やらないパターン)。


さて、書いてある手順通りにやったのだけど、うまくいかん。
うまくいかんというか、USBドングルが動いてないみたいだ。
dmesgを見てもbtusbがあるといってるし、lsusbで見てもHCIモードになってると出てるし。
うーむ。。。。とごにょごにょやっていたら、動いた。
1つ勘違いしていたのは、hci0が/devに見えてないから動いてないと思っていたことだ。
eth0と同じで、これは見えないようである。
hciconfigだけ打つと、hci0が動いていたら出てくるので、まずはそれで確認するのがよいだろう。
(lescanしても動かなかったのだけど。。。まあ動いているからよしとしよう)

ではgatttoolで、と思ったら、コマンドがない。
ビルドはされてるのに・・・。
と思ったら、こちらによると手動コピーらしい。
Linux でBLEのドングルを刺して通信させる。 | mbed
こちらのサイト、上の方しか見てなかったんだけど、下の方にBlueZをRaspberry Piでビルドすることも書かれているのね・・・。

なので、ここであれこれ書いたことよりも、上記のサイトを見た方がわかりやすいと思う。


さて、connectで気になっていたことを確認しよう。
Central側でSCANNINGを行っていなくてもCONNECTできるかどうか、だ。
Raspberry Piを再起動させて一からやっておこう(PeripheralはTI SensorTag)。

pi@raspberrypi ~ $ hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: 00:1B:DC:05:7F:D0  ACL MTU: 310:10  SCO MTU: 64:8
        DOWN
        RX bytes:564 acl:0 sco:0 events:29 errors:0
        TX bytes:358 acl:0 sco:0 commands:29 errors:0

pi@raspberrypi ~ $ sudo hciconfig hci0 up
pi@raspberrypi ~ $ hciconfig
hci0:   Type: BR/EDR  Bus: USB
        BD Address: 00:1B:DC:05:7F:D0  ACL MTU: 310:10  SCO MTU: 64:8
        UP RUNNING
        RX bytes:1128 acl:0 sco:0 events:58 errors:0
        TX bytes:716 acl:0 sco:0 commands:58 errors:0

pi@raspberrypi ~ $ sudo gatttool -b 34:B1:F7:D4:FA:33 -I
[34:B1:F7:D4:FA:33][LE]> connect
Attempting to connect to 34:B1:F7:D4:FA:33
Connection successful
[34:B1:F7:D4:FA:33][LE]>primary
attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x002d uuid: f000aa00-0451-4000-b000-000000000000
attr handle: 0x002e, end grp handle: 0x0038 uuid: f000aa10-0451-4000-b000-000000000000
attr handle: 0x0039, end grp handle: 0x0043 uuid: f000aa20-0451-4000-b000-000000000000
attr handle: 0x0044, end grp handle: 0x004e uuid: f000aa30-0451-4000-b000-000000000000
attr handle: 0x004f, end grp handle: 0x005d uuid: f000aa40-0451-4000-b000-000000000000
attr handle: 0x005e, end grp handle: 0x0068 uuid: f000aa50-0451-4000-b000-000000000000
attr handle: 0x0069, end grp handle: 0x006d uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle: 0x006e, end grp handle: 0x0078 uuid: f000ccc0-0451-4000-b000-000000000000
attr handle: 0x0079, end grp handle: 0x0085 uuid: f000bcc0-0451-4000-b000-000000000000
attr handle: 0x0086, end grp handle: 0xffff uuid: f000ffc0-0451-4000-b000-000000000000
[34:B1:F7:D4:FA:33][LE]> quit


Peripheralのアドレスがわかっていて、PeripheralがAdvertisingしていれば、Central側はScanningしなくてもConnectionができるということがわかった。
ただ、もしかしたらgatttoolが自動的にScanningをしているのかもしれない。
というよりも、Scannningというステータスにするかどうかは別として、飛んでる無線を捉まえないといかんから受信はするのだ。
だから「BlueZではアドレスがわかっていたらgatttoolでconnectできる」くらいにしておこう。
まあ、事前にアドレスがわかるっていう状況がどういう場合かはわからんがね。

あと、今のgatttoolは「[CON]」と表示されるのではなく、アドレスの表示色が変わるようになっていた。
上のログは、一番最後のアドレス部分が青く出力されている(TeraTerm上では)。


connectした状態でgatttoolからdisconnectしたり、Peripheralから切断したりすると、こう出てきた。

(gatttool:2202): GLib-WARNING **: Invalid file descriptor.

どこかで、イベントを処理する部分があるようだ。
g_main_loop_run()がそれっぽいのだが、本体がBlueZの中にはない。
検索すると、GLibのようだ。
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-loop-run

g_で始まってるのがいくつかあるから、グローバル変数とかグローバル関数とかのプレフィクスかと思ってたけど、GLibなのか・・・。
せめて「glib_」になってるとうれしいのだが、せんなきことじゃ。

Windows10 Technical Previewのアップデート

以前、Windows10のTechnical Preview版をインストールした。
hiro99ma blog: Win10 Tech Previewを見てみた

このときはBuild 9926だったようだ(WinVer.exeで確認)。
どうもちょくちょくビルドバージョンは上がっているらしいので、なんとなくアップデートしておこうかと思った。
頭がすっかりお休みモードになっているので、考えることをしたくないのだ。

 

さて、Windows10のWindows Updateだが、コントロールパネルになかった。
Settingsアプリの方に移動したのか、元は両方あったのか忘れたが、とにかくSettingsアプリの中にある。
日本とだと「保守と管理」だ。
ここでチェックするといくつかアップデートする項目は出てきた。
2回くらいやって、2回くらい再起動したのだけど、ビルドバージョンは変わらない。
ISOでインストールせんといかんのやったら、しゃーらしいなぁ・・・。

 

そう思ってたら、記事が見つかった。
Windows 10 Insider (Technical) Preview Build 10074 Available for Download - AskVG
詳細オプションで「高速」にしてからチェックするんだと。
おお、確かに進んだ!

そんな感じで、現在10074をインストール中。
けっこう時間がかかります。

image

 

ようやく終わった。
何が変わったかよくわからないけど、スタートメニュー内の終了させるメニュー名が「仕事率」になってた。
work ratioの訳? でも、電源と関係ないよなぁ・・・。

image

 

デスクトップアイコンの変更をしようと思ってテーマの設定画面を開いたんだけど、カスタマイズするボタンが消えていた。
うーん、なんか不要な情報が残ってしまったのか。
SHIFTキーを押しながら再起動させると、Windows8と同じように修復系のメニュー画面が出てきたので、初期化してみよう。

今はVirtualBoxで動かしているのもあって、動きはとても遅い。
実環境に入れてみればいいんだろうけど、Windowsのお仕事でもないので、既存の開発環境がどれだけ動くかによって乗り換え時期が決まるだろうな。