Supported Readers
| VID | PID | Description |
|---|---|---|
0x0C27 | 0x3BFA | Standard multi-technology reader |
0x0C27 | 0x3B4C | LEGIC enabled reader |
0x0C27 | 0x3B1E | Bluetooth Low Energy (BLE) reader |
| N/A | N/A | Serial Interface (RS-232) |
Connection Strategies
RIK provides three ways to identify which USB reader to connect to. The strategy is determined by which DeviceId fields you populate.
1. VID/PID Only
The simplest approach. RIK opens the first device matching the given Vendor ID and Product ID.
- C++
- C#
- Python
ReaderDefinition readerDef{};
readerDef.DeviceId.VendorId = 0x0C27;
readerDef.DeviceId.ProductId = 0x3BFA;
readerDef.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
auto handle = AbstractReader::CreateReaderInstance(readerDef, 3);
var readerDef = new ReaderDefinition
{
DeviceId = new DeviceId { VendorId = 0x0C27, ProductId = 0x3BFA },
ProtocolType = ProtocolType.FeatureReport
};
using var app = new Reader(readerDef);
reader_def = ReaderDefinition(
DeviceId=DeviceId(VendorId=0x0C27, ProductId=0x3BFA),
ProtocolType=ProtocolType.FEATURE_REPORT,
SerialPortSettings=SerialPortSettings()
)
with Reader(reader_def) as app:
app.init()
If multiple readers with the same VID/PID are connected, this opens whichever one the OS enumerates first. The result is non-deterministic. Use serial number or USB path to target a specific device.
2. VID/PID + Serial Number
Adding a serial number narrows the match to a specific device. The USB serial number is part of the USB Device Descriptor -- on newer rf IDEAS readers it matches the reader's ESN (Electronic Serial Number), but on older readers it may be empty or non-unique.
- C++
- C#
- Python
ReaderDefinition readerDef{};
readerDef.DeviceId.VendorId = 0x0C27;
readerDef.DeviceId.ProductId = 0x3BFA;
readerDef.DeviceId.SerialNumber = L"ABC123";
readerDef.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
auto handle = AbstractReader::CreateReaderInstance(readerDef, 3);
var readerDef = new ReaderDefinition
{
DeviceId = new DeviceId
{
VendorId = 0x0C27,
ProductId = 0x3BFA,
SerialNumber = Marshal.StringToHGlobalUni("ABC123")
},
ProtocolType = ProtocolType.FeatureReport
};
using var app = new Reader(readerDef);
import ctypes
reader_def = ReaderDefinition(
DeviceId=DeviceId(
VendorId=0x0C27,
ProductId=0x3BFA,
SerialNumber=ctypes.cast(ctypes.c_wchar_p("ABC123"), ctypes.c_void_p)
),
ProtocolType=ProtocolType.FEATURE_REPORT,
SerialPortSettings=SerialPortSettings()
)
with Reader(reader_def) as app:
app.init()
Connect one reader at a time and read its ESN from the metadata (GetMetadataStruct().ESN in C++, GetMetadata().ESN in C#, get_metadata()["ESN"] in Python). On newer readers, this ESN matches the USB serial number in the device descriptor.
VID/PID should be provided alongside the serial number. Both are passed to the underlying USB library as match criteria. Providing VID/PID narrows the search and avoids accidentally matching a non-reader device that happens to share a serial number.
3. USB Path
The USB path is a topological identifier for a physical USB port. When set, VID/PID and serial number are ignored entirely -- the connection is made purely by port location. This is the most deterministic strategy and is ideal for fixed installations with multiple identical readers.
Path formats:
- Linux:
"B-P"or"B-P.P.P"(e.g.,"1-7","1-7.2") where B = bus number, P = port number - Windows: Location path string (e.g.,
"PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(7)")
- C++
- C#
- Python
ReaderDefinition readerDef{};
readerDef.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
// USB path -- VID/PID are not required in this mode
std::wstring usbPath = L"1-7"; // Linux bus-port path
std::wcsncpy(readerDef.DeviceId.UsbPath, usbPath.c_str(),
sizeof(readerDef.DeviceId.UsbPath) / sizeof(wchar_t) - 1);
auto handle = AbstractReader::CreateReaderInstance(readerDef, 3);
var readerDef = new ReaderDefinition
{
DeviceId = new DeviceId
{
// VID/PID are not required when using USB path
UsbPath = Marshal.StringToHGlobalUni("1-7") // Linux bus-port path
},
ProtocolType = ProtocolType.FeatureReport
};
using var app = new Reader(readerDef);
import ctypes
reader_def = ReaderDefinition(
DeviceId=DeviceId(
# VID/PID are not required when using USB path
UsbPath=ctypes.cast(ctypes.c_wchar_p("1-7"), ctypes.c_void_p)
),
ProtocolType=ProtocolType.FEATURE_REPORT,
SerialPortSettings=SerialPortSettings()
)
with Reader(reader_def) as app:
app.init()
The USB path identifies a physical port, not a device. If you move a reader to a different port, its path changes. If you swap two readers between ports, each will take on the other's path.
See Discovering USB Paths for how to find topological paths on Linux and Windows.
Strategy Summary
| Strategy | DeviceId Fields | Behavior |
|---|---|---|
| VID/PID | VendorId + ProductId | Opens the first matching device. Simple, but non-deterministic with duplicates. |
| VID/PID + Serial | VendorId + ProductId + SerialNumber | Filters by USB serial number. Reliable when readers have unique serial numbers. |
| USB Path | UsbPath (VID/PID ignored) | Opens by physical port location. Most deterministic. Ideal for fixed multi-reader setups. |
Finding Your Reader's VID/PID
Windows: Device Manager > Universal Serial Bus devices > Properties > Details > Hardware Ids
Linux:
lsusb | grep -i rfideas
# Or for all USB devices:
lsusb
Reader Capabilities
rf IDEAS readers (Reader) support:
- Card data reading
- Beeper control (volume, beep count, duration)
- LED configuration
- Reader configuration (get/set)
- Extended configuration
- Keystroking enable/disable
- Transparent mode (capability check, enable/disable)
- Module state control (LF radio, HF radio, BLE)
- LUID get/set
- BLE configuration read/write
- HWG file import/export
- Smart card configuration
- Supported card type enumeration
Serial Readers
Serial readers use SerialBinary protocol with Reader. Configure the serial port:
ReaderDefinition readerDef{};
readerDef.ProtocolType = PROTOCOL_TYPE_SERIAL_BINARY;
std::strcpy(readerDef.SerialPortSettings.PortName, "COM3"); // Windows
// std::strcpy(readerDef.SerialPortSettings.PortName, "/dev/ttyACM0"); // Linux
readerDef.SerialPortSettings.BaudRate = SERIAL_PORT_BAUD_9600;
readerDef.SerialPortSettings.Parity = SERIAL_PORT_PARITY_NONE;
readerDef.SerialPortSettings.DataBits = SERIAL_PORT_DATA_BITS_8;
readerDef.SerialPortSettings.StopBits = SERIAL_PORT_STOP_BITS_ONE;
Linux USB Permissions
Create a udev rule for reader access. This rule covers all known rf IDEAS reader VID/PID combinations:
sudo tee /etc/udev/rules.d/99-rfideas.rules << 'EOF'
# rf IDEAS readers (VID 0x0C27)
SUBSYSTEM=="usb", ATTR{idVendor}=="0c27", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0c27", MODE="0660", GROUP="plugdev"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
The rf IDEAS rules above use a vendor-wide match (ATTR{idVendor}=="0c27") instead of per-PID rules. This covers all current and future rf IDEAS readers without needing rule updates.
Ensure your user is in the plugdev group:
sudo usermod -aG plugdev $USER
You must log out and back in (or reboot) for group membership changes to take effect.
For serial readers, add your user to dialout:
sudo usermod -aG dialout $USER