Thursday, December 15, 2011

ICS: Getting NFC Tags to Work

Since December I'm a happy owner of a Galaxy Nexus :)
NFC seemed like an interesting thing, so I started to integrate NFC support into PAW.

First thing I did was to order some Mifare Classic 1K tags from tagsfordroid.com.
They arrived fairly quickly and delivery was free of charge.
NFC Tags
To try things out I installed a lot of NFC reader and writer apps. To my dismay none of them seemed to work.
They could read the tags but could not write them. Having no idea how NFC worked, I was fairly disappointed :(

Searching the web I found out that this seems to be a bug in ICS:
http://code.google.com/p/android/issues/detail?id=22258

Googles sais that there will be a fix provided, but when, no one can tell.
So I tried to get it working myself...

If you would like to test the things below, install the latest PAW version (0.80) from the Android Market.

Disclaimer:
This solution is only working for Mifare Classic 1K tags!
If you try as described you do it at your own risk!
It's not my fault if your tags do not work afterwards!


Read the updates at the end of the post first!
This solution is no longer necessary and will most likely damage your tag(s), so do not use it!

The Problem
The problem (as reported in the bug report) seems to be that the tech reported by the tag do not contain
android.nfc.tech.Ndef which is necessary to write NDEF messages.

You can try this with the following code that you can insert into the BenShell Console of the PAW web application:

import de.fun2code.android.pawserver.AndroidInterface;
import android.nfc.NfcAdapter;

intent = AndroidInterface.getNfcIntent(5); // 5 secs timeout
if(intent != null) {
  tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  print(tag);
}
else {
  print("No Tag found!");
}

If the result is TAG: Tech [android.nfc.tech.MifareClassic, android.nfc.tech.NfcA] writing NDEF messages will not work!


The Possible Fix
As mentioned above I have no expirience with NFC, so I tried to find a solution that worked without having to know NFC or the Mifare tags in detail.

I searched the web and found some Mifare Classic 1K dumps at the nfc-tools site.
After downloading a dump I tried to write it to the tag. Interesting enough it seemd to work :)

After writing the dump, the above script reported:
TAG: Tech [android.nfc.tech.MifareClassic, android.nfc.tech.NfcA, android.nfc.tech.Ndef]

So here are the step by step instructions:
  1. Download the dump file from the nfc-tools site: mfc_1k__url_nfc-tools.mfd
  2. Save the dump file to the /sdcard of your android device.
  3. Start PAW and open the BeanShell console.
  4. Copy/paste the following script into the console:
    /*
    Mifare Classic - Write dump
    */
    import de.fun2code.android.pawserver.AndroidInterface;
    import android.nfc.NfcAdapter;
    import android.nfc.NdefRecord;
    import android.nfc.NdefMessage;
    import android.nfc.tech.*;
    import android.os.Bundle;
    
    
    intent = AndroidInterface.getNfcIntent(5); // 5 secs timeout
    print(intent);
    if(intent != null) {
      tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
      print(tag);
      
      if(tag != null) {
          nfc = MifareClassic.get(tag);
          nfc.connect();
        print("Is connected: " + nfc.isConnected());
    
      
         fis = new FileInputStream("/sdcard/mfc_1k__url_nfc-tools.mfd");
         
         b = new byte[16];
    
         errors = 0;
        
        sectors = nfc.getSectorCount();
        blocksPerSector = nfc.getBlockCountInSector(0);
        
        for(sector=0; sector<sectors; sector++) {
          print("Sector " + sector);
          
          for(block=0; block < blocksPerSector; block++) {
            logicBlock = nfc.sectorToBlock(sector) + block;
            $$.print("  Block: " + block + " ... ");
    
            fis.read(b);
    
            if(sector == 0 && block == 0) {
               print("Manufacturer block ... skipped");
               continue;
            }
    
            try {
              nfc.authenticateSectorWithKeyA(sector, MifareClassic.KEY_DEFAULT);
              nfc.writeBlock(logicBlock, b);
              print("ok");
            }
            catch(e) {
                print("error");
                errors++;
            }
          }
        }
        
        fis.close();
        nfc.close();
          print("--------------------------------------------------------------------------");
          print("Errors: " + errors);
          print("Dump written!");
       }
       else {
          print("Tag not supported!");
       }
    
    }
    else {
      print("No Tag found!");
    }
    
    
  5. Start the script and as soon as the PAW app is in foreground, place the tag at the back of the phone and leaf it there until the script is finished.
