2014/06/30

[ble][nrf51]S110をひもとこう (1)

とりあえず第1回としてみた。

https://www.bluetooth.org/ja-jp/Documents/Shenzhen%20Noridc_BLE%20sensor%20app.pdf

この資料がわかりやすかった。
bluetooth.orgって書いてあるから、本家でのプレゼンテーション資料とかかな?

  • BLEのプロトコルスタック
  • アプリケーションドライバ

この2つがメインかな、と今の感触として思っている。

[ble][nrf51]どこから手を付けようか

nRF51822というチップが手元にある。
デバッガもあるし、開発環境もある。

さて、どこから手を付けようか?

nRF51 SDKという環境と、それに付随してS110というSoftDeviceなるBLEスタックを含んだファームウェアというかミドルウェアというかがある。
私だってなるべく楽をしたいし、安全に使えるものであれば使いたい。


まず、SoftDeviceにはいくつかあるが、nRF51822には「S110」と「S120」が使える。
S110はBLEのperipheral用、S120はBLEのcentral用だ。
BLE_STACK_SUPPORT_REQDって定義を付けてビルドすると、peripheralとして使えるらしい(SoftDevice Handler Library)。

HPの内容をそのまま抜粋。

S110 SoftDevice

The S110 SoftDevice is a Bluetooth® low energy (BLE) Peripheral/Broadcaster protocol stack solution.
It integrates a Bluetooth low energy controller and host, and provides a full and flexible API for building Bluetooth low energy System on Chip (SoC) solutions.

Key Features

  • Bluetooth 4.1 compliant low energy single-mode protocol stack
  • Link layer
  • L2CAP, ATT, and SM protocols
  • GATT, GAP, and L2CAP pぢc  
  • Concurrent Peripheral and Broadcaster roles
  • GATT Client and Server
  • Full SMP support including MITM and OOB pairing
  • Complementary nRF51 SDK including Bluetooth profiles and example applications
  • Master Boot Record for over-the-air device firmware update
  • Memory isolation between application and protocol stack for robustness and security
  • Thread-safe supervisor-call based API
  • Asynchronous, event-driven behavior
  • No RTOS dependency
  • Any RTOS can be used
  • No link-time dependencies
  • Standard ARMR Cortex™-M0 project configuration for application development
  • Support for concurrent and non-concurrent multiprotocol operation
  • Concurrent multiprotocol timeslot API
  • Alternate protocol stack running in application space

nRF51 SDKを補完するものらしい。
ただ、SoftDeviceを使うようにしておくと、いろいろと面倒なことをせずに済む、という記事もあった。

うーん、もう少し絞りたい。
S110について知ればいいのかな?

2014/06/28

[ble]nRF51の省電力はどういうのがあるんだろう?

比較的、小さいものを作ることが多い。
私がハードを作れないので、そういうのは仕事でしかやれないんだけど、だいたい「省電力」が課題になる。
まあ、小さい→電池で動かす→長持ちさせねば!となるのは、当然な流れだ。

基本的な手段は、こんなところ。

  • 動作クロックを落とす
  • 使わない機能ブロックを止める

他にもあるけど、まあこんなところで。
マイコンの資料を見ると、消費電流が出ている。
この機能を使うとこのくらい、みたいなことが書いてあるので、じゃあ使うのをやめよう、とか、使う時間を短くしよう、とか、そういうことを考えるのだ。

では、nRF51822はどうかというと・・・ああっ!
スペックシートも、リファレンスマニュアルも、ユーザ登録が必要じゃないか!
ええい、もどかしい。。。

http://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822

ここにおおざっぱな消費電流が出ている。
送受信がmAオーダーなのに対して、待機中はμAオーダーだ。
これだけでも、送受信する時間を短くすれば消費電流が抑えられることがわかる。

とはいえ、BLEなんだから送受信しないと始まらない。
あるいは、Beacon端末であれば送信しっぱなしでいいのかもしれない。
送信しっぱなし、とはいえ、送信間隔が長くなればなるほど、消費電流は抑えられる。

じゃあ、その間隔を製品の性格に合わせて最大にしたとしよう。
次に待つのは、送信するまでの間をどうするか、だ。
本当に何もしなければ良いのなら、タイマを割込設定して、割込が発生するまで眠らせる、ということもできる。

でも、場合によっては間に受信をしないといけないかもしれない。
その時間がタイマで良いならば、同じようにタイマ割込にしておけば良い。
そうではなくユーザ操作が絡むとかだと、じゃあどうしよう。
いやいや、実は受信が不定期に来るから受信もやらないと、とか・・・。

そういう製品の仕様を考えながら省電力のことをやると、かなり電力を抑えることができる。
できるけど、汎用的なやり方ではなく、かなりOSみたいなことになってくる。
省電力を中心とした仕様設計や実装になる、という感じだろうか。


そういう細々したことをやってるから日本は・・・っていわれるのかもなあ、と思わなくもない。
そんな暇があったら、新しいサービスとかに力を入れろよ、みたいな。
でも、誰かがやらんといかんのよねぇ、とも思う私で、そういう方面が好きなのであった。

[ble][nrf51]センサーをつなげてみる

では、BVMCN5102-BKにセンサーでも付けてみよう。
まずは付けて動かすだけだ。

うちにあるセンサーで動きがわかりやすいのは・・・FeliCa Plugか。
あれも、13.56MHzの搬送波を検出するセンサーと見なせなくもないだろう。

image

それっぽく書いてみたが、意味があるのはFeliCa Plugの/RFDETとP0.21につないだLEDだけ。

#include "nrf_gpio.h"
static void set_gpio(void)
{
    //P0.21にLED接続。
    //HIGHで消灯。LOWで点灯。
    nrf_gpio_cfg_output(21);
    nrf_gpio_pin_write(21, 1);
    //P0.08 : /RFDET
    nrf_gpio_cfg_input(8, NRF_GPIO_PIN_PULLUP);
}
int main(void)
{
    set_gpio();
    while (true)
    {
        nrf_gpio_pin_write(21, nrf_gpio_pin_read(8));
    }
}

 

/RFDETを読み、GPIOに出力しているだけだ。
プルアップにしているので、LEDは1出力で消灯、0出力で点灯になる。
/RFDETも負論理なので、未検出時は1、検出時は0になる。

PaSoRiでFeliCaランチャーを立ち上げておくと定期的にポーリングするので、そのタイミングでLED点滅することを確認。
おめでとう、私!

 

