# 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<RadarLocationEntity> 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<RadarLocationEntity> 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