perf(machine): fewer NFC APDUs (E104-first) + single-attempt read
Retrying a read hammered the cheap CCID reader into a stuck present↔empty loop (only cleared by a reboot), so drop the retry: a read is a single attempt and the user re-taps if the RF link drops mid-read. Also skip the Capability-Container round-trip in the common case — NTAG424 Bolt Cards use NDEF FileID E104, so try E104/0004 directly and only read the CC to discover the id if both fail. Fewer APDUs → a read completes inside a shorter stable window. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ea736dfab0
commit
ed04c63b2f
1 changed files with 21 additions and 14 deletions
|
|
@ -87,20 +87,20 @@ export async function readNdefLnurlw(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer the FileID advertised by the Capability Container (EF E103).
|
// NTAG424 Bolt Cards use NDEF FileID E104. Try it (and 0004) directly to
|
||||||
const candidates: Array<[number, number]> = []
|
// minimise APDU round-trips over a flaky RF link; only fall back to reading
|
||||||
|
// the Capability Container to discover the id if both direct reads fail.
|
||||||
|
for (const fid of [[0xe1, 0x04] as [number, number], [0x00, 0x04] as [number, number]]) {
|
||||||
|
const found = await readNdefFile(send, fid)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
if (swOk(await send([0x00, 0xa4, 0x00, 0x0c, 0x02, 0xe1, 0x03]))) {
|
if (swOk(await send([0x00, 0xa4, 0x00, 0x0c, 0x02, 0xe1, 0x03]))) {
|
||||||
const cc = await send([0x00, 0xb0, 0x00, 0x00, 0x0f])
|
const cc = await send([0x00, 0xb0, 0x00, 0x00, 0x0f])
|
||||||
// CC layout: …[07]=TLV tag 0x04, [08]=len, [09..10]=NDEF FileID.
|
// CC layout: …[07]=TLV tag 0x04, [08]=len, [09..10]=NDEF FileID.
|
||||||
if (swOk(cc) && cc.length >= 13 && cc[7] === 0x04) candidates.push([cc[9], cc[10]])
|
if (swOk(cc) && cc.length >= 13 && cc[7] === 0x04) {
|
||||||
}
|
const found = await readNdefFile(send, [cc[9], cc[10]])
|
||||||
for (const fid of [[0xe1, 0x04] as [number, number], [0x00, 0x04] as [number, number]]) {
|
if (found) return found
|
||||||
if (!candidates.some((c) => c[0] === fid[0] && c[1] === fid[1])) candidates.push(fid)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const fid of candidates) {
|
|
||||||
const found = await readNdefFile(send, fid)
|
|
||||||
if (found) return found
|
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
@ -157,12 +157,19 @@ export async function startNfcReader(
|
||||||
|
|
||||||
r.on('card', async () => {
|
r.on('card', async () => {
|
||||||
onStatus({ state: 'reading', reader: name })
|
onStatus({ state: 'reading', reader: name })
|
||||||
|
// Single attempt: hammering a flaky RF link with retries wedges these
|
||||||
|
// cheap CCID readers. A read is a few APDU round-trips; if the card
|
||||||
|
// shifts mid-read the transmit fails and the user simply re-taps.
|
||||||
try {
|
try {
|
||||||
const lnurlw = await readNdefLnurlw((apdu, maxLen) => r.transmit(apdu, maxLen))
|
const lnurlw = await readNdefLnurlw((apdu, maxLen) => r.transmit(apdu, maxLen))
|
||||||
if (lnurlw) onCard(lnurlw)
|
if (lnurlw) {
|
||||||
else onStatus({ state: 'error', reader: name, message: 'not a Bolt Card' })
|
onCard(lnurlw)
|
||||||
|
} else {
|
||||||
|
onStatus({ state: 'error', reader: name, message: 'not a Bolt Card' })
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
onStatus({ state: 'error', reader: name, message: errMsg(e) })
|
onStatus({ state: 'error', reader: name, message: 'card read failed — hold steady & retap' })
|
||||||
|
void e
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
r.on('card.off', () => onStatus({ state: 'card-removed', reader: name }))
|
r.on('card.off', () => onStatus({ state: 'card-removed', reader: name }))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue