2014年9月30日

[ble]GATTがもやもやしてよくわからない

BLEのGATT、General ATTribute profileがどうももやもやしてよく理解できていない。

Core_v4.1のvol 3 Part Gが、GATTの章である。

image

GAPがあって、その一部がGATTで、その中にアプリに特化したプロファイルがある、という依存関係らしい。
ということは、継承関係にあるというイメージでよいのかな?

image

GATTプロファイルのやりとりは、ATT(ATTribute Protocol)を使うとのこと。
ATT PDUというデータの単位があって、これでデバイス間の命令(command)、要求(request)、応答(response)、指示(indicate)、通知(notification)、確認(confirmation)を行う。

image

 

とまあ、理屈はわかったようなわからないような感じだ。
前回、I/O Serviceというサービスを作ったが、あれとはどう絡んでいるのだろうか?
GATTを継承してI/O Serviceができあがっているのか、GATTがI/O Serviceを含んでいるのか。

Core_v4.1のp.2177 "2.6.1 Overview"に出てくる図を見ると、Profileが1つで、その中に複数のServiceを持つように描いてある。
ということは、BLEのProfileはGATTだけなんだけど、中に入っているServiceが異なるから「派生したGATT」という表現になっているという考え方でよいのかな。

じゃあ、標準にあるProfileはどうなっているのだろうか。
シンプルそうなANP(Alert Notification Profile)を見てみよう。
https://developer.bluetooth.org/TechnologyOverview/Pages/ANP.aspx

これは、ANS(Alert Notification Service)を1つ持つGATT、ということか。
下の方にある説明図が、Alert Notification ClientとAlert Notification Serviceになってるけど、右側はAlert Notification Serverの間違いなのかな。

あと、"enables a client device to receive"とあるけど、サーバ側が通知してクライアント側が受信するの?
英語力不足で自信がないところが哀しいな。


そんなあなたに、こんな本が出るらしい。
『「ジョジョの奇妙な冒険」で英語を学ぶッ!』
http://www.oricon.co.jp/news/2040463/full/

2014年9月24日

[nrf51]softdevice_assertion_handler()の嫌なところ

nRF51 SDK v6.1.0を使っている。

nrf_assert.hで、ASSERTマクロが定義されている(assertじゃなくて)のだけれど、判定が偽の時にassert_nrf_callback()を呼び出すようになっている。
assert_nrf_callback()はユーザアプリ、つまり私とかが定義せんといかん。

これが有効なのは、DEBUG_NRFかDEBUG_NRF_USERが定義されているとき。
前者はMakefile.commonが、後者はアプリのMakefileが定義する。
makeを引数無しで実行すると、という話を前回したのがこれで、make debugのときにはDEBUG_NRFが定義されるようになっている。

じゃあ、make releaseとしたときにはassert_nrf_callback()が不要、と思ったのだけど、そうではなかった。
softdevice_assertion_handler()が使っているのだ。
これは#ifdefとかじゃないので、softdevice_handler.cをリンクするならば定義が必要になってくる。

 

app_error_handler()も同じようなものなんだから、こっちも定義してしまえばいいんだけど、なんかちょっと抵抗があるのよねぇ。
なんでだろう・・・。

2014年9月23日

引数無しmakeの動作を勘違いしていた

nRF51 SDKにはMakefileのテンプレートなどもあるため、gccでやるときも楽だ。
その中に、こう書かれていた。

## Default build target
.PHONY: all
all: clean release

ああ、makeのデフォルトはreleaseで行われるのね、と思ったのだが・・・。
やってみると、どうもdebugで指定した動作をしているようなのだ。

調べてわかったのは、makeの引数無し動作は「最初に定義されたtargetが実行される」なのだ。
Makefileではこの行よりも前に、debug、releaseの順でターゲットが書かれていた。
そうか、そうだったんだ・・・。

自分でMakefileを書くとき、最初にallが出るようにしているので、ずっと「引数無しはall」と思い込んでいたのだ。
こういう、習慣でやっていることが思い込みにつながる事ってあるよね、うんうん。

