2014/11/29

[nrf51]ADCにチップバージョンでの差違あり

Blogs - Nordic Developer Zone - Using the ADC with the S110 SoftDevice

今のところ予定はないが、センサーを扱いたいとなるとAD変換を使うこともあろう。

制約としては、まず以下があるとのこと。

  • ADCの割り込み優先度をLOWにする
  • PPIチャネルで0~7を使う(8~15はSoftDeviceが使っている)
    SoftDeviceの初期化前に自分で直接設定するか、nRF51 SDKのsdppiラッパAPIを使う

 

これだけでなく、nRF51の第2世代と第3世代のハードウェアには制限があるとのこと。
世代は、ドキュメントのPANを見ると、チップの表面に書いてあるとのこと。
しかし、私が持っているのはモジュール製品で、nRF51822はカバーに覆われて見ることができない・・・。

どうも、ドキュメントのPSのバージョンとハードウェアのバージョンが一致しているように見える。
今はnRF51822_PS v3.1が最新なのだけど、それはrevision 3、つまり第3世代のドキュメントのようだ。
最新版が出たからって、前のドキュメントは捨てたらいかんな。

たぶん、時期的に、うちのはrevision 2だろう。
BLEの1パケットでだいたい1msecブロックするらしい。なので、例えば6パケット送信するのであれば6msecブロックするので、

1 / 6msec = 0.1667kHz = 167Hz

ということか(ブログでは、だいたい150Hzって書いてる)。

ここでの表現が「sampling frequency」なんだけど、アプリがADCできる間隔じゃなくて、本当にサンプリング周波数がこうなるってことだろうか?
Nordicのサンプルプロジェクトを見たが、時間に関する設定はなさそうで、100msec間隔でADCする、くらいのことしかないみたいなので、あまり周波数が高くないものだけにするか、速くしたいんだったら外部に任せるかになりそうだ。

[keil]32KBの壁はどこにある?

「keilのフリー版は32KB制限がありますよね」という記事を書いていたのだが、読んでくださった方々から情報をいただいた。
ありがたやありがたや。
私があんまり社交的じゃないためか、このブログはマイナーなんですよ。
ときどき、閉鎖して本業に集中しようかとも思うけど、見てくださる方がいるのであれば、もうちょっと続けようかという感じでやっとります。


さて、本題。

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

コメントをいただいた中で、誰もが「32KBを超えても大丈夫だった」ということだった(2人しかコメントがないが、これを「誰もが」と書くことで、すごく多くの人がコメントをくれたようなイメージを与えるテクニックだ)。

では、試してみなくてはならぬ。

まず、32KB、がどこを指しているのか。
ARM KEIL組み込み開発システム 統合開発環境 <MDK-ARM 正規代理店>|横河ディジタルコンピュータ株式会社
こちらの表を見ると、デバッガ、シミュレータ、そしてコンパイラが32KBとのこと。
しかし、コンパイルのどこら辺が32KBかは、見てもわからない。

セカンド・オピニオン (412) MCUで遊ぼう Part2 (3) | マイナビニュース
これを読むと、コード/データが32KBとある。
プログラムは基本的にROMとRAMの2つに分かれるが、ROMもデータとプログラムに分かれる。
RAMも、初期値があるものと、ないものに分かれる。
初期値があるものは、その初期値自体はROMに置かれることになる。じゃないと、初期値を保持しておくところがないからね。
C言語では、初期値を持つ変数というのは、staticなものしかない。
そのstaticな変数の中でも、初期値を代入しているものは「初期値あり」だが、代入していないものは「ゼロ」になる。
だから、staticな変数であっても、初期値の有無でROMのサイズが変わってくる。

なんでこんなことをごにゃごにゃ書いたかというと、32KBのROMをどうやったら作り出せるか、ということを考えていたからだ。
プログラムを書いて32KB作るのは、けっこう難しい。
できれば、var[32768]みたいな感じで、楽に32KBを作りたい。
でも、staticとかvolatileとかつけても、単に宣言しただけだとRAM領域の話になるので、コードサイズにならない。
初期値がないから、ゼロになるだけだ。
私が見たことのあるコンパイラだと、main()が呼ばれる前にmemset()とか、あるいはアセンブラなどでゼロ埋めするものがほとんどだったが、オプションによってゼロ埋めする処理すら省略するものもあった。

