2014/10/30

[nrf51]BLEスタックのイベントハンドラを見る (2)

では、nRF51822で作ったサンプルのイベントハンドラの中身を見ていこう。
私のわかる範囲で、になるから、期待しないよう。


BLE_GAP_EVT_CONNECTED
BLE_GAP_EVT_DISCONNECTED

これは、ワンセットでよいだろう。
サンプルはPeripheralなので、以下の図のタイミングで通知されると思う。

image

 

Connection状態になったら、m_conn_handleをハンドル値で更新しているし、Standy状態になったら無効値にしている。
Standby状態になったら、すぐにAdvertising状態に遷移し、Advertisingを始めているようだ。


ここで、もう行き詰まった。
これ以外のイベントは、nRF51 SDKのドキュメントを読んでも意味がわからないからだ。

しかし、イベントのenum値をネットで検索すると、わかりやすい説明が出てきた。
説明はdevzone.nordicsemi.com、つまりnRF51の元だ。
なんでインストールしたSDKよりも説明がわかりやすいんだー!

わかりやすいというか・・・このドキュメントがないと、BLE仕様と実装との関連づけができないような気がする。
リンク名からすると、4.3.0のようなんだけど、Nordicのサイトからはもうダウンロードできないようなのだ。。
あきらめて次回からは、サイトの情報を見ながら読んでいくか。

2014/10/29

[html]innerHTMLは、中の要素だけ書き換えられる

苦手なものは色々あるが、とにかくスクリプト言語は勝手がわからないので苦労する。
ちょっとHTMLとかJavaScriptとかを触らないといけないようになり、慌ててやっているところだ。

ありがちなのかもしれないが、ボタンを押すとHTMLの中身を書き換える、というような要求があった。
ああ、書き換えたHTMLファイルを作って、それを読込ませるようにせんといかんのか、と思っていたのだが、そういうことはやらず、innerHTMLなるもので一部の書き換えができるようなのだ。
ほほぅ(←初心者の証)!

 

しかし、哀しいかな初心者。
innerHTMLでどこがどう書き換えられるのかがわかっていない。。

image

"kuma"の適用範囲は、こう。

image

要素の内容だけなのだ。

なんでこれを勘違いしていたかというと、こうやって意図通りに動いたからだ。

image

「よく理屈はわからないが、タグを同じにしておけば自動的に置き換えられるんだ!」と理解していたのだな。
無知って怖い・・・。

 

現在表示されているブラウザ画面が、どういう解釈の元に表示しているかがわかればよいのだが、表示しているソースを見ても自分で書いたものが出てくるだけでわからん。

と思ったら、Firefoxだと「インスペクタ」で見ることができた。

image

こういう、何をしたらどうなる、とか、こうしたいときはだいたいどうする、という材料を持っていないのでイライラするんだろうな。

2014/10/26

[nrf51]BLEスタックのイベントハンドラを見る (1)

まだまだサンプルソースの解読中だ。
避けて通れないBLEの部分にさしかかっている。

パラメータ設定などを眺めていたが、その設定が必要かどうかになると、途端にわからなくなる。
そういう眺め方では進まないので、「今のソースは正しい」と考え、こういう処理をするようになっているのは、このパラメータが設定されているためだろう、という読み方に切り替えた。

そうなると、BLEスタックのイベントハンドラを読まねばなるまい。
softdevice_ble_evt_handler_set()で登録している関数だ。


私のI/Oサービスサンプルでは、こんな感じになっている。

    ble_evt_handler(p_ble_evt);
    ble_conn_params_on_ble_evt(p_ble_evt);
    //I/O Service
    ble_ios_on_ble_evt(&m_ios, p_ble_evt);

ble_evt_handler()は、自分の中でイベントを処理する関数。
ble_conn_params_on_ble_evt()は、SoftDevice側なんだが・・・nRF51 SDKのドキュメントでひっかからない。
S110のところが、ほとんどドキュメント化されていないような感じがする(doxygenで生成させると出てくる)。


ble_evt_handler()も、ほとんどサンプルで作られている。
switch-caseで処理されている。

イベント値には範囲があり、以下のようになっている(ble_ranges.h)。

  • BLE_EVT_xxx : 0x01-0x0F
  • BLE_GAP_EVT_xxx :  0x10-0x2F (ble_gap.h)
  • BLE_GATTC_EVT_xxx : 0x30-0x4F (ble_gattc.h)
  • BLE_GATTS_EVT_xxx : 0x50-0x6F (ble_gatts.h)
  • BLE_L2CAP_EVT_xxx : 0x70-0x8F (ble_l2cap.h)

 

