2016/07/31

[nrf52]NFCタグ設定のタイミングをずらしたが、ダメそうだ

nRF52のNFCペアリングサンプルで、うちのNexus5がうまくペアリングできない件を、まだやっている。

[nrf52]Pairingサンプルのタグ (2016/08/01:URL修正)

これの結果から、Advertisingを始めてからタグを設定したらいいんじゃないの?と思ったので、ようやく試した。

 

オリジナルでは、ペアリングしていないときは起動時にペアリング用のタグ設定をして、搬送波を検知してからAdvertisingを始める。
それを、

  • 起動時は搬送波検知だけ(タグの設定は特にしない)
  • 搬送波検知したらAdvertising開始と同時に1秒タイマ開始
  • タイムアウトしたらペアリング用のタグ設定をする

という順番にしてみた。

 

・・・ダメだった。
ダイアログにNordic_HRMが出るときもあるのだが、出ないときもある。
Bluetooth設定画面を開いたときは機器の検索をするのだけど、あのタイミングであれば成功しやすい感じがするが、確実ではない。

なんか、なんかよくわからん。
logcatを見比べたのだが、どっちもこんなログが出ていた。

I/BluetoothPeripheralHandover: ACTION_CONNECT addr=xx:xx:xx:xx:xx:xx name=Nordic_HRM

名前もアドレスも出てるんだけどねぇ。

I/ActivityManager: Displayed com.android.nfc/.handover.ConfirmConnectActivity: +121ms

こんなのも出ているから、名前がわかってからダイアログを表示しているような気がするのだが。。。
nRF Connectでスキャン中だったら引っかかりやすいかと思ったが、そうでもないし。

うーん、やはり今日もわからなかった。

[android]AndroidのBLEは今ひとつらしいが、つながりが悪い以外はよくわからなかった

もう少しでAndroid作業ともお別れになりそうなので(なってほしいという期待も含め)、メモを残しておく。

メモというか、よく「iOSと比べると今ひとつ」とよく耳にしたのだが、よくわからなかったという話だ。

 

確かに、よくわからない理由でつながらないとか、Androidだけ動きが変とか、そういうのはよくあった。
APIを呼んだタイミングとRFで出ていくタイミングが違ったり、受信したはずの時間からコールバックまで時差があったり、そういうのはあった。
ほかにも、いろいろあったさ。ああ、あったよ。。。

 

まあ、それだけで十分という気もするが、APIについてはBluetooth Developer Studioの自動生成ソースを参考にしてあまり悩まなかったせいか、こんなもんじゃないの?というところで終わってしまった。

iOSと比較すれば良いのだろうが・・・ごめん、調べてません。
やっぱり、いいのかなぁ。
私としてはあまり困らなかった、というだけかもしれない。

ただ、エラー値は変換せずにそのまま上げてほしかったところだ。
status=133って言われても、logcatを見ると違う値だったりしたので、結局テスト中は全部のログを見ないとわからず、疲れた。


iOS Developer Programって、毎年お金がかかるから、もう止めてしまったのだ。
今だといくらなんだろう?

https://developer.apple.com/programs/how-it-works/jp/
11,800円かー。
経費で落としたところで、元が取れるほど使わないのが目に見えてるので、LightBlueでいいや、と思ってしまうのだ。

もう、人に配布できるようなアプリを作ることができないのはわかっているから、自分の実機に焼いて試すだけの権利がほしいところだ。

2016/07/30

[nrf52]Centralしていく (3)

前回、何もいないのにAdvertisingのログが出る、と書いたけど、そういえばテスト中で動かしっぱなしにしているのがいるのを忘れていた。
それに、近くでAppleTVを持っている人がいるのか、それらしいAdvertisingもスニファで見えていた。

 

スニファと言えば、nRF51 DKをスニファとして使うというのは、ありなんじゃないかと思い始めている。
受信するだけだからだ。
まあ、送信する機能もある装置なのにどうよ、という気もするのだけど、その辺は信じてください、としか言いようがないな。

nRF52 Preview DKをスニファにしてみたのだが、まあまあ動いた。
数字を入力するタイプのペアリングを行うと、どうもうまく拾えないのだ。
まあ、まだ正式なnRF52用のFirmwareが出てないし、そもそもPreviewだしねぇ。

TIのスニファも、ペアリングのときからパスキーを打ち込んでいても途中で止まるのだ。
"TI ペアリング"で検索しても「ティファニーチタンペアリング」が出てきてガックリしたので、本題に戻ろう。


前回は半分寝ながら書いたので、もう一度。

出ているのは、BLE_GAP_EVT_ADV_REPORTイベントのログ。
typeが2と3のログが出ているが、これはまずtype=2で試して、だめだったら3で試す、という方式をとっているからだ。

2は、«Incomplete List of 16-bit Service Class UUIDs»。
3は、«Complete List of 16-bit Service Class UUIDs»。

IncompleteでもCompleteでもいいから、16bitのService UUID、つまりBluetooth SIGに登録されている一般的なUUIDがあるかどうかを見ているのだろう。

HRSのPeripheralでは、Complete Listを使っている。
0x180D(Heart Rate)、0x180F(Battery)、0x180A(Device Information)の3つだ。
services


Advertisingのデータは、Length, Type, Valueの並びだ。
Lengthは自分を含まない長さで、1byte。
TypeはAD Typeで、1byte。
たとえば、<<Flags>>は中身が1byteなので、Lengthは0x03、Typeは0x01だ。

BLE_GAP_EVT_ADV_REPORTイベントが来ると、p_ble_evt->evt.gap_evt.params.adv_reportにデータが返ってくるようだ。
型はble_gap_evt_adv_report_tで、こうなっている。

typedef struct {
  ble_gap_addr_t peer_addr;
  int8_t         rssi;
  uint8_t        scan_rsp : 1;
  uint8_t        type     : 2;
  uint8_t        dlen     : 5;
  uint8_t        data[BLE_GAP_ADV_MAX_SIZE(=31)];
} ble_gap_evt_adv_report_t;

あれ、typeって2bit分しかないの?と思ったが、そうではなくてBLE_GAP_ADV_TYPESの値とのこと。
なるほど、Advertisingの種類ということですな。
scan_rspが0のときだけ有効とのこと。

dataは31byteだから、ADV_INDなどのペイロードが全部入っているのだろう。
adv_report_parse()ではそれを頭から見ていって、typeが一致したらペイロードのアドレスとデータ長を返す、なければNOT_FOUNDを返す、という作りになっている。

 

今コミットしているソースだと、検索しているだけで、実際にそれを使うL.376~をコメントアウトしているから、次はそれを見ると良いだろう。

とりあえず、このくらいのソースでAdvertisingのスニファくらいはできるということはわかった。

2016/07/29

[win10]ウィンドウの枠を太くしようとしたが、ダメだった

Windows10にしてしばらく経つが、ウィンドウの枠が細いのが気になってきた。

普通はそこまでないのだが、コマンドプロンプトやTeraTermを重ねて非アクティブになると、境目がわからないのだ。

image

 

普通のテーマは、Aero.
C:\Windows\Resources\Themes\aero\aero.msstylesを使っている。
同じフォルダにあるaerolite.msstylesを使うと、太くなる!

image

太くなるのだけど、タスクバーの文字が黒になってしまうのだ。
うちは暗めの色を使っているので、これが黒になると使い勝手が悪い。

msstylesファイル自体をいじらないと、ちょっと使うのは厳しいようだ。


とまあ、結果だけだとそれで終わりなのだが、そこまでが長かった。

Themeファイルの構造を調べていたのだ。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/bb773190(v=vs.85).aspx

PanelDesktopWindowMetricsを設定すればいけるかも、と思い、NonclientMetricsのデータ構造まで調べたのだよ。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ff729175(v=vs.85).aspx
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd145037(v=vs.85).aspx


 

でも、幅っぽいところを変えても変化が見られなくてね。。。
aeroliteにすると太くなるから、それしかないのだろうと思ったのだ。

msstylesファイルを編集するツールがあったのだけど、編集して保存するとサイズが変わるのよねぇ。
それに、aeroliteをコピーしてaerolite2を作ってみたけど、それをPathにしていしても反映されないようなのだ。
aeroliteのファイル名を変更しようとしたら、TrustedInstallerのアクセス権限がいるとかなんとか。
ちょっと特殊なようだ。

2016/07/28

[nrf52]Centralしていく (2)

nRF52832+S132でCentralを試していくシリーズ。

BLE接続させたくないを動かしてみよう。


立ち上げて、HRSのPeripheralを動かすとこういうログが出てきた。

[on_ble_evt]BLE_GAP_EVT_ADV_REPORT
[adv_report_parse]type=2
[adv_report_parse]type=3
[on_ble_evt]BLE_GAP_EVT_ADV_REPORT
[adv_report_parse]type=2
・・・

まず、最初のADV_REPORTは、ここだ。
on_ble_evt()でイベントを受けるのは、Peripheralと同じだ。
まあ、PeripheralでAdvertising中はon_adv_evt()なので、違うといえば違うのだが、Central目線で考えると妥当な気がするのだ。

 

BLEのPeripheralとCentralは、ネットのServerとClientの関係とちょっと違うように感じてしまうのだ。
ネットのHTTPサーバには、ブラウザというHTTPクライアントが接続しに行く。
BLEだと、PeripheralにCentralが接続しに行く。
だから、PeripheralがServerで、CentralがClientになることが多い。
データの提供元はだいたいセンサで、センサはPeripheralになっていることが多いからね。

なんとなくだが、データを集める方がサーバという気がしてしまうのだ。
クライアントがアップする、ということが多いからだろうか?
しかし、データを提供する方がServerで、もらう方がClientだから、いくらファイルサーバなどと名乗っていたとしても、データを提供するのはセンサだから、データを集めるファイルサーバはクライアントになるのだ。

言葉遊びみたいになってしまいますな。


さて、ログに戻ろう。

下からADV_REPORT通知が来て、adv_report_parse()を呼んでいる。
これはローカルな関数で、データがある限り解析をしているようだ。

そのtypeは、2と3だけだ。
2が"BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE"で、3が"BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE"だろう。

typeの定義値は、ble_gap.hにある。
値は、Bluetooth SIGのAD Typeと一致するようだ。
adv_report_parse()の実装からすると、受信したAdvertisingデータの中で指定したtypeがあったら解析してくれ、というやり方のようだ。

まあ、30バイト前後のデータだから、それでよいのかもしれない。
それに自作ではなく汎用のUUIDなので、この程度のチェックでよいということかもしれない。
自作だったら、Advertisingデータもある程度固定になるので、その内容までチェックしたいはずだ。


今日はこれまでだ。

まだわからないこととして、Peripheralを検知したあと、Peripheralの電源を切ってもイベントが来続けているのだ。
単に、コメントアウトのしかたがまずかったのか、来るのが普通なのかで実装が変わってくるだろう。

2016/07/27

[nrf52]Centralしていく (1)

サンプルソースを読んでいても眠たくなってしまうし、ブログに記事がないのも寂しいので、Centralを動かしていくことにしよう。

nRF52832で見ていくが、たぶんnRF51822+S130でもそんなに変わらないと思う。
うちも、IC rev3があればよかったのだが、まあ彼はPeripheralとしてがんばってもらおう。
S130でもPeripheralは動いているから、Centralでも動くような気はするのだけどね。


今日は初回で眠たいので、準備だけにしておく。

https://github.com/hirokuma/nrf52_central_sample

nRF5 SDK v11のCentralサンプルを、そのまま持ってきた。
gcc以外の環境を削ったり、ログ追加されていたりするが、ほぼそのままだ。

 

このまま動かすとサンプルが動くだけだから、理解のためにBLE接続していると思われる箇所をコメントアウトした。
BLE接続させたくない

これで接続されずにAdvertisingしているログだけ出るのでは、という予想だ。


試してみれば良いのだが、いま机の上でBLEの連続テスト中でね。。。
寝ている間にテストが終わるようにしたいのだ。

 

長い時間動かすと、普通ではわからなかったバグが見つかったりするから、みんなやった方がよいよ。
頻度が低くて、今まで見たこともなかったような現象が出たりするしね。
ええ、今出てますとも。。。

2016/07/24

[nrf52]Centralサンプルを動かす

いままでBLEのPeripheralしか作っていなかった。
受ける側のCentralはスマートフォンに任せておけば良いだろう、と思っていた。

が、通信がうまく行かないことがあって、無線状況が原因では無さそうな感じがした場合、それが誰のせいなのかよくわからない。
スニファで見られるときは良いのだけど、TIのドングルはペアリングしていると接続後に途中でパケットが見えなくなってしまうようなのだ。

スマートフォン側のログを見ても、全部出るわけじゃないし、なんでそういうことになったのかまではわからない。
なんとなくドライバが原因のような気はするのだけど、もしかしたらPeripheral側がちょっとよくないのかもしれない。

 

こういう、Peripheral側にも原因があるのではないかという不安を払拭するためには、もっと信頼性の高いCentralが必要だ。
お客さんに「たぶんスマートフォンのBLEドライバ周りが原因だと思うんですけど。。。」と語尾を濁すのには疲れたのだ。

nRF Connectのデスクトップ版が使えるとよかったのだけど、nRF52 DKのようなNordicが出している基板じゃないと動かないようだった。

nRF51822がいくつかあるので、それでCentralを回せば良いのだけど、どうもS130はIC revisionが3以上ではないと動きを保証してくれないようなのだ。
じゃあ、nRF52832でやろう。


今回は、サンプルを動かすだけの紹介だ。
評価ボードは、太陽誘電さんのEBSHCNZXZを使う。

nRF5 SDK v11.0.0のexamples\ble_central\ble_app_hrs_cを使う。
「_c」は、Centralだと思うが、もしかしたらHRSのclientという意味かもしれない。

gcc版で試しているが、特に難しいことはなく、PCA10040でmakeするだけでよい。
これをEBSHに焼いて起動する。
USBはシリアルポートとして見えるので、TeraTermなどでつないでおく。115200bpsだ。
そうすると起動時に「Heart rate collector example」が出力される。

あとは、HRSのPeripheralを動かすだけだ。
今回はnRF51822のHRSサンプルをS110上で動かした。
そうするとペアリング(たぶんJust Works)して、取得した値をシリアルポートで見ることができる。

あっさりだ。


シリアルに出力されるのはAPPL_LOG()の内容で、デバッグ情報のAPPL_LOG_DEBUG()はそのままでは出力されない。
Makefileに「-DDEBUG」などとしてDEBUGマクロを有効にしておくと、nrf_log.hが使えるようにしてくれる。

 

