2011年1月30日日曜日

Android NFC での FeliCa の NDEF 判定

FeliCa standard に直接 byte[] data を書き込んでいたら、NDEF として認識されなくなっちゃったので、ちょっと調べてみました。

■ いきさつ

Android Bazaar and Conference で Sony さんに FeliCa Standard カードをいただいた。

 ・このカードには URL 情報が入っていた

 ・もらったときには Android 2.3 標準の Tag というアプリで
  NDEF として認識できてた

 ・自分用の FeliCa 情報を dump するアプリ (Suica Reader の
  tag info 部分と同じ) でも isNdef は true になっていた

 ・Raw Bytes をごりごり上書きしたら isNdef が false になってしまった


ということで、isNdef はどうやって判定しているのか調べてみた。


■ NFC の処理

polling で NFC タグが見つかると、NFCService の mHandler に message が送られます。

その結果 NfcService.java#2048 に辿りつきます。

判定は NfcService.java#2052 の if (nativeTag.checkNdef()) で行っています。

これが true だと NdefTag クラスのインスタンスが生成されて、Intent intent = buildNdefTagIntent(tag); で生成された Intent が broadcast されます。

  1. 2058                                msgNdef[0] = new NdefMessage(buff);  
  2. 2059                                NdefTag tag = new NdefTag(nativeTag.getUid(),  
  3. 2060                                        TagTarget.internalTypeToRawTargets(nativeTag.getType()),  
  4. 2061                                        nativeTag.getPollBytes(), nativeTag.getActivationBytes(),  
  5. 2062                                        nativeTag.getHandle(),  
  6. 2063                                        TagTarget.internalTypeToNdefTargets(nativeTag.getType()),  
  7. 2064                                        new NdefMessage[][] {msgNdef});  
  8. 2065                                Intent intent = buildNdefTagIntent(tag)  


  1. 2220         private Intent buildNdefTagIntent(NdefTag tag) {  
  2. 2221             Intent intent = new Intent();  
  3. 2222                intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);  
  4. 2223                intent.putExtra(NfcAdapter.EXTRA_TAG, tag);  
  5. 2224                intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());  
  6. 2225                intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, tag.getNdefMessages());  
  7. 2226                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  8. 2227             return intent;  
  9. 2228         }  


一方 false だと、 Tag クラスのインスタンスが生成されて、NfcAdapter.EXTRA_TAG キー との組み合わせとして Intent の extra に格納されます。

  1. 2102                        Intent intent = new Intent();  
  2. 2103                        Tag tag = new Tag(nativeTag.getUid(), false,  
  3. 2104                                TagTarget.internalTypeToRawTargets(nativeTag.getType()),  
  4. 2105                                nativeTag.getPollBytes(), nativeTag.getActivationBytes(),  
  5. 2106                                nativeTag.getHandle());  
  6. 2107                        intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);  
  7. 2108                        intent.putExtra(NfcAdapter.EXTRA_TAG, tag);  
  8. 2109                        intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());  
  9. 2110                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  


では、 checkNdef() を見てみます

NativeNfcTag.java#checkNdef

doCheckNdef を呼んでいます。

  1. 100     private native boolean doCheckNdef();  
  2. 101     public synchronized boolean checkNdef() {  
  3. 102         if (mWatchdog != null) {  
  4. 103             mWatchdog.reset();  
  5. 104         }  
  6. 105         return doCheckNdef();  
  7. 106     }  


この doCheckNdef() は native 側の com_android_nfc_NativeNfcTag_doCheckNdef を呼んでいます。

com_android_nfc_NativeNfcTag.cpp#571

  1. 571 /* 
  2. 572  * JNI registration. 
  3. 573  */  
  4. 574 static JNINativeMethod gMethods[] =  
  5. 575 {  
  6. ...  
  7. 582    {"doCheckNdef""()Z",  
  8. 583       (void *)com_android_nfc_NativeNfcTag_doCheckNdef},  
  9. ...  
  10. 590 };  


では、com_android_nfc_NativeNfcTag_doCheckNdef を見てみましょう。

com_android_nfc_NativeNfcTag.cpp#com_android_nfc_NativeNfcTag_doCheckNdef


phLibNfc_Ndef_CheckNdef() メソッドを呼んでいます。2番目の引数はこの処理が終わったときの call back です。

  1. 500 static jboolean com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o)  
  2. 501 {  
  3. ...  
  4. 504    jboolean result = JNI_FALSE;  
  5. ...  
  6. 512    status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)e);  
  7. ...  
  8. 523    if (nfc_jni_is_ndef == FALSE)  
  9. 524    {  
  10. 525       goto clean_and_return;  
  11. 526    }  
  12. 527   
  13. 528    result = JNI_TRUE;  
  14. 529   
  15. 530 clean_and_return:  
  16. 531    CONCURRENCY_UNLOCK();  
  17. 532    return result;  
  18. 533 }  


