Files
TagTinker/nfc/tagtinker_nfc.h
T
HoggorminoandClaude Opus 5 6aa67962b6 NFC scan: describe what the tag data shows, not the vendor
The scan only sees NFC data. It cannot sense whether a label's display
listens for infrared or radio, so the messages now say what was found
instead of naming a vendor or a transport as fact.

- "VUSION tag / SES-imagotag uses radio, not IR" becomes "Likely radio
  tag / Link: nfc.imagotag.com / TagTinker is IR-only".
- Match an http:// or https:// link whose host is nfc.imagotag.com
  (case-insensitive), as prefix code 0x03/0x04 or inline after 0x00,
  instead of the substring "imagotag" anywhere in the URL. A "://"
  inside a path, query or fragment is not taken as the scheme.
- "Not a Pricer tag" becomes "Unrecognized tag / No ID TagTinker can
  decode"; "Unsupported chip" becomes "Unreadable chip / Chip answered
  but no data was read".
- Move the decision into tagtinker_nfc_classify() so it can be tested
  off-device.
- De-duplicate on UID and result together. The firmware reports a read
  that stops partway as a success with fewer pages, so a UID-only check
  could keep a tag stuck on "Unrecognized tag" after a partial first
  read.
- Announce an unreadable chip once until the field is empty. Those reads
  carry no UID, so UID de-duplication never applied and the message
  repeated on every poll.
- Bring the prompt back from the scene tick instead of a popup callback.
  A popup with a callback consumes every short press, so Back only
  dismissed the message and a second Back was needed to leave.
- Stop the scanner on the Back event rather than waiting for on_exit, so
  the poll loop is already winding down when the scene is popped and the
  join there is as short as possible. On device, leaving from a message
  takes exactly one Back.
- Move custom event ids to 200+. NfcScanEventSuccess was 100, the same
  id as the target menu's "+ Type Barcode" item.
- Stop the scan LED when "Target list full" ends scanning.
- README: add "Which tags work", with vendor-documented radio examples
  and a table of what each scan message means.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 21:59:32 +02:00

55 lines
2.3 KiB
C

/*
* TagTinker — ESL NFC tag decoder
*
* Reads the NDEF URI from a Mifare Ultralight / NTAG tag and decodes the
* ESL id in its last path segment into the 17-character barcode format used
* by TagTinker.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
/* Longest NDEF URI body (scheme prefix excluded) we keep. */
#define TAGTINKER_NFC_URL_LEN 96
/* Extract the NDEF URI body (without the "https://" style prefix) from a tag.
* Walks the TLV area so lock/memory-control TLVs before the NDEF TLV are
* skipped, and reads as many pages as the record actually spans. */
bool tagtinker_nfc_extract_url(const MfUltralightData* mfu_data, char* url, size_t url_size);
/* Decode the ESL id in the URL's last path segment into a barcode. */
bool tagtinker_nfc_decode_url(const char* url, char barcode[18]);
/* True when the URL's host is `host` (case-insensitive). The URL may be an
* NDEF URI body without a scheme, or a full URL with one. The caller decides
* whether the stripped NDEF prefix code (for example "https://www.") changes
* the real host. */
bool tagtinker_nfc_url_host_is(const char* url, const char* host);
/* Convenience: extract the URL from the tag and decode it in one call. */
bool tagtinker_nfc_decode_barcode(const MfUltralightData* mfu_data, char barcode[18]);
/* What a completed read contains, from the app's point of view. None of these
* results identifies a vendor or a display technology; they only describe the
* NFC data. */
typedef enum {
/* A chip was activated but no page could be read: not an Ultralight/NTAG,
* or a tag that moved during the read. */
TagTinkerNfcResultUnreadable,
/* The NDEF URI carries an id TagTinker decodes; barcode is filled. */
TagTinkerNfcResultDecoded,
/* No decodable id, and the NDEF URI is an http:// or https:// link whose
* host is nfc.imagotag.com. */
TagTinkerNfcResultImagotagLink,
/* Readable, but no NDEF URI or no decodable id in it. */
TagTinkerNfcResultUnrecognized,
} TagTinkerNfcResult;
/* Classify a completed read. barcode is filled only for ..Decoded and is an
* empty string otherwise. */
TagTinkerNfcResult tagtinker_nfc_classify(const MfUltralightData* mfu_data, char barcode[18]);