ペアリングさせないようにSEC_PARAM_BONDをどちらも0にしたけど、DM_LINK_SECURED_INDのルートを通るな、うーむ。。。

まあ、ともかく、サンプルは簡単に動かせることがわかったので、中身を見ていこう。

2016/07/23

[esp8266]mbedTLSサンプルのコンパイルが通らない (2)

順番に確認しよう。


__GNUC_PREREQ (3, 2)

これでエラーが出ているのは、__GNUC_PREREQ()というマクロがないからだろう。
cygwinのgccが5.4.0だったので、コンパイルしてみる。

#include <stdio.h>

int main(int argc, char *argv[])
{
#if __GNUC_PREREQ(5, 5)
    printf("prereq\n");
#else
    printf("??\n");
#endif

    return 0;
}

通って、elseルートを通った。
(5, 4)にするとifルートを通るので、majorとminorが指定したバージョン以上であれば真になるマクロのようだ。

/* Macro to test version of GCC.  Returns 0 for non-GCC or too old GCC. */
#ifndef __GNUC_PREREQ
# if defined __GNUC__ && defined __GNUC_MINOR__
#  define __GNUC_PREREQ(maj, min) \
    ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
# else
#  define __GNUC_PREREQ(maj, min) 0
# endif
#endif /* __GNUC_PREREQ */

xtensa-lx106-elf-gccのバージョンは、4.8.3。
-cでビルドだけさせようとしたが、やはりコンパイルエラーになった。
「__」を外しても同じ。
試しに、同じ名前のマクロを定義してみたが、warningも出なかった。
本当にないんだ。。。

cygwinで同じことをさせてみると、/usr/include/sys/features.hにマクロ定義があるようだった。
ESP8266用のVMでgccコンパイルさせると、/usr/include/features.hに定義があることがわかった。
が、これはgccだからだよな。。。。

 

あ、/opt/xtensa-lx106-elf/xtensa-lx106-elf/include/sys/features.hがあった。
この中には__GNUC_PREREQ()がいる。
じゃあincludeさせてみればよいかと思ったが、やっても同じだ。

なんだ?


<sys/features.h>と書いてエラーにならなかったから、少なくともそういう名前のファイルは読み込めているのだと思う。
だからあり得るのは、

  • 検索パスで先に別のファイル名が引っかかっている
  • includeガードで同じ名前を使っているものがいて、ガードされている

のどちらかだろう。

後者の方が簡単に調べられるので、#ifdefでやってみたが、定義されていなかった。
そして、<sys/features.h>をincludeすると、定義されているようになった。
じゃあ、ガードされているわけではないようだ。

features.hの中身をコピペしたファイルをdemoのフォルダに置いてincludeさせてみた。
それだとうまくいく。
じゃあ、読んでいるファイルが違うだけ、ということか?

echo | xtensa-lx106-elf-cpp -Wp,-v > paths.txt 2>&1

こんな感じで検索パスを取ってくる。

#include <...> search starts here:
/opt/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/include
/opt/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/include-fixed
/opt/xtensa-lx106-elf/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/include
/opt/xtensa-lx106-elf/bin/../xtensa-lx106-elf/sysroot/usr/include
End of search list.

見ているパスと違うな。。。
xtensa-lx106-elfのincludeじゃなくて、lib/gccのずっと下にあるincludeだ。
こっちのfeatures.hには__GNUC_PREREQ()がいない!!

そういうことか・・・。


面倒なことに、エラーを出しているstdint.hはinclude_nextを使っていて、それが私が見ていたパスになるのだ。
だから、features.hもinclude_nextでやってやりたいところなのだが。。。

 

ああ!
リンク先のCompiler_Update_20150727.zipの方はlib/gccの下にあるincludeにはsysフォルダ自体がない!
https://drive.google.com/drive/u/0/folders/0B5bwBE9A5dBXaExvdDExVFNrUXM

じゃあ、こっちを使えば自動的にsys/features.hは自動的に期待している方のファイルを見に行くということか。。。

 

VMで提供されているコンパイラは/optに置いていたが、新しい方は自分のところで使うことを想定しているようだ。
書いてあるように、/optにある方を削除して、~/にbz2を展開して、.bashrcにパスを追加して、sourceなどで読み直す。

mbedtls_demoに移動して、make clobberで消して、./gen_misc.shでビルド。。。
ああ、ビルドが通りました。

[esp8266]mbedTLSサンプルのコンパイルが通らない

せっかくESP8266がmbedTLSをサポートしたので、必要があるかどうかは別としてビルドくらい試しておこう。
そう思って付属していたmbedtls_demoをビルドしていたらエラーが出た。

stdint.h:18:19: error: missing binary operator before token "("
#if __GNUC_PREREQ (3, 2)

とか、

xtensa/simcall-fcntl.h: No such file or directory

とか。


ESP8266のコンパイラは、ここから持って行っている。
http://bbs.espressif.com/viewtopic.php?f=57&t=2
 ↓
https://drive.google.com/folderview?id=0B5bwBE9A5dBXaExvdDExVFNrUXM&usp=sharing#list

 

新しいバージョンも無さそうなのだが、元になっていると書かれているcrosstool-NGを使った方が良いのか?

2016/07/22

[mrubyc]mruby/cをcygwinで動かしてみよう

以前、mruby/cのことを書いてから何もしていない。
Ruby自体、記憶からなくなってしまったが、mruby/cだけでも動かしてみよう。

cygwin上で動かす。


https://github.com/mrubyc/mrubyc/releases

今のところ、beta2がリリースされているので、それを取ってきた。
解凍して、make。
うん、ビルドできた。

よくわからんが、sample_cにできたmrubyc_sampleは動かせるようだ。
動かすと、「30」と出てきた。
うん、30だ。

これは、
https://github.com/mrubyc/mrubyc/blob/master/sample_ruby/basic_sample01.rb
で、10と20を足した結果をputするサンプルだった。
だから、30だ。

 

ただ、このbasic_sample01.rbはsample01.cになっていて、中は配列だ。
コンパイルしたバイトコードらしい。
それをloca_mrb_array()に通して、vm_boot()すると実行されるようだ。


他のサンプルも作ってみようとしたが、それにはmrubyに入っているコンパイラがいるようだ。

https://github.com/mruby/mruby/releases

今のところ、1.2.0が最新なので、それを取ってきた。
解凍して、make。
bisonがなかったので、取ってきてmake。
うん、ビルドできた。

binの中にmrbcがあるので、それだけ持ってきた。

$ ./mrbc.exe sample_ruby/basic_sample02.rb

これで、sample_ruby/basic_sample02.mrbができる。

$ cd sample_c
$ ./mrubyc ../sample_ruby/basic_sample02.mrb

うん、100~199までコンソールに出力された。


mrbファイルとsample01.cを見比べたが、単にmrbファイルを配列にしただけだった。

変換は何かツールがあるんだろうか?
と思ったら、mrbcのオプションで-Bに配列名を付けると生成してくれた。

$ ./mrbc.exe -Bany sample_ruby/basic_sample02.rb

これで、any[]という配列ができる。
これをmain_sample.cのまねをしてやれば実行できるのだろう。


さて、これを組み込みに使うのかどうか。。。

とりあえずは、RAMが最低でどのくらいいるのか、ですかね。
sizeで見てみた。

$ size sample_c/mrubyc_sample.exe
   text    data     bss     dec     hex filename
  27697    2500   33968   64165    faa5 sample_c/mrubyc_sample.exe

うん、よくわからん。
BSSは初期値を持たない変数のセクションということは、RAMということよね。
32KBくらいあるけど、大きすぎやしないかい?
cygwinでやっているからかなぁ。
余分に確保してあって、アプリを書いてもあまり増えないタイプもあるからな。

しかし16bitマイコンで使うのだったら、16KBもRAMがあるんだろうか?
RL78を使ったことがあるけど、あれの16KBはけっこう上位の方だったような。
その辺も、セミナーに行けば聞けるかもね。

[esp8266]Non-OS SDK Version 2.0.0とmbedTLS

ESP8266のバージョンアップって、RSSなどで引っ掛け方がよくわからないので気付かないのよね。
いつの間にか、2.0.0になったようです。

http://bbs.espressif.com/viewtopic.php?t=850&p=2915#p2915

mbedTLS ??
http://bbs.espressif.com/viewtopic.php?f=46&t=2443

これは、Non-OS SDK2.0.0とは別のファイルとしてリリースされている。
Ver 2.0.0より前の人はここからいろいろコピーしてね、ということらしい。

つまり。。。
axTLSの制限が外れたということか!
しかも、以前のバージョンであってもよいということだ。

 

リリースノートを見ておこう。
面倒なので、コピーペーストで済まぬ。

  • 1.1. Supports TLS 1.0, TLS 1.1, TLS 1.2, doesn’t support SSL 3.0.
  • 1.2. TLS cache of 2048 to 8192 bytes.
  • 1.3. Supports  AES-128 and AES-256 encryption algorithm, and CBC mode.
  • 1.4. Supports SHA-1, SHA-256, SHA-384 and SHA-512 hash algorithm.
  • 1.5. Supports RSA-512, RSA-1024, RSA-2048 algorithm.
  • 1.6. Supports certificates in PEM format and DER format.
  • 1.7. Supports both unidirectional authentication and bidirectional authentication.
  • 1.8. Supports three-tier certificate chain parsing.
  • 1.9. Doesn’t support verify three-tier certificate chain with root certificate.

楕円曲線暗号なんかは乗ってなさそうだけど、axTLSがTLS1.1までだったのでつなげられないサーバもあっただろうと思う。
そこら辺がいけるようになったのかな。

 

ESP8266だとArduinoしてる人が多いようだけど、そのうち使えるようになるのだろうね。

[android]Android StudioでJavaDoc

Android Studio 2.1.2のWindows版でJavaDocを作ろう!
私は比較的、コメントをたくさん書くのが好きなのだ。


メニューから「Generate JavaDoc...」を選択。

image

そうするとダイアログが出てくる。
設定して、一番下のOKを押すと生成される。

Other command line argumentsに-encoding UTF-8 -charset UTF-8」を書いておいた方がよいと思う。
お客様にリリースしたら、IEとChromeで文字化けしますっていわれてね。。。
Firefoxだと出ていたから安心していたのだよ。

 

私はモジュールだけJavaDocにしたかったのだけど、Custom scopeでコンボボックスからモジュールを指定しないと、R.javaとかBuildConfig.javaなんかも出てしまったのだ。
なんだろうね?


で、JavaDoc形式だ。

私はDoxygen形式でコメントを書くことが多いので、JavaDocも似たようなものだろうと思ってかなり失敗した。
今もうまく書けたと思ってない。

きれいに見せたかったら、ソース上での見栄えはあきらめて、HTML形式で書くのがよさそうだ。
<br>と<ul>~</ul>だらけになってしまった。

改行は<br/>じゃなくて<br>にしないとエラーになる(警告だったかも)。
どうも、後ろにスラッシュが来るタイプはダメらしい。

あとは、/**< ~ */とか///< のような後置タイプは使えない。
あれはdoxygen用のようだ。
おかげでenumとかpublic finalにした固定値なんかの説明で縦が長くなってしまった。

 

そういうのをあきらめれば、比較的まともな見栄えのコメントになるようだ。
Android Developersみたいに、引数や戻り値をテーブル形式にしたいのだけど、そこまではわからなかった。

2016/07/20

Bluetooth SIGからのメール2通

昨晩、Bluetooth SIGからメールが届いていた。
たぶん、Bluetooth Developer Studioをダウンロードしたときに登録したメールアドレス宛だろう。


1通目。

Bluetooth Developer Studio Usability Survey - win a $200 Amazon gift card

いやあ、これは怪しむでしょう!

心配なので、aguseさんで確認した。
リンク先の安全性をチェックできるサイトは、私はここしか知らないのだ。

見てみると、アンケートサイトに飛ぶようだ。
Bluetooth Developer Studioに対する質問らしい。

心配なので、ブラウザをステルスモードにしてやってみた。
「英語にどのくらい慣れてますか?」から始まり、どのくらい開発してきた人なのかや、BDSをどのくらい使っているか、のような当たり障りない内容ばかりだった。
後半は「このツールをどのくらい使いたいと思う?」みたいな質問だったので、英語に自信がなくなってきた。。。

ともかく、このサイトだけではどうのこうのはなく、最後に「全部答えたけど200ドルどうする?」と聞かれたので、とりあえずメールアドレスだけ入れてみた。
どうなるんだろうね?


2通目。

Update to your Bluetooth guest account

こちらは、どうやらBluetoothへの質問をStack Overflowに移動しました、ということらしい。

BLEの場合

2016/07/18

[nfc]NFC Forumジャパンミーティングの記事がよくわからん

Googleニュースのキーワードに「NFC」で登録をしているのだが、最近いくつかニュースが引っかかっていた。

第11回 NFC Forum ジャパン・ミーティング

  • JR東日本「公共交通におけるNFC規格のハーモナイゼーションについて」
  • NFC Forum Japan Task Force「GSMA/GCFによるNFC Forum規格の採用について」

記事になっているのはこの辺の話だろうか。
もうちょっと後ろに技術解説もあるのだが、RFの話っぽいから違うのかな。


引っかかったのは、こういう記事。

iPhoneでモバイルSuicaが使えるようになる? - NFC対応スマートフォンにFeliCa搭載という流れ (1) NFC Type Fの採用が決め手となる | マイナビニュース

今後のiPhoneがおサイフケータイ(FeliCa)に対応しそう!JR東日本がNFC Forumに働きかけ、2017年4月以降はグローバルモデルで対応にーーいよいよ日本のガラパゴス状態は解消か - S-MAX

読んだけど、よくわからん。
文章が悪いとかそういう話じゃなくて、記事とスライドの内容が一致していない感じがして、あやしげにみえるのだ。

だいたい、紹介しているスライドでも「NFC-F」って書いているのに、なんで記事では「Type-F」って書いてるんだろう?

 

一番、地に足が付いている記事は、こちらだと思う。

【レポート】2017年4月以降出荷されるグローバルモデルのNFC搭載スマートフォンはNFC-Fを実装する見通しに ~第11回NFCフォーラムジャパンミーティング | ePayments.jp - 電子決済研究所ウェブサイト


まず、JR東日本がNFC Forumに加入した、という話。
http://nfc-forum.org/about-us/our-members/#ejrc
さんざん企業アイコンを探したけど、画像無しかよ!
えーっと、Associate Membersとして登録したようだ。
有名どころ?はこういうところだ。
http://nfc-forum.org/about-us/our-members/associate/

ちなみに、よく「Appleも加入!」と出てくるけど、あちらはSponsor枠。
Google何かもそうですな。
http://nfc-forum.org/sponsor/


Suica事業本部担当部長の基調講演。

  • FeliCaで使っている212/424kbpsの規格はISO/IEC 18092にもなってるから、国際規格にはなっている
  • でも、NFC Forumが確立する前はスマートフォンなどもISO/IEC 14443のType-A/Bだけだったから、「対応してますか?」と聞かれると答えに窮した
  • が、最近はNFC ForumができてNFC-A/B/Fが標準になってスマートフォンにも搭載されるようになったから、そういう意味では安心している

私の勝手な文章が混ざっているので、ご注意を。

 

  • 相互接続性の組み合わせがふくれあがっている

これは、なかなか難しい問題ですな。
日本は狭くて相手が少ないからかもしれないけど、こういう試験が多いと時間と金がかかる。。。けど、通っているから相性の問題が少ないということなのだろう。
いや、そういう話だったのかどうかは知らないけどね。

 

で、講演タイトルの「ハーモナイゼーション」。

  • 世界ではまだ少ない「モバイルNFCの公共交通機関への導入事例」としてモバイルSuicaを紹介
    • どこで紹介したの?
      • 公共交通ワークショップ(PT Workshop)
  • ワークショップでの成果
    • 公共交通対応のため、GSMAのNFC規格として、NFC Forum規格を参照する
      • GSMA TS.26/27
        • GSMAはType-A/Bのみだったが、NFC-A/B/Fまで含むことになる
        • 2017年4月以降、GSMA対応端末はNFC-Fにも対応することになる

ということだと思う。

つまり「今までのGSMA端末はType-A/B対応のNFCチップでもよかった」が「2017年4月以降はNFC-A/B/F対応のNFCチップでよろしく」ということだろう。
まあ、今のAndroid端末はNFC-A/B/F対応が多いからいいだろう、ということかもしれんけど。

 

で、一番最後のスライド、記事の「写真⑪」でしょうな。
この話はNFCの通信仕様についての話だ、ということ。
他の通信だと、たとえばHTTPになるまでの経路がWiFiだろうと有線LANだろうとどうでもよいのだけど、NFCの場合は通信とアプリまでがほぼ一体化している。
だから、無線はNFC-AでやるけどアプリはFeliCaね、みたいなのができない。

それをやりたかったら、今度はデータをどう持つかという話になってくる。
今のモバイルSuicaはたぶんICチップ上に持っているけど、MIFAREなんかはSIM上に持ってるんじゃなかろうか。
ICチップ上だとデータアクセスが速いけど、後からスマホに足すことができない。
SIMだと後から足すことができるけど、データアクセスが遅い。

難しいねぇ。
GSMAの標準って、確かデータをSIMに入れること、みたいなのじゃなかったっけ。
そこは気になりますな。


ともかく、電子決済研究所さんの記事は私のイメージと同じだったのでわかった。

無線区間も確かに大変だったとは思うが、Android端末だと対応していることも多いと思うので、昔に比べると敷居は下がっていたんじゃ無かろうか。

土俵はできたので「本番はこれからだ」というところでしょうか。
2020年を目標としたら、あと4年。
うーむ。。。

HCE-Fなんかは、けっこう有力だと思うのだけど、どうなんだろう?
まあモバイルSuicaとしては無理そうな気がするのだけど、まずは決済部分が何とかならないと、乗り物へは進まないんじゃなかろうか。
でも、技術的なところは乗り物の方を優先しないとだろうしなぁ。

2016/07/17

[nrf52]LPC-Link2でCMSIS-DAPしようとしたがわからん

LPC-Link2を持っているので、nRF52832のデバッガとして使えるか試そうとしたが、eclipseで認識させる方法が良くわからなかった。

 


CMSIS-DAP用にする

JP1はオープンにしたまま、「Program LPC-Link2 with CMSIS-DAP」を起動する。
JP2はどうでもよいかもしれんが、私はオープンにしていた。

image

次々とボードに焼いていくようになっているので、焼き終わったら終了させる。

image


OpenOCDでやるようなので、Win32用にビルドしてあるものと、CFGファイルだけもらってきた。

http://gnutoolchains.com/arm-eabi/openocd/

https://raw.githubusercontent.com/ntfreak/openocd/master/tcl/target/nrf52.cfg

これでやったのだけど、CMD_INFOが失敗した、とかいわれてダメだった。


このまま終わるのも残念なので、Keilを立ち上げた。

image

うん、ちゃんとCMSIS-DAPとして見えている。

HRSサンプルもエラーなくビルドできたので、LOAD。。。

image

なんだ?
どうも、Flash Downloadの設定が消えていたようなので、追加。

image

そしてLOAD。。。

image

http://www.keil.com/support/docs/3824.htm
DeviceFamilyPackを8.6.0以降にせよ、と書いてあるな。
確かにSDKサンプルでは、8.5.0固定だったのだ。

最新が8.7.1だったので変更すると。。。同じじゃないか。。。

Insufficient RAM for Flash Algorithms !

というエラーが出ている。

どうも「RAM for Algorithm」のサイズが足りないらしい。
https://devzone.nordicsemi.com/question/18017/insufficient-ram-for-flash-algorithms/

0x2000にすると焼けたし、デバッグもできる。


じゃあ、あとはEclipseでCMSIS-DAPでのデバッグ方法がわかればよいだけか。
安定していそうな、ねむいさんスペシャルを使ってみよう。
http://nemuisan.blog.bai.ne.jp/?eid=192848#OPENOCD

 

ocd>openocd -s tcl -f interface/cmsis-dap.cfg -f target/nrf52.cfg
Open On-Chip Debugger 0.10.0-dev-00325-g12e4a2a-dirty (2016-07-06-07:39)
Licensed under GNU GPL v2
For bug reports, read
       
http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'swd'
adapter speed: 10000 kHz
cortex_m reset_config sysresetreq
Error: CMSIS-DAP command CMD_INFO failed.

だめかー。

[android]BLE接続の不安定さに迫る!の補足

結局のところ、前回は「Androidが一人で接続しようとして確立失敗しているようだ」という結論だった。
CONNECT_REQを出したつもりだけどうまく出せなかったとか、そういうことなのだろうか。


昨日のログで、いくつか気になっていることがあるので、補足しておこう。

 

まず、これ。

D/BluetoothGatt: cancelOpen()

もしかしたら、接続してからすぐ切断しているからこのログが出るのだろうか?

BluetoothGatt.java#750

単に、BluetoothGatt#disconnect()のトレースログが出ているだけだった。
最初はそういうAPI名だったのかもね。

 

次は、これ。

W/bt_btif: bta_gattc_conn_cback()

不審はないのだけど、なんだろう?

system/bt/bta/gatt/bta_gattc_act.c#1808

ここはsystemなんだ。
gattcなので、Client側ということか。
接続/切断関連のコールバック関数のようで、reasonが0以外であれば出力されている。
接続時には理由がないだろうが、切断時はだいたい理由があるから、切断時にしか出ないのかな。

 

最後に、これ。

D/BtGatt.GattService: clientConnect()

isDirectはどういう意味なのだろう?

GattService.java#1445

clientConnect()もたくさんあるようだが、AIDLになっているのはisDirectがあるやつだけだ。
AIDLはプロセス間通信に関するもので、ActivityがServiceをbindしてコールバックしてもらったりするようだ。
LocalのServiceじゃないやつ、ということかな。

呼んでいるのは、BluetoothGattの中にあるmBluetoothGattCallbackBluetoothGatt#connect()だ。
後者は再接続用だから、今回は前者だろう。
前者の時は、単にautoConnectを反転してisDirectにしている。
ちなみに、再接続の時はfalseを指定している。
gattClientConnectNative()までつながるのだろうが、そこから先はよくわからん。


何か安定した接続になるようなヒントがないかと思ったが、ないな。

2016/07/16

[android]BLE接続の不安定さに迫る!

迫れるのかどうか・・・。

お仕事でBLEをやっているのだが、しばしばBLE切断される。
そのほとんどが、BLE接続の段階だ。
ネットで検索しても、「接続段階がね-」みたいによく書かれている。

それで終わらせてしまいたいのだけど、今回はデバイス側も私が作っているので、どちらにも責任がないことを証明したいのだ。


CentralがBLE接続するときは、だいたいこうなると思う。

  1. 接続したいPeripheralを探す
  2. 見つかったら接続する

image

この図でいうところの、ScanningとInitiatingだ。
ScannninとInitiatingはシーケンスとしてはつながっていないので、Scannning無しでもInitiatingしてConnectionになることはできるはず。

が、だいたいは、探してつなぐ、だろう。
(こういう思い込みが、しばしば間違いにつながるのだが。。)


Androidでは、スキャンするところと、それ以降が分かれている。
(iOSはやっていないので、知らない。)

スキャンはBluetoothLeScannerが、それ以降はBluetoothGattが行う。
スキャンしたらデバイス情報が見つかるので、そこに対して接続を行うイメージだ。

接続要求(connectGatt())すると、コールバックが行われる。
BluetoothGattは非同期処理で、要求したらコールバックされる、という流れだ。

今回は接続の不安定さを見たいので、

  • スキャンする
  • 対象のデバイスが見つかったら接続する
  • 接続成功したら切断して、スキャンする

を繰り返して、そのときのBLE状況をスニファで見てみることにする。

スニファはTIのドングルを使っているのだが、切断と接続の間隔が短いとうまく拾えないようなので、その間は数秒開けることにした。


こうやって無線のところをモニタしたのだけど、成功の時も失敗するときも同じだった。
ちゃんとADV_CONNECT_REQして、Version Indをやりとりして、Featureをやりとりして、AndroidからTerminate Ind(status=0x13)している。
Peripheralのログには0x13=相手が切断した、しか出てこない。

この時点で、Peripheral側の責任がなくなる。
やれやれ・・・。

 

では、あとはAndroid側だけ見ていけば良い。
Nexus5(Android 6.0.1)のlogcatを見ていくと、リアルタイムで見ていないのではっきりはしないのだが、前後で違いそうなところがある。

長いので、順番に見ていこう。


成功時から見ていく。

接続要求。

D/BluetoothGatt: connect() - device: xx:xx:xx:xx:xx:xx, auto: false

connectGatt()でautoConnectをfalseにしているので、こういうログになる。
そしてregisterApp()や、onClientRegistered()が出てくる。
たぶん、BluetoothGattの下に要求を投げるのが、これだろう。

D/BtGatt.GattService: clientConnect() - address=xx:xx:xx:xx:xx:xx, isDirect=true

そこから接続できたところのログが、これだと思う。
isDirectが気になるが、放置だ。
本来はAndroidのソースを追いながらやるべきなのだけど、もうちょっと疲れたので勘弁しておくれ。

I/TrustAgent.Tracker: [BluetoothConnectionTracker] Bluetooth connect broadast for yyyyyyyy xx:xx:xx:xx:xx:xx

yyyyyはDeviceNameだ。
そうすると次は階層が上がって、GattServiceとBluetoothGattのログになる。

D/BtGatt.GattService: onConnected() - clientIf=5, connId=5, address=xx:xx:xx:xx:xx:xx
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=5 device=xx:xx:xx:xx:xx:xx

よくわからんけど、clientIfは5になっているのがほとんどのような気がする。

 

とにかく、この次でようやくBluetoothGattCallbackが呼ばれて、アプリの領域になる。
今回は、ここでdisconnect()を読んでいるためか、こういうログになる。

D/BluetoothGatt: cancelOpen() - device: xx:xx:xx:xx:xx:xx
D/BtGatt.GattService: clientDisconnect() - address=xx:xx:xx:xx:xx:xx, connId=5

続けて、こういうログになっている。

D/BtGatt.GattService: clientDisconnect() - address=xx:xx:xx:xx:xx:xx, connId=5
W/bt_btif: bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0016
W/bt_btif: bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0016
W/bt_btif: bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x0016

reasonの0x13は「相手が切断した」で、0x16は「自分が切断した」だ。
だから、ここは自分で切断している。
正しい。

 

失敗したときだが、けっこう前の段階で違っていて、同じなのは「isDirect」のところくらいまでだ。
その後、どちらもbt_btif_configが2つくらいログを出すのだが、失敗した場合にはこのログになっている。

W/bt_btif: bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x003e
W/bt_btif: bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x003e
W/bt_btif: bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x003e

reasonの0x3Eは、接続確立失敗、だ。
このログは、スニファでは出ていないし、接続しようともしていない。
スニファを信じるなら、Androidが勝手にやっているだけとなる。

その後、

I/bt_btm_sec: btm_sec_disconnected clearing pending flag handle:64 reason:62
D/BtGatt.GattService: onConnected() - clientIf=5, connId=0, address=xx:xx:xx:xx:xx:xx

などといって、最後には、

D/BluetoothGatt: onClientConnectionState() - status=133 clientIf=5 device=xx:xx:xx:xx:xx:xx

と、見慣れたstatus=133で終わる。
ちなみに、reason=62の62は、16進数で0x3Eだ。


うちにはスニファが1台しかないので、nRFの設定でAdvertisingをCH37だけに制限しているのだ。
だから、スニファが拾っているのはCH37だけになっている。

もしかしたら、Peripheralが設定に従わずにCH37以外にAdvertisingしたのかもしれない。
が・・・発生頻度からすると考えにくいと思っている。
少なくともスニファで見た限りでは、通常はCH37でしかAdvertisingしていない。

 

あるいは、CH37だけしかAdvertisingしないという不自然さが原因で、ということも考えられなくもない。
ただ、Advertisingってそういうものだろう、ということから考えると、それでおかしくなってはだめだろう。

そもそも、CH制限していない場合でも発生しているし。


あと、ほどほどの距離からApple系のものがAdvertisingしているのがあります。
おかげで、ログが見づらくてもうぅ。。。。。

image

電波暗室がほしいけど、庶民にはちょっとねぇ。
室内に発信源がいなければ、このくらいでけっこうはじけます。

[nrf]nRF Connect再び

hiro99ma blog: [nrf]nRF Connect v1.0

前回は、水晶発振子の関係で、やめた。
しかし、今はEBSHCNZXZがある。
ほとんどnRF52 DKと同じだから、動くんじゃなかろうか。


インストールして立ち上げたのだが、「Select serial port」に何も出てこない。
FTDIのチップがあるので、ちゃんとCOMポートとしては見えているのに・・・。

 

まさか、と思い、Preview-DKをつないでみた。
COMポートはCOMポートなのだけど、JLink CDC UART Port、という名前になっている。
そして・・・Select serial portに表示された。。。

 