うん、動作に意味はないんだけど、gccのテンプレートからプロジェクトを作ってビルドして動いた、という作業としてはちょうど良かった。
LEDにプルアップ抵抗を付けてたんだけど、大きすぎるのか点灯せず、結局直づけになった。
まずい気はするんだけど、まあいいや。

image

これがPlugじゃなくてLinkの方だったら、読んだIDmを転送、なんてのもできるんだけどね。

[ble]nRF51822のGPIO

nRF51のブロック図を見ると、SPIやらI2C互換やらのシリアル通信ブロックがあるのだけど、ピンアサインを見てもGPIOくらいしか出てない。
どうなっとるんじゃ?


nRF51のリファレンスマニュアル「9. Peripheral interface」を見ると、APBとAHBをtask/event/interruptレジスタで触ることができるって書いてある。

機能ごとに0x1000の固定ブロック=1024レジスタが割り当てられていて、それを使ってAPBにアクセスするようだ。
このブロックがID0~31ある。これをPeripheral IDと呼んでいる。
メモリマップではAPB peripheralsって書いてあるところだな。
Table 3にPeripheral instantiationという表があり、IDと機能の対応が見て取れる。

 

Tasksは、機能に働きかけるトリガ。「開始せよ」みたいな。
Eventsは、機能の変化通知。「状態が変わった」みたいな。
Shortcutsは、taskとeventの接続。接続・・・? eventが発生するとtaskが自動的にたたかれるらしい。
Interruptsは、CPU例外処理の、いわゆる割込。

え、これで説明終わり?
どうやってGPIOの割り当てを変更したりするの?


しょうがない、SPIの説明を読んでみるか。

ふむふむ、PSELSCK / PSELMOSI / PSELMISOのレジスタがあり、それにピン番号を書き込むようだ。
動的に変更できるってことですか。。。まさにGeneral Purpose。

しかし、ソフト的に変更できるっていうことは、多少の遅延が発生するのかな?
まあ私が作るようなソフトだったら影響はないだろうけど。

 

サンプルソースも見てみた。
SDKにレジスタを初期化するソースまで入っているので、全部書かなくてもよいみたいだ。
まあ、自分で書いた方がサイズは小さくなるかもしれんがね。

ちょっと嫌なのは、引数で初期値を渡すのではなく、"spi_master_config.h"というファイルに決められたマクロでピン番号などを書いておかないといかんところか。
まあ、メモリも少ないことだし、引数渡しなんかするよりは直接埋め込んだ方がよいってことなのかな。

[ble]BVMCN5102-BKにビルドして焼く

まだnRF51822自体がよくわかってないので、サンプルを焼くだけだ。

まず、Nordicのユーザ登録をしよう。
http://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822

image

Registerをクリックした先で、いくつか入力して登録。
メールが来たりして登録が完了したら、ログイン。

左側に「MY KEYS」があるので、クリック。

image

ここで、BVMCN5102-BKを購入したときに入っていた紙に書いてあるプロダクトキーを打ち込んでADD。
そうすることで、ダウンロード保護されていた開発環境などがダウンロードできるようになる。
今の私は、これがダウンロードできるようになった(スペックシートなどは保護されてない)。

image

とりあえず、全部ダウンロードしてから考えることにした。

image

nANはアプリケーションノートのPDF。RMはリファレンスマニュアル。PSはスペックシート。
nRF-MCPはMaster Control Panelなんだけど、いるかどうかわからん。
この中でインストールがいると思うのは、これらか。

  • nRFgo Studio
  • S110-SD-v?(今は6.0.0が最新なので、v6にした)
  • nRF518-SDK

SDKは統合開発環境とかじゃなくて、ヘッダやサンプルソースのような、純粋の開発環境。
nRFgo Studioは、焼かれているSoftDeviceの確認や、焼き換えに使う。


次は、デバッガの準備。
SEGGER社のJ-Link LITE CortexMが付属しているので、そのドライバをインストールする。

上記サイトに行くと、左側にDownloadsがあるので、クリック。
Productでコンボボックスから「J-Link LITE CortexM」を選択。
ドライバのダウンロードっぽいリンクが出てくるので、クリック。
そうすると、J-Link downloadsに飛ぶ。画像はLITEのじゃないけど、問題なさそう(J-Linkって黄色かと思ってた)。
今回はWindows環境なので、Windows用をダウンロード。
そうすると、シリアル番号の入力を求められる。
シリアル番号は、J-Linkのチップの上に書いてある。下画像の赤いところだ。

image

打ち込むとダウンロードできるので、ダウンロードして展開してインストール。
なお、このシリアル番号は接続の時にも使う。


BVMCN5102とJ-Link LITEはこんな接続になる。
ピンの穴が埋まっているのだが、逆にすると差し込めてしまうので注意だ。
ケーブルに油性マジックで3本の線が引かれている方がJ-Link側だと思う。

image

が、もう少し待とう。
まだクロスコンパイラが入っていないのだ。

今回は、gcc + eclipseを使う。
通常のARM開発と一緒のようなので、使い慣れた環境があるならそれでもよさそうだ。
私はあまり考えたくなかったので、NordicのアプリケーションノートnAN29に従うことにした。
「nRF51 Development with GCC and Eclipse」がそのタイトルだ。

では、順番にやっていこう。

1. Required tools

  • nRF51 SDKのインストール
  • GNU Tools for ARM Embedded Processorsのインストール
    • v4.7 2013q1と指定されてるけど、めんどうだったので右側から安定版っぽいのを探した
      • バージョンが上がって、warningがデフォルトでエラー扱いになってうっとうしいかも
    • CodeSourceryのとは、また別なの?
    • Makefile.windowsの編集
  • Core Utilityのインストール
  • Makeのインストール
    • cygwin入ってるけど、もういわれるがままにインストールした
  • J-Link
    • これは、さっき入れたやつ
  • eclipse
    • JunoのC/C++とあるけど、Android SDKがあったのでそれを使った。
      • 分けた方が良かったか・・・。
        • よし、せっかくなのでLunaでやり直そう!

 

1.1. Setting up Eclipse

  • CDTのMain FeatureとGDB Hardware Debuggingにチェックを入れてインストール
  • http://embsysregview.sourceforge.net/updateをインストール
    • これでレジスタ値が見やすくなる
  • eclipseのpluginsの中にembsysregviewがあるので、その中にnRF51 SDKに入っているnRF51.xmlをコピー
    • うちの環境だと、こんな感じ
      C:\Winappli\eclipse-cdt\plugins\org.eclipse.cdt.embsysregview.data_0.2.4.r168\data\cortex-m0\Nordic

 