サンプルソースでは、BLE_GAP_EVTとBLE_GATTS_EVTだけ対応している。
全部のイベントではなく、必要そうなところだけやっているようだ。
GATTSは、GATTのServerで、今回のServiceがServerだからだろう。

  • BLE_GAP_EVT_CONNECTED
    • Connection established
    • Connect LED点灯
    • Advertising LED消灯
    • ボタンの使用を許可
    • m_conn_handlerを渡された値に更新
  • BLE_GAP_EVT_DISCONNECTED
    • Disconnected from peer
    • Connect LED消灯
    • ボタンの使用を禁止
    • m_conn_handleを無効値に更新
    • Advertising開始
  • BLE_GAP_EVT_SEC_PARAMS_REQUEST
    • Request to provide security parameters
    • sd_ble_gap_sec_params_reply()してる。
      m_sec_params()を返しているのだが、なんだろうか?
      sec_params_init()で設定してはいるのだが。
  • BLE_GAP_EVT_SEC_INFO_REQUEST
    • Request to provide security information
    • sd_ble_gap_sec_info_reply()してる
  • BLE_GAP_EVT_AUTH_STATUS
    • Authentication procedure completed with status
    • m_auth_statusを更新している(static変数)
    • この値は、BLE_GAP_EVT_SEC_INFO_REQUESTで使われる
    • ということは、BLE_GAP_EVT_AUTH_STATUS→BLE_GAP_EVT_SEC_INFO_REQUEST、の順か
  • BLE_GAP_EVT_TIMEOUT
    • Timeout expired
    • タイムアウトの種別がBLE_GAP_TIMEOUT_SRC_ADVERTISEMENTだったら、Advertising LEDを消灯してシステムOFFになる。
    • システムOFFの関数を呼ぶと、もう戻ってこないらしい。
  • BLE_GATTS_EVT_SYS_ATTR_MISSING
    • A persistent system attribute access is pending, awaiting a sd_ble_gatts_sys_attr_set()
    • sd_ble_gatts_sys_attr_set()してる
  • default
    • 何も無し


CONNECT、DISCONNECTはわかる。
TIMEOUTも、だいたいわかる。
しかし、それ以外が理解できてない。

次回は、もう少し中身を掘り下げよう。

2014/10/25

[Tool]とりあえずdoxygen

「とりあえずビール」みたいなイメージで。
仕事などで、いきなりソースファイル一式をもらったとしよう。
どっから手を付けるか、途方に暮れることもあるだろう。
そういうときは、doxygenというツールで、とりあえずドキュメント化してみると良いかもしれない。
少なくとも、何もせずに手をこまねいているよりは良いのではなかろうか。

今回はcygwinでやってみよう。
いろいろなプラットフォームで動作するが、やり方はあまり変わらないだろう。
まずはインストール。
cygwinだと、setup.exeなどで出てくる。
このとき、doxygen本体だけでなく、graphvizもインストールしておこう。
graphvizというのは、グラフを作ってくれるツールで、doxygenからincludeグラフや関数呼び出しグラフ、クラス図などを生成してくれるのだ。
名前はgraphvizなんだけど、実行ファイル名はdotだ。
(追記)今のところ、フォントが解決できなかった。アルファベットですら□で表示されてる。cygwinじゃなくてWindows版の方がよさそう。
structble__advdata__manuf__data__t__coll__graph
インストールできたら、まずは対象となるソース一式の一番上のディレクトリでコンソールなりターミナルなりコマンドプロンプトなりを開こう。
doxygenは、設定ファイルに従ってドキュメントを作るようになっている。
なので、まずは設定ファイルを作らないといけない。
が、安心してほしい。
doxygenは設定ファイルのひな形を生成してくれるのだ。
$ doxygen -g
こうすると、Doxygen、というテキストファイルを生成する。
あとは、このファイルをいじって、実行するだけだ。
$ doxygen [設定ファイル名]
そんなに難しくない。

ただ、設定ファイルがデフォルトのままだと、ほとんどドキュメントを生成してくれないだろう。
私がC/C++をメインで作業しているので、C/C++でとりあえず何でもかんでもHTMLドキュメントに吐く設定を書いておこう。
  • PROJECT_NAME
    • あまり気にしなくて良い。ドキュメントのタイトルに出てきたりする程度。
  • OUTPUT_LANGUAGE
    • デフォルトはEnglishだが、気にならなければそのままで良いだろう。
  • EXTRACT_ALL
  • EXTRACT_PRIVATE
  • EXTRACT_PACKAGE
  • EXTRACT_STATIC
    • とりあえずYESで。その付近に展開してほしいものがあれば、それもYESで。
  • RECURSIVE
    • YESで。
  • INPUT_ENCODING
    • 必要に応じて変更。生成結果が化けていたら考えるくらいでよいだろう。
  • GENERATE_TREEVIEW
    • なんとなくYESに変更してる。
  • GENERATE_LATEX
    • TeX知らないので、NO
  • HAVE_DOT
    • これがgraphvizを使うかどうかの設定。YES。
  • CALL_GRAPH
  • CALLER_GRAPH
    • YESで。