えー、そこまで見分けるのーーー
シリアルポートと言うよりは、USBデバイスとして見ているということなのかい?

 

またしてもnRF Connectに敗れた私であった。


動かないのだからどうでもよい情報なのだが、nRF Connect用のファームウェアはnRFgo Studioでうまく焼けなかった。
CRENR0がどうたらこうたら、とエラーが出るのだ。

Commandline-Toolsのnrfjprogを使うと、焼けた。

[nrf52]EBSHCNZXZ基板の紹介

nRF52832が載った太陽誘電のモジュール、EYSHCNZXZ
その評価基板がEBSHCNZXZで、評価キットがEKSHCNZXZだ。
キットの方は、JLink-LITEがセットになっているようだ。

うちで買ったのは、評価基板。
JLink-LITEは手持ちがあったので、それを使っている。
ARM Cortex-M4Fだから、CMSIS-DAPのデバッガがあれば使えるのかな?


基板に関するドキュメントはリンク先の一番下にあるので、読めばよかろう。
ここでは、かいつまんで紹介だけする。

 

まずはEYSHCNZXZの部分。
これには、nRF52832が搭載されている。
メインクロックは32MHzで、サブクロックというか低周波数の方として32.768KHzが載っている。

EBSHCNZXZは、そこからGPIOなんかを引っ張り出している。
少し変えているのは、こういうところ。

  • P0.09-0.10 : NFCアンテナ用になっていて、デフォルトではパターンカットされている。
  • P0.05-0.08 : UART用になっていて、FTDIのチップとつながっている。

USBシリアル変換が載っているのは楽ですな。
ほかのGPIOは全部出ているようだから、この6本くらいはいいんじゃないの、と思える。

image

右側が、miniBでPCとつながっている。
右上は、JLink-LiteでPCとつながっている。
右側にあるボタンは、リセットボタン。
左側にあるのが、EYSHCNZXZ。
その右上にあるのが、NFCアンテナ。ここでは、nRF52-PreviewDKのアンテナをつないでいる。

LEDもいくつか載っているが、電源LEDやUARTのTX/RX用で、GPIOにつながっているものはない。
ボタンもない。
だから、nRF52-DKのようにしたければ、自分でスイッチなりLEDなりをつながんといかん。

上側に載っているスイッチはその例だ。
nRF5 SDK v11のpca10040用設定を使っているが、これのスイッチは内蔵プルアップでActive LOになっているから、片方をGNDにつないでGPIOを直結しておけばいいんじゃなかろうかね。


では、ついでにPCA10040設定を見ておこう。
PCA10040はnRF52-DKのことだ。

PCA1004はLED4つとボタン4つ
この構成は、nRFの評価基板だと同じようだ。
ピンアサインは、こうなっている
P0.00-0.01はEYSHの方で使っているから、EBSHには出ていないようだ。
リセットがP0.21なのも同じ。

UARTはEBSHも同じなので、サンプルから変更せずにいいだろう。
ボタンは、P0.13-16が1~4。LEDは、P0.17-0.20が1~4。
LEDはプルアップ抵抗でVDDにつながっているから、こっちもActive LOだ。
うちだとスイッチサイエンスさんから買ったLEDボードを使いたいのだが、こっちはActive HIなので、boards.hのマクロをやりくりするしかなかろう。

 

ちなみに、nRF52-DKのNFCアンテナはこんなのらしい。
Preview-DKとはコンデンサの容量が違うので、EBSHだとうまくつながらないかも?
(コネクタ自体違うので、つなぐのは大変だろうが。。)
image

[nrf52]Pairingサンプルのタグ

experimental_ble_app_hrs_pairing_nfcで流しているタグを解析した。
解析した、というと格好が良いが、単に読んで調べただけだ。

BLEというより、NDEFだ。


NDEFレコードが3つあるNDEFメッセージになっている。

 

1番目は、Handover Select Record。
これが先頭にあるので、Handoverの種類としてはStaticになる。

バージョンは1.3。
1.2とあまり変わらないようだが、BR/EDRのDevice IDが使えるのが1.3からのようだ。

Handover Select Record自体は大した情報がなくて、接続する相手の情報がこのIDのレコードに書かれていますよ、というインデックス的な役割程度だ。
アクティブなCarrier RecordがIDの'0'と'1'にありますよ、と書いてある。

 

ID'0'は、BLE関連が書かれている。
見分け方は、TNF=2となってMIME-Typeを指定するようになっていることと、MIME-Typeが'application/vnd.bluetooth.le.oob'になっていることだ。

ペイロードの部分はAdvertisingと同じく、Length-Type-Value、という構造になっている。
Typeも、AD-TypeなのでAdvertisingと同じだ。
ここでは、TK value、LE Role, LE Bluetooth Device Address, Appearance, Flags, Complete Local Nameが入っている。

 

ID'1'は、BR/EDR関連が書かれている。
見分け方は、TNF=2となってMIME-Typeを指定するようになっていることと、MIME-Typeが'application/vnd.bluetooth.ep.oob'になっていることだ。

ペイロードの部分はBluetooth BR/EDR Secure Simple Pairing OOB Dataのフォーマットになっている。
といっても、Bluetooth Device Address以降はLength-AD Type-Valueという形式だ。
なんで同じ形式にしなかったんだろうね。。
入っているのは、Security Manager OOB Flags, Device ID, Appearance, Complete Local Nameだ。


サンプルでタグの用途はもう1つあって、それは「アプリを起動させる」だ。
起動時にペアリング情報が存在したり、接続時にペアリング成功の経路を通った場合は、アプリを起動させるタグに書き換えている。

Androidだと、AARというのだっけ。
それと、Windowsのタグが入っている。
Windowsの方は知らないけど、タグが入っているから、読んだら立ち上がるのかもね。

実装しか見てないので、よくわからんです。


Static Handoverなのでタグを1回読んでしまえばNFCの部分は終わりだ。
だから、Androidで「ペアリングしますか?」というダイアログが表示された時点で、NFCの役割は終わっている。

ということは、ペアリングがうまく行かないのは、

  • タグを読んだけど、正しく読めていない
  • Androidが悪い

のどっちかだろう。
logcatを見る限りでは、タグはちゃんと読んでいる。
デバイス名とデバイスアドレスが出ているからだ。

では、やはりAndroidか。
bondStateChangeCallbackのnewStatusが1とか2とか、その辺で結果が違うのはわかっている。
ただ、もうここはアプリで制御できるところではない。

ずっと失敗するなら、それはそれで原因がありそうだけど、成功するときもあるのだ。
そのときは、いつの間にか成功している気がする。
ピクトに、Smart Lockとして使えますよ、と表示されていて気付くのだ。

なにが・・・何が違うのだ・・・。


あっ。

 

失敗するとき

image

 

成功するとき

image

 

ダイアログにデバイス名が表示されている!

しかし・・・ダイアログにデバイス名が表示される条件は、なかなか難しそうだ。
タグから取得した名前ではなく、BLEから取得したデバイス名で表示しているような感触なのだ。
Nexus5でBLE機器名が見つけられるタイミングを見ると、なんとなくBluetoothをONにしてすぐくらいしかやってくれていないように感じる。
すでにAdvertisingしている状態でBluetoothをONにすると、Bluetooth設定アプリの「使用可能なデバイス」に名前が出てくる。

でも、NFCペアリングサンプルの動作仕様は、タッチしたときにペアリングを開始する、だから、タッチする前はAdvertisingをしていないのだ。
いまのNexus5の動作としては、Advertisingしている機器に対してNFCペアリングを行ったときにしか成功しないような感じがしている。

 

もしかしたら、NFCタグから読んだデバイス名&アドレスの情報と、実際にAdvertisingしているデバイス名&アドレスの情報を見比べてからペアリングしようとしているのかもしれない。
だったら、一致しない間はダイアログを表示しなければ良いだけの話だ。

何度か試したが、標準のBluetooth設定アプリはBLE機器の捕捉があまり強くない感触だ。
nRF Master Control...じゃなくて、nRF Connectアプリでは確実に捕捉しているからな。

 

ここをうまくやらないと、NFCペアリングはうまくいかないと思う。
でも、市販されている機器もあるし。。。

2016/07/15

[android]Android Studio v2.1.2で編集していて困ったこと

WindowsでAndroid Studio v2.1.2を使っているけど、こういうときが嫌ですな。

image

スクロールバーをつかんで移動させようとしたら、先にホバーが出てきてつかめなくなる、という現象だ。

"hover"で設定を検索しても、これしか出てこない。

image

出てくるまでのディレイ時間を変更したいだけなんだけどねぇ。
編集した行が出なくてもよいので、このチェックを外した。

image

グッターってなんだろう?と思ったら、ガーターって読むんだね。
garterじゃないから、注意しよう。


あと、こういうのがあった。

ログ表示でこういうのを、

"function()"

カウント付きにしようとして、こう変更することにした。

"function(" + count + ")"

何箇所かあるので、

"function(" + count + ")"

の部分だけをクリップボードにコピーして、

"function()"

をマウスで選択してペーストしようとしたのだが、こうなるのだ。

"function(\" + count + \")"

あれー。

普通にペーストしたければ、Paste Simpleという機能を使わないといけないようです。
Windowsだと、Ctrl+Shift+Alt+V。
なんだ、この押させたくないようなデフォルトのキーバインドは。。。

元々のペーストの利点がよくわからないので、とりあえずCtrl+VはPaste Simpleにしておこう。
そういえば、コピーするときもRichTextになって不便だったから、普通のに変更した気がする。

 

・・・変更して、すぐわかった。
普通のペーストだと、インデントの高さなんかも考慮して貼り付けてくれるのだけど、Paste Simpleはそのままペーストするんだ、シンプルだから。
これは、悩ましい。。。
「勝手なことするな!」と「勝手にやっとくれ」が戦う感じですな。

折衷案で、

  • Ctrl+V : Paste
  • Ctrl+Shift+V : Paste Simple

にした。
Shiftキーくらいだったら、押すよ。
ヒストリーからのペーストは使わないから、キー削除で。

2016/07/14

[android]connectGatt()のautoConnectがわからん

わからんのだ。。。

BLE接続するときにconnectGatt()を使うのだが、その第2引数にautoConnectというものがある。

Whether to directly connect to the remote device (false) or to automatically connect as soon as the remote device becomes available (true).

falseだと「リモートデバイスとダイレクトに接続する」で、trueだと「リモートデバイスと接続可能になったら自動的に接続する」だ。

どういう意味なのだろう?


trueだと「いなくてもあきらめない」という解釈で良いのだろうか?

falseにしていると、BluetoothDeviceの持つ情報に一致したデバイスがなければ接続を止めるけど、trueにしていると、執念深く探し続けて、少しでも対象が近づこうものなら接続を仕掛ける、という動作だ。

SCANしてデバイスがいるのを確認してから接続するのだったら、falseにしておいた方が無難なのかな。
たぶん、切断したのに自動的に接続しに行くような動作はしないと思うのだ。
そういう場合は、close()していなければreconnect()だろう。

 

ただ調べていると、trueにしても効かないデバイスがある、と書いてあったりもしたので、あまり当てにできんのかもね。

2016/07/13

[nrf52]ATT MTU長の変更 (2)

今回は、お話だけ。

 

SoftDevice S132 v3.0.0-alpha2と一緒に提供されているヘッダファイルをSDK v11に突っ込んだのだけど、SDKが参照している構造体がなくなったりしていてね。。。

追加して良いものか、そもそもどうなるんだかわからん、ということで、SDKが対応するまで待とうと思う。
そう、以前も同じようなことをやって、あきらめたのよねぇ。

どこかにSDKのパッチでも提供されているのかしら?

[android]Serviceは1つ?

アプリに用意したServiceは複数インスタンスというか複数サービスというか、とにかく1つのclassから複数は生成できないような感じがしている。


バインドされたサービス | Android Developers

1つのBLE PeripheralにアクセスするServiceを作った。
作ったというか、BDSサンプルがそんな感じだったので、そうなった。
こあれを、複数台のPeripheralでも接続できるようにしたい。

これを読んでいて、基本のところに「複数のクライアントが同時にサービスに接続できます」と書いてある。
だから、Serviceを複数作って、それぞれバインドしてやればいいはずだ、と思ったのだ。

やってみたのだけど、なんだか動きがおかしい。。。
bindService()を呼ぶと、2つともServiceConnectionのonServiceConnected()は呼び出されているのだが、なんか、なんかおかしい。
呼ぶときのContextは、同じ画面上なので、同じActivityだ。

このフィールドの値が変わっていたらログが出ているはずなのに、出ていないのに値が初期値と違うとか、ログが出て値が変わっているはずなのに、変わったことになっていないとか。

 

HandlerのhandleMessage()でServiceからの通知を受け取っているのだけど、そこら辺がおかしいのよねぇ。
Handlerは、onServiceConnected()のところでServiceに渡している。

デバッガで追っていったところ、渡しているHandlerが最後にonServiceConnected()が呼ばれたときのものに差し替わっているようだ。
staticフィールドではないので、やはり大元が1つになったままということか。。。


というわけで、もうちょっと簡単に確認することにした。
Serviceの中にstaticではないint変数を用意して、onServiceConnected()で呼ぶgetService()でカウントアップさせるのだ。
bindService()ごとに作られているなら、毎回同じカウントのはず。。。

うん、カウントアップされますね。

 

つまり「複数のクライアントが同時にサービスに接続できます」というのは、接続できるサービスが異なる場合は、ということになる。
同じActivity上だと、クライアントとしては1人扱いになるのだろうね。
まあ、context.bindService()と2回呼んでいるだけだから、同じクライアントじゃないか、と言われても否定のしようがない。

 

たぶん「複数のクライアント」というのは、複数のActivityだったり、複数のアプリだったり、そういう人たちなのだろう。
クライアントの定義を確認せんかったのが悪かった。

2016/07/12

[ble]BLEのエラーコード

AndroidでBLEをやっていて、Statusが133というのが返ってきた。
なによ、133って?

毎回調べては忘れているような気がするので、書き残しておこう。
まあ、書いたこと自体忘れてしまうかもしれんが。

Core v4.2で見ていく。


[Vol 3, Part F][3.4 Attribute Protocol PDUs][3.4.1 Error Handling]

この辺りが、よく見るエラーのことになるだろう。
この階層で決まっているのは0x11まで。

133は0x85。
これはApplication Errorということになっている。
この「Application」は、誰だろうか?
いや、そもそもAndroidの返してくるStatusがエラーコードなのかもわからん。

 

