@@ -177,7 +177,7 @@ def _handle_iso14443a_cards(self, reader) -> bool:
177177 )
178178 if len (uids ) >= 1 :
179179 card = session .connect_iso14443a (uids [0 ])
180- self ._read_from_card (card )
180+ self ._read_from_card (card , True )
181181 return True
182182 return False
183183
@@ -190,7 +190,7 @@ def _handle_iso15693_cards(self, reader):
190190 )
191191 if len (uids ) >= 1 :
192192 card = session .connect_iso15693 (uids [0 ])
193- self ._read_from_card (card )
193+ self ._read_from_card (card , False )
194194 return True
195195 return False
196196
@@ -228,28 +228,91 @@ def stop(self) -> None:
228228 """Call to stop the handler"""
229229 self ._should_stop_event .set ()
230230
231- def _read_from_card (self , card ) -> None :
231+ class _Tag : # pylint: disable=too-few-public-methods
232+ def __init__ (self , card ):
233+ self ._card = card
234+ self ._records = None
235+
236+ def _read_field (self , mem : bytes , offset : int ) -> tuple [int , int | None ]:
237+ if offset >= len (mem ):
238+ return (- 1 , None )
239+ val = mem [offset ]
240+ offset += 1
241+ if val < 255 :
242+ return (val , offset )
243+ if offset + 2 > len (mem ):
244+ return (- 1 , None )
245+ val = (mem [offset ] << 8 ) | mem [offset + 1 ]
246+ offset += 2
247+ return (val , offset )
248+
249+ def _find_ndef_offset (self , mem : bytes ) -> int | None :
250+ if len (mem ) < 32 :
251+ return None
252+ if mem [12 ] != 0xE1 :
253+ return None
254+ offset : int | None = 16
255+ while offset is not None and offset < len (mem ):
256+ (typ , new_offset ) = self ._read_field (mem , offset )
257+ if new_offset is None :
258+ return None
259+ offset = new_offset
260+ if typ == 0x00 :
261+ continue
262+ (length , new_offset ) = self ._read_field (mem , offset )
263+ if new_offset is None :
264+ return None
265+ offset = new_offset
266+ if typ == 0x03 :
267+ break
268+ offset += length
269+ if offset is None or offset >= len (mem ):
270+ return None
271+
272+ return offset
273+
274+ @property
275+ def records (self ) -> list [ndef .Record ]:
276+ """Return parsed NDEF Records"""
277+ if self ._records is None :
278+ mem = b""
279+ try :
280+ offset = 0
281+ while True :
282+ # print(f"Reading from offset {offset}")
283+ chunk = self ._card .read_memory (offset // 4 , 64 )
284+ offset += len (chunk )
285+ mem += chunk
286+ except TimeoutError :
287+ pass
288+
289+ ndef_offset = self ._find_ndef_offset (mem )
290+ if ndef_offset is not None :
291+ self ._records = list (ndef .message_decoder (mem [ndef_offset :]))
292+ else :
293+ self ._records = []
294+ return self ._records
295+
296+ def _read_from_card (self , card , parse_ndef : bool ) -> None :
232297 """Read data from tag and call callback"""
233298 if self ._on_nfc_tag_present :
234299 identifier : str = card .uid .hex (":" )
235300
236- # pylint: disable=fixme
237- # TODO: Read memory and parse NDEF
238- mem = b""
239- try :
240- offset = 0
241- while True :
242- chunk = card .read_memory (offset // 4 , 64 )
243- # print(f"Read {len(chunk)}")
244- offset += len (chunk )
245- mem += chunk
246- except TimeoutError :
247- pass
248-
249- # print(f"Decoding:\nLEN: {len(mem)}\n{mem.hex(' ')}")
250- # print(mem)
251-
252- self ._on_nfc_tag_present (mem , identifier )
301+ if parse_ndef :
302+ tag = self ._Tag (card )
303+ self ._on_nfc_tag_present (tag , identifier )
304+ else :
305+ mem = b""
306+ try :
307+ offset = 0
308+ while True :
309+ # print(f"Reading from offset {offset}")
310+ chunk = card .read_memory (offset // 4 , 64 )
311+ offset += len (chunk )
312+ mem += chunk
313+ except TimeoutError :
314+ pass
315+ self ._on_nfc_tag_present (mem , identifier )
253316
254317
255318def create_nfc_handler (nfc_device : str , implementation : str = "nfcpy" ) -> NfcInterface :
0 commit comments