Asquarete

Integrating an Unbranded Chinese UHF Reader on Android

A no-name UHF reader with a CD, a broken .aar and a Chinese-only PDF is almost always a white-labeled module from a handful of chipset vendors. Identify the module, decompile the shipped APK or .aar with jadx to recover the real API surface, and — on built-in modules — raise the GPIO power rail before opening the serial port. A port opened onto an unpowered module succeeds and then times out on every command.

Device
Generic UHF module (white-label)
Platform
Android
Topic
The No-Brand Wedge
Updated
4 Sept 2026

Somewhere in the supply chain between a UHF module factory and a marketplace listing, branding and documentation get stripped out. What arrives is a reader with a working antenna, a CD with a Windows-only demo app, a .aar file that either doesn't compile or exposes no obvious inventory method, and a PDF entirely in Chinese. This is the guide for that box.

Photograph pending — Unbranded Chinese UHF RFID reader with generic packaging
A representative unbranded UHF handheld — no visible module vendor markings

What the vendor docs don't tell you

There is no vendor to ask, which is the actual problem this guide solves. The information exists, but it's distributed across the physical device markings, the chipset's public FCC/CMIIT filing, and a small set of known module vendor SDK families that most white-label hardware is built on top of.

What the docs don't tell you

The module may be unpowered, and nothing will tell you so. On one of these devices — an OEM Android tablet on an Allwinner A523 board with the UHF module soldered in rather than sledded on — every command we sent returned REQUEST_TIMEOUT (-79). The serial port opened cleanly. The permissions were right. The baud rate was right. Reads simply never came back.

The port was opening onto a dead radio. The module sits behind a GPIO power rail that the OS does not raise on boot, so a UART opened before the rail is up succeeds and then talks to nothing. Two GPIO lines — gpio200 and gpio204 on this board — have to be written before the port is opened, in the same order the stock demo app does it in its own PowerUtils.powerOn().

There is no vendor documentation that says this. We only found it by decompiling the demo app that shipped on the device and reading what it did before it opened the port. If you are timing out on a built-in UHF module and the serial layer looks correct, check whether anything has actually powered the radio.

Step 1: Identify the actual module

Before touching any code, physically inspect the device and its regulatory markings.

  • Look for an FCC ID or CMIIT ID sticker on the device housing or inside the battery compartment. Search that ID against the FCC ID database (fcc.report or the FCC's own equipment authorization search) — the filing often includes internal photos that reveal the actual module manufacturer's markings.
  • Open the .aar (it's a zip archive) and inspect AndroidManifest.xml and any .so native libraries inside jni/. Native library filenames (e.g., libuhf_xxx.so) frequently reference the actual module vendor's naming convention even when the wrapper Java/Kotlin classes were renamed for white-labeling.
  • Check the CD's demo app for an "About" or version string — Windows demo apps are less commonly rebranded than the mobile SDK and often retain the original module vendor's name in a splash screen or window title.

Step 2: Decompile the .aar with jadx

If the .aar doesn't compile as shipped, decompiling it reveals the real class and method structure, independent of whatever is broken in the build configuration.

# Unzip the .aar to get classes.jar
unzip reader-sdk.aar -d reader-sdk-extracted
cd reader-sdk-extracted
 
# Decompile with jadx
jadx classes.jar -d decompiled/

Inspect decompiled/ for the actual package structure. Look specifically for:

  • A class with init, open, or connect methods taking a serial port path or Bluetooth MAC address — this is almost always the entry point.
  • Method names resembling inventory, readTag, getEPC — these map to the read loop you'll eventually wire up.
  • Any hardcoded baud rate constants inside the native bridge classes — these tell you what serial configuration the module actually expects, without needing to guess.

Step 3: Probe the serial port directly if no usable SDK surfaces

Some white-label readers expose nothing usable in the .aar at all — in that case, treat the device as a raw serial peripheral and speak to it directly.

// Requires the device expose a usable serial path, e.g. via USB host mode
val port = "/dev/ttyUSB0"
val baudRates = listOf(115200, 9600, 57600)
 
fun probePort(path: String, baud: Int): Boolean {
    val process = ProcessBuilder("stty", "-F", path, baud.toString()).start()
    process.waitFor()
 
    val inventoryCommand = byteArrayOf(0xA0.toByte(), 0x03, 0x01, 0x00, 0x00) // vendor-specific framing, verify against captured traffic
    // Send inventoryCommand over the port, read response, check for EPC Gen2-style framing
    return true // placeholder for actual response validation
}

Most consumer-facing UHF modules speak a binary framed protocol over UART — typically a header byte, a length field, a command byte, a payload, and a checksum. If a public datasheet can't be found for the identified module, capturing traffic between the CD's Windows demo app and the reader (via a USB protocol analyzer, or by intercepting the demo app's serial calls) is the most reliable way to reconstruct the framing without documentation.

Step 4: Common SDK families to try before reverse-engineering from scratch

Before spending days on raw protocol reverse-engineering, check whether the module matches one of the SDK families that show up repeatedly across white-label UHF hardware:

  • Impinj Indy-based modules, which sometimes ship with a recognizable register-level API even under a rebranded wrapper.
  • Chainway-compatible UART framing — some white-label modules mimic the same command structure documented in Chainway's SDKs closely enough that the framing (not the Java wrapper) lines up directly.
  • Generic "YR" / "YM" prefixed module families common in Shenzhen-area UHF module manufacturing, which share a command set across multiple resellers even when the branding differs.

Production considerations

  • Document everything discovered during this process — the FCC ID, the identified module family, the decompiled class names, the working serial configuration — in a form the next engineer can use without repeating the reverse-engineering work.
  • Treat a reverse-engineered integration as inherently less stable across firmware batches than a documented SDK. Pin the specific firmware/hardware revision this integration was validated against, and re-verify before assuming a new batch behaves identically.
  • Weigh replacement cost against integration time realistically. Below a certain unit count, a known-brand reader with a documented SDK is often cheaper in total engineering time than reverse-engineering an unbranded unit, even though the unbranded hardware itself is cheaper.

Common errors

ErrorCauseFix
.aar fails to build with a manifest merge errorBundled SDK targets an incompatible API level or has a conflicting package nameExtract and repackage the .aar with a corrected minSdkVersion, or use jadx to extract only the needed classes into your own module
Every command returns REQUEST_TIMEOUT (-79) while the port opens fineThe UHF module is unpowered — the GPIO power rail was never raisedWrite the module's GPIO power lines (e.g. gpio200, gpio204) before opening the port, in the same order the stock demo app does
Port node /dev/ttyS3 doesn't exist, but the stock app worksThe vendor aliases the node — /dev/rfid pointing at /dev/ttyS3 or /dev/ttyAS3Open the alias the stock app opens rather than the raw node, and confirm the mapping on the actual board revision
Serial port opens but returns garbageWrong baud rate assumedSystematically try 115200, 9600, 57600, comparing response framing against expected EPC Gen2 binary structure
No response from the device at all over USB host modeDevice requires a specific USB vendor/product ID filter or permission intent not yet grantedCheck UsbManager device enumeration and confirm the app has requested and received USB permission for that specific vendor/product ID
Decompiled classes reference native .so methods with no visible implementationActual protocol logic lives in a native library, not the Java/Kotlin wrapperUse a native disassembler (e.g., Ghidra) on the .so if the JNI bridge alone doesn't reveal the framing, or fall back to traffic capture against the CD demo app

FAQ

The .aar that came with my reader won't compile. Now what?

Decompile it with jadx to inspect the actual class and method structure rather than relying on the broken build. Often the .aar itself is fine and the failure is a missing transitive dependency or an incompatible minSdkVersion in the consuming project.

How do I find out what UHF chipset is actually inside a white-label reader?

Check the FCC ID or CMIIT ID sticker if present, search it against the FCC/CMIIT public database, and cross-reference the physical module's markings against known module vendors' reference designs. Many white-label devices reuse the same handful of module families with only the enclosure and branding changed.

What if there's no SDK at all, just a serial port?

Probe /dev/ttyS* or /dev/ttyUSB* device nodes directly at common baud rates (115200 first, then 9600 and 57600) and look for EPC Gen2-style binary framing in the response to a basic inventory command. On a device with the module built in, the node may be aliased — /dev/rfid pointing at /dev/ttyS3, for instance.

Every command times out even though the serial port opens. What now?

Check whether the module is powered. On integrated UHF modules the radio often sits behind a GPIO power rail that the OS does not raise at boot, so opening the UART succeeds and then talks to a dead chip — every command returns a timeout, typically -79. Decompile the demo app that shipped on the device and look for a power-on sequence writing GPIO lines before the port is opened, then replicate it.

Is it worth reverse-engineering a reader this poorly documented for a production deployment?

Weigh it against the cost of a known-brand replacement. Reverse-engineering gets you a working integration, not a supported one — there's no vendor to call when firmware changes on a future batch.

Written by Efron, who has this device on the bench.

Hardware integration engineer at Asquarete. Published 18 Jul 2026, last revised 4 Sept 2026.

Related guides

Stuck on this device?

Send the model, the SDK version and what's failing. You get a written read on whether it's solvable within 24 hours, before any money moves.

Get a feasibility read