GATT_INSUFFICIENT_AUTHENTICATIONなんかを見るとエラーコードが一致しているので、方向性は間違っていないと思う。
ただ、定義している値が少ないので、載っていないと良くわからん。
Cross Reference: /frameworks/~/bluetooth/BluetoothGatt.java


じゃあ、こういうのがよいのか?
BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP

これはnRF51 SDKのドキュメントなのだけど、STATUSで値が0x85だ。
階層はGAPだから、ATTよりは上側だから、アプリと言えばアプリだ。

 

じゃあ、133で検索すると一緒に出てくる129は?
0x81なので、BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILEDか。
どちらもペアリングがらみだな。

しかし、今見ているやつはペアリングはもう済んでいるのよねぇ。。。



2016/07/23追記

HCIのエラーコードは、[Vol 2, Part D Error Codes]に出ている。
Vol 2は「BR/EDR」となっているので見過ごしてしまいそうだが、[Vol 6, Part B][2.4.2.3 LL_TERMINATE_IND]などのError Codeはそれを参照するようになっている。

nRF5 SDKはそちらをreasonとして返すことが多いので、覚えておくと良いだろう(と、いつも探し回る自分に言い聞かせる。。)。

[nrf52]ATT MTU長の変更 (1)

hiro99ma blog: [ble]ATT_MTU
hiro99ma blog: [ble]NotificationはATT_MTU-3まで

そう、nRF51822では、ATT MTUは23バイト固定だった。
そのため、認証がない場合のATT Protocol PDUはオペコード1バイトとATTパラメータ22バイトまで。

たとえばWrite Requestなんかだと、ATTパラメータのうち2バイトはハンドル値なので、書き込めるデータは20バイトまでになっていた。

image

これ以上やりたかったら、Long Writesせんといかん。

しかし最近、nRF52832のSoftDevice S132のv3.0.0-alpha2というものが出た。
なんと、MTUサイズの上限が512バイトまで拡張されたというではないか。

試してみたい。。。


しかし、だ。
気になるのは「4.2 feature」と書いてあるところだ。
ATT MTUのデフォルト値は23バイトだけれども、あれは規格でも固定だったのだろうか?

Interface誌の特集を読み返すと、PDUサイズが、

  • 4.1まで:2~39バイト
  • 4.2 : 2~257バイト

となっている(面倒だから、もう単位は「バイト」で書いている)。

数字がわかれば、検索しやすい。
257なんてのは、最適だ。
Core_v4.2の[Vol 6, Part B][2.1 Packet Format]に載っていた。

image

仕様書のつらいところは、以前からの変更が載っていないことだな。
ともあれ、257バイトまでだ。

ただ、これは無線上のパケットの話で、ATTはもっと上位層だ。
あくまで無線上のパケットに1回で載せられるデータ量が変わっただけで、その上位層とは別の話になる。

まあ、ここが大きくなるとパイプが太くなるのと同じで、大きいデータの転送効率はよくなるだろう。


だから、ATT MTUを大きくできるのは、v4.2とは関係ないんじゃないか・・・という気がしている。

SoftDeviceが新しくなることで、sd_ble_gatts_exchange_mtu_reply()という関数が追加された。
たぶん、MTUサイズの交換フェーズで、相手から聞かれたときに返すサイズを指定できるんじゃなかろうか。

 

MTUのサイズ交換したら、なんとなく小さい方にあわせられてしまいそうな気がする。
もしv4.2から対応するようなものだったら、そういうスマホを持っていないから動作確認できないな。

[java]非同期に翻弄される

人間、いろいろあると、不信感に襲われてしまいますな、いやいや。

状態変数のチェックをメソッドの始まりで2回やって、そこまでチェックをくぐり抜けたら処理する、とやってたのだけど、すり抜けるのをはじめて目にしてしまってね。
もう何日もテストして無事だったのに、なんでいまさらーっ?

 

タイトルからわかるように、非同期で状態変数を変更する処理が呼ばれていたのですな。

メソッド() {
    if (状態変数のチェック1) {
        return 成功でよい;
    }
    //★
    if (状態変数のチェック2) {
        return 失敗と見なす;
    }
    実行();
}

別メソッド(setVal) {
    状態変数 = setVal;
}

★のところでディスパッチして、別メソッドが呼ばれて、チェック1で引っかかるような値が代入されてしまったのですよ。
チェック1で引っかかる値はチェック2でも引っかかるので、先にチェック1で見て、既にこの状態だったらOK、ということだったのだ。

いやいや、そのタイミングでディスパッチできるとは、やりますな。


とまあ、教科書にあるような失敗例だったので、教科書にあるような対処法で済む。
Javaにはsynchronizedという便利なものがあるので、それを使えばよいだろう。

例では短く書いているけど、本当はもっと長くて、メソッド自体をsynchronizedしてしまうとデッドロックしてしまうのだ。
なので、「実行()」の手前までディスパッチを禁止してくれれば良いのだ。

ただ、そんなにひどいことをさせられないのか、synchronized(オブジェクト)、みたいな書き方なのですな。
「このオブジェクトに掛けて、排他してやる!」みたいな意気込みになっているように思える。

finalじゃないといかんようだ。
まあ、どんどんオブジェクトが変わってしまうと排他にならないからか。

 

final Object lockObj = new Object();

メソッド() {
  synchronized(lockObj) {
    if (状態変数のチェック1) {
        return 成功でよい;
    }
    //★
    if (状態変数のチェック2) {
        return 失敗と見なす;
    }
  }
  実行();
}

別メソッド(setVal) {
  synchronized(lockObj) {
    状態変数 = setVal;
 
}
}


で、問題はどちらかというとこれからで、本当にこの対策で現象が出なくなるのか?だ。
実は別の場所の方に問題があって、これではだめなのかもしれない。

しかし、再現性が元々かなり低いので、自然に発生するのを待つことはできないだろう。
どうするかというと、割込が入りやすいように、★のところにThread.sleep()を入れた。
まず、synchronizedを外した状態で動かして、発生していたエラーと同じことが起きることを期待する。
そして、synchronizedを付けて、エラーが起きないことを期待する。

 

うん、今回はうまくいったようだ。


ただねぇ、作りをあれこれ変えていったので、実はこういうチェック無しでもいけるんじゃないの?という気がしている。
その決断を下す勇気がないというか、判断ができないというかで、現状維持しているというところ。

ここら辺は、付け焼き刃の知識じゃダメだなー、と思う。
空気感が読めないというのかね。

2016/07/11

[android]Log.d()の文字列結合をStringBuilderにしたが、やはり残る

Android Lintはすぐ終わったので、Find Bugsに掛けることにした。
そうすると、ログ出力で文字列を足し算しているところに警告が出た。
StringBuilderとかがいいね、みたいなことを言っている。

うん、わかっているのだけど、ログ出すだけやん、とも思うのだ。
それに、最終的には出力されないし。

 

hiro99ma blog: [android]ProGuardでLog.d()がStringBuilderで残る
そういえば、ProGuardに掛けても文字列生成するところが残ってしまったのだが、もしかして最初からStringBuilder形式で書いておくと消してくれるのでは?

 

・・・ダメだった。
StringBuilderをnewして、append()して、最後にStringでnew(sb)したけど、全部残る。
しかも、以前は最適化してくれたせいかStringの足し算もStringBuilderに変換され、最後にStringに戻す部分がLod.d()がなくなることで不要になったのだけど、書き換えると明示的にStringBuilderからStringに変換する部分が残ってしまい、かえってコードが増えてしまっている。

 

だいたい、代入する人がいないのにnew StringBuilder()するところなんか、うまいこと消せないものなのだろうか。
C++だとできそうだけど、Javaはそういう書き方をすることが多いから無理か。。

 

とりあえず、こうしておこう。

  • Log.d()程度の文字列操作で、ProGuardでログ自体削除するなら、文字列は足し算で結合させた方が最終的に小さくなりやすい
    • StringBuilderからStringに変換する実装を明示的に書くと、それが残ってしまう
  • 自作で、結合させたい文字列を引数に取るログ出力メソッドを作って、文字列の結合処理をメソッドの中に押し込め、ProGuardで抑止させれば消えるのかもしれん。
    • Cなんかだとときどきある、DEBUG_LOG1(p1), DEBUG_LOG2(p1,p2)みたいに引数ごとにメソッドを作るとか

 

うーん、Javaにもプリプロセッサ、プリーズ!!
まあ、あったらあったでやっかいなのだけどね。。。

[java]finalをつけましょう、と言われた

ソースが安定してきたので、Android Lintに掛けてみた。

 

以前、finalについてはここここで考えたことがあった。
そのときは、finalはコンパイラレベルの話なので、finalを付けても付けてなくてもバイトコードには変化がないよね、というくらいで終わっていた。

今回指摘されたのは、フィールドでnewし、そのまま使い続けるやつと、コンストラクタの引数でしか代入されないやつらだった。
そういえば、C++のメンバ変数を参照型にするときも、コンストラクタの初期化子にしておけば設定可能だったから、同じ要領なのか。

 

今回は、意識してfinalにできるようになったわけじゃないので、正直なところどうでもよい。
私が最初からfinalにしたいのは、だいたいstatic finalのような定数的なものだけだ。

finalはC++のconstと同じで、変数への代入は怒ってくれるけど、アドレス先の更新までは考慮してくれない。
まあ、そうじゃないとやってられないだろうが。

 

どうしようかと思ったが、finalを付けることにした。
静的なツールだから仕方ないのだけど、今書かれているソースの内容でしか判断できないから、実はこれを拡張する予定があって・・・、なんてのには対応できない。
あまり言語仕様をわかっていないとツールの言いなりになってしまいそうだが、やってればそのうちわかるんじゃないの?くらいでやることにした。

[androidTest]testInstrumentationRunnerを書き忘れて1時間悩む

タイトル通りだ。

Local Unit Testsは行ったものの、実機じゃないと動きが見られないところがあるし、動いたなら何か結果を残したくなる。
なので、カバレッジを取りたい。

ただ、GCOVなどと違い、どうも「テストするぞ」というコードを書かないとカバレッジは取れないようであった。
準備として、testではなくandroidTestにテストコードを書いて実行させようとした。

したのだが、"no tests were found"になってしまう。
Invalidate/Resetとか、Rebuildとか、package名の書き間違えとか、@RunWithとか、それっぽいものはやってみたのだけれども、変わらず。

 

初心に戻り、Android Developersの記事を再確認することにした。
Building Instrumented Unit Tests | Android Developers
dependenciesには追加しているし。。。あ、defaultConfigの方にtestInstrumentationRunnerを追加してない!

追加すると、あっさり動きました。
そういうものよね。


ただ、今回は呼ばれるかどうかだけのテストメソッドだったため、コマンドラインから

gradlew createDebugCoverageReport

などとしても、テストメソッド以外呼ばれていないためだろうけど、足跡が残らない。
Activityからボタンを押してテストを実行するような作りにしているので、それと似たようなことをテストコードでやってしまわないといかんのだろう。

 

Testing UI for a Single App | Android Developers

この辺をまねすればよいのかもしれんが、使うのはContextだけだし。。。
いや、自分のServiceも持っているので、それが起動しないとダメか。

じゃあ全部の分岐にLog.v()でも書いて目視でチェック?
いやぁ、それもちょっとないな。

やっぱり、テストがしたいわけじゃなくて、どちらかと言えばアプリを動かしたときのカバレッジが取りたいだけなのだ。


Serviceのみ、とか、ContentProviderのみ、みたいなのは見つかるし、Unit Testのカバレッジというのも見つかるのだけど、テストせずにカバレッジ、というのがないな。

ないのか。。。。

2016/07/10

[nrf52]そもそも、nRF52のNFCペアリングはなんなのだろう

今さら?と言われそうだが、ああそうだ。
基本的なことを確認していなかったのは反省しよう。

 

NFC Forumのドキュメントは大半が有料になったが、NFCペアリングに関してはダウンロードできるようになっているし、下のようにBluetooth SIGからもダウンロードできる。
https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=264234

NFCペアリング、とあっさり書いているが、ハンドオーバーの種類としては3つある。

  • Static Handover
  • Negotiated Handover
  • Mediated Handover

3番目のは比較的最近だったためか、BluetoothについてはStaticとNegotiatedだけになっている。

大ざっぱに言うと、Staticの方が簡単で、Negotiatedの方がめんどくさい。
めんどくさいというか、StaticはNFCタグに書込んでおくだけなのだが、Negotiatedは文字通りネゴシエーションがいるので実装が必要なのだ。

hiro99ma blog: [nfc]よくわかってないハンドオーバー


では、nRF52のサンプルで行っているのはどちらだろう?

見分けるのは、最初のNDEFでわかる。
Static Handoverであれば「Handover Select Record」、Netotiated Handoverであれば「Handover Request Record」になるはずだ。
さあ、どっちだ?

image

Static Handoverだ!


NFC Forumなどで公開されているドキュメントでは、1.2。
もう1つドキュメントとして「Connection Handover」があり、これが1.3だった。

NDEFのメッセージは、NDEFレコード1つ以上から構成される。
Handover Selectメッセージは、Handover Selectレコードが先頭にあればよいことになっている。

そしてレコードの方だが、Global RecordとLocal Recordがある。
Handover Selectレコードは、その中に複数のAlternative Carrierレコードを持つ構成になっているので、Handover Select Recordは外側だからGlobal、Alternative Carrier Recordは内側だからLocal、なのかな。


で、ごにょごにょと見ていったのだが、BLEのペアリングだけじゃなくて、BR/EDRのペアリングについても載っていた。
それが邪魔なんじゃないのか?

nfc_ble_pair_default_msg_encode()でNFC_BLE_PAIR_MSG_FULLが指定されていたので、NFC_BLE_PAIR_MSG_BLUETOOTH_LE_SHORTに変更してみた。
・・・Handover Select Record自体がなくなって、application/vnd.bluetooth.le.oobのレコードだけになってしまった。。
でも、これはこれでペアリングできるようだ。

ただ、ペアリングに成功しやすくなったわけでもない。
そもそも「ペアリングしますか?」と聞いてくるところまででNFCの役割は終わりのはずだ。
ダイアログが出た後で、端末をEBSHから離して「はい」にしてもペアリングできるし。
接続しようとして失敗しました、ならまだしも、接続しようとしていないというのは言語道断だろう。


「失敗しました」のトーストが出るときと出ないときもあるし、なんか変なのだけど、表現ができない。

Nexus7でも同じだから関係ないかもしれんが、一度Nexus5を初期化してみよう。。

2016/07/09

[nrf52]NFCペアリングサンプルを動かす

