2012/10/13

[n7]FeliCa Lite用のライブラリを作ろう (1)

「作ろう」って書くと、「レジ袋とペットボトルでペンギンを作ろう」という歌(オフロスキー)を思い出してしまう。

それはどうでもいいとして、前回FeliCa Liteの読み込みをやろうとしたが、MifareUltralightみたいなクラスがないのでめんどくさかった。

誰か作っていそうな気がするけど、勉強がてらFeliCa Lite用のライブラリを作ろう。


(途中省略)


ひとまず、1ブロックのReadとWriteを作った。
ReadはPAD0の読み込みだけ確認。Writeは動作確認すらしていない。

https://github.com/hirokuma/NfcTest4/blob/master/src/com/blogpost/hiro99ma/nfc/FelicaLite.java

 

NfcFクラスを継承して、置き換えて使ってもらえるようなものにしようかと思っていた。
が、NfcFクラスはfinal classで継承できず・・・。
では、その親のBasicTagTechnologyクラスを継承しようとしたが、これはpublicじゃないので見えず・・・。

じゃあ、packageをandroid.nfc.techにすればいいか?とも思ったが、それはだめなような気がするので、is-aは諦めてhas-aの形にした(なんて呼ぶかわからん)。


こういうの、C/C++だといろいろと「強引な」やりかたがあるんだけど、Javaはさすがにできませんな。
まあ、それはその方がいいと思う。


Read

public static byte[] readBlock(int blockNo) throws IOException {
    byte[] buf = new byte[16];
    buf[0] = 16;                    //length
    buf[1] = (byte)0x06;            //Read Without Encryption 
    System.arraycopy(mTag.getId(), 0, buf, 2, 8);
    buf[10] = (byte)0x01;            //service num
    buf[11] = (byte)0x0b;            //service code(lower)
    buf[12] = (byte)0x00;            //service code(upper)
    buf[13] = (byte)0x01;            //blocklist num
    buf[14] = (byte)0x80;            //2byte-blocklist(upper)
    buf[15] = (byte)blockNo;        //2byte-blocklist(lower)
    
    byte[] ret = mNfcF.transceive(buf);
    
    //length check
    if(ret.length != 29) {
        ret = null;
        return null;
    }
    //IDm check
    for(int i=2+0; i<2+8; i++) {
        if(ret[i] != buf[i]) {
            ret = null;
            return null;
        }
    }
    //status flag check
    if((ret[10] != 0x00) || (ret[11] != 0x00)) {
        ret = null;
        return null;
    }
    
    //read data copy
    System.arraycopy(ret, 13, buf, 0, 16);
    ret = null;
    return buf;
}

シンプルに「コマンドデータ作成」「送信」「受信データチェック」「受信データコピー」の順に処理。
まあ、それ以外無いけど。

あ、受信データチェックに応答コマンド値(0x07)を見てないな・・・。
ブロック数をチェックしてないのは、データ長でほぼそれがわかるし、それ以外の値だったとしてもまあいいか、ということで。

サービスコードが0x000b固定なのは、ReadOnlyにしておけばRWでもROでも読めるようだから。
製品仕様なのかな? ドキュメントを読みきれてないけど、動いてるというレベル。


Write

public static boolean writeBlock(int blockNo, byte[] data) throws IOException {
    byte[] buf = new byte[32];
    buf[0] = 32;                    //length
    buf[1] = (byte)0x08;            //Write Without Encryption
    System.arraycopy(mTag.getId(), 0, buf, 2, 8);
    buf[10] = (byte)0x01;            //service num
    buf[11] = (byte)0x09;            //service code(lower)
    buf[12] = (byte)0x00;            //service code(upper)
    buf[13] = (byte)0x01;            //blocklist num
    buf[14] = (byte)0x80;            //2byte-blocklist(upper)
    buf[15] = (byte)blockNo;        //2byte-blocklist(lower)
    System.arraycopy(data, 0, buf, 16, 16);
 
    byte[] ret = mNfcF.transceive(buf);
 
    //length check
    if(ret.length != 12) {
        ret = null;
        return false;
    }
    //IDm check
    for(int i=2+0; i<2+8; i++) {
        if(ret[i] != buf[i]) {
            ret = null;
            return false;
        }
    }
    //status flag check
    if((ret[10] != 0x00) || (ret[11] != 0x00)) {
        ret = null;
        return false;
    }
    ret = null;
    return true;
}

こちらも、基本はReadと同じ。
返すデータが書き込みの成功か失敗になる、というところか。


途中でreturnするのが嫌いな人も多いだろうが、私は関数の最初(パラメータチェック)と最後(結果のチェック)ならreturnで抜けてもいいかな、と思っているので、こうなってる。

 

NfcF#transceive()の戻り値をreturn前にnull代入しているが、そこまでする必要はあるのかな?
いらんと思うけど、知識がない。。
無駄なコードを作り込んでいるような気がしてならん。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。