2015/04/28

汝の名はBlueZ - (5)

なんでこんなタイトルにしたんだろう・・・そう思いながらも5回目だ。

スキャンはなんとなくわかったので、次は接続だ。
いつもの図を載せるが、今回はCentralとしての動きになる。
Scanningするけど、そこから続けてInitiatingになるのではなく、一度Standbyを挟んでいる。
つまり、Scanningは必須ではないということだろう。
InitiatingからConnectionは一連の流れだ。

image

 

BlueZで使えるコマンドラインツールでも、そういう動きになっている。
Linux でBLEのドングルを刺して通信させる。 | mbed

まず、hcitool lescanでスキャンするが、次に使うのはgatttoolだ。
スキャンをCtrl+C・・・じゃなくてCtrl+Zで止めてるが、とにかく連続した操作ではなく、アドレスが共通で使われるだけだ。


と、勝ち誇ったように書いたのだが・・・。
Raspberry Pi乗で、gatttool使ってconnectしようとしても、エラーが出てしまう。
特に悪いことはしてなさそうなんだが・・・。

俺はこうやって対応したぜ、というのがあった。
raspberry pi - BLE gatttool cannot connect even though device is discoverable with hcitool lescan - Stack Overflow
apt-getでインストールされるBlueZではなく、自分で最新版を持ってきてビルドするのだ。
さっきRaspberry Piのbluezをdpkg -lで見ると、4.99とかだった。
今は5.30が最新みたいなので、その差なんだろうか。

 

ビルドして動かそうと思ったが、セルフビルドは遅い・・・。
また今度にしよう。

2015/04/26

汝の名はBlueZ - (4)

gattoolsのconnectっぽいところを実装しようかと思ったが、まずはBLEのスキャンについて残しておこう。
Bluezのソースファイルから、hcitool.cを見ていく。


hcitoolのlescanは、こういう構成になっている。

hci_open_dev()
    hci_le_set_scan_parameters();
    hci_le_set_scan_enable(始め);
    ・・・(あれこれ)・・・
    hci_le_set_scan_enable(終わり);
hci_close_dev();

では、スキャン中に何をやってるのか?


あれこれ、と書いているのはprint_advertising_devices()。
BlueZの関数ではない。

まず、取得するデータのフィルタを設定するようだ。
hci_filter_clear()でクリアして(やってるのは単なるmemset)、hci_filter_set_ptype()でパケットタイプを指定して(HCI_EVENT_PKT)、hci_filter_set_event()でイベントの種類を指定している(EVT_LE_META_EVENT)。

と書いてはみたものの、何をしているのかさっぱりわからない。
Core_V4.2.pdfを見ると、p.1238に「7.7.65 LE Meta Event」という章があった。
Event Codeは0x3Eで、EVT_LE_META_EVENTの定義値と同じだ。
どうやら、このイベントはBLEのコントローラ関連のイベント全部で、サブイベントコードでさらに細かい内容がわかるようだ。

hci_open_dev()で取得したハンドラ(ファイルディスクリプタ)をread()して、読み込んだデータをevt_le_meta_eventにキャストしている。これがhci_filterで設定していたイベントだ。
そのサブイベントコードがEVT_LE_ADVERTISING_REPORT、Core_V4.2.pdfの「7.7.65.2 LE Advertising Report Event」かどうかをチェックし、そうだったらさらにle_advertising_infoにキャストして、アドレスと名前を表示させている。

この辺の定義は、BlueZのlibディレクトリの中に入っている。
hci.hとかhci_lib.hとか。


しかしまあ、ソースにもコメントがないし、ドキュメントっていう感じのものもないので、つらいですな。

2015/04/25

[gcc?]本体側による共有ライブラリ側extern変数のオーバーライド

言葉で説明すると、こんな感じのソースコードに出会った。

Linuxで、プロセス側のソースコードに定義してあるグローバル変数を共有ライブラリでexternして参照している。

ifdefとかがいっぱいあるので深く追っていないのだが、grepしただけだと値渡しもアドレス渡しもしてるように見えない。
そんなことできるんだっけ?と思って新しくグローバル変数をプロセス側に追加し、共有ライブラリでexternしてみたけど、コンパイルは通るがリンクで未定義になる。
うん、そうだよな。
でも既存の部分は動いているようだ。
なんなんだ、これは??


よくわからんので「共有ライブラリ グローバル変数」みたいなキーワードで検索。
出てくるのは、メモリの確保はプロセス側でやるのだよ、みたいなことばかりだったが、ようやく見つけた。

いまさらC言語のexternで悩む | ビットログ

そうそう、こんな感じ。
これは同じコンパイル単位だけど、それが共有ライブラリでも起きているという感じ。
試してみよう。

 

shared_lib.h
#ifndef SHARED_LIB_H
#define SHARED_LIB_H
extern int gValues[];
extern int gSize;
int shared_lib_func(int *p_size);
#endif /* SHARED_LIB_H */

 

shared_lib.c

#include <stdio.h>
#include "shared_lib.h"
int gValues[] = { 0 };
int gSize = sizeof(gValues) / sizeof(gValues[0]);
int shared_lib_func(int *p_size)
{
    *p_size = gSize;
    return gValues[0];
}

 

main.c

#include <stdio.h>
#include "shared_lib.h"
int gValues[] = { 1, 2, 3 };
int gSize = sizeof(gValues) / sizeof(gValues[0]);
int main(int argc, char *argv[])
{
    int size = 0;
    int ret = shared_lib_func(&size);
    printf("ret = %d / size = %d\n", ret, size);
    return 0;
}

 

$ gcc -o libshared.so -fPIC -shared shared_lib.c
$ gcc -o tst main.c -L. -lshared
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
$ ./tst
ret = 1 / size = 3

ほう!
本体も共有ライブラリもgValues[]を持っているけど、本体側の方が優先されているのだ。
感触としては、WEAKの動作と似ている。
hiro99ma blog: [nrf51]app_error_handler()はWEAK