先に call back を見てみましょう。

com_android_nfc_NativeNfcTag.cpp#nfc_jni_checkndef_callback

引数の status が NFCSTATUS_OK なら nfc_jni_is_ndef に TRUE を、そうでなければ FALSE をセットしています。この nfc_jni_is_ndef は上記のcom_android_nfc_NativeNfcTag_doCheckNdef で参照されています。

  1. 60 static void nfc_jni_checkndef_callback(void *pContext,  
  2. 61    phLibNfc_ChkNdef_Info_t info, NFCSTATUS status)  
  3. 62 {  
  4. 63    LOG_CALLBACK("nfc_jni_checkndef_callback", status);  
  5. 64   
  6. 65    if(status == NFCSTATUS_OK)  
  7. 66    {  
  8. 67       if(nfc_jni_ndef_buf)  
  9. 68       {  
  10. 69          free(nfc_jni_ndef_buf);  
  11. 70       }  
  12. 71       nfc_jni_ndef_buf_len = info.MaxNdefMsgLength;  
  13. 72       nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len);  
  14. 73       nfc_jni_is_ndef = TRUE;  
  15. 74    }  
  16. 75    else  
  17. 76    {  
  18. 77       nfc_jni_is_ndef = FALSE;  
  19. 78    }  
  20. 79   
  21. 80    sem_post(nfc_jni_tag_sem);  
  22. 81 }  


では、phLibNfc_Ndef_CheckNdef のほうを見てみましょう。

phLibNfc_ndef_raw.c#phLibNfc_Ndef_CheckNdef

phFriNfc_NdefMap_ChkNdef を呼んでいます。また、 814 行目で先程の call back をgpphLibContext->CBInfo.pClientCkNdefCb にセットしています。

  1. 714 /** 
  2. 715 * This function allows  the user to check whether a particular Remote Device 
  3. 716 * is NDEF compliant or not 
  4. 717 */  
  5. 718 NFCSTATUS phLibNfc_Ndef_CheckNdef(phLibNfc_Handle       hRemoteDevice,  
  6. 719                         pphLibNfc_ChkNdefRspCb_t        pCheckNdef_RspCb,  
  7. 720                         void*                           pContext)  
  8. 721 {  
  9. ...  
  10. 770         for (cr_index = 0; cr_index < PH_FRINFC_NDEFMAP_CR; cr_index++)  
  11. 771         {  
  12. 772             /* Register the callback for the check ndef */  
  13. 773             RetVal = phFriNfc_NdefMap_SetCompletionRoutine(  
  14. 774                                 gpphLibContext->ndef_cntx.psNdefMap,  
  15. 775                                 cr_index,  
  16. 776                                 phLibNfc_Ndef_CheckNdef_Cb,  
  17. 777                                 (void *)gpphLibContext);  
  18. 778         }  
  19. 779         /*call below layer check Ndef function*/  
  20. 780         RetVal = phFriNfc_NdefMap_ChkNdef(gpphLibContext->ndef_cntx.psNdefMap);  
  21. ...  
  22. 812         if(RetVal== NFCSTATUS_PENDING)  
  23. 813         {  
  24. 814             gpphLibContext->CBInfo.pClientCkNdefCb = pCheckNdef_RspCb;  
  25. 815             gpphLibContext->CBInfo.pClientCkNdefCntx = pContext;  
  26. 816             gpphLibContext->status.GenCb_pending_status=TRUE;  
  27. 817             gpphLibContext->LibNfcState.next_state = eLibNfcHalStateTransaction;  
  28. 818         }  
  29. 819   
  30. 820     }  
  31. 821     return RetVal;  
  32. 822 }  
  33. 823   


では、phFriNfc_NdefMap_ChkNdef を見てみましょう。

phFriNfc_NdefMap.c#phFriNfc_NdefMap_ChkNdef

FeliCa に関係する部分を抜き出すと、phFriNfc_Felica_ChkNdef を呼んでいます。

  1. 632 NFCSTATUS phFriNfc_NdefMap_ChkNdef( phFriNfc_NdefMap_t     *NdefMap)  
  2. 633 {  
  3. ...  
  4. 737             case phHal_eFelica_PICC:  
  5. 738   
  6. 739                 /*Set the OpMode Type Flag*/  
  7. ...  
  8. 745                 status = phFriNfc_Felica_ChkNdef(NdefMap);  
  9. ...  
  10. 751                 break;  
  11. ...  
  12. 841 }  


では、phFriNfc_Felica_ChkNdef を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_ChkNdef