とりあえずこうやっておくと、何かはできる。
CALL_GRAPHやCALLER_GRAPHがYESだと、けっこう時間がかかるし、できるファイルも大きくなる。
そこら辺は、様子を見て変更すると良いだろう。

[nrf51]nRF51初期化のまとめ方

advertising_init()で、デバイス名があるだのないだの、あるならshortだのcompleteだの、ということを書いた。

しかし、だ。
そのデバイス名の設定は、gap_params_init()で行っているのだ。

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

遠すぎやしないかい?

また、advertising_init()ではサービスのUUID設定も行っている。
SCANのRESPONSEにいるんだけど、なんかそうなるとservices_init()が寂しく感じる。

この辺の初期化は、ble_stack_init()でまとめてしまっても良いのではないだろうか。
まとめた方がというか、まとめないと訳がわからなくなってしまいそうな感じがする。
あんまり1関数のステップ数が多くなると見通しが悪くなるのはわかるけど、わかりやすくなるんだったら1万行あっても1関数にまとめてしまっていいんじゃないの、って思ってる。

 

nRF51822は、Cortex-M0が搭載されたチップ、というだけの目的で使うこともできる。
が、BLEを使う前提でないとこのチップは使わないだろう。
ならば、BLEを使うように書いた方がよいのだと思う。
そして、それを自分で行うために、時間をかけてソースを眺めているのである。

2014/10/23

[nrf51]BLE_ADVDATA_FULL_NAMEとはなんぞや

nRF51822サンプルを読み進めているが、ようやくBLEにたどり着いた。
まずは、Advertisingだ。


ble_advdata_set()を使って初期化するのだが、何をやってるのかよくわからない。
nRF51 SDKのHTMLドキュメントでは、右上の検索ボックスでもひっかからない。doxygenコメントは付いているのに・・・。

第1引数も第2引数もble_advdata_tのポインタを渡す。
最初がadvertisingのデータ、次がscan responseのデータ。
やってることは、第1引数がNULLでなければ、チェックしてエンコード。第2引数がNULLでなければ、チェックしてエンコード。エンコードした結果を使ってsd_ble_gap_adv_data_set()を呼び出す。

つまり、sd_ble_gap_adv_data_set()が本当にやりたい内容なんだけど、使うのが面倒だろうからということでラッパというか便利関数が用意されているというところだろう。


便利関数は良いとして、どういう値を入れるとどうなるのかは把握しておきたい。

いきなりつまずいたのが、これ。

advdata.name_type = BLE_ADVDATA_FULL_NAME;

なにがフルネームなんだろう?
enumで、他にNO_NAMEとSHORT_NAMEがあった。

調べたところ、AD Typeの、0x08 : <<Shortened Local Name>>か、0x09 : <<Complete Local Name>>に変換されるようだ。
ルールはいくつかあるのだが、基本的にはSHORT_NAMEならShortened Local Nameに、FULL_NAMEならComplete Local Nameに変換される。
むかし、PaSoRiが出すAdvertisingデータを眺めたことがあった
BLE機器を探すときに出てくる名前が、この名前になるということのようだ。

 

「ルールはいくつかある」と書いたが、これは名前をエンコードするときに、FULL_NAME指定しているけどAdvertisingパケットに載らないサイズになったら、勝手に切り詰めて短くしますよ、という作りになっているからだ。
詳細は、ble_advdata.hのble_advdata_set()コメントを読むが良かろう。

2014/10/21

2014/10/20

[android]LollipopからSmart Lockという機能が付いたらしい

Android 5.0(になるのかな)から、ロックの解除にNFCタグも使えるらしい。
http://getnews.jp/archives/685243
試しておこう。

まず、設定画面>セキュリティで、ロック方法を設定する。
私はいつもパターン入力しているので、それを設定した。
そうすると、設定できる項目がいろいろ現れ、その中に「Smart Lock」がある。
image
Nexus7なので、画面が大きくて済まんね・・・。
とにかく、こういう画面が出てくるので、赤いプラスをタップ。

image
Bluetoothか、さもなくばNFCかの選択を迫られる。
私はNFCなので、下をタップ。

image
タップを促す画面が表示される。

image
タグが見つかると、名前入力する画面になる。

image
おしまい。
複数の登録が可能だ。