気持ちとしては「共有ライブラリ側にあるグローバル変数なんて本体側は知らないだろうから、本体側を優先させるのが筋よね」なんだろうが、共有ライブラリの動作も変わるとなると、なんかすごいな。

まあ、普通はグローバル変数をさらけだすなんてことはないから、今回見たコードもわざとやってるんだとは思うのだけど、わかりにくいよね・・・。
テクニックとして使っているつもりだったらコメントくらい入れてほしいし、それよりも普通にポインタをもらうような実装にしてもらった方がメンテナンス性はよいのだけどね。

汝の名はBlueZ - (3)

さて、BlueZを使ってBLEをなんかするプログラムを作ろう。
もちろん、C/C++だ(それしかわからん)。

動かすのは、Raspberry Piにする。
私がメインで使っているのはWindows7で、資料がそっちにあるからLinuxを立ち上げたくないのだ。
Raspberry Piだとセルフビルドできるので、お手軽でもある。
ファイルはWindowsで作って、WinSCPで転送している。

BLEが使えるドングルは、こちらで購入したものを使った。
http://ssci.to/2116


ソースは、ここからいただいた。
bluez-experiments/scantest.c at master · carsonmcdonald/bluez-experiments

$ sudo apt-get install libbluetooth-dev
$ sudo apt-get install libncurses5-dev
$ gcc -o scantest scantest.c -lbluetooth -lcurses

これでビルドできた。

$ ./scantest

・・・出てこない。
Scanning、というのは出てくるのだが、そこから出てこないのだ。
hcitool lescanでは出てくるから、作ったプログラムで読み取れてないだけのようだ。

よくわからんので、hcitoolのソースファイルからlescanの部分だけ抜き出してプログラムを作ってみた。
動かしてみると"Operation not permitted"って出てきた。
ああ・・・sudoしてやらんといかんのか・・・

$ sudo ./scantest

はい、無事に出てきました。

Raspberry PiはCentralとして使うので、gattoolでやってるようなことをやらにゃいかん。
それはまた次回で。

[ubuntu]apt-getではinstallした一覧は見えないので、dpkgを使う

いつも同じことを調べてしまうので、メモしておこう。

apt-get installでインストールした一覧を見たいときは、

dpkg -l

する。
「apt-getでやったことはapt-getで確認できてもいいじゃないか!」などと怒ってはダメだ。

特定のパッケージを確認したいなら、

dpkg -l [パッケージ名]

だ。
インストールされたファイルを見るならば、

dpkg -L [パッケージ名]

だ。

こちらが読みやすかったです。
[Ubuntu] apt-get まとめ - Qiita

2015/04/23

汝の名はBlueZ - (2)

BlueZのことを調べていたのだけれど、情報が少ない。
こういうコマンドが使える、みたいなのはあるのだが、何をどこまでやっているのかがわからない。

あきらめて書いてしまうと、私はCONNECTするチャネルを固定させたかったのだ。
Advertisingは37ch, 38ch, 39chの3つでやるのだけど、CentralがどのチャネルでCONNECTするかよくわかってない。
BLEの無線モニタを使うとわかるのだけど、どれか1chをAdvertisingのときから監視し、CONNECTされたらそこでやりとりする情報を使ってホッピングにも対応してモニタが続けられる、という感じだ(たぶん)。
だから、CONNECTがどのチャネルになるかわからないとなると、うまくCONNECT後もモニタできる確率は3分の1くらいになってしまう。
もし再現性がほとんどない不具合を追っていて、それをモニタで見られる確率が3分の1とかになると、非常に腹立たしいだろうと思うのだ。

BlueZだったらソースコードもあるし、その辺がいじれるんじゃないかと期待していた。
が、Core_V4.1とかのメッセージシーケンスを見ても、Advertisingは開始要求するだけだし、Scanningについても同様だ。
gatttoolを少し追ったけど、チャネルを指定してCONNECTするような感じには見えない。
なので、そういう部分はドライバか、おそらくはモジュールの内部で行われているのだろう。

 

という結論を勝手に出した。
どうしてもきっちりモニタしたいなら、モニタを3つ買え、ということになるが、まあそんなにがんばってないから、まだよしとしよう。

2015/04/21

汝の名はBlueZ - (1)

そろそろ、BLEのサービスを作ろうと思っている。
あー、FeliCa Plugが動くまで-、とか、I2Cが動くまで-、とか、FeliCa Linkが動くまで-、とか、いろいろ理由を付けていたんだけど、FeliCa Linkが動いてしまったので、Peripheral側に付ける理由がなくなってしまった。

だが、もう少し理由が残っている。
サービスを作るには、サービスを使う側も用意しないといけないのだ。
前回が単にInputとOutputするだけだったのでスマホのそういうアプリを使っていたのだけど、今回のサービスはちゃんとCentral側で実装をしたいと思っている。
そう、今回は「Central側が動かせるようになるまで-」という理由を付けようと思っている。

 

最初、Androidでやろうと思っていた。
iOSのAPIの方が出来がよい、という話は聞くのだけどまだその差がわかるレベルじゃないし、うちのiPad mini(old)は私の目を覚まさせるという重要な役目があるので、あまり寝床から動かしたくない。
かといって、Androidが得意というわけでもない。
できれば、コンソールとかでデバッグ出力を出しながら扱える方がよい。

そうなると、Linuxで動くBlueZかな、と思った。
いや、使ったことはないのだけど、デファクトスタンダードって感じがするし、Raspberry Piで調べてたときも出てきたし。
スマホベースだと安全な実装になるよう考慮されてそうだけど、PCベースだったら何でも出来そうな気がするし、ソースが全部あるんだったら、何とかなるんじゃないかな、くらいの軽い気持ちだ。

今までの経験で、こういうのは軽く考えても重く考えてもあまり結果が変わらなかったのだよ。


検索すると、日本語でも情報がよく出てくる。
なんだ、やっぱり軽く考えて正解だった、などと思ったのだが、次に書いてあるのは「ドキュメントがほとんど無い」という情報だった。

BlueZ初日は、こんな感じだった。

2015/04/19

アクティブタグのNFC