NFCペアリングサンプルがあるので、今度こそ動かそう。
前回は、理由はわからないけどうまく動かなかったのだ。

ベースはHRSサンプルで、変更点がいくつかある。
まず、接続開始まで。

  • アプリが起動したらNFCTを初期化する
  • アプリが起動してもAdvertisingを開始せず、ポーリングされたら始まる
  • Tagのメッセージにはペアリングの初期データが入っている
  • NFCデータが転送され始めたら、InitiatorはNFCアンテナにタップしないといけない

次に、接続開始から。

  • InitiatorがTagを読んだら、Initiatorはペアリングできる
  • 接続されたら、あとはHRSサンプルと同じ動きをする
  • もう一度Tagを読んだら、Advertising無しで接続できる
  • ペアリングが成功したら、nRF Toolboxアプリが起動するようになっている
  • 接続が切れても、自動的にはAdvertisingしない
  • Bonding情報を削除しないと、他のデバイスとは接続できない

大ざっぱには、こうなるようだ。
搬送波を検知しないとAdvertisingしないし、Advertisingし始めたらタップしてペアリングできる、ということか。

ボタンは、EBSHには載ってないので(リセットボタンのみ)、そろそろハンダ付けがいるか。。。
まあ、ペアリング情報はnrfjprogで消せばいいか。


前回のNFCサンプルでSoftDeviceが消されたので、もう一度焼いてからアプリを焼こう。

 

動かしてみたのだが、正直なところよくわからない。。。
困ったことに、そこそこ近くでiBeaconを出しているデバイスがいるようで、Advertisingがゴチャゴチャしているのだ。

それは置くとして、確かにスマホを近づけるまではAdvertisingしないようだ。
そしてAdvertisingしているときにアンテナに向けたままにしていると、Androidのペアリング確認ダイアログが出てくる。

これが、「はい」を押してもすぐ失敗して次のダイアログが出てくるのだ。
がんばって「はい」し続けると、いつの間にかペアリングしていた。
TIのツールでLTKが入っているので、うまくいったのだろう。
その状態でもう一度アンテナにタップすると、nRF Toolboxが起動した。

そのあと、BLE切断してタップすると、Advertisingするようだ。
「しない」と書いてあったけど、接続できるやつじゃないということか?

うーん、もう一度!


の前に、ボタンがないのでペアリング情報を削除しなくてはならない。
config/pstorage_platform.hを見て。。。

まず、pstorageで使っているFLASHの終わりを調べる。
NRF_UICR->NRFFW[0]に値が入っているかどうかで決まるようだ。

>nrfjprog --family NRF52 --memrd 0x10001014 --n 0x10
0x10001014: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|

というわけで、NRF_FICR->CODESIZEに入っているデータを見る。

>nrfjprog --family NRF52 --memrd 0x10000010 --n 0x10
0x10000010: 00001000 00000080 FFFFFFFE FFFFFFFF   |................|

PSTORAGE_FLASH_PAGE_ENDは0x80、と。
PSTORAGE_NUM_OF_PAGESは1。
PSTORAGE_FLASH_PAGE_SIZEは、NRF_FICR->CODEPAGESIZEで、0x1000。

PSTORAGE_DATA_START_ADDR = (0x80 - 1 - 1) * 0x1000 = 0x0007_E000

image

