Pure NFC Forum Type-4 Tag (T4T) APDU responder — the tested reference implementation of the Host Card Emulation state machine.
The Android MobNfcApduService
(priv/native/android/MobNfcBridge.kt) is a faithful Kotlin mirror of this:
identical Capability Container bytes, identical SELECT / READ BINARY /
UPDATE BINARY handling, identical write-completion detection. Because an
Android HostApduService must answer a reader even when the BEAM isn't
running, the Kotlin can't delegate here at runtime — so this module exists to
pin the protocol logic in host-runnable tests, and the Kotlin is reviewed
against it.
handle_apdu/2 is pure:
{response_bytes, new_state, event} = MobNfc.Hce.handle_apdu(apdu, state)where event is nil, :read (a reader finished reading the NDEF file), or
{:written, ndef_bytes} (a reader wrote a new message into a writable tag).
A T4T read is: SELECT NDEF app → SELECT CC → READ CC → SELECT NDEF file → READ BINARY. A write (writable tag only) additionally issues UPDATE BINARY commands: NLEN=0, the message at offset 2, then the real NLEN at offset 0.
Summary
Functions
The 15-byte Capability Container. Write-access byte is 00 (writable) when
writable, else FF (read-only); the NDEF File Control TLV points at file
E104 with max size 1024.
Handle one command APDU. Returns {response_bytes, new_state, event}.
The NDEF file image: 2-byte NLEN (message length) followed by the message.
Initial responder state serving ndef, optionally writable.
Types
Functions
The 15-byte Capability Container. Write-access byte is 00 (writable) when
writable, else FF (read-only); the NDEF File Control TLV points at file
E104 with max size 1024.
Handle one command APDU. Returns {response_bytes, new_state, event}.
Unknown instructions get 6D00; malformed/oversized get 6F00; a SELECT of
an unknown file id gets 6A82.
The NDEF file image: 2-byte NLEN (message length) followed by the message.
Initial responder state serving ndef, optionally writable.