After that the tag is hopefully working.

Good luck and happy hacking :)

Update:
Ndef.getMaxSize() returns only 92 bytes that can be written to a NDEF message. I don't think that's normal :(

You can check this yourself with the following code:
import de.fun2code.android.pawserver.AndroidInterface;
import android.nfc.NfcAdapter;
import android.nfc.tech.Ndef;
 
intent = AndroidInterface.getNfcIntent(5); // 5 secs timeout
if(intent != null) {
  tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  print("Max NDEF message size: " + Ndef.get(tag).getMaxSize() + " bytes");
}
else {
  print("No Tag found!");
} 

Update 2:
The latest NFC TagWriter by NXP is able to format unformatted tags and fixes the problem.
Here is the Android Market link: NFC TagWriter by NXP

13 comments:

  1. I can't paste into the console.. dammit!?

    ReplyDelete
  2. You will only have 92 bytes of NDEF storage when using the image ... just as warning!
    I'm glad that I now can use the tag at all.
    But I wouldn't do that with too many tags.
    Hope Android 4.0.3 comes soon...

    ReplyDelete
    Replies
    1. When I went to go re-program one of the tags with TagWriter I had programed using the BeanShell previousally, it still reported the size as 92 bytes and woudn't let me write large data sets to it. I've tried reading out the dump from a corretly programed 1k tag and writting it back into the BeanShell tag but the write errors out.
      http://www.mifarecards-rfid.com

      Delete
    2. The workaround described in the post is no longer necessary. Unfortunately it seems to damage the tag(s). So please do not use it.
      Use NFC TagWriter, this seems to work fine.

      Delete
  3. I see, so it's not worth further effort.. this issue is fixed with 4.0.3?

    ReplyDelete
  4. Yes, this should be fixed in 4.0.3.

    ReplyDelete
  5. Replies
    1. When I went to go re-program one of the tags with TagWriter I had programed using the BeanShell previousally, it still reported the size as 92 bytes and woudn't let me write large data sets to it. I've tried reading out the dump from a corretly programed 1k tag and writting it back into the BeanShell tag but the write errors out.
      http://www.mifarecards-rfid.com

      Delete
  6. Glad to see the NXP guys found a work around for 4.0.2

    When I went to go re-program one of the tags with TagWriter I had programed using the BeanShell previousally, it still reported the size as 92 bytes and woudn't let me write large data sets to it. I've tried reading out the dump from a corretly programed 1k tag and writting it back into the BeanShell tag but the write errors out.

    Is there anyway for me to re-format my BeanShell tag to give me the full storage size back?

    ReplyDelete
    Replies
    1. Unfortunately I think the tags are broken and can not be re-formatted. At least I could not get mine to work ... sorry

      Delete
  7. Hello Jochen, Ive been searching all over to make my ICS to communicate via peer-to-peer to lower versions Android NFC enabled devices like Android 2.3.3 and up. But no success. Have u had any experience with this? Im doing some NFC project now. Any input would be great. Jack (neoaspilet11@gmail.com)

    ReplyDelete
    Replies
    1. After writing this blog post I haben't played much with NFC, so I can't answer your question.
      Maybe the folks at the XDA developer forum can provide some help:
      http://www.xda-developers.com/

      Good luck!

      Delete
  8. Setting "Android Beam" = "off" in Wireles & Networks (more)
    Helped me erasing k1 milf-air!

    ReplyDelete