1.2. Import existing Eclipse project to Workspace

  • ここら辺をImportする。
    C:\Nordic Semiconductor\nRF51 SDK_v5.2.0.39364\Nordic\nrf51822\Board\nrf6310\s110\ble_app_hrs

 

2. Setting up a project for debugging in Eclipse

  • 書いてある通りにやる。
  • SEGGER J-Link GDB Serverを立ち上げる
    image
    image
  • BVMCN51に電源供給してなかったら、少しすると上ダイアログが消えるので、USBで電源供給してから起動すること。
  • このダイアログが出た状態でeclipseのDebugを開始させると、ビルドし直して、焼いて、main()の先頭で止まってくれる。
    • 毎回cleanしてビルドされるので、ちょっとうっとうしいかも・・・。
      • まあ、書き換えればいいんだけどね。
  • あとは、走らせるなりなんなり・・・。

と行きたいところだが、サンプルそのままではたぶん動作しない。


理由は前の方のブログ記事を見てほしいが、BVMCN5102は素のままでは32Kの外部クロックがない。
で、サンプルは外部がある前提で書かれている。
内蔵32Kがあるんだから、そっち前提にしてほしいような・・・。

ぶつぶつ言っていても仕方ないので、サンプルを修正する。

その前に、STATIC_ASSERTの解決をしよう。
Include/app_common/app_util.hにSTATIC_ASSERTマクロの定義があるのだが、gccのバージョンが新しいとエラー扱いになってしまうのだ。
https://devzone.nordicsemi.com/question/4192/static_assert-and-gcc-instead-of-keil/

#define STATIC_ASSERT(EXPR) typedef char static_assert_failed[(EXPR) ? 1 : -1] __attribute__((unused))

 

そして本題の32Kクロック。

main.cのble_stack_init()を書き換え。

元:
SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);

変更後:
SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION, false);

4000MSじゃなくてもいいけど、とにかくRC_250_PPMを選ぶ。

これをやっても動かないなら、SoftDeviceのバージョン違いを疑ってnRFgo Studioを使って焼き直そう。
動くと、こんな感じのパケットが吐き出される。

image

[ble]BVMCN5102-BKを接続する

Amazonで購入したBVMCN5102-BK KIT PLUSには、以下が付属していた。

  • (BVMCN5102-BK + 14pin x 2セット + DIP-SW) x 2セット
  • J-Link LITE CortexMとケーブル
  • BVMCN5102-BKのパターン図?
  • BVMCNDT52、SEGGER、USBの回路図

 

image

これは半田付け後の写真だ。
付けるのは、ムカデみたいなピンと、DIP-SWだけなので簡単。
ただ、DIP-SWのしたにはジャンパピンが半田付けできそうなところもあり、HPの写真ではなぜかそこも半田で埋まっていたので、実は何かするべきなのでは・・・と悩んだ。
テスターで計測し、SWだけで問題なかったので、それは忘れることにした。

 

image

SEGGERと接続すると、こんな感じ。
MicroUSBは、PCとの接続はないので、ACアダプタと接続することにした。
上がSEGGERというか、J-Link LITE CortexM。

 

ソフト的な環境は、ドキュメント通りだ。
nRFgo Studioは、最初にインストールすべきものだ・・・私の反省から。
組み込み技術者たるもの、すべてを疑ってかかるべきなのだ。
ああ、刑事の寂しい性だとは思いつつもな。

eclipse + gccでのことについては、また明日以降。

2014/06/27

[ble]nRF51822の勉強を始めよう

うちには、BLEものが3つある。
1つ目は、PaSoRi RC-S390
SDKが一般公開されていないので、使いようがない。
うう、残念・・・。
2つ目は、TIのSensorTag
こいつでばりばり遊ぶぜ!と思ってたんだけど・・・開発環境がお高い。
趣味でやるお値段じゃなかったわ・・・。
でもこれと、BLEスニファを一緒に買ったので、いろいろと調査に役立っている。
でもでも、やっぱり自分で動かさないと、わからないよなあ。
ということで3つ目に買ったのが、BraveridgeのBVMCN5102-BK KIT PLUS
転職先を探していて、ちょうど見つけて買ったというものだ。
(転職エージェントから、あんたは年齢層が高いから紹介をやめとくっていわれた(T_T) )

いかん、テンションが下がってしまったが、続けよう・・・。
この評価ボードは、GPIOもほどほどにあるが、Analog INも多い。
しかし・・・あまり初心者には親切じゃあない。
回路図がちょっと読みづらい・・・。
JP1, 2とあるけど、それが基板のどこになるかが書いてないので、テスターで確認したし。
それよりも、電源が不安だった。
MicroUSBのポートと、SEGGERのポートがある。
USBからはVout、SEGGERはVdd。
私はどちらも電源だろうと思い、USBを使わずにいたのだが、SEGGERに「ターゲットが見つからない」といわれる・・・。

えーーい、この基板を使っている人がどんだけいるかわからないけど、わかったことを書いていってやる!
と、SonyのRC-S620/Sを買ったときと同じような衝動を覚えた私であった。

2014/06/25

[ble]nRF51822評価環境の個人まとめ

サンプルソースが動いたので、これからちゃんと見ていくことにしよう。
まずは、自分が使おうとしている環境がどういうものか、まとめておく。


買ったもの

BLE開発キット with J-Link segger (amazon)

 

評価基板

BVMCNDT52

  • nRF51822搭載
  • 外部16MHzクロック / 内蔵32.768KHzクロック(外部32K用のピンもある)
  • SoftDevice書き込み済み(だが、バージョンが仕様書と違うような・・・)
  • BLEが使えるように実装されている以外は、ほぼ素のnRF51822っぽい。
  • nRF58122の開発環境をするためのプロダクトキー付き

 

デバッガ

SEGGER J-Link LITE Cortex

  • JTAGデバッガみたいなもの。SWDっていう接続方法らしい。
  • デバッガのチップにシリアル番号が書いてあり、それを入力しないとドライバなどがダウンロードできない。

 


開発環境を作るのに手間取った。
記憶が薄れかかっているので、メモ程度に。

  • Nordic社のアカウントを作る。ここの右上に「Register」とあるので、そこからできる。
  • ログインするとMy Pageに入れるので、My Keysに行く。
  • プロダクトキーを入力する。
  • そうすると、いろいろダウンロードできるようになる。