我々が求めているのは、ゼロ以外の初期値を持つ変数だ。
そうなると、初期値の部分がROMに配置されるので、今回のコードサイズ制限を調べるのに役立つ。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[256 * 1024 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

16byteのFILL16を、16個並べたFILL256を、4つ配置。これでFILL1K。
とりあえずエラーを見てみたいので、これを16個並べたら、16KBだからよさそうだけど、エラーになった。

Build target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
linking...
.\Objects\test.axf: error: L6047U: The size of this image (268436284 bytes) exceeds the maximum allowed for this version of the linker
Finished: 0 information, 0 warning, 0 error and 1 fatal error messages.
".\Objects\test.axf" - 1 Error(s), 1 Warning(s).
Target not created.

でたー。
これが、maximumなエラーメッセージらしい。
少し満足。

まあ、256 * 1024 * 1024だと、どの環境でもエラーになりそうよねぇ、ということで、32KB制限近くでやってみた。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[31 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

これのビルド結果は、こう。

Rebuild target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
assembling arm_startup_nrf51.s...
compiling system_nrf51.c...
linking...
Program Size: Code=598 RO-data=31970 RW-data=4 ZI-data=4196  
FromELF: creating hex file...
".\Objects\test.axf" - 0 Error(s), 1 Warning(s).

この、memの31を32にすると、リンクエラーになった。

Rebuild target 'Target 1'
compiling main_32k.c...
main_32k.c(15): warning:  #177-D: variable "jan" was declared but never referenced
        uint8_t jan = mem[256];
main_32k.c: 1 warning, 0 errors
assembling arm_startup_nrf51.s...
compiling system_nrf51.c...
linking...
.\Objects\test.axf: error: L6047U: The size of this image (33596 bytes) exceeds the maximum allowed for this version of the linker
Finished: 0 information, 0 warning, 0 error and 1 fatal error messages.
".\Objects\test.axf" - 1 Error(s), 1 Warning(s).
Target not created.

こっちが、warningだけだったコード。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[31 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

こっちが、エラーになったコード。

#include <nrf51.h>
#include <stdint.h>
#define FILL16 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
#define FILL256 FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16,FILL16
#define FILL1K FILL256,FILL256,FILL256,FILL256
static const uint8_t mem[32 * 1024] = {
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,
    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K,    FILL1K
};
int main(void)
{
    uint8_t jan = mem[256];
    __wfe();
    return 0;
}

違いは、memの添字になっている値が、31か32か、だ。

こうやって見る分には、ちゃんと32KBで制限がかかっていると感じます。


翌日。
飲みながら調べると、なんかいろいろ馬鹿なことやってるなー、と反省(したふり)。

リンクができる境界を調べて、以下のソースになった。
配列の202を203にすると、リンクエラーになる。

static const unsigned char mem[31 * 1024 + 202] = {0};
int main(void)
{
    return mem[0];
}

image

mapファイルのお尻だけ拾うと、こんな感じ。

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   
       594         88      32170          4       4196       7352   Grand Totals
       594         88      32170          4       4196       7352   ELF Image Totals
       594         88      32170          4          0          0   ROM Totals
==============================================================================
    Total RO  Size (Code + RO Data)                32764 (  32.00kB)
    Total RW  Size (RW Data + ZI Data)              4200 (   4.10kB)
    Total ROM Size (Code + RO Data + RW Data)      32768 (  32.00kB)

配列の要素数は、1024 * 31 + 202だから、31946。
mapでは32170になってるから、あと224バイトはコード以外のROMデータがあるらしい。

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name
        84         36        192          0       4096        648   arm_startup_nrf51.o
        12          6      31946          0          0       2055   main_32k.o
       232         30          0          4          0       4241   system_nrf51.o
    ----------------------------------------------------------------------
       328         72      32170          4       4096       6944   Object Totals
         0          0         32          0          0          0   (incl. Generated)
         0          0          0          0          0          0   (incl. Padding)

incl. Generated、というのが32バイトあるらしい。
ARMのヘルプを見ると、これはリンカが生成したオブジェクトらしい。

ともかく、うちで試した限りでは32KB制限というのは発生していることが確認できた。

 

{0}なのに初期値ありとみなされるんだ、というのが多少ショックだった。
前見たコンパイラは、{n}のような感じでnに数値を入れるとmemset(0)で勝手に0初期化してたのだ。
組込用のコンパイラだったから、それを正とみなしてたらいかん、という教訓を得た。

2014/11/28

[android]AndroidStudio 1.0 RC2が出ていた

Windowsにも、Android Studio 1.0 RC 2が出ていた。

image

前がどんなのか忘れたけど、あか抜けた感じがしますな。
あか抜けてない私が言っても説得力ないですが。

image

 

既存のプロジェクトを開くと、エラーが出た。
こちらを参考に修正すると、よさそうだった。
Android Studioでmethod not found: 'runProguard()'発生 電脳羊(Android Dream)/ウェブリブログ

ファイルを開いて、runProguard を minifyEnabledに変更し、設定をrecommendのものにしただけで、ビルドは通った。
動かしてはいないけど、まあいいや。

2014/11/26

[c/c++]enumはプリプロセスでは評価できません

「何を当たり前のことを」と言われそうだが、まあ聞いておくれ。

今、BLEの再履修をしているところだ。
一通り小さなサービスを動かしてきたことになるので、始めた当時にはよくわからなかったものが、今では理解できるようになったかもしれない。
私の場合、学習→試作→学習→試作、を繰り返すような感じで物事を把握することが多い。
なんというか、覚えるときは紙に目一杯書き込まないと覚えられないような、体で感じるタイプらしい。

 

まあそんなわけで、BLEのことを調べ直しているのだが、設定できる値の範囲が気になってきた。
例えば、connIntervalは7.5msec~4secの間だ。
これをS110とかでは、こんな表し方になる。

#define CONN_MAX_INTERVAL               MSEC_TO_UNITS(1000, MY_UNIT_1_25_MS)

MSEC_TO_UNITS()はapp_util.hにあるマクロで、こんな定義だ。

#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))

なんでこんな式かというと、connIntervalは7.5 + 1.25n、というBluetoothの仕様になっているからだ。
TIMEはmsec単位なので、それを1000倍して割る。
ということは、全体としてはμsecになってしまうので、そうならないようにRESOLUTIONも1000倍された値を使う。
「どうせconnIntervalなんて固定値でしか持たないだろうから、そこまでやらなくていいんじゃないの」と思ったが、実装にも仕様にも固定じゃないといかんというわけではなく、もしかしたら普通は曜日や時間帯に合わせて可変にするものだけど、サンプルだから固定にしているだけなのかもしれん。

 

前置きが長くなって済まん。
nRF51で使うconnInterval値の範囲は6~3200になるのだが、そういうマクロ値が既に定義されていることを知った。
BLE_GAP_CP_MAX_CONN_INTVL_MINが6で、BLE_GAP_CP_MAX_CONN_INTVL_MAXが3200とか。
ならば、コンパイル前に定義値の範囲チェックをしておけば、変なバグで悩むことが減るんじゃなかろうか、と思ったのだ。

それで、こんなチェックマクロを埋め込んだ。

#if (CONN_MAX_INTERVAL < BLE_GAP_CP_MAX_CONN_INTVL_MIN)
#error connInterval_Max(Connection) too small.
#elif (BLE_GAP_CP_MAX_CONN_INTVL_MAX < CONN_MAX_INTERVAL)
#error connInterval_Max(Connection) too large.
#endif  //CONN_MAX_INTERVAL

 

メモリを消費するでもなく、ビルド段階で範囲チェックができてよかろう、と満足したのだが、これがgccでエラーになるのだ(他のは知らん)。
さんざん悩んだが、結果としてはこのせいだった。

enum {
    UNIT_0_625_MS = 625,
    UNIT_1_25_MS  = 1250,
    UNIT_10_MS    = 10000
};

えっ、ここにenum使ってたの??
なんでまた・・・。

#defineはプリプロセス段階で展開されるけど、enumはコンパイル時に展開される。
だからプリプロセスとしては、MSEC_TO_UNITS(1000, MY_UNIT_1_25_MS)みたいなenumを含む式を見つけると、展開できないという扱いにしてしまい、ここではゼロとみなして「ゼロで割ってます」というエラーになっていたのだ。

まあ、enumにするとデバッガなどで値が見やすくなるのはあるけど、ここでは使ってほしくなかったなぁ。
せっかくdefineがあるけど、ここは自分で7.5msecとか4secとかの定義値を作って、値でチェックする方式に置き換える方がよさそうだ。
時間かかったわー。

2014/11/24

Excel2013のコンテキストメニューが薄い

何も解決しない話になるが、Excel2013のコンテキストメニューの文字色が薄い。

image

使えるのは濃いグレーで、使えないのは薄いグレー。
どうにもコントラストが低く、最初見たときは全部ディセーブルなのかと思ったくらいだ。

テーマを変えても色が変わらないので、どうしようもなさそうだ。
Window自体も、アクティブと非アクティブでタイトル文字色しか変わらないので見分けづらい。
Excelの機能に不満はないけど、ちょっとこれはねぇ・・・。

2014/11/23

[nrf51]iBeaconとNordic

別にNordicに限定したことじゃないが、iOS8からiBeaconの仕様が変わったらしく、今のところNordicのVendor IDはCore Location Frameworkではじかれているらしい。

Nordic beacons and iOS

 

iBeaconのパケット仕様は、もともとAppleからは出てなくて、どちらかというと「こういうAdvertisingデータを流すと反応してくれた」みたいな感じだったのではなかっただろうか。
少なくとも私は、Appleの技術ドキュメントからは見つけられていない。

んで、いつしかMFi対象になってた。
あんまりわかってないけど、Advertisingのデータに書いてあるだけで、それが平文だったら、普通にスキャンしてまねすればだませてしまいますわな。
なので、自由度はなくなってしまうけど、まあAppleなら仕方ないかな、というところか。

2014/11/22

[android]LollipopのFOTAがNexus5に来たが、TeamWinだったので失敗した

白いNexus5を使っているのだが、昨日の朝、出勤前にLollipopのアップデートが来ていることに気付いた。
ヨドバシの480円SIMを使っているので、外に出てしまえば200kbpsになるため、家の中でダウンロードだけしておきたい。

そう思ってダウンロードは成功して再起動させたのだが、アップデートは始まらずにteamwinって出てきた。
よくよく思い出すと、SMS無しの契約のためセルスタンバイが気になり、root化して押さえ込んでいたのだった。
こういうときは、どうしたらいいんだろう?

 

調べると、recovery領域をオリジナルに戻せばよいようだった。
では、と、Lollipopのイメージを持ってきて解凍し、recovery.imgを焼いて再起動!
そしてリカバリモードにしたのだが・・・ドロイド君が横たわって赤い三角が出てる。
ネットだと、ここにメニューが出てくるような感じで書かれているのに。。。

やっぱり今インストールされてるのと同じじゃないとだめなのか、とKitkatのイメージからrecovery.imgを持ってきて、焼いて再起動してリカバリモード!
・・・同じだ。

もうあきらめて全部焼き直そうかと思ったが、よくネットに書いてあることを読むと、ボタンの操作をしないとメニューが出てこないとか。
昨日なのでうろ覚えだが、確か電源+音量上ボタンの同時押しだったと思う。
そうすると、出てきた。
まあ、私がリカバリモードで何かしたいわけでもないので、焼くものが間違っていなければよいだけだ。

普通にAndroidを起動させ、システムアップデートを促す画面に行くと再起動ボタンがあったので、タップ。
そしたら、自動的に再起動して、今度はごにょごにょとアップデート作業が始まった。

初めてだから、仕方ないよね。


Lollipopだが、あのイースターエッグ画面というか、あそこに入っているLollipopゲーム。
あれは、Nexus5の方がNexus7よりもやりやすかった。
私でもN5なら3点取れた! (レベル低い。。。)

2014/11/18

[nrf51]UARTログを使い、bonding時のイベントが見えたような気がした

BLEイベントハンドラの各caseにログを埋め込んだところ、bondingしたときに通知されるイベントの順番がわかった。
こんなに簡単に使えるなら、最初からやっときゃよかった。

advertising start
BLE_GAP_EVT_CONNECTED
BLE_GAP_EVT_SEC_PARAMS_REQUEST
BLE_GAP_EVT_AUTH_STATUS

ただ、すぐにDISCONNECTが通知されてしまった。
私の予想では、続けてSEC_INFO_REQUESTが来るはずだったんだが・・・。

そして、その次のCONNECTでは、すぐにSEC_INFO_REQUESTが通知された。
んんん?

advertising start
BLE_GAP_EVT_CONNECTED
BLE_GAP_EVT_SEC_INFO_REQUEST

何度か試したが、これはnRF Master Control Panelアプリを使ったときの動作のようだ。
CONNECTする画面があるのだが、そこで「bond」を選択すると、bondingだけ行うようなのだ。
だから、すぐに切断しているのだろう。

その状態で接続しに行くと、SEC_INFO_REQUESTが来ているような気がするのだけど、そうじゃなくても元々CONNECTできるということもあり、なんだか訳がわからなくなってきた。
ここら辺は、資料からお勉強することになりそうだ。

2014/11/17

[nrf51]何故simple_uartは38400bps固定なんだろうか

nRF51822の動作をデバッガでブレークポイント使って止めながら見ていたのだが、そろそろ限界になってきた。
SDKがassertionを起こすのだ。
src/rem.cなるファイルだと言ってくるのだが、SDKの中にはなさそうなので、よくわからん。

それに、通信系のデバッグで片方が止まってしまうと、相手側も無応答とみなしてエラー扱いにするだろうから、ログを出しながら確認するのがよいだろう。
そういうわけで、デバッグ用にUARTを組み込むことにした。


ざっとSDKを見ると、simple_uart.hというものがあり、実装例もあったので、それを使うことにした。
configのパラメータでピン設定すると、あとはput/getすれば使えるというシンプルさ。

しかし・・・なぜか通信速度の設定などがない。
ソースを見ると、38400bpsで動くように実装されていた。
いくらシンプルとはいえ・・・。

動作クロックのつごうかとも思ったが、リファレンスマニュアルを見てもあまりそんな感じがしない。
嫌だったら自分で組めばいいやん、ということにはなるけど、でもこの実装になっているのは何か意図があるのか・・・。

気になるが、寝よう。

2014/11/16

[nrf51]bondingされないけどconnectできる

BLEイベントとしてBLE_GAP_EVT_SEC_PARAMS_REQUESTが来たとき、sd_ble_gap_sec_params_reply()でbondingありを返しているのだが、どうもbondingなしでconnectできているようだ。

デバッガで試したが、そもそもBLE_GAP_EVT_SEC_PARAMS_REQUESTが来ていない。
このイベントはconnect後に必ず来るものと思っていたが、別にそういうものでも無いようだ。

つまり、bondingしてないとアクセスできない、という処理をするのはアプリ側の仕事ということか。
相手がセキュリティとか何も気にせず、こちらも何も気にしなかったら、connectするだけで使えるから注意がいるな。

[nrf51]core_cm0.hはincludeしないほうがよい

eclipseでエラー扱いされないようにincludeを変更したが、ついでに順番も整理していた。
整理と言っても、「bleとs110だったら、bleが上にあった方がいいよね」「common系はその上がよさそう」くらいなものだ。

が、コンパイルエラーになった。
整理する際に、core_cm0.hを読込むようにして、それを一番上に配置したのだが、それがよくないようだ。
doxygenでつくったincludeグラフを見てみよう。

core__cm0_8h__dep__incl

core_cm0.hはnrf51.hとnrf51_bitfields.hだけがincludeしていて、普通の人はnrf51.hをincludeするもののようだ。

nrf51.hをざっと見てみたが、割込の定義みたいなnRF51系の固有設定はこのファイルに書かれているから、勝手にcore_cm0.hをincludeしてしまうと未定義でエラーになるのだった。

 

じゃあ、どこまでincludeを整理できるか、とやってみたら、こんな感じになった。
まあ、こういうのに正解はないんだろうけど、とりあえずね。
https://github.com/hirokuma/nrf51822_templete

[android]Android Studioを入れなおした

昔なら「無駄話」ラベルも付けるような話だ。

Android Studioを久しぶりに起動すると、アップデートがあると言ってきた。
ほうほう、とアップデートすると、「SDKの場所は別の場所で頼むよ」とか言い出した。
『あんたが勝手にそこにインストールしたんやん!』と突っ込みつつも、別の場所に移動。

もしかすると、この移動の前にダイアログをExitだかNextだか、とにかくRetry以外のを実行したのがよくなかったか。
ダイアログには「次に起動したらSDKの場所を聞きますね」とか言ってたはずなのに、そのまま進んだ。
そして、ExplorerでAndroidStudioがインストールされているフォルダを開いていたせいか、「なんか削除できん」と言われ、旧バージョンで再び立ち上がった。
もちろん、SDKは移動しているので、SDK Managerなんかはグレーアウトのままだ。

「そういえば、ネットにSDKの場所を移動させたときのやり方が書いてあったな」と調べて、その手順で変更しようとしたのだが、なぜかSDKのパスを保存してくれず、どうにもこうにもならない。
設定ファイルを直接いじるとかあるんだろうけど、この辺でめんどうになってきた。

えーい、全部消して入れ直してしまえ!


環境は、Windows7 64bitだ。

まず、WindowsのコントロールパネルからAndroid Studioを削除。
これは普通に消えた。

手動で残骸を削除。
c:\User\xxxの中にある、.androidとか.AndroidStudioBetaとかを削除。
c:\User\xxx\AppData\Localの中にあったAndroidも削除。

あとはAndroidStudioを入れ直すだけだが、DevelopersにあるボタンだとSDKも入ってきそうだ。
それはめんどうなので、Android Tools Projectを見ると、こんな感じでzipファイルがあった。
"not contain an embedded SDK"とあるので、目的にあう。

解凍して動かすと、無事に動いたようだ。
やれやれだぜ。

2014/11/15

[nrf51]CDTの設定

nRF51822でビルドするとき、eclipse + gccで行っている。
Keilも便利なのだけど、仕事でeclipse環境を使っているので、慣れておこうという意味合いもある。

 

eclipseでC/C++を扱うときは、CDTというプラグインというかパッケージというか、そういうものになる。
今の私は、バージョンがLUNAのCDTを使っている。
CDTをデフォルトで使うと、いろいろとコードの指摘をしてくれる。
こんな感じだ。

image

マクロや関数の宣言や文法を確認して、おかしいと思ったらマークを付けてくれる。
ただ、Makefileに書いた設定を読んでくれるわけではないので、ビルド上問題が無くてもeclipseはわからずにマークを付けてしまうのだ。

無視しても特に問題は無いので、ちょっとした開発であれば目をつぶるし、邪魔なら設定をオフにすることもできる。
でも、BLEは長くやるつもりなので、ここらで設定を合わせておいた方がよいんじゃなかろうか、ということで設定をし直すことにした。

なお、環境はWindowsでやってます。


環境変数

コンパイラの場所や、SoftDeviceの場所は変わりやすいので、Windowsの環境変数に設定することにした。
名前は何でもよいので、ARM_HOMEにコンパイラを、NORDIC_NRF51にSoftDeviceの場所をそれぞれ設定。

ARM_HOME : C:\xxxxxx\CodeSourcery\arm-none-eabi
NORDIC_NRF51 : C:\xxxxx\nrf51_sdk_v6_1_0_b2ec2e6\nrf51822

パスは、自分のところに合わせておけばよい。

SoftDeviceはzipを解凍したものだからよいとして、なんでARMはCodeSourceryにしたんだっけ・・・。

 

eclipse

includeパスの追加

eclipseの設定はプロジェクト単位のようだ。
プロジェクトで右クリックして、コンテキストの一番下にあるプロパティを選択。
C/C++ General > Paths and Symbolsにインクルードパスの設定を行う。

image

最初は、includeの下のフォルダも追加していったのだけど、面倒になってきたのでCソース側にフォルダを書くようにしてしまった。
まあ、どのincludeをしているのか明確に把握しておくのも大切だろう、うんうん。

gccだけフォルダを掘っているのは、次に関係している。

 

Symbolsの追加

今回のソースで、こんな書き方をしている。
まねしただけなんだけどね。

__attribute__( ( always_inline ) ) __STATIC_INLINE void led_on(int pin);

最初のattributeは、強制インライン関数化だ。
__forceinlineでもよいらしい。
C++のinlineはコンパイラの動作依存になるから、「どうしてもインラインにしたい」という場合はマクロにするしかない。
このオプションはgccのARM用らしいのだけど、それをやってくれるのだ。

後ろの__STATIC_INLINEは、単にstatic inlineと書きたいところだけど、コンパイラの種別でcore_cm0.hが使い分けるようになっていた。
このcore_cm0.hがgccフォルダの中にあるので、ここだけincludeパスに追加したという次第だ。

こんなコンパイラ依存の内容をeclipseが知るわけもないので、適当に無視してもらうよう設定する。
このやり方は、stackoverflowに書いてあった。

image

上が、__attribute__(xxx)という書き方をしたものを置換するもので、次が__STATIC_INLINEを解決するために定義したものだ。


とりあえずこんな感じでやっておけば、警告的なものは出なくなる。

2014/11/13

[android]fplutil (2)

fplutilを動かすのに、いくつかインストールしてある必要がある。
Windowsでやっているから、それベースで書くが、他のプラットフォームでもそれほど変わるまい。

  • Android SDK
  • Android NDK
  • ant
  • python

コマンドラインで動かすためにパスを通す必要があるが、それはパスが通ってなかったときに考えよう。
足りてるかどうかは別として、以下は動いていることが確認している。

  • javac, javaw
  • adb
  • android
  • ant
  • python
  • ndk-build

overview

ここに、ライブラリで出来ることが書いてある。

libfplutilは、main()やprintf()で書いたような普通の(traditional)アプリをAndroidで開発できる

意味がわからない・・・。
まだ動きを試していないので、想像だけしてみよう。

きっと、AndroidアプリにTextViewがぺたっと貼られたアプリができあがるのだろう。
やはり、その背景色は黒で、文字が白。
pythonとかを絡ませるところを考えると、C/C++のプリプロセスの前にソースファイル自体の変換を行い、main()やprintf()をうまいこと置き換えるのだろう。

さて、ではサンプルを動かしてみようか。


Using libfplutil_main

libfplutilは、libfputil_mainとlibfputil_printの2つからできているらしい。
どちらもstatic libraryのようだ。
NDKがshared libraryだから、組み込みやすくしているのかな?

まずはmainの方だが、これはNativeActivityとして実装されるらしい。
名前は聞いたことがあるようなないような・・・。
まあ、書いてあるソースを見てみよう。

#include <android/log.h>
int main(int argc, char *argv[]) {
    __android_log_print(ANDROID_LOG_VERBOSE, "test", "Hello World");
    return 0;
}

これって、native層のログの書き方やん!
よい例が出てこないけど、OESFで「__android_log_print」を検索すると、いろいろ出てくるだろう。
ともかく、知ってる人には知っている書き方が使えるようだ。

また、標準のC/C++だけではマルチスレッドのようなしくみがないため、イベント待ち、みたいな処理を書くことができない。
大ざっぱに言えば、イベントを待つというのは、どこかのメモリを眺め続ける作業になる。
変化がなければ、イベントが来ていないので何もしない。
変化があれば、イベントが来たとみなして処理を進める。

それだけといえばそれだけなのだが、「ずっと何かする(ここではメモリの変化を見る)」という作業は、かなり電力を使うということが問題になる。
例えば、CPUが(コアが、というべきか)1つだけの場合、プロセスがイベントが来るかどうかをずっと待っていた場合、CPU使用率は100%になるだろう。
「待つ」という処理を、一生懸命やっているのだ。けなげではないか。
コンピュータとしては、一生懸命むずかしい計算をしているのも、一生懸命待っているのも、あまり変わりは無く電力を消費することになる(違うマイコンもあるが)。


Using libfplutil_print

標準出力(stdout)を、terminalに出力するようだ。
libfplutil_printは、libfpl_mainには依存していないらしく、単独で使える。


入れてみよう

githubからclone。
cloneしたが・・・configureとかがないな。
わからんので、exanplesを見る。

build_all_anrdoidというコマンドがあるらしいので、書いてある通りに打ってみた。
Androidまで接続していると、ビルドしてアプリ転送までやってくれる。

いろいろログが出てしまうが、こんな感じでlogcatに出てきた(logcat -s main、でフィルタできるらしい)。

I/ActivityManager(  535): Start proc com.google.fpl.libfplutil.example for activity com.google.fpl.libfplutil.example/android.app.NativeActivity: pid=24609 uid=10068 gids={50068, 9997} abi=armeabi-v7a
I/art     (24609): Late-enabling -Xcheck:jni
V/PhoneStatusBar(  651): setLightsOn(true)
V/threaded_app(24609): Creating: 0xac370b60
V/threaded_app(24609): Config: mcc=440 mnc=0 lang=ja cnt=JP orien=1 touch=3 dens=320 keys=1 nav=1 keysHid=3 navHid=0 sdk=21 size=3 long=1 modetype=1 modenight=1
I/main    (24609): Hello, World!


できることの最初だけしか見ていないが、Javaを何も書かなくても、とりあえずログだけではあるが動かせるというのは面白い。
どこまでどうできるのかわからないけど、自分でandroid OSをビルドするようなシステムを作っている場合、アプリから自分で組み込んだ下回りを動かすようなことができるかもしれんな。

アプリに組み込むというのも説明されているが、あとは各人でご参照下され。

2014/11/12

[android]fplutil (1)

Android Developersを見ていると、C/C++のユーティリティが出ていることに気付いた。
Utilities for C/C++ Android Developers: fplutil 1.0

最近はLinuxが使える組込み環境も増えてきたので、便利そうなものは知っておきたいところだ。
以前、Pocoというライブラリを使って、便利さに感激したのと同時に、知らなかったらどうなってたんだろうという恐怖も感じたため、そこら辺に積極的になってきている。


fplutilは、Fun Propulsion Labsの頭文字から来ているようだ。
"propulsion"は、推進、とか、推進力、とかの名詞。
楽しいこと推進研究室、みたいな訳でよいのかな?

ただ、この単語で検索するとあれこれ出てくる内容を見ると、「自分たちが楽しければいいから適当にやろうや」という"楽しい"ではなく、「この方面の楽しみ方にかけては、俺たちが一番だ」みたいなイメージがある。
まあ、そうかどうかは知らないが、とにかくそういう研究室なんだろう。


とりあえず、環境の作り方を見てみよう。

まず、普通にAndroid SDKが動かせる環境を作るようだ。
Javaなんかもそろえる。

そして、C/C++なので、Android NDKも。

さらに、Pythonが動かせる環境がいるようだ。
Windowsだと、2.7らしい。


今日はここで時間切れ。
すまぬ。。。

2014/11/10

[nrf51]sd_ble_gap_conn_param_update()はPeripheralなら呼ばずともよい?

相変わらずサンプルソースを見ている。
私も飽きない人だ。

ようやく定義値の意味を考え始めたところだ。
コメントに「sd_ble_gap_conn_param_update()を呼び出してから~」のようなものがあった。
ソース中では呼んでいないのだが、よいのだろうか?

この関数は、自分がCentralなのかPeripheralなのかで意味が違い、Peripheralの場合はCentralからの要求を待つ状態にするように読めた。
そして、パラメータにNULLを指定した場合はPPCPキャラクタリスティックを使う、とある。

確かにPPCPの設定は初期化時に行っている。
私の理解としては、PPCPの設定をしておくと、接続したときにConnection Parameter Update要求を送信せずに済むから楽でよいな、くらいだった。
しかしsd_ble_gap_conn_param_update()を説明を読んでから考え直すと、

  • デフォルトではsd_ble_gap_conn_param_update()でNULL指定されたのと同じ状態
  • だからPPCPの設定をしておかないといけない

ということのように思えてきた。

このあたりは、Core_v4.1の中でAdvertisingから接続するときの説明があったような気がする。
気が向いたら読んでおこう。

2014/11/08

[wsh]JScriptで改行ごと消し去りたい

前回、HTMLに書いた文字を置換するJScriptのことを書いた。
そのとき、「もういやだ」の行は文字だけ置換したのだけど、やはり行ごと消し去りたい。

 

inText = inText.replace(/もういやだ/g, "");

じゃあ、改行コードまで見るにはどうしたらよかろうかとmicrosoftのJScript.NETのページを見た。
ドット「.」の説明に、

'\n' を含む任意の 1 文字に一致させるには、'[.\n]' などのパターンを使用します。

とあるので、そう書いてみたのだが・・・だめっぽい。

こちらのサイトで、そうじゃないと書いてあった。
ありがたや。

 

var inFile = "test.html";
var outFile = inFile + ".html";
//読込み
var inStream = new ActiveXObject("ADODB.Stream");
inStream.Type = 2;      //text
inStream.charset = "utf-8";
inStream.Open();
inStream.LoadFromFile(inFile);
var inText = inStream.ReadText(-1);       // -1:全部 -2:1行ごと
inStream.Close();
//置換
inText = inText.replace(/<value2>/g, "abc");
inText = inText.replace(/<value1>/g, "-1");
inText = inText.replace(/^.*もういやだ.*[\s\S]/mg, "");
WScript.Echo(inText);
//console.log(inText);
//書き込み
var outStream = new ActiveXObject("ADODB.Stream");
outStream.Type = 2;
outStream.charset = "utf-8";
outStream.Open();
outStream.WriteText(inText, 0);    // 0:改行無し 1:改行有り
outStream.SaveToFile(outFile, 2);  // 1:なければ新規作成 2:新規作成かつ存在すれば上書き
outStream.Close();

[wsh]JScriptはShift-JIS + CR/LFっぽい

Windows上でJavaScriptを動かすときは、どうやらJScriptと呼ぶらしい。
JavaScriptともちょっと違った書き方ができるというか、何かルールがあるようだ。

ファイルを読んで、置換して、別ファイルに書き込む、というものを書いてみた。

var inFile = "test.html";
var outFile = inFile + ".html";
//読込み
var inStream = new ActiveXObject("ADODB.Stream");
inStream.Type = 2;      //text
inStream.charset = "utf-8";
inStream.Open();
inStream.LoadFromFile(inFile);
var inText = inStream.ReadText(-1);       /* -1:全部 -2:1行ごと */
inStream.Close();
//置換
inText = inText.replace(/<value1>/g, "-1");
inText = inText.replace(/<value2>/g, "abc");
inText = inText.replace(/もういやだ/g, "");
WScript.Echo(inText);
//console.log(inText);
//書き込み
var outStream = new ActiveXObject("ADODB.Stream");
outStream.Type = 2;
outStream.charset = "utf-8";
outStream.Open();
outStream.WriteText(inText, 1);    /* 0:改行無し 1:改行有り */
outStream.SaveToFile(outFile, 2);  /* 1:なければ新規作成 2:新規作成かつ存在すれば上書き */
outStream.Close();

読み込むファイルは、これ。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>Hello</title>
</head>
<body>
    <script language="JavaScript">
        var foo = <value1>;
        document.write("寒い<value2>。");
        もういやだ
    </script>
    Hello World!
</body>
</html>

<value1>に「-1」を、<value2>に「abc」を、「もういやだ」を空行にしたい。
「もういやだ」は行ごと削除したいけど、まあHTMLだからいいだろう。

これを実行したのだが・・・。
結果がこれ。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>Hello</title>
</head>
<body>
    <script language="JavaScript">
        var foo = <value1>;
        document.write("寒いabc。");
        もういやだ
    </script>
    Hello World!
</body>
</html>

中途半端に<value2>だけ置換されている。
よくわからんので、jsの方で<value1>と<value2>の順番を入れ替えた。
そうすると、<value1>が置換された。

ここら辺で、Windowsだから、ということに気付いた。
文字だけではわからないところだが、HTMLファイルはUTF-8/LF、JSファイルもUTF-8/LFで保存している。
やっぱりCR/LFじゃないとわからないってことか?ということで、JSファイルをUTF-8/CRLFにした。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>Hello</title>
</head>
<body>
    <script language="JavaScript">
        var foo = -1;
        document.write("寒いabc。");
        もういやだ
    </script>
    Hello World!
</body>
</html>

<value1>と<value2>は置換された。
そして日本語が残った。。。
ということは、Shift-JISじゃないとだめなのか?ということで、JSファイルをShift-JIS/CRLFで保存。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>Hello</title>
</head>
<body>
    <script language="JavaScript">
        var foo = -1;
        document.write("寒いabc。");
        
    </script>
    Hello World!
</body>
</html>

はー、そういうことなんですな。

結論としては、こう。

WindowsのJScriptは、Shift-JIS + CR/LFで保存しよう

 

ちなみに、このJSをそのまま動かすと、出力したファイルの最後にCR/LFの改行が入る。
「ちっ」と思っていたが、WriteText()で改行有りにしていたからだった・・・。

[wsh]JScriptでUTF-8ファイルを読んで置換して保存

今のお仕事の、作業環境にいろいろと制約がありましてな・・・。
簡単な作業をしたくても、パズル的に制約をかいくぐる必要がありまして。

今回やりたいのは、こんなこと。

  • Windows環境
  • ファイルを読み込んで、置換して出力したい
  • 文字コードは、UTF-8 / LF
  • 出力したファイルを別コマンドに喰わせたいので、スクリプト1発で済ませたい
  • Windowsの素の環境で動くこと+ダウンロードをまったく使わないこと

sedとかperlとかあれば済む話なんだけど、ネットを使えないので入っていない。
いや、頼めばやってくれそうではあるけれども、頼むのがめんどくさいし、少しくらい障壁があった方が燃えるじゃないか。
そもそも、この課題自体が自分で立てたようなものだし。

ネットで検索して、こんなコードができた。
ここに書いてもダウンロードできないけど、見ながら入力するのはよいだろう。

var inFile = "in.txt";
var outFile = "out.txt";
var inStream = new ActiveXObject("ADODB.Stream");
inStream.Type = 2;      //text
inStream.charset = "utf-8";
inStream.Open();
inStream.LoadFromFile(inFile);
var inText = inStream.ReadText(-1);       //-1:全部 -2:1行ごと
inStream.Close();
inText = inText.replace(/100/g, "-1");
inText = inText.replace(/ABC/g, "abc");
var outStream = new ActiveXObject("ADODB.Stream");
outStream.Type = 2;
outStream.charset = "utf-8";
outStream.Open();
outStream.WriteText(inText, 1);    //0:改行無し 1:改行有り
outStream.SaveToFile(outFile, 2);   //1:なければ新規作成 2:新規作成かつ存在すれば上書き
outStream.Close();

最後のSaveToFile()には、ドキュメントにだまされた
詳細はこちらをご確認くだされ。

あと、replace()の第1引数も想定と違っていた。
最初は"/100/g"のような文字列で書いてたんだけど、ダブルクオーテーションとかで囲むとダメなんだな。
理屈はわからんが、/で囲むのが正規表現値、みたいな意味なのかな。

2014/11/03

[rpi]Android端末をAccessory Modeにしてみよう

前回Raspberry Piにシリアルをつけたけど、SSHが使えるんだったらそっち経由でよいことに気付いた。
どこら辺の問題かわからないけど、シリアルを取りこぼしているような感じがするのだ。
ばたばた出力が流れていると、いつの間にか1文字分が遅れているような感じだ。
TeraTermからリセットを通知するとうまくいくし、そうでなくても「遅れる」という現象なので、データとしては届いていると思うのだ。
んー、なんだろう?

 

それは忘れて、Raspberry PiとNexus5を接続して、Nexus5をAccessory Modeにしてみよう。
Accessory Modeというのは、USB Host機能を持つ端末にAndroid端末を接続し、データを通信し合うモードだ。
標準?といってよいかわからないが、Arduino MEGA ADKが一般的によく使われるようだ。
Arduino UnoなどにUSB Hostのドータボードを載せればよいとも聞いた。


理屈はそんなに難しいものではなく、USB接続して、Accessory Modeになる手順を通信すればよい。

ドライバを作るとよいのだろうが、あまり手間はかけずにアプリだけで実装した。
libusb 1.0でNexus5のVID/PIDを検索してオープンし、libusb_control_transfer()でACCESSORY_GET_PROTOCOLを送信してNexus5がAccessory Modeをサポートしていることを確認し、ベンダ名、モデル名、ディスクリプション、バージョン、URI、シリアル番号を送信し、最後にACCESSORY_STARTを送信。

そうすると、Nexus5に対応したアプリが入っていないためかURI先に飛ぶ確認画面が出てきた。
Androidアプリはまだ作っていないのだが、セミナーでやった様子からすると、対応したアプリがあればこのタイミングで起動することだろう。

上で出てきたACCESSORY_STARTなどは、f_accessory.hというヘッダファイルに定義してある。
これがどこから持ってきたのか・・・。
gitには入っているようなので、AOSPから落としてくるか、少なくともkernel-headersだけでもcloneすればよいのではなかろうか。

 

むかーし、この辺りは調べていたようだが、もう3年半くらい前になるため記憶がほとんどない。。
BeagleBoardにAOSPであれこれ試しながら進めていたようで、プロトコルを訳しながら調べたドキュメントもあった。
やるなあ、当時の私。

2014/11/02

[pi]シリアルケーブルをつなぐ

ひさーしぶりに、Raspberry Piに火を入れた。
たまには違うことしないと、頭が固まりそうだからね。


image

シリアルケーブルは、スイッチサイエンスさんから購入していたものを使う。
http://www.switch-science.com/catalog/1196/

レベルコンバータとか使うのが面倒なので、3.3Vで使えるケーブルがあるから買っていたのだ。
ここで使うとは思ってなかった。

思ってなかったが、上記ページに行くと、Raspberry Piへの接続が載っていた。
なんか、先回りされた気分だ・・・。

このケーブルはUSBから電源を供給しているので、microUSBケーブルがなくてもONできるのがありがたい。

最初、buildrootか何か忘れたけど、自分でビルドしたシステムで起動させていたのだが、シリアルには何も出てこなかった。
オリジナルのRaspberianにすると、出てきた。

LANケーブルをつなげばpingも通ったので、HDMIで画面出さなくてもなんとかなりそうだ。
グラフィックを使う予定がないときは、コンソールの方が楽なのよねぇ。

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

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

前回から1ヶ月半くらい経ったが、それなりに経験値が上がったように思う。
メモとして残しておこう。


Keil v5を試した。

さすがというか、使いやすいと感じた。
今はgcc環境ができあがっているから使わないけど、仕事でやるならこれだろう。


スケジューラについて調べた。

今のところ、割込コンテキストで動作する時間を短くするためのもの、という解釈をした。


試しに、サービスを含めて一式作ってみた。
といっても、サンプルを改造しただけだが。

  • [nrf51]はじめてのBLEアプリ - (1)サービスをつくる
  • [nrf51]はじめてのBLEアプリ - (2)アプリを作る
  • [nrf51]はじめてのBLEアプリ - (3)デバッグ
  • サービスについてはドキュメントもあったため比較的やりやすかったが、アプリ部分はよくわからないまま流用している。


    わからんままじゃだめだろう、ということで、BLEイベントハンドラを調査した。

  • [nrf51]BLEスタックのイベントハンドラを見る (1)
  • [nrf51]BLEスタックのイベントハンドラを見る (2)
  • [nrf51]BLEスタックのイベントハンドラを見る (3)
  • [nrf51]BLEスタックのイベントハンドラを見る (4)
  • [nrf51]BLEスタックのイベントハンドラを見る (5)
  • [nrf51]BLEスタックのイベントハンドラを見る (6)
  • nRF51 SDK v4のドキュメントであればシーケンスが載っていることがわかったのが、一番の収穫だった。


    こんなところか。
    まあ、がんばってるんじゃないかね、うむ。

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

    サンプルソースのBLEイベントハンドラの調べ物。
    最後の1つだ。


    BLE_GATTS_EVT_SYS_ATTR_MISSING

    前回まではGAPのイベントだったが、これはGATT Serverのイベントだ。

    https://devzone.nordicsemi.com/documentation/nrf51/4.3.0/html/group___b_l_e___g_a_t_t_s___s_y_s___a_t_t_r_s___b_o_n_d_e_d___p_e_e_r___m_s_c.html

    Disconnectされたとき、SoftDeviceにsystem attributeデータを取得して保持しておき、次に接続するときに再設定するしくみのようだ。

    BLE_GATTS_EVT_SYS_ATTR_MISSINGの説明としては、sd_ble_gatts_sys_attr_set()待ち、らしい。
    確かにイベントハンドラでも、sd_ble_gatts_sys_attr_set()を呼び出している。
    "persistent system attribute"というのは、BLEスタックが返す値のようで、アプリはそのコピーを持っておき、この関数で渡すようなしくみらしい。
    コピーじゃなくてNULLを渡すと、前回の値はないよ、ということで初期化されるようだ。
    storageという単語が出てくるから、保持しておきたいデータ、みたいな使い方なのか。

    サンプルではNULLを渡すだけになっている。


    似たような感じで、Notify投げようとしてエラーで帰ってくる場合もあるようだ。

    https://devzone.nordicsemi.com/documentation/nrf51/4.3.0/html/group___b_l_e___g_a_t_t_s___h_v_x___s_y_s___a_t_t_r_s___m_i_s_s_i_n_g___m_s_c.html

    sd_ble_gatts_hvx()を呼んで、エラーが発生した場合のようだ。
    まずsd_ble_gatts_hvx()はNotifyを投げるときに使っている。
    サンプルでは、このエラーが発生すると、単にエラーという扱いにしている。

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

    nRF51 SDKを読んでも理解できなかったので、あれこれ読みながら調べている。


    BLE_GAP_EVT_TIMEOUT

    サンプルにあるGAPイベントの最後が、これ。
    https://devzone.nordicsemi.com/documentation/nrf51/4.3.0/html/group__nrf51__evt__timeout__encoding.html

    サンプルではAdvertisementでタイムアウトした場合の処理だけしてある。
    取り得る値は、以下。

    • BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT
    • BLE_GAP_TIMEOUT_SRC_SECURITY_REQUEST

    Advertisingのタイムアウト時間は、sd_ble_gap_adv_start()で設定している。
    Security Requestの方は、sd_ble_gap_sec_params_reply()か、30秒(Core_v4.1 Vol.3 Part.H "3.4 SMP TIMEOUT")だと思う。

    ビーコン端末だとAdvertisingでタイムアウトしたら困るよな、とble_app_beaconサンプルを見ると、0で指定されていた。