phFriNfc_Felica_HUpdateManufIdDetails と phFriNfc_Felica_HRdAttrInfo が呼ばれています。

  1. 2118 NFCSTATUS phFriNfc_Felica_ChkNdef( phFriNfc_NdefMap_t     *NdefMap)  
  2. 2119 {  
  3.  ...  
  4. 2128     /* check the ndef compliency with the system code reecived in the RemoteDevInfo*/  
  5. 2129     status = phFriNfc_Felica_HUpdateManufIdDetails(NdefMap);  
  6. 2130   
  7. 2131     if (status == NFCSTATUS_SUCCESS)  
  8. 2132     {  
  9. 2133   
  10. 2134         /* set the operation type to Check ndef type*/  
  11. 2135         NdefMap->Felica.OpFlag = PH_FRINFC_NDEFMAP_FELI_CHK_NDEF_OP;  
  12. 2136         status = phFriNfc_Felica_HRdAttrInfo(NdefMap);  
  13. 2137     }  
  14.  ...  
  15. 2149 }  


まず、phFriNfc_Felica_HUpdateManufIdDetails を見てみます。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HUpdateManufIdDetails


システムコードが 0x12 0xFC かどうかチェックしています。
これ以外の場合、status として NFCSTATUS_NO_NDEF_SUPPORT が返されるので、NDEFではないと認識されます。

つまり、FeliCa Lite の場合 0x88 0xb4 が返ってくるので、ここで NDEF ではないと認識されてしまいます。

  1.  2205 /*! 
  2.  2206  * ¥brief Checks validity of system code sent from the lower device, during poll operation. 
  3.  2207  */  
  4.  2208   
  5. 2209 static NFCSTATUS   phFriNfc_Felica_HUpdateManufIdDetails(const phFriNfc_NdefMap_t *NdefMap)  
  6.  2210 {  
  7.   ...  
  8.  2214     /* copy the IDm and PMm in Manufacture Details Structure*/  
  9.  2215     (void)memcpy( (uint8_t *)(NdefMap->FelicaManufDetails.ManufID),  
  10.  2216                 (uint8_t *)NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm,  
  11.  2217                 8);  
  12.  2218     (void)memcpy( (uint8_t *)(NdefMap->FelicaManufDetails.ManufParameter),  
  13.  2219                 (uint8_t *)NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm,  
  14.  2220                 8);  
  15.  2221     if((NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode[0] == 0x12)  
  16.  2222         && (NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode[1] == 0xFC))  
  17.  2223     {  
  18.  2224         status = PHNFCSTVAL(CID_NFC_NONE, NFCSTATUS_SUCCESS);  
  19.  2225     }  
  20.  2226     else  
  21.  2227     {  
  22.  2228          status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,  
  23.  2229                                         NFCSTATUS_NO_NDEF_SUPPORT);  
  24.  2230     }  
  25.   ...  
  26.  2260     return (status);  
  27.  2261   
  28.  2262 }  


次に、phFriNfc_Felica_HRdAttrInfo を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HRdAttrInfo


システムコードが 0x12 0xFC だけでは NDEF とは認識されず、ここでさらにチェックされます。

read コマンドを送って、0x000B のサービスコードの1ブロック目を読んでいます。
ここは、 Random Access (Read Only) の領域です。

受信データは NdefMap->SendRecvBuf[] に入ります。

