2015年12月31日木曜日

RaspberryPi で温度センサー + MCP3002 を使って室内の温度を計測してみた

概要

アナログ温度センサー + MCP3002 を使って室内の温度を計測してみました
RaspberryPi はアナログ温度センサーのアナログ信号を直接受け取ることはできません
そこで、A/Dコンバータである MCP3002 を使ってアナログ信号をデジタル信号に変換し RaspberryPi で取得します

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+
  • Python 2.7.9
  • pip 7.1.2
  • spidev 3.1

SPI を有効にする

RaspberryPi の SPI (Serial Peripheral Interface Bus) を有効にします
デフォルトでは無効になっているので有効にして再起動する必要があります

SPI を有効にすることで A/D コンバータ (MCP3002) を使うことができるようになります

  • sudo cp /boot/config.txt{,.back}
  • sudo vim /boot/config.txt

以下のような差分になるように修正します

48c48
< dtparam=spi=on
---
> #dtparam=spi=on

dtparam=spi という項目があるので、それをコメントアウトすれば OK です
コメントアウトしたら RaspberryPi を一旦再起動します

  • sudo reboot

再起動したら SPI が有効になっているか確認します

  • lsmod | grep spi
spi_bcm2835             7980  0

上記のようになっていれば OK です

spidev をインストールする

spidev は Python 用の SPI ライブラリです
pip を使ってインストールすれば OK です

  • sudo pip install spidev

配線

RaspberryPi とブレッドボードを使って配線します
実際の配線全体図は以下の通りです
rpi_temp_circuit.jpg

写真だと分かりづらいのでツールを使って書いた配線図は以下の通りです
rpi_temp_circuit_fritzing.png

ポイント

左上の三本足の黒いセンサーがアナログ温度センサーです
VDD と GND そして信号を出力する三本があります
平面左から VDD、出力、GND になります
順番を間違えずに配線する必要があります

真ん中から出力された信号を MCP3002 で受信します
受信するピンは決まっており MCP3002 の場合は 2 箇所 ( 2ch ) で受信することができます
今回は 1 つしかセンサーを使っていないので 1 ch 使えば OK です

あとは MCP3002 の出力を RaspberryPi の SPI 用の GPIO で信号を受信すれば OK です
RaspberryPi 側で使用する SPI 用の GPIO は「CS0」「SCLK」「MISO」「MOSI」になります

配線が完了したら RaspberryPi の電源を入れましょう

ソースコードデプロイ

あとは受信したデータを表示するプログラムをデプロイすれば OK です

  • cd ~
  • mkdir -p work/mcp3002_temperature
  • cd work/mcp3002_temperature
  • touch temperature_sample.py
#!/usr/bin/env python

import time
import sys
import spidev

spi = spidev.SpiDev()
spi.open(0,0)

def readAdc(channel):
    adc = spi.xfer2([1, (2 + channel) << 6,0])
    data = ((adc[1] & 31) << 6) + (adc[2] >> 2)
    return data

def convertVolts(data):
    volts = (data * 3.3) / float(1024)
    volts = round(volts, 4)
    return volts

def convertTemp(volts):
    temp = (100 * volts) - 50.0
    temp = round(temp,4)
    return temp

if __name__ == '__main__':
    try:
        while True:
            data = readAdc(0)
            print("adc  : {:8} ".format(data))
            volts = convertVolts(data)
            temp = convertTemp(volts)
            print("volts: {:8.2f}".format(volts))
            print("temp : {:8.2f}".format(temp))

            time.sleep(5)
    except KeyboardInterrupt:
        spi.close()
        sys.exit(0)

実行してみましょう

  • python temperature_sample.py

でうまく配線できていれば以下のように出力してくれます

adc : 222
volts: 0.72
temp : 21.54
adc : 219
volts: 0.71
temp : 20.58

温度は一番したの 21.54, 20.58 になります
摂氏で出力するようにプログラムしています

ポイントは readAdc でここで spidev を使って変換したアナログ信号をデジタル信号で取得します
実行した際の adc がその値になります
今回使っている MCP3002 は 10 bit 2ch の A/D コンバータでデジタル信号に変更すると 0 - 1024 の範囲 ( 10bit の範囲 ) で値を変換してくれます
最近だと 12bit の A/D コンバータもありビット数が増えれば増えるほどより精度の高い信号を取得できるようになります

最後に

MCP3002 という A/D コンバータを使ってアナログ信号をデジタル信号に変換してみました
センサー系のデバイスは基本的にアナログ信号で受信するしかないので A/D コンバータが必須になります
次は圧力センサーの値でも取得してみたいと思います

参考サイト

2015年12月24日木曜日

Windows7 で Apple の Magic Keyboard を使ってみた

概要

Apple の新しいWireless キーボードである Magic Keyboard を Windows7 で使ってみたのでその設定方法について紹介します

環境

Magic Keyboard を接続する

とりあえず Windows7 と接続して使えるようにしてみましょう

1. Windows7 に USB の Bluetooth ドングルを接続する

USB のレシーバを接続すると自動でドライバのインストールが始まるのでインストールが完了すれば OK です

2. Magic Keyboard の電源を ON にする

Magic Keyboard の電源は側面上部にあります
スライド式で右にスライドすると電源が ON になります
電源が ON なのか、充電状況はどうなのか、充電中なのかをどうやって確認すればいいのかがわかりませんでした
とりあえず購入した直後は Lightning ケーブルを挿して充電しながら作業しました

3. Magic Keyboard を Windows7 に認識させる

あとは Windows7 側でスキャンしてキーボードを接続すれば OK です

ドングルが使えるようになるとタスクトレイに Bluetooth のアイコンが出現します
select_icon.png

アイコンを右クリックして「デバイスの追加」を選択します
add_device.png

デバイスの追加画面になるとスキャンが始まります
先ほど Magic Keyboard の電源を ON にしているのでしばらくすると Windows7 が Magic Keyboard を認識すると思います
認識したらデバイスを選択して「次へ」を選択します
select_device.png

PIN コードを確認する画面になります
どうやら Magic Keyboard とペアリングする場合は Magic Keyboard 側で発行されている PIN コードを Windows7 で確認する感じみたいです
とはいえ、 Magic Keyboard 側で発行されている PIN コードが何かわからないのでとりあえず「次へ」を選択すれば大丈夫です
pairing.png

これで Windows7 と Magic Keyboard のペアリングは完了です
おそらくこの段階でキーボードとして使えるようになっていると思います

US 配列用の設定

自分の場合 Windows7 側の PC はノート PC でキー配列は日本語配列のキーボードになっています
なのでこの状態で US 配列の Magic Keyboard を接続すると日本語配列として認識されてしまいます

自分は US 配列として Windows7 に認識させるために yamy を使っています
プラス Magic Keyboard をより Windows7 で使いやすくするために以下の設定を追加しました
※ Caps <- -> Ctrl の切り替えは別のキーマップツールを使っています

mod          windows         -= LeftWindows
mod          alt             += LeftWindows
key          *LeftWindows    = *LeftAlt
def subst    *RightWindows   = $ToggleIME
def subst    *RightAlt       = *Insert

これを 104on109.mayu ファイルに追記してあげています
やっていることは以下の通り

  • 左 Command ボタンを Alt キーに変更
  • 右 Command ボタンを IME 切り替えトグルに変更
  • 右の Alt キーを Insert キーに変更

その他困ったことなどをメモ

  • Windows キーを押したい場合
    今回の yamy で左右の Command キーを別のキーに割り当てたので Windows キーがなくなってしまいました (デフォルトだと Command キーが Windows キーに割り当てられている)
    どうしても押したい場合は別のキーに割り当てるしかないと思います
    ただ、複合キー (別のキーと一緒に押すこと)にするとなぜか Windows キーとして認識されるみたいで Command + r でファイル名実行が起動しました
    -> 「def subst *LeftWindows = ESC」だとその挙動になりましたが、Alt キーにバインドするようになってからできなくなりました
    ただ、右 Command + r は動作するので、それで代用するといいと思います
    ( おそらく、キーのバインドの定義によって同時押ししたときには、変更を反映させないみたいな定義方法があり、それで定義しているためだと思います、、、詳しくは調べてみないとわからないです、、、すいません)

  • Delete キーが BackSpace になっているため Delete キーがない
    本来であれば Mac の挙動として Fn キー+ Delete キーでカーソルの後の文字列も消せるのですが、どうやら Fn キーがうまく動作していないみたいでそれができません
    https://discussions.apple.com/thread/7283262?tstart=0
    場所的には Eject キーが Delete キーの場所としてピッタリのなのですが、 Eject キーもうまく認識されず置き換えもできない状況でした
    なので、これもやろうとしたら別の使わないキーに Delete を割り当てる必要があります

  • Insertキーがうまく動作しない
    動作するようになりました
    def subst *RightAlt = Insert

    def subst *RightAlt = *Insert
    と記載する必要がありました
    理由は不明ですがうまく動作しませんでした
    うまく動作しないというのは具体的に Cygwin 上での話なのですが、Cygwin 上で Shift + Insert は貼り付けなのですがそれがうまく動作しませんでした
    キーを押した時の挙動だとちゃんとInsertとして認識されているみたいなのですが、Shift と合わせて押すと意図した動作になりませんでした

感想

