2011/03/27

[java]JNIからのコールバック

コールバックといえども、関数呼び出しに代わりはなかろう。
関数というか、メソッド呼び出し。
そう考えると、StringBuffer.append()を呼び出したようなしくみでいいはず。

と、自分一人で解決できたように書いているが、そんなことはない。
bitlogさんの記事を見て、ようやくできた。

package com.jnitest;

class Jni {
        public static void main(String[] args) {
                System.out.println("Hello");
                callCallback("callbackFunc");
        }
        
        public void callbackFunc() {
                System.out.println("callback");
        }
        
        static {
                System.loadLibrary("jnicallback");
        }
        
        public static native void callCallback(String funcName);
}


#include "com_jnitest_Jni.h"

JNIEXPORT void JNICALL Java_com_jnitest_Jni_callCallback
  (JNIEnv *env, jclass clazz, jstring funcName)
{
        const char* fname = (*env)->GetStringUTFChars(env, funcName, NULL);

        jclass jc = (*env)->FindClass(env, "com/jnitest/Jni");
        jmethodID mid = (*env)->GetMethodID(env, jc,
                                fname,
                                "()V");
        if(mid) {
                jmethodID ctor = (*env)->GetMethodID(env, jc, "<init>", "()V");
                jobject jo = (*env)->NewObject(env, jc, ctor);

                (*env)->CallVoidMethod(env, jo, mid);

                (*env)->DeleteLocalRef(env, jo);
        } else {
                printf("mid is null.\n");
        }
        (*env)->ReleaseStringUTFChars(env, funcName, fname);
        (*env)->DeleteLocalRef(env, jc);
}

$ java com.jnitest.Jni
Hello
callback


よくわかってないのが、なぜCallVoidMethod()するのにjobjectが必要なのかということ。
NewObject()しているから、これはJava_com_jnitest_Jni_callCallback()を呼び出した人とは別の人になっていると思う。

引数のclazzから取ってくることはできないのかな?
まず、jcを取り除き、clazzに置き換える・・・よし、動いた。

あれ、jclassからオブジェクトを取ってくる関数はないな。
そもそもメソッドなのにjclassが引数で渡されるなんておかしいのでは?

・・・自分でpublic static nativeって書いとるやん。
そしてコールバックして呼び出そうとする方は非staticだ。
これがいかんのですな。

そんなわけで、コールバックする方もstaticにするか、nativeを非staticにするか、だ。
今回はmain()から呼び出すので、コールバックする方をstaticにした。

package com.jnitest;

class Jni {
        public static void main(String[] args) {
                System.out.println("Hello");
                callCallback("callbackFunc");
        }
        
        public static void callbackFunc() {
                System.out.println("callback");
        }
        
        static {
                System.loadLibrary("jnicallback");
        }
        
        public static native void callCallback(String funcName);
}


#include "com_jnitest_Jni.h"

JNIEXPORT void JNICALL Java_com_jnitest_Jni_callCallback
  (JNIEnv *env, jclass clazz, jstring funcName)
{
        const char* fname = (*env)->GetStringUTFChars(env, funcName, NULL);

        jmethodID mid = (*env)->GetStaticMethodID(env, clazz,
                                fname,
                                "()V");
        if(mid) {
                (*env)->CallVoidMethod(env, clazz, mid);
        } else {
                printf("mid is null.\n");
        }
        (*env)->ReleaseStringUTFChars(env, funcName, fname);
}

$ java com.jnitest.Jni
Hello
callback

[android]JNIHelp

Androidのソースを見ていると、javahが生成したような関数名のものもあるが、そうではないものもある。
そうではないものはどうやっているのか気になっていたのだが、JNIからのコールバック関連を調べていて少しわかった。

RegisterNatives()というJNI用関数がある。
これは、ネイティブメソッドの登録らしい。
Javaに書いたnative付きの関数と、C/C++で書いた関数を動的に結びつけるのであろう。

AndroidのJNIHelpには、jniRegisterNativeMethods()という関数がある。
これは、FindClass()とRegisterNatives()、その後片付けをやってくれる。

ほほぅ。

[nfc]規格の関係

NFC関係の規格はいろいろとあって、なにがなんだかわかりづらい。
自分のイメージを図にしてみた。
これはこれでわかりづらい。。。

nfc_relate.png

ISO 15693が浮いているのは、私がよくわかっていないから。

[java]Cからコールバックしたい(考察編)

まだ考えている段階で、調査してない。

今回Javaを調べ始めたのも、元はといえばJNIで呼び出した先からコールバックしたいというだけのことだ。
私の思うコールバック(Javaではない)は、自分の関数を相手から呼び出してもらう、だ。
それだけのしくみ。
電話の「かけ直してください」だ。

電話だと、相手が誰からなのかは固定されていない。
固定された相手だったら単なる関数呼び出しなのだが、不定なので「かけ直してください」という登録が必要になる。
なので、呼び出してもらう関数を登録するところから呼び出しするまでが「コールバック」としてよいだろう。
よいのだ。

C/C++ならば、引数でアドレスを教えてもらって保持するだけだ。
コールも、そのアドレスを呼び出すだけ。
実にシンプルで、私にとってはわかりやすい。
わかりやすいが、安全ではない。
アドレス/ポインタでC/C++でチェックできるのは、NULLかどうかくらいしかない。
無効なポインタかどうかのチェックはできない。
inlineとかになると、関数になるかどうかすら確定してない。
とにかく「書いたコード以上のことはしない」というスタイル。

JNIもC/C++だから、Objectでメソッドのアドレスとコンテキストをもらえば何とかなるかな、と思っていたけれども、リフレクションの話を聞いていて、そんな簡単では済まないと感じた。
ちゃんとJavaVMを介して呼び出すようにしないと、呼び出せないだろうという感触だ。

高速だけど何かあったら即死するC/C++、死んでもJavaVMが管理してくれるJava、というところか。
いつもC/C++でしかコードを書かないけれども、一番気を配らないといけないのは死なないようにすることで、それが一番難しいし時間もかかる。
想定する範囲外でなにか起こったら対処できないし。
「安全」のためには、そういう言語がいいのだろうな、と改めて思った。

まあ、OSの類が動ける環境でなくても使えるC/C++が好き、ということには変わりないがね。
いいところはいいと認める心の余裕はあるのだ。
あとは勉強が足りないのを何とかせんと・・・。

[java]リフレクションに似ているらしい

前回、Call<type>Method()でBufferString.append()を呼び出した。
どうやら、リフレクション、も同じような使い方らしい。

ただ残念なことに、リフレクションについての書籍を持たない。
いくつかネットで見てみたところからすると、JavaのリフレクションというのはAPIを文字列で使えるしくみ、ということでいいのかな?

いや、まだ奥があるらしい。
@esmasui さんに教えてもらったのだが、リフレクションはメタデータを扱うしくみらしい。
メタデータ・・・。
多階層とかそんな意味だよな、メタって。

検索して見つかったのは、developerWorksの「Javaプログラミングのダイナミックス 第1回:クラスとクラスのロード処理」。
ここから先を読んでいけば、私のほしい情報が手に入りそうだ。

今日はもう酔っ払いなのでやめておくが、ToDoリストに追加しておこう。

2011/03/26

[java]引数で文字列を返してみる

前回、NewStringUTF()で文字列を作って返した。
が、その前に考えていたのは違うことだった。

NewStringUTF()って、メモリを生成するから、どこかで解放せんといかんのでは?ということ。
解放しようとしても、そのときにはCを抜けたあとだ。
それじゃあ遅いよなあ。。。
ならば引数でバッファをもらって返すようにせんといかんよなぁ。。。

引数をバッファにするなら、StringBufferだろう。


package com.jnitest;

import java.lang.StringBuffer;

class Jni2 {
        public static void main(String[] args) {
                StringBuffer sb = new StringBuffer();
                System.out.println("Hello");
                getHelloString(sb);
                System.out.println(sb);
        }
        
        static {
                System.loadLibrary("jnihello");
        }
        public static native void getHelloString(StringBuffer sb);
}
#include "com_jnitest_Jni2.h"

JNIEXPORT void JNICALL Java_com_jnitest_Jni2_getHelloString
  (JNIEnv *env, jclass clazz, jobject jstrbuf)
{
        jclass jcstrbuf = (*env)->GetObjectClass(env, jstrbuf);
        jmethodID mid = (*env)->GetMethodID(env, jcstrbuf,
                                "append",
                                "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
        jstring js = (*env)->NewStringUTF(env, "Hello!");
        (*env)->CallObjectMethod(env, jstrbuf, mid, js);
}

参考にしながら作ってみた。

これでちゃんと"Hello!"返してくれた。


何しているのか考えてみた。

まず、StringBufferのクラスを取ってくる。
そしてGetMethodID()でStringBuffer.append()のIDを取ってくる。
最後にCallObjectMethod()にIDを渡すと、CからStringBuffer.append()を呼び出すことができるのだろう。
StringBuffer.append()ってどういう関数か知らずに使ったけど、引数1つなんだな。

"(Ljava/lang/String;)Ljava/lang/StringBuffer;"

これは、java.lang.StringBuffer.append(java.lang.String)を使うという意味であろう。
そしてCallObjectMethod()ですな。
Call<type>Method()という形で、typeには

  • Void
  • Object
  • Boolean
  • Byte
  • Char
  • Short
  • Int
  • Long
  • Float
  • Double

が入るとのこと。
CallNonvirtual<type>Methodというものもあるそうだ。
一度にやっても覚えないから、こっちは使うときでいいや。

<type>はどうやって選ぶかというと、戻り値でいいのかな。
引数は可変らしいので、必要なものをずらずら書けばいいのだろう。

まあ、なるべく使わずに済ませたいものだ。

[java]cygwinでのJNIにはgcc-3を使うとよいのか

こうコンパイルした。

$ gcc-3 -mno-cygwin -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I/java/include -I/java/include/win32 -shared -o jnihello.dll com_jnitest_Jni2.c

動いた・・・。

どうも、no-cygwinがいるみたいだ。
-mno-cygwinを付けてコンパイルするには、gcc-4ではなくgcc-3にする必要がある。

まあ、これで逃げられるなら、それでいいか。

[java]gcjが動かない

もしかすると、JDKを使っているからだめなのか?
cygwinだから、gcjを使うといいんではなかろうか。

public class HelloWorld
{
  public static void main(String[] args) { System.out.println("Hello World!"); }
} 
$ gcj --main=HelloWorld -O HelloWorld.java
Exception in thread "main" java.lang.NoClassDefFoundError: org.eclipse.jdt.internal.compiler.batch.GCCMain
   at gnu.java.lang.MainThread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.eclipse.jdt.internal.compiler.batch.GCCMain not found in gnu.gcj.runtime.SystemClassLoader{urls=[], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}
   at java.net.URLClassLoader.findClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   at gnu.java.lang.MainThread.run(Unknown Source)

だめだねぇ。

$ gcj --version
gcj (GCC) 4.3.4 20090804 (release) 1
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


$ cygcheck -c | grep gcj
libgcj-common        4.3.4-4                 OK
libgcj9              4.3.4-4                 OK

よくわからん。

[java]cygwinでのJNIがうまくいかん

2回目にしてよくわからん。。。

package com.jnitest;

class Jni2 {
        public static void main(String[] args) {
                System.out.println("Hello");
                System.out.println(helloString());
        }
        
        static {
                System.loadLibrary("jnihello");
        }
        public static native String helloString();
}

こんなのだ。

これをコンパイル。

$ javac com/jnitest/Jni2.java

そして、javah

$ javah com.jnitest.Jni2

com_jnitest_Jni2.hというヘッダファイルができる。
これを使ってCソースを書く。

#include "com_jnitest_Jni2.h"

JNIEXPORT jstring JNICALL Java_com_jnitest_Jni2_helloString
  (JNIEnv *env, jclass clazz)
{
        return "Hello !";
}

まあこんなもんだろう。

これをコンパイル。参考はここ

gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -shared -o jnihello.dll com_jnitest_Jni2.c

jnitest.dllができるので、パスが通ったところにコピー。
そして実行。

$ java com.jnitest.Jni2
Aborted

Abortか・・・。


DLLがないと、loadLibrary()が例外を出す。
だから、DLLが見つからないわけではない。

helloString()を呼び出す行をなくしても変わらないので、関数でエラーになっているわけではない。
ということは、DLLの読み込み付近でJava以外でのエラーが発生していることになる。

幸いなことに、むかーしJavaを勉強したときのJNI DLLが残っていた。
StdAfx、なんてのがあるから、Visutl Studio6で作ったのだろう。
これが読み込めるなら、jnihello.dllに問題がある。。。読み込めた。
というわけで、jnihello.dll自体に何かありそうだ。

今使っているJavaは、1.6.0_24である。


MINGWのコンパイル方法と違うのは、-Iしてないところくらいか。
コンパイルできてるから、インクルードパスの指定はいらんと思ってるけど、まあやっておくか。

・・・コンパイルエラーが出た。
ということは、デフォルトの参照先ではだめということか!
うん、書いてあることはちゃんと意味があるのだな。

コンパイルエラーは、jlongがうんたらかんたら。
include/win32/jni_md.hのところだ。
ここで__int64というのがあるが、これがいかんのだろう。long longかな。

そうすると、今度は「互換のない型だ」といわれた。
const char*を返しているけど、要求されているのはjstring型か。
どうせtypedefしなおしただけなんじゃないの? jni.hを見てみると、

class _jstring : public _jobject {};
typedef _jstring *jstring;

違うやん。
変換が必要ということか。
しかもコピー返しではなくアドレス返しか。
ヒープに取ってやらんといかんことになるが、どうやって解放すればいいんだろう?
JavaVMがやってれるのか?

NewStringUTF()は、なんか解放処理みたいなことはしなくてもよさそうに見える。
GetStringChars()したらReleaseStringChars()し、GetStringUTFChars()したらReleaseStringUTFChars()しないといかんが、それ以外の文字列操作は気にしなくてよさそうだ。

#include "com_jnitest_Jni2.h"
JNIEXPORT jstring JNICALL Java_com_jnitest_Jni2_helloString
(JNIEnv *env, jclass clazz)
{
jstring js = (*env)->NewStringUTF(env, "Hello");
return js;
}

$ gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I/java/include -I/java/include/win32 -shared -o jnihello.dll com_jnitest_Jni2.c

実行させてみよう!

$ java com.jnitest.Jni2
Aborted

Abortか・・・。


もしかしたら、パスがわからなくなっているとか?

System.load("e:/Prog/Java/JniStudy/2/jnihello.dll");

直指定してもだめか。。。

2011/03/25

[java]Helloを書く

まずは、Hello Worldだろう。
が、私はひと味違うので、Hello、だけでいいや。
何が違うのかはよくわからんけどね。

JNIの道もHelloから、だ。


com/jnitestディレクトリを作り、そこにJni1.javaというファイルを作る。

package com.jnitest;

class Jni1 {
        public static void main(String[] args) {
                System.out.println("Hello");
        }
}

publicが先か、staticが先か・・・しばし悩む。
たぶん、公開属性が先だろうということで、publicにした。

$ javac com/jnitest/Jni1.java
$ java com.jnitest.Jni1

これで、Helloと出てきた。

最初、Main、と書いていて動かなかった。
その次は、Jni1ではなくJniと書いていて動かなかった。
まあ、そんなものだよ。


Linux上で動かしているように見せかけているが、実はWindows上だ。
JNIはネイティブ環境だから、プラットフォームを決めないとなぁ。
Windowsではめんどくさいので、Linuxとかcygwinがいいのだが。

2011/03/24

[android]あきらめてJavaも少しは勉強しよう

今から一杯くらい飲もうかと思ったが、体力が尽きてきた。
筋肉を付けるような運動もせんといかんな。

さて、私なりに考えていた。
NativeActivityはC++で使えるからいいけど、画面を作るのが大変そうだ。
それに、文字入力とか考えると、かなり大変そうだ。
エンコードもiconvとか使ったりするのは、めんどくさい。

ならば、やはりJavaをあきらめて少しくらいは勉強せんといかんか、と。
でも、書かないと覚えんよな、Java。
仕事で書くことがないから、自分で作らないとなぁ。。。

そんなわけで、JavaといえばやはりJNIを最初にやらねばなるまい。
JNIでやりたいのは、

  • javahを使わないやり方
  • Nativeからのメンバ変数アクセス
  • Nativeからのコールバック

といったところだろうか。

わからんわからんと、いつも逃げてきたが、4月になるし始めるにはいい季節じゃないだろうか。
本で勉強する方が好きなのだが、JNI本って見かけたこと無いなぁ。
ネットで勉強しよう。

2011/03/21

[nfc]IDm

前にも似たようなことを書いたが、まとめて書いておこう。
IDm(NFCID2)についてだ。


FeliCaに、IDmという8byteの番号がある。
256^8ということで、組み合わせとしてはたくさんある(ルールはあるけど)。
値も、FNさんとかが割り振っていたと思う。

ならばユニークか?
これは、保証していないとのこと。
ほぼユニーク、くらいか。
Mifareの4byte UIDも同じようなことをいってた。

だから、IDmを使ったシステムを作るのはいいけど、セキュリティに関わるような場合には使わないこと。
システムの受け手となる人は、見分けないといかんが・・・難しい。
携帯電話でも自前のnimocaとかSuicaとかのカードならなんでもOK、というやつは、危ないかも。
自前のカードを発行したり、携帯電話ならアプリをインストールするタイプなら安心だと思う。


「自分たちでIDmがユニークであることを確認したカードならいいよね?」と思うかもしれないが、そうはいかん。
ある程度知識があれば、PaSoRiなどでIDmを自前で作り出すことができるからだ。
私ですら、ちょろちょろっと調べればできたのだ。

カードからIDmを読むのは、ポーリングすればいいので簡単。
そうなると、ちょっとしたソフトを作れば相手のIDmをコピーすることができてしまう。
相手はそんなこと気づきもしないだろう。。。

安全にするためには、FeliCa Liteにはセキュリティ機能があるので、それを使うのがよかろう。
手抜きをせずに、ちゃんとやればいいだけだろう。
まあ、私は持っていないので何とも言えないが。
普通のFeliCaカードとかは鍵があるのでさらに安全にアクセスできるのかな。
FeliCaの「セキュリティ」はここにあるのだ。
誰かがアクセスできるからには、開けられないことはないはずだが、まあ大変だろう。
特に私はそういうのがしたいわけではないので、やらない。


さて、これからどうなるのかね。
Mifareは巨人としていることだろう。
近接型だけでなく近傍型も出てきている。
多様化していくのか集約されていくのか。。。

[nfc]おサイフケータイ

やはり、ちょくちょく見かける、NFCとFeliCaの関係に対する誤認。
ここまで多いと、単なる情報不足とは別の原因があるのではないか?と考えたくなる。
おサイフケータイについてだ。

やっかいなのは、NFCの規格がどこまでなのかがなんかよくわからないところだ。
私の認識は、こう。


まず無線のところ。
R/Wから無線を出して、カード側のCPUと無線で通信する。
磁気のように読み取るのではなく、カードに命令を出して、カードから応答が返ってくる。
この無線の規格がまとめられている。
プロトコルを含む(コマンドは含まない)無線の部分については、NFCとして含まれていると思っている。

たぶん、国内の携帯電話に搭載されているFeliCaチップは、NFC-AやBに対してこの部分が対応できないのではないかと思う。
根拠はないのだがね・・・。
対応してたら、iCカードリーダアプリとして出しそうな気がしたので、出てないから対応してないのかな、というだけだ。
根拠無くてすまん。


次に、カードに命令を出す、と書いた部分。
この命令も規格として決めないと、やりとりができない。
ソフトを書いている人で一番身近なのは、ここだと思う。
ここについて、NFCはISO14443やISO18092の命令の一部のみをサポートしていると考えている。
まあ、これはISO18092のFeliCaとDigitalProtocol仕様書のNFC-Fを見比べてだけのことだ。
もしかすると一文として「ISO18092をフルサポートするが」とか書いてあるのかもしれん。

現在NexusSという機種に搭載されているNXPのPN544を見ると、どうもFeliCaのPUSHなどのISO18092に書かれていない命令もサポートしているようだ。
これがどういうことを意味するのか、よくわからん。
NXPとSONYが話し合った結果かも知れんし、研究した結果なのかもしれん。私が知らないところに書いてあるのかもしれん。
ここまでは、カードと無線チップ(FeliCaチップとか)の間の話。


その次に、メモリがある。
読み書きしたデータをどこに置くか。どう置くかだ。
NFCで論理的な決まりは書かれてたように思うが、物理的な決まりはないと思っている。
情報によると、FeliCaの場合は専用チップ、MifareなどはSIMに持っているらしい。
また、その情報を秘密化するようなことはNFCに書かれていない。
そこら辺は、FeliCaとかMifareとかで決まっているのだと思う。
(ドコモは、将来的にSIMにデータを持っていくらしいが。)

私としては、ここまでが携帯電話側で揃って、初めて「 おサイフケータイ 」を名乗る準備ができた、ということになると思っている。
まあ、ここからいろいろと試験を受けないといかんのだろうけどね・・・。
なので、NFCのチップを載せたからおサイフケータイだ、というのは、ない。
まあそもそも、「おサイフケータイ」というのはドコモの登録商標だからね・・・。
だから、もしNFCチップが載ってMifareとかでバンバン使うことができたとしても、それだけでは「おサイフケータイ」ではない。
おサイフケータイと名乗ってよい、とされたものがおサイフケータイなのだ。


なので、おサイフケータイが世界的にはあまり広くない、というのは正しいと思う。
インフラはあんまり得意ではない気がする。

まあともかく、NFCにすればなんでも大丈夫、というわけではないという話だ。
ハード的な無線レベルでは上位互換だけど、それ以降はチップ次第というか規格次第というか。

というようなことは、調べれば出てくる。
しかし、そうでない情報が出てくる方が多い。
そりゃ、出てくる情報が多い方が正しいと思ってしまうよねぇ。。。


まず、情報の更新が新しくないため、とか。
昔ブログに、「FeliCaがISOだかIEEEの規格に入れんかった」という記事を書いたとしよう。
Type-Cについては私もあまり情報がないのだが、Type-A, Bは正式に規格となったのは何となく覚えている。
たぶん、ISO14443だろう。
このときの情報で書くと、たぶんこの記事は正しいと思う。
でも、かなり昔のことだと思うけどなぁ。。。


あとは「思い込み」とか。
Googleで「おサイフケータイ nfc」で検索したときに出てきた一番最初のサイトを見ると、元記事では「e-Wallet」ってちゃんと書いてあるのに、なぜか日本語にするときに「おサイフケータイ」になっている。
これはたぶん、「e-Walletって書いてもわからないだろうな・・・日本ならおサイフケータイかな」ということで書いたと思う。
(コメントにも突っ込まれてるけど。)
なので、親切心で書いたと思いたい。


「まあいいや」と思っている人もいるかもしれない。
後で気付いたけど、大した違いはないだろう、とか。
実は、そういうのが一番困るのかもしれない。
なぜかというと、そのまま記事が修正されないまま残ってしまうからだ。
それを見た人が、またその情報を元に・・・と連鎖していく。
代替えの言葉が思いつかないからかなぁ。
「電子マネー」でいいと思うのだが。


それと、なぜか知らないけど、妙におとしめたがってる人がいるような気もする。
  FeliCa→国内→だめ
  NFC→海外→OK
みたいな。
まあ別にいいんだけど、曲解はよろしくないだろう。
あるいは、思い込みが強くて、そう自分で読んでしまう、ということがあるのかもしれない。


そうこういう私だって、曲解していないとは限らない。
FeliCaとかほとんど使わない私だが、意外とNFCというものは気に入っているのだ。
そのひいき目があるかもしれん。


そういえば、気になっていることがある。
Mifareの方が発行数が多いのはわかったのだが、携帯電話に搭載された実績があるのだろうか?
決済機能を持つ携帯電話という意味でだ。
あるとは思うのだけど、情報が無くてねぇ。

なんだかんだ書いたが、私の情報もしょせんこの程度ということだ。

[ndk]NativeActivityを使ってみる(1)

なるべく、楽をしたい。

今のところ、AndroidでNFC関係をやっているわけではないが、そのうちやりそうな気がする。
やるときは、楽をしたい。

Androidで楽をするというと、

  • Javaを使わない
  • JNIを使わない

が最初に出てくる。
楽をするというか、苦手なものを避けたいというか。
しかし、画面を出すにはJavaを使わないといかんし、RC-S620/SのライブラリをC/C++で作っているのでJNIを使わないといかん。

なのでいろいろと避けてきたのだが、そういえばNativeActivityというものがあることを思い出した。
ゲームなどの高速性が必要となる分野にはいいよ、みたいな記事をよく見かけたのだが、単にJavaを使うのがめんどうという人にも使えないだろうか?

そんな気持ちでやってみる。
3連休なのに家から出てないいいわけをするためにやっているわけではないぞ。


まず手本となるのは、NDKのサンプルであるnative-activityだろう。
サンプルを見ながらEclipseに組込み、動かす。
もちろん、動く。

OpenGL|ESなんかもよく知らないので、とにかく必要最低限のところまで削除することにした。
そうすると、glueを使う限りはあまり苦労しそうにない。

  • hasCode=false
  • android_main()
  • app_dummy
  • ALooper_pollAll()

コールバックを登録しておくと、タッチイベントがとって来れた。
座標もわかるので「見えないボタンを押す」と考えれば、適当な処理を座標で分岐すればできそうだ。
まあ、画面サイズの取得がわからないけど・・・。

よくわからんところも多いが、ここら辺から始めるかね。


static int32_t handle_input(struct android_app* app, AInputEvent* event)
{
        LOGI("handle_input");
        switch(AInputEvent_getType(event)) {
        case AINPUT_EVENT_TYPE_MOTION:
                LOGI("(%f, %f)", AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0));
                break;
        default:
                break;
        }
        return 0;
}

