Skip to main content

Multi-Reader

Examples for managing multiple reader instances simultaneously. Each instance is independent and thread-safe.

Two Readers

#include <iostream>
#include "Reader/Reader.h"

int main() {
using namespace Rik;
using namespace RikCommon;

ReaderHandle handle1 = nullptr;
ReaderHandle handle2 = nullptr;

try {
// Reader 1
ReaderDefinition readerDef1;
readerDef1.DeviceId.VendorId = 0x0C27;
readerDef1.DeviceId.ProductId = 0x3BFA;
readerDef1.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;

handle1 = AbstractReader::CreateReaderInstance(readerDef1, 3);
auto* app1 = AbstractReader::GetInstance(handle1);
app1->Init();

// Reader 2
ReaderDefinition readerDef2;
readerDef2.DeviceId.VendorId = 0x0C27;
readerDef2.DeviceId.ProductId = 0x3BFB;
readerDef2.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;

handle2 = AbstractReader::CreateReaderInstance(readerDef2, 3);
auto* app2 = AbstractReader::GetInstance(handle2);
app2->Init();

// Use both
auto meta1 = app1->GetMetadataStruct();
auto meta2 = app2->GetMetadataStruct();
std::cout << "Reader 1: " << meta1.PartNumber << std::endl;
std::cout << "Reader 2: " << meta2.PartNumber << std::endl;

// Cleanup
app1->Close();
AbstractReader::DestroyInstance(handle1);
app2->Close();
AbstractReader::DestroyInstance(handle2);
return 0;

} catch (const ReaderException& e) {
std::cerr << "Error: " << e.Message << std::endl;
if (handle1) AbstractReader::DestroyInstance(handle1);
if (handle2) AbstractReader::DestroyInstance(handle2);
return 1;
}
}

Identical Readers (Same VID/PID)

When multiple readers share the same VID/PID, use serial numbers or USB paths to distinguish them. See Connection Strategies for full details on each approach.

By Serial Number

Add a serial number alongside VID/PID to filter to a specific device. On newer rf IDEAS readers, the USB serial number matches the reader's ESN.

ReaderDefinition readerDef1{};
readerDef1.DeviceId.VendorId = 0x0C27;
readerDef1.DeviceId.ProductId = 0x3BFA;
readerDef1.DeviceId.SerialNumber = L"ABC123";
readerDef1.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;

ReaderDefinition readerDef2{};
readerDef2.DeviceId.VendorId = 0x0C27;
readerDef2.DeviceId.ProductId = 0x3BFA;
readerDef2.DeviceId.SerialNumber = L"DEF456";
readerDef2.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
Finding serial numbers

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.

warning

On older rf IDEAS readers, the USB serial number may be empty or non-unique. If serial numbers are not reliable for your readers, use USB paths instead.

By USB Path

If serial numbers are not available, use UsbPath to target specific physical USB ports. When UsbPath is set, VID/PID and serial number are ignored -- the connection is made purely by port location.

ReaderDefinition readerDef1{};
readerDef1.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
std::wcsncpy(readerDef1.DeviceId.UsbPath, L"1-7",
sizeof(readerDef1.DeviceId.UsbPath) / sizeof(wchar_t) - 1);

ReaderDefinition readerDef2{};
readerDef2.ProtocolType = PROTOCOL_TYPE_FEATURE_REPORT;
std::wcsncpy(readerDef2.DeviceId.UsbPath, L"1-8",
sizeof(readerDef2.DeviceId.UsbPath) / sizeof(wchar_t) - 1);
note

USB paths identify physical ports, not devices. If you move a reader to a different port, its path changes.

See Discovering USB Paths for how to find topological paths on Linux and Windows.

Thread Safety

All RIK instances are internally thread-safe. You can access different reader instances from different threads without external synchronization. Accessing the same instance from multiple threads is also safe -- RIK handles locking internally.

#include <thread>

void readerWorker(ReaderHandle handle, int id) {
auto* app = AbstractReader::GetInstance(handle);
auto metadata = app->GetMetadataStruct();
std::cout << "Reader " << id << ": " << metadata.PartNumber << std::endl;
}

// After creating and initializing handle1 and handle2:
std::thread t1(readerWorker, handle1, 1);
std::thread t2(readerWorker, handle2, 2);
t1.join();
t2.join();