カードのオペレーション終了時に呼ばれる処理は 2772行目で設定されており、
phFriNfc_NdefMap_Process が呼ばれます。

  1. 2704 static NFCSTATUS   phFriNfc_Felica_HRdAttrInfo(phFriNfc_NdefMap_t *NdefMap)  
  2. 2705 {  
  3. 2706   
  4. 2707     NFCSTATUS   status = NFCSTATUS_PENDING;  
  5. 2708     uint8_t BufIndex = 0;  
  6. 2709   
  7. 2710     /* Set the Felica Cmd*/  
  8.  ...  
  9. 2712     NdefMap->Cmd.FelCmd = phHal_eFelica_Raw;  
  10.  ...  
  11. 2720   
  12. 2721     /* 1st byte represents the length of the cmd packet*/  
  13. 2722     NdefMap->SendRecvBuf[BufIndex] = 0x00;  
  14. 2723     BufIndex++;  
  15. 2724   
  16. 2725     /* Read/check command code*/  
  17. 2726     NdefMap->SendRecvBuf[BufIndex] = 0x06;  
  18. 2727     BufIndex++;  
  19. 2728   
  20. 2729     /* IDm - Manufacturer Id : 8bytes*/  
  21.  ...  
  22. 2731     (void)memcpy((&(NdefMap->SendRecvBuf[BufIndex])),  
  23. 2732                 (void * )&NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm,  
  24. 2733                 8);  
  25.  ...  
  26. 2740   
  27. 2741     BufIndex+=8;  
  28. 2742   
  29. 2743     NdefMap->SendRecvBuf[BufIndex]    =   0x01;  /*  Number of Services (n=1 ==> 0x80)*/  
  30. 2744     BufIndex++;  
  31. 2745   
  32. 2746     NdefMap->SendRecvBuf[BufIndex]    =   0x0B;  /*  Service Code List*/  
  33. 2747     BufIndex++;  
  34. 2748   
  35. 2749     NdefMap->SendRecvBuf[BufIndex]    =   0x00;  /*  Service Code List*/  
  36. 2750     BufIndex++;  
  37. 2751   
  38. 2752     NdefMap->SendRecvBuf[BufIndex]    =   0x01;  /*  Number of Blocks to read)*/  
  39. 2753     BufIndex++;  
  40. 2754   
  41. 2755     NdefMap->SendRecvBuf[BufIndex]    =   0x80;  /*  1st Block Element : byte 1*/  
  42. 2756     BufIndex++;  
  43. 2757   
  44. 2758     NdefMap->SendRecvBuf[BufIndex]    =   0x00;  /*  1st Block Element : byte 2, block 1*/  
  45. 2759     BufIndex++;  
  46. 2760   
  47. 2761     NdefMap->SendRecvBuf[PH_NFCFRI_NDEFMAP_FELI_PKT_LEN_INDEX]             =   BufIndex;  
  48. 2762   
  49. 2763     *NdefMap->SendRecvLength = NdefMap->TempReceiveLength;  
  50. 2764   
  51. 2765     /* Update the Send Len*/  
  52. 2766     NdefMap->SendLength = BufIndex;  
  53. 2767   
  54. 2768     /* Change the state to  PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR */  
  55. 2769     NdefMap->State =  PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR;  
  56. 2770   
  57. 2771     /*set the completion routines for the desfire card operations*/  
  58. 2772     NdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_NdefMap_Process;  
  59. 2773     NdefMap->MapCompletionInfo.Context = NdefMap;  
  60. 2774   
  61. 2775     /*Call the Overlapped HAL Transceive function */  
  62. 2776     status = phFriNfc_OvrHal_Transceive( NdefMap->LowerDevice,  
  63. 2777                                          &NdefMap->MapCompletionInfo,  
  64. 2778                                          NdefMap->psRemoteDevInfo,  
  65. 2779                                          NdefMap->Cmd,  
  66. 2780                                          &NdefMap->psDepAdditionalInfo,  
  67. 2781                                          NdefMap->SendRecvBuf,  
  68. 2782                                          NdefMap->SendLength,  
  69. 2783                                          NdefMap->SendRecvBuf,  
  70. 2784                                          NdefMap->SendRecvLength);  
  71. 2785       return (status);  
  72. 2786   
  73. 2787 }  
  74. 2788   


では、phFriNfc_NdefMap_Process を見てみましょう。

phFriNfc_NdefMap.c#phFriNfc_NdefMap_Process

FeliCa の場合、phFriNfc_Felica_Process が呼ばれています。

  1. 854 void phFriNfc_NdefMap_Process(  void        *Context,  
  2. 855                               NFCSTATUS   Status)  
  3. 856 {  
  4. 857   
  5. 858     if ( Context != NULL )  
  6. 859     {  
  7. 860         phFriNfc_NdefMap_t  *NdefMap = (phFriNfc_NdefMap_t *)Context;  
  8. 861         /* 
  9. 862         * 4 Changed 
  10. 863         *   Description: Opmode replace with RevDevTyp. 
  11. 864         */  
  12. 865   
  13. 866         switch ( NdefMap->psRemoteDevInfo->RemDevType )  
  14. 867         {  
  15. ...  
  16. 908         case phHal_eFelica_PICC :  
  17. ...  
  18. 910             /*  Remote device is Felica Smart card */  
  19. 911             phFriNfc_Felica_Process(NdefMap, Status);  
  20. ...  
  21. 916             break;  
  22. 917   
  23. ...  
  24. 960         }  
  25. 961     }  
  26. ...  
  27. 969 }  
  28. 970   


では、phFriNfc_Felica_Process を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_Process

2321 if ( NdefMap->SendRecvBuf[10] == 0x00)

で read コマンドが成功したかどうかチェックしています。

2328 Status = phFriNfc_Felica_HUpdateAttrInfo(NdefMap);

ここで、NdefMap の SnedRecvBuf に入っているデータ(タグから読み込んだデータ)を FelicaAttrInfo に入れ、CardState も設定しています。

2360 Status = phFriNfc_MapTool_SetCardState( NdefMap,
2361 NDEFLen);