>nrfjprog --family NRF52 --memrd 0x0007e000 --n 0x200
0x0007E000: 6354EF2A 5B2CE37A A06EA323 BDD2C536   |*.Tcz.,[#.n.6...|
0x0007E010: E9A5B700 FF344DF7 FFFE2FD3 7923AD64   |.....M4../..d.#y|
0x0007E020: 640B4C4A C5C60605 4C708827 2FD30040   |JL.d....'.pL@../|
0x0007E030: 44AAEAF4 FDF9FCBE 00000003 0000000E   |...D............|
0x0007E040: 0002000C 00120000 00000002 000030A3   |.............0..|
0x0007E050: 00000000 00000000 00000000 FFFFFFFF   |................|
0x0007E060: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
....

なんか入っているので、この辺を消せばいいんじゃなかろうか。

>nrfjprog --family NRF52 --erasepage 0x7e000-0x7f000
Erasing addresses 0x7E000 to 0x7EFFF.

>nrfjprog --family NRF52 --memrd 0x0007e000 --n 0x200
0x0007E000: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x0007E010: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x0007E020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x0007E030: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x0007E040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
....

"erasepage"という割りには、アドレスを指定するんだな。


今度は、adbでログを見ながらやってみた。
全然うまく行かないのだが、こういうログが出ていた。

E/BluetoothEventManager: Got bonding state changed for xx:xx:xx:xx:xx:xx, but we have no record of that device.

DISCOVERY_FINISHED、なんてのも出ているから、端末は見つけているのだろう。
でも見つからない??

その1つ前のログが、こうだ。

BluetoothEventManager: CachedBluetoothDevice for device xx:xx:xx:xx:xx:xx not found, calling readPairedDevices()

CachedBluetoothDevice??
何かキャッシュされている方を見に行こうとしているのだろうか。

 

よくわからないので、一度BluetoothをOFFにしてからやってみた。
よくわからんが、ペアリングされたようだ。
でも、その前もOFFにしたんだけどね。。。

image

OOBDataFlagが1と返しているから、nRF52は返事をしているようだ。
まあ、うまくいった後だから、そうだろうけど。

 

うまく行かないときは、

BluetoothBondStateMachine: bondStateChangeCallback: Status: 0 Address: xx:xx:xx:xx:xx:xx newState: 1

で、うまく行くときは、

BluetoothBondStateMachine: bondStateChangeCallback: Status: 0 Address: xx:xx:xx:xx:xx:xx newState: 2

といなっている気がする。
でもその前に、

bt_smp: io_cap = 4

のようなログが出ているので、SMPが動くとかどうとかいう辺りなのかも。
(io_cap=4はReqで出ているから、スマホ側だろう)

image

これより前は、LL_Version_IndとかLL_Connect_UpdateReqとかしかないので、もう接続処理に入っている。
失敗しているときはAdvertisingが止まるような感じがしなかったから、単に接続できなかったとかそういう話か?

でも、なんで??


スマホが接続してくれようとしなければ、そもそもペアリングも何もあったものではない。
だから、なんとなくAndroid側に原因がありそうな気がする。
しかし、NFCペアリングするスピーカーなども売られているから、ここまで失敗しそうな気もしない。
うまくいくときは、ちゃんといくし。

もしかして、タグとかNFCアンテナとかがそこら辺に置いてあるからいかんとか、ピンをハンダ付けせずにやってるからとか、アンテナが裸だから距離が近すぎるとか、そういうハードウェア的(?)な要因なのか?

ちゃんとハンダ付けしてみたが、うーん、よくわからん。。。


nRF52 DKなんかは、NFCアンテナ周りにコンデンサやら抵抗やらが挟まっている。

image

私が使っているアンテナはPreview-DKのものなので、そちらの回路も見た。

image

やっぱり130pFのコンデンサが左右に入っているな。
NFCのアクセスはできるけれども、実はRF部分で何度もリトライしてうまくいっているだけで、その遅延によってうまくいかない場合が多い、とか?

EBSHはどうなっているだろうか?

image

C10とC11がそれか。
でも、基板を見ても書いてないから、よくわからんのよねぇ。
でも、確かに外側に着いているP9とP10とはつながっていなかったから、この図通りではある。

わからん。
調整されていることにしよう。

それにしても、太陽誘電のドキュメントにNFCのことがほとんど書かれていないのだ。
お前達のNFCに対する思い入れはそんなものなのかーッ!

[nrf52]NFCタグのサンプルを動かそう

まずは、nRF52832のNFCサンプルが動くか試そう。
このくらいだったらハンダ付けしなくても、ピンを挿すだけで使えるだろう。

 

電源を入れても何も動かなかったのだが、FLASHが空だった。
SoftDeviceはS132v2.0.1を入れておく。

なお、電源はUSB(MiniB)から取るだけでよさそうだ。

image

 

NFCサンプルは、nRF5 SDK v11.0.0のexamples\nfc\record_url\pca10040\armgcc。
ARM-GCCは4.9と、nRF51のときと同じものにした。

何も考えず、makeして、make flash。
そして、Android端末でTagInfoアプリを起動してNFCアンテナに近づける。

image

あっさり動いた。
GCCでも変更せずにビルドできるのは、楽だねぇ。


TagInfoアプリはタグから読めるだけ読もうとするので、えらく時間がかかる。
というのも、Type2Tagに見えるのだが、アドレスが0x100あるのだ。
1アドレス4バイトだから1KB!
すごいねぇ。

搬送波を検知するとLEDが点灯するようなソースになっているけど、この基板にはそういうのがないので、特に光らない。


で、NFCIDだ。
ここを見ると、FICRに初期値が入っているようだ。
まあ、Factory設定だから、それがよいのだろう。
UIDが1~15ってのがすごいな。

ただ、初期値なので、実際の値はNFCTのレジスタに入れるようだ。

  • 4バイトUID
    • SENSRES.NFCIDSIZE = 0
    • NFCID1_W, X, Y, Z
  • 7バイトUID
    • SENSRES.NFCIDSIZE = 1
    • NFCID1_T, U, V, W, X, Y, Z
  • 10バイトUID
    • SENSRES.NFCIDSIZE = 2
    • NFCID1_Q, R, S, T, U, V, W, X, Y, Z

サンプルを動かすと7バイトUIDに見えた。
デフォルトがそうなっているのだろう。
まあ、4バイトは推奨されなくなったので、7バイトなのかな。

components\nfc\t2t_lib\hal_t2t\hal_nfc_t2t.cのhal_nfc_common_hw_setup()でSENSRESを設定していて、Doubleになっていた。
これが初期値か。

そしてその前にNFCID1への設定があるから、それより後で設定すればUIDを好きな値に変更できそうな気がする。
やってみるか。

image

できてしまった。。。
こ、こいつは強力だな。
PN532みたいなR/Wチップの場合、カードエミュレーションさせてもType-AについてはUIDの一部しか変更できなかったのだ。
FeliCaについてはIDmを8桁とも変更できたので、ちょっと危ないと思っていたのだ。
が、これがあるとType-Aでも好きにUIDを変更できるのだ。

まあ、UIDだけで何かする、という実装はセキュリティ的にやってはいかんのだが、最近はどうなってるんだろうね。

[nRF52]EBSHCNZXZ来たる

はい、そういうわけで、うちにもnRF52832基板が来ました。
円高なので、買うなら今かな、ということで。
1万1千円くらい

image

ちゃんと技適にマークが入っているので安心だ。
総務省 電波利用ホームページ | 技術基準適合証明等を受けた機器の検索


2.54mmのピンは自分でハンダ付けだ。
1.27mmのSWD用はつながっているので助かった。

どうせなら、NFCアンテナも付けてくれると良かったんだけどね。
うちにはPreview-DKを買ったときについていたアンテナがあるのでいいけど、うちにはスペアナなんてないから調整が必要だったら厳しいぞ。
https://devzone.nordicsemi.com/blogs/957/nfc-tag-antenna-tuning/

 

とりあえずUSB接続すると、FT232Rに見えるようだ。
ほほぅ、よく見るとFTDIのチップが載っていた。
COMポートに見えるが、MassStorageとしては見えないようだ。
電源のLEDは点灯するが、特に出力はしないようだし、無線も吐いていない模様。

P0.05~08がUARTとしてつながるようになっているらしいから、その辺は楽そうだ。
38400bpsになってるけど、そこは制限を掛けるようなものではなかったような。。
まあ、試してからだな。


注意点なのかどうかわからんが、クロックは32MHzだ。。。と思ったが、nRF52は外部水晶は32MHzになっていた。
じゃあ、普通だ。

LCLKも載っているので、サンプルも変更せずに動くだろう。
しばらく遊んでみますかね。

[勉]Visitorパターン

唐突だが、デザインパターンの中のVisitorパターンの勉強をしよう。

以前購入した『モダンC言語プログラミング』の中に出てくるのだが、なんだかよくわからなかったのだ。


GoF本には、

あるオブジェクト構造上の要素で実行されるオペレーションを表現する。

と書いてある。
うーん、意味がわからん。
一応GoF本は買うだけ買ったのだけど、文章の意味がわかりづらくてほとんど読んでいないのだ。。

 

13.Visitor パターン | TECHSCORE(テックスコア)
こちらでは、「処理を追加しやすくするため、Visitor側に書けるようにする」みたいに書かれている。

あれ、オブジェクト指向って、データと操作をオブジェクトでまとめましょう、みたいな感じじゃなかったっけ?
これだと、操作をデータと別の場所に書けるようにしました、という受け取り方をしてしまうのだが。。。

まだ、理解が足りてないので、あせらないようにしよう。


TECHSCOREさんのところにあるソースファイルを見ると、最後にやりたいのは鈴木さんの家庭SuzukiHomeのpraisedChild()やreprovedChild()だと思う。

それを呼ぶ処理は、RookieTeacherのvisit()なのだけど、visit()の引数でTanakaHomeだったりSuzukiHomeだったりの処理を呼んでいる。

鈴木さんに対してはreprovedChild()を呼んでいるのだけど、これは親の発言だと思うから、先生側が呼び出してよいものだろうか。。。
どっちかといえば、TanakaHomeでもSuzukiHomeでも同じメソッドを呼び出して、TanakaHomeだったらこういう発言、SuzukiHomeだったらこういう発言、という方が、発言の内容からすると自然だと思う。

まあ、サンプルだし、ここの記事全体が先生を例に取っているようだから、内容が多少不自然なのは仕方ないのかもしれん。

ここで言いたいのは、鈴木さん向けの処理や田中さん向けの処理をRookieTeacherの中に実装するのではなく、SuzukiHomeやTanakaHomeに書くことができるということだろう。
もし吉田さん向けの処理を追加したければ、RookieTeacherには引数がYoshidaHomeのvisit()を用意して、中身はYoshidaHomeの中に書いてしまえば良い。
これが「追加しやすい」なのだろう。


もしRookieTeacherの中に処理を追加するのだったら、どう書くだろうか?
visit()の引数を各Homeの基底クラスか何かにして、オブジェクトの種類でswitch-caseで分けるとかかな。

これを回避したい理由は何だろうか?
思いつくのは、家庭が増えるにつれてcaseが多くなってしまう、だろう。
各caseに処理を書くと長くなるので別のメソッドにするかもしれない。
それくらいだったら、別のオブジェクトにメソッドを書いて、switch自体なくしてしまえばよいじゃないか、ということか。

 

ただ、私の感想からすると、別にswitch-caseでいいやん、と思ってしまう。
だって、デバッグしやすいじゃないか。
JavaとかC++だったらよいかもしれないけど、Cだと値しかないから、もしオブジェクトが異なるポインタをもらったとしても、その先のオブジェクトの種類を調べるのは面倒だと思う。
もしオブジェクトの最初にオブジェクトの種類があると、ああこのオブジェクトはこの型でキャストされるのね、とわかって追いやすい。

 

でも、switch-caseで書き始めてしまって、どんどん追加になっていって、あああああ、と思うこともしばしばなので、やはり場合によりけりだろう。
やはりデザインパターンというだけあって、パターンが有効なデザインというのも考えんといかんはず。


GoF本に戻ってみよう。
TECHSCOREさんのソースに当てはめると、こうなるか。

  • あるオブジェクト=RookieTeacher
  • 実行されるオペレーション=各HomeのpraisedChild()やreprovedChild()
  • 表現する=各Homeに実装を書く

読んでみると、分岐がどうのこうのというよりも、行いたいことの本質ではない、値のチェックとかそういう処理を同じクラスに書いてしまうとわかりづらい、という主張をしているようだ。

 

GoF本の例では、コンパイラになっている。
「アブストラクト・シンタックスツリーとしてプログラムを表現するコンパイラ」なのだけど、何かもうちょっとわかりやすい例はなかったのだろうか・・・。
ソースファイルを食わせたら文法を解析してXMLみたいなツリーに変換してくれるツールということか?
"Gang of Four"だから、4人のうちの誰かがこういうコンパイラみたいなものが得意だったのかもしれん。

困ったことに、私にコンパイラの話をされてもピンとこないのだ。
例では、VariableRefNodeとAssignmentNodeになっている。
VariableRefは変数参照、Assignmentは割り当て、か?
日本語で「変数あるいは算術表記を表現するノードとは別に代入文を表現するノードを扱う必要がある」と書かれているので、VariableRefNodeは「変数あるいは算術表記を表現するノード」で、AssignmentNodeは「代入文を表現するノード」なのかも。

Visitor
原文らしきものがあった。

Most of these operations will need to treat nodes that represent assignment statements differently from nodes that represent variables or arithmetic expressions.

色を付けたところが、それぞれ対応する箇所になるか。

代入文は"assignment statements"になるようだ。
AssignemntNodeは、これだろう。

もう片方が"variables or arithmetic expressions"なのにVariableRefNodeなのは、VariableNodeだとわかりづらいからか。
VariableArithmeticNodeだと長いし。
VarArithExpNode・・何かだめだな。

 

例として載っているメソッドは、

  • TypeCheck() : 型チェック
  • GenerateCode() : コード生成
  • PrettyPrint() : きれいに印刷する

なのだが、

  • これらのメソッドは各クラスに分散して実装することになるけど、それだとメンテナンス性が悪いんじゃないの?
  • 同じクラスの中に型チェックときれいな印刷のための処理が混ざっているのはどうなの?

ということらしい。
じゃあクラスを分けなければいいじゃないか、と思ったのだが、そうもいかないのだろうか。。。

 

これをどう解決しているかというと、TypeCheckingVisitorやCodeGeneratingVisitorというクラスを作って、

  • TypeCheckingVisitor
    • VisitAssignment() : AssignmentNodeのTypeCheck()
    • VisitVariableRef() : VariableRefNodeのTypeCheck()
  • CodeGeneratingVisitor
    • VisitAssignment() : AssignmentNodeのCodeGenerate()
    • VisitVariableRef() : VariableRefNodeのCodeGenerate()

と、処理でクラスを分けている。

そうか・・・C言語だとクラスに分けずとも関数が書けるから、あまり気にしないのかもしれないな。。。

2016/07/08

[nRF52]nRF52832関連の情報(2016/07/08)

nRF52832のSoftDeviceもv3版準備が始まったことだし、今の時点でどういう情報があるのか見ておこう。


まずはSoftDeviceから。
http://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52832

  • v1版 : 1.0.0-3αで中断
  • v2版 : 2.0.1
  • v3版 : 3.0.0-2αが出たところ

ついでに、nRF5 SDK。
https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v11.x.x/

v11.0.0が3月に出たままですな。
SoftDeviceのv3が出始めているし、時期的にはそろそろバージョンが上がりそうな気がします。

なお、v3αにはSDKの差分が入っているので、もし使うときは差し替えよう。


ツール類は、nRF51822と同じですな。

  • nRF5x Command Line Tools : 9.0.0
  • nRFgo Studio : 1.21.2

SEGGERのJ-Linkアプリも一緒にインストールされるけど、SEGGERのページに出ているものの方がだいたい新しいので、そこら辺はご自由に。
というよりも、SEGGERのアップデートって早いよねぇ。。。

細かいことだが、nrfjprogの動きがnRF51とnRF52で少し違うので注意がいるかも。
nrfjprogの動きが違うというか、チップが違うから結果が違うというだけかな。
FLASH操作周りが違うようだ。

 

うちは基本的にARM-GCCでやっているのですが、そろそろGCC 5系にしようか悩んでいるところ。
nRF5 SDK v11.0.0のリリースノートを見ると、GCC4.9なのだ。
もうそろそろいいんじゃないの?と思っているけど、変なところで失敗したくないし。


nRF52832のICリビジョンは1
Product Specは1.1(pdf)が出ている。
nRF51822のときは、Reference ManualとProduct Specが別だったけど、nRF52832はProduct Specだけのようだ。

 

nRF51からnRF52に移植するときの資料もある。
Cortex-M0からM4Fになっただけだろう、なんて思っていたらひどい目にあうだろうから、軽く目を通しておくと良いだろう。


あとは、評価基板。。。
これがまだ少ない。

太陽誘電さんはもう紹介したので良いとして、その次がない。
Arduino Primoは秋くらいらしいし。
MDBT42が評価サンプルを出し始めたようなので、またRedBearさんから出たりするとうれしいかも。

まあ、評価基板を作っても、モジュールが売れないと意味がないだろうから、あまりたくさんは出ないとは思う。
だから、nRF52-DKみたいに、メーカーが出すやつは重要なのよねぇ。

[java]breakラベルはうらやましい

あまり、Javaに対して「ここがよい」とか「ここが悪い」とかは思わない。
まあ、unsignedがないのはめんどくさいとは思うのだが、そういう言語だしね、と思うことにしている。

ただ、breakについてはJavaがうらやましいと思った。
多重ループを抜けるときが、Cだとあまりきれいに行かないのだ。
私はこういうときのgoto文を許容するのだけど、プロジェクトとかによってはgoto一切禁止、ということもある。
多少は戦うのだけど、そういう文化のところなんだから仕方ない、とあきらめることの方が多い。

そういえば、switch以外でのbreak禁止、なんてところもあった。
ループを抜けるためにフラグを追加したりしたけど、逆にわかりづらいと思うのだけどねぇ。


そういえば、C++だとgotoでスコープを抜けたらデストラクタが動くんだろうか?
いや、動くのだと思うけど、けっこうめんどくさくないか。
どうやって「スコープを外れた」というのを監視してるんだろう。。。

だいたい関数に入ったら、レジスタをいくつかPUSHして、スタック変数を確保して、とやっていると思う。
ただ、抜けるときの動きがよくわからんな。

#include <stdio.h>

class ClassA {
public:
    ClassA()
    {
        printf("ClassA ctor\n");
    }

    ~ClassA()
    {
        printf("ClassA dtor\n");
    }
};

class ClassB {
public:
    ClassB()
    {
        printf("ClassB ctor\n");
    }

    ~ClassB()
    {
        printf("ClassB dtor\n");
    }
};


int main(int argc, char* argv[])
{
    printf("main - begin\n");

    for (int lp1 = 0; lp1 < 10; lp1++) {
        ClassA cla;
        for (int lp2 = 0; lp2 < 80; lp2++) {
            ClassB clb;

            if (lp2 == 71) {
                goto CATCH;
            }
        }
    }

CATCH:
    printf("main - end\n");
    return 0;
}

$ ./tst
main - begin
ClassA ctor
ClassB ctor
ClassB dtor
ClassB ctor
ClassB dtor
ClassA dtor
main - end

うん、"main - end"の前にClass Aのデストラクタが動いている。
Class Bよりも後なので、スコープが外れる内側から順番に呼ばれているのだろう。

arm-none-eabi-g++ -Sでアセンブラにしてみたのだが、なんかよくわからん。
main()の中でClassAのデストラクタだけ2回呼ぶ処理が入っている。
__cxa_end_cleanup()があって、これは何か最終処理っぽいものだったような気がする。

71と比較してイコールだったときのルートを追っていくと、確かにClassBのデストラクタ→ClassAのデストラクタという順で呼んでいた。
最後のClassAデストラクタも呼んでいるので、このときに2回呼ばれることになる。

ClassAのデストラクタを見たけれども、1回処理したら2回目以降はしない、みたいな処理は書いてないように見えるなぁ。。。
あまり読み方がわかってないせいかもしれん。

2016/07/06

[java]CountDownLatchはawait()前にcountDown()されることも考慮しよう

非同期処理の待ち合わせに、CountDownLatchを使っていた。
Effective Javaにも書いてあったので、だいたいそうするのだろう。

 

これをタイムアウト有りでawait()させていたのだが、ときどきタイムアウトが発生していることに気付いた。
通信なので相手とのタイミングはときどき変わるものの、タイムアウトするような要素はない。
なぜだ。。。

 

今回、await()やcountDown()でチェックしたいものがあったので、それらをラップしたメソッドを作っていた。
で、await()させるほうのメソッドでCountDownLatchをnewし、非同期で終わったときにcountDown()させるようにしていた。
一応、異常時にawait()せずに非同期処理だけが動くパターンがあるので、その場合はcountDown()させないようにしていた。

そしたら、await()が呼ばれる前に非同期処理の方が先に完了していたのだ。
もしcountDown()をそこで呼んでいればawait()はtrueで終わるのだけど、異常時と同じルートを通ったためcountDown()せず。。。

 

いや、言い訳だけすると、これでも非同期処理が先に終わるのは考慮したつもりだったのだよ。
ただなんとなく、Javaのスレッドってメソッド単位とかでやってくれるんじゃないの、などと思っていたのだ。
適当は、いかんね。

 

対処は、非同期処理を呼ぶ前にCountDownLatchをnewさせ、異常ルートでもcountDown()を呼ぶようにした、だ。
カウントダウンする準備さえ整えておけば、怖いものではない。

 

ただ、そこに行くまでが紆余曲折してね。。。
スレッドだから、ディスパッチ禁止させようとしてメソッドをsynchronizedにしてしまい、デッドロックしたとかね。。。

[nrf51]IC rev.3以上でないとSD130v2はサポートされない

nRF52832のSD132v3α版が出ていた。
うちには使えるnRF52832ないのだけど、ATT MTUが512バイトまで拡張されるなど、どういう感じになるのか興味深い。

 

そういえば、nRF51822はどうなっていたっけ、と見てみると、SD130v2.0.1というのが出ていた。
v2.0.0までしか気付いていなかったが、HEXファイルからすると2016/04/20にリリースされていたようだ。

そしてこれにも気付いていなかったのだが、v2からはICリビジョンは3からじゃないと保証しないようだ。
v2のNotesには「リビジョン1は~」と書いてあるけど、その下のUpdate1には「リビジョン2以前は~」になっている。

 

うーん、うちにあるのはリビジョン2だけなのだ。。。
リビジョン3が確実である評価基板は、こういうやつだろう。

でも、いまだったらnRF52832の方がいいよなぁ。。。
あきらめて太陽誘電さんの評価基板をDigiKeyとかで注文したら、もっと安い基板が出て後悔しそうな気もするし。。。

悩める私であった。

2016/07/05

[java]byte解析の恐怖

何度かやらかしたアレを、またやってしまった。。。

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

プロトコル解析処理で、byte配列のデータを扱っていたのだけど、ところどころ間違っていた。

たとえば、res[5]にデータ長が入っていたとして、

int length = res[5];

何てことを平気でやっていたのだ。
テストデータも長さが短かったのですり抜けていて、負荷テスト用の大きいデータにしたら、もういきなり「配列サイズに負の数を指定してる例外」とか「バッファサイズが足りないよ例外」とか、「チェックサムが一致してナインだけど」とか、あれこれ言われ始めた。。。

 

unsignedな自分のために、対策を書いておこう。

  • byte変数を比較するだけだったら、あまり気にしなくて良い。
    相手が直値だったら、(byte)とか付けてやることもあるだろうが、まあエディタの段階でわかるだろう。
  • 計算するときは、「& 0xFF」としておくのだ。
    byte以外に代入するときも、やっておこう。
    チェックサムは案外いけるんじゃないかと思ったけど、計算方法次第か。
    あとで見て迷うと思うから、論理積を取っておこう。

計算するとint型になる、だったはず。

 

では、byte型を演算して、その結果をbyte型と比較するんだったら、ここまでしなくても大丈夫だろうか?
前回も「ビットが小さくなる方は勝手に削られるからよかろう」としている。
ただ、演算した方をbyte型にキャストするのをわすれんようにせないかん。

 

1箇所こういうのを見つけると、急に不安になるから困りますな。
もうbyte演算恐怖症です。。。

[android]今の時間を文字列でほしい

TextViewにログを出そうとしている。
日付はいらないのだが、ミリ秒までの表示はいる。

ネットで検索していて、こういうのを使っていた。

long currentTimeMillis = System.currentTimeMillis();
Date date = new Date(currentTimeMillis);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss SSS");
return simpleDateFormat.format(date);

これはこれで動いていて気にしなかったのだが、Android Studioでgitのcommitをしようとしたら警告が出てきた。
そうか、Android Studioはなにかチェックしてからcommitしてくれるんだ。。。

image

長いよ。
なんか、ロケールを考慮するんだったらちゃんとやれ、みたいなことを言っているようだ。
検索すると、こちらが出てきた。

Y.A.M の 雑記帳: SimpleDateFormat ではなく android.text.format.DateFormat を使おう

まあ、そんなに難しくなく置き換えられそうだ。

return (String) DateFormat.format("HH:mm:ss SSS", Calendar.getInstance());

 

ただ気になったのが、format()がイタリック体で表示されていることだ。
ほぼAndroid Studioのデフォルトで使っているのだが、どういう意味だろう?
そういえばgetInstance()もイタリックだから、クラスメソッドという意味だろう、きっと。

 

で、これを使うと・・・ミリ秒のつもりが"SSS"とそのまま出力された。。
でも、format()→SimpleDateFormatとたどると、ミリ秒はやはり"S"だ。
Examplesもそうなっているので、文字列コピーして使ってみたが、やっぱり"SSS"。

musyamusya: 【Android】日時の取得でミリ秒までとりたい時【メモ】
やはり、"SSS"になってしまうらしい。
理由はわからんが、最初の書き方にロケールを書くしかないか。

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss SSS",
      Locale.getDefault());