FeliCa Linkは、大きく分けて2つのモードを持つ。

  • タグモード
  • リーダ/ライタモード

そう、FeliCa LinkはR/Wになることができるのだ。
ただし、RC-S730に載っているチップはRC-S967/1Vで、この子にはリーダ/ライタモードが無い
無いのだ・・・。

これは残念なことなのだが、やはり小さいモジュールにはリーダライタとして動かせるほどのアンテナを載せられないということなのだろうか。
iPhone6が出たときも、アンテナが見当たらないけどブーストICはある、みたいな記事があったし。
NFCのR/Wになるということは、普通はパッシブなタグに対して起電力を生み出せる程度の搬送波が必要なのだろう。

はっ!
パッシブタグを前提として考えてたんだけど、アクティブタグとしか通信しないと割り切ったのだったら、どうなるんだろう。
アクティブタグを使ったことはないんだけど、きっと、起電力どうのこうのは関係なくなるに違いない。
iWatchだっけ、あれにもNFCが載るという話だったが、あれ自身が無線を出せるのなら、iPhone6でも受信できそうな気がする。

まあ、お店決済用と割り切って、ばんばん無線を出せるのだったら関係ないだろうけどね。

2015/04/18

[nrf51]とりあえずFeliCa Linkが動いた(nRF51822)

mbedで動いていたFeliCa Linkのライブラリを、nRF51822に移植した。
前回が3/29だったので半月近くかかったように見えるが、実はやってないだけだった。。。

UART接続したのと、/RFDETにプルアップ抵抗を付けたので、回路図を貼り直しておこう。
プルアップしたのは、ロジアナで波形が取れなかったからだ。
LEDが点灯していたので動かす上では問題が無かったんだけど、LEDだとプルアップ抵抗代わりにはならないってことなのかな。

image

ソースはこちら。
https://github.com/hirokuma/nrf51822_felicalink

まだBLEの方は全然手つかずだ。
だがあえて・・・あえてこの作業状況をみんなの前にさらそう。

image

下にある赤い基板が、nRF51822の載ったBVMCNDT52。
その下に緑と白の線があるが、これはUART(回路図のTx/Rx)。
びろーんと延びているのは、J-Link LITEへのケーブルだ。
LEDは、回路図のAdvertising、Connected、AssertのLEDだ。

上側のブレッドボードに、液晶SB1602と、RC-S730。
白いやつは、ロジアナだ。
左側の黄色いLEDは、RFDETにつながっている。
たぶん、回路図通りに並んでいるはずだ。

一番上が、RC-S730本体と、その下にPaSoRi。
PaSoRiから下のブレッドボードまでが30cmくらいだ。
私が何かやっているときのスペースは、この30cm x 20cmくらいの範囲でだいたいやっている。
せ、狭い・・・。


GitHubに置いたのは、FeliCa Linkが動いた、というだけのソースなので、BLEなんかはまったく動かしていない。
nRF51822としては、これからが本題なのだ。

本番なんだけど、ちょっと手が動かない・・・。
これからは通信する相手が必要になってくるんだけど、iOSにせよAndroidにせよ、なんか作らんといかん。
その一歩が、なかなか踏み出せないのよねぇ。

まあ、今年はGWが長いこと取れそうなので、踏ん張ってみますかね。

[nrf51]GPIOとGPIOTE

GPIOはよいとして、GPIOTEというのはあまり他のマイコンでは見られない周辺機能だと思う。
nRF51822には、そのGPIOTEがある。


まず、GPIO。
General Purpose Input/Outputで、これは他のマイコンでもおなじみだ。
nRF51822には32本のGPIOがある。
それぞれのピンは独立していて、設定もそれぞれにできる(PIN_CNF[n]レジスタ)。

  • DIR(InputかOutputかの方向)
  • INPUT(inputバッファに接続するかどうか。使わんなら切断しとくと省電力に貢献)
  • PULL(プルアップ/プルダウン/なし)
  • DRIVE(他周辺機器用?)
  • SENSE(入力の1/0検出レベル)

リファレンスマニュアルの図を見ないと、意味がわかりづらいと思う。

ビットをセットするだけのレジスタとクリアするだけのレジスタがあるので、自分で読んで論理演算操作しなくてもよい。
これができないと、アトミックな操作ができなくて面倒なことがあるのよね。

SENSEは、次のGPIOTEに関係していると思う。
あるいは、WFI/WFEの解除トリガになってくれるのかもしれないが、Peripheral interfaceの図を見ると、NVICにつながっているのはEVENTになっているので、DETECTがアサートされただけでは解除されないと思う。
DETECT線へ通知するとは書いてあるんだけど、これがどうなるかまでは書いてないのだ。


GPIOTEは、GPIO Task and Eventの略。
だから、TaskとかEventとかの概念があるnRF51822くらいしか持ってないんじゃないかと思う。

Taskはアプリ→周辺機器方向への要求で、こんなのができる。

  • SET
  • CLEAR
  • TOGGLE

まあ、こんなもんでしょうな。

Eventは周辺機器→アプリ方向への通知で、こんなのが来る。

  • 立ち上がりエッジ
  • 立ち下がりエッジ
  • 変化あり

まあ、こんなもんでしょうな。
CONFIGで設定ができるが、2bit分あるのに設定値が0, 1(Event mode), 3(Task mode)だ。
なんとなく、2がTask modeで、3がTask and Event modeみたいになりそうだけど、そうじゃないんだ。

これはCONFIGが4つ分しかないので、4ピン分しか使えないはずだ。
ではnRF51 SDKがどうしているかというと、特にそういう制約は書かれていない。
むしろ、初期化時に「最大いくつのセットを使うか」みたいな指定ができるくらいだ。
割込テーブルを見ると、GPIOTE_IRQHandlerと1つ分しか登録していない。
どうやってるんだろう?

ちなみに、app_gpiote_fast_detect.cという方もあり、こちらはCONFIGを設定している。
引数がchannelになってて、0~3までのようだから、こっちはGPIOTEを使ってる感じがする。
SDKをgrepすると、SPIスレーブがTASKS_OUT[]を使っているので、SPIスレーブを使うとGPIOTE fastは使えない、という制約があるのかもしれん。