ここで、何をインストールすれば良いかだが・・・とりあえず全部入れてみようって感じでやってしまった。
思うに、以下があればよいと思う。

  • nRF51 SDK
  • nRFgo Studio
  • S110-SDのどれか

nRF51 SDKでは、ヘッダとソースとサンプルソースがインストールされる。
このヘッダの中に、S110-SD(SoftDevice)に対応したインクルードファイルがあるのだが、おそらく最新の安定版が入っているようだ。
使うnRF51822にどういうSoftDeviceが入っているかは、nRFgo Studioで確認できる。
SDKと一致してなかったら、S110-SDに入っているインクルードファイルを入れ替えるか、同じく入っているHEXファイルを焼いてしまうかだろう。
前回の私は、焼きかえることで対応した。

 

nRFgo Studioのインストール時に、もしかしたらJ-Linkのドライバもインストールされたかも。
私はnRFgo Studioをインストールしてなかったので、自分でダウンロードした。

nRF51822にはCortex-M0が入っているので、開発環境はARMのものが使えそうだ。
私は、Nordicのドキュメントを見ながら、gcc+eclipse環境を作った。
gccはドキュメントに書いてあるバージョンじゃなくて最新のを使ったから、それに関する変更は行ったけど、それくらいでほぼPDFそのままできた気がする。
そこに書いてあった、hrsサンプルがようやく動いたのが、昨日だ。


次は、hrsサンプルをいじくって、自分で動かしてみるというところかな。
BLEよりも、まずはボードを動かしてみるというのが先だ。

[ble]意外ッ! それはバージョン違い!

コメントをいただき、やはり内蔵クロックがうまく出てないのじゃないかという気になってきた。

では、まずなんでマクロが終わらないかを見ていこう。
SOFTDEVICE_HANDLER_INITで止まっている理由を見るのだ。

 

image

 

この範囲をぐるぐる回っていた。
- r1 : 0x4000_0100
- r3 : 0x0000_0000

イベント待ち
0x4000_0104の値をr3にロード
r3が0かどうか比較
0だったら、戻る

0x4000_0104は、LFCLKSTARTEDだ。
それが0以外、つまり開始したらループを抜ける。
値が0なので、ぐるぐる回っている。

でもね・・・

image

LFCLKSTATのSTATEはRUNNINGなのよねぇ。
うーん・・・アセンブラレベルで追っていくか・・・。

あ、

image

ぐるぐる回る前に、32Kが外部クロックに指定されてる!
でも、sd_softdevice_enable()呼ぶまでは設定されてなかったし、sd_softdevice_enable()から抜けてないとなると、この中で設定されたことになる。

第Ⅰ引数は10進数で13。enumの順番とは一致している。
うーん・・・・?

今回私が使っているのは、SoftDevice6.0.0が焼かれている、と書いてあった。
6.0.0のenumは、こんな並び。

/**@brief Possible lfclk oscillator sources. */
enum NRF_CLOCK_LFCLKSRCS
{
  NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM,                       /**< LFCLK Synthesized from HFCLK.                    */
  NRF_CLOCK_LFCLKSRC_XTAL_500_PPM,                        /**< LFCLK crystal oscillator 500 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_250_PPM,                        /**< LFCLK crystal oscillator 250 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_150_PPM,                        /**< LFCLK crystal oscillator 150 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_100_PPM,                        /**< LFCLK crystal oscillator 100 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_75_PPM,                         /**< LFCLK crystal oscillator 75 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_50_PPM,                         /**< LFCLK crystal oscillator 50 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_30_PPM,                         /**< LFCLK crystal oscillator 30 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,                         /**< LFCLK crystal oscillator 20 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION,        /**< LFCLK RC oscillator, 250ms  calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_500MS_CALIBRATION,        /**< LFCLK RC oscillator, 500ms  calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_1000MS_CALIBRATION,       /**< LFCLK RC oscillator, 1000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_2000MS_CALIBRATION,       /**< LFCLK RC oscillator, 2000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION,       /**< LFCLK RC oscillator, 4000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_8000MS_CALIBRATION,       /**< LFCLK RC oscillator, 8000ms calibration interval.*/
};

その1つ前、5.2.1は、こんな並び。

/**@brief Possible lfclk oscillator sources. */
enum NRF_CLOCK_LFCLKSRCS
{
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_500MS_CALIBRATION,  /**< LFCLK RC oscillator, 500ms  calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_1000MS_CALIBRATION, /**< LFCLK RC oscillator, 1000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_2000MS_CALIBRATION, /**< LFCLK RC oscillator, 2000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION, /**< LFCLK RC oscillator, 4000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_RC_250_PPM_8000MS_CALIBRATION, /**< LFCLK RC oscillator, 8000ms calibration interval.*/
  NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM,                 /**< LFCLK Synthesized from HFCLK.                    */
  NRF_CLOCK_LFCLKSRC_XTAL_500_PPM,                  /**< LFCLK crystal oscillator 500 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_250_PPM,                  /**< LFCLK crystal oscillator 250 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_150_PPM,                  /**< LFCLK crystal oscillator 150 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_100_PPM,                  /**< LFCLK crystal oscillator 100 PPM accuracy.       */
  NRF_CLOCK_LFCLKSRC_XTAL_75_PPM,                   /**< LFCLK crystal oscillator 75 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_50_PPM,                   /**< LFCLK crystal oscillator 50 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_30_PPM,                   /**< LFCLK crystal oscillator 30 PPM accuracy.        */
  NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,                   /**< LFCLK crystal oscillator 20 PPM accuracy.        */
};

赤文字は、13番目。
もしかして・・・6.0.0じゃなくて、5.2.1が焼かれているのでは?

nRFgo Studioをインストールしてみてみると・・・当たり!
バージョン違いだったー--

そりゃ動かんですな。
細かいことはわからんけど、サンプルのHeartRateも動いて、以前買ったスニファにも出てきた。

 

ふいー、ようやく地面に降りたった、というところだ。

2014/06/24

[ble]SD_SOFTDEVICE_ENABLEの解釈が間違ってた

まだnRF51822でSoftDeviceの初期化がうまくいっていない。
うーむ。。。

とりあえず、コメントの解釈を間違っていたことだけはわかったので、メモ。
解決にはならないんだけどね。

* @note Some care must be taken if a low frequency clock source is already running when calling this function:
*       If the LF clock has a different source then the one currently running, it will be stopped. Then, the new
*       clock source will be started.