では、使い方。
まず、ロックして画面が消えている状態では、何もならない。
これは今まで通りだ。
電源ボタンを押してロック画面を表示させ、かざしてみた。
・・・変化がない・・・・・・。
パターン入力画面になってからかざすのか?
・・それでも変化がない。
なんだ???
正解は、「ロック画面でタップしてから、画面をスワイプ」だ。
そうすると、パターン入力画面が出てこずにホーム画面が出てきた。
ロックが外れる音がするわけじゃないので、気付かんかったわ。。。
何回かやってわかったけど、タグを読めなかったときの音はするみたいだ。
そういえばHCEはロック画面でも使えるような設定があったから、そっちなのかな?

パターンよりも、すごく複雑なパスワードとかPINにしておいて、ほとんど記憶での入力ができないようにしておき、普段はNFCタグを使うとかがよいのかなぁ。
あるいは、外では電話専用にするために、タグは家の中に固定しておくとか。

2014/10/19

[nrf51]softdevice_sys_evt_handler_set()は、何だ? - (3)

ちょっと追った。

softdevice_sys_evt_handler_set()は、sd_common/softdevice_handler.cにある。
これは、m_sys_evt_handlerという変数に覚えるだけ。

使っているのは、intern_softdevice_events_execute()だけ。
これの呼び出し元は、SWI2_IRQHandler()。
名前からすると、ソフトウェア割り込みのハンドラだろう。
スケジューラの関数が登録されていればそちらを呼び、登録されていなければintern_softdevice_events_execute()を呼ぶ。

ここでいうスケジューラの関数は、SOFTDEVICE_HANDLER_INIT()でスケジューラを使うと指定すると、自動的に割り当てている。
softdevice_evt_schedule()という関数で、やっているのはapp_sched_event_put()でスケジューラに登録するだけ。
登録するのは関数呼び出しで、結局はintern_softdevice_events_execute()を呼ぶようにしている。
私のイメージだと、とりあえず発生したイベントだけは吸い上げて、それをスケジューラに登録するんだろうと思ったんだけど、そうではないんだな。

intern_softdevice_events_execute()では、SoftDeviceからのイベントとBLEスタックからのイベントの両方をさばいている。
SoftDeviceの方は必ず処理するが、BLEスタックはBLE_STACK_SUPPORT_REQDが定義されているときだけだ。
softdevice_sys_evt_handler_set()は引数がNULLの場合には処理されないので、それが"Once the application has registered for the events, it is not possible to possible to cancel the registration"と説明している意味だろう。

 

さて、最初の疑問に戻ろう。
「なんでBLEスタック初期化の中で呼び出しているの?」だ。
関数コメントを信じるなら、SWI2_IRQHandler()はBLEスタックイベントの割込ハンドラらしい。
だから、ble_stack_init()でしか呼び出さないということか。

じゃあ、なんでBLEスタックイベントの割込とSoftDeviceのイベントが一緒になってるんだ?
また、SoftDeviceイベントというのは、sd_evt_get()で取得しているので、enum NRF_SOC_EVTSみたいなのだ。
これはNRF_EVT_FLASH_OPERATION_SUCCESSみたいな定義があることから、必ずしも異常発生だけとは限っていない。

あまり考えても仕方ないから、こんな感じになるだろうか。

  • BLEを使うなら、softdevice_sys_evt_handler_set()でコールバック関数を設定した方がよい。
  • FLASH操作するなら、その処理結果がコールバックされるようである。
  • なので、必ずエラー処理にするのではなく、内容によりけり。

 

現在までで整理した内容を、githubにプッシュした。
残るは、main.cのBLE周りですな。
https://github.com/hirokuma/nrf51822_templete

みんなはどのlibusbを使っているのだろうか?

疑問系だ。

LinuxやWindowsで、あるいはMacでもかもしれないが、USBデバイスを制御したいとなるとlibusbを使うことが多いんじゃなかろうか。
デバイスドライバを作ればいいのかもしれないけど、アプリ層からUSBアクセスできるというのを知ってしまうと、もういいや、と思ってしまう。

で、libusbなのだけど、バージョンが存在する。
大きくは、0.1系と1.0系だと思っている。
0.1と1.0があれば、そりゃ1.0だよねぇ。

そう思っていたんだけど、「cygwin libusb」で検索すると、ここが先頭に出てきた。

http://sourceforge.net/p/libusb-win32/wiki/Home/

Homeって書いてあるので、メインページみたいな位置づけだろうと思う。
そしてこれは、libusb-0.1系なのだ。

1.0系は、おそらくこちらがメインページ。
http://www.libusb.org/wiki/windows_backend

libusb.orgの方が本物っぽいので、一番上のページを見た。
http://www.libusb.org/wiki
表を見ると、1.0系がtrunkで、0.1系のソースを使っている人のためにcompatibleなソースも提供している、という位置づけのようだ。