じゃあfastじゃない方のGPIOTEはどうやってハンドラが呼ばれているのかというと、これはINTENレジスタによるもののようだ。
Port eventの説明を読むと、ようやくGPIOのDETECT線が出てきた。
つまり、わざわざTaskの設定をしなくても、割込を有効にしておけばDETECT線のアサートによってNVICに通知が来て割り込みハンドラが呼ばれるしくみになっているんだろう。

 

あれ、じゃあGPIOTEユニットを止めたりすると割込が発生しなくなるんだろうか?
そもそも、GPIOTEは有効/無効の設定があるんだろうか?
推測だが、UARTとかの周辺機能にはTaskとしてSTART/STOPがある。
これがユニットへの電源供給制御も兼ねてるんじゃなかろうか。
GPIOTEにはそういうのがないから、常に有効なんだろう。

正規表現は難しいと思うが面白くもある

長年、勉強せんといかんと思っていた正規表現を、最近やり始めた。
だいたい何かツールを作ったりするときはC/C++でやってるのだけど、少なくとも文字列の操作だけが目的だったら別の言語がよいだろうと思っている。
文字列には文字列を、というわけではないが、スクリプトを書いてやろうとしている。

しかしまあ、初心者には正規表現はつらい。
書いているときはまだわかるんだけど、それを後から見直したとき「何がやりたかったんだっけ?」となることがしばしだ。
コメントを書かないとさっぱり思い出せん(記憶力の問題?)。

それと、ツールによって動きが若干違うことがあるのが、困る。
sedで、コンマで区切られた一番最初の部分、という抜き出しをしたかったのだけど、どうやっても最長一致した文字列しか取ってくれなかったのだ。
秀丸でやるとできるのに、sedだとできない・・・・。
さんざん調べると、sedでは最長一致にしかならないよ、という情報を見つけた。
正規表現の書き方が悪いんだと思って、そっちばかり調べていたのだが、ツールによって違いがあるのに気付いたのはそのときだった。

置換結果の末尾に「0」がつき始めたので「これを勝手につけたのは誰だ!」と思った。
しかし、sedでは「$10」みたいなのは2桁は認識してくれないので「$1」に0がついた結果になっていただけだった、とか。

ちなみにやりたかったのは、C言語のプロトタイプ宣言から戻り値と関数名と引数の型をコンマで区切る、だ。
いろんなことができないのはわかっているから、1行で書かれている、とか、仮引数は必ず書かれている、とかの条件ありありにしたんだけど、それでもかなりかかってしまった。
まだツールの選択肢と使える正規表現の数が少ないせいかもしれんが、どうやるのが一番速かったんだろう?

 

ただ、文字列のとらえ方が違う観点からできるようになったのは、よいことだった。
繰り返しが0回以上/1回以上とか、この文字に当てはまる/当てはまらないとか、そういうのをつなぎ合わせて文字列は構成されてるんだなー、という、当たり前といえば当たり前なんだけど、そういうとらえ方。
他の言語もたまにはやってみらんといかんですな。

2015/04/16

[nrf51]PPI、あるいはTaskとEvent

自分の記憶が薄れていくのは、もう仕方が無い。
nRF51822のGPIOTEのことも調べていたのだけど、もう記憶に残っていない。
お仕事だと資料ファイルを作ってまとめるんだけど、家だと実装して満足してしまっているようだ。
つまりまあ、何も残ってない。
これじゃいかんので、とりあえずネットに残しておこう。


nRF51822は、周辺機器機能を"Task"という扱いにしているようだ。
何かの機能を使おうと思ってリファレンスマニュアルのレジスタ仕様を見ると、

  • TASKS
  • EVENTS
  • REGISTERS

の3つに分かれている。
この辺のことは「Peripheral interface」に書かれている。
大ざっぱに言えば、Taskはアプリ→周辺機器への要求、Eventは周辺機器→アプリへの通知、のようだ。

 

Event、という言葉を聞くと、ARMの命令であるWFIとWFEとの関係が気になってくる。
ARM Information Center
ようわからん。。
10.2. WFIとWFE
Iは割り込みハンドラを経由して、Eは経由しない、という違いのようだが、そもそもnRF51822のEventと関係あるかがわからん。
ほとんどSoftDeviceとSDKで吸収しているから、知らなくても何とかなるのだけど、知らずに使うよりは知っていて使いたい。

わかってる、わかってるんだ!
そんな内部のことをせっかく隠してるんだから、もっと違うところに力を入れるべきだというのは。
でも、そういう意味では、私は大きくなれないんだよなぁ。

2015/04/15

実験用の回路図を引いてみる

でん。

image

水魚堂さんの回路図エディタを使って、作ってみようと思っている実験用回路図を引いてみた。
LEDを抵抗器とか無しで接続してるけど、よいのかいな?
保護抵抗とかなんとかいう言葉をよく聞くけど、まあ、壊れてから考えればいいや。
・・・回路図を引く仕事じゃなくてよかった。

 

まだまだ初心者の域を脱しないので、実際にブレッドボードなどでつないだ後で引いたので、間違いがあるかも。
なんというか、単体テストがある程度終わってから詳細設計書を書いているようなもんだから、順番としては入れ替わったことになるだろうが、まあ、ね。
それに、詳細設計書だって実装を少しやって雰囲気をつかんでから書くことだってあるから、悪いもんでもないと思う。
少なくとも、動くはずがない設計書を書くよりはよいはずだ。

私が今までやってきてるお仕事では、開発工程をきっちり進めるのがほとんどだ。
ウォーターフォール型、といえるだろう。
昔は「ウォーターフォール型なんて古いし遅いし、よいことない!」と思ってたんだけど、最近は丸くなったというか、業種が変わったからか、気持ちが変わってきた。