return simpleDateFormat.format(new Date());

すっきりせんが、仕方ない。


さて、これでだいたい終わりなのだが、DateFormatとは関係なくもうちょっと気になることがある。

こちらがformat()の説明なのだが、戻り値がCharSequence型だ。
第1引数も戻り値もCharSequence型。
引数には"HH:mm"など書いているので、String型になっていると思うのだけど、特に怒られない。
だが、String型のreturnを直接format()にすると、これはキャストしろと怒られるのだ。
CharSequenceはなんだろう?

 

何かと思ったら、CharSequenceはjava.lang.CharSequenceというinterfaceとのこと。
まあ、ダウンキャストを自動でされると、ちょっと気持ち悪いしね。

2016/07/03

[DL]ゴッホ風の絵に変換するところを理解したい (4)

ゴッホ風の絵に変換するところを理解したい、といいつつ、その部分よりも前の方でつまずいているのだが、仕事でやっているわけでもないので、まあいいとしよう。

当面の目標は、畳み込みニューラルネットのフィルタはどうなっているのか調べる、だ。


[1508.06576] A Neural Algorithm of Artistic Style

こちらが元の論文らしい。
なんとなく眺めてみたが、なんとなくフィルタについては書いていないようだ。

となると、やはり元のVGGというニューラルネットがフィルタの情報を持っているんじゃなかろうか。


[1409.1556] Very Deep Convolutional Networks for Large-Scale Image Recognition

VGGは、Visual Geometry Groupの略だと思われる。
オックスフォード大学のマークが入っている。
PDFだと「Department of Engineering Science」と書いてあるので、理工学部みたいなものかな?

1ページ目にリンクが書いてある。
Modelsの16-layer modelが、使っているネットワークのモデルのようだ。
Caffe用だ。

64チャネルは最初のレイヤーだから、これの一番上にあるやつだろう。
bottomがinputで、topがoutput。つまり、"data"は画像で、このレイヤーで計算した結果が"conv1_1"になる。
レイヤーは畳み込みの"CONVOLUTION"で、出力は64枚、kernel_sizeが3なのでフィルタは3x3、出力がフィルタ後も同じサイズになるようにpadを1にしている。
フィルタ後も同じサイズにしたい場合、Cで言えば(int)(フィルタサイズ / 2.0)にするのだ(フィルタサイズは普通奇数なので)。

そういうのはわかるけど、ここにもフィルタについては情報がない。
これだけで動くのだったら、フィルタの情報は"CONVOLUTION"が持っていることになるのか。


Theanoによる畳み込みニューラルネットワークの実装 (1) - 人工知能に関する断創録

こちらを読むと、フィルタは学習して得られると書かれている。
なるほど、どこに学習する要素があるのかと思ったけど、ここだったのか。
そりゃ、話が出てこないわけだ。

 

畳み込みニューラル・ネットワークの使い方、わかりますか? | Altera - SDJ JP

ここの「トレーニング」にフィルタ係数のことが書かれている。
アルテラ社だからFPGAの話だけかと思ったけど、こういう記事もあるのですな。

この記事はわかりやすいと思う。
畳み込みニューラルネットが、どういう技術で構成されているか書かれているし、どここが学習する要素なのか書いてあった。
最後の方の「何か納得がいかない」には共感を得るだろう。

やはりここでも、フィルタというかカーネルは学習から得られるものとなっている。

 

ゴッホ風の絵でも「予め物体認識で訓練したニューラルネットを使用し」とあるが、カーネルの学習も行わないものなのだろうか?
それとも、そこは入力画像によって学習するのが当たり前のものなのだろうか。
アルテラ社の記事では、カーネルの部分と、最後のパターン解釈でニューラルネットを使うように書かれているので、「カーネルの部分は毎回学習させるけど、最後のパターン解釈は訓練済みを使う」みたいなこともできるのかもしれん。

なんとなくだけど、全部セットになって「学習」という気がするので、一部だけってのはないんじゃなかろうか。
フィルタの部分だけで誤差関数を決めるのって、できないと思うのだ。


よくわからないところも残っているが、気になったらまた考えることにしよう。

ここまでが、アルゴリズムの説明の「モデル」のVGG 16-layerの話だ。
ようやくここから、CNNで得られた中間層の結果をどう使っていくのかという話になる。
先が長い・・・。

[DL]ゴッホ風の絵に変換するところを理解したい (3)

「なるようになる」という言葉がある。
だいたい、私はそういう気分だ。
そもそも、なるようにならない、という方が言葉としてはおかしいだろう。

ただ、それでも、自分が思うようになってほしい、ということはある。
それは傲慢ではあるが、人間らしくもある。
「機械学習」といいつつも、実は機械的じゃない部分があるのではないか?、何か見えざる何者かの手が入っているのではないのか?という不安は、あまり無視できないのかもしれない。

八百万の神、みたいな概念ではなく、一神教、あるいは数の限れた多神教の考え方からするとよろしくないかもしれないので、「シンクタンク」みたいな表現の方が良いのかもしれない。

表現方法は大事だと思う。


さて、深層かどうかは置くとして、機械学習には「学習」という期間が必要になる。
学習しながら間違いを探す、というのはできないと思う。
間違って、教えてもらう、というだけだ。
自分で間違っていることがわからないからだ。

そういうわけで、深層学習においても学習の過程は大切なのだ。
今回読んでいる記事では、ゴッホ風の絵に変換するという作業に対しては新しく学習を行っていない、とある。

読んでいった感じからすると、絵の特徴を残して、それ以外の要素をなるべくそぎ落とし、そぎ落とした部分に他の絵画の特徴を付け加えることによって「○○風」という特徴を出そうとしている、と私は読んだ。

記事としては「○○風」を出すところがメインのようだけど、私としてはその手前までの過程が気になっている、というのがこの3回までの趣旨だ。


元になっているのは、④のデータだと思う。
記事の真ん中くらいにある、ネコさんだ。

特徴だけ、というわりには、かなり最初のイメージが残りすぎている気がするが、おそらくそれは、目的が「ゴッホ風の絵にする」だからだと思う。
というよりも、3x3のフィルタをちょこちょこ掛けても、そんなに元の画像から変わらないんじゃないかと思うのだ。

元のPDFの目的まではわからないのだけど、この画風変更のお話からすると、元の画像の特徴がきれいさっぱりなくなっていると意味がないので、わざと残しているのではないかと思ったのだ。

だからこそ、フィルタってどういう風に作っているのだろう、が気になるのである。
どういう画像にも合うフィルタを作るアルゴリズムがあるのなら、そっちの方がすごいと思うのだ。


この辺りは、日本語記事の「おわりに」の辺りにも書かれている。
まだ、アプローチの段階なのだ。
楽しいところではないか。

私個人としては、こういうところに自分なりの解法を見つけて、他の人に「どういう式なのか意味はさっぱりわからないけど、確かにこれでうまくいってしまう」みたいなものを見つけたいと思っているのだ。

そういうささやかな夢を楽しみたいものである。。。

 

ときれいに締めたいのだが、フィルタの選び方についてはわからんままなので、、わかったら記事にしよう。

2016/07/02

[DL]ゴッホ風の絵に変換するところを理解したい (2)

前回、図まで描いて説明したフィルタだけど、『深層学習』の6.3.3章に全部書いてありますな。。。
まあ、こういった内容は、画像処理の勉強をし始めると最初の方に出てくるのだ。
輪講とかで使ったテキストを持っていれば、今役に立ったかもしれないのに。。。

そう、なので、この辺りは深層学習というよりも、画像処理の話だろう、と思いながら読んでしまうのだ。
たぶん、時系列データに向いている再帰型ニューラルネットも、私が知らないだけで、何かそういう既存の処理が応用されているんじゃなかろうか。
この辺りが深層学習の奥が深いところですな。


さて、それでは畳み込み層の64チャネルって何よ?を続けていこう。

まず、入力画像のチャネル数は、画像に使われている原色の数(でいいのかな?)になる。
普通のカラー画像なら、RGBということで3。
モノクロなら、1。
いくらグレースケールで256段階で表現されていても、そこは1なのだ。

説明図では、チャネル数がKの入力に対して、M種類のフィルタを掛ける例になっている。
フィルタ1をチャネル1~Kの画像に掛け、次にフィルタ2をチャネル1~Kの画像に掛け・・・とやっていく。
そしてその結果は・・・チャネル数がMになるのだ!

だから、入力画像のチャネル数がいくつであっても、掛けるフィルタの数で出力のチャネル数が決まるのだ。
うん、推測は当たっていた。


では、どうやって64種類ものフィルタを決めているのだろうか?
しかも次の段では128、さらに256、512まであるのだ。

『深層学習』p.102に、conv1層のフィルタという画像が96例載っている。
カラーだったりモノクロだったり、丸っぽかったりしましまだったりと、数学的に数値を1~96まで当てはめたような感じはしない。
なにか、何かあるはず。。。


私は数学の人じゃないのだけど、結果的にうまくいった、というのはあまり数学っぽくないと思うのだ。
それが良いとか悪いとかじゃなくて、太陽を見るとまぶしい、とか、この花はきれいだ、とか、そういう感触がない気がするというだけのことなのだ。

うーん「根拠」といえばよいのかな?

ここでフィルタが64だの128だのあるけれども、なにか理由があって選ばれたものなのか、なんかランダムで作ったフィルタの中でよさそうなものを選りすぐったのかというのが気になるだけだ。


もう一度、最初に読んだ日本語の記事に戻ろう。

画風を変換するアルゴリズム | Preferred Research

最初だけ読んでいったが、全体的にどういうことをしているのかを見ておくと、何か思いつくかもしれない。

  • CNNを使って画像生成する
  • 新たな学習は行っていない
  • VGG 16-layerのCNNモデルを使っている
  • 処理は④の出力を使う

ここまでが前段になるか。
やっているのは、フィルタ処理だけだから、深層学習とかニューラルネットとか、そういうものは使っていないと思う。
使っているのか?
うーん、使っていそうなところが思いつかない。
フィルタを何段階かかましているだけのように思う。

 

内容は気にせず、この次の流れを見てみよう。

  • CNNを10層進んでも、元の画像の雰囲気は残っている
    • が、ここまで来ると主立った特徴だけが残っている感じがする
      • では、消えた部分に他の特徴を足せば、そっちの特徴が強まって見えるのでは?
        • 試しにゴッホ風の特徴を足してみよう

この読み方が当たっているなら、ここで使われているディープラーニングは「弱い特徴をそぎ落とす」というフィルタ処理だろう。
イメージとしては、音楽で低音を強めにしたり、声と同じ周波数帯を強めてボーカルだけ大きくしたりとか、そういう感じか。
知能的なミッドパスフィルタ、とでも言おうか。

なるほど、そういう考え方もあるのか。


ただ、どこら辺で学習した内容を使っているのかを読み取れていない。

もしかすると「どうやってフィルタを選んでいるんだ?」のところなのか??
ネコの画像から下がお話のメインなのだろうけど、その前が気になっているのだ。

 

うーん、もうちょっと調べるべきか?

[DL]ゴッホ風の絵に変換するところを理解したい (1)

深層学習でやるのは、クラスタリングがメインだと思っていた。
が、よく「○○風の絵をディープラーニングでつくる」みたいな記事もある。
最初に見かけたのは、ゴッホ風の絵にする、だったと思う。

どこら辺が深層学習と結びついているのだろう?
理解できるかどうかわからんが、努力してみよう。


画風を変換するアルゴリズム | Preferred Research

日本語で説明が書いてあるので、これを読むことにする。
が、いきなり詰まった。。。

入力画像は、RGBの256x256なので、3*256*256なのはわかる。
その次が、64*256*256。
3の倍数じゃないやん!

その下にある中間層を画像化したものも、チャネル3つ分がそれぞれあるので、64*256*256が3つ分ある、でよいのかな?
つまり、①以降は、入力画像の1チャネルに対しての結果という考え方だ。

・・・違うな、数が多いから3チャネル分だけ抽出したと書かれている。
ということは、RGBをグレースケール化して計算したのかしら。
カラーからグレースケールするときには一般的な変換式があるけど、そのパターンが64あるから64チャネルになる、という考え方だ。

 

http://arxiv.org/pdf/1409.1556.pdf
おそらく、こちらが「VGG 16-layerのCNNモデル」と書かれている原本だと思う。
3ページ目のDが、16weightで、conv3-64, -128, -256, -512, -512と表になっているから、表の上から4つが、①~④になっていると思われる。
「conv<receptive field size>-<number of channels>」と書いてあるので、たぶんそうだろう。

receptive field sizeが3。
『深層学習』p.80にもある、受容野だ。
3x3のフィルタと考えるとよいのかな?
もしそうだったら、普通に3x3のフィルタを掛けると、上下左右で1ピクセルずつ小さくなる。

3x3のフィルタだと、たとえば画像の左上だとしたら、(0, 0)-(2, 2)になる。
このフィルタで計算できるのは、(1, 1)の画素値だ。

image

今は知らないけど、私が画像処理の勉強をしていた頃はこういうフィルタの書き方をしていて、画素に対してこの掛け算を行い、その総和を中央の値にするのだ。
これだと、画素が9つあって、それぞれ1/9だから、移動平均のフィルタになる。

もし画像が5x5だったら、3x3のフィルタで計算できるのは黄色の範囲だけになる。

image

画像が小さくなるのが嫌だったら、それっぽい画素値を外側に用意してやるしかない。

image

というわけで、フィルタした後も256x256を保っているから、そういう計算をしたのだろう。

じゃあ、64ってのは何だろうか?
PDFを検索したけど、"2.2 CONFIGURATIONS"に「最初のレイヤーは64から始めて~」しか書いてない。
主語は、width of conv. layers。
畳み込み層の大きさか。

 

『深層学習』のp.87に畳み込み層の章がある。
たしかにここにも、多チャネルの画像に対して複数個のフィルタを並行して演算するようなことが書かれている。
書いてあることと、ネットで説明してあることが一致しているのはだいたいわかるのだが、あっさりと「入力では3チャネルだけど中間層では16チャネルとか256チャネルとかになります」と書かれても、納得できないではないか!

もうちょっと調べて理解を進めよう。


こんな感じでやっていきます。
2回目があるのかどうか、我ながら心配です。。