# Chainway C5 UHF RFID Reader — Tag Relative Positioning via SDK ## Overview This document covers how to get the **relative position** of an RFID tag using the Chainway C5 UHF RFID reader's Android SDK (`API_Ver20251103`). Based on a direct examination of the Javadoc bundled inside `DeviceAPI_ver20251103_release.aar`, the SDK provides **three approaches** to tag positioning — from a simple proximity value to raw RF data for custom algorithms. --- ## 1. `UHFTAGInfo` — Complete Tag Data Per Read The `com.rscja.deviceapi.entity.UHFTAGInfo` class (returned by `inventorySingleTag()` and the inventory buffer) exposes **significantly more data** than commonly documented by third-party wrappers. The full getter list from the actual SDK Javadoc: | Method | Return Type | Description | |--------|-------------|-------------| | `getEPC()` | `String` | Electronic Product Code | | `getEpcBytes()` | `byte[]` | EPC as raw bytes | | `getTid()` | `String` | Tag Identifier | | `getTidBytes()` | `byte[]` | TID as raw bytes | | `getRssi()` | `String` | Received Signal Strength Indicator | | **`getPhase()`** | **`int`** | **RF phase angle** | | **`getFrequencyPoint()`** | **`float`** | **Frequency point / channel** | | **`getAnt()`** | **`String`** | **Antenna port identifier** | | **`getTimestamp()`** | **`long`** | **Timestamp of the read** | | `getCount()` | `int` | Number of times this tag was seen | | `getPc()` | `String` | Protocol Control bits | | `getUser()` | `String` | User memory bank data | | `getUserBytes()` | `byte[]` | User memory as raw bytes | | `getReserved()` | `String` | Reserved memory bank data | | `getRemain()` | `int` | Remaining tags in the buffer | | `getIndex()` | `int` | Tag index | | `getChipInfo()` | `UHFTAGInfo.ChipInfo` | Chip information (nested class) | | `getExtraData(String key)` | `String` | Extra data by key | ### Key Fields for Positioning - **`getPhase()`** — The RF phase angle of the backscattered signal. This is the most important raw measurement for computing relative distance to a tag. Phase changes predictably with distance (modulo the RF wavelength). - **`getFrequencyPoint()`** — The RF frequency (in MHz) at which the tag was read. Combined with phase data across multiple frequencies, this enables more accurate distance estimation. - **`getRssi()`** — Signal strength. Useful for coarse proximity estimation but less accurate than phase-based methods. - **`getTimestamp()`** — Enables time-series analysis of tag movements. - **`getAnt()`** — Antenna port, relevant for multi-antenna setups. --- ## 2. `startLocation()` — Built-in Relative Proximity (0–100) The SDK provides a **built-in location API** that continuously reports a relative proximity value for a specific target tag. This is the simplest way to get "relative position" — it does not require any external sensor. ### Interface: `IUHFLocationCallback` ```java public interface IUHFLocationCallback { /** * Obtain location data. * * @param value (0-100) The larger the value, the closer to the tag. * @param valid Flag whether value is valid. */ void getLocationValue(int value, boolean valid); } ``` ### Method Signature on `RFIDWithUHFUART` ```java public boolean startLocation( Context context, String label, // EPC or TID of target tag int bank, // Memory bank: IUHF.Bank_EPC, Bank_TID, etc. int ptr, // Pointer/offset within the memory bank IUHFLocationCallback callback // Callback receiving proximity updates ) public boolean stopLocation() ``` ### Usage Example ```java RFIDWithUHFUART reader = RFIDWithUHFUART.getInstance(); reader.init(context); // Start tracking proximity to a specific tag reader.startLocation(context, "E2003412AB01234500000001", IUHF.Bank_EPC, 0, (value, valid) -> { if (valid) { // value is 0-100 // 100 = very close to tag, 0 = far away / not detected updateProximityIndicator(value); } }); // ... when done: reader.stopLocation(); ``` ### What "value" means | Value Range | Interpretation | |-------------|----------------| | 80–100 | Very close — tag is within arm's reach | | 50–79 | Nearby — tag is in the general vicinity | | 20–49 | Moderate distance | | 1–19 | Far — weak signal | | 0 / invalid | Tag not detected | The exact mapping depends on tag type, environment, and reader power settings. Use it as a relative "hot/cold" indicator rather than an absolute distance measurement. --- ## 3. `startRadarLocation()` — Radar-Style Location with Azimuth Angle For more advanced positioning, the SDK provides a **radar location mode** that reports both signal strength and **azimuth angle** (bearing direction to the tag). This uses the device's built-in sensors (gyroscope/accelerometer) combined with RF readings. ### Entity: `RadarLocationEntity` ```java public class RadarLocationEntity { /** Get the tag identifier (EPC/TID value) */ String getTag(); /** Get the azimuth angle to the tag (degrees) */ int getAngle(); /** Get the signal strength value (proximity indicator) */ int getValue(); /** Get the memory bank type used (Bank_EPC, Bank_TID, etc.) */ int getUhfBank(); } ``` ### Interface: `IUHFRadarLocationCallback` ```java public interface IUHFRadarLocationCallback { /** * Receive positioning data for detected tags. * @param radarLocationEntityList List of tags with their location data. */ void getLocationValue(List radarLocationEntityList); /** * Receive the current device azimuth angle. * @param angle Device azimuth in degrees. */ void getAngleValue(int angle); } ``` ### Method Signature on `RFIDWithUHFUART` ```java public boolean startRadarLocation( Context context, String tag, // Target tag identifier int bank, // Memory bank int ptr, // Pointer/offset IUHFRadarLocationCallback callback // Callback receiving radar data ) public boolean stopRadarLocation() ``` ### Usage Example ```java RFIDWithUHFUART reader = RFIDWithUHFUART.getInstance(); reader.init(context); reader.startRadarLocation(context, "E2003412AB01234500000001", IUHF.Bank_EPC, 0, new IUHFRadarLocationCallback() { @Override public void getLocationValue(List entities) { for (RadarLocationEntity entity : entities) { String tagId = entity.getTag(); int angle = entity.getAngle(); // azimuth to tag (degrees) int signal = entity.getValue(); // signal strength int bank = entity.getUhfBank(); // which bank was matched updateRadarDisplay(tagId, angle, signal); } } @Override public void getAngleValue(int deviceAngle) { // Current device orientation (from gyro/compass) updateCompassDisplay(deviceAngle); } }); // ... when done: reader.stopRadarLocation(); ``` ### Supporting Entity: `TagLocationEntity` Wraps a `UHFTAGInfo` together with its `TagLocationInfo`: ```java public class TagLocationEntity { UHFTAGInfo getUhftagInfo(); // Full tag data TagLocationInfo getTagLocationInfo(); // Location-specific data } public class TagLocationInfo { int getSignalValue(); // Signal strength (proximity) boolean isValid(); // Whether the reading is valid } ``` --- ## 4. Custom Positioning Using Raw Phase + Frequency Data For maximum accuracy, you can implement your own positioning algorithm using the raw RF data from `UHFTAGInfo`: ### Phase-Based Ranging The RF phase angle changes linearly with distance (within one wavelength cycle). By combining phase readings across **multiple frequencies** (frequency hopping), you can resolve the distance ambiguity: ```java // During inventory, collect phase + frequency per read UHFTAGInfo tag = reader.inventorySingleTag(); int phase = tag.getPhase(); // RF phase angle float frequency = tag.getFrequencyPoint(); // Channel frequency (MHz) String rssi = tag.getRssi(); // Signal strength long timestamp = tag.getTimestamp(); // When the read occurred ``` ### Algorithm Sketch ``` distance ≈ (phase × c) / (4π × frequency) ``` Where: - `phase` is in radians (convert from the SDK's integer representation) - `frequency` is in Hz - `c` is the speed of light (3 × 10^8 m/s) Since a single phase measurement is ambiguous (repeats every half-wavelength ≈ 16 cm at 920 MHz), combine readings from multiple frequency hops to resolve the true distance. Academic references: - **ReLoc** (Hybrid RSSI-and-Phase-based Relative UHF-RFID Tag Localization) — uses COTS readers - **Tagoram** (Real-Time Tracking of Mobile RFID Tags to High Precision) — Microsoft Research --- ## Summary: Three Approaches | Approach | Data Returned | Complexity | Accuracy | |----------|---------------|-----------|----------| | **`startLocation()`** | Proximity 0–100 | Trivial | Coarse (hot/cold) | | **`startRadarLocation()`** | Proximity + azimuth angle | Low | Moderate (direction + distance) | | **Raw phase + frequency** | Phase, frequency, RSSI, timestamp | High (custom algorithm) | Best (sub-meter possible) | ### Recommendation - **Start with `startLocation()`** for a quick proof-of-concept. It gives you a working proximity indicator with zero algorithm development. - **Upgrade to `startRadarLocation()`** if you need directional guidance (e.g., "the tag is to your left"). - **Use raw phase/frequency data** only if you need sub-meter accuracy and are prepared to implement or integrate a positioning algorithm. --- ## SDK Version & Source - **SDK**: `API_Ver20251103` (latest as of April 2026) - **AAR**: `DeviceAPI_ver20251103_release.aar` - **Download**: https://www.chainway.net/Support/Info/34 → "SDKS & MORE" → Android Studio - **Key Package**: `com.rscja.deviceapi` - **Key Classes**: - `com.rscja.deviceapi.RFIDWithUHFUART` — main reader class for C5 - `com.rscja.deviceapi.entity.UHFTAGInfo` — tag data per read - `com.rscja.deviceapi.entity.TagLocationEntity` — tag + location wrapper - `com.rscja.deviceapi.entity.TagLocationInfo` — signal value + validity - `com.rscja.deviceapi.entity.RadarLocationEntity` — radar positioning data - `com.rscja.deviceapi.interfaces.IUHFLocationCallback` — simple proximity callback - `com.rscja.deviceapi.interfaces.IUHFRadarLocationCallback` — radar location callback - `com.rscja.deviceapi.interfaces.IHandheldRFID` — parent interface defining location methods