なんというか、身を守る必要があるのよね。
「こういう指示だったから、こう設計した」とか「こういう話だったから、こうした」とか。
エビデンス、ってやつですか。
そこを守ってくれるのが、ドキュメントと議事録くらいしかないのですわ。
あとはもう、言った言わないになるのがわかっているから、必要以上のことは言いたくないし、言われることは文字に全部表してもらう。

でも、設計書書いてると時間が経過して仕様変更がやってきて、それドキュメント反映に時間がかかる、となると先に実装して、ドキュメントは後回しで作業が全部終わり、ドキュメントに回す工数がなくておしまい、とか。
なんだかねぇ。

 

そんなわけで、ドキュメント的なものはほしいのだけど、何かもうちょっと力を入れずに役立つドキュメントが作れないかねぇ。
doxygenで作るようなやつじゃなくて、もうちょっと上の方だ。

そう思うと、回路図って適度に抽象化されてるよなぁ。
抵抗器とかコンデンサみたいなものは見ればわかるし、ICなどは型番があるから仕様書読めばよいし。
だからきっと、ソフトの設計書はハードの設計書を参考にして考えたらいかんのだろう。

以前は、建築工学が一番近いとかで、用語もビルドとか構築とか、そっち系の言葉がよく使われていたと思う。
最近の研究で「実は酔っぱらった親父のくだの巻き方が一番近い!」とかになってたら嫌だなぁ。
でも、開発し始め(飲み始め)は言ってることがまだわかるんだけど、進むにつれて何をやってるのかどんどんわからなくなるし、時に火を噴くし(省略)、終わってしまうと途中経過が残ってなかったりするし。

 

回路図1つ書くだけでここまで考えることになるとは思わんかった。

2015/04/09

[nfc]搬送波はどこへ行った

でん。

image

PaSoRi RC-S370と、左がFeliCa Plug RC-S802、右がFeliCa Link RC-S730。
モジュール全体としてはFeliCa Plugの方が小さいけど、チップ単体ではFeliCa Linkの方が小さいな。

写真はなんとなく撮ってみただけで、意味はない。


今回は何をしたかというと、FeliCa Linkに、電源3.3V、GND、それとLEDを付けて、搬送波が来たときにLEDを点灯させようとしたのだ。
これだけだと、ソフトを書いたりしなくてよいので手軽だ。
だいたい、PaSoRiから5cmのところくらいまでは検知してくれた。
これは「FeliCaを検知した」ではなく、「搬送波を検知した」だけである。
その差は大きい。

 

私が小学生の頃は電池と豆電球で、スイッチで点けたり消したりしてたけど、そのうち豆電球がLEDになって、スイッチがNFCの搬送波になったりするのかも。

そうなると、搬送波をどうやって出すか、というのが問題になる。
PaSoRiがあればよいのだが、FeliCa Linkは家にあってもPaSoRiは置いてないかもしれない。
しかし、そこで断念するのは早い!
NFCの搬送波は、(思っているよりも)けっこう身近にあるのだ。

例えば、nimocaとかSuicaをかざせるようなところは、搬送波が出ている。
JRの改札とかは、いつかざされるかわからないから、搬送波は出っぱなしじゃないだろうか。
お金をチャージするところは、チャージしてほしい人が来るまでは出てない気がする。
(※注意※ 搬送波目的で改札とかを使うのは迷惑になるからやめようね)

自動販売機も、可能性があるな。
ただ、あれも買う商品を決めてからじゃないと読み取る意味が無いので、それまでは出してない気がする。

それらだと外に行かないといけないが、家の中にもある。
NFCに対応した携帯電話だ。
ただ、これは私がよくしらないのだ。
うちにあるAndroidのNexus7、Nexus5はNFCに対応していて、ホーム画面などでは搬送波を出している。
少し古いが、P906iもi-appliでR/Wモードがあるので、搬送波を出しそうだ。

iPhone6は「NFC対応」というよりも、「Apple Payでの支払い対応」のような感じがしている(持ってない)。
ネットに出ていた記事を読む限りでは、ハードウェアとして搬送波を出す機能は持っていないように見える。
まあ、Androidだから搬送波が必ず出るというわけでもないと思うが。


ちなみに「搬送波」というのは、無線をやっているとよく出てくる言葉だ(というのを、無線を少しやって知った)。
英語だと「キャリア(carrier)」と呼んでたけど、Wikipediaでは「carrier wave」で出てきた(って、中にも書いてあった)。
まあ、運ぶ波、と直訳してもよさそうだ。
正直なところ、Wikipediaを読んでもよくわからなかった。。。

私のイメージでは、通信したいデータの周波数は±αみたいな、0を境目に上がり下がりしているデータ、それを空中に伝えるためにエネルギーがいるので、搬送波というエネルギーに載せている、という感じだ。
だから、搬送波が近いもの同士は混線しやすいとか、通信できないとか。

NFCの搬送波は、13.56MHzだ。
WiFiとかBluetoothが2.4GHzくらいだから、そこら辺とは重ならないと思う。
それ以外は、よく知らん。

2015/04/05

[nrf51]デバッグログを出すならapp_trace

以前、nRF51822のUARTについて、こういう記事を書いた。
hiro99ma blog: [nrf51]何故simple_uartは38400bps固定なんだろうか
このときからあったのかどうか知らないが、app_traceというデバッグログ用のAPIがあることに気付いた。
nRF51 SDK - S110 SoftDevice: Debug Logger
これも出力はUARTにするのだが、ENABLE_DEBUG_LOG_SUPPORTマクロを有効にした状態じゃないとビルドされないので、実装する方は気にせずapp_traceを使い、リリースするときはENABLE_DEBUG_LOG_SUPPORT無しでビルドすればよいようだ。

で、このapp_traceだが、速度が115200bpsのようだ。
なんだろうね・・・。

あと、出力はapp_trace_log()で行うけど、これはマクロだ。
printfに置き換えられる。
gccでリンクは通ったんだけど、一体何が呼ばれるんだろうか?
Noteには「KEILだとmicrolibを有効にしてね」とあるけど、どうなっているのか。。。

