MifareUltralight.java revision 4a5e2532205252e0b8616ebc07ca089fd3721681
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.nfc.tech; 18 19import android.nfc.Tag; 20import android.os.RemoteException; 21 22import java.io.IOException; 23 24//TOOD: Ultralight C 3-DES authentication, one-way counter 25 26/** 27 * Technology class representing MIFARE Ultralight and MIFARE Ultralight C tags. 28 * 29 * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology 30 * MIFARE Ultralight class tags will still be scanned, but will only show the NfcA technology. 31 * 32 * <p>MIFARE Ultralight compatible tags have 4 byte pages. The read command 33 * returns 4 pages (16 bytes) at a time, for speed. The write command operates 34 * on a single page (4 bytes) to minimize EEPROM write cycles. 35 * 36 * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first 37 * 4 pages are for the OTP area, manufacturer data, and locking bits. They are 38 * readable and some bits are writable. The final 12 pages are the user 39 * read/write area. For more information see the NXP data sheet MF0ICU1. 40 * 41 * <p>The MIFARE Ultralight C consists of a 192 byte EEPROM. The first 4 pages 42 * are for OTP, manufacturer data, and locking bits. The next 36 pages are the 43 * user read/write area. The next 4 pages are additional locking bits, counters 44 * and authentication configuration and are readable. The final 4 pages are for 45 * the authentication key and are not readable. For more information see the 46 * NXP data sheet MF0ICU2. 47 */ 48public final class MifareUltralight extends BasicTagTechnology { 49 /** A MIFARE Ultralight compatible tag of unknown type */ 50 public static final int TYPE_UNKNOWN = -1; 51 /** A MIFARE Ultralight tag */ 52 public static final int TYPE_ULTRALIGHT = 1; 53 /** A MIFARE Ultralight C tag */ 54 public static final int TYPE_ULTRALIGHT_C = 2; 55 56 /** Size of a MIFARE Ultralight page in bytes */ 57 public static final int PAGE_SIZE = 4; 58 59 private static final int NXP_MANUFACTURER_ID = 0x04; 60 private static final int MAX_PAGE_COUNT = 256; 61 62 private int mType; 63 64 /** 65 * Returns an instance of this tech for the given tag. If the tag doesn't support 66 * this tech type null is returned. 67 * 68 * @param tag The tag to get the tech from 69 */ 70 public static MifareUltralight get(Tag tag) { 71 if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null; 72 try { 73 return new MifareUltralight(tag); 74 } catch (RemoteException e) { 75 return null; 76 } 77 } 78 79 /** @hide */ 80 public MifareUltralight(Tag tag) throws RemoteException { 81 super(tag, TagTechnology.MIFARE_ULTRALIGHT); 82 83 // Check if this could actually be a Mifare 84 NfcA a = NfcA.get(tag); 85 86 mType = TYPE_UNKNOWN; 87 88 if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) { 89 // could be UL or UL-C 90 //TODO: stack should use NXP AN1303 procedure to make a best guess 91 // attempt at classifying Ultralight vs Ultralight C. 92 mType = TYPE_ULTRALIGHT; 93 } 94 } 95 96 /** Returns the type of the tag. 97 * <p>It is very hard to always accurately classify a MIFARE Ultralight 98 * compatible tag as Ultralight original or Ultralight C. So consider 99 * {@link #getType} a hint. */ 100 public int getType() { 101 return mType; 102 } 103 104 // Methods that require connect() 105 /** 106 * Read 4 pages (16 bytes). 107 * <p>The MIFARE Ultralight protocol always reads 4 pages at a time. 108 * <p>If the read spans past the last readable block, then the tag will 109 * return pages that have been wrapped back to the first blocks. MIFARE 110 * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to 111 * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE 112 * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to 113 * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01. 114 * <p>This requires that the tag be connected. 115 * 116 * @return 4 pages (16 bytes) 117 * @throws IOException 118 */ 119 public byte[] readPages(int pageOffset) throws IOException { 120 validatePageOffset(pageOffset); 121 checkConnected(); 122 123 byte[] cmd = { 0x30, (byte) pageOffset}; 124 return transceive(cmd, false); 125 } 126 127 /** 128 * Write 1 page (4 bytes). 129 * <p>The MIFARE Ultralight protocol always writes 1 page at a time. 130 * <p>This requires that the tag be connected. 131 * 132 * @param page The offset of the page to write 133 * @param data The data to write 134 * @throws IOException 135 */ 136 public void writePage(int pageOffset, byte[] data) throws IOException { 137 validatePageOffset(pageOffset); 138 checkConnected(); 139 140 byte[] cmd = new byte[data.length + 2]; 141 cmd[0] = (byte) 0xA2; 142 cmd[1] = (byte) pageOffset; 143 System.arraycopy(data, 0, cmd, 2, data.length); 144 145 transceive(cmd, false); 146 } 147 148 /** 149 * Send raw NfcA data to a tag and receive the response. 150 * <p> 151 * This method will block until the response is received. It can be canceled 152 * with {@link #close}. 153 * <p>Requires {@link android.Manifest.permission#NFC} permission. 154 * <p>This requires a that the tag be connected. 155 * 156 * @param data bytes to send 157 * @return bytes received in response 158 * @throws IOException if the target is lost or connection closed 159 */ 160 public byte[] transceive(byte[] data) throws IOException { 161 return transceive(data, true); 162 } 163 164 private static void validatePageOffset(int pageOffset) { 165 // Do not be too strict on upper bounds checking, since some cards 166 // may have more addressable memory than they report. 167 // Note that issuing a command to an out-of-bounds block is safe - the 168 // tag will wrap the read to an addressable area. This validation is a 169 // helper to guard against obvious programming mistakes. 170 if (pageOffset < 0 || pageOffset >= MAX_PAGE_COUNT) { 171 throw new IndexOutOfBoundsException("page out of bounds: " + pageOffset); 172 } 173 } 174} 175