ここで、phFriNfc_Felica_HUpdateAttrInfo から読み込んだカードの状態を設定しています。

  1. 2273 void phFriNfc_Felica_Process(void       *Context,  
  2. 2274                              NFCSTATUS   Status)  
  3. 2275 {  
  4. 2276     uint8_t  CRFlag = FALSE;  
  5. 2277     uint16_t RecvTxLen = 0,  
  6. 2278              BytesToRecv = 0,  
  7. 2279              Nbc = 0;  
  8. 2280     uint32_t TotNoWrittenBytes = 0,  
  9. 2281              NDEFLen=0;  
  10. 2282   
  11. 2283     /*Set the context to Map Module*/  
  12. 2284     phFriNfc_NdefMap_t      *NdefMap = (phFriNfc_NdefMap_t *)Context;  
  13. 2285   
  14. 2286     if ( Status == NFCSTATUS_SUCCESS )  
  15. 2287     {  
  16. 2288         switch (NdefMap->State)  
  17. 2289         {  
  18.  ...  
  19. 2319             case PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR:  
  20. 2320              /* check for the status flag1 and status flag2for the successful read operation*/  
  21. 2321                 if ( NdefMap->SendRecvBuf[10] == 0x00)  
  22. 2322                 {  
  23. 2323                     /* check the Manuf Id in the receive buffer*/  
  24. 2324                     Status = phFriNfc_Felica_HCheckManufId(NdefMap);  
  25. 2325                     if ( Status == NFCSTATUS_SUCCESS)  
  26. 2326                     {  
  27. 2327                         /* Update the Attribute Information in to the context structure*/  
  28. 2328                         Status = phFriNfc_Felica_HUpdateAttrInfo(NdefMap);  
  29. 2329                         if ( Status == NFCSTATUS_SUCCESS )  
  30. 2330                         {  
  31. 2331                             PH_NFCFRI_NDEFMAP_FELI_CAL_LEN_BYTES(NdefMap->FelicaAttrInfo.LenBytes[0],  
  32. 2332                                                                 NdefMap->FelicaAttrInfo.LenBytes[1],  
  33. 2333                                                                 NdefMap->FelicaAttrInfo.LenBytes[2],  
  34. 2334                                                                 NDEFLen);  
  35. 2335   
  36. 2336                             if ( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_WR_ATTR_RD_OP )  
  37. 2337                             {  
  38.  ...  
  39. 2346                             }  
  40. 2347                             else if( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_RD_ATTR_RD_OP )  
  41. 2348                             {  
  42.  ...  
  43. 2356                             }  
  44. 2357                             else if( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_CHK_NDEF_OP )  
  45. 2358                             {  
  46. 2359   
  47. 2360                                 Status = phFriNfc_MapTool_SetCardState( NdefMap,  
  48. 2361                                                                         NDEFLen);  
  49. 2362                                 /* check status value*/  
  50. 2363                                 NdefMap->CardType = PH_FRINFC_NDEFMAP_FELICA_SMART_CARD;  
  51. 2364                                 /*reset the buffer index*/  
  52. 2365                                 NdefMap->ApduBuffIndex = 0;  
  53. 2366                                 /* set the Next operation Flag to indicate need of reading attribute information*/  
  54. 2367                                 NdefMap->Felica.OpFlag = PH_FRINFC_NDEFMAP_FELI_OP_NONE;  
  55. 2368                                 /* call respective CR */  
  56. 2369                                 phFriNfc_Felica_HCrHandler(NdefMap,PH_FRINFC_NDEFMAP_CR_CHK_NDEF,Status);  
  57. 2370                             }  
  58. 2371                             else if ( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_WR_EMPTY_MSG_OP )  
  59. 2372                             {  
  60.  ...  
  61. 2381                             }  
  62. 2382                             else  
  63. 2383                             {  
  64. 2384   
  65. 2385                                 /* invalid operation occured*/  
  66. 2386                                 Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,¥  
  67. 2387                                         NFCSTATUS_INVALID_DEVICE_REQUEST);  
  68. 2388                                 CRFlag =TRUE ;  
  69. 2389                             }  
  70. 2390                         }  
  71. 2391                         else  
  72. 2392                         {  
  73. 2393                             CRFlag =TRUE ;  
  74. 2394                         }  
  75. 2395                     }  
  76. 2396                     else  
  77. 2397                     {  
  78. 2398                         CRFlag =TRUE ;  
  79. 2399                     }  
  80. 2400                 }  
  81. 2401                 else  
  82. 2402                 {  
  83. 2403                     CRFlag =TRUE;  
  84. 2404                     /*handle the  Error case*/  
  85. 2405                     Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,¥  
  86. 2406                                         NFCSTATUS_READ_FAILED);  
  87. 2407                 }  
  88. 2408                 if ( CRFlag == TRUE )  
  89. 2409                 {  
  90. 2410                     /* call respective CR */  
  91. 2411                     phFriNfc_Felica_HCrHandler(NdefMap,PH_FRINFC_NDEFMAP_CR_RD_NDEF,Status);  
  92. 2412                 }  
  93. 2413                 break;  
  94. 2414   
  95.  ...  
  96. 2667         }  
  97. 2668     }  
  98. 2669     else  
  99. 2670     {  
  100.  ...  
  101. 2697     }  
  102. 2698   
  103. 2699 }  