今までそれでやれていたので、間違った説明をしたことがあったかも・・・とちょっと怖くなった。

[ble]BLEモジュールを使った場合のがんばりどころは?

3回に分けて、nRF51822で基本的なサービスとアプリを作ってみた。

  • [nrf51]はじめてのBLEアプリ - (1)サービスをつくる
  • [nrf51]はじめてのBLEアプリ - (2)アプリを作る
  • [nrf51]はじめてのBLEアプリ - (3)デバッグ
  • よしよし、これでCentralからの入力も、Peripheralからの通知もできるようになった。
    Indicateとかセキュリティとかあるけど、まあそれは後回しでよかろう。

    そこで、はた、と手が止まった。
    入力と出力と通知ができて、他に何かやることがあるんだろうか?

    もしハードウェアの設計をしていたりするんだったら、いろいろありそうな気がする。
    でも、BLEモジュールでアンテナまでセットになっているので、やれることが無い。
    プロトコルスタックも、SoftDeviceがやってくれるので、やることが無い。

    もしかして・・・あとはアプリ層でごにょごにょがんばるだけってことかしら・・・。
    それとCentralか。Centralも似たようなもので、BLEはOSが吸収してくれるから、あとはアプリ層でやる気がする。
    そうか、だからサービスについての記事があまりないのか・・・。

     

    そんなわけで、まだ認識が違ってるかもしれないのだけども、BLE自身についてはこのくらいにして、何か作ってみよう。
    1回目は捨て石にするつもりで、と本にも書いてあったし。
    やってみれば、問題点もわかってくるだろう。

    2014年9月22日

    [nrf51]はじめてのBLEアプリ - (3)デバッグ

    BLEアプリをデバッグしたが、特に問題なく動作していた。

    BLEモニタに出ていなかったのは、やはりチャネル違いのためのようだ。
    Bluetoothは通信する周波数が移動するので、CONNECTしたときを捉まえられないと、それ以降はほぼ捕捉できない。

    なのでデバッグするためにやったことは、BLEモニタにCONNECT後もパケットが出力されるようになるまで、何度もCONNECTとDISCONNECTを繰り返すことだった。

     

    ここまでをgithubに置いたので、ご参考まで。
    git@github.com:hirokuma/nrf51822_templete.git

     

    ひとまずこれで、はじめてのBLEアプリは終わりである。
    あとはこれをベースに勉強していこう。

    2014年9月21日

    [nfc]AS3923

    iPhone6のNFCアンテナがちっさくて、そんなアンテナで大丈夫か(R/Wとして使えるのか)?という話があった。

    アンテナが小さいと、NFCタグはR/Wからの搬送波で電力を起こして動くので、その力が足りないのではないか、ということだと思っている。
    カードエミュレーションする場合は、自前の電源を積んでいることがほとんどなので、電力を起こすのに足りなくても大丈夫だ。

    http://www.nfcworld.com/2013/03/07/322941/ams-launches-active-boost-afe-chip-that-can-add-nfc-to-standard-mobile-phones/

    このページに、前の型番なのかAS3922というチップの説明がある。
    microSDやSIMでNFCをやるような、スペースがないデバイスのためのチップで、active tag analog front end、と説明されている。
    真ん中の方に図があるのだが、AS3922があり、それにアンテナと、SEと、NFCコントローラがつながっている。
    私のイメージでは、SEはNFCコントローラとお話しするものだったんだけど、AS3922は何をするんだろうね?

    Q factorを自動調整する機能があって、FeliCaなんかでも使えるように書いてある。
    FeliCaっていうか、無線の話なのでNFC-Fよね。FeliCaのSEが接続できるような気がしないし。
    13.56MHzだからNFC-A, B, Fどれでも同じアンテナでいいんだろうと思っていたけど、そういうものでもないのか。。
    無線の世界は奥が深いですな。

    今週になれば、実機がどんな感じかの情報も出てくるだろうから、推測はここまでだな。

    2014年9月20日

    [nrf51]はじめてのBLEアプリ - (2)アプリを作る

    前回:[nrf51]はじめてのBLEアプリ - (1)サービスをつくる
    nRF51822のBLEアプリを作る練習。
    前回はサービスだったので、今回はそのアプリ実装を行う。
    今気付いたが、チュートリアル記事を書いているような感じに見えてしまうな。。。
    すまん、この一連の記事は、実況中継なのだ。
    もちろん動くようになるまでやるけれども、PDFに書いてある手順を見ながらやっているだけなので、今の段階では間違っていることもあるかもしれない(SoftDeviceのバージョンも上がってるし)。

    サービスを呼び出すだけだから簡単だろうと思っていたが、いやいやどうして。
    作ったサービスは、あくまで部品のようなもの。
    AdvertisingやConnectなどはやらないので、そこはアプリがやる。

     

    PDFのLBSサービスでは、クライアント(相手)からのLED制御と、サーバ(nRF51が搭載されたボード)のボタン押下通知ができるようになっている(LED / Buttonサービス)。
    私は機能名を付けず、I/Oサービスとして、クライアントからのInputと、サーバからのOutputということにしている。
    Output側は、Clientから値を読むこともできるし、変化があったときにNotifyで通知を出すように考えている。

    前回サービスを作ってわかったのは、Bluetoothのプロファイルやサービスというのは、あくまでBluetoothの通信自体を指すと言うこと。
    音楽関係のプロファイルだからと言って、再生したい音楽を送信する必要も無ければ、受信して音楽を再生するという必要も無い。
    ただ、音楽を再生したい/音楽を再生させたい、という需要と供給があるので、そのプロファイルやサービスを使用しているだけなのだ。

    その需要と供給を叶えるのがアプリの部分である。


    アプリの作成

    BLEではいろいろと想定があるかもしれないが、今回はほぼ素のnRF51822を使っていることもあるので、電池駆動を前提として考える。
    携帯電話のような充電電池駆動でもなく、乾電池で駆動する想定。

    前提がどこに影響するかというと、省電力だ。
    スマートフォンの場合でも省電力は求められるだろうが、乾電池駆動の場合はさらに厳密だ。
    製品にするときに「通常使用時には○年持ちます」みたいなことを書くことになるからだ。

    と書いてはみたものの、nRF51822ではSoftDeviceが主な部分を握っているので、まず「無線の送受信」というところで省電力を考えることはできない。
    Nordicのブログにある情報が一番信用がある。というよりも、それくらいしか情報がない。
    How to minimize current consumption for BLE application on nRF51822 [closed]

    情報がないんだけど、書いてあることが長い・・・。
    ま、まずは動くことを確認してから読もう。

     

    予定では、こんな感じの回路にする。
    右側3つは、アプリのテンプレートで名前の定義があったので、そのまま使おう。
    実際の製品だと、電池がもったいないから外すんだろうな。

    左側が、今回のサービスで使う部品。
    やっぱり、簡単なのってLEDとSWしかなくてね・・・。
    これにとってかわるのって、相当難しいんじゃないか? 出力は圧電ブザーも簡単ではあるが、鳴りっぱなしになるとイライラするだろうし。

    image
    (2014/09/22修正:SWにプルダウン抵抗追加)

     

    テンプレート

    nRF51 SDKのアプリテンプレートは、こういう初期化が行われている。
    全部はやらなくてよいように思う。

        // Initialize
    
        leds_init();
    
        timers_init();
    
        gpiote_init();
    
        buttons_init();
    
        ble_stack_init();
    
        scheduler_init();
    
        gap_params_init();
    
        advertising_init();
    
        services_init();
    
        conn_params_init();
    
        sec_params_init();

     

    スケジューラの使用

    SoftDeviceにはOSっぽい機能は無いのだけれども、その中でもOSっぽいといえるのはスケジューラだ。
    何ができればOSなんだ?というのはあるけど、私のイメージとしては、何か少しでもリソースを管理してくれるなら、それだけでOSだ。厳密な定義には興味が無い。

    前回スケジューラを調べたときは、wfeを実行している、というところまで見ていたようだ。
    ARMは、WFEかWFIを使うと、省電力状態になるらしい。
    http://www.aps-web.jp/academy/cortex-m/20/a.html

    細かいことはともかく、スケジューラを使わないとがんがん無限ループするだけのようだから、使おう。
    テンプレートでスケジューラの使用有無を設定しているのは、以下だった。

    • APP_TIMER_INIT()
      • app_timer_evt_schedule() : app_timer.c
    • SOFTDEVICE_HANDLER_INIT()
      • softdevice_evt_schedule() : softdevice_handler.c
    • APP_BUTTON_INIT()
      • app_button_evt_schedule() : app_button.c

    大文字の方が初期化マクロで、小文字の方はスケジューラが使用する関数名だ。
    この関数自体はSDKの中に入っているので、スケジューラを使用する場合にはMakefileで該当する関数を含んだファイルもビルドするように追加しておかないといかん。
    追加してなかったらリンクエラーになるのだが、事情がわかってないと「このリンクエラーは何だ?」ということになってしまう。

    テンプレートのMakefileはGCCのオプションで-ffunction-sectionsと--gc-sectionsが付いているので、未使用の関数は削除されるはず。
    そう考えると、とりあえずMakefileにはソースファイルをあれこれ置いていてもそこまで心配はしなくてよさそうな気はする。
    が、使ってないものが入っているのも気持ち悪い気がするので、最後に整理したらよい、くらいにしておくか。

     

     

    サービス

    #includeして、サービス構造体のインスタンスを用意して、services_init()で初期化を呼び出して、ble_evt_dispatch()でハンドラを呼び出す。

    ということはわかったのだけど、複数のサービスを登録している場合にはどうなるのだ?
    ble_evt_dispatch()は特定のサービス向けに登録するものではないし、呼ばれたときの引数を見てサービスのハンドラを呼び出しているわけでもない。

        ble_gatts_evt_write_t *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
        if ((p_evt_write->handle == p_ios->char_handles_in.value_handle) &&
    
          (p_evt_write->len == 1) &&
    
          (p_ios->evt_handler_in != NULL)) {
    
            p_ios->evt_handler_in(p_ios, p_evt_write->data[0]);
    
        }

    このhandleを比較している箇所だ。
    これで、該当するキャラクタリスティックへの要求かどうかを判断している。

     

     

    ボタン

    ボタンは以前も使ったが、GPIOTEとAPP_BUTTONの両方がいる。
    テンプレートでは、よくわからんが「WAKEUP_BUTTON」というものが定義されている。
    BLE_GAP_EVT_TIMEOUTで使うようなんだが、うーむ。。。
    GPIO_WAKEUP_BUTTON_CONFIG()というマクロもコメントアウトながら呼ぶようになっているが、SDKには定義がない。
    テンプレートではそのマクロは使わず、普通のボタンの1つとして取り扱っているし。
    わからないのでそのボタン定義は削り、今回のボタンだけにしておく。

    ボタンは、初期化した段階では使用できなかったと思う。
    使うときにapp_button_enable()を呼び出し、使わないときにapp_button_disable()を呼び出す。
    テンプレートでは、CONNECTしたときにenable、DISCONNECTしたときにdisableにしている(コメントアウトされてるが)。

     

    Advertising

    そしてAdvertisingだ。
    ここでは、サービスのUUID(16bit値)と、登録したときのUUID typeを指定するようだ。
    これが配列で指定できるので、複数設定できるのかもしれん。
    そこまでは書かれていなかったので、動くようになったら試してみよう。

     

    ここまででアプリの説明は終わりになっている。


    動作確認

    ビルドして、コンパイルエラーなどを取ったら、動作させてみよう。

    コンパイルしてわかったが、これがwarningになる。

    ble_uuid128_t   base_uuid = IOS_UUID_BASE;

    なんでかというと、ble_uuid128_tは構造体だからだ。
    構造体の中に、uint8_t uuid128[16]というメンバがいる。
    だから、こうなる。

    ble_uuid128_t   base_uuid = { IOS_UUID_BASE };

    あと、テンプレートのボタンイベントハンドラは、引数の名前と使っている名前が違っている。
    テンプレートに過ぎないとは言え、やはり自分用のテンプレートを一度作った方がよいだろう。

     

    なお、「make」のデフォルト動作は「clean release」である。
    gdbでソースデバッグするなら「make debug」とやる。

     

    eclipse

    今までテキストエディタとコマンドプロンプトでやっていたので、デバッグのためeclipseを使う。
    nRF51822で使うための環境設定は省略だ(参考)。

     

    デバッグ

    まず、ble_advdata_set()でエラーが返ってきた。
    値は7で、NRF_ERROR_INVALID_PARAM(nrf_error.h)。
    adv_data_encode()でscanrspの方をさばいているときにエラーを出している。
    うーむ・・・。

    ん、UUID typeが0だな。。。
    handlerもNULLになっている。。。
    あ、services_init()がadvertising_init()より後で呼び出されてる!
    テンプレートぉぉぉぉぉ!!!

    順番を入れ替えると、無事Advertisingされました。
    やれやれ・・・。

    image

     

    iPad miniからLightBlueで見ると、こんな感じだった。

    image

    うーん、0002はINPUTにしてるので、Writeになっててほしかったんだけど・・・。
    ああ、char_mdの設定を間違えていた。

    image

     

    CONNECTまでは確認できたのだが、Writeができてない。
    BLEモニタにも出てないので、LightBlueが出していないのか、モニタの設定を間違えたか。。。
    ここは、後日だ。

    [nfc]iPhone6にはNXPのチップとAMSのチップが載っているそうだ

    ざっと読んだ。
    http://www.nfcworld.com/2014/09/19/331560/iphone-6-teardown-shows-nfc-chips-nxp-ams/
    単語をかいつまんでいるだけなので、間違っていたらすまん。
    • iPhone6には、NXP 65V10とAMS AS3923が載っている
    • NXP 65V10はNFCモジュールとSEが一緒になったチップ(PN65と同じ?)
      • PN544が入っているようなものだ
    • AMS AS3923は、ブースターIC
      • アンテナ設計があまり必要なくなる?
    • 普通のNFCアンテナっぽいものが見つからない
    • 可能性としてだが・・・Appleはすごく小さなアンテナを使ってて、microSDやSIMのような外部デバイスで使うAS3923を載せたんじゃなかろうか
    • 支払のような用途では問題ないと思うけど(カードエミュレーションでR/Wが搬送波を出す場合ということ?)、普通のNFCタグを読み書きするならもっと大きなアンテナがいるんじゃなかろうか
    こんな感じで読んだのだけど、どう?

    続き:http://hiro99ma.blogspot.com/2014/09/nfcs3923.html

    [nrf51]はじめてのBLEアプリ - (1)サービスをつくる

    今まで、nRF51822やBLEのことを調べてきたが、結局アプリを作るに至っていない。
    ごにょごにょ言っていないで、動くものを作ろう。


    参考にするのは、アプリケーションノートnAN-36。
    4章をやっていく。
    開発環境は、GCC(gcc-arm-none-eabi-4_8-2014q2-20140609-win32)+Eclipse(Luna)。
    GCCが4.8なので、そのままだとコンパイルエラーが発生すると思う。
    http://hiro99ma.blogspot.com/2014/06/blebvmcn5102-bk_28.html

     

    まず、アプリのテンプレートをコピーする。
    今回はS110(Peripheral)なので、SDKをインストールした中にあるs110のものをとってきた。
    misファイルでインストールした場合だと、たぶんこんな感じの場所に入っている。
    C:\Nordic Semiconductor\nRF51 SDK_v6.1.0.0\Nordic\nrf51822\Board\nrf6310\s110\ble_app_template

    コピーする先のフォルダは、多少手間を減らすのであればテンプレートと同じフォルダ内に置くのがよい。
    そうではない場合、Makefileの変更が発生する。
    armフォルダを削除して、gccの中にあるファイルをMakefileにリネーム。
    テキストエディタで開いて、SDK_PATHを変更する。

    SDK_PATH = C:/NORDIC~1/NRF51S~1.0/Nordic/nrf51822/

    なんで8.3形式かというと、フォルダ名にスペースが入っているからだ。
    やりようはあるのかもしれんが、めんどくさいので dir /xでいちいち確認している。
    msiじゃなくてzipを解凍した方がよいかも。msiでインストールするとスタートメニューに登録されるんだけど、そのパスがインストールしたパスになってるわけでもないし。。。

    Eclipseでデバッグすることも考えると、環境変数に置いておいた方が楽そうだ。
    もちろん、パスはスペースが入っていないところにする、という前提だが。
    (Eclipseは、か、GDBか、はわからないが、そっちはスペースが入ったパスでもよさそうだった。)

     

    ここで一度、Makefileのあるフォルダでコマンドプロンプトを開き、make cleanが通ることを確認しよう。
    次に、makeしよう。
    そうすると、コンパイルが始まるのだが、SDKをインストールしたままだとコンパイラの場所を正しく指していないかもしれない。

    ツール類は、

    $(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-gcc

    のような名前で実行される。
    定義しているのは、Makefile.windowsなので、これを書き換える(GNU_VERSIONは使ってないような気がする)。
    $(SDK_PATH)\nrf51822\Source\templates\gcc\Makefile.windows

    もう一度makeして、最後にhexファイルができたら、とりあえず環境は整ったことになる。

    人によっては、Makefileのこれが気になるかもしれない。

    BOARD := BOARD_NRF6310

    $(SDK_PATH)\nrf51822\Include\boards.hで使っていて、これがないとコンパイルエラーになる。
    たぶんNordic社のサンプルボードなんだろうが、気になる人はここを変更するか、boards.hをincludeしないようにするとよかろう。
    テンプレートではこれを使っているので、今回は自分用のビルドが通るまでは残しておく。

    これで、ひとまず自分用のテンプレートができたことになるので、記念に残しておこう。
    そういえば、元のテンプレートはCopyrightがNordicになっているから、自分のものにしておいた方がよかろう。
    ああ、Makefileの「OUTPUT_FILENAME」は、何か名前を付けた方がよいかも。
    なお、未設定にしてもビルドは通って「_s110_xxaa.hex」みたいな名前がつくから、気になるなら対策しよう。


    サービスの作成

    アプリの前に、サービスを作る。

    テンプレートをコピーした後、ble_basを持ってきて、それをカスタマイズするようになっている。
    なぜBASかというと、内容がシンプルだからだそうだ。
    ファイルはここにある。

    ソース:$(SDK_PATH)\Source\ble\ble_services\ble_bas.c
    インクルード:$(SDK_PATH)\Include\ble\ble_services\ble_bas.h

    ファイルとして、ble_bas_cもあるのだが、これはBASのクライアント側。
    バッテリー情報を提供するのがble_basでサーバ側と考えてよいだろう。

    サンプルは、LEDの点灯制御と、ボタンの押下状態取得だ。
    他の例を考えようとしたが、結局のところ基本は「制御をしてもらう」「結果や状態を教えてもらう」なので、悔しいがまねをしておこう。
    (名前だけでも変えておくか、と「I/O Service」にしたが、略称が「ios」になるので、なんかやだな。)

    image

     

    構造体を、3つほど用意する。

    • データ保持用。thisみたいなもの。
    • 初期化用。thisの初期化に使う。
    • イベントデータ用。イベントが発生したときに、値を詰めてコールバックするときに使う。

    初期化用は、なくてもよい。
    ble_basというか、S110でのお作法みたいなもので、init関数を作るときにアプリが初期値を入れて渡せるようにしているだけだ。
    使うのもそこだけなので、だいたい呼び出し元がローカル変数で設定して渡すだけのようだ。

    データ保持用は、これは呼び出し元でメモリを保持する。
    だから、ローカル変数じゃなくてグローバルにする。まあ、staticがほとんどだろうが。

    イベントデータ用は、SoftDeviceから通知されたとき、呼び出し元にコールバックの引数として渡すようだ。
    だから、コールバック元、つまりble_xxxのイベントハンドラがローカル変数で設定してコールバックするだけのようだ。

     

     

    サービスの初期化

    UUIDを生成する。
    これには、nRFgo Studioを使う。
    カーソルを「nRF8001 Configuration」にしておかないと、メニューのnRF8001 Setupが使えない。

    image

    image

    生成は簡単なのだけど、これをどうしたらいいんだ・・・。
    以下、最終的にはやらなくてよかったのだけど、せっかくやったので残しておく。

    「GATT Services」というタブでやる?
    image

    右の「Add new templete」を選んで、

    image

    真ん中右くらいにある「Add new characteristic templete」を選んで、

    image

    「Base」でさっき作ったUUIDを選び、空いたところになにやら入力。
    inputとoutputを作ると、templete欄に入るので、そこからMandatoryにD&Dし、適当に入力。

    image

    で、前の画面に戻ってtemplete欄からI/O ServiceをD&D。
    image

    ・・・それで??
    気を落ち着けてメニューを見てみると、ソースファイルを生成してくれるような項目が出てきた。
    実行すると・・・よくわからないソースファイルが出てきた。

    PDFの例と見比べて、以下のような関係になっていればよさそうだ。
    BLE_LBSのUUIDが書いてあればいいのにと思ったが、前の章に書かれていたようだ。。

    生成されたUUID:87C9xxxx-CBA0-7D7D-F1B5-E1635787F177
    XXX_UUID_BASE:{ 0x77,0xf1,0x87,0x57,0x63,0xe1,0xb5,0xf1,0x7d,0x7d,0xa0,0xcb,0x00,0x00,0xc9,0x87 }

    base UUIDはバイト単位で書くので自分でリトルエンディアンにし、16bit UUIDはそのまま書けばよいようだ。
    というわけで、nRFgo StudioはUUID生成だけの目的で使えばよいようだ(PDFもそうなってる)。

    さて、base UUIDはnRFgo Studioが生成してくれるとして、16bit UUIDはどうやって決めるとよいのだろうか?
    nAN-36の2.2.4.2節では、Bluetooth Core Specificationでは特に決められていない、と書いてある。
    そういうのが一番困る・・・。
    なんとなく、0x0000とか0xFFFFは避けたくなってきた。
    どういう無線なのかわからないけど、同じデータが続くとまずい、とかいうことはアプリ層では考えなくてよいと思うので、やっぱり適当に割り振ろう。

    #define IOS_UUID_SERVICE        (0x0001)
    #define IOS_UUID_CHAR_INPUT     (0x0002)
    #define IOS_UUID_CHAR_OUTPUT    (0x0003)

     

    init処理では、base UUIDをsd_ble_uuid_vs_add()で登録する。
    そうすると、8bitのUUID typeなる値が返される。
    以後はこのtype値と、16bit UUID値を使って操作することになるようだ。

    まず、UUID typeとIOS_UUID_SERVICEをble_uuid_tの変数に突っ込んで、sd_ble_gatts_service_add()で登録。
    これで、空のサービスが登録されたことになるそうだ。
    「空の」というのは、キャラクタリスティックが登録されていない、ということだ。

    image

     

    キャラクタリスティックの登録

    まず、出力方向のキャラクタリスティックを用意する。
    中身はわかっていないが、こういうことをやっていると思われる。

    • Attributeメタデータの設定(cccd_md)・・・NotifyかIndicateをサポートする場合
      • ReadとWriteの動作
    • キャラクタリスティックメタデータの設定(char_md)
      • Read可能
      • Notify可能
    • UUIDの設定(ble_uuid)
      • サービスのUUIDタイプ値
      • 16bit UUID値
    • Attributeメタデータの設定(attr_md)
      • ReadとWriteの動作
    • Attributeの設定(attr_char_value)
      • 値のサイズ

    これらとサービスのハンドラなどをsd_ble_gatts_characteristic_add()に与えて、登録。
    登録すると、キャラクタリスティックのハンドラが取得できる。

    image

    CCCDは、NotifyかIndicateをサポートする場合、つまりクライアント側に通知を行うキャラクタリスティックの場合に必要となる。

    ここは出力方向のキャラクタリスティックの説明になったが、入力のみや入出力の場合でも同じだ。
    その違いは、Attributeメタデータ設定で行っている。

    ここで、サービスの初期化は終わりだ。

    image

     

    スタックイベントのハンドリング

    BLEスタックからの通知は、サービスにではなくアプリで受けとるようにする。
    アプリがあれこれ初期化するときに、BLEスタックの初期化も行う。
    softdevice_ble_evt_handler_set()でアプリのイベントハンドラを登録し、そのハンドラが呼ばれたときにサービスのハンドラを呼び出してもらうように書くようだ。

    PDFのサンプルでは、イベントタイプとして3つ用意されている。

    • BLE_GAP_EVT_CONNECTED
    • BLE_GAP_EVT_DISCONNECTED
    • BLE_GATTS_EVT_WRITE

    上2つがGAPイベント(enum BLE_GAP_EVTS)で、最後のはGATT Serverイベント(enum BLE_GATTS_EVTS)。
    LEDの点灯制御要求がWriteになる。

    引数から、渡されたデータをこんな感じでコールバックする。

    ble_gatts_evt_write_t *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    p_ios->evt_handler_in(p_ios, p_evt_write->data[0]);

    なお、ble_gatts_evt_write_tのdataは、uint8_t data[1]で定義してあるので、malloc()か何かでメモリが取られてるんじゃなかろうかね。

    PDFの例だとLEDの点灯制御なので、ble_lbsサービスでLED点灯まで制御するかと思ったが、そうではなくアプリにコールバックするだけだ。
    プロファイルとかサービスとかは、あくまでプロトコルスタックで、機能のデバイスドライバではないのだ。
    製品として「このプロファイルに対応しています」という場合には、アプリまで含んだ機能の説明になるのだろう。
    まあ、「このヘッドセットはA2DPに対応しています(音は聞こえません)」などとなってたら売れないだろうから当然ですな。

     

    逆方向の、nRF51822からClientに通知したい場合は、sd_ble_gatts_hvx()を使う。
    値の設定だけしたい(Notifyを投げたくない)ときは、sd_ble_gatts_value_set()を使うそうだ。

    そういえば、Clientが値を取得したいときの動作が書かれていない。
    BLE_GATTS_EVTSにもないので、SoftDeviceが自動的にさばいてくれるのかな?

    image

     

    これで、サービスの説明は終わりのようだ。
    次回、アプリを作って動作確認だ。

    2014年9月17日

    [nrf]Em::Blocks

    Em::BlocksでNordic ARMが対応されたということなので、少し試すことにした。
    と書くと、やったことがある人のように見えるが、知識は何もない。

    今まではEclipseでやっていたが、その場合もEclipseが何かするのはGDBからで、それまではMakefileをたたくだけなので、GUI環境が変わったとしても、そんなに影響はないだろう。
    ただ、上記サイトにあるconvSD.batなんとかがよくわからない。

    インストールすると、特になんというものもなく終わった。
    新規プロジェクトを作ると、Nordic ARMが候補にあるので、上記サイトのように進めると、何かできた。
    アイコンをクリックしてビルドすると、ELFファイルができあがっていたので、失敗はしていないようだ。

     

    convSD.batは、私の環境ではここにあった。

    C:\Program Files (x86)\EmBlocks\2.20\share\EmBlocks\templates\wizard\arm\Nordic\softdevices

    そこにs110フォルダがあったので、SoftDeviceを解凍して、convSD.batを実行した。
    したんだけど、アクセス権がないからか、うまくいかなかった。
    アクセス権を付けたが、s110.cの生成がうまくいかなかった。
    どうもサブフォルダに出力できないっぽいので、あきらめてカレントディレクトリで生成するようにして、手動でコピーした。

    何をしているかというと、どうもHEXファイルをバイナリ(C言語の配列)に置き換えるようなので、毎回焼くようなことになりそうだ。
    それに、Makefileを使うわけでもないようだ。

    うーん、今の私では、あまりメリットは感じないため、採用は見送ろうと思う。
    「ここがいいよ」みたいなものがあったら、また考えよう。