「先にLFCLKを動かしてないといかん」と思っていたが「先に動かしていた場合は以下を気をつけろ」だった。
ってことは、動かさなくていいんだ。
そして、それは最初と同じ話に戻るということで、結局はここで固まっているという・・・。

うーん、HFCLKは外部CLKで動作させ、LFCLKは止めたままで呼んでみるか。。

[ble]nRF51822にはTasksというレジスタがある

nRF51なのかCortex-M0なのかわからないけど、周辺機器をたたくためのレジスタがある。

昨日でいえば、LFCLKをたたくために、NRF_CLOCK->TASKS_LFCLKSTART、というレジスタが用意されていた。
昨日は、ここにLFCLKSRCと同じ値を突っ込んでいたのだ。
なんかよくわからないけど、ドキュメントをそう読んでしまってたのだな。

今日、CLOCKのドキュメントを読み返していて気付いたのだが、そこのレジスタ一覧にはTaskレジスタの説明がなかった。
Peripheralのページを見てわかったのだが、Taskレジスタには"1"を書き込むものらしい。
ちなみに、私が選択したLFCLKは内蔵RCで、そのLFCLKSRCへの書き込み値は0・・・。
そりゃ、クロックも立ち上がらんってものだ。

"1"をNRF_CLOCK->TASKS_LFCLKSTARTに書き込むと、イベントが発生した。
なーんだ・・・。

ささいなことでも、気付かないとまったくわからないのが、この辺なんだなぁ。


気をよくした私は、SOFTDEVICE_HANDLER_INIT()を呼び出した。
こんな感じで。

SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION, false);

しかし・・・sd_softdevice_enable()から返ってこない。
うわー。。。。

マクロの説明からすると、LFCLKSRCが引数と異なっていた場合は、今のLFCLKを止めて、新しく開始させる、という動作すらするのだ。
じゃあ、私がLFCLKを動かそうとしていたこと自体・・・無駄だったか・・・。

いや、無駄はいいのだ。
それよりも、なぜ最初の実装で動かなかったのか、なぜ今の実装でも動かないのか。。。
動いてもよさそうなんだけどなぁ。

2014/06/23

[ble]LFCLKが立ち上がらん

NordicのnRF51822が載った評価ボードを買った。
とりあえず動かしてみようとしているのだが、LFCLKSRCにRCやSynthを設定しても、LFCLKSTARTEDが発生しない。
うーむ。

これが立ち上がらないと、SOFTDEVICE_HANDLER_INIT()が設定できないので、BLEスタックが動かせない。
外部に32.768kHzのXTALを載せて試してみればいいのかもしれないが、手元にない。
HFCLKは立ち上がったので、同じようにいけると思ったのだが・・・・。
Cortex-M0が載っているようだが、ちゃんとチップの動かし方を最初から読まねばならぬか・・・。

 

久々に、こういう組込みっぽいことをやってわかったけど、やっぱりこういう作業が好きなんですな、私は。

2014/06/22

[felica]外部認証がうまくいかん

FeliCa Lite-Sの内部認証はうまくいくのだが、外部認証がうまくいかん。

Write without Encryptionで、ステータスレジスタ1=0x02、ステータスレジスタ2=0xB2になる。
ユーザーズマニュアルで確認すると、この段階でエラーになる要因は4つ。

  • RCブロックの書き込み無し
  • MAC不一致
  • WCNT不一致
  • 書き込み回数エラー

Lite-Sからは2ブロック同時書き込みが可能になっているが、2ブロック目はMAC_Aのみとなっている(ドキュメントはSTATEって書いてあるけど間違いだな)。

さて、何が悪いんだろう?

RCの書き込みは、内部認証の時にやってるから、大丈夫だろう。
WCNTは、読んだ値をそのままなので、よいはず。

ということは、やはりMACの計算が合ってないのか。
SK1とSK2が読み出しの時と逆、というくらいしか意識しなくてよさそうなんだけど。

気になっているのは、1次発行してないときに外部認証できるのか?ということ。
WCNTレジスタの説明で、「工場出荷時はFFFE00」「FFFE00に達した後はMACつき書き込みができない」と書いてあるからだ。
せめて、MC_STATE_W_MAC_Aを0x01にして、書き込みにMAC必要とするべきなのか?

試してみたいけど、MCレジスタは書き込むと元に戻せないので、もうちょっと確証がほしいところだ。


ついでだが、4.2.2にも誤記あり。
MAC_Aの読み出しってなってるが、値がMACレジスタ(0x81)になってる。

2014/06/21

[felica]相互認証(2) - 外部認証

さっき気付いたが、FeliCa Lite-Sのドキュメントが新しくなっていた。
といっても、2012年のことだから、ずいぶん前のことではあるが。。。
更新通知来てたかなぁ。
せめて、せめて改訂した内容が書かれていればいいのに・・・。

ただ、新しいドキュメントは評価しよう!
というのも、PDFのデフォルトが変更になったからだ。
スターターマニュアルなんかは今もそうなんだけど、しおりでジャンプするとドキュメント全体が収まるような倍率に変更されてしまう。それがかなりストレスになっていたのだ。
おそらく設定が「自動」か何かになったのかな。

それはともかく。
FeliCa Lite-Sの最大の売りとも思われる相互認証。
その中心は、外部認証にある。
内部認証によってR/Wがカードを認証した後で、カード側にR/Wを認証してもらう感じだ。
必要条件と、十分条件のそれぞれを満たすから、必要十分条件になる、というイメージだと思う。


外部認証

資料から読み取ったシーケンスを以下に置くが、ドキュメントが足りてない気がする。
とりあえず、スターターマニュアルの相互認証で、10番と11番がドキュメントになっていない。

そのせいかどうかわからないが、相互認証に失敗した場合の記述が見つけられていない。
それでもあえて、あえてそこから読み取った姿を見せよう。

image

外部認証の部分は、わずかだ。
MAC_A(Write)の計算をして、書き込むだけ。
その結果は、たぶんSTATEレジスタに反映されるのだろうけど、先に書き込むのがこちらなので、もしかしたらWrite without Encryptionが失敗するのかもしれない。
そういう情報が不足しているのだな。


もし、STATE[0]が0x01にならないのであれば、この後にSTATEレジスタを確認するという作業がいる。
もしSTATEレジスタへの書き込み自体が失敗するのであれば、このシーケンスで良い。

というわけで、後者じゃないのかと思うんだけど、どうだろうね。

[felica]相互認証(1) - 内部認証

FeliCa Lite-Sの最大の売り、相互認証。
それを実現するために、内部認証と外部認証を行う。