では、受信したデータが NDEF 形式かどうかチェックするところを見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HUpdateAttrInfo

受信データ NdefMap->SendRecvBuf[] はこんな形式になっています。


  LEN Bytes
0 1 2 3 4 5 6 7 8 9 10 11 12
1d 07 -------- IDm ---------- 00 00 01
↑ ↑ ↑
LEN COMMAND RD SUCCESS

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
---------------- data 部分 --------------------
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


data部分がサービス部分に書かれているデータです。ここのフォーマットを NDEF にするポイントは

  1. 74 #define PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX                    13 /* Specifies Index of the version in Attribute Resp Buffer*/  
  2.   
  3.  61 #define PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM             0x01  
  4.  62 #define PH_NFCFRI_NDEFMAP_NFCDEV_MINOR_VER_NUM             0x00  
  5.  63   
  6.  64 /* Macros to find major and minor TAG : Ex:Type1/Type2/Type3/Type4 version numbers*/  
  7.  65 #define PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(a)           (((a) & (0xf0))>>(4))  
  8.  66 #define PH_NFCFRI_NDEFMAP_GET_MINOR_TAG_VERNO(a)           ((a) & (0x0f))  


SendRecvBuf[13] = data[0] : Version : 0x1*
Felica の場合、上位 4bit が 0001 でなければならない、下位 4bit は 0000 以上でなければならない

SendRecvBuf[14] = data[1] : Nbr
Nmaxb より小さくなければならない
SendRecvBuf[15] = data[2] : Nbw
Nmaxb より小さくなければならない
SendRecvBuf[16] = data[3] : Nmaxb1
SendRecvBuf[17] = data[4] : Nmabb2
Nmaxb : 2 byte (上位 1byte が SendRecvBuf[16], 下位 1byte が SendRecvBuf[17])
 0 以外でなければならない
SendRecvBuf[18] = data[5] : RFU 0x00 でなければならない
SendRecvBuf[19] = data[6] : RFU 0x00 でなければならない
SendRecvBuf[20] = data[7] : RFU 0x00 でなければならない
SendRecvBuf[21] = data[8] : RFU 0x00 でなければならない
SendRecvBuf[22] = data[9] : WriteFlag 0x00 か 0x0f でなければならない
SendRecvBuf[23] = data[10] : RdWrFlag 0x00(READ_ONLY) か 0x01(READ_WRITE) でなければならない
SendRecvBuf[24] = data[11] : LEN Bytes
SendRecvBuf[25] = data[12] : LEN Bytes
SendRecvBuf[26] = data[13] : LEN Bytes
DataLen : 3 byte (最上位 1byte が SendRecvBuf[24], 真ん中 1byte が SendRecvBuf[25], 最下位 1byte が SendRecvBuf[26])
Nbc : (uint16_t )((( DataLen % 16) == 0 ) ? (DataLen >> 4) : ((DataLen >> 4) +1));
Nmaxb より小さくなければならない
0 の場合 READ_ONLY ではいけない
SendRecvBuf[27] = data[14] : ChkSum1 : Check Sum
SendRecvBuf[28] = data[15] : ChkSum2 : Check Sum
RecvChkSum : 2 byte (上位 1byte が ChkSum1, 下位 1byte が ChkSum2)
   SendRecvBuf[13] から SendRecvBuf[26] までの値の加算

チェックサムを行っているところ
  1. 2817 static NFCSTATUS phFriNfc_Felica_HCalCheckSum(const uint8_t *TempBuffer,  
  2. 2818                                               uint8_t StartIndex,  
  3. 2819                                               uint8_t EndIndex,  
  4. 2820                                               uint16_t RecvChkSum)  
  5. 2821 {  
  6. 2822     NFCSTATUS   Result = NFCSTATUS_SUCCESS;  
  7. 2823     uint16_t CheckSum=0,  
  8. 2824              BufIndex=0;  
  9. 2825   
  10. 2826     for(BufIndex = StartIndex;BufIndex <=EndIndex;BufIndex++)  
  11. 2827     {  
  12. 2828         CheckSum += TempBuffer[BufIndex];  
  13. 2829     }  
  14. 2830     if( RecvChkSum != CheckSum )  
  15. 2831     {  
  16. 2832            Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,  
  17. 2833                             NFCSTATUS_INVALID_FORMAT);  
  18. 2834     }  
  19. 2835     return (Result);  
  20. 2836 }  


ということで、まとめるとこんな感じ


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
1* ----------- 00 00 00 00 00/0f 00/01 --------------
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