セミホスティングとかで、gdb側に出力されるって可能性もあるけど、それだったらUARTじゃなくてよいだろう。
ただ、セミホスティングで動きはしたけど使い物にならなかった、という回答があった。
Printing "Hello World" to terminal from some board including nrf51822. - Nordic Developer Zone
UARTでやることにしよう。


gccの場合、makefileはこういうのをリンクしている。
--specs=nano.specs -lc -lnosys

arm-none-eabiをインストールしたところにあるarmv6-mのものがリンクされるようだ(Cortex-M0はv6-mなので)。
printfもそこに入っているのだろう。

さて、arm-none-eabiにあるprintfは、もちろんnRF51822のUARTなど知らない。
これは、_write()や_read()をリンクすることで置き換えられるようになっているみたい。
nRF51 SDKでは、components/libraries/uart/retarget.cに入っているので、これをリンクさせる。

割込で動くかと思ってWFIで待たせたのだが、これでは出力されなかった。
まあ、やり方が悪いのかもしれないが、while()の中に入れ込むと出力されたので、後で考えよう。

ただ、while()の中だと当然出力するスピードよりもループするスピードの方が速いため、バッファが追いつかない。
なので、UARTドライバをapp_uart.cからapp_uart_fifo.c + app_fifo.cにすることで、かなり軽減された。
そんなにログを出すような作りはよくないのだが、デバッグのときしか使わないのに出力する情報を減らしすぎて解析に時間がかかるくらいだったら、多少はメモリをぜいたくに使ってもFIFO側にしといた方が無難か。


この辺の情報は、今回は運良く見つかったからよかったけど、nRF51 SDKの入れ替わりが早いこともあり、ネットでは見つけにくかった。
腰を落ち着けてほしいなぁ。


補足。
app_traceで使うUARTのピンは、boards.h名前のファイルに書いておく。

#define RX_PIN_NUMBER                   (9)
#define TX_PIN_NUMBER                   (8)
#define RTS_PIN_NUMBER                  (-1)
#define CTS_PIN_NUMBER                  (-1)

ピンの番号に特に制約はないと思う。
flow controlを使わないので、RTSとCTSはどうでもよいのだが、構造体のメンバーになっているので何か書かないといかん。
UART_PIN_DISCONNECTEDを使いたいところだが、構造体側がuint8_tなのでwarningになるのだ。

2015/04/04

gdbでCソースが見えないときは、コンパイル後のデバッグオプションを疑おう

nRF51822で、なぜかブレークポイントが設定できなくなった。
以前はできていたので、その時の環境に戻す、という選択もある。
が、今後のことも考えて、「こうやったら直った」を探そうと思う。

まあ、きっちりした解決にはならないかもしれないが、近づくことはできるだろう。


簡単なソースファイルをarm-none-eabi-gccでビルドした場合は、gdbでソースファイルが確認できた。
では、今のnRF51822で使っているMakefileでそのファイルをビルドしてみよう。

 

コマンドラインでビルド&デバッグ

  • ソースファイルはmain99ma.c、その下にmkdir gcc/_buildしておく。
  • cd gcc
  • arm-none-eabi-gcc ../main99ma.c -mcpu=cortex-m0 -mthumb -mabi=aapcs --std=gnu99 -Wall -Werror -mfloat-abi=soft -flto -fno-builtin -ggdb3 -O0 --specs=nano.specs -lc -lnosys -Xlinker -Map=_build/tst.map
    -Wl,--gc-sections -o _build/tst
  • cd ..
  • arm-none-eabi-gdb gcc/_build/tst
  • (gdb) list main99ma.c:main
#include <stdio.h>
int main(void)
{
    printf("Hello.\n");
    return 0;
}

 

これをmakefileに入れ込む。
結果は・・・・・だめだ。No source file named main99ma.cだ。
ふむ、幸先がよい。


コマンドラインでビルドしたときのオプションだが、よく見るとmakefileのものとまだ違いがあった。
同じにしよう。

  • arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mabi=aapcs --std=gnu99 -Wall -Werror -mfloat-abi=s
    oft -flto -fno-builtin -ggdb3 -O0 -c -o _build/main99ma.o ../main99ma.c
  • arm-none-eabi-gcc -Xlinker -Map=_build/tst.map -mthumb -mabi=aapcs -L .. -mcpu=cortex-m0 -Wl,--gc-sections --specs=nano.specs -lc -lnosys _build/main99ma.o -o _build/tst

あれ・・・リンクエラーが出た。libc_nano.aが参照しているsbrkなどが無い、と。
単に2つに分けただけなんだが・・・。
あ、これはリンクするオブジェクトの並べ方がよくない。

  • arm-none-eabi-gcc -Xlinker -Map=_build/tst.map -mthumb -mabi=aapcs -L .. -mcpu=cortex-m0 -Wl,--gc-sections --specs=nano.specs _build/main99ma.o -lc -lnosys  -o _build/tst

これで通った。
確か、並べた順番に処理していくので、大元になるライブラリは最後の方に並べるとか、そんなルールだったと思う。

 

あららららら。
このtstをgdbで読むと「Reading symbols from gcc/_build/tst...(no debugging symbols found)...done.」だと。
1行だとsymbolがあるのに、2行にすると消える・・・?

mapファイルを見比べると、確かに、なさそうだ。
と、いうことは・・・・!


2つに分けた、リンクの方をさらに修正。

  • arm-none-eabi-gcc -ggdb3 -Xlinker -Map=_build/tst.map -mthumb -mabi=aapcs -L .. -mcpu=cortex-m0 -Wl,--gc-sections --specs=nano.specs _build/main99ma.o -lc -lnosys  -o _build/tst

そうすると、できあがったtstにシンボルが入っていて、gdbもちゃんと読めた。
そうか、デバッグオプションっていうと、コンパイルレベルのものしか考えてなかったんだけど、リンクレベルにも影響があるんだ。

nRF51822アプリのmakefileを書き換えて、eclipseでもちゃんとCソースにブレークが貼れることが確認できた。
満足した。


