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,
UsbPath = new byte[512], SerialNumber = new byte[256]
},
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;
std::strncpy(readerDef.DeviceId.SerialNumber, "ABC123",
sizeof(readerDef.DeviceId.SerialNumber) - 1);
readerDef.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
auto handle = AbstractReader::CreateReaderInstance(readerDef, 3);
using System.Text;
var id = new DeviceId
{
VendorId = 0x0C27, ProductId = 0x3BFA,
UsbPath = new byte[512], SerialNumber = new byte[256]
};
Encoding.UTF8.GetBytes("ABC123").CopyTo(id.SerialNumber, 0);
var readerDef = new ReaderDefinition
{
DeviceId = id,
ProtocolType = ProtocolType.FeatureReport
};
using var app = new Reader(readerDef);
reader_def = ReaderDefinition(
DeviceId=DeviceId(
VendorId=0x0C27,
ProductId=0x3BFA,
SerialNumber=b"ABC123"
),
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)") - macOS: Hexadecimal USB location ID (e.g.,
"0x14100000"); decimal format is also accepted
- C++
- C#
- Python
ReaderDefinition readerDef{};
readerDef.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
// USB path -- VID/PID are not required in this mode
std::strncpy(readerDef.DeviceId.UsbPath, "1-7", // Linux bus-port path
sizeof(readerDef.DeviceId.UsbPath) - 1);
auto handle = AbstractReader::CreateReaderInstance(readerDef, 3);
using System.Text;
// VID/PID are not required when using USB path
var id = new DeviceId
{
UsbPath = new byte[512],
SerialNumber = new byte[256]
};
Encoding.UTF8.GetBytes("1-7").CopyTo(id.UsbPath, 0); // Linux bus-port path
var readerDef = new ReaderDefinition
{
DeviceId = id,
ProtocolType = ProtocolType.FeatureReport
};
using var app = new Reader(readerDef);
reader_def = ReaderDefinition(
DeviceId=DeviceId(
# VID/PID are not required when using USB path
UsbPath=b"1-7" # Linux bus-port path
),
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 Readers for how to discover connected readers programmatically or find topological paths on Linux, Windows, and macOS.
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
// std::strcpy(readerDef.SerialPortSettings.PortName, "/dev/cu.usbserial-1410"); // macOS
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
macOS USB Permissions
On macOS 12.0 (Monterey) and later, RIK accesses USB HID readers through IOKit and
HIDAPI. No root / sudo and no App Sandbox HID/USB entitlements are required for
CLI or non-sandboxed apps.
You do not need to run your application with sudo, and you do not need App Sandbox
HID/USB entitlements on CLI or non-sandboxed binaries. Reader discovery does not
require Input Monitoring. Opening a keyboard-class HID collection (typical for
current rf IDEAS readers) may require an Input Monitoring (kTCCServiceListenEvent)
grant on the responsible process — often the host app such as Terminal.app, not the
RIK binary itself. Headless or LaunchDaemon hosts can discover readers but still fail
to open them when no console TCC identity is available.
Keystroking while connected
Some rf IDEAS readers can operate in keystroking mode, where the reader sends card data as keyboard input to the focused application. RIK opens the HID device non-exclusively by design: a reader in keystroking mode continues to send keystrokes to the focused application while RIK is connected and reading.
This behavior is intentional. When designing your application:
- If keystroking must be suppressed during programmatic reads, disable it with
EnableKeystroking(false)(C++/C#) orenable_keystroking(False)(Python) before connecting, or configure the reader to disable keystroking at startup. See Enable/Disable Keystroking. - Ensure no sensitive input field (password box, PIN entry) is focused when a card is presented while RIK is active.
App Sandbox entitlements
com.apple.security.device.hid and com.apple.security.device.usb are App Sandbox
entitlements. They apply only to sandboxed .app bundles (Mac App Store
submissions or apps with the App Sandbox entitlement enabled). CLI binaries and
non-sandboxed applications do not use entitlements for HID access.
Declaring these entitlements in a CLI binary or non-sandboxed application has no effect and is misleading. Do not copy App Sandbox entitlements from sample projects into a RIK CLI or non-sandboxed integration.
Troubleshooting
If a reader is not detected on macOS:
- Verify the reader appears in System Information.app under USB. If it does not appear, the issue is hardware or cable, not permissions.
- If macOS Gatekeeper blocks
libReaderIntegrationKit.dylib, see Gatekeeper. - If the reader is enumerated in System Information.app but still fails to open:
- Confirm the process is not running inside an App Sandbox without the appropriate entitlement.
- For keyboard-class collections, grant Input Monitoring to the responsible app (for example Terminal.app when running from a terminal) in System Settings > Privacy & Security > Input Monitoring.