で、だ。

バージョンが新しいものをみんなが使うわけじゃ無いし、新しい方がよいというばかりでもないのはよくあることだ。
それに、たとえ新しい方が良かったとしても、使われなければ無いのに等しくなる(私は、倉庫に眠るベータのビデオデッキを思い出した)。

じゃあ、みんなはどのlibusbを使っているんだろう?が気になるのだ。
長いものに巻かれる必要はないのだが、今回みたいに「USBが扱えれば良い」というものについて、マイナーなものを選択する理由がないというだけだ。

 

なんで急にlibusbのことを言い出したかというと、AndroidのADKだ。
当時はBeagleBoardにAndroidをインストールして使っていたのと、Arduinoを持っていなかったこともあり、よくわからんけど仕様書どおりにやってみようと思って、libusbで通信してみたのだ、たしか。
もう2年半も前なので、全然記憶はない・・・。
リンク先にあったgithubのリポジトリも削除していたので、著作権的にまずいと思ったか、なんか動かないとかあったのだろう。
もちろん、手元にあるソースでNexus7にアクセスしてみたけどだめだった。

[android]Lollipopゲームが難しい

Nexus7(2013)に、Lollipop Previewをインストールした。
前回はL previewという名前だったんだけど、今回はLollipopという名前が付いている。
チュッパチャップスじゃないんだ。。
インストールして起動すると、新規立ち上げと一緒なのであれこれ設定が必要になる。
が、今回は「タップアンドゴー」というものが出てきた。
タッチアンドゴーみたいな感じがするが、NFCを使うので、少し近い気がしたけど、関係はやっぱりない。
Nexus5端末(4.4が入っている)を向かい合わせると、Bluetoothを有効にするか確認され、OKするとアカウントの移行がある程度できた。
もちろん、パスワード入力は必要だけどね。2段階認証してるけど、そっちの入力は求められなかった。
今、アプリが自動でダウンロード&インストールされているところだ。
とりあえず開発者モードにでもしておくか、といつもの手順を踏もうとした。
が、間違えてイースターエッグというのか?あっちをやったようだ。
なんか、ゲームが起動した。
image
画面をタップすると、ドロイド君が跳ね、何もしないと落ちていく。
なので、手際よくタップしつつ、現れるロリポップの間をくぐり抜けていくという、横スクロール型のゲームだ。
けっこう、難しくないかい??

アプリの同期が終わったようだ。
Nexus5のホーム画面と同じアイコン並びになっている。
まあ、タップしたのがNexus5だから仕方ないけど、タブレットとは別になってる方がうれしいかな。
  • アプリ一覧画面の背景が白くなった。
  • 「ブラウザ」が追加? Chromeがアンインストールできる。
  • 「メール」が2つある・・・片方はアンインストールできたから、ダウンロードしてきたのかな

Lollipopとは関係ないのだけど、写真とかのバックアップ機能が良くわからない。
4つくらいGoogleアカウントがあり、メールを読むためだけにアカウント登録してるのだけど、どのアカウントがいつ使われているのかがわかっていないのだ。
よく読めばわかるのかねぇ。

[勉強会]スマホ連動の講義に参加した

「はじめてのスマホ連動」という講義に参加した。
http://hslinkup.doorkeeper.jp/events/15299

出不精の私にしてみれば珍しいのだが、講師の栗元さんにお会いしたことがあることと、内容に興味があることから参加させていただいた。
それと、私が今使っているBLEのモジュール、BVMCN51を製造・販売しているBraveridge社の小橋CTOが講義されるということもあり、気分が盛り上がって参加したのだ。
今でこそフリーランスになっているが、そのちょっと前までは「Braveridge社って面白そうだな」とか思っていたこともあったので、就職の面接をお願いしようかどうしようかと調べたりしててね。

ふっ、今では過ぎた話よ。


一番前の席でかぶりつきになっていたこともあり、どういう方々が参加しているかがあまりわかってない。。。
「Arduino使ったことありますか」の挙手にけっこう手が上がっていたようだったので、そういう参加状況だったのだろうと思う。

内容は、

  • 講義
  • 実習
  • Braveridge社小橋さんの講演

の3本。
詳細は省略するが、いろいろ聞けて満足。
ADKは今まで使ったことが無かったこともあり、どういう動きをするのか確認できたのが良かった。

ADKは、2年前に調べていたみたいだ。
http://hiro99ma.blogspot.com/2012/05/adk_31.html
そうだ、手近でUSB Hostできる基板があったので、USBドライバを書いてADKしてみようとしたんだった。
途中まで認識したけど、よくわからんがダメだった、で終わっている。
あれから知識が付いた今なら、もうちょっとできるだろうか?

 