static void handle_cmd(struct android_app* app, int32_t cmd)
{
        LOGI("handle_cmd");
}

void android_main(struct android_app* state) {
    app_dummy();

    state->userData = 0;
    state->onAppCmd = handle_cmd;
    state->onInputEvent = handle_input;

    while (1) {
        int ident;
        int events;
        struct android_poll_source* source;

        while ((ident=ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) {
            if (source != NULL) {
                source->process(state, source);
            }

            if (ident == LOOPER_ID_USER) {
            }

            if (state->destroyRequested != 0) {
                break;
            }
        }
    }
}

2011/03/19

[falp]開始の所だけ書いてみた

FALP開始の所だけ、Android2.3.3・・・というか、余所様のソースに追加して書いてみた。
動くかどうか試せなかったので、OBEXの接続をする前までしかやってない。
9割がた動かないんじゃないのー、というところ。

https://github.com/hirokuma/Android_NFC_FelicaEdit

参考にさせていただいたサイトは、ゆめ技さんのところ。

Androidのところがあってるのかどうかすら、よくわからない。。
動くのか動かないのか、動かないときは何が動かないのか、教えていただけると非常に喜びます。


(後日)
うごいたー、という話を聞かないから、やっぱりだめなのだろう。
まあ、うまくいったとしても、携帯電話の状態が変化するだけだから、機種によってはわからないのかも。
それもまたよし、だ。

2011/03/18

「マーケティングの除外」が効いているようだ!

久しぶりにandrolibやandroiderを見ると、私のアプリが無くなっていた。
ほほう、これが「マーケティングの除外」か!

疑ってすまんかった。

[falp]画像はちょっと大変

何が大変かというと、解析作業がだ。

Snoopy Proでキャプチャし、それをExcelみたいなのに1byteずつ書き写して解析している。
XMLにしてから貼り付けられるのかもしれんが、どうせ解析するときには1byteずつ眺めるので、どうでもいい。
どうでもいいが、この作業に時間がかかる。

とりあえずわかったのは、2つ。

  • X-DOCOMO-というタグがある
  • 画像はBase64になってる

というわけで、画像のサイズだけでも3分の4倍になる計算だ。

2011/03/17

[falp]FeliCaチップじゃないと無理なんじゃなかろうかね

ふっと、NexusS向け(Android2.3.3)にFALPのコードを書いてみたら、他の環境でも試してもらえるのでは?と思った。
うちではP906iだけでしか確認できないので、ちょっと寂しいからだ。

しかし、またふっと思った。
あれはやはり、FeliCaチップじゃないと無理なんじゃなかろうかね?と。
持ってないもののコードを書くのはつらいし、動いても動かなくてもなんだかわからないので、やっぱりやらなくて正解だろう。

もし動いたら・・・
どういうことなんだろう?
PUSHだって動いているようだし、案外サポートされているのか?
気にはなるが・・・。

2011/03/16

[falp]長いテキスト送信

FALPで長いテキストを送信した。 vNote形式だ。 ツールとしては、ブックマークやメールなんかも転送できるようだが、それはFALPではなくOBEXの範囲だ。 だから、あまり気にしない。
やってみてわかったのは、FALPのコマンド種類がまだあるということだ。
  • 0x00 : FALP開始(HELLO)
  • 0x01 : FALP開始了解(HEY)
  • 0x02 : FALP転送-途中(CSND)
  • 0x03 : FALP転送-最後(SEND)
  • 0x05 : キャンセル(ADIOS)
  • 0x07 : FALP終了(BYE)
たぶん、0x04や0x06もあるんだろうな。
今回でいえば、長いテキストはOBEX PUTの部分に当たる。 ここがFALPの1回で送信できるサイズを超してしまったので、別のFALPパケットに分けたというところだ。 そのとき、続きがありますよという意味で0x02を使うようだ。
画像を送ってみると、さらによくわかるだろう。 あれはテキストの比ではないだろうからな。

2011/03/15

[falp]どうやって受信するかが思いつかない

FALPについて、今日は何もしていない。
何をしていいのかわからない、というところだ。

送信ができたんだから受信はその逆をやればいいだろう、と軽く考えていた。
しかし、最初に届いたFeliCaコマンドは、今まで見てきたものとは異なるものであった。
うーむ。

対策は3つ。

  1. 適当に応答を返してみる
  2. FNの情報を待つ
  3. 忘れる

2と3は近いのだが、進む意志を見せる2に対し、3は忘却の彼方だ。
忘れ去ることなり。

1もいいんだけど、LLCPのときにめんどくさくなったことを思い出した。
わかっているコマンドですら面倒なのに、知らないコマンドなどどうやればいいというのだ。
総当たりしてまで調べたいものでもないし。

じゃあ別のことをしてみるか。
Androidで動くようにする、というのは面白いかもしれん。
しかし、BeagleBoard+RC-S620/Sで動かしても、あまり楽しくない。
SmartQ5で動かすのはいいかもしれないけど、使い道無いしなぁ。

もうちょっと地道にいこう。

  • 長い文字列を受信してみる
  • 画像を受信してみる

似たようなものなんだけど、どちらもやってみたほうがいいだろう。
FALP受信の資料は出てくるのかなぁ。

2011/03/14

[falp]サンプルソース

FALPのサンプルを作っている。
下の方に「initAsFalp()」という関数がある。
ここら辺で、今まで書いてきたことを実際にやっている。
書いてないこともたくさんある。
あまりにもわからんからだ。
そのうちFNさんから資料が出るらしいので、期待しておこう。
コメントは日本語だけど、日本語EUCで書いているのでgithubでは化けてるようだ。
だって、UTF-8でコンパイル通るかわからんのやもん。。。
サンプルは、RC-S620/S+cygwinで確認している。PaSoRiでもいけた。
ただ確認した相手は、ドコモのP906iのみである。
他でうまくいくかは、わからんです。
もう少し中身がわかればいいんだけど、今はマジックナンバーばかり。
ここら辺も、FNさんの資料に期待しよう。

[falp]7. 終了

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

7. 終了
ようやく最後だ。
おそらく、FeliCaコマンド0xaaがFALP開始で、終了が0xaeだ。
よくわからないが、FALPコマンド0x07(BYE)をつけることで終わるみたいである。
確証も何もないがね。
この0xaeコマンドは、レスポンスがない。
レスポンスがないことがFALPの終わりなのかもしれない。
最後に、こちらからACKを送信している。
ACKのみの送信は、キャンセル動作に当たるんだったと思う。
あとは、RFConfigurationで無線を停止させるだけだ。

[falp]6. OBEX disconnect

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

6. OBEX disconnect
DISCONNECTは一番簡単。
0x81を投げると、0xa0が返ってきて、おしまい。

[falp]5. OBEX put

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

OBEX PUTは、そんなに語ることがない。
CONNECTも本来はそんなに語ることはなかったはずなのだが、FALPの転送についての推測を長々と書いてしまった。
ここは短くいきたい。
OBEX PUTで送っているのは、vNOTE形式のテキストデータ。
BEGIN:VNOTE
VERSION:1.1
DCREATED:20110311T111804Z
LAST-MODIFIED:20110311T111804Z
BODY;CHARSET=SHIFT_JIS;ENCODING=QUOTED-PRINTABLE:abc CATEGORIES:
END:VNOTE
赤文字が、文字列として送ったもの。
こんなところだ。

[falp]4. OBEX connect

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

4. OBEX connect
こっから先は、実はFALPとはあまり関係がない。
FALP転送コマンドでOBEXパケットをやりとりするところだ。
FeliCaコマンド0xbcで送る。
このコマンドはいつものと少し違う。
普段、コマンドを投げるとレスポンスとして+1した値が返ってくる。
しかしこの0xbcは、レスポンスがない。
あるのかもしれないが、少なくとも返ってきているのは確認できなかった。
どうするかというと、相手も0xbcで返してくる。
足を止めてのインファイトだ(意味不明)。

今回のOBEX は、
  1. CONNECT(0x80)
  2. PUT(0x82)
  3. DISCONNECT(0x81)
だけである。
後ろに書いた値は、コマンド値だ。
CONNECTがFALPとして渡す最初のデータだからか、シーケンス番号が0x0000だった。
0xbcはレスポンスがないと書いたが、R/Wのコマンドに対するレスポンスはある。
これが・・・いつもの戻り値と違うのだ。
R/Wに直接データを渡す系統のコマンドは、だいたい「結果」が1byteある。
0x00なら成功で、それ以外はエラーというのが一般的だ。
しかしここでは、普通に0x01が返ってくる場合が多い。
うまくいっていないわけではない。
そういう応答みたいなのだ。
もちろん、0x00の場合もある。
そのときは、0xbcに続けてデータがやってくる。
なので、私はこう考えた。
  • 0x01で返るときは、相手から送るデータがない場合
  • 0x00で返るときは、相手からのデータがある場合

ではこちらはどう動いているかというと、これがまたよくわからない。
例のコマンド。
あれをデータ長無しで送っているのだ。
これが相手に渡ると、さっきの0x01になるのだろうか?
そして困るのが、パラメータが毎回異なること。
同じ値であれば、わからないなりに同じ値を使うのだが・・・。
そこで私が得た結論は、こうだ。
  • 例のコマンドの第1、第2パラメータは、やはりタイムアウトで正しい
  • タイムアウト値はランダム
そうでないと、説明が付かない。
RFConfigurationでタイムアウト値を設定するところがあるのだが、この範囲内でやっているのかもしれないし、FALPのHELLOでパラメータがたくさんあったから、その範囲でやっているのかもしれない。
そこのところは、よくわからん。
わからんが、ランダム値だろう。
今回の実装では、めんどくさいので固定値にした。

ちなみにOBEX CONNECTは、0x00が正しい。
ただOBEXは複数回パケットをやりとりすることを想定していて、最後に送るコマンド値は最上位ビットを立てるようになっている。
だから、0x80になるのだ。
CONNECTを受け付けると、相手から0xa0が返ってくる。
これも、0x20の最上位ビットがついたものかもしれん。
CONNECTを行うと、相手のバッファサイズなどがわかるので、小さい方に合わせてやりとりをするのかな。
いや、FALPはFALPコマンドの中で同じようなことを最初にやっているはずだ。
ここのところは、FALPの仕様書レベルものがないとわからんだろう。

[falp]3. 準備2(OBEX準備?)

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

3. 準備2(OBEX準備?)
OBEX準備と書いたが、FALPはここから始まると見てよいのではなかろうか。
ここから先はFeliCaコマンドだけなので、例のコマンドで送信する。
ただ、例のコマンドにはタイムアウト値がパラメータとしてあると思うのだが、この辺りからそうではなくなってきているような気がする。
あくまで「気がする」だ。
FeliCaコマンドは0xbc。
続けてUID。
そしてつらつらデータがあって、おそらくFALPコマンドとシーケンス番号が続く。
それがここ数日間、値を眺めていた結論だ。
今のところ、
  • 0x00 : FALP開始(HELLO)
  • 0x01 : FALP開始了解(HEY)
  • 0x03 : FALP転送(SEND)
  • 0x05 : キャンセル(ADIOS)
  • 0x07 : FALP終了(BYE)
だと考えている。
あ、アルファベットのやつはライブラリソースに書いている名称だ。
正式なものでもなんでもない。
最初はHELLOを投げると、相手からHEYが返ってくる。
そしたらFALP転送のやりとりが続くことになる。
で、HELLOの中身は、さっぱりわからない。
「DCMI20」という文字があったが、文字列らしきものはそれくらいだ。
なので、これはOBEXかなんかの準備なんじゃないかな、と思った次第だ。
DCM、はたぶんDoCoMoだな。

[falp]2. 準備1

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

2. 準備1
はい、もう具体的な説明ができないところになりました。。。
ここでは0xaaというFeliCaコマンドを使っている。
サブコマンドではなく、FeliCaのコマンド。
R/Wへは例のコマンドを使って送る(コマンド名はRC-S620/Sのドキュメントに書いてあるので、私は書けない)。
パラメータは、IDmと、2byteのUIDらしきもの、それと4byteの何かわからない値。
この「UID」としたものは、セッションIDみたいなものみたい。
このUIDをFALP中はずっと使うことになる。
4byteのわからない値は、何回やっても同じ値なので、わからないまま使っている。

[falp]1. R/Wの準備

見たところ、FALPは以下の順で行っていると推測している。
推測に沿って見ていく。
1. R/Wの準備
2. 準備1
3. 準備2(OBEX準備?)
4. OBEX connect
5. OBEX put
6. OBEX disconnect
7. 終了

1. R/Wの準備
いつもの初期化に加え、RFConfigurationが2つ行われていた。
0x80と0x0b。
0x0bは、PN533ではアナログ関係の設定らしい。
0x80は不明。
それに、これが役立っているのかどうかもわからないし、調べてない。
まねしてやったというレベル。
また、いつものようにポーリングも行う。
424kbpsであることの確認をしている。
まあ、私の携帯電話は424kbpsで対応しているからいいだろう。
Faver1.5とかだと212kbpsなんじゃないかな。
まあ、1.5にはFALPないけど。
やっているのはそのくらいだ。

[falp]推測過多

FALPを使って携帯電話に転送できると思われるアプリがあった。
これができるのはFALPしかない、と。
ならば、このアプリの動向を調べれば、FALPもわかるはず。
その推測で、パケットを取得し、解析した。
取得方法はそんなに種類がないので、省略しよう。
1回取得。
2回取得。
2回やると、比較して違いがわかりやすい。
しかし・・・それでもわからないので3回目。
それでも、わからないところは多数。

推測にしても、全部の説明ができない(推測だからか?)。
やったのは、PCからP906iに対してのメモ転送。
メモの中身は「abc」みたいな短いテキスト。
これを相手に押しつける。
1. R/Wの準備
・RC-S956に対してFALPの準備をする。
2. 準備1
・送信側が通信するためのUIDパラメータを決定し、受信側に送る。
・受信側が了解したら、UIDを返す。以後、このUIDを使って通信する。
3. 準備2(OBEX準備?)
・送信側が通信するためのパラメータを決定し、受信側に送る。
・受信側から何か返ってくる。
4. OBEX connect
  ・送信側がOBEXのCONNECTパケットを送信。
  ・受信側がCONNECTをACKする。

5. OBEX put
  ・送信側がOBEXのPUTパケットを送信。
  ・受信側がPUTをACKする。

6. OBEX disconnect
  ・送信側がOBEXのDISCONNECTパケットを送信。
  ・受信側がDISCONNECTをACKする。

7. 終了
・切断パケットを送信。
・受信側は、パケットを切断するが、あまり気にしてない。
8. 無線停止

青文字がOBEXパケットだ。
OBEXパケット以前にも解析できそうな内容があるのかもしれないが、見た目ではわからなかった。
ただ初回のUIDは、何らかの16bit乱数値を使っているように感じた。
また、FALPで使うFeliCaコマンドの仕様についても迷った。
未だによくわからない。
やってみたところ、5パターンくらいあった。
1. 初回の通信開始
2. 初回の通信開始に対する応答
3. データ送信
4. 中断
5. 終了
こんなところか。
今のところ、OBEXのデータには3byteくらいしか置いていない。
これももう少しすると、データ拡張するんだろうな。

地震に関して

ここまでの大きな地震に対して、何をいっていいのかよくわかりません。

個人でできることをしようと思います。

それと、邪魔にならないようにしようと思います。
想像、妄想したことを書くのは簡単なのですが、意味がないため、そのことだけは注意します。

2011/03/10

[falp]パケットを眺めてみよう

わーわーいうだけではだめだ。
行動で示さなければ!

というわけで、今日はFALPパケットを眺めてみた。


手順

  1. iC通信で携帯電話に文字列を転送する
  2. そのパケットを取得する

以上。


私が持っているのは、DoCoMoのP906iなので、iC通信だ。
他の端末の人は、それぞれ読み替えていただきたい。

これでパケットはとれたのだが、読んでもよくわからん。
「なにやってんだ、これは?」か、「こんなコマンド載ってないぞ?」か。

それでも、データを眺めていると文字列の部分はわかる。
特に暗号化したデータでもないので、文字列を送ればわかりやすい。
これがいきなりバイナリファイルだと、なんだかわからんからね。


FALPというのは、LLCP+PHYの構成に近いと思う。
アプリの部分は、規定してないのだ。データの送受がメイン。
今回のデータはOBEXになっていた。VNOTE。
OBEXはそんなに詳しくないが、タグの見覚えくらいはある。

なので、FALPを実装する、と書いても、FALPだけ載せてもよくわからない。
私がNFC-DEPは動いていると思うけど、相手がいないのでよくわからないのと同じだ。
確認するには、アプリ層まで含めて実装しないといかん。

そんなわけで、今回はOBEX+FALP、OBEXはもうごくごく簡単なものに絞ろう。
OBEXといっても、ファイル仕様だけではなく、プロトコル仕様もあったはずだ。
まあ、短いテキストだけなら、仕様書は読まなくても何とかなるんじゃないか。
あまい?

まあ、そんな軽い気持ちでやってみよう。
できなくても、FNさんから何か出てくるという情報があるので、そんなに悲観することもあるまい。
プールに飛び込む前の準備運動になればいいや、というところだ。

2011/03/09

[pn533]InListPassiveTarget

いわゆる「ポーリング」を行うコマンドである。
名称からすると、自分でRFを出さないターゲットのリストを取得するのだろう。

ここに書いたパラメータは一例にすぎない。
optionalなものは記載しなかったので、必要なら調べよう。


コマンド

main cmd sub cmd MaxTg BrTy data...
d4 4a 01 ※1 ※2

TypeA(106kbps)

main cmd sub cmd MaxTg BrTy
d4 4a 01 00

TypeB(106kbps)

main cmd sub cmd MaxTg BrTy AFI
d4 4a 01 03 ??

FeliCa(212kbps)

main cmd sub cmd MaxTg BrTy cmd system code request code time slot
d4 4a 01 01 00 ff ff 00 00

FeliCa(424kbps)

main cmd sub cmd MaxTg BrTy cmd system code request code time slot
d4 4a 01 02 00 ff ff 00 00

212kと424kの違いはBrTyだけなので、それ以外は共通でよい。

system codeのffffは、ワイルドカード。
メイン名システムが取ってこれる。
request codeの値によっては、レスポンスでシステムコードが取ってこれる。
といっても、全部が取ってこれるわけではない。
ほしければ、FeliCaコマンドを発行する必要がある。
タイムスロットは00固定でよかろう。


レスポンス

main cmd sub cmd NbTg data...
d5 4b nn ※2

nnは検出したターゲット数。
00のときは、data以降はない。
うまくいけば、01のはず。

TypeA(106kbps)

main res sub res NbTg Tg SENS_RES SEL_RES NFCID LEN NFCID1 ATS[]
d5 4b 01 01 xx yy zz mm pp qq rr ss ...

ここでNFCID1と書いたが、ここのサイズは何種類かある。
SENS_RESからわかるが、LENも取得できるからまあいいだろう。
4byte, 7byte, 10byte。4byteはUniqueではなくなったという。

TypeB(106kbps)

main res sub res NbTg Tg ATQB res ATTRIB_RES LEN ATTRIB_RES[]
d5 4b 01 01 [12byte] xx ...

よく知らん。持ってない。

FeliCa(212k/424kbps)

main res sub res NbTg Tg POL_RES LEN res NFCID2 Pad
d5 4b 01 01 xx 01 [8byte] [8byte]

NFCID2は、いわゆるIDm。PadはPMm。
コマンドを投げるときにシステムコードを要求すると、メインのシステムコードも返ってくる。

基本的にFeliCaにコマンドを投げる場合は、まず相手のシステムコードをInListPassiveTargetで投げておくのが無難である。


追記1

InListPassiveTargetというコマンドにまとめられているが、行っている内容は種別によって異なる。
種別というのは、TypeAとかBとかだ。

こういうR/Wに投げたコマンドは、R/Wがエアプロトコルに変換してターゲットに投げる。
ここも、例えばPOL_REQなどに変換されているのだ。
POL_REQのパラメータが、InListPassiveTargetのパラメータと一致している。
なので、詳しいことが知りたければJIS X5211を見るのがよかろう。

2011/03/08

ALSA Module not foundとhw_get_module()

昨日の続き。
カメラアプリが起動しないので、その調査。

E/AudioHardwareALSA( 778): ALSA Module not found!!!

omxはどこをたどるとよくわからないので、logcatで最初に出ているこれを見ていこう。


cgrepで探してもいいけど、ALSAでHardwareと書いてあるので、hardwareディレクトリにいってalsaという名前を探すと、alsa_soundがあった。
中にAudioHardwareALSA.cppがあり、見てみると上記のログがあった。

cgrep/jgrepよりも、OESFさんが提供している検索サイトの方が、きっと速い。


さて、話を元に戻そう。

"ALSA Module not found!!!"が出る条件。
それは、ALSAのモジュールが見つからないこと。

・・・

Androidでよく用いられる関数にhw_get_module()がある。
hw_module_tのポインタのアドレスを渡すと、使えるアドレスを返してくれる関数だ。

hw_module_t *module;
err = hw_get_module(ALSA_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

こんな感じ。
hw_module_tはC++の基底クラスみたいなもので、各ハードウェアのI/Fはアドレスを取得した後、それをキャストして自前の構造体として使う。
Cでvirtualっぽいしくみを実現するのによく使う手法だ。


さて、このhw_get_module()。
こんなI/Fだ。

int hw_get_module(const char *id, const struct hw_module_t **module)

ALSA_HARDWARE_MODULE_IDは"alsa"。
つまりhw_get_module()は、"alsa"がわかればhw_module_tを返すことができるのだ。
まず、このプロパティがあるか。

  • ro.hardware
  • ro.product.board
  • ro.board.platform
  • ro.arch

あったら、そっから文字列を引っ張り出して、"/system/lib/hw"か"/vendor/lib/hw"にあるかどうか。
今は"/vendor"って使わなくなったように思うが、これは/deviceに移して、/vendorをそういう意味に使おうとしているだけなのかしら?
歴史を追ってないのでわからん。

それでもなければ、/system/lib/hw/*.default.soがあるかどうか。
それであれば、もういいみたい。

ということは、そこら辺になかったのだろう。


今回は、"alsa.*.so"がほしかったところ。
ないのは、ビルドしてないからか、置き忘れか。。。

こういうところから、少しずつやっていかないかんですな。

2011/03/07

[camera]OMXMaster::addPlugin()で落ちる

思い出しながら、USBカメラを動かそうとしている。
最後に動いたのは、froyoのとき。
gingerbreadでもそんなに変わらんだろうと思っている。
まあ、ディレクトリなんかは変わってたけど。

ドライバは、USBカメラを認識してくれた。
さて、とカメラアプリを起動させたのだが、いきなりアプリが落ちる。
logcatで見ると、

F/OMXMaster( 1088): frameworks/base/media/libstagefright/omx/OMXMaster.cpp:90 err != OMX_ErrorNoMore

などといわれている。
その後、mediaserverが落ちる。というよりも、mediaserverが落ちるのは上記のせいだろう。


よくわからないが、キーワードは「omx」「libstagefright」「openmax」というところか。
openmaxは、Android.mkに出てきてた。
libstagefrightは検索したけど、よくわからず。

出てきたのは、OpenMAX
これはKHRONOSがまとめてる?やつで、OpenGLとかあんなのと同じ感じがする。
ストリーミングのコーデックAPIをまとめているようだ。
omxは、これの略だろう。

カメラ画像はストリーミング的な扱いになっているのか?
フレームバッファにばんばん書き込んでるだけかと思っていたのだけど。
少なくとも、CameraHardwareはそんな風になってたな。

E/CameraHolder( 1098): fail to connect Camera

落ちた後は、こんなログが出ている。
android.hardware.Camera.open(id)が呼ばれているので、たどってみよう。
Cameraのコンストラクタが呼ばれ、native_setup()が呼ばれて。。。どこにいくんだ?
→frameworks/base/core/jni/android_hardware_Camera.cpp
→frameworks/base/libs/camera/Camera.cpp
・・・

疲れた。
全部追わなくていいのだけど、ログがこれくらいだとわからんなぁ。

まあ、Androidは久しぶりなので、リハビリがてら追っていくことにしよう。

2011/03/06

[camera]うちのUSBカメラは初期化に時間が足りないのか?

USBカメラをBeagleBoardで使えるようにしていた。
バッファローのBWC-35H01/SVというUSBカメラだ。
しかし昨年の10月くらいだったらしいので、ほとんど記憶にない。

まあ動くだろうと思ってやってみたのだが、だめ。
どうも、デバイスのopenでこけているみたいだ。
つまり、デバイスドライバのところ。

記憶にないので過去の記録を探ったところ、少し残っていた
どうやら、デバッグログを出すことで対処していたようだ。
まあ、それを対処と呼んでいいのかどうかは分からんが。

追加したのは、drivers/media/video/sn9c102/sn9c102_core.c。
そこのsn9c102_i2c_try_raw_write()。
sn9c102_i2c_wait()の直後に、DBG(2)とかでログを追加しただけだ。
なので、ログじゃなくても適当なwaitを追加すればいいんじゃなかろうか。

しかし・・・呼び出しているのがそもそもwaitの関数だよな・・・。
I2Cがらみで何かあるのかな?

[linux]シリアル通信の設定

RC-S620/Sでの開発はやらない!と書いたものの、中途半端なのはいかん。
Androidで動くかどうかくらいは見ておこうか。
しかしそうなると、やることが多くなる。。。
弱気なので、Linuxで動くことの確認、にしよう。


いくつかの修正が必要だったが、動いた。
必要な修正のほとんどは、シリアル通信についてだ。
今回はこのような設定で動いた。

struct termios ter = {0};
ter.c_iflag = IGNPAR;
ter.c_cflag = CLOCAL | CS8 | B115200 | CREAD;
tcsetattr(s_fd, TCSANOW, &ter);


受信がなかなか動いてくれなかったのだが、CREADしてなかったせいだと思う。
思うのだが、削ってみても動くようになった。
設定が残っているのか?

いつも忘れてしまうのが、カノニカル、非カノニカルの意味。
おおざっぱに言うと、リターンを押すまで出力しないのがカノニカルで、文字入力する度に出力するのが非カノニカル、ということになろう。

Windowsのオーバーレイアイコン数には上限があるらしい

TortoiseSVNとTortoiseGitを使っている。
TortoiseGitの方は、あんまり使っていないが便利そうなのでインストールしている。
さて、この2つ。
Explorerのオーバーレイアイコンが同じであるため、見分けにくい。
まあ、Windowsの場合は.gitとか.svnとかがあるのでわかるけど、できれば見た目でわかった方がうれしい。
なんとか見分けられるようにできないだろうか・・・。
と調べていると、どうやらWindowsのオーバーレイアイコンは15個までと決まっているらしい。
アプリとして使えるのは11個。
それなら、別々になると他が不便になるか。。。
そんなわけで、あきらめることにした。

仕様がないものを売るな

DEPをやろうと、いろいろRC-S620/SのコマンドをPN533の仕様書やISOやらJISやらを見ながらやってきた。
が、なんだ、この無駄な作業は?と思ってしまった。
普通は部品を買うと、仕様書が入手できるはずだ。
汎用部品ならともかく、RC-S620/Sはけっこうなデバイスだ。
仕様書が別売りといっても、一般人の入手ルートはない。
なら、なぜRC-S620/Sは一般人が入手できるのだ?
というようなことを思いついてしまった。
考えなければよかったんだけどねぇ。
いま持っている資料だけあれば、たぶんLLCPとかまで実装はできると思う。
だからといって、うちにあるP906iのiC通信(だっけ?)ができるわけではない。
これは、FALPの仕様書がないからだ。
そんなこんな考えると、FeliCaのカードが読みたいわけでもなかった私としては、買わなければよかったかも、という気がした。
買ってしまっただけに、使いこなそうとして、あれこれやってしまう。
まあ、NFCの仕様にはかなり詳しくなったような気はするが。。。本来の目的が果たせそうにない。
そういうわけで、土曜日の夜中なのに私は非常にお怒りである。
もう少し権力があれば、数社つぶすくらいのお怒りだ(意味不明)。
私が怒ったからといって何が変わるわけでもないだろうけど、それでもねぇ。

2011/03/05

[nfc][dep]私は考え違いをしていたように思う

私は・・・DEPについて考え違いをしていたのではなかろうか。

まず、PFBの件。
これは前回も書いたが、InDataExchange()の引数にする必要はないと思う。
PN533・・・もそうだが、きっとRC-S620/Sもそうだと思いたい。

ということは、だ。
PN533は、ISO-14443のDEPもサポートしている。
それもInDataExchange()で自動的にやってくれていることになる。
つまり、ISO-DEPとNFC-DEPを使い分けるのは、ホスト側が作るパケットというよりも、コントローラ側が現状を把握して使い分けているということになろう。

私も今、DEP_REQ/RESで通信できていると書いているが、実は既にNFC-DEPかISO-DEPで通信しているのではないか?ということである。


しかし、それがどうなのかを確認するのは難しい。
リファレンス機というか対抗機というか、相手がいないからわからないのだ。
せめて、PN533ではどこを見て使い分けているのかを調べておこう。

ドキュメントp.102に、PN533からターゲットに渡すパケットが書かれている。
ターゲットに応じてパケットの中身が変わってきている。
p.153をみると、ISO-DEPの場合はSEL_REQの戻り値で区別しているように見える。

しかししかし、Type-AはISO-DEPもNFC-DEPもどっちもいける。
だから、相手からの応答だけで判断できないはずだ。
どっちでやるかの意志をどこかで示しているはず。

私にわかるのは、ISO-DEPの場合はInListPassiveTargetから始まり、NFC-DEPの場合はInJumpForPSLから始まっているということ。
InJumpForPSLは、ほとんどInJumpForDEPと同じはず。
PSLだから、通信速度も変更するのかな?

それくらいしか、違いがわからない。


なので、今はいきなりInDataExchangeをしているから、NFC-DEPになっていると思う。。。

その認識でいいのかなぁ。

[nfc][dep]PFBはホストからは不要な気がしてきた

PFBの仕様を読みながら、どう実装しようかと考えていたのだが、不要な気がしてきた。
コントローラがうまいことやってくれるんじゃなかろうか。

だって、MIビットの有無は引数として指定するのよ。
PN533のドキュメントで見ていなかったのだが、SecureなDEPのところで、Secureじゃないのとも比較しながらシーケンスが書かれているのだが、ホストからはPFBを指定してないのに、エアプロトコルになってからはPFBが出てきているのだ。

InDataExchangeのところにもあった。
ホストからPN533へはペイロードだけ渡しているのに、PN533からターゲットになるとDEPヘッダが付加されているのだ。
もうこれは、間違いなかろう。
PN533は、PFBを制御している。

RC-S620/Sはどうなのだ?
これはわからない・・・。
わからないが、私は何もしてないのに通信できているのだから、RC-S620/Sは何もしていないのでうまくいっているか、ちゃんと制御しているからうまくいっているのかのどちらかだ。
そうなると、後者である可能性が高いな。

私は男らしく、ライブラリからPFBの実装を削った。。。

[nfc][dep]中断後にエラー

DEP_REQ/RESレベルでの送受信はできている。
まあ、これはコマンドを投げれば返ってくるので、そんなに難しいことではない。

depping.jpg

こんな感じでDEPをやっている。
今のところシングルスレッドでやっていて、ユーザ操作はほとんどできない。
なので、DEPでデータをやりとりしているのを中断させるのに、お互いを引き離す、という方法でやっている。
このときの動きがそれぞれ違う。

InitiatorにしているPaSoRiは、しばらくしてからタイムアウトしている。
まだタイムアウト処理など組み込んでいないので、PaSoRiがしばらくすると返事をしてくれていることになる。
Statusは0x13だ。

TargetにしているRC-S620/Sは、すぐに終了する。
TgSetDataがStatus=0x31で返ってくる。
それはいいのだが、困っているのはその次。
終了させようとしてコマンドを投げるのだが、エラーフレームと認識されてしまう。
リセットコマンドは大丈夫なのだが、その次に投げているRFConfigurationがそうなる。
あー、でも搬送波は出てなさそうだな。P906iが反応してない。

エラーフレームはパケットの文法エラーなので、中身が間違っていることになる。
しかし普段は大丈夫なコマンドなので、少なくともそこの実装に間違いはない。
もしかすると、タイムアウトしてから送ったコマンドが残っているとか・・・とも思ったが、RC-S620/Sはタイムアウト時間を持っていて、それ以上経つと受信したパケットを破棄する。
だから、そんなことはない。

うーむ。。。


待ち受けているコマンドが決まっているのだが、それが来てないのでエラーにしている、という筋書きを考えた。

しかし・・・それはなぁ。
情報がないのだ。。。

InReleaseしてみたが、やはりだめだ。Status=0x31が返ってくる。
Statusの意味がわからんな。。。情報がないのだ。。。
まあ、InReleaseはInitiatorのコマンドだから動かんのが当たり前か。

もう少しFeliCaのことを強く考えながらでないとうまくいかないのだろうか。

[nfc][dep]ISO18092とJIS X5211

前回、ISO 18092を読みながらDEPを解釈していった。
しかし私の英語には不安がある・・・。
そこで、今日はJIS X5211を読んでみることにした。
全部はきついので、関係あるところだけ。

自分の誤訳がいくつも見つかった。
ターゲットの「RTOしか送ることができん」は「代わりにRTO pduを送ることもできる」とか。
Initiatorのタイムアウトに関するところも間違えていた。
ここら辺は、こそっと修正しておこう。


それはいいのだが、用語として困っているものがある。
「data pdu」だ。
X5211は「情報pdu」と訳している(pduは、Protocol Data Unit)。
しかし、情報pduは「Information pdu」という用語が既にある。
これはまずいのではないか?

それに、こんな文もあった。

(前略)情報pduによって、確認応答しなければならない。

ちょっと待て。
確認応答にはACK/NACK pduというものがあるだろう。
英文も「shall be acknowledged by an ACK pdu」となっている。


私が持っているISO 18092が古いか何かなのか?


NFC Forumのドキュメントも合わせて読んでみた。
こちらは、書き方がちょっと違う。

連鎖ビットが立ってないInformation PDUを受信したら、Information PDUかRTOX要求のどちらかだ。

そんな意味になるか。
これはわかりやすい。
わかりやすいのだが、ISO 18092ともJIS X5211とも解釈が違うように思う。

なにがなんだか、わからなくなってきた。。。

[nfc]副作用

いい情報をいただいた。
PaSoRiはFeliCa以外の規格に対応したための副作用がごにょごにょあって、電気的にターゲットになりにくいらしい。

た、確かに・・・。
確かに私は、昨日ターゲットでPaSoRiを動かそうとしていたのだ。
以前「ターゲットになれないようだ」と書いていたけど動いたので、今日は訂正文を書こうかと思ったくらいだ。

まったく動かないわけでもなかったから、不安定ということかな。
とにかく、動作させる環境の不安定要素がわかったのは大きい。

2011/03/04

[nfc]うまく動かないときは、動かない

よくわからん。

DEP関係のコマンドが、うまく動くときと動かないときがある。
理由がさっぱりわからない。
まあそもそも、コマンドがRC-956でどう動くのかわかっていないのが一番の問題なのだが。
PN533マニュアルでは、さすがに限界がある。

かといって、正式なマニュアルは入手できない。
ここらへんが、個人で(遊びではあるが)開発するのに不便なところだ。

なんとかしてくれー

2011/03/03

[nfc]RC-S620/Sの終わらせ方

DEPを中断させると、それ以降RC-S620/Sへアクセスできなくなった。
アプリエラーが返ってくる。

もちろん、電源を落とせば大丈夫なのだが、それはめんどくさい。
よくわからないリセットコマンドを使ってみると、なんかよさそうな気がする。
もしかすると、RFを停止させたのがよかったのかもしれんが、確認してない。

Ctrl+Cでだめになるのは、しかたがない。
シリアルはつなぎっぱなしだろうし、電源も供給されたままなので、RC-S620/SはCtrl+Cされたことすら知らないだろう。
ステージが初期化されないといかんだろう。

なので「もう使い終わりましたよー」を通知しないと行かんと思うのだが、そのあたりがよくわからん。
リセットコマンドでよいような気がするけど、アプリエラーが返ってきてるような。。。
あるいはその手前に投げているコマンドがよくないのか。。。

冷静な判断と情報がほしいところである。
あ、冷静な判断は私がやらんといかんところだな。。。

2011/03/02

[nfc][dep]どう非同期にしたものか

DEP関係のコマンドは、相手が何かしないとレスポンスが返ってこない。
いずれは、タイムアウトやユーザからのキャンセルにも対応せねば。
そう考えると、今のうちに非同期APIにしておいたほうが無難だ。

しかし、私は楽をしたい。
どんなプラットフォームでも使えるライブラリがいいんだろうけど、そんな労力を裂くのは嫌だ。
できるだけ簡単に非同期化したい。

思いつくのは、

  • POSIXなどのスレッドで使われることを前提にしてしまう
  • コールバックで返してやる

まあ、コールバックにしておくのがいいんだろうけど、じゃあ受信はどうやってさせるんだ?ということになってしまう。
ポーリングするAPIを用意して定期的に呼んでもらうくらいしかないなぁ。

Androidでやるなら、バックグラウンドでサービスを回しっぱなしにして、そこで定期的に呼んでもらうという手がある。
まあ、今がそんな感じだ。
携帯電話向けの実装なら、割り込みにするなどして消費電力を抑えないといかんけど、RC-S620/Sだからそこまで考えなくていいだろう。
搬送波だって、みっともないけど出しっぱなしだ。
(Nexux Sって、確か画面が点いている間は搬送波出しっぱなしだし、FeliCaロックみたいな形の止め方がないような気もするし、電池の減りが早そうだなぁ。)

まあ、それはそれとして。
受信側をポーリングにすると、全体的に非同期にしなくてはやりづらい。
かといって、なんもかんも非同期にすると、アプリがめんどくさくなりそうな。
通常のコマンドくらいなら、同期でも十分間に合うと思うのだよ。

そうなると、同期APIの場合は、ユーザからのコンテキストで待たせておいて、サービスからのコンテキストで受信結果が返るまで待たせる、ということになる。
そんな実装くらいしか思いつかない。

そうしてしまうと・・・cygwinで簡単に実装して動かす、というわけにはいかなくなる。
ちゃんとpthreadかなんかで動かす部分も一緒に作らなくてはならない。

ほら、めんどくさい。。。

2011/03/01

[nfc]ライブラリをgithubに置いてみた

置いた、と断言せず、置いてみた、と言葉を弱くするのは、いかん癖だな。
永遠のβ版、みたいな雰囲気をかもし出してしまう。

とにかくまあ、githubにこそこそと作っていたNFCのライブラリを置いた。
大半は、PN533から。次いでSONYさんのライブラリとJISから。あとはネットから。
そんな情報を寄せ集めて作っているので、完全には動かない物もありそうだ。
特に、パラメータについてはPN533を信用しきっている。
違ってたら、ごめん・・・。

基本的に、FeliCaカードへアクセスするAPIは少ない。
なぜかというと、私にとって使い道がないからだ。
もう少し充実してきて、FeliCa Liteなんかも買ったりして、遊べるようになったらがんばるかも。
それまでは、NFC-DEPの学習用になっている。

doxygen対応しているつもりなので、あればどうぞ。


使い方は、test/とtestp/を見ていただきたい。

あ、使うためには環境設定が必要。
READMEにも書いているが、NFCPCD_DEVを直接書き換えねばならない。
これがねぇ。。。Makefileでやりたかったのだけど、うまくできなかったのだ。
ダブルクォーテーションが消されてしまうみたいでね。
\"とかすればいいのかもしれんが、まあいいや。

libpafeを使えば、PaSoRiからもいけるつもり。
うちのRC-S370は動いている。
ここに感謝の意を示したい。
ありがとうございます。


でもまあ、FeliCaさんに「消して!」といわれたら、消すつもり。
今回公開したのは、規約が整理されたため。
これもまた、感謝である。
このライブラリを作ることができたのは、そもそもSONYさんのライブラリがあって動作確認ができたからだ。
それがないと、何もできなかっただろう。

必要となるコマンドはだいたいわかったとはいえ、下地となっているのはSONYさんのライブラリだ。
大半は書き換えたつもりではあるが、見る人が見ればわかるのかも。


ソースの解説などは、しません。
そんなに難しいことはしていないし。
あるとすれば「このコマンドは何?」がほとんどだろうから、それは調べていただきたい。
PN533のドキュメントにたいがい載ってるし、JISにも載ってるのは多い。

ああ、一週間分の仕事をした気持ちだが、まだ月曜日が終わったばかりなんだよな。
まあいいや。
2月の作業が終わった、ということで。

3月はNFC-DEPをがんばろう。