さて、先ほど「リンクの方を」と書いたが、GCCのリンクオプションを見ると、-gは無い。
まあ、-Xlinkerとか-Wlに続けて書いているわけじゃないから、リンクオプションにはなってないんだが。

しかし、修正した方は特にコンパイルを行っているわけでもない。
だから昔の感覚からすると、

プリプロセス→コンパイル→リンク

のリンクになる、と考えてしまう。

ただ、最近のコンパイラはもう1段挟むようになり、gcc4からそうなったという記事をC Magazineで読んだ記憶がある。
だから、それをリンクする工程でも「デバッグオプションは残しておいてくれ」という意味で付けるのだろうか。

Interface誌のコンパイラ特集を読みながら調べようかと思ったが、これはもうちょっと時間に余裕があるときにやろう。
今回の教訓は、「Cソースレベルのデバッグができないときは、コンパイル以降のデバッグオプションを見てみよう」だ。

[nrf51]GDBでCソースデバッグできなくなった

コンパイルはできる、リンクもできる、焼くこともできる、立ち上がって動作することもできている。
なのに、gdbでCソースでバッグができなくなっていたのだ。
以前動いていたのは覚えているのだが、いつそうなったのかがわからない。

症状は、ブレークポイントを設定すると「No source file named xxx.c」みたいなメッセージが出る、だ。
stripされてるわけでもないし、directoryコマンドではパスが通っているし、カレントディレクトリにCソースがある状態でやってるし。
gccのバージョンが関係あるかと思い、とりあえず最新のをインストールしてみたが、同じ。
J-Link Liteも最新版にしたが、同じ。
Eclipseの関連するpluginもupdateしたが、同じ。

じゃあ、arm-none-eabi-gccでやったものがだめなのかというと、そうでもない。
小さなmain.cみたいなのをビルドしてみると、それは大丈夫なのだ。
ということは、少なくともnRF51822のアプリをビルドするという環境で発生することになる。

-gとか、-ggdbとか、-ggdb3とか試したが、同じ。
makefileしかビルドに関係してないので、あれこれ試している最中。

 

初めてnRF51822を使い始めてから、この手のことで行き詰まったことがなかったため、はたと困っている。
まあ、これで解決できれば、またノウハウも増えるというものだ。


gdbでデバッグしても、BLEの通信が始まってしまうとあまり役に立たない。
だから放置したい気もするのだが・・・。

実は、これに気付いたのは、この記事より前に書いていたネタのせいなのだ。
「simple_uartじゃなくて、app_traceを使おう」みたいな感じのネタだ。
app_traceは便利そうなんだけど、printfを呼んでいるところが気になっている。
何がどうなるのかをデバッガで見ながらやっていくか、と試したときに、あれっ、となったのだ。

トラブルシューティングってのは、結局はトラブルに遭わないとシューティングできないわけなので、よい経験と思うことにしよう(まだ終わってないけど)。

[nrf51][v7]configファイルは自分のところに置くべし(たぶん)

nRF51822 + nRF51 SDK v7でI2Cを動かそうとしたときのことだが、SDAやSCLのピンをどこに設定するかがわからなかった。
UARTなんかは初期化時に引数で指定するんだけど、TWIにはそういうのがなくて。

見ていくと、components\drivers_nrf\twi_master\config\twi_master_config.hにピンの記載があった。
が、24ピンと25ピンになってて、これはBVMCNDT52では出ていないピンだった。
しかも、includeパスに入っているわけでもないからコンパイルエラーになるし。
なんじゃこりゃー、と思ったが、ようやく理解した。

このconfigファイルは、カスタマイズするためのひな形なのだ。
自分で使う場合は、そのファイルを手元にコピーして、includeパスが通るようにしておくということになる。
(ファイル名はSDKが提供しているソースが読込むから、変更できない。)

ただ、全部がそうかというと、ちょっと自信がない。
componentsでconfigフォルダを持っているのは、以下だ。
使う時になったら、また調べよう。

  • ble/device_manager
  • drivers_nrf/pstorage
  • drivers_nrf/sdio
  • drivers_nrf/twi_master
  • libraries/hci
  • properitary_rf/gzll
  • serialization/common/transport/ser_phy

[nrf51]SB1602はあっさり動いた

以前購入していたSB1602Bという液晶モジュールを、nRF51822で動かすことにした。
I2C低電圧キャラクタ液晶モジュール(16x2行) - SB1602B - ネット販売

ベースは、以前FM3 + TOPPERSで動かしたときのドライバ。
hiro99ma blog: [fm3]I2Cが動かんのはプルアップ抵抗の値か

これをnRF51 SDKで提供されているI2Cインターフェースで置き換えてやる。


nRF51822では、I2CじゃなくてTWIと呼んでいる。
Two Wire Interfaceの略で「I2C compatible」とまで書いている。
なんでI2Cと名乗らないのだろう?という疑問はあるが、ライセンスとか微妙な規定とか、そんなところにあるのかもしれん。
スレーブは対応しておらず、マスターのみとなる。

リファレンスマニュアルにはいろいろと説明が書いてあるのだが、TWIを使うだけであればSDKのAPI仕様があればよさそうだ。
私は、SDK v7.2.0のS110なので、こちらになる。
nRF51 SDK - S110 SoftDevice: Software controlled TWI Master driver

APIとしては2つしかなく、初期化と転送だけだ。
割り切ってるねー。
まあ、読み書きはアドレス値からわかるから勝手にやるよ、というパターンみたいだ。
libusbの転送と同じ感じ。

SB1602というかST7032iというか、とにかくこの液晶モジュールは書込み方向しかないので、元々APIも1種類しか使っておらず、移植は簡単だった。
そして動かしてみると、あっさり動いた。

image

 

これに気をよくして、FeliCa Linkも動かしてみよう。
こっちはmbed用に作ったライブラリを移植するつもりなんだけど、はてさて。


ロジアナZeroPlusのLAP-Cの使い方をメモで残しておこう。

まず、I2C解析するには、I2Cのバスとして扱うためのチャネル設定がいる。
チャネルのコンテキストメニューか、ツールバーのアイコンで「Channels Setup」を選択。
image