やはり Mac 用に作られたキーボードなので思い通りに動かない部分はある感じです
特に US 配列の Magic Keyboard を Windows で使うとキーが足りずに普段使わないキーに使いたいキーを割り当てるなどしないとダメだと思います
そうなると本当はいつもそこにあるキーが、Magic Keyboard で作業するとないということになり逆に作業効率が下がるような気もします

とは言えキーストロークは最高です

2015年12月21日月曜日

CentOS で LuaRocks のインストールと簡単な使い方

概要

LuaRocks という Lua 言語用のパッケージ管理ツールがあります
CentOS 上でインストールして簡単に使ってみたので紹介します

環境

  • CentOS 6.7 64bit Final
  • Lua 5.1.4
  • LuaRocks 2.1.2

LuaRocks のインストール

Epel を使えるようにすれば yum コマンドでインストールすることができます
開発用の devel パッケージもインストールします

  • rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
  • yum -y install lua-devel
  • yum -y install luarocks

ライブラリのインストール

ここではサンプルとして暗号化ツールの luacrypto をインストールしてみます

  • luarocks install luacrypto

でインストール完了です
自分の環境では何も指定しない状態だと /usr/lib/luarocks/rocks/luacrypto/ にインストールされました

インストールしたライブラリが使えるか確認する

  • eval `luarocks path`
  • lua

でまずはライブラリを使えるようにします
あとは lua コマンドのインタラクティブモードで試していきます

> require "crypto"
> crypto.hmac.digest('sha256', "hoge", "fuga", false)
> digest = crypto.hmac.digest('sha256', "hoge", "fuga", false)
> print(digest)
4a68986307d6d29a8060f2e6a6394f29ddd8b4e5a0d9694c886bd400922c0841

こんな感じで使うことができます
require するときのパッケージ名が install 時のパッケージ名と違うのに注意が必要です
require 時のパッケージ名は luarocks show luacrypto で Modules という項目に書かれたパッケージ名を使えば OK です

Tips

  • パッケージが存在しないというエラーが出た

> require “crypto”
stdin:1: module ‘crypto’ not found:
no field package.preload[‘crypto’]
no file ‘./crypto.lua’
no file ‘/usr/share/lua/5.1/crypto.lua’
no file ‘/usr/share/lua/5.1/crypto/init.lua’
no file ‘/usr/lib64/lua/5.1/crypto.lua’
no file ‘/usr/lib64/lua/5.1/crypto/init.lua’
no file ‘./crypto.so’
no file ‘/usr/lib64/lua/5.1/crypto.so’
no file ‘/usr/lib64/lua/5.1/loadall.so’
stack traceback:
[C]: in function ‘require’
stdin:1: in main chunk
[C]: ?

インストールしたライブラリに対してパスが通っていないことがほとんどです
luarocks path で export したパスにインストールしたライブラリがあるか確認してください
ない場合はイントールしたパスを LUA_PATH と LUA_CPATH に設定してください

  • Nginx 上の Lua スクリプトで使いたい場合

Lua 上でパスを通せば OK です
以下をライブラリを使いたい Lua スクリプトの先頭に記載してください

local p = "/usr/lib/luarocks/rocks/"
local m_package_path = package.path
package.path = string.format("%s?.lua;%s?/init.lua;%s?/init.lua;%s", p, p, p3, p3, m_package_path)

2015年12月18日金曜日

lua-resty-libcjson をインストール

概要

Nginx + Lua スクリプト内で JSON 情報を扱うために lua-resty-libcjson というライブラリを追加してみました

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3
  • lua-resty-libcjson 5260553b26a264c1cfb27bcd1b9c28d117f05b8f
  • cJSON 67d3c7fbc705e82e97baf22d35aa8abfddbe2d3e

インストール

lua-resty-libcjson のインストール

まずは Lua スクリプト用のライブラリをインストールします

Lua のライブラリは /usr/local/openresty/lualib/resty にインストールしていますが、お好きなところにインストールして OK です

cJSON のインストール

cJSON とはその名の通り C/C++ で JSON を扱えるようにするためのライブラリです
ソースをダウンロードしてコンパイルして共有ライブラリ ( .so ) ファイルを作成する必要があります

共有ライブラリのパスはすでに通っているパスに配置してください
独自のパスに配置した場合は ldconfig 等を使ってパスを通してから Nginx を起動してください

サンプル

  • json_sample.lua
local p = "/usr/local/openresty/lualib/"
local m_package_path = package.path
package.path = string.format("%s?.lua;%s?/init.lua;%s", p, p, m_package_path)

local json = require "resty.libcjson"
local str = json.encode({key = "value"}, false)
ngx.log(ngx.ERR, str)
  • ログ
    • tail -f /opt/nginx/logs/error.log

2015/12/18 12:23:39 [error] 11875#0: *1 [lua] json_sample.lua:47: main(): {“key”:”value”}, client: 127.0.0.1, server: localhost, request: “GET /hoge HTTP/1.1”, host: “localhost”

テーブル情報を JSON 文字列に変換するサンプルです

はじめに lua-resty-libcjson を配置したパスを package.path に追加します
追加に成功していれば require してライブラリを読み込みます
パスがうまく通っていない場合、require に失敗します

テーブルから JSON の文字列を取得するには json.encode を使用します
第一引数にテーブル情報を与えて第二引数には JSON をフォーマットするかの boolean を与えます
true を指定すると改行コードやタブ文字が入った情報が取得できます
JSON 文字列からテーブル情報を取得する場合は json.decode を使用してください

2015年12月16日水曜日

lua-nginx-module でサンプルの lua スクリプトを試してみた

概要

前回 Nginx + lua-nginx-module のインストール方法を紹介しました
今回は簡単なサンプルの挙動を確認してみます

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3

サンプルの Lua スクリプト作成

  • touch /opt/nginx/lua/sample.lua
  • vim /opt/nginx/lua/sample.lua
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = "application/json"
ngx.say('{"code": "E401001", "error": "Authentication error by header incorrect."}')
ngx.exit(ngx.HTTP_OK)

今回は、認証エラーを返却する lua スクリプトを作成しました
ステータスを設定 (ngx.status) して、Content-type を設定 (ngx.header.content_type) してレスポンスボディを設定 (ngx.say) して、スクリプトを終了しています
最後の ngx.HTTP_OK は 200 以上のステータスを設定すれば OK です
200 以上のステータスを設定した場合はリクエスト全体のレスポンスを返却し、200 未満の場合はそのスクリプトが実行されているフェーズだけが終了され、次の処理に進みます

Lua スクリプトを呼び出す

  • vim /opt/nginx/conf/nginx.conf
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    access_by_lua_file "/opt/nginx/lua/sample.lua";
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass   http://www.kakakikikeke.blogspot.jp/;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

nginx.conf はデフォルトのものからコメントアウトを削除した設定を使用しています
http ブロック内で先ほど作成した Lua スクリプトを access_by_lua_file を使ってコールします
これで各リクエストが来た時に必ず Lua スクリプトが呼ばれることになります

動作確認

今回のサンプルは Lua スクリプトを有効にしている場合は必ず認証エラー用の JSON が返ってくることになります

まず Lua スクリプトを有効にした状態で Nginx を起動しましょう
その状態でリクエストしてみると

> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost
> Accept: */*
> 
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.9.3
< Date: Mon, 14 Dec 2015 02:16:19 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< 
{"code": "E401001", "error": "Authentication error by header incorrect."}

こんな感じで先ほど設定した Json が返却されます

では、次に nginx.conf で呼び出した Lua スクリプトをコメントアウトして Nginx を再起動してください
すると次は認証エラーにはならず HTML が返ってくることが確認できると思います

最後に

簡単なサンプルを試してみました
リクエストのヘッダ情報やボディ情報を取得することができるので簡単な認証フィルタを作成したいのであれば、Nginx だけでできるようになると思います
ただ、認証情報が MySQL や Redis 等のデータベースにある場合がほとんどだと思うので、その場合は DB にアクセスできる Lua ドライバを使う必要があります

この辺のドライバの使い方も今後試したいなと思っています

2015年12月15日火曜日

lua-resty-mongol を使って Nginx から MongoDB を操作してみた

概要

Nginx 上で Lua スクリプトを動作させる環境を構築しました
http://kakakikikeke.blogspot.jp/2015/12/nginx-with-lua-nginx-module.html

今回は更に拡張して Lua スクリプトから MongoDB を操作できるようにしてみたいと思います

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3
  • lua-resty-mongol 682ad317f0d3451308a2a953fef80fbad1de872d

lua-resty-mongol のインストール

/usr/local/openresty/lualib/resty/mongol/ に必要な Lua スクリプトがインストールされました

lua-resty-string のインストール

/usr/local/lib/lua/resty/ に必要な Lua スクリプトがインストールされました

nginx.conf の修正

MongoDB に接続するためのサンプルの Lua スクリプトを実行するように修正します

access_by_lua_file "/opt/nginx/lua/connect_db.lua";

nginx.conf でインストールした各種ライブラリを読み込むこともできますが、今回は Lua スクリプト側でライブラリの読み込みを行います

Lua スクリプトの作成

  • cd /opt/nginx/lua
  • vim connect_db.lua
local p = "/usr/local/openresty/lualib/"
local p2 = "/usr/local/lib/lua/"
local m_package_path = package.path
package.path = string.format("%s?.lua;%s?/init.lua;%s?.lua;%s?/init.lua;%s", p, p, p2, p2, m_package_path)

local function test_connect()
   local mongol = require "resty.mongol"
   local conn = mongol:new()
   conn:set_timeout(1000)
   local ok, err = conn:connect("127.0.0.1", 27017)
   if not ok then
      raise_error(ngx.HTTP_INTERNAL_SERVER_ERROR, '{"code": "E500001", "error": "Auth System error."}')
   end
   local db = conn:new_db_handle("test")
   local col = db:get_col("test_col")
   local r = col:find_one({key=value})
   ngx.log(ngx.ERR, r["key"])
end

local function main()
   test_connect()
end

main()

簡単にポイントを紹介します

まず、スクリプト冒頭でライブラリのパスを指定します
今回は別々のパスにインストールされたので、2 つのパスを読み込むように設定します
もし、一箇所にインストールした場合は 1 つのパスだけ設定すれば OK です
Lua スクリプトのインストールパスが違う場合は変更してください

connect する場合の引数は IP アドレス + ポート番号になります
ホスト名でも指定できるのですが、Nginx が名前解決できない場合があるので IP で指定すると確実です

あとはサンプル通り DB 接続、Collection 接続、データ取得の流れになります

その他のメソッドは細かい仕様については公式 の README.md を見るといいと思います
あとはソースもそこまで難しくないのでソースを見ても理解できると思います

最後に

これで Nginx だけで MongoDB にアクセスできるようになりました

まだガッツリと触っていないのと複雑な処理まで実装していないので、何とも言えませんが完成したら負荷テストなどでどれくらい処理性能があるかと DB への負荷が掛かるかは確認したほうがいいかもしれません

2015年12月14日月曜日

Nginx with lua-nginx-module のインストール

概要

Nginx 上で lua スクリプトを実行することができる lua-nginx-module をインストールしてみました
Nginx も一からインストールしているので既存の Nginx は一度アンインストールしてから行っています

環境

  • CentOS 6.7 64bit Final
  • LuaJIT 2.0.4
  • ngx devel kit 0.2.19
  • lua-nginx-module 0.9.19
  • nginx 1.9.3

事前準備

yum でインストールした既存の nginx を削除

  • yum remove nginx.x86_64

PCRE (Perl Compatible Regular Expressions) のインストール

正規表現を扱うためのパッケージをインストールします

  • yum -y install pcre-devel gcc openssl openssl-devel

インストール

LuaJIT インストール

  • cd /root/work
  • wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz
  • tar zvxf LuaJIT-2.0.4.tar.gz
  • cd LuaJIT-2.0.4
  • make
  • make install
  • luajit -v

ngx devel kit のダウンロード

  • cd /root/work
  • wget https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
  • tar zvxf v0.2.19.tar.gz

lua nginx mode のダウンロード

  • cd /root/work
  • wget https://github.com/openresty/lua-nginx-module/archive/v0.9.19.tar.gz
  • tar xvzf v0.9.19.tar.gz

nginx のインストール

  • cd /root/work
  • wget 'http://nginx.org/download/nginx-1.9.3.tar.gz'
  • tar -xzvf nginx-1.9.3.tar.gz
  • cd nginx-1.9.3/
  • export LUAJIT_LIB=/usr/local/lib
  • export LUAJIT_INC=/usr/local/include/luajit-2.0
  • ./configure --prefix=/opt/nginx --with-http_ssl_module --with-ld-opt="-Wl,-rpath,/usr/local/lib" --add-module=/root/work/ngx_devel_kit-0.2.19 --add-module=/root/work/lua-nginx-module-0.9.19
  • make -j2
  • make install

configure 時の各種パスは絶対パスで記述してください
https 用のモジュールもついでにインストールしておきます

動作確認

  • 起動

/opt/nginx/sbin/nginx

  • ログ確認

/opt/nginx/logs/access.log

  • 停止

/opt/nginx/sbin/nginx -s stop

最後に

これで nginx.conf 内に lua スクリプトが書けるようになりました
次回は実際に lua スクリプト書いてリクエストやレスポンスを操作してみたいと思います

参考サイト

2015年12月11日金曜日

SDK for NFC を使って Pasori でカード情報を読み込んでみた

概要

Pasori は Sony が提供する Ferica 用の IC カードリーダでよく目にするやつだと Edy のチャージなどに使います
SDK for NFC というこれまた Sony が提供する SDK がありこれを使うと Pasori を使っていろいろな IC カードの情報を読み込んだり書き込んだりすることができます
今回は SDK を使った簡単なサンプルを作成してみました

環境

  • Windows7 64bit
  • Felica RC-S320
  • Microsoft Visual Studio Express 2015 Community 14.0.24720.00 Update 1
  • SDK for NFC 2.0.3

Visual Studio のインストール

詳細はこちらを御覧ください
SDK for NFC に含まれる nfc 用のライブラリを使うのですが、これが .lib ファイルという形式で提供されているため Visual Studio が必要になります
自分もよくわかっていないのですが、 .lib ファイルをリンカーとして登録して実行するには普通の gcc が実行できる環境だけではダメなようです

SDK for NFC のダウンロードとインストール

ダウンロードは以下のリンクからできます
http://www.sony.co.jp/Products/felica/business/products/ICS-D004_002_003.html

sdk4nfc_starter203J.zip をダウンロードしたら解凍して、Cドライブ直下に保存します

C:\sdk4nfc_starter203J

あとは Pasori 用のドライバをインストールしましょう
SDK 内に含まれている exe ファイルを実行すれば OK です
C:\sdk4nfc_starter203J\driver\NFCPortWithDriver.exe がそれになるのでを実行してドライバをインストールしてください
ドライバをインストールしたら一度再起動したほうが良いと思います

プロジェクトの作成と各種ライブラリの追加

Visual Studio を起動してプロジェクトを作成しましょう
作成するプロジェクトの種類は「Visual C++ -> Windows -> 全般 -> 空のプロジェクト」で OK です

プロジェクトを作成したインクルードパスとリンカーの設定をしましょう

インクルードパスの設定

プロジェクトのプロパティを開きます

C/C++ -> 全般 -> 追加のインクルードディレクトリ -> 編集

で追加ダイアログを開いて

新しい行 -> 参照ボタン

で以下のパスを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\include
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\include

追加できたら OK -> 適用しましょう

リンカーの設定

プロジェクトのプロパティを開きます

リンカー -> 入力 -> 追加の依存ライブラリ -> 編集

で追加のダイアログを開いて以下のライブラリを追加します

  • C:\sdk4nfc_starter203J\FeliCa_Library\lib\x86\felica.lib
  • C:\sdk4nfc_starter203J\NFCAccessLibrary\lib\x86\felica_nfc_library.lib

追加できたら OK -> 適用でプロパティを閉じましょう

ソースファイルの追加

ソースファイルをプロジェクトに追加します

プロジェクトを右クリック -> 追加 -> 新しい項目

で追加ダイアログを開いて

Visual C++ -> C++ ファイル (.cpp) -> 追加

でソースファイルを追加しましょう
デフォルトだと Source.cpp というファイルが追加されます

追加できたら早速サンプルコードを記載しましょう
コードの全容は以下の通りです

#include <cstdio>
#include <cstdlib>

#include "felica.h"

int main(void);
void error_routine(void);
void print_vector(char* title, unsigned char* vector, int length);

int main(void)
{
    if (!initialize_library()) {
        fprintf(stderr, "Can't initialize library.\n");
        return EXIT_FAILURE;
    }
    printf("Complete initialize_library\r\n");

    if (!open_reader_writer_auto()) {
        fprintf(stderr, "Can't open reader writer.\n");
        return EXIT_FAILURE;
    }
    printf("Complete open_reader_writer_auto\r\n");

    structure_polling polling;
    unsigned char system_code[2] = { 0xFF, 0xFF };
    polling.system_code = system_code;
    polling.time_slot = 0x00;

    unsigned char number_of_cards = 0;

    structure_card_information card_information;
    unsigned char card_idm[8];
    unsigned char card_pmm[8];
    card_information.card_idm = card_idm;
    card_information.card_pmm = card_pmm;

    unsigned long timeout;
    get_polling_timeout(&timeout);
    printf("timeout: %lu\r\n", timeout);
    timeout = 2000;
    set_polling_timeout(timeout);

    if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
        fprintf(stderr, "Can't find FeliCa.\n");
        return EXIT_FAILURE;
    }

    fprintf(stdout, "number of cards: %d\n", number_of_cards);

    print_vector("card IDm:", card_idm, sizeof(card_idm));
    print_vector("card PMm:", card_pmm, sizeof(card_pmm));

    if (!close_reader_writer()) {
        fprintf(stderr, "Can't close reader writer.\n");
        return EXIT_FAILURE;
    }

    if (!dispose_library()) {
        fprintf(stderr, "Can't dispose library.\n");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

void error_routine(void) {
    enumernation_felica_error_type felica_error_type;
    enumernation_rw_error_type rw_error_type;
    get_last_error_types(&felica_error_type, &rw_error_type);
    printf("felica_error_type: %d\n", felica_error_type);
    printf("rw_error_type: %d\n", rw_error_type);

    close_reader_writer();
    dispose_library();
}

void print_vector(char* title, unsigned char* vector, int length) {
    if (title != NULL) {
        fprintf(stdout, "%s ", title);
    }

    int i;
    for (i = 0; i < length - 1; i++) {
        fprintf(stdout, "%02x ", vector[i]);
    }
    fprintf(stdout, "%02x", vector[length - 1]);
    fprintf(stdout, "\n");
}

SDK に含まれているサンプルのソースコードをほぼ流用しています
C:\sdk4nfc_starter203J\sample\FeliCa_Library\sample_06.cpp

サンプルコードの説明

以下ポイントを説明していきます

main メソッドの一番初めで NFC ライブラリの初期化をしています

if (!initialize_library()) {
    fprintf(stderr, "Can't initialize library.\n");
    return EXIT_FAILURE;
}

初期化が完了したら接続されている Pasori をオープンします
なので、これを実行するときに Pasori がパソコンに接続されて、正常に動作する状態になっている必要があります

if (!open_reader_writer_auto()) {
    fprintf(stderr, "Can't open reader writer.\n");
    return EXIT_FAILURE;
}

もし、Pasori が接続されていなかったりドライバインストールされていなくてうまく動作しない場合はここでエラーになります

カードのスキャンをスタートする前に Pasori がスキャンする時間を設定してます

unsigned long timeout;
get_polling_timeout(&timeout);
printf("timeout: %lu\r\n", timeout);
timeout = 2000;
set_polling_timeout(timeout);

デフォルトだと 100 ms しかスキャンしないので、カードを乗せた状態で実行しないと検知してくれません
なので、今回は少しスキャンに余裕を持たせて 2 秒間スキャンするようにしました

このあとでスキャンを開始します

if (!polling_and_get_card_information(&polling, &number_of_cards, &card_information)) {
    fprintf(stderr, "Can't find FeliCa.\n");
    return EXIT_FAILURE;
}

スキャンに成功してカードの情報が取得できると引数として渡している card_information に値が設定されます

それをその後で参照します

print_vector("card IDm:", card_idm, sizeof(card_idm));
print_vector("card PMm:", card_pmm, sizeof(card_pmm));

最後に処理が完了したので終了処理をしています

if (!close_reader_writer()) {
    fprintf(stderr, "Can't close reader writer.\n");
    return EXIT_FAILURE;
}

if (!dispose_library()) {
    fprintf(stderr, "Can't dispose library.\n");
    return EXIT_FAILURE;
}

このあたりでコールしている関数の詳細は SDK に付属の pdf を参照するといいと思います
C:\Users\username\Downloads\sdk4nfc_starter203J\sdk4nfc_starter203J\doc\FeliCa_Library\M735_FeliCaLibrary_StarterKit_1.3j.pdf

ビルドして実際に試してみる

ソースを記載したビルドしましょう
プロジェクトを選択した状態で

ビルド -> ソリューションのビルド

でビルドが成功すれば OK です
失敗する場合はインクルードパストリンカーの設定を再度見なおしてください
今回の場合だと大抵はライブラリの読み込みに失敗してビルドが失敗します

コマンドプロンプトを開いて実際に実行してみましょう
実行するまでに Pasori を PC に接続してください

C:\Users\username\Documents\Visual Studio 2015\Projects\Project2\Debug>Project2.exe

で Pasori のスキャンがはじまります
今回はスキャンが 2 秒なのであらかじめ IC カードを置いておくといいと思います
スキャンに成功するとカードの IDm という識別番号が表示されると思います

自分は Pasumo がうまくスキャンできて IDm が取得できることは確認しました

最後に

今回スキャンして IDm を表示するとこまでやってみました
Pasumo の場合は乗車履歴とかも書き込まれているようで、それも取得できるみたいなので、次はそこまでやってみたいです
あとは、読み込みだけじゃなくて IC カードへの書き込みもやってみたいなと思います

ライブラリにはもう一つ lite 版というのがあり、関数とかの先頭に「felica_」がついた版があります
自分は初め lite 版を使っていたのですが、どうしても「 felicalib_nfc_open」で Pasori をオープンするところでこけてしまい、lite 版をあきらめました
これは予想ですが、Pasori のバージョンが RC-S320 というだいぶ古いバージョンを使っていたので失敗したのかもしれません
S370 や S380 という比較的新しいバージョンの Pasori を使えば lite 版でも動作するかもしれません

2015年12月10日木曜日

Visual Studio Express 2015 Community バージョンをインストール

概要

タイトルの通りですが、Windows7 に Visual Studio 2015 をインストールしてみました
結構はまったのでメモしておきます

環境

  • Windows7 64bit
  • Microsoft Visual Studio Express 2015 Community 14.0.24720.00 Update 1
  • Microsoft .NET Framework 4.6.01055

インストール方法

インストーラをダンロードできるダウンロードサイトにいきます
https://www.visualstudio.com/ja-jp/products/visual-studio-express-vs.aspx

ダウンロードできた「vs_community_JPN.exe」をクリックしインストールを開始します

IE のバージョン 10 以上がインストールされていないと警告が表示されます
特に気にせず次に進みます
install_vc_step1.png

インストール方法を選択します
ここでは必ず「カスタム」を選択しましょう
install_vc_step2.png

インストール機能を選択します
「すべて選択」のチェックボックスがあるのでチェックします
自分の場合はすべてインストールするのに 32GB 必要と言われました
他のマシンでインストールしたときは 23GB 必要と言われたので環境によってはすでに必要な機能がインストールされており、必要な容量が少なく表示されるのだと思います
それにしても 32GB も必要というのは IDE としてちょっとありえないかなと思います
install_vc_step3.png

あとは確認画面を確認してインストールすれば OK です
install_vc_step4.png

さらっと書きましたがインストールまでに数時間平気でかかります
自分は正確に測っていませんが 3 時間以上かかったと思います
install_vc_step5.png

無事インストールが完了したら Visual Studio を起動しましょう
一応起動するときもポイントなのですが、起動するためのファイルが 2 種類あるみたいで「Blend for Visual Studio 2015」と「Start Experimental Instance of Visual Studio 2015」があり、後者を起動しましょう
起動も結構長いので気長に起動を待ってください

コンソールアプリケーションのサンプルプロジェクト作成

簡単なサンプルプロジェクトの作成までやってみましょう
初回起動時は開発する言語やカラーテーマを選択するように言われると思います
開発する言語は「全般」を選択しましょう
カラーテーマは好きなのを選択してください
( すいません、ここのスクリーンショットを撮るのを忘れました )

あと確か Microsoft アカウントでログインも求められると思います
これも任意なのでどちらでも OK です
アカウントがない場合は「後で登録する」みたいな文言のボタンがあったと思うのでそれを選択すれば OK です

起動したら「新しいプロジェクト」を選択します
vs_new_project.png

テンプレートを選択するダイアログが表示されるので

インストール済み -> テンプレート -> Visual C++ -> Windows -> Win32 -> Win32 コンソールアプリケーション

を選択しましょう
vs_select_template.png

プロジェクトの作成がはじまります
アプリケーションウィザードが表示されますが、どんどん進んでいけば OK です
プロジェクトはデフォルトだと「C:\Users\Username\Documents\Visual Studio 2015\Projects」に保存されます

プロジェクトが作成できたらソースファイルを追加しましょう

ソースファイルが作成できたら以下のサンプルコードを記載しましょう
そのままコピペでもいいと思います
ConsoleApplication1.cpp

#include "stdafx.h"

int main() {
    printf("Hello world");
    return 0;
}

記載できたらビルドしてみましょう
右ペインのソリューションエクスプローラーでプロジェクトを選択した状態で

ビルド -> ソリューションのビルド

でビルドできます
成功すれば OK です

これで exe ファイルも作成されているのでコマンドプロンプトで exe ファイルを実行してみてください
実行に成功すると「Hello world」と表示されるはずです

C:\Users\Username\Documents\Visual Studio 2015\Projects\ConsoleApplication1\Debug>ConsoleApplication1.exe
Hello world

はまったポイント

数々のはまったポイントを紹介します

  • Visual C++ の Win32 コンソールアプリケーションが新しいプロジェクト作成時に選択することができない

新しいプロジェクトを作成するときに

インストール済み -> テンプレート -> Visual C++ -> Windows -> Win32 -> Win32 コンソールアプリケーション

がなぜかありません

インストール済み -> テンプレート -> Visual C++ -> Windows -> ユニバーサル

しか選択できずにコマンドプロンプトで実行できる exe ファイルが作成できませんでした
ネットでいろいろ調べると、ちゃんとインストールできていないのが原因らしいとわかりました
ちなみに今となってはわかるのですが、一番はじめにインストールしたときにインストールを「標準」にしていたので、コントーロルパネル -> プログラムのアンインストールから「変更」で足りない機能を追加でインストールしたり、「修復」とか何度も試してみたのですが、結局どれもダメであきらめて再インストールをしました

再インストールするときにはカスタムインストールを選択して、はじめからフルインストールしました

  • 起動するアプリケーションの選択

これはインストール方法の部分でも書きましたが「Start Experimental Instance of Visual Studio 2015」から起動するようにしてください
調べてみると「Blend for」の方は Windows のデスクトップアプリなど GUI アプリを開発するための IDE のようでこれだと Win32 コンソールアプリケーションが作成できないようです
「Start Experimental Instance of Visual Studio 2015」これがすべてのプログラムから選択できない、もしくは存在しない場合はカスタムインストールに失敗している可能性が高いと思います

  • 最新版の IE をインストールする

自分は再インストールしたときに最新版の IE ( ver11) もインストールしました
その後カスタムインストールで必要な機能を全部インストールしたら無事インストールが完了しました
IE が絶対必要だとは考えられないですが、どうしてもうまくインストールできない場合はためしてみるのはありかなと思います

最後に

とにかく動作が重いので何をするにも忍耐が必要です

C や C++ の開発だけであれば別に Visual Studio を使う必要はありません
今回は .lib ファイルをリンカーにしたかったのと、Windows 向けのアプリを開発する必要があったのでどうしても Visual Studio が必要でした

にしても開発するだけなのにこれだけの時間とコストを使うのは割にあわないかなと、もう少し軽量で気軽に使える IDE を作ってほしいなと思いました

2015年12月4日金曜日

AllJoyn 触ってみた

概要

Alljoyn はスマホやデバイス間同士の近傍 P2P を実現するための規格です
元は Qualcomm がオープンソースとして公開した規格で現在は Linux Foundation の AllSeen Alliance という会社が仕切っているようです
今回は導入として iPhone 上で動作する AllJoyn のサンプルアプリを動作させるところまでやってみました

環境

  • Mac OS X 10.10.5
  • Xcode 7.1.1
  • OpenSSL 1_0_2d
  • Alljoyn 14.12.00
  • iPhone 5 ( iOS 7.0.2 )

SDK をビルドする

SDK はサイトからほいとダウンロードしていきなり使える感じではありません
自分でビルドして、できたスタティックライブラリを使っていきます

サイトから SDK をダウンロードする

まずはビルド元になる SDK をダウンロードします
https://allseenalliance.org/framework/download

ここから以下 5 つの iOS 用の zip をダウンロードしてください

  • Core SDK (alljoyn-14.12.00b-osx_ios-sdk.zip)
  • Onboarding SDK (alljoyn-onboarding-service-framework-14.12.00-ios-sdk-rel.zip)
  • Configuration SDK (alljoyn-config-service-framework-14.12.00-ios-sdk-rel.zip)
  • Notification SDK (alljoyn-notification-service-framework-14.12.00-ios-sdk-rel.zip)
  • Control Panel SDK (alljoyn-controlpanel-service-framework-14.12.00-ios-sdk-rel.zip)

ダウンロードが完了したら解凍して適切なパスに配置していきます

  • mkdir -p ~/work_alljoyn
  • cd ~/work_alljoyn
  • mkdir -p alljoyn-ios/core
  • unzip alljoyn-14.12.00b-osx_ios-sdk.zip
  • mv alljoyn-14.12.00b-osx_ios-sdk alljoyn-ios/core/alljoyn
  • unzip alljoyn-config-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-controlpanel-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-notification-service-framework-14.12.00-ios-sdk-rel.zip
  • unzip alljoyn-onboarding-service-framework-14.12.00-ios-sdk-rel.zip
  • pushd alljoyn-ios/

とりあえず問題なく解凍できればここは OK です
初めの work_alljoyn はお好きな名前で大丈夫です

openssl を使って SDK をビルドする

次に解凍した SDK を openssl を使ってビルドします
作業パスは前のコマンドのパスを引き継いでいる想定なので cd とかで移動しないでください

  • git clone git://git.openssl.org/openssl.git
  • git clone https://github.com/sqlcipher/openssl-xcode.git
  • cp -r openssl-xcode/openssl.xcodeproj openssl
  • pushd openssl
  • git checkout tags/OpenSSL_1_0_2d
  • sed -ie 's/\(ONLY_ACTIVE_ARCH.*\)YES/\1NO/' * openssl.xcodeproj/project.pbxproj
  • xcodebuild -configuration Release -sdk iphonesimulator
  • xcodebuild -configuration Release -sdk iphoneos
  • xcodebuild -configuration Release
  • xcodebuild -configuration Debug -sdk iphonesimulator
  • xcodebuild -configuration Debug -sdk iphoneos
  • xcodebuild -configuration Debug

ビルド時間は全部で 20 分くらいかかると思います
すべてビルドが問題なく完了すれば OK です

ビルドおよび Xcode で開発するための環境変数を設定します

ビルドが完了したら環境変数を設定します
ここで設定した環境変数は再起動するとなくなるので、必要な場合は Mac 自体に環境変数を設定してください
ここも作業パスは引き継いでいる想定なので移動せずそのまま作業してください

  • sudo launchctl setenv OPENSSL_ROOT `pwd`
  • export OPENSSL_ROOT=`launchctl getenv OPENSSL_ROOT`
  • popd
  • popd
  • cd alljoyn-ios
  • sudo launchctl setenv ALLJOYN_SDK_ROOT `pwd`
  • export ALLJOYN_SDK_ROOT=`launchctl getenv ALLJOYN_SDK_ROOT`
  • cd services
  • sudo launchctl setenv ALLSEEN_BASE_SERVICES_ROOT `pwd`
  • export ALLSEEN_BASE_SERVICES_ROOT=`launchctl getenv ALLSEEN_BASE_SERVICES_ROOT`

必要なスタティックライブラリを一箇所にコピーする

このあと Xcode でスタティックライブラリ (xxx.a のファイル) を参照するライブラリとして使うのですが、いろいろな場所にあり追加が面倒なので、一箇所にコピーします

結構あるのでコマンド長いです

  • DIST_PATH=”core/alljoyn/build/darwin/armv7/iphoneos/debug/dist/cpp”
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_config_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_controlpanel_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_notification_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/cpp/lib/liballjoyn_services_common_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_onboarding_services_common_cpp.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_config_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_controlpanel_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_notification_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/objc/lib/liballjoyn_services_common_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_onboarding_services_common_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/liballjoyn_about_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_debug_about_cpp.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/liballjoyn_about_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_release_about_cpp.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/liballjoyn_about_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_debug_about_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/liballjoyn_about_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/liballjoyn_release_about_objc.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/debug/dist/about/lib/libAllJoynFramework_iOS.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/libAllJoynFramework_iOS_debug.a
  • cp $ALLJOYN_SDK_ROOT/core/alljoyn/build/darwin/arm/iphoneos/release/dist/about/lib/libAllJoynFramework_iOS.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/libAllJoynFramework_iOS_release.a
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/cpp/lib/liballjoyn_config_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-config-14.12.00-rel/objc/lib/liballjoyn_config_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/cpp/lib/liballjoyn_controlpanel_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-controlpanel-14.12.00-rel/objc/lib/liballjoyn_controlpanel_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/cpp/lib/liballjoyn_notification_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-notification-14.12.00-rel/objc/lib/liballjoyn_notification_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/cpp/lib/liballjoyn_onboarding_cpp.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/
  • cp $ALLJOYN_SDK_ROOT/services/alljoyn-onboarding-14.12.00-rel/objc/lib/liballjoyn_onboarding_objc.a $ALLJOYN_SDK_ROOT/$DIST_PATH/lib/

これをやることで Xcode 上で Search Paths を設定するのも少し楽になります
この DIST_PATH はサンプルアプリを開いた時にデフォルトで Search Paths の対象になっています

Xcode の起動

今回 Xcode の起動方法も少しポイントです
環境変数をターミナルで設定している関係で Xcode の起動は環境変数を設定したターミナル上から起動してください

  • open -a xcode

でないと環境変数が xcode にわたらずビルドでエラーになります

Xcode でサンプルアプリを開く

今回開くサンプルアプリはチャットアプリを開きます

$ALLJOYN_SDK_ROOT/core/alljoyn/alljoyn_objc/samples/iOS/AllJoynChat/AllJoynChat.xcodeproj

上記を開きましょう

プロジェクトの設定をする

開いたらプロジェクトの設定を変更します
プロジェクトを選択し

Targets -> AlljoynChat -> Building Settings -> All

と選択して以下を設定していきます

  • Architectures -> Architectures -> Standard architectures (armv7, armv7s) を選択
  • Architectures -> Build Active Architecture only -> Yes を選択
  • Linking -> Other Linker Flags -> -lalljoyn -lajrouter -lBundledRouter.o -lssl -lcrypto を選択
  • Search Paths -> Header Search Paths -> + -> "$(ALLJOYN_SDK_ROOT)/core/alljoyn/build/darwin/arm/$(PLATFORM_NAME)/$(CONFIGURATION)/dist/cpp/inc""$(ALLJOYN_SDK_ROOT)/core/alljoyn/alljoyn_objc/AllJoynFramework/AllJoynFramework/" を追加
  • Search Paths -> Library Search Paths -> + -> "$(ALLJOYN_SDK_ROOT)/core/alljoyn/build/darwin/$(CURRENT_ARCH)/$(PLATFORM_NAME)/$(CONFIGURATION)/dist/cpp/lib""$(OPENSSL_ROOT)/build/$(CONFIGURATION)-$(PLATFORM_NAME)" を追加
  • Apple LLVM 7.0 - Language - C++ -> Enable C++ Exceptions -> No
  • Apple LLVM 7.0 - Language - C++ -> Enable C++ Runtime Types -> No
  • Apple LLVM 7.0 - Language - C++ -> C++ Language Dialect -> Compiler Default
  • Apple LLVM 7.0 - Custom Compiler Flags -> Other C Flags -> Debug -> -DQCC_OS_GROUP_POSIX -DQCC_OS_DARWIN を入力
  • Apple LLVM 7.0 - Custom Compiler Flags -> Other C Flags -> Release -> -DNS_BLOCK_ASSERTIONS=1 -DQCC_OS_GROUP_POSIX -DQCC_OS_DARWIN
  • Apple LLVM 7.0 - Language -> C Language Dialect -> Compiler Default
  • Apple LLVM 7.0 - Language -> Compile Sources As -> Objective-C++

次に

Targets -> AlljoynChat -> Building Phases

と選択して以下を設定していきます

  • Link Binary With Libraries -> + -> で以下のライブラリを追加

    • SystemConfiguration.framework
    • libstdc++.6.0.9.tdb
    • libstdc++.6.tdb
    • libstdc++.tdb
  • Link Binary With Libraries -> + -> Add Other で先ほどコピーしたスタティックライブラリを全部追加

で Xcode 上での設定は完了です
設定から完了したら iPhone 5 を USB で接続して Xcode で実機ビルドをする準備をしましょう

サンプルアプリを動作させる

では実機を接続してビルドしましょう
おそらく特に問題なくビルドできてアプリが起動すると思います
起動するとチャットアプリが立ち上がります
※起動するチャットアプリのイメージはこちら

このチャットアプリは join モードと host モードがあり、join モードの場合は同一ネットワーク上に存在する host モードのデバイスを自動で検索してチャットに参加します
host モードの場合は自分がホストになるので、join モードのデバイスが来るまで待ちます

なのでチャット実際に試したい場合は 2 台のデバイスが必要になります

最後に

感想としては「便利だけど、開発が大変そう」というイメージです
サービスへの応用としてはいろいろ考えられて 3DS みたいなすれちがい通信や HEMS に応用して家に帰った ( 家のネットワークに入った ) ら勝手に電気をつけるなんかもできると思います

ただ、今回触ってみて気づいた点ですが、最新バージョンのデバイスや OS に追従ができていなかったので、その辺の対応速度が遅いとなるとちょっと実用面では厳しいような気もします

あとは今回は実際に SDK を使って AllJoyn アプリを開発していないので開発の難易度や他の SDK とのシナジーなんかもどれくらいあるのかわかっていません

トラブルシューティング

  • iOS9 には対応していません

  • iPhone 6 以上のデバイスにも対応していません
    正確に言うと arm64 のアーキテクチャに対応していません

  • 今回の手順の場合は実機の iPhone 5 ( iOS7 ) でしかおそらく動作しません
    上記のアーキテクチャ問題にも絡んでくるのですが、この AllJoyn のサンプルは環境変数で読み込むライブラリが変わってくるためシミュレータや armv7 以外のアーキテクチャの iPhone だと動作しません
    もう少し話をすると、Xcode 上で設定した Search Paths 上で PLATFORM_NAME や CURRENT_ARCH などの環境変数を使っており、これがデバイスやシミュレータごとに異なるためライブラリを見つけれれずビルドを実行すると
    ld: library not found for -lalljoyn_config_cpp
    みたいな感じでエラーになります

  • コピーするスタティックライブラリや Search Paths を変えればシミュレータでも動作すると思います
    上記の問題を逆に考えるとシミュレータで動作する場合の環境変数がわかり、それを Search Paths と Link Binary With Libraries に追加すれば、シミュレータでも動作すると思います

  • Xcode7 で bit code のエラーが出た場合
    http://qiita.com/satoshi_imanishi/items/8b64af8262d7fe2eb2ba で対応してください

参考サイト

2015年12月3日木曜日

RaspberryPi で Huawei の HWD12 を使う方法

概要

過去に Yosemite で使えるようにした HWD12 ですが、今度は RaspberryPi (RPi) で使ってみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

設定方法

とりあえず何も考えずに以下のコマンドを実行すれば使えるようになると思います

  • sudo apt-get install usb-modeswitch
  • sudo cp /etc/usb_modeswitch.conf{,.back}
  • sudo vim /etc/usb_modeswitch.conf
DefaultVendor=0x12d1
DefaultProduct=0x1f03

TargetVendor=0x12d1
TargetProduct=0x14db

MessageContent="55534243123456780000000000000a11062000000000000100000000000000"
  • sudo modprobe usbserial vendor=0x12d1 product=0x14db
  • sudo usb_modeswitch -c /etc/usb_modeswitch.conf

usb_modeswitch.conf は一番下に内容を追記すれば OK です

何をしているのか

usb_modeswitch というツールを使って、USBストレージとして認識されてしまった HWD12 を USBモデムとして認識させ直しています
最後の sudo usb_modeswitch -c /etc/usb_modeswitch.conf のあとで HWD12 のランプが紫になりインターネットに接続できることが確認できると思います

本来は USB を接続した際に VendorID が 0x12d1, ProductID が 0x14db として認識されなければいけないのに、それぞれ 0x12d1, 0x1f03 として認識されているせいで Wifi モデムとして動作していません

設定ファイル ( /etc/usb_modeswitch.conf ) に正しい ID 情報を記載して、usb_modeswitch コマンドを実行することで正しい ID として認識させます

本来正しく認識させなければいけない ID や MessageContentここ に記載されているものを使いました

Tips

  • IPv4 の IP アドレスを取得できない場合

以下のコマンドを試してみたください

sudo dhclient -4 -v usb0

RPi 自体で IPv4 を切る方法もありそうなのでそれを設定して再起動でもいいかもしれません
というのも今回の HWD12 を使えるようにする設定を行った後に RPi 自体を再起動すると HWD12 を挿してもうまくインターネットに接続できない現象が発生しました
自分の場合ですが、調べてみると USB はモデムとして認識されているものの IPv4 がうまく取得できていなかったようで、RPi を再起動するたびに dhclient のコマンドを実行していました
コマンドを 1 個実行するだけなのでそこまで大変ではないですが、そもそも IPv4 を切っておけば、そのコマンドすら実行する必要がなくなるのかなと思った感じです

  • そもそも他のネットワークがない人はどうすればいいか

今回のコマンドは一発目に apt-get コマンドがあります
つまりネットワークに繋がっていなければなりません
自分はスマホのテザリングを使って RPi をネットに繋いて実行しましたが、そもそもその環境すらない場合は詰んじゃうかもしれません

参考サイト

2015年12月2日水曜日

TinkerMode 試してみた

概要

Tinker Mode は IoT 用のクラウドサービスで Tinker Mode に接続しているデバイスをスマートフォンや PC から制御できるようにすることができます
シミュレータを使って制御することもできますが、せっかくなので RaspberryPi を使って Tinker Mode に接続しスマホから L チカしてみました

環境

  • TinkerMode 2015/12/01 時点
  • node 4.2.1
  • mode-device ( npm module ) 1.0.3
  • iPhone 6 ( iOS 9.1 )
  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

サインアップ

まずはサインアップします
名前/パスワードとメールアドレスを入力して確認のメールが来たら記載の URL をクリックすれば登録完了です
signup_mode.png

登録できたら早速コントロールパネルにログインしてみましょう
https://console.tinkermode.com/console/

サンプルプロジェクトの作成

サンプルプロジェクトを作成します
ログインするとすでに「Sample Project」というプロジェクトが 1 つ存在していると思います
今回はこれを使っていきます

制御用のサンプルアプリ Lumos をダウンロードする

このアプリを使って最終的に RPi の L チカを制御します

App Store から「Lumos」というアプリをダウンロードしてください
検索すると Lumos という同じ名前の他のアプリがいろいろと出てきてしまうので MODE INC が公開者になっているアプリをダンロードしてください

ダウンロードしたら早速アプリを開きましょう
アプリを開くといきなりプロジェクト ID を入力させられます
先ほど確認したサンプルプロジェクトのプロジェクト ID を入力すれば OK です
プロジェクト ID はコントロールパネルの

Dashboard -> OVERVIEW -> Project ID

で確認することができます
プロジェクトを開いているのであれば URL にも番号があるのでそれでも OK です

次にプロジェクト内に存在するユーザを登録します ( これはサインアップしたユーザとは違うユーザになります )
登録には電話番号が必要になります
Name と Phone number を入力したら Next で登録処理に進みます
電話番号は国別コードから入力する必要があるので、日本で試している場合は「+8109xxxxyyyy」みたいな感じで入力してください
入力した電話番号に SMS メッセージが届きます
そこに記載されている PIN コードを入力すれば登録完了です

Tinker Mode ではユーザの認証に電話番号による SMS 認証を採用しています
電話番号に記載の PIN コードを入力することで認証することができます

ここの流れは Getting Started の Install the Sample App を見ると画像もあるので、やり方のイメージがつかみやすいと思います

Home を作成する

このまま Lums のアプリ上で作成します
Home はデバイスやユーザを管理するものです

アプリにログインすると初めは Home の一覧になるので何もないと思います
右上に「+」ボタンがあるのでそこから Home を追加しましょう
名前とタイムゾーンを決定すれば OK です

制御するデバイスを Home に登録する

コントロールパネルでデバイスシミュレータを開きます
Sample Project にはすでにデバイス ( デバイスクラス ) も登録されているのでそれを使います

Devices -> smart_light -> DEVICE LIST -> 適当なデバイスを選択 ->
Device Simulator -> LAUNCH SIMULATOR

でシミュレータを起動しましょう
起動すると別ウィンドウで開きます
シミュレータの左ペインに「CLAIM MODE」というボタンがあるのでクリックします
claim_code.png

すると 300 秒間のカウントに入ります
この間に再度 Lumos のアプリ上で Home にデバイスの登録を行います

作成しておいた Home を選択して Devices を開きます
Home 追加時同様に右上に「+」ボタンがあるのでタップしてデバイスを追加します
デバイスを追加するには「Claim Code」が必要になります
これはデフォルトだとランダムに発行される文字列になります ( スクリーンショットの Claim Code は自分で変更したものになります )
Claim Code の確認は開いているシミュレータ上でもできます
コントロールパネルのデバイス一覧からも行えます
Claim Code を 300 秒間の間に入力してアプリ上で Add しましょう
エラーが発生しなければ登録成功です

一覧に出てこない場合は一旦 back して再度 Home を選択してみてください
登録したデバイスが表示されるはずです
ここまでできれば一旦アプリ上での作業は完了です

RPi 側の準備

ここからは RPi 側の準備になります
OS のインストールやネットワークの設定は事前に済ませておいてください

node をインストールする

最新の node が必要になります

Tinkder Mode を操作する Javascript SDK をインストールします

エラーなくインストールされれば OK です
執筆時点での SDK のバージョンは 1.0.3 でした
https://www.npmjs.com/package/mode-device

ソースコードを修正する

取得した app.js を修正します
修正するといっても API 認証のための情報を書き換えるだけです

Tinker Mode の API をコールするためには Device ごとに割り振られている DeviceID と API Key が必要になります
プロジェクトごとではなくデバイスごとなので別のデバイスを制御したい場合は、別の DeviceID と API Key に書き換えてください

DeviceID と API Key の取得はコントールパネルから行えます

Devices -> smart_light -> DEVICE LIST -> 適当なデバイスを選択

get_id_and_key.png

取得できたらソースを修正していきます
修正する箇所は app.js の 10, 11 行目です

var DEVICE_ID = 1;
var API_KEY = 'v1.cccc.bbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

取得した Device ID と API Key に書き換えたら保存して終了しましょう

接続できるか試してみる

この状態で一旦 RPi から Tinker Mode に接続できるか試してみるといいと思います

  • node app.js

でスクリプトを起動しましょう

Connecting to wss://api.tinkermode.com:443/devices/1/command
Event is triggered
WebSocket Client Connected

となれば成功です
ほっておくと ping - pong のやり取りもはじまります

Lチカ用の配線をする

ブレッドボードを使って L チカ用の配線をしましょう
ここでは配線に関する詳細は省略します
Lチカ配線は過去にも紹介しているので参考にしてください
あとはググってもいろいろと情報がでてくると思います

一点だけポイントですが、GPIO は論理番号 4 番ピンを使ってください
app.js 内で 4 番 PIN を制御しているためです
もちろんスクリプトを修正して別の番号の PIN を制御するようにすれば別の PIN を使っても OK です

アプリシミュレータから LED を点灯させてみる

これで準備が整いました
では、アプリから LED を点灯させてみましょう
まずはアプリシミュレータを使って点灯させます
アプリも Sample Project 作成時に 1 つ存在するのでそれを使えば OK です

Apps -> controller_app -> App Simulator -> LAUNCH SIMULATOR

で別ウィンドウでシミュレータが起動します
スマホから Home を作成したと思うのですでにシミュレータ側にも Home があると思います
ないスマホで作成した方法と同様でいいので Home を作成してください

Home を選択すると右ペインに「Outgoing: Commands」というのが表示されます
これを使ってデバイス ( RPi ) に信号を送り LED をチカっとさせます
送信する信号の情報は以下の通りです
send_signal.png

Target のデバイス情報は Home に登録したデバイスがプルダウンで選択できるので、登録したデバイスを選択してください
プルダウンにデバイスが表示されない場合は、Home へのデバイス登録が失敗している可能性があります
再度 Claim Mode にして Claim Code を使って Home にデバイスを登録してください

情報が入力できたら「SEND COMMAND」で OK です
で、成功すると LED がチカっ光るはずです
なんかリモコンみたいな感じで初めは感動します
消灯する場合は送信する信号の Parameters を on : 0 にすれば OK です

Lumos アプリから LED を点灯させてみる

アプリの場合はトグルを ON/OFF するだけで LED が点灯したり消灯したりします
アプリにログインして Home を選択してデバイスの一覧を表示するとデバイスの右にトグルボタンが表示されていると思います
そのトグルを ON/OFF してみてください
LED がチカチカするはず、、、がしない

ちょっとだけソースを修正する必要があります
21, 22 行目で Tinker Mode から受け取る信号を if 文で切り分けている部分があります
そこを書き換えましょう
以下のようにすれば OK です

device.commandCallback = function(msg, flags) {
  if (msg['action'] == 'change') {
    var v = msg['parameters']['switch'] ? 1 : 0;
    led.writeSync(v);
  }
}

どうやら Lumos アプリから送信される信号は以下の JSON 情報のようでシミュレータから送られる情報とは異なるようです

{“action”:”change”, “parameters”:{“switch”:0}}

書き換えて再度 node app.js で起動して Lumos アプリからトグルを ON/OFF すればアプリから L チカを制御できるようになります

最後に

確かにおもしろいサービスだと思いました
おそろく制御の情報はすべて WebSocket でやり取りしているのでほぼリアルタイムに行えます
今回は GPIO の制御をしましたが、逆に言えば GPIO の制御ができるデバイスは全て Tinker Mode から制御できるということになります

参考サイト

Tips

iPhone アプリの「Lumos」で制御したい場合はプロジェクト配下にあるアプリ名が「controller_app」でなければなりません
一度プロジェクトを削除した場合などで Lumos を使いたい場合はアプリ名を必ず上記にしてください

2015年12月1日火曜日

RaspberryPi で CUI モード時にフォントサイズを大きくする方法

概要

CUI モードで起動した RaspberryPi ( 以下 RPi ) を起動しモニタに HDMI 接続のモニタ ( 例えばテレビなど ) を使っていると文字が小さすぎることがあります

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

対応方法

1つ設定ファイルを編集し、再起動します

  • sudo vi /boot/config.txt

でコメントアウトされている以下の 2 つの設定をコメントインし再起動します

hdmi_group=1
hdmi_mode=4
  • sudo reboot

でいい感じのサイズの綺麗なフォントが映るはず

参考サイト

2015年11月30日月曜日

BL600 で RSSI の強度を上げる方法

概要

前回の記事で nrf51822 で RSSI の強度を上げる方法を紹介しました
この場合は例えば nRF51 DK ボード上で動かしていたり、USB ドングルを使って開発している場合にはいいのですが、BL600 等のサードパーティ製の製品上で動かす場合に有効になりませんでした
今回は BL600 上で動作する nRF51 系のアプリで RSSI を強くする方法を紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

設定方法

ずばり以下を設定する
自分は advertising_init メソッド内でコールしました

nrf_gpio_cfg_output(20);
nrf_gpio_pin_clear(20);

初めこれでできたときは「魔法とはこれか」と思ったくらいビックリしました
詳しいことは良くわからないのですが、どうやら nRF51 DK の P0.20 ピンが VDD 周りの制御をしているらしく、そこに信号を送らないようにすればいいとか、詳しい方ヘルプ、、、

参考サイト

2015年11月27日金曜日

nrf51822 で RSSI の強度を上げる方法

概要

アドバタイジング時に RSSI の強度を強くしたり弱くしたりすることで検知させたいデバイスの距離を操作することができます
nrf51822 で RSSI の強度を設定する方法を紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0

設定方法

適当な場所で以下をコールすれば OK です
自分は advertising_init 内でコールして問題ありませんでした

err_code = sd_ble_gap_tx_power_set(4);
APP_ERROR_CHECK(err_code);

sd_ble_gap_tx_power_set メソッドは ble_gap.h のヘッダファイルに含まれているのでない場合は include してください

設定できるパラメータは -40, -30, -20, -16, -12, -8, -4, 0, 4 だけです
これ以外を指定すると APP_ERROR_CHECK でエラーとなりアプリが停止します
試した感じだと -40 が弱く 4 が強い設定になります
-40 とかは本当に弱く 20 cm くらい離れると検知できません
4 は正確には計測していませんが、5m くらいは余裕でした

一度設定してからアプリ内で動的に変更することもできるようです

最後に

RSSI の強さが動的に変更できると具体的に何ができるか思いつきませんが、何かおもしろいことができるような気がします

参考サイト

2015年11月26日木曜日

RaspberryPi で無線 LAN のアクセスポイントを追加する方法

概要

過去に WiMax2 に接続する方法を紹介しました
WiMax2 が使えない状況が発生し iPhone のテザリングしかネットワークがなく、デザリングを新しい無線 LAN のアクセスポイントとして追加してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

手順

新規に network の定義を追加する

  • sudo cp /etc/wpa_supplicant/wpa_supplicant.conf{,.back}
  • sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf
  • sudo wpa_passphrase ssid ssid-password >> /etc/wpa_supplicant/wpa_supplicant.conf

ssid と ssid-password は今回は iPhone のテザリング情報を入力しました

追加した network 定義を編集する

  • sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

追加した ssid の network の定義に以下を追加する

  • proto=WPA2
  • key_mgmt=WPA-PSK
  • pairwise=CCMP

記載したら保存して終了する

  • sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf

権限を戻しておく

ネットワークを再起動する

  • sudo systemctl restart networking

でしばらくするとテザリング用の NAT IP が iPhone からもらえると思います

最後に

既存の無線 LAN 設定が記載されている wpa_supplicant.conf に設定を追記するだけなので簡単でした

両方のネットワークにアクセスできる状況で、この設定ファイルを使うとどっちのネットワークを使うのか気になりました
優先度とかを定義することができるのか、単純にファイルの上位に記載されているネットワーク定義から評価していくのか、、、どうなんだろうか

試せる機会があったらやってみよう

2015年11月25日水曜日

nrf51822 でタイマーのクロック間隔を短くすることで起動時間を長く管理する方法

概要

前回 タイマーを使って起動時間を取得する方法を紹介しました
前回の問題点として管理できる時間が短いという点をあげました
今回はそれが解決でき、長い時間管理できるようになったので紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

実装方法

タイマーを使う方法は前回の記事を参照してください

まず前提として前回から判明したことが

  • 保存できるカウントの最大値は 24bit = 16, 777, 216 まで
  • 1 秒間のカウントで増加する値は 32, 768

であることがわかりました ( 参考 )

保存できるカウントを増やす方式は難しいため増加するカウントを減らすことで管理できる時間を増やせないか検討してみました

ずばり回答としては

#define APP_TIMER_PRESCALER 0

の値を増やすことです
この値を増やすことで影響するのが

APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

の部分です
この初期化をしている第一引数で増加するカウントの 32, 768 を割り算しているようです
例えば APP_TIMER_PRESCALER を 16 とすると 1 秒間でカウントされる値は

32, 768 / 16 = 2, 048

になります
なので最大保存時間は

16, 777, 216 / 2, 048 = 8, 192 (sec) = 136 (min) = 2.27 (hour)

になります
一応この値が 32 でも正常に動作することは確認しています

カウントから時間 (秒) を取得する方法は

uint32_t time = p_ticks / (APP_TIMER_CLOCK_FREQ / APP_TIMER_PRESCALER);

で OK です

気になる点

では一体 APP_TIMER_PRESCALER の値はいくつまで設定できるのかと言うとおそらく 4,095 までいけるっぽいです ( かなり不確定、カウントの最大が 24 bit であることから逆算しているみたいです )
確かに 4,095 を設定しても問題なく動くことは確認しました

ただ、今度はタイマーを使っているバッテリーレベルの Characteristics が更新されなくなってしまいました
32 や 16 のときはほぼリアルタイムで read してもバッテリーレベルが更新されていたのですが 4, 095 を設定すると更新されなくなりました

詳しく調査していないので、予想ですがこの後タイマーを作成 (app_timer_create) してスタート (app_timer_start) すると思うのですが、スタートする際にタイマーのインターバルを決定する引数 ( BATTERY_LEVEL_MEAS_INTERVAL) がありこれが APP_TIMER_PRESCALER を使っているため、更新するインターバルの時間が伸びたんだと思います

なので、ちゃんとやるとしたら時間を取得するためだけのタイマーを作成、スタートして、そのポインタから時間を参照するようにしたほういいと思います
チュートリアル を見てもアプリごとに 10 個タイマーを持てるとあるので、そうするのがベターなんだと思います

Tips

わからないことは Nordic Developer Zone で質問してみましょう
基本英語です
もちろん過去ログは検索してから質問したほうがいいです
結構適当な英語でも頑張って解釈してくれるので、ちゃんした返事が返ってきます

2015年11月24日火曜日

nrf51822 でデバイスをスキャンして Macアドレスと RSSI を取得する方法

概要

nrf51822 に Central の機能を実装して BLE デバイスをスキャンしてみました
スキャンした際に対象デバイスの Mac アドレスと RSSI (受信信号強度) を取得してデバッグ出力してみます

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

実装方法

今回は Peripheral ではなく Central の機能を実装するので SoftDevice のバージョンは s120 or s130 が必要になります
なので、あらかじめ上記の SoftDevice を書き込んでおいてください
実装方法は SDK に含まれる Central のサンプルコードベースで説明します

スキャンできるように初期化する

まずスキャンの方法を設定します
サンプルコードでは基本的に main メソッド内で初期化用のメソッドをコールすることで初期化を行っています

スキャンの初期化の流れは ble_stack_init -> softdevice_ble_evt_handler_set -> ble_evt_dispatch -> on_ble_central_evt になります
簡単に説明するとスキャンを実行した際に発生するイベントを on_ble_central_evt メソッドでハンドリングする設定を行っています

このコールの流れは基本サンプルのままで OK です
これが設定されていればスキャンの基本の設定は完了です
次にハンドリングしたイベント内で実際に Macアドレスと RSSI を取得してみます

Macアドレスと RSSI を取得するロジックを追加

修正は on_ble_central_evt メソッドだけになります
このメソッドは発生したイベント ID を取得して switch 文でイベントを分岐しています

static void on_ble_central_evt(ble_evt_t * p_ble_evt) {
    uint32_t                err_code;
    const ble_gap_evt_t   * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id) {
    case BLE_GAP_EVT_ADV_REPORT: {
            // ...
            break;
        }
    case BLE_GAP_EVT_TIMEOUT:
        // ...
        break;

    case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
        // ...
        break;

    case BLE_GAP_EVT_DISCONNECTED:
        // ...
        break;

    default:
        break;
    }
}

今回はこの中の BLE_GAP_EVT_ADV_REPORT の switch 文を修正します
Mac アドレスと RSSI は引数として渡ってきた ble_evt_t のポインタから取得します

取得方法は以下の通りです

ble_gap_addr_t pa = p_gap_evt->params.adv_report.peer_addr;
int8_t rssi = p_gap_evt->params.adv_report.rssi;
printf("Mac Address: %02x:%02x:%02x:%02x:%02x:%02x \r\n", pa.addr[5], pa.addr[4], pa.addr[3], pa.addr[2], pa.addr[1], pa.addr[0]);
printf("RSSI %d \r\n", rssi);

これをそのまま BLE_GAP_EVT_ADV_REPORT の switch 文中に記載すれば OK です
Mac アドレスは LSB (下位ビットから格納する方式) になっているので、添字の大きい方から参照します

ドットや矢印でいろいろと参照していますが流れとしては

  1. ble_evt_t から evt.gap_evt で GAP (General Access Profile) のイベントを取得
  2. イベントの params フィールドからパラメータを参照
  3. パラメータの adv_report フィールドからアドバタイジング情報を参照
  4. アドバタイジング情報の peer_addr フィールドから Mac アドレス情報を参照
  5. アドレス情報の addr[6] フィールドが Macアドレスが格納されている配列になっている

という感じです
RSSI は adv_report から直接数値が参照できます
この辺りはリファレンスを参照すると、この構造体のこのフィールドを参照しているという流れがわかると思います

スキャンを開始する

これもサンプルをそのまま使っているのであれば特に変更する箇所はありません
main メソッド内 scan_start というメソッドをコールしていれば Central のスキャンを開始することができます

int main(void) {
    uint32_t err_code;
    bool erase_bonds;

    // Some Initialize ...
    ble_stack_init();
    // Some Initialize ...

    // Some Initialize ...
    scan_start();
    // Some Initialize ...

    for (;; ) {
        power_manage();
    }
}

scan_start を辿ってみるとわかると思いますが結構いろいろな設定をしています
スキャンの間隔やホワイトリストを使って、信頼するデバイスだけスキャンするようにするとか、タイムアウトをどうするかなど設定できます
興味があれば、scan_start メソッドのサンプルとリファレンスを見ながらいろいろとパラメータチューニングしてみてください

コードが記載できたら Keil でビルドして nRFgo Studio でアプリケーションを焼きこんでみましょう
焼きこみが完了すれば自動的に nRF51 DK が BLE デバイスとなりスキャンを開始します

試す

アドバタイズしている BLE デバイスは結構街中に飛んでいるのでスキャンを開始すればデバイスが見つかるかもしれません
ない場合はスマホアプリで Peripheral になれるアプリがあるので、それを使ってみてください
自分は SensorTag CC2650 を使いました

デバッグは nRF51 DK を PC に USB で接続して TeraTerm でシリアルモニタをすればいいと思います
ボーレートは 38400 を設定してください

今回のサンプルは printf しているだけなので、デバイスが見つかればそのまま出力されると思います

最後に

コンシューマ向けの BLE デバイスは基本は Peripheral のみが実装されており、iPhone とか Android などのスマホが Central になっています
nrf51822 は Central にもなることでできるのでちょっとおもしろい実装ができます

nrf51822 には pstorage という仕組みもあってデバイス上にデータも保存できるので、スキャンした情報を保存しておくこともできます

pstorage の話もどっかでできればなぁと思っています
あと、サラッと書いたデバッグの方法とかも書いたほうがいいかなと思っています