例えば、こんなの


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
10 00 00 01 00 00 00 00 00 00 01 00 00 00 00 12
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


ここで読んだ内容は phFriNfc_Felica_AttrInfo
に突っ込まれます。

2866 status = phFriNfc_MapTool_ChkSpcVer(NdefMap,
2867 PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX);

で、バージョンの値をチェックし、

2939 status = phFriNfc_Felica_HCalCheckSum(NdefMap->SendRecvBuf,

で、チェックサムを検証しています。

  1. 2848 /*! 
  2. 2849  * \brief On successful read attribute blk information, this function validates and stores the 
  3. 2850  * Attribute informations in to the context. 
  4. 2851  */  
  5. 2852 static NFCSTATUS   phFriNfc_Felica_HUpdateAttrInfo(phFriNfc_NdefMap_t *NdefMap)  
  6. 2853 {  
  7. 2854     NFCSTATUS status = NFCSTATUS_PENDING;  
  8. 2855     uint8_t   CRFlag = FALSE,  
  9. 2856               Nmaxb1, Nmaxb2 = 0,  
  10. 2857               ChkSum1 = 0, ChkSum2=0;  
  11. 2858   
  12. 2859     uint16_t  Nmaxblk = 0,  
  13. 2860               RecvChkSum=0,  
  14. 2861               NdefBlk = 0;  
  15. 2862     uint32_t  DataLen =0;  
  16. 2863   
  17. 2864   
  18. 2865     /* Validate T3VNo and NFCDevVNo */  
  19. 2866     status = phFriNfc_MapTool_ChkSpcVer(NdefMap,  
  20. 2867                                         PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX);  
  21. 2868     if ( status != NFCSTATUS_SUCCESS )  
  22. 2869     {  
  23. 2870         CRFlag = TRUE;  
  24. 2871     }  
  25. 2872     else  
  26. 2873     {  
  27. 2874         /* get the Nmaxb from the receive buffer*/  
  28. 2875         Nmaxb1 = NdefMap->SendRecvBuf[16];  
  29. 2876         Nmaxb2 = NdefMap->SendRecvBuf[17];  
  30. 2877   
  31. 2878         Nmaxblk = (((uint16_t)Nmaxb1 << 8) | (Nmaxb2 & 0x00ff));  
  32. 2879   
  33. 2880         if ( Nmaxblk != 0 )  
  34. 2881         {  
  35. 2882             /* check the Nbr against the Nmaxb*/  
  36. 2883             if ( NdefMap->SendRecvBuf[14] > Nmaxblk )  
  37. 2884             {  
  38. 2885                 CRFlag = TRUE;  
  39. 2886             }  
  40. 2887             else  
  41. 2888             {  
  42. 2889                 /*check Nbw > Nmaxb*/  
  43. 2890                 /*check the write flag validity*/  
  44. 2891                 /*check for the RFU bytes validity*/  
  45. 2892                  if ( (NdefMap->SendRecvBuf[15] > Nmaxblk) ||  
  46. 2893                      ((NdefMap->SendRecvBuf[22] != 0x00) && (NdefMap->SendRecvBuf[22] !=0x0f ))||  
  47. 2894                      ( (NdefMap->SendRecvBuf[23] != 0x00) && (NdefMap->SendRecvBuf[23] !=0x01 ))||  
  48. 2895                      ( NdefMap->SendRecvBuf[18] != 0x00) ||  
  49. 2896                      ( NdefMap->SendRecvBuf[19] != 0x00) ||  
  50. 2897                      ( NdefMap->SendRecvBuf[20] != 0x00) ||  
  51. 2898                      ( NdefMap->SendRecvBuf[21] != 0x00))  
  52. 2899   
  53. 2900                 {  
  54. 2901                     CRFlag = TRUE;  
  55. 2902                 }  
  56. 2903                 else  
  57. 2904                 {  
  58. 2905                     /* check the validity of the actual ndef data len*/  
  59. 2906                     PH_NFCFRI_NDEFMAP_FELI_CAL_LEN_BYTES( NdefMap->SendRecvBuf[24],  
  60. 2907                                                           NdefMap->SendRecvBuf[25],  
  61. 2908                                                           NdefMap->SendRecvBuf[26],  
  62. 2909                                                           DataLen);  
  63. 2910   
  64. 2911   
  65. 2912                     /* Calculate Nbc*/  
  66. 2913                     NdefBlk = (uint16_t )((( DataLen % 16) == 0 ) ? (DataLen >> 4) : ((DataLen >> 4) +1));  
  67. 2914   
  68. 2915                     /* check Nbc against Nmaxb*/  
  69. 2916                     if ((NdefBlk > Nmaxblk))  
  70. 2917                     {  
  71. 2918                         CRFlag = TRUE;  
  72. 2919                     }  
  73. 2920                     else  
  74. 2921                     {  
  75. 2922                         /*Store the attribute information in phFriNfc_Felica_AttrInfo*/  
  76. 2923                         NdefMap->FelicaAttrInfo.Version = NdefMap->SendRecvBuf[PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX];  
  77. 2924                         NdefMap->FelicaAttrInfo.Nbr = NdefMap->SendRecvBuf[14];  
  78. 2925                         NdefMap->FelicaAttrInfo.Nbw = NdefMap->SendRecvBuf[15];  
  79. 2926   
  80. 2927                         NdefMap->FelicaAttrInfo.Nmaxb = Nmaxblk;  
  81. 2928   
  82. 2929                         NdefMap->FelicaAttrInfo.WriteFlag = NdefMap->SendRecvBuf[22];  
  83. 2930                         NdefMap->FelicaAttrInfo.RdWrFlag = NdefMap->SendRecvBuf[23];  
  84. 2931   
  85. 2932                         /* Get CheckSum*/  
  86. 2933                         ChkSum1 = NdefMap->SendRecvBuf[27];  
  87. 2934                         ChkSum2 = NdefMap->SendRecvBuf[28];  
  88. 2935   
  89. 2936                         RecvChkSum = (((uint16_t)ChkSum1 << 8) | (ChkSum2 & 0x00ff));  
  90. 2937   
  91. 2938                         /* Check the check sum validity?*/  
  92. 2939                         status = phFriNfc_Felica_HCalCheckSum(NdefMap->SendRecvBuf,  
  93. 2940                                                               PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX,  
  94. 2941                                                               26,  
  95. 2942                                                               RecvChkSum);  
  96. 2943                         if ( status != NFCSTATUS_SUCCESS )  
  97. 2944                         {  
  98. 2945                             CRFlag = TRUE;  
  99. 2946                         }  
  100. 2947                         else  
  101. 2948                         {  
  102. 2949                             /*check RW Flag Access Rights*/  
  103. 2950                             /* set to read only cannot write*/  
  104. 2951                             if ( NdefMap->FelicaAttrInfo.RdWrFlag == 0x00 )  
  105. 2952                             {  
  106. 2953                                 NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_ONLY;  
  107. 2954                             }  
  108. 2955                             else  
  109. 2956                             {  
  110. 2957                                 NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_WRITE;  
  111. 2958                             }  
  112. 2959   
  113. 2960                             NdefMap->FelicaAttrInfo.LenBytes[0] = NdefMap->SendRecvBuf[24];  
  114. 2961                             NdefMap->FelicaAttrInfo.LenBytes[1] = NdefMap->SendRecvBuf[25];  
  115. 2962                             NdefMap->FelicaAttrInfo.LenBytes[2] = NdefMap->SendRecvBuf[26];  
  116. 2963                             status = PHNFCSTVAL(CID_NFC_NONE,NFCSTATUS_SUCCESS);  
  117. 2964                         }  
  118. 2965                     }  
  119. 2966                 }  
  120. 2967             }  
  121. 2968         }  
  122. 2969         else  
  123. 2970         {  
  124. 2971             CRFlag = TRUE;  
  125. 2972         }  
  126. 2973     }  
  127. 2974     if ( (status == NFCSTATUS_INVALID_FORMAT ) && (CRFlag == TRUE ))  
  128. 2975     {  
  129. 2976         NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID;  
  130. 2977     }  
  131. 2978     if ( CRFlag == TRUE )  
  132. 2979     {  
  133. 2980         /*Return Status Error  Invalid Format*/  
  134. 2981         status =  PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,NFCSTATUS_INVALID_FORMAT);  
  135. 2982     }  
  136. 2983   
  137. 2984     return (status);  
  138. 2985 }  



phFriNfc_MapTool_SetCardState も見ておきましょう。

phFriNfc_MapTools.c#phFriNfc_MapTool_SetCardState

  1. 64 NFCSTATUS phFriNfc_MapTool_SetCardState(phFriNfc_NdefMap_t  *NdefMap,  
  2.  65                                         uint32_t            Length)  
  3.  66 {  
  4. ...  
  5.   
  6. 110     }  
  7. 111     Result = ((NdefMap->CardState ==  
  8. 112                 PH_NDEFMAP_CARD_STATE_INVALID)?  
  9. 113                 PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,  
  10. 114                 NFCSTATUS_NO_NDEF_SUPPORT):  
  11. 115                 Result);  
  12. 116     return Result;  
  13. 117 }  

 
 ここで、 NdefMap->CardState が PH_NDEFMAP_CARD_STATE_INVALID だと NFCSTATUS_NO_NDEF_SUPPORT が帰るので
 NDEF としては認識してくれません。


ということで、Raw bytes をごりごりカードにかいて、NDEF として認識することができました。


 

0 件のコメント:

コメントを投稿