Before sending any custom messages to the reader, you must send the IMPINJ_ENABLE_EXTENSIONS message. Here is an example of how to do that.
public void enableImpinjExt()
{
BytesToEnd_HEX data = new BytesToEnd_HEX();
CUSTOM_MESSAGE msg = new CUSTOM_MESSAGE();
msg.setVendorIdentifier(new UnsignedInteger(25882));
msg.setMessageSubtype(new UnsignedByte(21));
data.add(new SignedByte(0));
data.add(new SignedByte(0));
data.add(new SignedByte(0));
data.add(new SignedByte(0));
msg.setData(data);
reader.send(msg);
}
The magic number 25882 is the vendor ID for Impinj. The message subtype for IMPINJ_ENABLE_EXTENSIONS is 21.
Once you enable the custom extensions, you can create and send the ROSpec. This sample code shows how add a custom parameter (Inventory Search Mode) to an ROSpec.
// Create a new inventory parameter
InventoryParameterSpec inventoryParam =
new InventoryParameterSpec();
// We're reading Gen2 tags.
inventoryParam.setProtocolID
(new AirProtocols(AirProtocols.EPCGlobalClass1Gen2));
inventoryParam.setInventoryParameterSpecID
(new UnsignedShort(1));
// Create a custom parameter (Inventory Search Mode)
Custom searchMode = new Custom();
BytesToEnd_HEX data = new BytesToEnd_HEX();
// Set the data to 0x0001 (Single target)
// Dual target = 0x0002
data.add(new SignedByte(0));
data.add(new SignedByte(1));
// 25882 is the vendor ID for Impinj
searchMode.setVendorIdentifier(new UnsignedInteger(25882));
// Parameter 23 = ImpinjInventorySearchType
searchMode.setParameterSubtype(new UnsignedInteger(23));
searchMode.setData(data);
// Set the session to Session 2
// Session is a standard LLRP setting
C1G2InventoryCommand invCmd = new C1G2InventoryCommand();
invCmd.setTagInventoryStateAware(new Bit(0));
C1G2SingulationControl c1g2SingCtrl = new C1G2SingulationControl();
TwoBitField session = new TwoBitField();
session.clear(0);
session.set(1);
c1g2SingCtrl.setSession(session);
// Tag population
c1g2SingCtrl.setTagPopulation(new UnsignedShort(32));
// Tag transit time
c1g2SingCtrl.setTagTransitTime(new UnsignedInteger(0));
invCmd.setC1G2SingulationControl(c1g2SingCtrl);
// Add our custom setting to the C1G2InventoryCommand
invCmd.addToCustomList(searchMode);
// Apply these settings to all four antennas
for (int i=1; i<=4; i++)
{
AntennaConfiguration antennaConfig = new AntennaConfiguration();
antennaConfig.setAntennaID(new UnsignedShort(i));
antennaConfig.addToAirProtocolInventoryCommandSettingsList(invCmd);
inventoryParam.addToAntennaConfigurationList(antennaConfig);
}
// Add the inventory parameters to the AISpec
aispec.addToInventoryParameterSpecList(inventoryParam);
// Add the AISpec to the ROSpec
roSpec.addToSpecParameterList(aispec);
Optionally, you can load the ROSpec from file using Util.loadXMLLLRPMessage rather than creating it programatically. This is the equivalent ROSpec XML for the code above.
<?xml version="1.0" encoding="UTF-8"?>
<llrp:ADD_ROSPEC xmlns:llrp="http://www.llrp.org/ltk/schema/core/encoding/xml/1.0"
Version="1" MessageID="0">
<llrp:ROSpec>
<llrp:ROSpecID>123</llrp:ROSpecID>
<llrp:Priority>0</llrp:Priority>
<llrp:CurrentState>Disabled</llrp:CurrentState>
<llrp:ROBoundarySpec>
<llrp:ROSpecStartTrigger>
<llrp:ROSpecStartTriggerType>Null</llrp:ROSpecStartTriggerType>
</llrp:ROSpecStartTrigger>
<llrp:ROSpecStopTrigger>
<llrp:ROSpecStopTriggerType>Null</llrp:ROSpecStopTriggerType>
<llrp:DurationTriggerValue>0</llrp:DurationTriggerValue>
</llrp:ROSpecStopTrigger>
</llrp:ROBoundarySpec>
<llrp:AISpec>
<llrp:AntennaIDs>0</llrp:AntennaIDs>
<llrp:AISpecStopTrigger>
<llrp:AISpecStopTriggerType>Null</llrp:AISpecStopTriggerType>
<llrp:DurationTrigger>0</llrp:DurationTrigger>
</llrp:AISpecStopTrigger>
<llrp:InventoryParameterSpec>
<llrp:InventoryParameterSpecID>1</llrp:InventoryParameterSpecID>
<llrp:ProtocolID>EPCGlobalClass1Gen2</llrp:ProtocolID>
<llrp:AntennaConfiguration>
<llrp:AntennaID>1</llrp:AntennaID>
<llrp:C1G2InventoryCommand>
<llrp:TagInventoryStateAware>0</llrp:TagInventoryStateAware>
<llrp:C1G2SingulationControl>
<llrp:Session>2</llrp:Session>
<llrp:TagPopulation>32</llrp:TagPopulation>
<llrp:TagTransitTime>0</llrp:TagTransitTime>
</llrp:C1G2SingulationControl>
<llrp:Custom>
<llrp:VendorIdentifier>25882</llrp:VendorIdentifier>
<llrp:ParameterSubtype>23</llrp:ParameterSubtype>
<llrp:Data>0001</llrp:Data>
</llrp:Custom>
</llrp:C1G2InventoryCommand>
</llrp:AntennaConfiguration>
<llrp:AntennaConfiguration>
<llrp:AntennaID>2</llrp:AntennaID>
<llrp:C1G2InventoryCommand>
<llrp:TagInventoryStateAware>0</llrp:TagInventoryStateAware>
<llrp:C1G2SingulationControl>
<llrp:Session>2</llrp:Session>
<llrp:TagPopulation>32</llrp:TagPopulation>
<llrp:TagTransitTime>0</llrp:TagTransitTime>
</llrp:C1G2SingulationControl>
<llrp:Custom>
<llrp:VendorIdentifier>25882</llrp:VendorIdentifier>
<llrp:ParameterSubtype>23</llrp:ParameterSubtype>
<llrp:Data>0001</llrp:Data>
</llrp:Custom>
</llrp:C1G2InventoryCommand>
</llrp:AntennaConfiguration>
<llrp:AntennaConfiguration>
<llrp:AntennaID>3</llrp:AntennaID>
<llrp:C1G2InventoryCommand>
<llrp:TagInventoryStateAware>0</llrp:TagInventoryStateAware>
<llrp:C1G2SingulationControl>
<llrp:Session>2</llrp:Session>
<llrp:TagPopulation>32</llrp:TagPopulation>
<llrp:TagTransitTime>0</llrp:TagTransitTime>
</llrp:C1G2SingulationControl>
<llrp:Custom>
<llrp:VendorIdentifier>25882</llrp:VendorIdentifier>
<llrp:ParameterSubtype>23</llrp:ParameterSubtype>
<llrp:Data>0001</llrp:Data>
</llrp:Custom>
</llrp:C1G2InventoryCommand>
</llrp:AntennaConfiguration>
<llrp:AntennaConfiguration>
<llrp:AntennaID>4</llrp:AntennaID>
<llrp:C1G2InventoryCommand>
<llrp:TagInventoryStateAware>0</llrp:TagInventoryStateAware>
<llrp:C1G2SingulationControl>
<llrp:Session>2</llrp:Session>
<llrp:TagPopulation>32</llrp:TagPopulation>
<llrp:TagTransitTime>0</llrp:TagTransitTime>
</llrp:C1G2SingulationControl>
<llrp:Custom>
<llrp:VendorIdentifier>25882</llrp:VendorIdentifier>
<llrp:ParameterSubtype>23</llrp:ParameterSubtype>
<llrp:Data>0001</llrp:Data>
</llrp:Custom>
</llrp:C1G2InventoryCommand>
</llrp:AntennaConfiguration>
</llrp:InventoryParameterSpec>
</llrp:AISpec>
<llrp:ROReportSpec>
<llrp:ROReportTrigger>Upon_N_Tags_Or_End_Of_ROSpec</llrp:ROReportTrigger>
<llrp:N>1</llrp:N>
<llrp:TagReportContentSelector>
<llrp:EnableROSpecID>0</llrp:EnableROSpecID>
<llrp:EnableSpecIndex>0</llrp:EnableSpecIndex>
<llrp:EnableInventoryParameterSpecID>0</llrp:EnableInventoryParameterSpecID>
<llrp:EnableAntennaID>0</llrp:EnableAntennaID>
<llrp:EnableChannelIndex>0</llrp:EnableChannelIndex>
<llrp:EnablePeakRSSI>0</llrp:EnablePeakRSSI>
<llrp:EnableFirstSeenTimestamp>0</llrp:EnableFirstSeenTimestamp>
<llrp:EnableLastSeenTimestamp>1</llrp:EnableLastSeenTimestamp>
<llrp:EnableTagSeenCount>0</llrp:EnableTagSeenCount>
<llrp:EnableAccessSpecID>0</llrp:EnableAccessSpecID>
</llrp:TagReportContentSelector>
</llrp:ROReportSpec>
</llrp:ROSpec>
</llrp:ADD_ROSPEC>
Once you're up and running, I recommend pulling the ROSpec to verify that your application has configured the reader correctly.