内部認証

これは、従来のFeliCa Liteにもあった「片側認証」である。
片側認証については、いくつか書いてきた。

リーダライタから上位が、「このカードは自分が発行したものだ」と認証するしくみ。
偽造カードじゃないことを確認するしくみ、といえばよいか。

さて、FeliCa Lite-SになってMAC_Aというレジスタが追加されたが、「MACまたはMAC_Aを使います」ということなので、どちらのレジスタでも同じことができるようだ。

ただ、MACとMAC_Aでは計算方法が異なるそうだ。
以前作った片側認証アプリのレジスタ名だけ変更してみたが、MACの値が一致しなかった。
(前ブログで、MAC_Aが読み込み失敗した、という現象は発生せず。IDブロックと一緒に読み込んだからか。)

違いは、ブロックデータの3DES暗号化でのIVが、RC1なのか、RC1をさらに3DES暗号化したものかどうかだけのようだ。
RC1の3DES暗号化に使うIVが、何か良くわからない(資料の通りにやれば良いのだろうが)。

なんか、暗号化の知識がないから書いてある通りにやっているけど、知っている人からすると関数一発で終わる、みたいなものではないんだろうか、と変な心配をしている。

2-1 基本

 

スターターマニュアルには、MAC_Aと一緒にID, CKV, WCNTを読み出すように書いているが、ユーザーズマニュアルではIDとWCNTになっている。
最低限、IDとWCNTは必要だからってことでいいのかな?

[felica]FeliCa Lite-Sカードを読んでみる

では、さっそくFeliCa Lite-Sカードを読んでみよう。

コマンドとしては、以前と同じく3つをサポートしている。

  • Polling
  • Read without Encryption
  • Write without Encryption

 

では、まずPollingから。
と行きたいところだが、手元にSDK for NFC Starter Kitしかないので、明確に「このコマンドを動かした」という確認ができない。
まずはStarter Kitで作っていたツールを使って、新しく増えたブロックを読むことにする。


WCNT

4B-FE-FF-00-00-00-00-00-00-00-00-00-00-00-00-00

WCNTはライトカウンタ値が入っている。
先頭3byteが有効でエンディアンはリトル。ReadOnly。
デフォルト値は「00 FE FF」だそうなんだけど・・・・???

どういうタイミングでカウントされる勝とうと、S_PAD0~13、REG、ID、SER_C、CKV、CK、MC、STATEブロックへの書き込みでインクリメントとのこと。

デフォルト値、というのは0次発行のときらしいが、出荷試験などで書き込んだと言うことかな?
次は、MC=0x00を書き込んだとき、つまりシステムブロックの書き込み禁止をしたときに、カウント値が0になる。
それ以降はリセットできない。

WCNTが0xfffe00になると、MACつき書き込みができなくなる。
えっ、と思ったが、回数としては16,776,704。1677万回だ。毎秒書き込んだとしても194日かかる。
達する前にWrite withoute Encryptionでエラーになるかもね。

 

MAC_A

エラー

ReadOnlyではないらしいのだが、エラーになった。
なんだろう?
MACブロックと同時に読み込んではいけないとはあるんだけど・・・。
えーっと、ステータスフラグ2が0xB2ってことで「MAC_Aブロック読み出し時にRCブロックへの書き込みがない」と。

では、とりあえずRCブロックに適当な値を書き込んでから・・・同じく0xB2になった。
なんだなんだ?

 

STATE

00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00

意味を持つのは、0番目と8番目。

[0]EXT_AUTH
認証前か後か。
まだやってないけど、新しく追加された認証(片側認証じゃない方)の前か後かだろうかね。

[8]POLL_DIS
Pollingに応答するかどうか。
へー、そんな機能があるんだ。

で、これはReadOnlyではなく、R/Wとのこと。
起動時はどちらも0(認証前、Polling応答する)になるらしいから、Polling未応答にしたまま忘れるという心配はしなくてよさそうだ。

POLL_DISは、他にカードがあるかどうかのチェックに使えるそうだ。
複数あるときは、対象以外を応答しないようにするのか?と思ったが、POLL_DISが設定できるということは捕捉したということになるので、意味がないか。 
テクニカルノートには「複数枚のカードがかざされていた場合に1枚のカードを特定するための手段の1つ」とある。
うーむ。

Pollingして応答が返ってきている時点で、カードは捕捉できてると思う。
おそらく、R/Wは最初に返ってきた応答の結果を渡していると思う。
複数枚のカードがあって、異なるタイムスロットで応答を返した場合は、無視された形になる。
しかし、最初に返ってきたカードに対してPOLL_DISすると、次にPollingしたときには別のカードが応答を返すことになる、という考え方で良いのかな。

PaSoRiで複数枚カードはきついような気はするが、試してみたいところではあるな。

 

CRC_CHECK

00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00

0番目だけ有効。
0x00はCRC一致、0xFFはCRC不一致。

これは不正アクセスというよりは、衝撃によるデータ破壊なんかを検出する目的なのかな。


なお、FeliCa Liteで上記レジスタを読もうとしても、ブロックが存在しないのでエラーになる。
LiteとLite-Sの見分けは、とりあえずそれでつければよいのかな。

2014/06/20

[felica]FeliCa Lite-S来たる!

BLEがんばる、といった矢先、FeliCa Lite-Sカードが届いた。

私「ご、ごめん・・・」
BLE「ううん、いいのよ」

と言ったか言わないかはわからないけど、初めて見るNFCタグが来た以上、調査しないわけにはいかない。


カタログから

まずは、カタログでのスペック違いを見ていこう。
まあ、商品ページを見るとだいたいわかるんだけど。
http://www.sony.co.jp/Products/felica/business/products/RC-S966.html

使用許諾を認めれば、差分ドキュメントもある。
そっちの方がわかりよいか。
http://www.sony.co.jp/Products/felica/business/tech-support/index.html#Lite05S

 

とりあえず覚えておかないといけないのは、上位互換であること。
上位互換という言葉でいいのかわからんが、今までのFeliCa Liteカードとの完全互換があるというのは知っておいた方がよいだろう。
その上で、機能が追加されているのだ。
これを入手できるまで、2年くらいかかった、ということだな。

 

相互認証!

今までのFeliCa Liteは、「片側認証」という認証があった。
何が「片側」かというと、カードリーダ含むカード発行側はFeliCa Liteに対して認証することができる(自分が発行したカードかどうか確認できる)のだけど、FeliCa Lite自身はアクセスされることに対するガードができない。
FeliCa Standardになると相互認証ができるので、「認証がしっかり必要なものはStandardだよねー」という立ち位置だった。

それが、だ。
FeliCa Lite-Sでは相互認証ができるようになったのだ!
やり方はStandardとは違うし、めんどくさそうな感じもするのだが、できないのとできるのとでは雲泥の差がある。
私の調査も、相互認証のやり方を調べることから始めるだろう。

 

その他

私にとっては、それ以外の部分はあまり興味がない。
まあ、212Kbps/424Kbpsの両方に対応したので、もう少し高速化できるかも、というところか。


さて、ついでにIDmのことも書いておこう。
別にこれは、Lite-Sだけのことではないと思う。

FeliCa Standardは、発行側がIDmを決められるらしい。
FeliCa Lite/Lite-Sは、出荷時にIDmが決められているらしい。

この違いが私にはあまりわかっていないのだけれども・・・。
とりあえず、発行されたカードの中では、というところに絞れば、IDmはユニークである。

絞らなければ・・・だと?
IDmってのはなあ、お嬢ちゃん、単なる数字なんだよ、8byteの。
Tg系のコマンド仕様とか見てみるとわかるけど、IDmなんて適当だ。
ソフトで指定することだってできる。

だから、だ。
だからLite-Sのように相互認証するカードを待ち望んでいたのだ。
今まで、LiteとStandardの間が大きすぎたのだ。
データの保持だけなら、NFC-Aの安いやつでも偽造しづらい(Tg系のコマンドは、NFC-AのIDが一番小さい4byteのものでも、ソフトとしては3byteまでしか指定できないので、少なくとも私レベルでは偽装できない。
7byteのNFCIDだったら、もう何もできないのかもね。

 

そんなわけで、どっちかというとIDmをソフトレベルで全部指定できるというコマンド仕様を変更した方が良いように思うのだが・・・。

2014/06/19

[ble]nRF51822というチップ

2回のRejectに心を痛めた私は、逃避行動を取ることにした。

BLEを勉強し直そう。
スイッチサイエンスさんからFeSCa(FeliCa Lite-S)が発売されているので気にはなるが、それは注文したものが来るまで待とう。
近距離通信として、BLEはまだ学び始めにすぎない。
もう少し、ちゃんとやらないと。


そんなわけで、注文していたBLE開発キットが今日届いた。
Nordic社のnRF51822というチップが載っている。

https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822

nRF51822は、BLEが使えるSoCらしい。
SoC・・・System on Chip、か。
わかるようなわからんような。マイコンとデバイスが一緒になってる、みたいなものか?

この子、ARM Cortex-M0 32bitが載っているそうだ。
こ、こんなに小さいのに・・・。
Cortex-M3のFM3が比較的大きかったので、ちょっと驚きだ。
M0も少しは知らないといかんな。

メモリは、256KB or 128KBのプログラム用FLASHと、16KBのRAM。
そうか・・・16KBもあるのか・・・。まあ、32bitマイコンだから、それなりにないと苦しいのだろうが。

あとは、

  • 温度センサ(センサ目的? マイコン加熱検出用?)
  • SPI
  • I2C互換
  • UART
  • RTC

などか。

まだ開発環境の構築に至っていないので、また後日。

2014/06/12

[ios]そして再Rejectされる

ふふ、ふふふふふ・・・・・・・。

2.12: Apps that are not very useful, are simply web sites bundled as apps, or do not provide any lasting entertainment value may be rejected

ええ、力強くRejectされましたとも。
予想はしてたんですよ?
きっと通らないだろうなあ、とは思ってたんですよ?

でもね・・・心の奥底では「もしかしたら」って希望を持ってましたよ。
ほら、パンドラの箱の底にだって残ってたじゃないですか。

 

Windows8もブルースクリーンになったし、今日はダメダメだぁ。

2014/06/09

[android]威嚇!セイバー! 1.0.4

設定画面を追加したので、アップした。
久々にアプリ管理画面を見たけど、あか抜けたねー。

署名付きAPKも久々だったんだけど、2037年に切れるけどいい?って聞かれた。
最初に作ったkeystoreをずっと使ってるんだけど、定期的に更新した方がよいのかな?
でも、最初にアップした署名はずっと管理するだろうし・・・。
期限だけ延ばすとか、できるのか?


AndroidとiOSで同じようなアプリを作ったけど、やっぱりいろいろ違いますな。
めんどくさいので、なんか別の言語で作って、それをAndroid用やiOS用に変換してくれるようなしくみがあるといいのになぁ。
できんよなぁ・・・。

とりあえず、自分にできる技がほとんどないことがわかった・・・。
ちょっとまじめにやらないと、これからの人生が危ないと悟ったのが収穫だったか。

2014/06/08

[android]ActionBarを表示させたら、onTouchEventの座標がずれる

iOS版の「威嚇!セイバー!」は、設定画面を追加したくらいでReviewに出した。
またリジェクトされる恐怖と戦う日々が始まる・・・。

それまでの間なにもしないのもなんだから、Android版も同じ修正をすることにした。


今まではAndroid1.6から対応してたんだけど、これを機に4.0まで引き上げることにした。
少しずつ新しくしていかんとね。

同じように設定画面を追加しようとしたが、はて、やり方がわからぬ。
どうも最近では、ActionBarを付け、そこから呼べるようにするらしい。
今まではフルスクリーンだったけど、ActionBarを付けることにした。
動的に変化するわけでもないので、AndroidManifestに「@android:style/Theme.WithActionBar」を付けた。

それで表示されるようになったんだけど、onTouchEventで通知される座標がActionBarの分くらい下にずれて通知されている。
威嚇セイバーって、タッチされた座標に向かって歩いて行くんだけど、それが下にずれる結果となっている。
うーむ。

下にずれる、ということは、通知される座標は以前と同じで、表示するViewが下にずれている、ということになる。
たぶん、通知座標は画面左上を原点とした座標系で、ViewはActionBarの下からの座標系なのだろう。
Windowsでいうところのクライアント座標に変換せんといかんのか。

 

しかし、ネットで調べても・・・そんなことをしてる人が見当たらない。
フルスクリーンで作っていたときの残骸が、どこかに残っているのか・・・。

すっきりしないが、getActionBar().getHeight()で座標を差し引くことにした。
うーむ。。。

2014/06/06

[ios]Xcode6(beta)でAppIDが変わっていた

タイトルがわかりづらくて済まん。
用語がまだよくわかってないのだ。

今朝は7時過ぎに目が覚めたので、そのまま起きて、中途半端になっていた威嚇セイバーを完成させようとした。
といっても、単に絵を増やすだけなので、絵を数枚描いただけなのだが・・・。

で、画像も作り、シミュレータでも動作したので、またRejectされてもいいからアップしようとした。
すると、なんかProvisioningと違うとか、サーバの情報と違うとか、なんかそんな感じのエラーが出た。
(内容は忘れた。すまん。)

うちのiPad miniをiOS8 beta1にしたので、Xcodeもbetaを使っていたからそのせいか、と思いXcode5に戻したけどダメ。
なにがちがうんじゃー、とよくよく見ると、アプリの名前が「com.blogpost.hiro99ma.IKAKU」みたいなので作っていたものが「com.blogpost.hiro99ma.test.IKAKU」になっていたのだ。

このtest付きのって、プロジェクトを新規作成すると自動的にできるTARGETだよなぁ・・・。
なんでそれに切り替わってたんだ・・・。

あと、アプリのバージョン表記も「1.0.0」ってしてたのが、「1.0」になってた。
訳わからんですたい・・・。


そんな艱難を乗り越え、2回目のWaiting For Review状態になった。
来年のDeveloperアカウントの更新もしてしまったので、どうやってもリリースさせないと気が済まない!
これで認めてくれ~~

2014/06/03

[ios]Static Cellで設定画面を作りたい

Macで、無料のブログエディタ(Blogger対応)があったら教えてくだされ。
画像を貼ることさえできればよいので。。。
なんか設定がうまくできんのよねぇ。。。


さて、それはともかく。
Static Cellで設定画面を作りたい。

まず、UITableViewControllerはこんな。

その中のTableView。
ここがStatic Cellsだ。

そうすると、"Table View Section"というのがセクション数分できる。
Table View Section自体は、特に用が無いみたいで、設定するのはRows。行数だ。



Cellの例。


さて、これを設定として使うときはどうするのか。
今回は、セクションの中身は選択肢で、タップしたものが1つだけ選択されるようなものを考えている。
ラジオボタンみたいなイメージなのだが、iOSではラジオボタンがないからcheckmarkになるんじゃないかと思っている。

ただ、iOSとしてはチェックマークとか、ディスクロージャーとか、そういうのは”Accessory"らしい。
付属物、みたいなものか?
だから、「チェックマーク? 付けたければ付ければいいやん」みたいなスタンスのようだ。
何かというと、タップしたからマークを付ける、とか、他がタップされたからマークを外すとかは、たぶん実装でやってあげないといけない、ということだ。

あ、文句を言っているように聞こえるかもしれないが、どちらかというと「私が文化をわかっていない」の方じゃないかと思っている。
あるいは、やり方をわかっていないだけか。
まあ、文句であることには変わりが無いんだけどね。

そんなわけで、こういう実装をした。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *curCell = [tableView cellForRowAtIndexPath:indexPath];
    
    //同じセクションのチェックを全部外す
    for (NSIndexPath *path in [tableView indexPathsForVisibleRows]) {
        if (path.section == indexPath.section) {
            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
            cell.accessoryType = UITableViewCellAccessoryNone;
        }
    }
    //自分にチェック

    curCell.accessoryType = UITableViewCellAccessoryCheckmark;
}

