【Felicaを使う】Felicaリーダー・ライターとFelica Plug の通信プロトコル
吉田は『回想十年』の中で、彼らしい好悪の強さをにじませて、マッカーサー司令部にも二つのグループがあったと語っている。 ものごとの道理をわきまえ、勝者と敗者を超えて相互に理解と信頼をもちあえるマッカーサーとその側近の軍事グループ、 そして急進的な改革の情熱に突き動かされて日本の実情を無視した乱暴な要求を仕かけてくるニューディーラーたちである。吉田は前者と協力関係を築き、後者とはつきあわなかった。
ケーディスの民政局は、保守政治を忌避して、鳩山追放を強行した結果、意図に反してもっと手ごわい保守外交官を政権につかせることになってしまった。
日本の近代6 戦争・占領・講和 P287より引用
前回はGR-KURUMIとFelica Plugを接続し、データの送受信を行う方法を説明しました。
ですが、データを単に送受信するだけでは通信は出来ません。
データは規格に従ったデータ構造を持ち、適切なタイミングで送受信されと通信は成立しません。
今回はFelicaリーダー・ライターとFelica Plug の通信プロトコルについて説明します。
今回のシステムは以下の構成になっています。
RX62Nマイコン ⇔ Felicaリーダー・ライター ⇔ Felica Plug ⇔ RL78マイコン
これらの機器間において、通信プロトコルは以下のようになっています。
まずRX62NマイコンはRFConfigurationコマンドを送信することによりFelicaリーダー・ライターの初期設定をしています。
この初期化をしないとFelicaリーダー・ライターはFelicaカードやFelica Plugを認識しません。
コマンドの詳細は別記事で説明しますが、RFConfigurationコマンドは1つにつき1個のパラメータしか設定できないので、必要なパラメータの分だけ複数回送信する必要があります。
次にRX62NマイコンはInListPassiveTargetコマンドを送信します。Felicaリーダー・ライターはこのコマンドを受信すると、Pollingコマンドを無線送信し、FelicaカードやFelica Plugを探索します。
ここでFelicaカードやFelica Plug を検知するとは、Felicaリーダー・ライターはPollingレスポンスを受信することを意味します。Felicaリーダー・ライターはPollingレスポンスを受信すると、RX62Nに対してInListPassiveTargetレスポンスを送信します。
私のプログラムではInListPassiveTargetコマンドに対するレスポンスがあるまで、繰り返しこのコマンドを送信するようにしています。
Felica PlugがFelicaリーダー・ライターに近づくと、磁気検出し、RFDET信号がLOWになります。これを検知したRL78マイコンは初期化コマンドをFelica Plugに送信します。
これによりFelica PlugはPollingコマンドを受信した際に、Pollingレスポンスを送信できるようになります。 (上の図では、Felica Plug初期化していないときにPollingコマンドを受信しても、何の応答も返していません。)
Felica PlugとFelicaリーダー・ライター間のデータ送受信はCommunicationThruEXコマンドを用いて行います。
Felica Plug側へデータを送信したいときはWrite Without Encryptionコマンドを使い、Felica Plug側からデータを受信したいときはRead Without Encryptionコマンドを使います。
CommunicationThruEXコマンドのデータ構造は以下のようになっています。
RX62NはCommunicationThruEXコマンドのData outにFelicaコマンドを格納して、Felicaリーダー・ライターへ送信します。
するとRL78は、Felica PlugからこのData out、Felicaコマンドを受信します。Felicaコマンドを受信するとFelica PlugのIRQ端子がHighになり、RL78へ受信データがあることを報せます。
RL78(HOST CPU)ではオレンジ色の部分のみが受信データとして確認できます。
そして、RL78がFelica plugへ送信したFelicaレスポンスはCommunicationThruEX応答のData inに格納され、RX62Nが受信します。
RL78(HOST CPU)ではオレンジ色の部分のみ用意して送信すれば、残りは自動的に生成してくれます。
このFelicaコマンドとFelicaレスポンスは、ブロックリストとブロックデータという構造を持ちます。
(Felica PlugユーザーズマニュアルP49参照)
ブロックリストは複数のブロックエレメントから構成されます。
1個のブロックに対して1個のブロックエレメントが存在します。よってt個のブロックを持つブロックリストは、先頭にt個のブロックエレメントが配置されています。
送信するブロックの数が256個以上ならばブロックリストは3bytesで、255個までならブロックリストは2bytesになります。
ブリックリストに続いて、必要ならばブロックデータが配置されます。1ブロックは16bytesのデータを持ちます。
また、ブロックエレメントは以下の構造を持ちます。
ここでブロックエレメントの1byte目をD0、2byte目をD1、3byte目をD2と表記します。
ブロックリストエレメント2bytesの場合
bit | 名称 | 内容 |
---|---|---|
D0のbit7 | 長さ | ブロックリストエレメントの長さ 0:ブロックリストエレメントは2bytes |
D0の[bit6:bit4] | アクセスモード | Felica Plugは000b固定 |
D0の[bit3:bit0] | サービスコードリスト順番 | Felica Plugは0000b固定 |
D1 | ブロック番号 | このブロックリストエレメントに対応するブロック番号 |
ブロックリストエレメント3bytesの場合
bit | 名称/th> | 内容 |
---|---|---|
D0のbit7 | 長さ | ブロックリストエレメントの長さ 1:ブロックリストエレメントは3bytes |
D0の[bit6:bit4] | アクセスモード | Felica Plugは000b固定 |
D0の[bit3:bit0] | サービスコードリスト順番 | Felica Plugは0000b固定 |
D1 | ブロック番号 | このブロックリストエレメントに対応するブロック番号 の下桁(リトルエンディアンなので) |
D2 | ブロック番号 | このブロックリストエレメントに対応するブロック番号 の上桁(リトルエンディアンなので) |
【社会】死の虚無は恐れるに足らず
「死ぬのはいつも他人ばかり」
このブログは公共の利益(The Greater Good)のために書いている。
このブログの記事が他人様の役に立てば、この上ない喜びである。
今回は、お盆にふさわしく、死ぬことの話をしたい。そして、僭越ながら皆さんをある種の死の恐怖から解放して差し上げたいと思う。
それはとても人々の役に立つ公共の利益(The Greater Good)に叶うことに違いない。
死ぬのは恐ろしいことだと多くの人は思っている。
その通りだ。私も死ぬのは恐ろしい。
私が思うに、死ぬのが恐ろしい理由は3つあると考える。
このうちの2つの理由は、容易に取り除くことは出来ない。
しかし1つだけは、私のように明確に取り除くことが可能である。
それを説明するために、まずは死の恐怖の分類から始めよう。
①死に至る痛みと苦しみ
死ぬときには身体の損傷や機能障害が伴う。それはとても痛く、苦しいものであるはずだ。
死ぬほど痛いというのは、死ぬほど嫌なことに違いない。
痛いのは怖い。単純明快で誰もが納得できる恐怖の理由だ。
私も死に至る痛みと苦しみの恐怖から解放されることはない。
この恐怖は死ぬ日まで続く。
ちなみに人間は極限の痛みを感じると、脳が痛みを遮断して苦痛を感じなくなる。
ひどく痛みつけられた人が、突然冷静になることがあるが、それはこの脳の作用によるものなのだろう。
ちなみに、この脳の作用を妨害し、死の直前まで激しい痛みを感じさせ続ける薬があるそうだ。
この薬の話が本当だとしたらひどい話である。
(以前にこの薬のことを調べたが見つけることは出来なかったので、この薬の存在は都市伝説かもしれない。)
②やり残したことが出来なくなる無念
多くの人は、卑近な雑事から遠望壮大な計画まで含めて、何かをしたいと思って生きている。
今晩は味噌ラーメンを食べよう。
来月に発売される小説が楽しみだ。
1年かけた仕事がもうすぐ終わる。
子供が大学を出るまで頑張って働こう。
老後は趣味の園芸を楽しもう。
死は、それら全ての未来を断絶させる。
それは無念なことだろう。
自分が生きて守らなければ、壊れてしまう大事なものを、多くの人が持っている。
それは、恋人、幼い子供、老いた両親かもしれない。
それは、自分がいないと成立しない仕事かもしれない。
それは、自分しか管理する人間のいない大事なコレクションや美術品かもしれない。
死は、それらの行く末を見守る権利を根こそぎ奪う。
それは未練なことだろう。
この恐怖を逃れるために、人は後事を託せる仲間、組織や集団を作る。
残された家族のことは、親戚や地域の福祉団体に託す。
残した仕事は、会社の同僚に託す。
残したコレクションは、同好の士に託す。
もっとも私は今は亡き先生に託されたものを、ほとんど守っていない。
不肖の弟子で申し訳ないことである。
人は自分の荷物を持っているのだから、他人の残した荷物をいつまでも預かってはいられない。
歴史を見れば分かる。周囲の人間を見れば分かる。本人の死と共に、本人の残したものが滅び、忘却された事例は五万とある。
死後、自分の思い通りになることは一つもない。
だから、私も計画をやり遂げられない恐怖から解放されることはない。
③死後の虚無もしくは死後の裁きの恐怖
魂や死後の世界を信じている人は、死後に偉大なる存在に裁かれることを恐れている。
魂や死後の世界を信じていない人は、死後に自分というものが完全になくなり、虚無に返ることを恐れている。
前者の恐怖は私には無縁なので、考察しない。
死後の世界を信じているならば、教義に沿って生きてさえいれば恐怖とは無縁だ。
私の知る宗教家、シスター、神父、神主、イスラム教徒、ユダヤ教徒は、死後に神の御許に行くことを誉れとしていた。
彼らとは異なり、魂を信じられない私のような人間は、死後の虚無への恐怖と向き合わないといけない。
死後、自分が消えて無くなるというのは、人生最大の未知だ。
それがどのようなものか想像もつかない。だから、それが恐ろしい。
何も見えない暗闇の中に飛び込むのは、いつだって恐ろしいことだ。
しかし、私はこの恐怖から解放された。
私に虚無への恐れはない。そして世界中のほとんどの人もまた、虚無の恐怖とは無縁なはずなのである。
実は虚無は未知でもなんでもない。既知なのである。誰もが生まれた時から常に経験しているのである。
虚無は未知であるが故に恐ろしいのに、種を知ってしまえば未知でもなければ、恐れるべきものでもない。
ただの雑魚だ。
「恐ろしいと評判の魔王の城に乗り込んだら、玉座に座っていたのがスライムだった」というのと同じくらいの拍子抜けだ。
結論から言うと、100年、200年、それ以上の昔に自分が生きていないことが恐ろしくないならば、将来に自分がいないことも恐れる必要はない。
何故なら過去の虚無と未来の虚無、この2つは同じことだからだ。
よって私たちは全員、自分が存在しないという状態を知っている。死の虚無は未知でもなんでもない。
「江戸時代に自分が生きていなかったことが、恐ろしくて恐ろしくてたまらない」という人だけが、将来に自分が存在しないことを恐怖する資格を持つ。
そうでないならば、死の虚無への恐怖は偽りであり、錯覚であり、嘘であり、間違いである。
もう少し詳しく説明しよう。
物理学的真理として、過去と未来は同じものである。これは時間の一様性、対称性として知られる物理学の根本原理だ。
エネルギー保存則という自然界の大原則も、この時間の対称性から導かれる。
最新の量子物理学でも、相対性理論でも、この原理は覆らない。
過去と未来は同じであるから、数百年前に私が存在しないことも、数百年後に私が存在しないことと同じである。
この点について異論はありえない。誰も宇宙の真理に逆らうことは出来ないのだから。
これを否定することは、時間の一様性とそれから導出されるエネルギー保存則を否定することに等しい。
もしこの点に反対したい人がいれば、私にではなく世界に訴えるべきである。
その無謀な訴えが認められれば、ノーベル賞を100個もらってもお釣りが来るくらいの大発見だ。
ノーベル賞を取れる自信がないならば、おとなしく私の説明を受け入れていただきたい。
争点とすべきなのは、この真理をどのように解釈するかである。
ここにいる自分が消えてなくなり、思考も意思もない状態になるというのは、絶対に自分で経験できない死後の未来の出来事であるが故に恐ろしい。
将来にやりたいことができなくなるというのは②の恐怖であるから、ここには含めない。
厳密に自分が虚無に返る事だけの恐怖を考えたとき、その恐ろしさは、ただひたすらに「誰もが経験するのに、誰もが語ることの出来ない圧倒的未知」に由来する。
だが、私たちは過去に自分が存在していないことは既に知っている。そして、それを微塵も恐れてはいない。
はるか昔の過去に自分が存在していないのは当然のことだと思っている。ならば、過去と未来は等しいが故に、未来に私たちが存在していないことも当然と思わなくてはいけない。
悠久の長い時間のわずかな一瞬のみに私たち一人一人は存在している。無限の過去と無限の未来に自分は存在しない。それなのに、無限の過去の虚無を恐れず、無限の未来の虚無のみを恐れるのは不合理だ。
故に私は死の虚無を恐れることを迷妄と断罪する。
以上が、死の虚無を恐れる必要がない理由である。
私は最初にこのことに気が付いたとき、この発見を他人と共有したくなり、誰彼となく話して回った。
私は誰もが私の話に共感し、喜んでくれるものと信じて疑わなかった。
だが現実はそうならなかった。
この話を聞かされた誰もが、私の予想に反して「お前は何を言っているんだ?」という顔をした。
実際に言われたこともある。
狂人を見るかのような目で、ドン引きする人もいた。
「へぇー、そうですか」とか「お……、おう!」とか言って、視線をそらし、私と距離を置く。
私はがっかりした。そして、思った。
理解されなかったのは、真剣に考慮されなかったからだと。
これから死ぬ人ならば、もっときちんと私の話に耳を傾け、この発見に賛同してくれるはずだ。
そこで私は、これから死ぬ人に対して3つの死の恐怖を語り、少なくとも3番目は恐れる必要はないと説いてみた。
結果は散々だった。
ある人は侮辱されたと怒り、ある人は脅迫されたと怯え、ある人は何故か泣き叫び、ある人はすぐに死んでしまった。
これに懲りた私は、この話を他人にしなくなった。
しかし、ネットの広い世界ならば、私の発見に救いを見出す人もいるかもしれないと考え、久しぶりに説いてみることにした。
よって皆様におかれては、死ぬ時には何の恐れもなく虚無に返っていただければ幸いであります。
【Felicaを使う】Felica Plug とマイコンの半二重シリアル通信
吉田茂は養父、吉田健三の財産50万円(現在換算で約40億円)を使い尽くした。
某氏「どこそこの家の養子になった誰それは、そこの財産を倍に増やしたそうだ」
吉田茂「そういう男は養子の風上にもおけませんな」
今回はGR-KURUMI(RL78/G13)を使用してFelica plugを制御する方法について説明します。
Felica plugの端子は以下のようになっています。
RC-S926のインターフェイスについては「FeliCa Plugユーザーズマニュアル」の「2.2.1 物理層」を参考にしました。
ソニー株式会社 | FeliCa | 法人のお客様 | 技術情報
端子名 | In/Out | Active | 内容 | GR-KURUMIの接続先 |
---|---|---|---|---|
RFDET | OUT | Low | 磁界検知信号 L:磁界入力信号有り H:磁界入力信号無し | 外部割込み端子 |
SW | IN | - | スタンバイ制御信号 L:省電力モード H:省電力モード解除 | PORT出力端子 |
IRQ | OUT | High | 無線データ受信信号 L:CPUへのデータ無し H:CPUへのデータ有り | 外部割込み端子 |
SEL | IN | - | データ転送方向信号&データ完了通知信号 L:Host CPU → FelicaPlug H:FelicaPlug → Host CPU | PORT出力端子 |
DATA | IN/OUT | High | シリアルデータ | PORT入出力端子 |
SPICLK | IN | - | シリアルデータ用クロック | PORT出力端子 |
磁界検出RFDET端子と無線データ受信信号IRQ端子はマイコンの外部割込み端子に接続しました。
SW端子、SEL端子、SPICLK端子はマイコンのPORT出力端子に接続しました。
DATA端子はIN/OUTの両方として使用するので、IN/OUT両方の機能に切り替えられるマイコンのPORT端子と接続しました。ちなみに初期状態ではPORT端子は入力端子にしておき、マイコンからFelica plugにデータを送信するときだけ、出力端子にして、送信完了したら入力端子に戻します。
またpull-up/pull-downは同マニュアルで以下のように説明されていました。
DATA,IRQ,RFDET:Pull-Up/Pull-Downの処理は不要です。
SW,SPICLK,SEL:モジュールに電源を供給しているとき、必ずH or Lを入力すれば、Pull-Up/Pull-Downともに不要です。
Felica Plugの磁界検出RFDET端子は、普段はHigh出力になっています。Felicaリーダー・ライターに接触すると磁界を検出してLOWに変化し、磁界を一定時間検出しないとHighに戻ります。
Felica PlugのIRQ端子は、普段はLOW出力です。Felica plugがFelicaリーダー・ライターからWrite Without EncryptionコマンドもしくはRead Without Encryptionコマンドを受信するとHighに変化します。
その後、最初のSPICLK立ち上がり時にLOWに戻ります。コマンドの内容や実際の波形については別記事でも検討します。
Felica plugはSPI通信ではなく、独自の三線式半二重シリアル通信という方式を採用しています。
SPI通信機能のないマイコンでSPI通信をする時、SPICLKをPORT端子に割り当てて、単純に出力をHigh⇔Lowにするのを繰り返して擬似的にクロックを作ることがあります。
Felica plugは基本的にそれと同じことをします。
例えば1byteのデータをマイコンRL78からFelica plugへ送信するプログラムは以下のようになります。
PORT7.1をDATA端子と接続し、PORT7.0をSPICLK端子と接続しています。PM7はPORTの入出力を制御するレジスタです。
GR-KURUMIのSPICLK端子出力をプログラムでHigh→LOW→High→LOWと変化させながら、送信したいデータを8bit目から順に1bitずつ送信します。
プログラムはSonyがArduino用に公開しているサンプルプログラムを参照しました。
Arduino向けFeliCa Plug 制御ライブラリの提供 « FeliCa Developers' Blog
void sendByte(unsigned char data) { int i; //DATA用端子を出力に設定 PM7 &= 0xFD; //8bit目から開始して、1bit目までデータ送信 for (i = 0; i < 8; i++) { P7.0 = 0; //CLK 立ち下げ if (data & 0x80) { //dataを1bit送信 P7.1 = 1; } else { P7.1 = 0; } data <<= 1; //dataを右に1bitシフト us_wait(1); //1us待機関数 P7.0 = 1; //CLK 立ち上げ us_wait(1); //1us待機関数 } //DATA用端子を入力に設定 PM7 |= 0x02; }
このプログラムを使って実際に0x1A=00011010のデータを転送したときの波形を以下に示します。 SPICLK立ち上がり時のDATAの値が送信され、8bit目から1bit目まで順に送信されているのが分かります。
Felica PlugからRL78へのデータ受信の場合も、基本的に送信と同じことをします。
GR-KURUMIのSPICLK端子出力をプログラムでHigh→LOW→High→LOWと変化させてやると、そのタイミングに合わせてFelica Plugがデータを1bitずつRL78へ送信してくれます。
送信と違う点は、別記事にて詳細に説明しますが、DATA用に使用しているPORT端子を入力に変更し、SEL端子をHighにしてやることだけです。
unsigned char receiveByte ( void ) { unsigned char data = 0; unsigned char i; //8bit目から開始して、1bit目までデータ受信 for (i = 0; i < 8; i++) { P7.0 = 0; //CLK 立ち下げ us_wait(1); //1us待機関数 data = data << 1; //dataを右に1bitシフト if(1 == P7.1) //dataを1bit受信 { data |= 0x01; } P7.0 = 1; //CLK 立ち上げ us_wait(1); //1us待機関数 } return data; }
SPI通信ならば入力と出力が同時に行われますが、Felica plugではSEL端子をHigh/Lowに変えることでデータの入出力方向を切り替えて、入力と出力を別々に行います。
【Felicaを使う】Felicaリーダー・ライターとFelica Plugの購入
「戦争に負けて、外交で勝った歴史がある」
① Felicaとは何か
NFC「近距離通信技術(Near Field Communication)」の種類の一つがFelicaです。
Sonyが作成し、日本国内やアジアの一部で普及していますが、世界的にはあまり普及していません。
Felicaカードは2.5億枚普及していますが、その内2億枚が日本国内です。
一方でMifare(TypeA)カードは12億枚普及しています。
Felicaとは? - 技術者向けNFC(FeliCa,Mifare)開発支援サイトNFC-Developer.com
http://nfc.s-cubism.jp/2011/12/28/79/
http://www.chip1stop.com/web/HKG/zh/dispRfid.do
数は力であり、技術は普及してこそ意味があると私は考えています。その点においてFelicaは負けてしまいました。
ですがFelicaには、まだ勝ち目が残っているので、今後に期待しています。
また、趣味として利用するならば、普及率や将来性などとは関係なく、Felicaは素晴らしく高機能で楽しいおもちゃです。
私は趣味で、記録したセンサーの数値をFelica plugに取り込み、FeliCa リーダー・ライターに読み込ませる仕組みを作りました。
その製作過程を備忘録としてここに残したく思います。
② FeliCa リーダー・ライター RC-S620Sの購入
Felicaリーダー・ライターRC-S620SはFeliCa Lite非接触ICカードからデータを読み書きするためのモジュールです。今回は以下を使用します。
FeliCa リーダー・ライター RC-S620S - スイッチサイエンス
Felicaリーダー・ライターはシリアル通信で制御します。
外部と接続するにはピッチ変換基板を利用します。
FeliCa RC-S620S/RC-S730 ピッチ変換基板のセット(フラットケーブル付き) - スイッチサイエンス
私は、CQ出版のInterface付録についていたRX62Nマイコンと接続して制御しました。
使用マイコンにこだわりはなく、RX62Nマイコンを選んだのは手元にそれがあったからです。
マイコンのことが分かる人には、Arduinoでもmbedでも何を使っても同じことです。
マイコンの性能差が影響を与えるような高度な使い方はしません。
また、資料は以下のsonyのFelicaサイトから以下を取得しました。
ソニー株式会社 | FeliCa | 法人のお客様 | 技術情報
RC-S620/S製品<簡易版>(386KB) RC-S620/Sコマンドリファレンスマニュアル<簡易版>(740KB)
③ FeliCa Plugの購入
FeliCa Plug はFeliCaカードと同じ機能を持つモジュールです。
機械の中にFeliCa Plugを組み込んでやれば、機械がFelicaリーダー・ライターとデータ交換をできるようになります。
FeliCa Plug モジュールとしてRC-S801とRC-S802が販売されています。この2つはアンテナの面積が異なるだけで機能は同じです。今回はRC-S801を使用しました。
またチップ単体ではRC-S926という名称で販売しているようです。
FeliCa Plug RC-S801 - スイッチサイエンス
FeliCa Plug RC-S802 - スイッチサイエンス
FeliCa Plug は独自の規格である半二重シリアル通信で制御します。SPI通信に似た規格です。 外部と接続するにはピッチ変換基板を利用します。
FeliCa Plug ピッチ変換基板のセット (フラットケーブル付き) - スイッチサイエンス
私はGR-KURUMI(RL78)と接続して制御しました。
Felicaリーダー・ライターと同様に、マイコンのことが分かる人には、Arduinoでもmbedでも何を使っても同じことです。
RC-S801から配線のヒゲがたくさん生えているのはオシロスコープで波形を取るためです。(ヒゲの先にプローブをひっかけて波形を取りました。)
また、資料は以下のsonyのFelicaサイトから以下を取得しました。
ソニー株式会社 | FeliCa | 法人のお客様 | 技術情報
FeliCa Plugユーザーズマニュアル(957KB)
【社会】祈る価値のない祈りのみを捧げる
皆さん、よろしくて?
誰のためでもなく、何のためでもなく、誰にも願わず、何も祈らず、乾杯!
私は子供の頃、カソリック系のシスターの世話になっていたので、クリスチャン的世界観を刷り込まれて育った。
神は唯一絶対であること、イエス・キリストは死後三日目に復活したことで自分が神の子であることを証明したことや、イエスは中東人のはずなのに外見は白人そのものであることは、疑うべきではない自明の真理であった。
その後、私は彼らの世話が必要なくなり、神道系の伝統が強い場所で生活を始めた。
治天下皇尊(あめのしたしらしめす すめらみこと)を名乗る現人神がいたり、何にでも神を見出す多神教であったり、いきなり今までとまるで価値観の違う宗教に放り込まれ、更にそれらの儀式を執り行う側になったので私はひどく混乱した。
その後、いろいろあって「神は信頼に値しない」「神なんて、どうでもいい」と思うようになり、アレとは関わるまいと決め、アレに頼ることはしないと私は誓ったのであった。
神を否定することで、神に関する矛盾した教えによる自我の危機から逃れたのだと、今の私は自己分析している。
他にも実際に神に頼って破滅した人間を何人も見たことも大きな理由ではある。人間を救えるのは人間だけだ。
それでも日常を生きていれば、何かの行事で神に祈ることを強制される場面が出てくる。
そんなとき、神に頼らぬ私に祈ることは何もないのだが、何も祈らないのは神主殿への非礼になる。どうせ分からないのだから、何も祈らずにいればいいという考えは浅慮である。
その道のプロならば、相手がどの程度真剣に念じているかは、言葉に出さなくても分かるものである。何よりもバレなければどうしたっていいという考え自体が不敬の極みだ。
そこで仕方なく、私はどうでもいいことを祈るようにしている。
先日も祈らざるをえない機会があったので私はこんなことを祈った。
AEDという装置がある。意識を無くした人に対して心臓マッサージが必要かを自動判定し、必要ならば電気ショックを与えてくれる装置だ。
これを使うとき、装置のパッドを相手の胸に取り付けるために、相手の上半身を脱がして裸にしないといけない。
だから、もしこれを使う場面に出くわした場合、相手が若い女性だったら凄く困るわけである。
その女性が可愛ければ、困難は倍増する。
若くて可愛い女の子なら幸運ではないかと思うのは素人である。
そんなことで嬉しがれるギラギラした時期は当の昔に終わっており、今の私は世間様の目が気になるお年頃だ。
路上に倒れた可愛い女の子を裸にしている姿など、変質者以外の何者でもない。
許されることなら無視して見殺しにしたいが、残念ながらそれは許されない。
ここで相手が男性なら正々堂々としていられる。太った中年女性なら言い訳の必要もない。
あんな自意識過剰の塊である繊細で可憐な若い女性なんて、神の次に関わりあいたくない人種である。
本当に危機的状況で脱がしたのならばいいが、「私は単に軽い貧血で倒れていました。ふと目を覚ましたら、見知らぬ男が私を脱がそうとしていました」なんてことになれば、私はどんな汚名を着せられるか分かったものではない。
ああ、考えただけで、恐ろしい。そんな場面に出くわしたら、本当に無視して見殺しにしたいのですけれど、ダメですかね?
もちろんダメということは分かっている。
けれど、この恐怖を思えば、そんな状況になることが幸運どころか不運でしかないことはご理解いただけるであろう。
そんな場面には遭遇しないようにと私は祈り、神主殿の祈祷が終わるまでの時間を過ごした。
今、私は意外とどうでもよくないことを祈ってしまったかもしれないと、猛省しているところである。
(追記)
真面目な話をすれば、AEDを使用する際はブラジャーを付けたままでも可能である。
また、周囲の人に声をかけて、なるべく性別が同じ人やAED講習経験者に行ってもらうのが好ましい。
しかし、他人任せにするのは良いことではなく、野次馬にならないよう、実践者として自分の役割を見つけるように努めるべきである。(救急車を呼ぶ、AEDを探す、腎臓マッサージを行う)。
ただの野次馬にしかなれないなら、居るだけジャマなので立ち去るようにする。
AEDの使用前は、倒れた人間に声をかけ、意識がないかどうかを確認する。
声かけに反応がなければ、命にかかわる事態なので、使用を躊躇してはいけない。数秒の遅れが命取りになる。
(参照)
【BLEを使う】GATT(Generic Attribute Profile)概要
青いぞ、
ゆきは まっさを、
もも、さくらぎに花咲かず、
青いこなゆき、
光る山路に泣きくらす。
青いぞ。
萩原朔太郎「青いゆき」より引用
いままでの記事はこちらをご覧ください。
ここではGATTについて自分のメモ用に調べた結果を書きます。 勉強しながら随時追加修正を行うので、内容の正確さを保証しません。
本記事は、以下の文献およびサイトを参照しています。
http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/
GATTの重要性
GATTは、実際にBLE通信でデータを送受信する方法や形式を決める。
異なる会社のBLEもGATTに従って形式を整え、送信されているからこそ、共通にデータのやり取りができる。
だからアプリケーションを作る際には是非ともGATTを理解しておくべきである。
GATTの役割
GATTは装置の通信役割を規定する。
①クライアント
クライアントはサーバにリクエストを送信し、サーバからの応答を受信する。
②サーバ クライアントからの要求を受信すると、応答を返す。
GAPの記事においても言及したように、GAPの役割とGATTの役割は独立している。
GAPがPeripheralであっても、GATTはクライアントにもサーバーにもなれる。
UUID
Universally unique identifier(UUID)は16bytesの識別子で、他のUUIDと重複することのない数字である。
リンク層においてデータpayloadは27bytesまでなので、UUIDの16bytesはそのほとんどを占有してしまう。
また、データが長いと通信時間が増え、消費電力も増えてしまう。
そのためUUIDには短縮した2bytes版と4bytes版がある。
この短縮版はBluetooth SIGで定義されたものだけを使える。また短縮版から16bytesのUUIDを再構築する時は
xxxxxxxx-0000-1000-00805F9B34FB
が使われる。xxxxxxxxの部分に短縮されたUUIDが入る。(2bytesの場合は0000xxxxのxxxxに代入する。)
SIGで定義されていないUUIDを使う時は、短縮版は存在しないので、必ず16bytesを使わないといけない。
例えば自分で新しいサービス、「ボタンを押すとLCDにメッセージが表示される」等を作る場合は、Bluetooth SIGにそのようなサービスに該当するUUIDはないので自分で16bytesのUUIDをUUID generatorを利用して作らないといけない。
Attributeとデータ階層
attributeはGATTにおけるデータ構造の最小単位である。クライアントとサーバのデータ交換は全てこのattributeを用いて行われる。
attributeを複数集めてグループ化したものをサービスと呼ぶ。ここでサービスとは機能を意味する。心拍計サービス、温度計サービスなど、何らかの機能を果たすために、一連のデータ交換のやり取りを一つにまとめたものがサービスである。
サービスはattributeより大きな単位に分類できる。サービスは複数のcharacteristicに分解できる。characteristicは複数のdescriptorが含まれることがある。
(サービスがcharacteristicを含まずにattributeだけから成る場合もある。characteristicがdescriptorを含まずにattributeだけから成る場合もある。)
もちろんcharacteristicやdescriptorも最小単位であるattributeで出来ている。
Attributeの構造
attributeの構成要素を以下に示す。
①Handle
handleとはGATTサーバの全attributeに与えられる、各attributeに固有の16bit識別子である。
handleは0x0001から0xFFFFまでのどれかの値が割り振られ、接続中にその値が変わることはない。
handleの値は、クライアントがアクセスできるattributeの順に従って0x0200→0x0201→0x0202と大きくなっていく。
ただしその値は連続しておらず、0x0202→0x0210と値を飛ばすこともある。
②Type
TypeとはUUIDのことに他ならない。
UUIDにおいて述べたように、サイズは2bytes、4bytes、16bytesのどれかになる。
attributeの値にどのようなデータを格納するのかを定義する。
例えばattributeの値にcharacteristic宣言のデータを格納する場合は、UUID=0x2803、CCCDのデータを格納するならUUID=0x2902となる。
③Permissions(許可)
各attributeに個別に与えられている。ATT operationがattributeに読み書きできるか、どのようなセキュリティになっているかを示している。
Permissionsはmeta-dataなのでクライアントが直接に値を読むことはできない。
valueの読み書き許可について、以下の4つのどれかを設定する。
・NONE:読むことも書くこともできない
・Readable:読み込みのみ可能
・Writable:書込みのみ可能
・Readable and writable:読み書き可能
クライアントがattributeにアクセスする際に、どのようなレベルの暗号が必要かも示す。
・Security mode Lv1:暗号化なし
・Security mode Lv2:このattributeにアクセスするには暗号化された接続が必要。ただし、暗号鍵による認証は必要としない。
・Security mode Lv3:このattributeにアクセスするには認証された鍵で暗号化された接続が必要。
④Value(値)
Typeで定義した種類のデータを格納する。Permissionsの設定がReadableやWritableでさえあれば、クライアントは自由にこの値を読み書きできる。
一方で①~③はクライアントが直接アクセスして読み出しや修正することはできない。
Valueには最大512bytesまで格納でき、整数、文字列、小数点と様々な型のデータが使えて、指定したtypeによってattributeそのものの情報やアプリケーションの実データを持つ。
Service
何らかの意図や目的に関連するattributeを集めてセットにしたのがサービスである。実際に全てのattributeは何らかのサービスに所属しているので、GATTサーバはサービスで出来ているともみなせる。
各サービスの先頭には、サービスの開始を示す1個のattribute、サービス宣言が存在する。サービス宣言のattributeは以下の構造を持つ。
Handle | Type | Permissions | Value | Value の長さ |
---|---|---|---|---|
0x●●●● | 0x2800 or 0x2801 | Read Only | Service UUID | 2,4,or 16 bytes |
Handleの値は、クライアントのアクセス順に従い、その時々に応じた値になる。
TypeはPrimary Service UUID(0x2800)かSecondly Service UUID(0x2801)になる。いずれも2bytesに短縮されたUUIDである。
Secondly Serviceは他のPrimary Serviceのincluded service(後述)としてのみ使えて、外部には公開されず、単独では意味を成さない。主に使われるのはPrimary Serviceの方である。またPrimary Serviceは別のPrimary Serviceのincluded serviceとしても使用できる。
Permissionsは読み込みしかできないように設定されている。
ValueにはService UUIDsを持つ。Service UUIDについてはGAPの解説も参照。
サービスは他のサービスをInclude serviceとして参照できる。別のサービスを含めることで、既存のサービスを拡張した新しいサービスを作成することが出来る。またサービスを使いまわすことで、似たようなサービスが重複することを避けられるのでメモリの節約にもなる。
(より詳しい解説はこちらのサイトのサービスの項目を参照)
Include serviceとして使用したいサービスは1個のattribute、include定義で指定する。include定義のattributeは以下の構造を持つ。
Handle | Type | Permissions | Value | Value の長さ |
---|---|---|---|---|
0x●●●● | 0x2802 | Read Only | Include service handle, end group handle, Included Service UUID | 6,8,or 20 bytes |
Handleの値は、クライアントのアクセス順に従い、その時々に応じた値になる。
TypeはInclude UUID(0x2802)の2bytesに短縮されたUUID。
Permissionsは読み込みしかできないように設定されている。
ValueにはInclude Serviceとして使用したいサービスについて、サービス宣言のhandleの値2byte、そのサービスの最後のattributeのhandleの値2byte、サービスのUUIDの値2bytesもしくは4bytesか16bytesを使う。
characteristicの構造
characteristicはユーザデータを格納するのに用いられる。characteristicは常に最低でも2つのattribute、characteristic宣言とcharacteristic valueを持つ。
また、descriptor(記述子)がcharacteristic valueに続くこともある。
これらの種類のattributeが集まって1つのcharacteristicを構成する。
・characteristic宣言
characteristic宣言のattributeは以下の構造を持つ。
Handle | Type | Permissions | Value | Value の長さ |
---|---|---|---|---|
0x●●●● | 0x2803 | Read Only | Properties, value handle, characteristic UUID | 5,7,or 19 bytes |
Handleの値は、クライアントのアクセス順に従い、その時々に応じた値になる。
Typeはcharacteristicを示すUUID(0x2803)の2bytesに短縮されたUUID。
Permissionsは読み込みしかできないように設定されている。
Valueは以下の構造を持つ
vlaueの項目 | byte数 | 内容 |
---|---|---|
Properties | 1 | このcharacteristicに対して許されている操作 |
value handle | 2 | characteristic valueのhandle |
characteristic UUID | 2,4 or 6 | このcharacteristic固有のUUID |
Propertiesは1byteデータで、以下の種類がある。0x80に設定した場合は、descriptorのCharacteristic Extended Propertiesの設定を用いる。
Property | 値 | 内容 |
---|---|---|
Broadcast | 0x01 | これを設定すると、指定されたcharacteristic valueのデータがadvertisingパケットで送信される |
Read | 0x02 | これを設定するとクライアントからの読み込み可能 |
Write Without Response | 0x04 | これを設定すると、クライアントからの書き込み可能。(サーバからのレスポンスなし) |
Write | 0x08 | これを設定すると、クライアントからの書き込み可能。書き込みリクエストに対して、サーバからのレスポンスが有る。 |
Notify | 0x10 | これを設定すると、サーバがクライアントにcharacteristicの変更を通知できる |
Indicate | 0x20 | これを設定すると、サーバがクライアントにcharacteristicの変更を通知できる。Notifyとの違いは、Indicateはクライアントからの応答も要求することである。 |
Signed Write Command | 0x40 | これを設定すると、クライアントからの署名付き書き込み可能。 |
Extended Properties | 0x80 | これを設定すると、descriptorのCharacteristic Extended Propertiesを使用できる。 |
value handleは実際のデータを持っているcharacteristic value attributeのhandleの値である。
このhandleの値は、必ずしもcharacteristic宣言のhandle値+1の連続した値にはならないことに注意する。
characteristic UUIDはcharacteristic固有のUUIDである。事前に定義された短縮版の2bytes,4bytesと、そうではない16bytesがあるのは他のUUIDと同じである。
・characteristic value
characteristic valueのattributeは以下の構造を持つ。
Handle | Type | Permissions | Value | Value の長さ |
---|---|---|---|---|
0x●●●● | characteristic UUID | 任意 | 実際のデータ値 | 可変 |
Handleの値は、クライアントのアクセス順に従い、その時々に応じた値になる。characteristic宣言のvalueでも使われる。
Typeはcharacteristic宣言のvalue で設定したのと同じcharacteristic UUIDを使う。
Permissionsは状況に応じて任意の設定を使用する。
Valueにはあらゆる種類のデータ、温度、keyコード、文字、速度、心拍などが用いられる。
descriptor
descriptorはcharacteristic valueの後に続き、characteristic valueの追加情報を持つ。
descriptorは1個のattributeで構成されている。
Expanded properties descriptor(拡張プロパティ記述子)
characteristic宣言のpropertiesを0x80に設定することで、この拡張propertiesが使用できる。
名称 | 内容 |
---|---|
Queued Write | これを設定すると、クライアントにQueued Write ATT Operationsの使用を許可する。 |
Writable Auxiliaries | これを設定すると、クライアントからdescriptorへ書き込みができる。 |
CCCD (Client Characteristic Configuration Descriptor)
最もよく使われる重要なdescriptor。
CCCDに1を書き込むとNotifyを許可し、2を書き込むとIndicateを許可する。0を書き込むと、NotifyおよびIndicateの両方を無効にする。
CCCDの設定が適用されるのは、そのCCCDが属しているCharacteristicに対してのみである。別のCharacteristicは、そのCharacteristicが持つCCCDで設定しないといけない。
また、通常、Characteristicの値は接続が切れると失われるが、CCCDの値だけは接続が切れても保持される。
Characteristic User Description descriptor
【BLEを使う】mbed HRM1017サンプルプログラムのプロトコル解析 その2
それは私の竪琴から
はじめてこの世に現れた
それ以来
たくさんの鼻でゆっくりと
自分の子どもを引き連れて
ナゾベームは歩く
「鼻行類」より引用
いままでの記事はこちらをご覧ください。
前回はHRM1017がadvertisingパケットをひたすら周囲に送信し、ipadのnRF Toolboxがそれを検知してスキャンパケットの送受信をするところまでを解析しました。
この時点では、まだHRM1017とipadは接続されておらず、ipadは周期的に周囲のデバイスのスキャンを繰り返しています。
HRM1017はスキャン応答を受けてしばらくは、ipadからの接続開始要求を待ちますが、一定時間経過しても接続開始要求がない場合は、advertisingパケットの送信を再開します。
実際に、接続開始をしないと、advertisingパケットの送信とスキャンパケットの送受信が延々と繰り返されます。
④ 接続要求パケット
本記事は主に以下を参考にしました。例のごとく、そちらを読んだ方が正確で勉強になります。
http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/
BLUETOOTH SPECIFICATION Version4.1 [Vol6] 2.3
BLUETOOTH SPECIFICATION Version4.1 [Vol6] 4.5
nRF ToolboxはHRM1017のadvertisingパケットを検知して、画面上に検知したnRF5を表示しています。これを選択することで接続開始され、以下のパケットを取得します。
Adv PDU TypeがADV_CONNECT_REQの接続要求パケットが確認できます。
これはipad(central)からHRM1017(peripheral)へ送信されています。
Access AddressやPDU Headerの意味は以前と同様です。
Lengthが34なのでpayloadが34bytesであることが分かります。
payloadはInitA(6bytes)とAdvA(6bytes)、それにLLData(22bytes)で構成されています。
InitAは、Initiator's addressのことで、接続要求を出すipad(central)側のアドレスです。これはScanAと同じになります。
AdvAは同様に先ほど確認したAdvAと同じHRM1017(peripheral)側のアドレスです。
次に、LLDataについて解析してみます。
・AccessAddr(4bytes)
接続先であるCentralのAccess Addressです。毎回ランダムに決められています。
以降のデータパケットのAccess Addressがこれと同じ値になっていることが確認できます。
・CRCInit(3bytes)
以降のデータパケットのCRCの計算で使うシフトレジスタの初期値です。接続を確立するたびに毎回ランダムに決められます。
プログラミングの際は、CRCの計算は自動的に行われるので、特に意識する必要はない数字です。
CRCはPDUの通信エラーの検出に使われます。通信が正常に行われたかを確認する仕組みです。詳細は省きますが、計算方法はシフトレジスタと EX-OR を使用します。データパケットで使われるシフトレジスタの初期値がこのCRCInitです。
ちなみにAdvertisingパケットのCRC計算で使われるシフトレジスタの初期値は0x555555と決まっています。
・WinSize、WinOffset、Interval
接続要求パケット以降のデータパケットの送受信タイミングを設定しています。
WinSize ×1.25msec = transmit Window Sizeです。
WinOffset×1.25msec = transmit Window Offseです。
接続要求転送後、遅くともtransmit Window Size + transmit Window Offsetの時間以内に1回目のデータパケット送受信を開始します。
今回の設定では、transmit Window Sizeが3.75msec、transmit Window Offsetが8.75msecに設定されています。
実際に接続要求終了から1回目のM->S(マスターからスレーブへの通信)が始まるまでの時間を見ると10.992msecになっているので、3.75+8.75=12.5msec以内に開始できています。
また、Interval×1.25msec = connInterval sizeです。
connIntervalは、マスター(central)からスレーブ(peripheral)へデータパケットが送信されてから、次のマスター(central)からスレーブ(peripheral)の転送が開始されるまでの周期を意味します。
ちなみに仕様書ではM->SとS->Mの送受信をコネクション・イベントと呼んでいます。
今回の設定では、connInterval は30msecに設定されています。
実際に1回目のM->Sが終了してから、2回目のM->Sが開始するまでの時間が279+29,720=29,999usecで、connInterval設定値の約30msecとほぼ等しくなっているのが確認できます。
・Latency
Latency(connSlaveLatency)はスレーブがマスターからのデータ送信を無視できる回数のことです。
これは消費電力削減のための仕組みです。
スレーブ側に送信すべきデータがない時、それにも関わらずデータ送信するのは電力の無駄です。だからスレーブにデータがなければ、M->Sを無視して、S->Mのデータ送信をしない方が電力節約になります。それならばスレーブにデータがない時は常にマスターからの送信を無視すればいいと考えるかもしれません。
ですが、そうすると困ることがあります。スレーブ側からの反応がない場合、マスターはスレーブが意図的に無視しているのか、それとも接続が切断されてしまったのかを区別できないからです。
そのため、スレーブはデータがなくても、いつかはマスターにデータ送信をする必要があります。 そのいつかが、いつであるかを決める設定がLatencyです。
スレーブにデータがないときは、Latencyに設定した回数だけM->Sを無視し、Latency+1回目のM->Sはデータの有無に関わらず必ずS->Mのデータ送信をします。
今回は設定値が0なのでスレーブは1回たりともM->Sを無視しません。
以下において具体的な数値での計算例が提示されているのでご参照ください。
http://reinforce-lab.github.io/blog/2013/08/13/blebook-ch2-ble-spec/
・Timeout
マスターがスレーブからデータを受信してから、Timeout時間が経過してもスレーブから次のデータ送信がない場合、マスターは接続が切断されたと判定します。
この値は最小でも(Latency + 1)回×1.25msecである必要があります。つまり、スレーブがデータ送信を無視できる回数分の時間を、マスターは必ず待ってやります。
ですがこの計算値ギリギリでは、設定時間を目一杯使った直後のM->S通信に失敗すると、やり直す間もなく通信切断となってしまいます。
そこで設定値は最小値に余裕を持たせた値にします。
ここではLatencyが0だったので、そういうことは考慮する必要もなく、72×1.25msec = 90msecが設定されています。
もしここでLatencyが10だったりしたら、(10+1)×1.25+90=103.75msecにしたりするわけです。(推奨設定値は(Latency + 1)回×1.25msec×6だそうです。)
・ChM
データパケット転送に使用可能なchを選択します。
GAPの解説記事でも書いたようにadvertisingパケットの転送には37ch,38ch,39chを使用し、データパケットの転送には0ch~36chの37個を使用します。
ChMはLSB、つまり1bit目が0chを意味し、37bit目が36chを意味します。各bitを1に設定すると、対応するchを使用します。0なら使用禁止です。
今回は37bitsの全てが1なので全chを使用します。
・Hop
コネクション・イベントでは、毎回同じchの周波数を使用しません。M->S、S->Mの通信が終わると、次のM->S、S->Mの通信では別chを選択します。
これにより他周波数との干渉を避けやすくなります。頻繁に通信周波数を変更することで周波数が重複しにくくなり、例え重複してもすぐに切り替わるので重複期間が一瞬で済むようになります。
この周波数の切り替えをどのように行うかを設定するのがHop(hopIncrement)です。
計算は (次回のch) = (今回のch + Hop )mod 37です。modは剰余のことです。
実際に上の例ではch=0x0Dの次のchは、(0x0D+0x0D)% 37 = 0x1A になっています。
・SCA
マスターのスリープクロックの精度です。
BLUETOOTH SPECIFICATION Version4.1 [Vol6] 2.3によれば、0x05は31~50ppm(百万分の1)になります。
BLEの時間を計る発振回路は高精度ですが、わずかなずれがあります。このずれを放置すると、ずれが蓄積してパケットの送受信ができなくなってしまいます。
これを回避するため、マスターがパケットを送信するとき、スレーブはこのずれの分だけ受信時間を前にずらします。そのずれの値がSCAのようです。(詳しく調べていないので間違っている可能性があります。) このようにAdvertisingの最終段階である接続要求では、以降のデータパケットの送受信の設定やタイミングを決めています。
次回はデータパケットの送受信について解析します。