これは設定後の画面だが、やり方は、
 ・「Add Bus/Signal」で新しい行を追加する。
 ・新しい行で、バスとみなしたいチャネルにチェックを付ける。
ここでは、0chと1chをSDAとSCLにしたので、0と1にチェックをしている。
ポート名も変更できるので、気になるならやっておくとよい。
image

そしてまたコンテキストメニューかツールバーから「Bus Property」を選択。
image

こんなダイアログが出てくるので、I2C MODULEを選択。
その後「Parameters Config」を押す。
image

選択したバスに応じた設定画面が出てくる。
私は、SDAとSCLのチャネルを変更しただけだ。
image

I2Cの設定としてはこれだけ。

 

ST7032iの設定では200msec待つところがある。
そのため、普通にロジアナでとっていると、時間が足りない。
そういうときは、データ圧縮してやるとよい。
よくわからんが、Glitchみたいなものか?

image

ツールバーのこれでもよい。
image

2015/04/03

多項式、あるいはCRC計算を理解したい

なんかやってると「多項式」というものに突き当たることがある。
CRCとか。
いつも、適当にネットで調べて、実装だけ持ってくることが多いのだけど、そろそろ理解した方がいいんじゃないか、と思うようになった。
というよりも、多項式、という言葉が出てくるたびに思考停止に陥るのが嫌になっただけだ。



多項式 - Wikipedia
和と積から成るということは、四則演算からできあがる式ってことらしい。

『C言語による最新アルゴリズム事典』
いきなりこの本が出てきたのがなぜかというと、手元に持っている本でアルゴリズムのようなものを説明しているのが唯一これだけだからだ(持っているのは21刷)。
こちらは、私が具体的に知りたい多項式の説明になる。
項目としては「多項式の計算」。

 

理屈は・・・まだ理解できていない。
私は、具体例がないとよくわからんのだ。
本に、CRC16のことが書かれているので、それから読み解こう。
CRC16(CCITT)はこうなるそうだ。

x^16 + x^12 + x^5 + 1

ここで、今までなら「で?」だったのだが、多項式のことを書く記事になったから、調べないといけない。
自分を追い詰めるというのは、こういうことだったのか。

 

元の多項式は、n番目の項の係数に、xのn乗を掛けたものを足していったものらしい。
n番目の係数をc[n]として、べき乗を^で表すと、

c[n] * x^n + c[n-1] * x^(n-1) + ・・・ + c[1] * x + c[0]

だそうだ。
c[z]の部分を、2進数の1とか0とかに置き換え、0を掛けたところを省いたのが、上記の式になるようだ。
c[16]と、c[12]と、c[5]とc[0]が1、つまり、10001000000100001、なのかな?
  1 | 0001 | 0000 | 0010 | 0001
17bitあるやん!
何か間違っているのかと思ったが、本のCRC項目を読むと、CCITTのX.25では0x11021で割るということらしい。
だから、さっきの式は正しい。

ん、割る?

 

2進数で考えよう。

00 / 0 = (;_;)
00 / 1 = 0
01 / 0 = (;_;)
01 / 1 = 1

10 / 01 = 10 ... 00
10 / 10 = 01 ... 00
10 / 11 = 00 ... 10
11 / 01 = 11 ... 00
11 / 10 = 01 ... 01
11 / 11 = 01 ... 00

111 / 100 = 001 ... 011
1111 / 100 = 0011 ... 0011
11111 / 100 = 00111 ... 00011
111111 / 100 = 001111 ... 000011

1111 / 1000 = 0001 ... 0111
11111 / 1000 = 00011 ... 00111
111111 / 1000 = 000111 ... 000111

桁がxの最大な数字を、桁がyの最小の数字で割ると、割った値は(x - y + 1)桁になる。
だから、割る数がy桁なら、どんなにその数字が大きくても、結果が(x - y + 1)桁以上になることはないはず。
取りあえず2進数だけで考えると、そういう法則になる。なるはず。

 

本の説明では、割る数のビット数より1つ小さいビットだけ左シフトしてから割り、その余りがCRCになるとのこと。
割った結果が関係あるだろうと思って法則を見つけていたのだが、余りだとは・・・。
どんなに割られる数のビット数を増やしても、余りが割る数より大きくなることはない。
上記を見ればわかるように、割った余りの最大値はy-1ビットだ。

だから、17bitの値で割ったなら、その余りの最大は16bit。
CRC16は、だから16bitなのだ。


CRCの計算式はいろいろあるが、そこは高速化のためだから、もうよい。
多項式の理解というよりも、CRC計算の桁数の理解だけになったが、なんとなく満足した。

2015/04/02

汎用的に作る時代か

nRF51822で、I2Cを動かそうとしている。
mbedであれこれやったので、そんなに難しいことでもないだろう。

うちにあるI2Cデバイスは、LCDのST7032iが載ったストロベリーリナックスさんで買った、これだ。
I2C低電圧キャラクタ液晶モジュール(16x2行) - SB1602B - ネット販売

そしてもちろん、FeliCa Linkもある。
Sony Japan | FeliCa | 法人のお客様 | 製品情報 | RC-S967・S730

まあ、その2つしか持ってないのだが。


最近、自分の作るコードを、コードの傾向を見て思うのだが、一番その時のサイズが小さくて済むような作り方をしようとしている。
これは、メモリが少ない環境では利点になるのだけど、今のように性能が向上してチップが安価になると、むしろ足かせにしかならない。

例えば、さっき書いたST7032i。
当時はTOPPERS/ASP向けに作ったような気がする。ASPじゃないかもしれないけど、とりあえずTOPPERSへ。
もし、nRF51822でTOPPERSを動かすなら、このまま使えるのかもしれない。
しかし、なんとなくであるが、nRF51822でTOPPERSは雨後かしづらいんじゃないかと思った。

nRF51822は、BLEを動かすためにあるといってもよいと思う。
割込の優先順位も、かなり決められていたと思う。
なんか、SoftDeviceがOSを兼ねているような感じがしたのだ。


うーん、難しいね。