# NFC to RFID > Full text of 13 page(s) across 1 book(s), for language-model ingestion. # NFC to RFID ![NFC to RFID — encode NFC card UIDs onto UHF RFID tags](asset:assets/banner-large.png) **NFC to RFID** is an Android app that copies the UID of an NFC card onto a UHF EPC Gen2 tag, so that the tag becomes a radio-readable "shadow" of the card: a UHF scan from a distance returns the same identifier that the card reports over NFC. It runs on Sunmi handheld terminals with UHF RFID — a built-in module (L2s RFID, L3) or the UHF trigger handle attached to an L2k / L2s / L2H / L2s Pro — and on any NFC-capable Android device paired with an external Chainway reader (e.g. R2 / R3) over USB or Bluetooth — see [Supported readers](md/nfc-to-rfid/readers.md). Tested with Chainway R2, Chainway R3, Sunmi L2k, Sunmi L2s RFID and Sunmi L3. Typical use case: assets or badges carry both an NFC card (short-range, secure identification) and a UHF label (long-range, bulk inventory). This app encodes the labels, keeps them password-locked against tampering, and verifies that card–tag pairs match. ![About tab](asset:assets/about.png#w=300&h=75vh) ![About tab (tablet)](asset:assets/about_l.png#w=300&h=75vh) ## What the app does - **Encode** — reads an NFC card's UID, checks that exactly *one* UHF tag is in range, and writes the UID into the tag's EPC memory bank (with confirmation before every write). See [Encoding a tag](md/nfc-to-rfid/encoding.md). - **Lock** (optional, on by default) — after writing, the tag is protected: an access password and a kill password are set, and the EPC, access-password and kill-password banks are locked. Re-encoding a locked tag is only possible with the configured access password. See [Settings](md/nfc-to-rfid/settings.md). - **Scan** — bulk inventory of tags encoded by this app, with live pairing validation against tapped NFC cards. See [Bulk inventory and validation](md/nfc-to-rfid/scanning.md). - **Validate** — one-by-one check: tap a card, get an immediate PAIRED / TAG MISSING verdict. See [One-by-one validation](md/nfc-to-rfid/validating.md). - **NXP originality check** — on every card tap the app verifies the card's NXP originality signature against NXP's public keys. See [NXP originality check](md/nfc-to-rfid/nxp-originality.md). > [!TIP] > Feedback is designed for warehouse use: distinct success/error tones, vibration, > and a full-screen green/red flash visible from the corner of your eye. --- ![NFC to RFID](asset:assets/banner.png) --- # Requirements | Component | Requirement | |---|---| | UHF reader | One of the [supported readers](md/nfc-to-rfid/readers.md): the built-in UHF module of a Sunmi L2s RFID / L3, the UHF R2000 trigger handle on a Sunmi L2k / L2s / L2H / L2s Pro, or an external Chainway reader (e.g. R2 / R3) over USB or Bluetooth | | Device | Android 7.0+ with NFC; for Sunmi readers a Sunmi handheld with the Sunmi scanner service (`com.sunmi.scanner`, preinstalled) | | Cards | NFC-A: MIFARE Classic/Ultralight, NTAG, DESFire (UID 4, 7 or 10 bytes) | | Tags | EPC Gen2 (ISO 18000-6C) with a 96-bit EPC bank — e.g. Impinj Monza R6, M730/M750, NXP UCODE 8/9 | Tested with Chainway R2, Chainway R3, Sunmi L2k, Sunmi L2s RFID and Sunmi L3. > [!NOTE] > Cards with random UIDs (e.g. bank cards) are rejected — a random UID cannot serve > as a stable identifier. --- # Supported readers All app functions — encoding, locking, scanning and validating — work on several UHF reader backends. The reader is picked automatically by default and can be forced in [Settings](md/nfc-to-rfid/settings.md). | Backend | Connection | Hardware | |---|---|---| | Sunmi | Sunmi scanner service | Built-in UHF module of an L2s RFID / L3 (Inner M500, UHF S7100, Inner SIM3500), or the UHF R2000 trigger handle attached to an L2k / L2s / L2H / L2s Pro | | Chainway USB | USB cable / dock | Chainway desktop and handheld readers, e.g. R3 | | Chainway Bluetooth | Bluetooth LE | Chainway handheld readers, e.g. R2 / R3 | Tested with **Chainway R2**, **Chainway R3**, **Sunmi L2k**, **Sunmi L2s RFID** and **Sunmi L3**. ## Auto-detection With the reader setting on **Auto-detect** (the default), the app probes on start and after every settings change, in this order: 1. **Chainway USB** — a reader attached over USB is the strongest signal of intent; 2. **Sunmi** — the built-in UHF module via the Sunmi scanner service; 3. **Chainway Bluetooth** — the previously selected reader, if one was saved. The first reader that answers wins; the About tab shows which one is active. To pin a specific backend regardless of what is attached, choose it explicitly in [Settings](md/nfc-to-rfid/settings.md). ## Chainway over USB Attach the reader and confirm the Android USB permission prompt on first use. No pairing is needed — the reader is picked up automatically (or select **Chainway USB** in settings). ## Chainway over Bluetooth 1. Open [Settings](md/nfc-to-rfid/settings.md) and tap **Choose…** next to the Bluetooth reader row. 2. Grant the Bluetooth permission when asked (Android 12+: *Nearby devices*; Android 11 and older: *Location*). 3. Pick your reader from the list — it is sorted by signal strength and shows only devices that advertise a name, so the nearest reader is usually on top. 4. Save. The reader is remembered and reconnected automatically from then on. ## Trigger support The hardware trigger works on every backend in the Scan tab (press to scan, release to stop): - **Sunmi** — the pistol-grip / side key configured as the RFID trigger; - **Chainway R2 / R3** — the reader's own trigger button, delivered over the active USB or Bluetooth link. ## Power ranges The [read/write power settings](md/nfc-to-rfid/settings.md) apply to all backends. Each reader clamps the value to its supported range: Sunmi modules accept 10–33 dBm, Chainway modules 1–30 dBm. --- # Installation On a Sunmi device, install the app from the **Sunmi App Store** — open this link on the device: ``` market://woyou.market/appDetail?packageName=dev.duma.android.nfctorfid ``` Alternatively, download the APK from the project's [GitHub Releases](https://github.com/kduma-autoid/android-sunmi-nfc-to-uhf-rfid/releases) page or build from source (see [Development](md/nfc-to-rfid/development.md)). --- # Using the app The bottom navigation has four tabs — **About**, **Encode**, **Scan**, **Validate** — plus a settings gear in the top bar. The About tab shows the app version, the detected UHF reader model and a summary of the encoding format. ## The workflows - [Encoding a tag](md/nfc-to-rfid/encoding.md) — copy a card's UID onto a UHF tag (Encode tab). - [Bulk inventory and validation](md/nfc-to-rfid/scanning.md) — continuous inventory with live pairing checks (Scan tab). - [One-by-one validation](md/nfc-to-rfid/validating.md) — instant PAIRED / TAG MISSING verdict per card (Validate tab). - [Settings](md/nfc-to-rfid/settings.md) — passwords, locking, scan duration and radio power. --- # Encoding a tag The **Encode** tab copies an NFC card's UID onto a UHF tag in four steps. ## 1. Tap the NFC card The UID and the [NXP originality](md/nfc-to-rfid/nxp-originality.md) status appear in step 1. A short beep confirms the tap was registered. ## 2. UHF tag check The app scans for the configured duration (default 3 s) and requires exactly one tag in range. Zero or multiple tags stop the workflow with an error — isolate a single tag and press *Scan again*. ## 3. Confirm the write The screen shows the tag's current EPC (with RSSI) and the new EPC to be written. If the tag already carries a UID from a *different* card, an overwrite warning is shown. Press **Write tag**. ## 4. Write, lock, verify The app writes the EPC, sets the passwords, locks the tag (when locking is enabled), and verifies the result by reading the tag back. Success is signalled with a green flash. ~~~gallery w=210 scroll ![1. Waiting for card](assets/encode-wait-for-card.png) ![2. UHF check](assets/encode-uhf-scan.png) ![3. Confirmation](assets/encode-confirm-write.png) ![4. Success](assets/encode-success.png) Signalled with a green flash and a success tone. ![Already encoded](assets/encode-already-encoded.png) Shown when the tag already carries this card's UID. ![Invalid signature](assets/encode-invalid-signature.png) Shown when the card's NXP originality signature does not validate. ~~~ ~~~gallery w=210 scroll ![1. Waiting for card (tablet)](assets/encode-wait-for-card_l.png) ![2. UHF check (tablet)](assets/encode-uhf-scan_l.png) ![3. Confirmation (tablet)](assets/encode-confirm-write_l.png) ![4. Success (tablet)](assets/encode-success_l.png) ![Already encoded (tablet)](assets/encode-already-encoded_l.png) ![Invalid signature (tablet)](assets/encode-invalid-signature_l.png) ~~~ ## Continuous mode **Continuous mode** returns to step 1 automatically two seconds after a success — convenient for encoding a batch of cards. ## Already-encoded tags If the scanned tag already carries this card's UID, the app reports *"re-writing is not required"* instead of writing. > [!NOTE] > With locking enabled the app silently completes any missing passwords/locks first — > this also repairs tags left half-secured by an interrupted write. **Write again > anyway** forces a full re-write. ## If a write fails > [!TIP] > If a write fails mid-sequence (e.g. the tag left the field), simply scan again — > the workflow re-reads the tag's current state and the whole sequence is safe to > re-run. --- # Bulk inventory and validation Press **Start scan** or hold the **trigger key** to run a continuous UHF inventory on the **Scan** tab. The trigger works on every [reader backend](md/nfc-to-rfid/readers.md): the Sunmi RFID trigger key as well as the built-in trigger of Chainway R2/R3 handhelds over USB or Bluetooth. How tags respond to the inventory is controlled by the **Inventory mode** [setting](md/nfc-to-rfid/settings.md), which selects the EPC Gen2 session used on this tab: - **High speed** (default) — tags answer continuously; best for finding a single tag and watching its live RSSI. - **Balanced** — each tag stays quiet for a moment after it has been read, giving the others more air time. - **Traversal** — each tag answers once per scan; best for taking inventory of many tags at once. The mode applies only to this tab — encoding, validation and the post-write verification always scan in high speed. Tags encoded by this app are listed with their decoded UID, live RSSI and read count; foreign tags are only counted, not listed. The list accumulates between scans — **Clear** resets it, **Share** exports the UID list (one per line) via the system share sheet. ## Validating cards against the inventory Tapping NFC cards while on this tab validates card–tag pairs: - Card whose tag has been seen over UHF → entry turns **green** (*Paired*), success signal. - Card without a matching UHF read → **red** entry pinned to the top (*missing tag*), and it turns green automatically once a scan reads the tag. ~~~gallery w=180 scroll ![Empty](assets/scan-empty.png) ![Inventory](assets/scan-tag-list.png) ![Paired](assets/scan-validation-paired.png) The card's tag was seen over UHF — the entry turns **green**. ![Missing](assets/scan-validation-missing.png) No matching UHF read — pinned **red** at the top. ~~~ ~~~gallery w=180 scroll ![Empty (tablet)](assets/scan-empty_l.png) ![Inventory (tablet)](assets/scan-tag-list_l.png) ![Paired (tablet)](assets/scan-validation-paired_l.png) ![Missing (tablet)](assets/scan-validation-missing_l.png) ~~~ --- # One-by-one validation Tap a card on the **Validate** tab — the app searches for a tag carrying exactly that card's EPC and shows a full-screen verdict: green **PAIRED** (with the tag's RSSI) or red **TAG MISSING**. The card's [NXP originality](md/nfc-to-rfid/nxp-originality.md) status is shown underneath. The screen is immediately ready for the next card. ~~~gallery w=180 scroll ![Idle](assets/validate-idle.png) ![Searching](assets/validate-searching.png) The reader looks for the card's EPC within the configured scan duration. ![Paired](assets/validate-paired.png) A tag answered — its RSSI is shown. ![Missing](assets/validate-tag-missing.png) No tag with this card's EPC in range. ~~~ ~~~gallery w=180 scroll ![Idle (tablet)](assets/validate-idle_l.png) ![Searching (tablet)](assets/validate-searching_l.png) ![Paired (tablet)](assets/validate-paired_l.png) ![Missing (tablet)](assets/validate-tag-missing_l.png) ~~~ --- # Settings Open the settings with the gear icon in the top bar. ~~~gallery ![Settings (top)](assets/settings.png) ![Settings (bottom)](assets/settings-bottom.png) ![Settings (tablet)](assets/settings_l.png) ~~~ | Setting | Default | Description | |---|---|---| | UHF reader | Auto-detect | Which [reader backend](md/nfc-to-rfid/readers.md) to use: Auto-detect, Sunmi (built-in), Chainway USB or Chainway Bluetooth | | Bluetooth reader | — | The Chainway reader used by the Bluetooth backend; **Choose…** scans for nearby readers and remembers the selection | | Access password | — | 8 hex digits. Used to lock tags and to re-encode tags locked by this app | | Kill password | — | 8 hex digits. Written to the tag so nobody else can set one and kill the tag | | Lock tags after writing | on | Requires both passwords to be set and non-zero | | Inventory mode | High speed | How tags respond to a [Scan tab](md/nfc-to-rfid/scanning.md) inventory — see *Inventory modes* below | | Scan duration | 3 s | Length of the UHF check in the Encode workflow and the Validate search window | | Read power | 20 dBm | Inventory power. Keep it low — a small field makes isolating a single tag easier | | Write power | 26 dBm | Power used for write/lock operations. Writes target one EPC, so more power is safe. Internal modules accept 18–26 dBm; each reader clamps the value to its own range (Sunmi 10–33 dBm, Chainway 1–30 dBm) | > [!WARNING] > **Store the passwords safely.** A tag locked with a lost access password cannot be > re-encoded. ## Inventory modes The inventory mode selects the EPC Gen2 *session* used while scanning. A session controls how long a tag stays quiet after it has been read once — the trade-off is between re-reading the same tag quickly (live RSSI, finding one tag) and giving every tag in the field a chance to answer (bulk inventory): - **High speed** (session S0) — tags answer continuously and the same tag is re-read many times per second. Best for working with a single tag: the read count climbs and the RSSI updates live, so you can locate a tag by signal strength. - **Balanced** (session S1) — a tag stays quiet for a short while (roughly 0.5–5 s) after each read, freeing air time for the other tags. A middle ground when a handful of tags are in the field. - **Traversal** (session S2) — a tag that has been read stays quiet for a long time, so each tag answers essentially once per scan. Best for counting many tags at once; expect read counts of 1 and no live RSSI updates. The mode applies **only to the Scan tab**. Encoding, validation and the post-write verification always scan in high speed — a tag silenced by the S1/S2 quiet period could otherwise be missed and fail the check falsely. --- # EPC encoding format The EPC is 96 bits (12 bytes, 6 words) and is written together with a new PC word, so encoding works regardless of the tag's previous EPC length: ``` PC word = 0x3100 L = 6 words; T (toggle) = 1 → non-GS1 / ISO namespace, AFI = 0x00 byte 0 = 0x4E application magic ('N') byte 1 = UID length 0x04 / 0x07 / 0x0A bytes 2–11 = UID bytes, left-aligned, zero-padded ``` Example: card UID `74:0B:2A:EB` (4 bytes) → EPC `4E04740B2AEB000000000000`. ## Design notes - The T bit in the PC word declares the tag as a **non-GS1** identifier (ISO 15961), so the encoding can never collide with present or future GS1 EPC schemes. GS1-conformant software represents such tags as `urn:epc:raw:...` instead of failing to decode. - Some tag chips do not persist the T/AFI bits of a written PC word. This is harmless — decoding keys on the `4E` prefix and the UID length byte, and post-write verification compares the EPC only. - Two tags carrying the identical EPC look like one entry during inventory. The write sequence detects this after the fact: if the *old* EPC is still in the field after a successful write, the app reports a duplicate-tag error. --- # NXP originality check On every card tap the app reads the NXP originality signature (DESFire family over ISO-DEP, NTAG21x/Ultralight over NFC-A) and verifies it against NXP's public keys. > [!IMPORTANT] > A valid signature proves the silicon is a genuine NXP chip — it does **not** prove > the card belongs to your system. An invalid signature pauses the workflow with a warning dialog asking whether to continue. The originality status is shown in step 1 of the [Encode workflow](md/nfc-to-rfid/encoding.md) and under the verdict on the [Validate tab](md/nfc-to-rfid/validating.md). --- # Troubleshooting ## Found N tags — leave exactly one tag in range More than one tag answered during the check. Move other tags away or lower the [read power](md/nfc-to-rfid/settings.md). ## The tag left the field during the operation Hold the tag close to the reader and scan again; the sequence is safe to re-run. ## Access failed / Write failed — locked with a different password The tag was locked with a password other than the configured one. Without that password the tag cannot be re-encoded. ## A tag with the old EPC is still in range Two tags carried the identical EPC and only one took the write. Remove one and scan again. ## NXP originality: could not read signature The card was pulled away too quickly — hold it on the reader a moment longer. ## NXP originality: INVALID signature The signature does not match any known NXP key — possible counterfeit chip. The app asks whether to continue. See [NXP originality check](md/nfc-to-rfid/nxp-originality.md). ## RFID reader: not detected (About tab) No reader answered during auto-detection. Depending on the backend: - **Sunmi** — UHF module not present/attached, or the Sunmi scanner service is unavailable; - **Chainway USB** — cable not attached, or the USB permission prompt was declined (re-attach the reader to get the prompt again); - **Chainway Bluetooth** — no reader selected yet, the reader is out of range / powered off, or the Bluetooth permission was declined. See [Supported readers](md/nfc-to-rfid/readers.md) and [Requirements](md/nfc-to-rfid/requirements.md). Selecting the backend explicitly in [Settings](md/nfc-to-rfid/settings.md) shows the connection state for that specific reader. --- # Development ## Building ```bash ./gradlew :app:assembleDebug ``` AGP 9 with built-in Kotlin, JDK 17+; the Sunmi `SunmiScannerSdk` AAR is bundled in `app/libs/`. ## Unit tests ```bash ./gradlew :app:testDebugUnitTest ``` ## CI Pushes and PRs build the APK (`.github/workflows/build.yml`); the release workflow (`.github/workflows/release.yml`) bumps the version, tags `vX.Y.Z` and publishes the APK to GitHub Releases. > [!NOTE] > Release signing uses the single `RELEASE_SIGNING` JSON secret; without it the APK > is debug-signed. ---