Pages

Thursday, May 12, 2016

Android NFC readBlock for MifareClassic to dump data in RFID tag



Last example "Android NFC read MifareClassic RFID tag, with android.nfc.action.TECH_DISCOVERED" read some general info of the RFID tag; such as type, size... This example dump the data inside the tag by calling readBlock() of MifareClassic.

Test on bland new MifareClassic RFID Card and Key.
(Android Studio project and signed APK are available on bottom of this post, you can test on your Android devices)


MifareClassic.readBlock() is an I/O operation and will block until complete. It must not be called from the main application thread. So we have to implement our AsyncTask to perform in background thread.

Modify MainActivity.java in last example:
package com.blogspot.android_er.androidnfctechdiscovered;

import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {

private NfcAdapter nfcAdapter;
TextView textViewInfo, textViewTagInfo, textViewBlock;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewInfo = (TextView)findViewById(R.id.info);
textViewTagInfo = (TextView)findViewById(R.id.taginfo);
textViewBlock = (TextView)findViewById(R.id.block);

nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(nfcAdapter == null){
Toast.makeText(this,
"NFC NOT supported on this devices!",
Toast.LENGTH_LONG).show();
finish();
}else if(!nfcAdapter.isEnabled()){
Toast.makeText(this,
"NFC NOT Enabled!",
Toast.LENGTH_LONG).show();
finish();
}
}

@Override
protected void onResume() {
super.onResume();

Intent intent = getIntent();
String action = intent.getAction();

if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
Toast.makeText(this,
"onResume() - ACTION_TECH_DISCOVERED",
Toast.LENGTH_SHORT).show();

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(tag == null){
textViewInfo.setText("tag == null");
}else{
String tagInfo = tag.toString() + " ";

tagInfo += " Tag Id: ";
byte[] tagId = tag.getId();
tagInfo += "length = " + tagId.length +" ";
for(int i=0; i<tagId.length; i++){
tagInfo += String.format("%02X", tagId[i] & 0xff) + " ";
}
tagInfo += " ";

String[] techList = tag.getTechList();
tagInfo += " Tech List ";
tagInfo += "length = " + techList.length +" ";
for(int i=0; i<techList.length; i++){
tagInfo += techList[i] + " ";
}

textViewInfo.setText(tagInfo);

//Only android.nfc.tech.MifareClassic specified in nfc_tech_filter.xml,
//so must be MifareClassic
readMifareClassic(tag);
}
}else{
Toast.makeText(this,
"onResume() : " + action,
Toast.LENGTH_SHORT).show();
}
}

public void readMifareClassic(Tag tag){
MifareClassic mifareClassicTag = MifareClassic.get(tag);

String typeInfoString = "--- MifareClassic tag --- ";
int type = mifareClassicTag.getType();
switch(type){
case MifareClassic.TYPE_PLUS:
typeInfoString += "MifareClassic.TYPE_PLUS ";
break;
case MifareClassic.TYPE_PRO:
typeInfoString += "MifareClassic.TYPE_PRO ";
break;
case MifareClassic.TYPE_CLASSIC:
typeInfoString += "MifareClassic.TYPE_CLASSIC ";
break;
case MifareClassic.TYPE_UNKNOWN:
typeInfoString += "MifareClassic.TYPE_UNKNOWN ";
break;
default:
typeInfoString += "unknown...! ";
}

int size = mifareClassicTag.getSize();
switch(size){
case MifareClassic.SIZE_1K:
typeInfoString += "MifareClassic.SIZE_1K ";
break;
case MifareClassic.SIZE_2K:
typeInfoString += "MifareClassic.SIZE_2K ";
break;
case MifareClassic.SIZE_4K:
typeInfoString += "MifareClassic.SIZE_4K ";
break;
case MifareClassic.SIZE_MINI:
typeInfoString += "MifareClassic.SIZE_MINI ";
break;
default:
typeInfoString += "unknown size...! ";
}

int blockCount = mifareClassicTag.getBlockCount();
typeInfoString += "BlockCount = " + blockCount + " ";
int sectorCount = mifareClassicTag.getSectorCount();
typeInfoString += "SectorCount = " + sectorCount + " ";

textViewTagInfo.setText(typeInfoString);

new ReadMifareClassicTask(mifareClassicTag).execute();

}

private class ReadMifareClassicTask extends AsyncTask<Void, Void, Void> {

/*
MIFARE Classic tags are divided into sectors, and each sector is sub-divided into blocks.
Block size is always 16 bytes (BLOCK_SIZE). Sector size varies.
MIFARE Classic 1k are 1024 bytes (SIZE_1K), with 16 sectors each of 4 blocks.
*/

MifareClassic taskTag;
int numOfBlock;
final int FIX_SECTOR_COUNT = 16;
boolean success;
final int numOfSector = 16;
final int numOfBlockInSector = 4;
byte[][][] buffer = new byte[numOfSector][numOfBlockInSector][MifareClassic.BLOCK_SIZE];

ReadMifareClassicTask(MifareClassic tag){
taskTag = tag;
success = false;
}

@Override
protected void onPreExecute() {
textViewBlock.setText("Reading Tag, dont remove it!");
}

@Override
protected Void doInBackground(Void... params) {

try {
taskTag.connect();

for(int s=0; s<numOfSector; s++){
if(taskTag.authenticateSectorWithKeyA(s, MifareClassic.KEY_DEFAULT)) {
for(int b=0; b<numOfBlockInSector; b++){
int blockIndex = (s * numOfBlockInSector) + b;
buffer[s][b] = taskTag.readBlock(blockIndex);
}
}
}

success = true;
} catch (IOException e) {
e.printStackTrace();
} finally{
if(taskTag!=null){
try {
taskTag.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

return null;
}

@Override
protected void onPostExecute(Void aVoid) {
//display block
if(success){
String stringBlock = "";
for(int i=0; i<numOfSector; i++){
stringBlock += i + " : ";
for(int j=0; j<numOfBlockInSector; j++){
for(int k=0; k<MifareClassic.BLOCK_SIZE; k++){
stringBlock += String.format("%02X", buffer[i][j][k] & 0xff) + " ";
}
stringBlock += " ";
}
stringBlock += " ";
}
textViewBlock.setText(stringBlock);
}else{
textViewBlock.setText("Fail to read Blocks!!!");
}
}
}
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout


android_layout_width="match_parent"
android_layout_height="match_parent"
android_padding="16dp"
android_orientation="horizontal"
tools_context=".MainActivity">

<LinearLayout
android_layout_width="0dp"
android_layout_height="match_parent"
android_layout_weight="1"
android_orientation="vertical">

<TextView
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_layout_margin="10dp"
android_layout_gravity="center_horizontal"
android_autoLink="web"
android_text="http://android-er.blogspot.com/"
android_textStyle="bold"/>

<TextView
android_id="@+id/info"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textStyle="italic"/>

<TextView
android_id="@+id/taginfo"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textStyle="bold"/>

</LinearLayout>

<ScrollView
android_layout_width="0dp"
android_layout_height="match_parent"
android_layout_weight="1">
<TextView
android_id="@+id/block"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_typeface="monospace"/>
</ScrollView>
</LinearLayout>

Other files, AndroidManifest.xml and nfc_tech_filter.xml, refer to last example "Android NFC read MifareClassic RFID tag, with android.nfc.action.TECH_DISCOVERED"

download filesDownload the files (Android Studio Format) .

download filesDownload APK .


- Similarly example run on Arduino: Arduino Uno + RFID-RC522, MFRC522 library example DumpInfo
- Step-by-step to make MFRC522-python work on Raspberry Pi 2/raspbian Jessie, read RFID tags using RFID Reader, RFID-RC522.
- Raspberry Pi 2 + MFRC522-python - Dump RFID Tag data using mxgxw/MFRC522-python

Related Posts by Categories

0 comments:

Post a Comment