小橋CTOの話も面白かった。
面白いと書くとあれだが、内容が興味深かった。
ちょっと前に、福岡が起業特区になったことを書いたけど、考えてる人は考えてますな。
特にCTOという現場で見た福岡という観点が、ね。


さて、家に帰ってきたので反省会(単なる家飲み)だ。

まず、多少二日酔い気味であったことを告白せねばなるまい。
前日が職場の歓迎会で、しかも3時くらいまで飲むなんて想定してなかったよ。。。
酒臭いってことはなかったと思うが、ちょっと鈍っていたことは否めない。

 

買ったばかりのNexus5が、役に立った。
主に、地理的なところで。。。
高校生の頃は近くに通っていたんだけど、もう20年以上前だしね。
Googleマップを見ながら移動できたので、安心であった。
Nexus7とかだと、見ながら移動するってのはちょっと難しいです。
あ、実習でデバイスドライバのインストールがうまく行ってるかどうかの確認にも役立った。

 

WindowsでのADBドライバ問題。
問題というか、端末ごとにドライバのインストールが必要になってくる。
あまりドライバを触ったことがないので推測になるが、Windowsの場合はINFファイルにUSBデバイスのVID(ベンダIDで、製造メーカーごとのIDだろう)/PID(プロダクトIDで、商品ごとのIDだろう)が書かれているので、INFファイルありきで機器を認識することになるんじゃなかろうか。
なので、INFファイルにないデバイスを接続したときには大騒ぎになる。さらにWindows Updateにドライバを探しに行く動作がデフォルトになっているため、てんやわんやだ。
たぶんだけど、LinuxやMacではlibusbのようなアプリ層で動けるようなしくみになっているから、そんなに困らないのではなかろうかね。

 

今のADKは、さらに進んでいるのか。。。
http://developer.android.com/tools/adk/adk2.html
Cortex-M3ベースみたいだ。
Bluetooth接続なんかもあるらしい。
接続がいろいろできるのはありがたいが、Bluetooth接続にするんだったら、最初からBLEを前提に検討するだろうな。
まあ、そこは使い方次第だ。

 

創業特区。
福岡に産業がないことを嘆いておられたのが新鮮だった。
仕事ないよねー、とは思っていたけど、やはりそうなんだ。
どこかに閾値があって、あるラインを越したら一斉に引いていくんかね。


めったにお外に出ないので、外の環境に触れただけですごく勉強した気になってしまう。
しかし、それだけではダメだ。
まあ、ダメって事はないだろうが、世の中としてはもうちょっと役割を演じることを期待されてるだろう。
そこら辺ですかなぁ。

2014/10/17

[nrf51]softdevice_sys_evt_handler_set()は、何だ? - (2)

つづき。

softdevice_sys_evt_handler_set()は、nRF51 SDKのドキュメントに説明がある。
あるのだけど・・・正直なところ、なんだかよくわからない。

  • SoftDeviceからのSoCイベントを登録する関数(イベントハンドラってことかな)
  • これを呼ばなかったら、フェッチされない
  • 一度呼んだら、もうキャンセルすることはできないが、関数を差し替えることは可能

このくらい。
SoCイベントがどういうものだとか、何したらいいのかよくわからん。


よくよくドキュメントを見ていくと、「SoftDevice Handler Library」という章があり、そこに説明があるとのこと。

・・・読みつつあるが、何が言いたいのかわからん。
SoftDevice Handler Libraryは、アプリがSoftDeviceイベントを正しく取り出す(フェッチする)のを補助するAPIとのこと。
例として、S110ではBLEイベントをsd_ble_evt_get()で、SoCイベントをsd_evt_get()で取ってくる、と。しかしS210では違うのだと。

うーん、ということは、アプリにシステムから「イベントが来たよ」と通知が来ても、どのAPIを使って取得したらよいかわからないだろうから、SoftDevice Handler LibraryのAPIで呼び出してほしいコールバック関数を登録する方式にして、アプリからフェッチしなくてもよいようにしましょう、というくらいの考え方で良いのかな。

 

でも・・・でもだ。
それがble_stack_init()に入っているのは、あんまり納得できてない。
SOFTDEVICE_HANDLER_INIT()もここだし。
それなら、softdevice_init()みたいな名前にしておいて、一緒にBLEスタックの初期化も入っている方がすっきりするんじゃないかと思うのだ。

もうちょっと、自分の理解度を進めながら、スケルトンを整理していきたいな。

2014/10/15

[nrf51]softdevice_sys_evt_handler_set()は、何だ? - (1)

 人「最近、家でなにを開発してるんですか?」(私が家でごにょごにょやってることを知ってる人)
 私「び、Bluetooth関係とか」

といってしまったので、もうちょっとちゃんと開発しよう。


