Home › Forums › Ask the Flomies › NDEF Records Not Parsing
Tagged: ACR1255U-J1, Flomio Pro SDK, iOS, NDEF
-
AuthorPosts
-
January 22, 2018 at 2:32 am #62022
Hey all,
I’m evaluating the Flomio Pro SDK v2.3 with the ACR1255U-J1 (I already had one, so we just bought the Pro license) for my company. We do in-event experiential technology, and we often read the NDEF encoded messages from NFC tags. I have several MIFARE Ultralight tags that have NDEF encoded messages on them. I have verified this with several Android apps as well as using CoreNFC on iOS with an iPhone X.
Using this code:
func readData(deviceId: String) { flomioMW.readNdef(deviceId) { (ndef) in guard let ndef = ndef else { print("ndef was nil!") return } print("ndef error: \(ndef.error)") guard let ndefRecords = ndef.ndefRecords else { print("ndefRecords was nil!") return } for record in ndefRecords { let ndefRecord = record as! NdefRecord print("Payload: " + ndefRecord.payloadString) } } }
The variable, ndefRecords, is always nil for these tags, so I can’t read the NDEF messages.
Using this code:
func readData(completionHandler: @escaping (String, Error?) -> Void) { var fullResponse = "" var isHalted = false for currentPage in stride(from: 4, to: 16, by: 4) { let st = String(format:"%02X", currentPage) let apdu: String = "FF B0 00 \(st) 10" guard isHalted == false else { return } flomioMW .sendApdu(apdu, toDevice: self.deviceUuid) { (response) in guard isHalted == false else { return } print("response: \(response)") guard response != "63 00" else { completionHandler("", NFCReadError.ndefPartialRead) isHalted = true return } guard let thisResponse = response?.replacingOccurrences(of: "90 00", with: "") else {return} fullResponse.append(thisResponse) print("fullResponse: \(fullResponse)") print("count: \(fullResponse.count)") if fullResponse.count == 144 { completionHandler(fullResponse, nil) } } } }
I’m able to extract the payload of the tags by sending APDU messages. An example of the output of the payload of one of these tags is:
01 03 A0 0C 34 03 10 D1 01 0C 54 02 65 6E 48 53 54 4E 2D 30 36 35 32 FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Screenshots from NXP TagInfo app:
Am I doing something wrong? Is this an issue with the SDK? Is there an update to the SDK that works? Do you have code to parse the payload into NDEF encoded records? Any and all help would be greatly appreciated.
– Steven
- This topic was modified 6 years, 10 months ago by Steven.
January 22, 2018 at 9:57 am #62025Hi Steven,
Thanks for the detailed post. I am looking into this now and will find the issue and release an updated SDK with a fix for you as soon as it’s ready and tested.
Scott
- This reply was modified 6 years, 10 months ago by Scott.
January 22, 2018 at 11:09 am #62027Hi Steven,
I have determined the issue. The
readNdef
method expects the NDEF TLV (explained below) to start at the first byte of the first page of user data (page 04). There are unrelated bytes in your tag that are throwing the parser off (01 03 A0 0C 34). If you feed from D1 to FE into the parser like:let exampleNdef = "D1 01 0C 54 02 65 6E 48 53 54 4E 2D 30 36 35 32 FE" let bytes = Utilities.byteArray(fromHexString: exampleNdef) let ndef = NdefMessage.init(byteBuffer: bytes)
you should get the correct NdefMessage object.
As the other apps you mention can find an NDEF message using the TLV
T (Tag) NDEF Message TLV: 03 L (Length): 10 V (Value): D1 01 0C 54 02 65 6E 48 53 54 4E 2D 30 36 35 32 Terminator TLV: FE
we will add that to our parser and update the SDK for you.
For the moment, if you know there are fixed length non-ndef bytes at the start of your tags, you could just do the above, otherwise standby and we will update the SDK with the improved parser ASAP.Scott
- This reply was modified 6 years, 10 months ago by Scott.
January 22, 2018 at 1:12 pm #62029Thanks Scott for the quick reply! I dug up 6 different tags that we had lying around the office. Of the 6, 5 of them had 7 words before the D1 of their messages, and one had 2 words before the D1:
01 03 A0 0C 34 03 15 D1 01 11 54 02 65 6E 30 34 46 38 36 33 30 32 45 43 34 43 38 30 FE
01 03 A0 0C 34 03 10 D1 01 0C 54 02 65 6E 48 53 54 4E 2D 30 36 35 32 FE
01 03 A0 0C 34 03 10 D1 01 0C 54 02 65 6E 4E 49 4B 45 2D 30 34 39 31 FE
01 03 A0 0C 34 03 0E D1 01 0A 54 02 65 6E 67 69 6E 73 65 6E 67 FE 65 73 74 69 6E 67 FE
01 03 A0 0C 34 03 2A D1 01 26 54 02 65 6E 45 4F 31 37 56 4C 4C 75 50 4B 4D 70 5A 61 4F 6F 31 50 50 36 62 79 31 54 58 35 30 3D 0A 7C 4A 65 66 66 <- (This one’s payload is longer than what I’m reading.)
03 13 D1 01 0F 55 03 6D 73 66 74 2E 69 74 2F 41 72 69 65 6C 61 FE
All of these tags could be read using CoreNFC on an iPhone X.
Here are the prefix words in the order of the messages above:
01 03 A0 0C 34 03 15
01 03 A0 0C 34 03 10
01 03 A0 0C 34 03 10
01 03 A0 0C 34 03 0E
01 03 A0 0C 34 03 2A
03 13Does this correspond to Section 3.2 Record Layout of the NFC Data Exchange Format Technical Specification (starts on page 14)?
NFC Data Exchange Format (NDEF)January 22, 2018 at 1:41 pm #62030Hey Scott,
Removing the prefix bytes worked for all the tags except for the one that was too long. I can work with this solution for the near term events. Thank you so much!!! I’m still very curious what those prefix bytes are for, and like I said, CoreNFC has no problems reading them. If you want the Flomio SDK to be as similar to CoreNFC as possible to get the most adoption in the iOS community, you’ll want to figure out why those bytes are there and how CoreNFC has no problems ignoring them. I’d be happy to test your updated SDK when you figure this stuff out.
– Steven
January 22, 2018 at 1:44 pm #62031Another quick thought. If those prefix bytes tell us the length of the NDEF messages, we can just make one APDU call to get the entire NDEF payload…
January 23, 2018 at 5:41 am #62057I agree that our parser should handle this case and thanks for offering to help test it.
Let me know if you have any more questions.
Scott
January 23, 2018 at 7:26 am #62058For your information, the bytes are Lock Control TLV bytes.
So parsing01 03 A0 0C 34 03 15 D1 01 11 54 02 65 6E 30 34 46 38 36 33 30 32 45 43 34 43 38 30 FE
manually gives us:T 01: Lock Control TLV L 03: Length V A0 0C 34 T 03: NDEF Message TLV L 15: Length (21 bytes) V D1 01 11 54 02 65 6E 30 34 46 38 36 33 30 32 45 43 34 43 38 30 T FE: Terminator TLV
Parsing
03 13 D1 01 0F 55 03 6D 73 66 74 2E 69 74 2F 41 72 69 65 6C 61 FE
gives usT 03: NDEF Message TLV L 13: Length (19 bytes) V D1 01 0F 55 03 6D 73 66 74 2E 69 74 2F 41 72 69 65 6C 61 T FE: Terminator TLV
Just in case you are curious.
Scott
January 23, 2018 at 8:04 pm #62064Thanks Scott! With this info I’m able to read the memory just enough to read the first NDEF encoded message. This’ll be enough for what I need in the near future. Here’s the code for reference:
func didFind(_ tag: FmTag!, fromDevice deviceUuid: String!) { DispatchQueue.main.async { if let thisUuid = tag.uuid, let thisDeviceId = deviceUuid { print("Did find UUID: \(thisUuid) from Device: \(thisDeviceId)") self.getFirstNDEFMessage() { response in print("Response: \(response)") self.printBits(hexString: response) guard let prefix = response.uppercased().components(separatedBy: "D1").first else { print("No prefix") return } let range = NSString(string: response).range(of: prefix) var message = NSString(string: response).replacingCharacters(in: range, with: "") guard let withoutSuffix = message.uppercased().components(separatedBy: "FE").first else { print("Could not remove suffix") return } message = withoutSuffix + "FE" print("ndef message: \(message)") let bytes = Utilities.byteArray(fromHexString: message) let ndefMessage = NdefMessage.init(byteBuffer: bytes) print("ndef: \(ndefMessage)") guard let ndef = ndefMessage else { print("ndef was nil!") return } print("ndef error: \(ndef.error)") guard let ndefRecords = ndef.ndefRecords else { print("ndefRecords was nil!") return } for record in ndefRecords { let ndefRecord = record as! NdefRecord print("Payload: " + ndefRecord.payloadString) let status = ndefRecord.payload[0] let encodingBit = Int(status & 0x80) var encoding: String.Encoding if encodingBit == 0 { encoding = .utf8 } else { encoding = .utf16 } let length = Int(status & 0x3F) let tagId = String.init(data: ndefRecord.payload[length + 1 ... ndefRecord.payload.count - length + 1], encoding: encoding) ?? "<Unknown>" print("TagId: \(tagId)") DispatchQueue.main.async { self.tagLabel.text = tagId } } } } } }
func getFirstNDEFMessage(completionHandler: @escaping (String) -> Void) { readBlockAt(page: 4, fullResponse: "") { (fullResponse) in print("FullResponse: \(fullResponse)") completionHandler(fullResponse) } }
func readBlockAt(page: Int, fullResponse: String, completionHandler: @escaping (String) -> Void) { let st = String(format:"%02X", page) let apdu: String = "FF B0 00 \(st) 10" print("CURRENTPAGE: \(page)") print("APDUSTRING: \(apdu)") flomioMW.sendApdu(apdu, toDevice: self.deviceUuid) { (response) in let response = response?.replacingOccurrences(of: "90 00", with: "") let fullResponse = fullResponse + " " + (response ?? "") guard response != "63 00" else { completionHandler(fullResponse) return } guard !(fullResponse.contains("D1") && fullResponse.contains("FE")) else { completionHandler(fullResponse) return } self.readBlockAt(page: page + 4, fullResponse: fullResponse, completionHandler: completionHandler) } }
Hopefully that helps if not you, someone else.
I have a few more questions I’ve asked the forum if you get the time. Thanks so much for your help!
– Steven
-
AuthorPosts
You must be logged in to reply to this topic.