2014/09/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/09/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/09/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/09/22

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

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

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

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

     

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

     

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

    2014/09/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/09/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/09/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を使うわけでもないようだ。

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

    [ble]nRF51822の開発環境を思い出す(2014/09/17現在)

    Androidを一部だけ触ったので、しばらく組込みに戻ろう。
    人間の時間には限界があるよな-。
    あれこれやるには、時間と体力と、頭がついていかん。
    それに、何もしない、という時間も必要だし。

     

    とっかかりに、何かセンサーをやろうと思った。
    ちょうど、アルコールセンサMQ-3を買っていたのだ。
    しかし買ったはよかったが、うちで駆動できそうな電源環境がなかった・・・。
    5Vでけっこうな電流がかかるようなので、ホスト側とセンサ側で別電源にすればいけるような気はするんだけど、「経費で菊水とかの安定化電源買えばいいやん」という声が聞こえてきてね。。。

    ちょっと心を落ち着かせよう。


    BLEをやろう。
    前回が、8/10くらいに書いているので、約1ヶ月くらいか。
    その間に、nRF51822のSDKがバージョンアップしているので、まずはそこから思い出そう。

    まず、nRF51822について。
    これは、NORDIC社のBLEチップで、ARM社のCortex-M0が搭載されている。
    大きさは、こんな感じ。

    image

    上が、Braveridge社の開発ボードBVMCN5102で、右側の白いのが、それだ(たぶん)。
    下は大きさの参考で、TI社のCC2540が載ったUSBドングルだ。

     

    これにデバッガとしてSEGGER社のJ-Link LITE CoretexMをつなげている。
    なお、CC2540はARMではなく、8051が載っていて、デバッガやコンパイラは私は持っていない。
    評価版以外は個人で手が出せる範囲のお金じゃなさそうだ。

     

    ハードウェア周りは、こんなところだ。


    続いて、ソフトウェア周り。

    まず、nRF51822だが、プロトコルスタックの実装とアプリの実装が別になっている。
    アプリからシステムコールで呼び出すイメージだ。
    ソフトウェア割り込みでやっているので、「プロトコルスタックだけ焼く」「アプリだけ焼く」ということができる。
    (実際はプロトコルスタックだけじゃなく、省電力のためのスケジューリングなども入っている。)
    これを、SoftDevice、と呼んでいる。

    SoftDeviceは大きく3つ有り、S110、S120、S130という名前になっている。
    これはバージョンではない。
    S110はBLEのPeripheral/Broadcaster、S120はBLEのCentral/Observer、S130はその両方。
    ただ、S120については私はダウンロードできないので、よくわからない。

    S110は、v5, v6, v7と3系統あって、これはバージョンだ。
    で、このバージョンが曲者で、先ほど「プロトコルスタックだけ焼く」と書いたが、バージョン間で互換性があまりないようなのだ。
    ソースレベルでは互換があるけれども、バイナリにないというか。
    以前はまったのが、enumの定義値が変わっていたというもの。
    SoftDeviceはHEXファイルで提供されるので、こちらとしては焼くだけしかできない。

    自分が作ったアプリがそれによってビルドし直す必要があるかどうかは、リリースノートを読むしかないだろう。
    v7.0.0が出たときには「requiring applications to be recompiled」と書かれていた。

     

    コンパイラは、ARMの好きなものが選べるようだ。
    私は、nRF51のGCC環境の説明が書かれているnAN-29というアプリケーションノートにあわせた。
    まあ、趣味でやる程度だから、無料のものをありがたく使わせてもらおう。

    デバッガは、同じくnAN-29にあったEclipseを使っている。
    ただ、リセットをかけるタイミングがよくないのか、ブレークポイントがうまく動かなかったのだ(v7にしてからか?)。
    このあたりをやるとよいらしいので、そういう方はお試しを。
    Strange behaviour with nRF51822 and S110
    UART Application Problem

    あと、Em::Blocksという開発環境があり、それも使えますという説明があった。
    次回貯めそう。
    Nordic nRF51 support in Em::Blocks (with softdevice integration)

     

    SoftDeviceとアプリをつなぐ環境が必要だ。
    「nRF51 SDK」という名前で提供されている。今は、v6.1.0が提供されている。
    この辺がごちゃごちゃしているのだが、まずダウンロードできるnRF51 SDKとしては、zip形式とmsi形式が選択できる。
    たぶん、どっちでも同じだ。msiを使うと、今のファイルはbakにして、別途インストールすることになる。

    image

    なんか、えーって感じのフォルダ構成なんだけど、こういうことになる。
    前回と何が変わったのか、という比較はしやすいんだけどね。
    (あ、フォルダは"Nordic Semiconductor"から下だけね)

     

    また、nRF51 Tools、というものがある。
    これは、nRF51822などのFLASHに書込むツールなんかが入っているらしい。
    インストールしておこう。

     

    最後に、nRFgo Studioも。
    これは、私はSoftDeviceを焼くのに使っている。
    nRF51 Toolsに入っているツールでも焼けそうな気はするが、現在焼かれているSoftDeviceのバージョンも取得できるので、こっちを使った方が楽だろう。


    巷では、nRF51822ではmbedのHRM1017が有名になったけど、Braveridge社の開発キットも、Amazonで購入できてボード2枚+J-Link LITE付きで1万5千円くらいなので、なかなかですぞ。

    [android]FeliCa Lite認証アプリをアップ

    なんとか、FeliCa Lite認証アプリをアップした。
    image

    アイコンの「A」が大文字なのは・・・寝ぼけながら作ったからだ。
    もう、めんどうなので、そのままにした。
    Android 4.1以上としているが、特にそういう機能を使ってはいないはず。

    どういうアプリかというと、「FeliCa Lite-Sはこんなことできますよ」の説明だ。
    はっきりいって、このアプリが作業の役に立つとか、そんなことはない
    むしろ、NDEFなどの使い方をする人にとっては1ブロック使用できなくなるので、困るかもしれない(Lite-S)。
    説明ページは、こちら


    FeliCa Liteにも、FeliCa Lite-Sにも認証機能はある。
    Liteは内部認証といって、R/W側が「このカードは大丈夫そうだ」という認証方法。
    Lite-Sは、それにプラスして、このカードを発行した人じゃないと知らないデータをR/Wに書込むことで、Lite-SがR/W側を認証する方法だ。

    ただ、発行をきっちりやると、そのFeliCa Lite-Sカードは他の目的で使用できなくなってしまう。
    それも困るので、ゆるゆる認証にして、PAD13ロックだけは認証しないと読み書きできないようにしているし、認証の設定も書き換えられるようにしている。
    何も知らずにこれを使ってしまうと、NDEFで使用できるブロックが1つ減ってしまうことになる。

    なので、作っておいて何だが、FeliCa Lite-Sの認証を試してみたい人以外、邪魔なアプリになるのでご注意だ。

    2014/09/16

    [android]AndroidライブラリとJavaライブラリ

    Android Studioでライブラリの作り方がわからない、と書いていたら、教えてくれた。
    http://hiro99ma.blogspot.com/2014/09/androidandroid-studio_14.html?showComment=1410834685828#c2233468687230081908

    ライブラリ単独のプロジェクトじゃなくて、モジュールとして追加するのね。

    image

    ライブラリが2つある・・・。
    「Android Library」と「Java Library」だ。

    Android Library
    image

    Java Library
    image

     

    こちらによると、リソースなどもまとめられるのがAndroid Libraryで、Android ARchiveってことでaarファイルができるらしい。
    その中にjarも入るそうだ。

    Android Studio で簡単に jar をつくる手順はないのかと

    今作っているNFCライブラリはリソースを含んでないのでjarファイルでよさそうだ。
    そう思ってJava Libraryを選んでみたのだが・・・なんか、なんかだめだ。
    たぶん、Android用じゃないから、パスの設定なんかがされてないんだろう。

    あまり深く考えるのはやめ、AARというやつでやってみよう。


    NfcLib、というモジュールを追加した。

    image

    build.gradleの違いは、

    apply plugin: 'com.android.application'

    が、

    apply plugin: 'com.android.library'

    となってるくらいか。

    resフォルダなども入っているので削除し、appで使っていたJavaファイルを移動させた。
    AndroidManifest.xmlも削除したのだが、なんか「同期エラー」みたいなのが発生したので、形だけ残すことにした。

    あと「File>Project Structure...」で、appがNfcLibに依存している設定を追加。
    いるのかいらんのかわからん設定だが、依存しているのは確かだから、悪くはなかろう。

    image

    ここからがよくわからないのだが、ModuleのcleanやRebuildをやっていくと、勝手にNfcLib/build/outputs/aarの中にNfcLib.aarができていた。
    cleanしたら、作り直しているみたいだが、まあいいや。


    aarはzipらしいので解凍すると、classes.jarとAndroidManifest.xmlが入っていた。

    >jar tvf classes.jar
    
         0 Tue Sep 16 12:59:28 JST 2014 META-INF/
    
        25 Tue Sep 16 12:59:28 JST 2014 META-INF/MANIFEST.MF
    
         0 Tue Sep 16 12:59:28 JST 2014 com/
    
         0 Tue Sep 16 12:59:28 JST 2014 com/blogpost/
    
         0 Tue Sep 16 12:59:28 JST 2014 com/blogpost/hiro99ma/
    
         0 Tue Sep 16 12:59:28 JST 2014 com/blogpost/hiro99ma/nfc/
    
     23770 Tue Sep 16 12:59:28 JST 2014 com/blogpost/hiro99ma/nfc/FelicaLite.class
    
      7324 Tue Sep 16 12:59:28 JST 2014 com/blogpost/hiro99ma/nfc/NfcFactory.class
    
         0 Tue Sep 16 12:59:28 JST 2014 hiro99ma/
    
         0 Tue Sep 16 12:59:28 JST 2014 hiro99ma/blogpost/
    
         0 Tue Sep 16 12:59:28 JST 2014 hiro99ma/blogpost/com/
    
         0 Tue Sep 16 12:59:28 JST 2014 hiro99ma/blogpost/com/lites_sample/
    
       748 Tue Sep 16 12:59:28 JST 2014 hiro99ma/blogpost/com/lites_sample/BuildConfig.class

    いや、最後のBuildConfig.classなんて頼んでないんですが・・・。
    アプリと一緒にしてるから入ってくるのか。
    しかもこれ、最初にパッケージ名を付け間違えたときのパスじゃないか。。。

     

    あと、ProGuardをかけるとエラーになった。

    Error:Execution failed for task ':NfcLib:proguardRelease'.
    > java.io.IOException: The output jar is empty. Did you specify the proper '-keep' options?

    うーん、アプリの方に置いていたときは問題なかったのだが・・・。
    seeds.txtもあるが、だめなのか。


    proguard-rules.proの書き方がよろしくなかったようだ。

    -keepattributes Exceptions
    
    -keep class com.blogpost.hiro99ma.nfc.**
    
    -keepclassmembers class com.blogpost.hiro99ma.nfc.FelicaLite {
    
        public *;
    
    }
    
    -keepclassmembers class com.blogpost.hiro99ma.nfc.NfcFactory {
    
        public *;
    
    }

    こんな感じにした。
    -keepだけだとだめで、-keepclassmembersだけでもだめで、両方設定すると名前が残った。
    あと、throwsが消えてしまったので、Exceptionsも追加した。

    と、こんなに苦労してProGuardかけたけど、jadで見るとそれなりにわかるもんだな。
    まあ、資料見ながら作っただけの実装なので、そんなに隠すまでもないか、とは思うが、「できることはやった」という気分になれるし、サイズも小さくなるから、いいのだ!

    [android]setStyle()というAPIは無いようだ

    <style name="xxx">で設定を書いていけば、XMLでstyle="@style/xxx"という形で使うことができるのはわかった。

    そうそう、ListViewのフッタも同じスタイルにしないと、と思った。
    ヘッダやフッタは実装で引っ付けているので、スタイルも実装で引っ付けることになる。
    どうせsetStyle()だろう、と打ってみたが候補に出てこない。
    そう、setStyle()というAPIは無いようなのだ。


    文字色だったので、setTextAppearance()で事足りたのだが、どうも腑に落ちない。
    ネットで調べると、R.attrで参照できる形にして、Viewのコンストラクタの第3引数に設定するらしい(試してない)。
    うーん、めんどくさい・・・。

    [android]コメントを食え!

    Androidアプリの見栄えを変更するのに、スタイルやテーマというものがある。
    http://developer.android.com/guide/topics/ui/themes.html

    と書いたが、使ったことがないので調べておこう。


    上記リンクには、こう書いてあった。

    • スタイルは、Viewやウィンドウの見栄えやフォーマットを指定するプロパティの集合
    • テーマは、全Activityやアプリにスタイルを反映させたスタイル(個別のViewじゃなくて)

    というわけで、とりあえずスタイルが基本と考えてよさそうだ。


    Android Studioで新規アプリを作ったとき、こんなスタイルが作られた。

    <resources>
    
        <!-- Base application theme. -->
    
        <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    
            <!-- Customize your theme here. -->
    
        </style>
    
    </resources>

    まあ、スタイル自体については、あちこちで説明があるから調べよう。

    上記リンクを見ていくと、最後にstyles.xmlへのリンクがあった。
    https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/styles.xml

    そこに「<eat-comment />」って書いてある。
    コメントを食え?
    検索すると、ドキュメント化するときにコメントは取り除いてね、という意味だとのこと。
    http://stackoverflow.com/questions/21837986/android-xml-tag-called-eat-comment-what-is-its-use

    @hideとかもそうだけど、隠し技というか、拡張された機能は気になるものですな。

    2014/09/15

    [android]Android Studioでidを変更していると、別のidが変更された

    Windowsで、Android Studio 0.8.9を使っている。
    layoutで画面を作るとき、idが重なると面倒なので、Activity名の一部を付けるようにしている。
    MainActivityなら、@id/main_xxx、みたいな。

    さっき見ると、layoutのXML中に別のプレフィクスが見つかった。
    「酒飲みながらやってると、こういうのやるよなぁ」と思ってレイアウトエディタでidを変更すると・・・今度は別layout XMLのidが変更になった。

    むむむ・・・なんかバグってる気がする・・・。
    GUIの方で変更していると発生するけど、最初にやったときにはそんなことがなかったので、何か要因があるのかも。
    ともあれ、気をつけておくんなまし。

    2014/09/14

    [android]Android Studioでライブラリを作る方法がわからん

    わからんシリーズだ。

    NFC関係の処理をまとめているので、それをライブラリに仕立てておき、普段はソースを触らないようにしようと思っている。
    いや、それよりも、ライブラリだけ切り出して販売する、なんていうこともできんじゃろうか、という思惑がある。10月からフリーランス生活の予定なので、収入ルートを考えてないとね(現実的かどうかは別として)。

     

    Eclipseのときはjarファイルを作っていたから同じかと思っていたけど、なんか雲行きがあやしい。
    ネットで調べたページでは、プロジェクト作成ウィザードで「ライブラリにする」みたいなチェックボックスがあるんだけど、今私が使っている0.8.9にはそれがない。
    Activityの追加有無ページがあるくらいだ。追加したら、Activity名などを付けるページが出てくるだけだし、Activityの追加をやめたらそれまでだ。
    プロジェクトツリーにも「libraries」フォルダが出てくるようなんだけど、私が作ったプロジェクトだと「app」だ。

    うーん・・・できるかどうかすらわからん・・・。
    Android Studioの進化が速いせいか、ネットで情報を見つけられていない。
    簡単にできるようになるまで待つか。

    [android]L(preview)だと罫線が消える

    先日、ListViewのitemをisEnabled()でfalseを返すようにすると罫線が消えた、という話を書いた。
    http://hiro99ma.blogspot.com/2014/09/androidlistviewitemdisablelineinvisible.html

    さっき気付いたのだが、うちのNexus7(2012)では表示されているのだが、Nexus7(2013)では消えているのだ。

    2012
    image

    2013
    image

    同じAPKなのに・・・。
    そういえば、これをやっていたときも、2012と2013を行ったり来たりしてた。
    もしかしたら、あんな変更をしなくても罫線は表示されていたのでは・・・。

    こういう「バージョン違い」で現象が発生すると、もう弱気になってしまう。
    ああ、私にはAndroidは向いてないんだ・・・。


    気になったので、先日追加した罫線表示対応を外してみたところ・・・2012では表示された。
    関係なかったんだ・・・。

    Nexus7(2012)は、Android 4.4.4。
    Nexus7(2013)は、L。

    @dividerを設定してみたが、同じだ。
    表示しようとしていない、と見るのがよいか。

    image  image

    うーん、OSがまだpreviewだから、ということで放置してよいのかな・・・。

    [android]strings.xmlの管理は、けっこう面倒

    iOSの多言語対応がめんどう、というのを書いたが、Androidもそれなりにめんどうだ。
    いや、言語切替などはうまいことやってくれるし、リソースもXMLで書いておけばいいので、そこは便利だ。

    めんどうなのは、多言語のリソースを作る、という作業。
    まあ、Androidに限った話ではないんだけどね・・・。
    お仕事では、こちらのサイトのExcelファイルを使わせてもらっていて、これは便利だった。
    今回もそれを使おうと考えたけど、私が文言リソースを別ファイルにしていたので、迷った。

    特にstrings.xmlという名前限定じゃなくてよさそうなので、strings_main.xml、strings_auth.xml、みたいにActivityごとにXMLを分けていたのだのだ。
    ごちゃごちゃしなくてよいかな、と思ったんだけど、一括管理するんだったらファイルは少ない方がやりやすい。
    結局、string-arrayも含めてstrings.xmlにまとめてしまった。

    そしてExcelのマクロを書き換え、string-arrayも含めて対応することにした。
    設定の項目なんかは英語だけでよいので翻訳を作ってなかったのだが、APK作るときに「jaに翻訳がない」って怒られた。
    tools:ignore="MissingTranslation"を<resources>に追加するとよいらしいので、入れると確かに消えたが、ちょっと釈然としない。
    まあ、後で考えよう。


    そんなこんなして、すごい暫定版ながらFeliCa Lite/Litei-S認証のAndroidアプリを作った。
    https://sites.google.com/site/hiro99ma/nfc/files/freeapk/FelicaIssuancer.apk?attredirects=0&d=1

    FeliCa Lite-Sの場合、「発行」を実行すると、STATEレジスタへの更新が書込MAC必須となる。
    これが、一度設定すると元に戻せなくなるので、もしやってみるのであれば注意が必要だ。

    外部認証をやるようにしたんだけど、見た目の区別がつかない。。。
    わかるようにするなら「認証付き読み出し」「認証付き書き込み」を実装しないといかんが、はてさて。

    2014/09/12

    [android]MifareClassicクラス

    NXPにMIFARE Classicという種類のタグがある。
    これは、NFC Forumの分類Type 1~4 Tagの中には入っていない。
    入っていないのだが、値段やセキュリティがついていることから普及率はかなり高いと思う。
    NXP独自でNDEFフォーマットを決め、Android APIにもクラスを突っ込んだくらいだ。
    (このあたり、SONYさんもやっていただきたかった。。。)

    さて、FeliCa Lite-Sの認証を見ているので、どこか参考になるものはないかと考え、MifareClassicクラスに思い至ったというところだ。
    MIFARE Ultralight-Cも認証はあるんだけど、許可を得ないといかんようで仕様書の入手方法がわからん。。。


    MifareClassic
    http://developer.android.com/reference/android/nfc/tech/MifareClassic.html

    最初に断っておくと「Implementation of this class on a Android NFC device is optional」と書かれているように、このクラスの有無については端末依存だ(存在はするけど使えない、のかな)。
    使えるときはNfcAとして検出されるらしい。
    確か、Nexus7(2012)にはPN65が載っているからサポートされて、Nexus7(2013)にはBroadcomのチップが載っているからサポートされてない(NCI対応だから、の方なのかな?)。
    ざっと見たが、IOExceptionとTagLostExceptionがあるくらいで、認証失敗例外、みたいなものはないようだ。

    ただ、authenticateSectorWithKeyAとBというメソッドがあるのだが、そこのSee Alsoが気になる。
    何かあったのかもしれないが、エラーになっていてリンク先がない(android developerのページに飛ぶ)。
    http://tools.oesf.biz/android-4.4.0_r1.0/xref/frameworks/base/core/java/android/nfc/tech/MifareClassic.java
    なんだ、Javadocの書き間違えか。

    2014/09/11

    [nfc]FeliCa Lite-S実装への悩み

    Androidで、FeliCa Lite-S向けのライブラリ実装をしている。
    いろいろ、悩み有り・・・。

    まず1つだが、なんでTagTechnology#close()がIOExceptionするのか。

    Also causes all blocked I/O operations on other thread to be canceled and return with IOException

    ってのはわかるんだけど、じゃあどこでclose()したらよいの?となる。
    設計として、複数スレッドで同時にNFCを読み書きするようなことはしない方がよい(したらいかん)ってことなんだろうけど、じゃあ無視してアプリが死んでしまえばいい!
    と思ったら、これはChecked exceptionなので、throwsして上に投げるか自分で処理するしかない。
    じゃあRuntimeExceptionに変換してやればいいんだけど、なんかそれは変だと思った。

    この辺の考え方は、Linuxのclose()の戻り値がvoidなのとあわせてくれるとうれしかったな。
    そしたら、finallyに入れればよかったんだけど。。。
    実は、まだ普通に書く方法あり?

    try {
      nfcf.connect();
      nfcf.xxx();
    }
    catch(IOException e){
    }
    try {
      nfcf.close();
    }
    catch(IOException e){
    }


    上記のはまだどうでもよくて、内容として困ってるのがカードごとの対応。
    FeliCa Liteとか、FeliCa Lite-Sとか、MIFARE Ultralight Cとか、MIFARE Classicとか。

    何を困ってるかというと、認証関係だ。
    FeliCa Lite-Sでは、以下が可能だ。

    • MAC付き書込が必要なブロック
    • 認証付き書込が必要なブロック
    • 認証付き読込が必要なブロック

    特に3番目。
    これは、Read without Encryptionでエラーが発生することを意味するッ!
    具体例がないとわかりづらいので、実際にセキュリティを施してみた。
    わかってると思うけど、セキュリティ関係は不可逆なのよ~。

  • MAC付き書込が必要なブロック:11~13
  • 認証付き書込が必要なブロック:10~12
  • 認証付き読込が必要なブロック:9~11
  • image

    1ブロックずつずらしたが、読込に認証が必要なのは9~11ブロックなので、そこがまるまる読めなくなっているのがわかる。

    NFC-FやType 3 Tagの範囲内で読込のセキュリティすらかけられる、というのがFeliCa Lite-Sの魅力なのだ。
    同じことは、MIFARE Classicにも言えるが、ちょっとそのしくみは難しいと思う(だからセキュリティか。。)。

    なので、セキュリティをかけたカードは、結構エラーを返してくる。
    IOExceptionだ。
    以前の方針にあわせて、どうしようもないところ以外は吸収して戻り値で返すようにしてたんだけど、使っている側からすると「失敗」の理由がわからない。

    Exceptionの理由を文字列で返すと、ライブラリとしては気持ちが楽なんだけど、アプリとしては「えっ、今そんな告白されても」みたいな気持ちになるだろう。
    やっぱり、エラー番号をそのまま返すか、getLastError()方式にするしかないのか。
    今までの私は、後者をよく使っている(後付けが楽だから)。


    以前調べて、ブログとかにも書いてはいるのだが、MIFARE ClassicはNFC Forumの範疇から外れたアクセス方法になるため、Android端末にNXPのチップが搭載されているときしか使えない(のだと思う)。実際、Nexus7(2012)はPN65だから使えるけど、Nexus7(2013)はBroadcom(型番わからん)だから使えない。

    って書いて、「そういえばClassicってAndroid標準にあるやん!」と気がついた。
    セキュリティ有りのカードについては、これを目安にするとよいのかな。


    ともあれ、FeliCa Lite/Lite-S、MIFARE Classicのセキュリティ機能は「普通に」NFCアクセスするときに使うものではない。
    一度その設定をすると、カードはだいたい元に戻せないので、そのセキュリティを施したまま生きていくことになる(Classicは戻せるのかな)。

    MIFARE Classicが魅力的なのは、容量が大きいのにセキュリティ機能が標準で存在しているところだろう。
    おそらく日本国内でも、セキュリティ付きのカードとしてかなり数多く提供されてるんじゃなかろうか。
    NFC-Aではあるので、MifareClassicクラスを使わなければ読めるのかも。

    のんびりではあるが、来週中には「FeliCa Lite-Sはこんな感じですよー」のアプリを作りたいものだ。

    [android]ListViewのitemをdisableにするとlineがinvisibleだ

    がんばって英語を多用してみました。。

    前の記事で、ArrayAdapter#isEnabled()をオーバーライドする件を書いたが、あれをやるとそのアイテム前後の罫線が消えてしまうのだ。

    image

    これは、Viewに対しては何もしてないのだ。
    もしかして、disableだから罫線もいらんでしょう?ってことだろうか。
    罫線を含めてitemだからかなl。

    おっと、いつもの私なら、もうAndroidわからーん、で投げてしまうのだが、少し経験値がついた。
    こういうときは、罫線のカスタマイズの方法を調べてみるとよいのだ。
    そうすると、android:dividerって項目らしい。
    これで検索すると出てきた。

    http://stackoverflow.com/questions/5375138/disappearing-divider-in-listview-when-arrayadapter-isenabled-returns-false

    areAllItemsEnabled()でtrueを返すようにするとよい、か。
    これなら簡単だ。
    よかったよかった・・・・あれ、変わらない。
    呼ばれていないわけではないのだが、trueを返してもfalseを返しても、何も変わらない。

    呼ばれるのは、HeaderViewListAdapter#areAllItemsEnabled()からだ。
    Headerとついているのが、なんか嫌な予感がする。

    HeaderとかFooterがついている場合はこっち、ということだ。
    確かに今回、ヘッダはないけどフッタは付けてるんだった。
    http://java.dzone.com/articles/android-listview-%E2%80%93-fixing
    ぐわあ、実装が増えるな。

    //罫線は出したい
    
    ListView.FixedViewInfo footerInfo = listView.new FixedViewInfo();
    
    footerInfo.view = footer;
    
    footerInfo.isSelectable = false;
    
    ArrayList headers = new ArrayList(0);
    
    ArrayList footers = new ArrayList(1);
    
    footers.add(footerInfo);
    
    HeaderViewListAdapter wrapper = new HeaderViewListAdapter(headers, footers, adapter) {
    
        @Override
    
        public boolean areAllItemsEnabled() {
    
            return true;
    
        }
    
    };
    
    listView.setAdapter(wrapper);

    image

    やれやれだぜ・・・。

    あと、サンプル通りに書くと、ArrayList#add()を呼ぶところで「unchecked」って出てくる。
    どうも、型チェックが働かんぞ、と言っているらしいので、

    ArrayList<ListView.FixedViewInfo> headers = new ArrayList<ListView.FixedViewInfo>(0);

    こんな感じにすると消えた。

    [android]ListViewで一部をグレーにしようとしたが、先頭もグレーになった

    ListViewでメニューを作ったけど、まだ2番目と3番目が未実装なので、押せないようにした。
    それはArrayAdapterのisEnabled()を乗っ取ればよかった。
    しかし文字色が変わらなかったので、そのときだけ文字色をグレーにしようとした。

    @Override
    
    public View getView(int position, View convertView, ViewGroup parent) {
    
        TextView view = (TextView)super.getView(position, convertView, parent);
    
        ListData item = getItem(position);
    
        if ((view != null) && (item != null)) {
    
            view.setText(item.title);
    
            if ((position != 1) && (position != 2)) {
    
                //view.setTextColor(Color.BLACK);
    
            }
    
            else {
    
                view.setTextColor(Color.LTGRAY);
    
            }
    
        }
    
        return view;
    
    }

    これだと、なぜかリストの先頭もグレーになってしまうのだ。
    コメントアウトしているBLACKのところを有効にすると、大丈夫。
    うーむ。

    isEnabled()を元に戻してみたが、変わらず。
    じゃあ、真ん中だけグレーにしたらどうなる?とやってみると、先頭と3番目がグレーになった。
    どっかでViewが使い回されるから、デフォルトじゃない値を入れるときは、そうじゃないときはデフォルトの値を指定するようにすべきなのかね。

    Android StudioがうちのWin8.1(32bit)+2GBメモリでヒープが足りんらしい

    うちには、デスクトップPCとノートPCがある。
    ノートPCはThinkPad T61で、発売は2007年らしい。
    ブラウザで見るくらいだし、開発もテキストエディタとかTeraTermとかが動けばよいので、そんなに困ってない。
    eclipseも、設定値を変更すれば起動するし。
    SSDにしたので、デスクトップPCよりも快適なくらいだ。

    が、Android Studioがうまくいかない。。。
    起動はするのだが、プロジェクトを立ち上げて、Gradleのビルドのくるくるが終わるくらいになると、「not enough heap」みたいなエラーが出て、エディタも開けない。
    Xmxとか変更したけど、変わらん。
    「あんまり俺に無理させるなよ、ごほごほ」みたいな感じもするし。


    GUIが無理ならコンソールでやればいいじゃないの、という声が聞こえてきた。
    そうか、それがあったか。
    動いている方のWindowsで試しておこう。

    > gradlew clean
    > gradlew build

    ビルドしたものは、app\build\outputs\apkに入っているようだ。
    cleanすると、outputsフォルダごと消えていた。
    あとはadbでインストールしたりすればよいのかな。

    ブレークポイントを設定してのデバッグができんとつらいだろうが、まあいいや。

    2014/09/09

    [java]符号無し演算にはまる

    プロトコル解析するときは、だいたい符号無し1byteで扱っていって、必要があれば符号有りにしたりすると思う。
    いつも忘れるのだが、Javaは符号無し、が無い。
    "byte"すらも、符号付き1byte型だ。
    なんとなく話の方向の想像がついただろうが、まあ書かせておくれ。

     

    C#で書いて動いているFeliCa Lite-Sの相互認証処理を、Androidに移植している。
    実装は終わってデバッグしているのだが、どうにもMAC(W)計算が合わない。
    半日あれこれ調べたところ、書込カウント値が正しく計算できていないことに気付いた。。

    Lite-SからはMACが強化されて、書込カウント値を使うようになった。
    これが24bit(3byte)ある。
    Read without EncryptionでWCNTレジスタを読込み、その中の3byteを整数変換するだけだ。
    C#では、こんな感じで書いている。

    int wcnt = rbuf[0] | (rbuf[1] << 8) | (rbuf[2] << 16);

    rbufはbyte[]なんだけど、C#のbyteは符号無し1byteだ。
    だから、ビットシフトしても符号無しのままでいてくれる。

    ええ、Javaでも同じように書いてますよ。
    このときのrbufは、こんな値だった。

    rbuf[0] = 0x85
    rbuf[1] = 0xFE
    rbuf[2] = 0xFF

    リトルエンディアンなので、0xFFFE85、という値になることを期待していた。
    していたのだが、Javaでは0xFFFF85になっていたのだ!
    なぜなぜ??

    デバッグのため、int aaにrbuf[0],、bbにrbuf[1] << 8、ccにrbuf[2] << 16を突っ込んで確認した。

    image

    1byteの符号付き0x85が、符号付きint型に拡張される際に、最上位ビットが立っているので「これはマイナス値だ!」と判断して、そっから先のビットを全部1にしてしまったのだな。。。

    Cでたまにやらかすので、心配せんでいいように符号無しで扱う習慣なんだけど、Javaだと記述で解決せんといかんのか。

    int wcnt = (rbuf[32] & 0x0000ff | (rbuf[33] << 8) & 0x00ff00 | (rbuf[34] << 16) & 0xff0000) & 0xffffff;

    ビットシフトして型が大きい方に膨らむ場合は、ほしい分だけ論理積を取るのが安全か。
    小さい方に代入するときは勝手に消えるからいいだろう。
    まあ、byte型の-1をint型にキャストして255になったら困るけど、それならunsignedがほしくなる。


    大刷新リリース Java 8の新機能 - 符号なし整数のサポート
    http://news.mynavi.jp/special/2014/java8/011.html

    おおおお?
    とうとうunsignedが使えるようになるんだ!
    ・・・と思ったが・・・・・・

    Integer.toUnsignedString(a)
    あれ?
    こっちも「Unsigned Integer API」って書いてる。
    http://www.informit.com/articles/article.aspx?p=2216988&seqNum=2
    違うんだ、私がほしいのは"unsigned"なんだーー

    [android]Fragmentに手を出して良いものか・・・

    Android Studioで値を見るとデフォルトで10進数になるようだ。
    切り替えるのが面倒なので、デフォルトを16進数にできないものかと思いつつ、今日も勉強中です。

     

    AndroidやJavaのわからんことを書いているが、心優しき人々がコメントをくださる(全然関係ないけど、なんでサマリア人は「よき」がつくんだろう?)
    ありがたく読みながら、お勉強している。

    さて、今回はFragment。
    「NFC関係はFragmentに書いて、Activityのサイクルとは切り離している」とのコメントが。
    名前は聞いたことがあるけど、そもそもFragmentが何かわかってないので、とりあえずそこだけ調べて、私が手を出せるものか考えよう。


    ネットでFragmentを調べて、心惹かれるキーワードだけ書いてみよう。
    やる気が出るかもしれない。

    • タブレット端末とスマートフォン端末で表示を切り替えやすくなる
    • 複数のFragmentを合成してActivityを作ることができる
    • ロジックとUIを分けることができる

    惹かれるような、そうでもないような・・・。
    たぶん、「ボタン押す→何か動く」くらいのアプリしか作ってないからだろう。
    ロジックっちゅうロジックは、全部ライブラリに突っ込んでるからなぁ。

    わかりやすいスライドがあった。

    あー、再利用かー。
    あんまり画面作るの好きじゃないので、一度作ったら使い回せるとうれしいけど、そんなイメージかいな?
    あるいは、あれこれ悩まず、とりあえずやってみたらわかるようなものか。


    今作っているアプリで、唯一Fragmentが使われている画面がある。
    PreferenceFragmentだ。
    どっかのサイトに「PreferenceActivityじゃなくてPreferenceFragmentを使う場合」ってのがあったので、まねしてみたのだ。

    短いので、貼ろう。

    public class SettingsActivity extends Activity {

        public static final String PREF_MASTER_KEY = "pref_master_key";
    
        @Override
    
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
    
            getFragmentManager().beginTransaction().replace(android.R.id.content, new PlaceholderFragment()).commit();
    
        }
    
        public static class PlaceholderFragment extends PreferenceFragment {
    
            @Override
    
            public void onCreate(Bundle savedInstanceState) {
    
                super.onCreate(savedInstanceState);
    
                addPreferencesFromResource(R.xml.preference_settings);
    
            }
    
        }
    
    }

    関係するのはonCreate()の2行目と、static classなPlaceholderFragment。
    Activityは、PreferenceActivityじゃなくて普通のActivity。
    static classになっているPreferenceFragmentってのが、Fragmentだろう。
    それをnewして置き換えるように書かれているところが「複数のFragmentを集めて1つのActivityを作る」というところの一端なんだろう(ここではFragmentが1つしかないので)。

     

    Activityっていう動物園があって、そのなかにゾウたちのFragmentとかトラたちのFragmentとかがそれぞれ入っているようなイメージなのかな(なんで動物園なんだ・・・)。

    2014/09/08

    NFCとFeliCaとおサイフケータイ

    Nexus5買おうかなあ、などと思っているくらいなので、iPhoneはあまり興味がないのだが、NFCが扱えるとなると話は違ってくる。
    前回はもごもごと書いたけど、なんか、iPhone6だかiWatchだかにNFCが載るとか載らないとかってことになっているので、ちょっと整理しよう。
    またしても記憶の範囲で書くので、容赦なく突っ込んでいただければと。

    まず、「NFC搭載」となったとき、どういう端末が出てくるか、いくつかパターンを出してみよう。
    1. NFC Forumの内容だけを搭載
    2. Type-A, Type-Bが使えるけど、FeliCaが使えない(ISO/IEC-14443)
    3. NFC-A, NFC-Fが使えるけど、NFC-Bが使えない(ISO/IEC-18092)
    4. SEが端末搭載型
    5. SEがSIM搭載型
    まあ、まだあるだろうけど。

    1番が、最も「NFC搭載」って感じがするかもしれないけど、おそらくみんなが期待している動作を一番やらないだろう。
    Nexus7とかが、これに近いのかな。
    現在、私が読むことができるNFC Forumの技術仕様書には、セキュリティのことは含まれていない。
    だから、NFC Forumの内容「だけ」となると、セキュリティを扱った機能を持てないことになる(NCIにNFCEEってのがあり、それがSEとのアクセスになるっぽい感じはするが、規定はなかったと思う)
    タグにタッチしたらブラウザが起動したとか、Android Beamとか、Suicaの残高が読めるとかは、ここの範囲でできる。
    ただ、意外かもしれないが、HCE(Host Card Emulation)はここに入る。
    CPUが介在せずにNFCチップが直接セキュアなメモリとやりとりするのが今の主流なんだけど、HCEはCPUを介在するので、ハードウェアのセキュアなメモリがいらない。
    「セキュリティを扱った機能を持てない」と書いたが、それはNFC Forumが技術仕様書として書く範囲であって、そこに書かれた範囲でセキュリティのかかったデータを取り扱うことについては規定がない。データだから好きにすれば、だろう。
    そういう意味では、HTTPSで通信してるから安全、というのとあまり違いはないような気はする。
    問題は、HTTPSみたいにユーザの目に見える形でセキュアさがわからないことかな。

    2番は、海外の端末にありそうな気がする。
    このタイプの端末は、きっと4番や5番の端末だと思う。

    3番は・・・そういう端末が想像できない・・・。
    Type-AとかBは、ISO/IEC-14443での呼び方(たぶん)で、NFC-A, B, FはNFC Forumの呼び方。
    ISO/IEC-18092ではそういう呼び名がなく、106kbpsの~、とか、212kbpsの~とかいう書き方になっている。
    まあ、売られてないだろう。

    4番と5番が、海外でNFCが搭載された端末の一般的なタイプじゃなかろうか。
    1番で「NFC Forumにはセキュリティが含まれてない」と書いたが、NFCでセキュリティ的な部分はだいたいSE、Secure Elementが持っている。
    普通、携帯電話でデータとデバイスがあると、メインのCPUがデータを取り扱って、デバイスに書いたり読んだりする。
    SDカードに入っているファイルをネット上にアップするとき、SDカード用のチップがネットワークのチップと直接やりとりしたりするわけではなく、一度CPUがデータを吸い取って、それをネットワークのチップに書き込むようなものだ。
    しかし、SEはNFCチップと直結していて、CPUとはつながっていない。
    だから、どんなにソフト上でアクセスしたくても、NFCチップにアクセスできなかったら何もできない。
    これが「Secure」のゆえんだと思っている。
    image

    SEは、FLASHメモリみたいな感じで端末の中に置く場合と、電話帳みたいにSIMに置く場合がある。
    端末の中にあると、NFCチップとは直接つながっているので、アクセスが速い。しかし、搭載していないとアクセスできない。
    SIMの中にあると、SIMチップとは通信をしてやりとりしないといけないので、アクセスは遅い。しかし、SIMは差し替えたり書き換えることができるので、拡張性がある。
    例えば、私が持っている携帯電話のP906iは、モバイルFeliCaチップというNFCのチップと、基板上にFeliCaのSEが載っている。
    だから、SEの中にSuicaやEdyなどが入っていれば、それを使うことができる。
    しかし、NFC-AやNFC-Bの読み書きができないので、それ以外のことはできない。
    その逆も然りで、SEにFeliCaが載っていなければ、それを使うことができない。
    また載っていたとしても、NFC-Fの読み書きができないとアクセスできないし、アクセスできたとしてもFeliCaのSEとお話しできるアプリがなければ、何もできない。
    上記の絵で言えば、日本内でFeliCaが搭載された携帯電話を使う場合には太陽のルートになるけど、FeliCaが搭載されていない場合や、FeliCaが搭載されていても相手がFeliCaに対応していないなら、鬼のルートになる。
    NFCチップにしてみれば「自分が知らない人とお話ししてはいけません」ということだ。


    ようやく、ここで本題に戻ろう。
    「NFC搭載」となったとき、じゃあその端末ではどういうことができるの?まで確認しないといけない。
    上に書いた1~5は、どれも「NFC搭載」だからだ。
    FeliCaが使えるかもしれないし、おサイフケータイが使えるかもしれない。使えないかもしれない。
    「NFC搭載」を謳ったときに言えるのは、13.56MHzで近接通信しますよ、ということくらいか。
    それだと何だかわかりにくいので、NFC Forumで規格を作って・・・という話に戻っていく。
    iPhoneがFeliCaのSEを載せるかというと、載せないような気がする。なんとなく。
    かといって、SIMのSEかというと、うーん。
    でも、端末にSEチップを載せるっていうのも、あんまりAppleらしくない気はする。
    それならまだSIM搭載か、HCEか。
    読んでたサイトの中で、予想として「2段階認証にiWatchのNFCを使うのでは」というのがあった。
    http://jp.techcrunch.com/2014/09/08/20140907iwatch-payments/
    真偽は知らんが、通帳と印鑑は別々に管理しましょう、ということか。
    とりあえず私がなんとなく思うのは「iOSは、ユーザにはNFCに直接アクセスするAPIを提供しないだろう」ということかな。
    外れてほしいんだけどねー。

    [android]ProgressDialogのsetMessage()は、なんでresidがないんだろう?

    純粋な疑問だ。

    NFCのタグを待っている間、くるくるを出そうと思った。
    サンプルを見ると、setTitle()やsetMessage()に文字列を設定している。
    まあ、サンプルだからそういうもんだよな、とR.string.fooみたいなのを設定すると、setTitle()はいけるのに、setMessage()はエラーになった。

    そういう実装なんだから、仕方ないと言えば仕方ないんだけど、なんでだろう?
    show()なんかも、ことごとくCharSequenceを引数に取ってるし。
    そういえば、AndroidはいつからかBuilderで作るようになってたな、と思い出した。

     

    ProgressDialog.Builder builder = new ProgressDialog.Builder(this);

    こんな感じでやっていくと、setMessage()もresidを受け付ける。
    よしよし、と、最後にcreate()でProgressDialogにキャストし、SPINNERの設定をさせた。
    さて、実行!

    ・・・キャストできません、と落ちた。
    キャスト失敗って動的な例外なんだ、という感想はさておき、なんでだめなんだろう?
    ProgressDialogはAlertDialogの派生だから、キャストしても悪くなさそうなのに。
    (だから静的にはエラーが出てないんだろうけど。)

    使いたければ使えばいいし、カスタマイズするなら自分でやればいいじゃないの、というスタンスなんだろうか・・・。

    [android]基底クラスで今のActivity名を知りたい

    NFC関係の画面を作っているのだが、いくつか作っていると、だいたいどの画面でも同じようなことを書いていることに気付いた。
    onResume()でenableForegroundDispatch()して、onPause()でdisableForegroundDispatch()して、あとはインテントが飛んできたときに処理する・しないを書いて・・・。

    えーい、こういうときはActivityの派生クラスを作って、そこにまとめてしまおう。
    abstractでextends Activityなクラスを作って処理をまとめた。

    それはよかったのだが、「このActivityのときはやらないけど、それ以外ではやる」というのがあった。
    タイトルバーをタップしたときに、一番上のActivityに戻る処理だ。

    if (!getLocalClassName().equals(MainActivity.class.getSimpleName())) {
    
        getActionBar().setHomeButtonEnabled(true);
    
        getActionBar().setDisplayHomeAsUpEnabled(true);
    
    }
    Activityが提供しているのが、一番下のクラス名を返すAPIだったので、それにあわせている。
    同じActivity名で別パッケージが存在すると区別はつかないのだが、まあこれでいいや。

    2014/09/07

    [android]<string>の中に@stringが書けるんだ

    Androidで設定画面を作っていた。
    もう、ネットがないとまったく何も作れないレベル・・・。

    それはともかく、設定なので、値がある。
    これは、SharedPreferenceでよい。
    その初期値をどうやって設定すればよいか悩んでいた。

    ListPreferenceでやってるのだが、中にandroid:defaultValueを書いておくと、それが初期値になると言うことはわかった。
    しかし、設定画面を呼ばずに使うこともあるので、未初期化の値があれば初期値を設定したい。
    そんなときは、

    PreferenceManager.setDefaultValues(this, R.xml.preference_settings, true);

    みたいに書けばよいこともわかった。

    何を悩んでいたかというと、defaultValueの設定が文字列だったことだ。
    ListPreferenceで画面に見せる値はandroid:entriesで、実際に設定する値はandroid:entryValuesに書いていて、それらは@arrayで指定している。
    だけど、defaultValueに設定するのは文字列なので、「@arrayの一番上」みたいな指定ができないようなのだ。
    かといって、このXMLの中に直接文字列を書くのも、格好が悪い。
    じゃあ、@stringの方に「デフォルト値」みたいな文字列をわざわざ用意するというのも、あまりきれいでない気がした。
    もし@arrayの値を書き換えてしまったときに、デフォルト値への反映をし忘れそうな気もする。

    ああもう!とやけになって、<string-array>の中に@string形式で書いたら、あら、動くやん。

        <string name="felica_key1">xxyyzz</string>
    
        <string name="felica_key2">112233</string>
    
        <string name="felica_key3">aabbcc</string>
    
        <string-array name="felica_master_keys">
    
            <item>@string/felica_key1</item>
    
            <item>@string/felica_key2</item>
    
            <item>@string/felica_key3</item>
    
        </string-array>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    
        <PreferenceCategory
    
            android:title="@string/settings_category_id">
    
            <ListPreference
    
                android:key="pref_master_key"
    
                android:entries="@array/settings_master_key"
    
                android:entryValues="@array/felica_master_keys"
    
                android:defaultValue="@string/felica_key1"
    
                android:title="@string/settings_master_key"
    
                android:dialogTitle="@string/settings_master_key" />
    
        </PreferenceCategory>
    
    </PreferenceScreen>

     

    いやー、まだまだわかってないですな、私・・・。

    [android]ForegroundDispatchだけやりかった

    enableForegroundDispatch()を呼ぶと、そのActivityに対してNFCのintentが飛んでくる。
    私がやりたかったのは、ボタンを押したときだけintentを受けとって、それ以外は受けとりたくなかった。
    が、だからといって、他のアプリが立ち上がってきても嫌だ。
    つまり、ForegroundDispatchはするけど、intentを飛ばしてほしくない、ということをしたかった。

     

    よくわからんなりにいろいろやってみたが、最後は「intentが飛んでくるけどアプリで捨てる」ということにした。。。
    だって、どうやってもダメやったけん・・・。

    「タグが見つかった!」というときの音がするので、ユーザにToastなどで違うということを説明せんといかんのはあるが、まあ、それはそれでよいか。