ちまちまと進めているのは、以前作ったInputとOutputのサービスを持つアプリについての読解。
サービスの実装についてはなんとなくわかったんだけど、アプリについてはほとんどサンプルを使い回しているだけなので、何をやっているか把握できていないのだ。
BLEとは直接関係ないのだけど、BLEでなにかPeripheralを作ろうと考えたとき、BLE自身は多くても3~4割くらいで、残りはアプリの制御になると思っている(もちろん、BLEのプロトコルスタックはできあがっている上でだ)。

サンプルでは、BLEを使うときにble_stack_init()という関数を作り、そこに初期化をまとめているようだ。
以前はまった内蔵クロックの初期化とか、BLEスタックを死傷するためにsd_ble_enable()というAPIを呼び出したりしている。
BLEイベントのディスパッチをするsoftdevice_ble_evt_handler_set()を呼び出したりもする。

そういうのはわかるのだが、softdevice_sys_evt_handler_set()もここで呼び出している。
このAPIはBLEイベントのディスパッチャー登録と同じように、システムイベントのディスパッチャー登録をするAPIのようだ。
疑問は2つ。

  • システムイベントって、なに?
  • なんでBLEスタック初期化の中で呼び出しているの?

プレフィクスにsoftdevice_とついているので、これはSoftDeviceを使う機能全般のものじゃなかろうか。
じゃあ、BLEスタックとは切り離されてもいいんじゃないの?
なんでここで呼ぶの??

では、softdevice_sys_evt_handler_set()についてしらべようじゃないか。


と、書いているところにNordicのMLが来た。

SoftDevice S110-SD-v7が、7.1.0にバージョンアップ!
しかも、これ以前の7.x.x系はdeprecatedになるんだと。
LDCD(てきとう)もサポートすると書いてあるし。。。

そっちを先にやりましょうかね。

2014/10/11

[nrf51]Keilを使ってみる

KeilでnRF51のs110/ble_app_hrsサンプルプロジェクトが開けたので、使ってみよう。

ツールバーはこんな感じだ。
image

左下の、箱を上から押さえつけるようなアイコンでビルド。

焼くのはその隣のLOADアイコンだと思うが、デバッグしたいときは右上のdアイコンなのかな?
main()の先頭にブレークポイントを設定してからdアイコンをクリックしてみると、nRF Toolsをアップデートした直後だったためかSEGGERのファームウェア更新が行われた。

続けて、このダイアログが出てきた。
image

OKすると、ブレークポイントに止まってくれた。
こりゃ楽じゃわい!
image

なお、ブレークポイントを設定しなくても、デバッグの開始時にはmain()で止まってくれるようだ。

 

gdb + eclipseでブレークポイントに止まらず悩んでいたことを考えると、Keilを使って開発に慣れて、バイナリのサイズが32KBじゃ足りなくなってからgccにするというのがよいような気がするな。
SoftDeviceが別バイナリだし、コンパイラがARM謹製ならサイズも小さくなりそうな気がするので、少々じゃ32KBで足りなくなるって事がなさそうだしね。

[nrf51]Keil v5でプロジェクトが開けなかった (2)

プロジェクトが開けなかった件について、コメントをいただいた。
http://hiro99ma.blogspot.com/2014/10/nrf51keil-v5-1.html?showComment=1412899880719#c7654399720798830608

Packの中にあるNordicフォルダを探し、そこからファイルを編集すればいけるらしい。
が・・・うちのKeilにはPackの中がほどんど空だった。
どうやって、これをインストールしたらいいんだ?

 

と検索すると、どうやらKeilをインストールした後でnRF51 SDKのインストーラでインストールすると、Packをインストールできるらしい。
最近はZIPファイルを解凍しているだけだったので、気付かなかったよ・・・。

msiファイルを立ち上げると、確かに候補が出てきた。
そして、インストール後にプロジェクトファイルを開くと、特にエラーも無く立ち上がった。
うーん、気付かなかったですわ・・・。

2014/10/10

[nrf51]Keil v5でプロジェクトが開けなかった (1)

Keilを使うと比較的楽にnRF51822の開発などができる、ということだったので、インストールしてみた。
mdk512.exeだった。

あまり調べず、nRF51 SDKをインストールしたときのs110/ble_app_hrs/arm/ble_app_hrs.uvprojxを開いてみた。
うん、だめだ。

image

Packをインストールすれば良いように見えるけど、クリックしても404エラー。
その下のリンクを見たが、このサイトにはNordicが出てこない。
うーむ。

 

Legacy Support、というページがあるとのこと。
v5に対応しきれていないものをサポートするってことかな?
インストールしているが、本体と同じくらい時間がかかってる。