動いてはいるんだけど、ここまでやってやらんといかんの?とは思う。
あと、indexPathsForVisibleRowsで見えてる部分のindexPathを取得してるけど、じゃあ画面外まで広がってたらどうすんだよ、とか。

まず、didSelectRowAtIndexPathで、タップされたセルの情報が取得できる。
セクション番号とか、行番号とか。
NSIndexPathは、行番号とセクション番号がわかれば取得できる。
ならば、あとはセクション番号から行数がわかれば、indexPathesForVisibleRowsに頼らずに済む。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *curCell = [tableView cellForRowAtIndexPath:indexPath];
    
    //同じセクションのチェックを全部外す
    NSInteger rows = [tableView numberOfRowsInSection:indexPath.section];
    for (NSInteger row=0; row<rows; row++) {
        NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:indexPath.section];
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    //自分にチェック

    curCell.accessoryType = UITableViewCellAccessoryCheckmark;
}

どうだ?

2014/06/02

[ios]設定画面を作ろうとしているが、よくわからん

よくわからんシリーズだ。

iOSで、設定画面を作ろうとしている。
Rejectされたので、なんか設定できるようにしてやろうという考えだ。
iOSの設定アプリに追加するやつじゃなくて、アプリの中に組み込むやつを作る。

設定画面と言えば、UITableViewController。
Storyboardエディタで、これを貼り付ける。
ついでにUITableViewControllerを継承した新規クラスも作成する。
そしてStoryboardのCustom Classとして指定してやれば、何かあったときに作ったクラスのメソッドが呼ばれるようになる。

UITableViewをStoryboardでやるとき、デフォルトはDynamicなんだけど、Staticという選択もできるとあった。
Staticでやると、実装部分を減らせるらしいので、今回はそうしてみよう。

--------
Static Cellって、あまり情報が見つからない。

設定画面なので、設定した情報を取ってきたり、反映したりしないといかん。
それをどうしていいかが・・・。

最終的には、didSelectRowAtIndexPathで全部やることにした。
セクションがいくつかあって、そのセクションごとにチェックマークが1つあるような設定画面だったのだけど、その「セクションごとに」とかを自動でやれるのかどうかがわからん。
だから、cellForRowAtIndexPathでタップされた位置のセクション番号を取ってきて、indexPathsForVisibleRowsで持っているセルを全部さらい、同じセクションだったらチェックマークをクリアし、最後にタップされたセルにチェックマークする、という泥臭い方法にした。
あー、かっこわるいーー。

設定値はNSUserDefaultsで保持することにした。
設定項目は2つしか作ってなかったんだけど、NSMutableDictionaryで管理させた。
NSUserDefaultsって、NSDictionaryは保持するけど、NSMutableDictionaryがよくわからんかった。
めんどくさいけど、一度NSDictionaryとして取得し、NSMutableDictionaryに変換することにした。保持するときは、setObjectでNSMutableDictionaryすればよかった。

dictionaryForKeyで取得するからNSDictionary形式になったんだけど、objectForKeyで取得すればよいのか?
でも、「オブジェクトを保存する」っていうしくみがどう動いているかわからないので、型が違うとだめそうな気もする。

なんか、こういう基礎的なところがまだ理解できてないよなぁ。。。