Android NFC writeNdefMessage throws IOException Tag is not ndef
Asked Answered
S

1

9

I'm developing a NFC environment consisting of a tag (AS3953 chip + microcontroller) and a smartphone (Samsung Galaxy Fame runnung Android 4.1.2).

While reading a NDEF message works I'm stuck on writing the message to the tag. I copied most of the code from http://tapintonfc.blogspot.de/2012/07/the-above-footage-from-our-nfc-workshop.html and modified it to accept ISO14443A Tag Type 4 by searching the tag techlist for IsoDep, NfcA and Ndef in supportedTechs(). Since all of them are listed the app continues to writeTag():

public WriteResponse writeTag(NdefMessage message, Tag tag) {
try {
    Ndef ndef = Ndef.get(tag);
    if (ndef != null) {
        Log.d(TAG, "writeTag: tag type: "+ndef.getType());
        ndef.connect();
        Log.d(TAG, "writeTag: connected!");
        if (!ndef.isWritable()) {
            return new WriteResponse(0, "Tag is read-only");
        }
        if (ndef.getMaxSize() < message.toByteArray().length) {
            return new WriteResponse(0, "size error");
        }
        Log.d(TAG, "writeTag: write ndef...");
        ndef.writeNdefMessage(message);
        Log.d(TAG, "writeTag: wrote ndef!");
        if (writeProtect)
            ndef.makeReadOnly();
        return new WriteResponse(1, "Wrote message to pre-formatted tag.");
    } else {
        Log.d(TAG, "writeTag: ndef==null!");
        return new WriteResponse(0, "writeTag: ndef==null!");
    }
} catch (Exception e) {
    Log.d(TAG, "writeTag: exception: " + e.toString());
    return new WriteResponse(0, "Failed to write tag");
}
}

LogCat shows:

11:08:46.400: onNewIntent
11:08:46.400: supportedTechs: techlist: android.nfc.tech.IsoDep,android.nfc.tech.NfcA,android.nfc.tech.Ndef,
11:08:46.400: supportedTechs: tech is supported!
11:08:46.400: writeTag: tag type: org.nfcforum.ndef.type4
11:08:46.410: writeTag: connected!
11:08:46.410: writeTag: write ndef...
11:08:46.490: writeTag: exception: java.io.IOException: Tag is not ndef

As you can see an IOException is thrown saying the Tag is not ndef which contradicts the techlist. Looking further into the android code writeNdefMessage() tries to get a TagService and a ServiceHandle from the tag to match them against. This fails so the exception is thrown (no message written up to now):

public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException {
...
INfcTag tagService = mTag.getTagService();
...
int serviceHandle = mTag.getServiceHandle();
if (tagService.isNdef(serviceHandle)) {
    ...
}
else {
    throw new IOException("Tag is not ndef");
}
...
}

Is there a workaround for that or is it not possible at all with my kind of tag? As I'm also programming the tag the error might be on the other side, but it seems to be a Java problem.


Edit 1:

I don't connect to any technology before so there shouldn't be any opened connection. If I open an connection before ndef.connect() there is IllegalStateException: Close other technology first!

I configured AS3953 to ISO14443A Level-4 so only Tag Type 4 Blocks are forwarded to the microcontroller. Only I-Blocks are handled but even if there are other commands the µC has to read it out over the SPI port which isn't the case by logic analysis. As I said reading the ndef file works and I tested it for a 4KB file. Looking at the logic analysis the following steps are made (all returning a positive 9000-code):

(c=command, r=response) (corrected due to renaming mistake)
select by name:
c: 02 00 a4 04 00 07 d2 76 00 00 85 01 01 00
r: 02 90 00
select by id - select cc file
c: 03 00 a4 00 0c 02 e1 03
r: 03 90 00
read 0x0f bytes of cc file
c: 02 00 b0 00 00 0f
r: 02 00 0f 20 00 3b 00 34 04 06 e1 04 0f ff 00 00 90 00
select by id - select ndef file
c: 03 00 a4 00 0c 02 e1 04
r: 03 90 00
read 0x02 bytes (first 2 bytes are apdu-size)
c: 02 00 b0 00 00 02
r: 02 0f d3 90 00
read 0x3b bytes (frame size) of first part of ndef file (external type, jpeg image as payload)
c: 03 00 b0 00 02 3b
r: 03 c4 0c 00 00 0f c1 64 65 2e 74 65 73 74 61 70 70 3a 61 01 ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 60 00 60 00 00 ff db 00 43 00 49 32 36 40 36 2d 49 40 3b 40 52 4d 49 56 6d 90 00
[ndef file]
read 0x26 bytes of last part of ndef file
c: 03 00 b0 0f ae 27
r: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 FF D9 00 00 90 00

Using the same app for writing I start the activity which filters NfcAdapter.ACTION_TAG_DISCOVERED intents. Just as in the linked example the phone touches the tag calling onResume() doing mNfcAdapter.enableForegroundDispatch(...);

When I log the SPI communication the same reading procedure as above is done. Since LogCat shows a working intent dispatcher I guess the app stops at the IOException, closing the connection and immediately going over to read out as android found the tag again.


Edit 2:

There might be a hint as one of the first interrupts issue a deselect command which is handled by AS3953 itself:

(count * interrupt)
3 * power up 
1 * Wake-up IRQ at entry in ACTIVE(*) state 
1 * Deselect command
1 * Wake-up IRQ at entry in ACTIVE(*) state 
1 * IRQ due to start of receive
Schubert answered 14/4, 2014 at 9:53 Comment(19)
Do you issue a connect() for any of the other technologies (NfcA or IsoDep) before you connect as Ndef technology?Azucenaazure
I assume you are using the AS3953 in direct mode and that you handle the ISO 14443-4/ISO 7816-4 commands on the microcrontroller. Could it be that you do not properly handle all the commands necessary for an NFC Forum Type 4 tag?Azucenaazure
I added some information in the original post. What do you mean by direct mode? Most of the protocol stack (namely up to ISO14443A-4) is done by the AS3953 itself. If any command is not handled there has to be an SPI command which reads out the rx buffer at leastSchubert
With direct mode I mean exactly that mode, where you receive the frames over SPI. In fact the AS3953 does not really handle the ISO 14443-4 protocol (even if AMS insists that the chip does). The chip actually only handles the protocol activation/deactivation procedures. The protocol frames (I/R/S-blocks) are put into the FIFO as is, whereas if the chip handled ISO 14443-4, it should only pass the information field of I-blocks up to the microcontroller.Azucenaazure
Can you post the contents of the CC file that you send to the Android device? Also it would be interesting what frames you actually receive over SPI (and what responses you send) for the failing write procedure.Azucenaazure
One more, I assume you expect that the SELECT (by DF name) command will be sent multiple times (actually there may even be a protocol deactivation in between): At least once for the automatic NDEF detection procedure of Android and once for connecting the Ndef tag technology.Azucenaazure
I added the SPI communication, a perfect behaviour if I want to read the ndef message but I want to write to the tag, so the line 'read 0x02 bytes' should look like 02 00 d6 ...Schubert
Let me describe the situation a bit further: Once I start the app so foregrounddispatching is enabled I touch the devices, a sound is played indicating a PICC was found, half a second later a more neutral sound is played indicating transmission complete OR interrupted and the app returns the IOException. During that time logic analysis shows the communication stated above (which shouldn't happen). I want to stress that there was probably no write command frame send at all so either it's the AS3953 (writing worked on the demo board) or android.Schubert
Am I right that -- during the read phase -- there is only one READ BINARY command (i.e. c: 0x 00 b0 xx xx xx) sent from the Android device to the AS3953?Azucenaazure
If yes, could you please post the whole response APDU you send for that command?Azucenaazure
No, there are several READ BINARY commands during the read phase (indicated by b0 in the 3rd place), one for getting the cc file (see 'APDU read 0x0f bytes of cc file'), one for getting the ndef APDU size (see 'read 0x02 bytes (first 2 bytes are apdu-size)') and many more from 'read 0x3b bytes (frame size)' on. The PCD uses sliding window so the first 2 bytes after b0 are offset and the 3rd one is window size.Schubert
Okay then, could you please post the full first and the full last READ BINARY command+response for the NDEF file?Azucenaazure
Added the first and last read commands to the original post, after the image was read the system seems stuck, starting with select again, no cc is read so it directly goes on reading the ndef file (only 1 or 2 bytes at all). I didn't work out the post-communication phase up to now so I cannot tell precisely if its the PICC or PCD, but what is so interesting about the reading process? I have trouble writing to the tag - or is it that android first reads out the ndef file before it starts writing to it?Schubert
Obviously my first shot answer wasn't right. So lets continue discussion. A quick overview of how a communication cycle with an NFC T4T tag works: 1. Tag is activated (anti-collision, activation, etc). 2. NDEF discovery is performed (Android checks if the tag contains the NDEF Tag application and tries to read the NDEF message. 3. Deactivate tag (not all devices will do this!) 4. If tag is NDEF and contains NDEF message: fire intent so that application can take over communication with the tag (in this step the read message and a handle to the tag will be passed to your app).Azucenaazure
5. Depending on how long it takes until your app picks up the intent and starts to interact with the tag, Android may keep the connection with the tag alive through either (NXP chipset) exchanging ISO 14443-4 (R-)blocks or (Broadcom chipset) sending READ BINARY APDUs on the NDEF file. 6. When your app performs the Ndef.connect(), Android disconnects the tag, tries to activate it again and selects the NDEF application. It should then read the CC file (and possible some bytes of the NDEF file) and check if the new NDEF message is smaller than the maximum size of the NDEF file.Azucenaazure
If that's the case, it should set the first two bytes of the NDEF file to zero, write the NDEF message and then set the first two bytes of the NDEF file to the new message size.Azucenaazure
So I assume you are giving valid responses to all the I-/R-/S-blocks received for these commands?Azucenaazure
Hi! I don't really understand all the process you went through or how you solved it (it is not really explained in the answe) but this might be happening to me. I can only write to the nfc card if I have previously erased it using another app (Nfc tools), once I have written in it, if I try it again it throws java.io.IOException: Tag is not ndef... Any idea why?Deferment
Actually now it is throwing the same error although I previously erased it...Deferment
S
4

It works now. I figured out that a startup routine which checks and sets the configuration word was transmitted with a too high baud rate for the AS3953. This worked for reading but something must have been mixed up for writing to the tag.

I cannot tell for sure if this is the only reason why it didn't work. There is also a problem with slow reading of the 32Byte FIFO as waterlevel interrupts are handled too late - I simply expected the problem to be on the android side since I couldn't find the write command in the logic analysis and the exception didn't describe the reason enough.

Thanks a lot to Michael Roland for further debugging, I still don't unterstand why the tag is read at first if I want to write to it but well - there should be a workaround reading an empty ndef message so the writing process will be done quickly.

For now I have to work on the firmware and cannot forecast any further problems but the actual issue (ndef.writeNdefMessage()) returns successfully.

Schubert answered 15/4, 2014 at 18:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.