そして、それをインストールしてもだめだった。
とにかく、Packが入っていないのだ。
いっそのこと、v4をインストールし直そうか、というところになってきている。

2014/10/08

[nrf51]スケジューラは結局なんなんだ? - (2)

スケジューラとタイマの関係がよくわからないので、あれこれ考えたが、動かしてみることにした。
理詰めも大切だけど、わからんことを考えても面白くない。

nRF51のテンプレートにありがちなmain()を、こう書き換えた。
timersをコメントアウトだ。

    // 初期化
    leds_init();
    //timers_init();
    gpiote_init();
    buttons_init();
    ble_stack_init();
    scheduler_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();
    // 処理開始
    //timers_start();
    advertising_start();
    while (1) {
        //スケジュール済みイベントの実行(mainloop内で呼び出す)
        app_sched_execute();
        uint32_t err_code = sd_app_evt_wait();
        APP_ERROR_CHECK(err_code);
    }

 

動かすと・・・、はい、assertしました。
予想してなかったけど、buttons_init()でapp_error_handler()が呼ばれていた。

エラーコードは8で、発生はAPP_BUTTON_INIT()の行らしい。
8はNRF_ERROR_INVALID_STATE。

マクロをひもとくと、app_button_init()がapp_timer_create()を呼び出しているのだが、app_timer_init()を呼び出していないと設定されないmp_nodesという変数がNULLなのでエラーになっている、ということらしい。
このmp_nodesは、app_timer_init()の第4引数だ。
第4引数は、APP_TIMER_INIT()マクロを使ったときに定義されるstatic変数だ(自分でやっても良いけどね)。

そんなわけで、ボタンを使う場合には、タイマの初期化も必要だし、開始も必要と思われる。


じゃあ、結果が見えているのだけど、ボタンの処理を外してみよう。

・・・はい、assert()。
今度は、ble_conn_params_init()。
罪状は8なので、もう追うまい。


ひとまず、スケジューラというか、タイマを使うかどうかについて1つの結論が出たことになる。

  • ボタンを使う場合には、タイマも使う。
  • BLEを使う場合にも、タイマを使う。
  • そしてタイマの初期化は、それよりも先に済ませておかないといけない。

ボタンを使わないことはあると思うが、nRF51822を使っているのにBLEを使わないことは無いだろう(用途として)。
だから、基本的にタイマは初期化しておくことになると思って良かろう。

 

なんか、スケジューラの話をしていたのにこんな結論で終わったのは寂しいが、まあそういうこともあるさ。

2014/10/04

[nrf51]スケジューラは結局なんなんだ? - (1)

またnRF51822のスケジューラで悩んでいる。
前回は、こちら。

[ble][nrf51]スケジューラーって、何よ?
http://hiro99ma.blogspot.com/2014/07/blenrf51_17.html

以前は省電力のためにwfiで待ち状態にするために使ってるんだろう、みたいなことを書いたけど、よく考えるとあれはスケジューラじゃなくてsd_app_evt_wait()だ。
ドキュメントに、スケジューラの有無でのシーケンスが書いてあるのだが、BLE Stackとアプリの間にスケジューラが挟まっているだけだ。
うーむ。


何度かシーケンスを見比べていて気付いたが、スケジューラが挟まっていない場合はBLE Stackなどの各ユニットが直接アプリとやりとりをするのだが、スケジュールが入っている場合は各ユニットではなくスケジューラがアプリとやりとりをしている。
つまり、各ユニットの占有時間が減るということだ。
この利点は、割込コンテキストで動作する時間を減らせるので、割込の取りこぼしが少なくなるとか、そういうことじゃなかろうか。
スケジューラを使えないようにできるのは、アプリのサイズを小さくしたかったり、アプリの応答性を優先させたいとかの判断があったりとか、そういうことなんかね。


もしそういう存在理由なら、スケジューラを使うからといってタイマユニットを使わないといけない、ということはないはずだ。
いや、ドキュメントのどこにもそんなことは書いてないのだけど、テンプレートでタイマの初期化だけしてあったし、スケジュールっていうと時間が関係しそうだから必須かもしれない、と思っていたのだ。

では、はずしてビルドしてみればわかるだろう。
make・・・リンクエラーだ。
そうか、ボタンのチャタリング防止(なんか単語があったが忘れた…)とか、BLEの時間制御もこれを使っているんだ。
じゃあ、BLE使うんだったらapp_timer.cが必要になるのか。
リンクするのは良いとして、初期化はアプリでやってやらんといかんのかな?

それに、今スケジューラの初期化を見て気付いたのだが、スケジューライベントの最大値をsizeof(app_timer_event_t)で与えているのだ。
理由はわからんが、やはりスケジューラにはタイマが必要ってことかい??