Friday, June 11, 2010

Get Low-Level Reader Data with LLRP

Impinj makes some low-level reader data available on Speedway Revolution via LLRP. RF Phase Angle and Peak RSSI are two fields that can be useful when trying to eliminate stray reads. In this post, I'll cover how to setup an ROSpec so that this data is returned in tag reports.

First, since these fields are Impinj custom extensions to LLRP, you'll have to enable them.
static void Enable_Impinj_Extensions()
{
MSG_ERROR_MESSAGE msg_err;
MSG_IMPINJ_ENABLE_EXTENSIONS imp_msg = new MSG_IMPINJ_ENABLE_EXTENSIONS();
MSG_CUSTOM_MESSAGE cust_rsp = 
reader.CUSTOM_MESSAGE(imp_msg, out msg_err, 2000);
MSG_IMPINJ_ENABLE_EXTENSIONS_RESPONSE rsp = 
cust_rsp as MSG_IMPINJ_ENABLE_EXTENSIONS_RESPONSE;

if (rsp != null)
{
// Success
Console.WriteLine(rsp.ToString());
}
else if (msg_err != null)
{
// Error
Console.WriteLine(msg_err.ToString());
}
else
{
// Timeout
Console.WriteLine("Timeout Error.");
}
}

Next, modify your ROReportSpec (in the ROSpec) so that these fields are included in tag reports.
// Create a new ROReportSpec
msg.ROSpec.ROReportSpec = new PARAM_ROReportSpec();
// Send a report for every tag
msg.ROSpec.ROReportSpec.ROReportTrigger = 
ENUM_ROReportTriggerType.Upon_N_Tags_Or_End_Of_ROSpec;
msg.ROSpec.ROReportSpec.N = 1;
msg.ROSpec.ROReportSpec.TagReportContentSelector = 
new PARAM_TagReportContentSelector();

// Add RF Phase Angle and Peak RSSI fields to the report
PARAM_ImpinjTagReportContentSelector 
contentSelector = new PARAM_ImpinjTagReportContentSelector();
contentSelector.ImpinjEnableRFPhaseAngle = 
new PARAM_ImpinjEnableRFPhaseAngle();
contentSelector.ImpinjEnableRFPhaseAngle.RFPhaseAngleMode =
ENUM_ImpinjRFPhaseAngleMode.Enabled;
contentSelector.ImpinjEnablePeakRSSI =
new PARAM_ImpinjEnablePeakRSSI();
contentSelector.ImpinjEnablePeakRSSI.PeakRSSIMode = 
ENUM_ImpinjPeakRSSIMode.Enabled;
// These are custom fields, so they get added this way
msg.ROSpec.ROReportSpec.Custom.Add(contentSelector);

Finally, here's how to parse the EPC, RF Phase Angle and Peak RSSI from the tag report.
static void OnReportEvent(MSG_RO_ACCESS_REPORT msg)
{
int phaseAngle = 0;
int peakRSSI = 0;

// Loop through all the tags in the report 
for (int i = 0; i < msg.TagReportData.Length; i++)
{
if (msg.TagReportData[i].EPCParameter.Count > 0)
{
string epc;
// Two possible types of EPC: 96-bit and 128-bit
if (msg.TagReportData[i].EPCParameter[0].
GetType() == typeof(PARAM_EPC_96))
{
epc = ((PARAM_EPC_96)
(msg.TagReportData[i].EPCParameter[0])).
EPC.ToHexString();
}
else
{
epc = ((PARAM_EPCData)
(msg.TagReportData[i].EPCParameter[0])).
EPC.ToHexString();
}

// Loop through all the custom fields
for (int j = 0; j < msg.TagReportData[i].Custom.Count; j++)
{
// Get RF Phase Angle and PeakRSSI
Object param = msg.TagReportData[i].Custom[j];
if (param is PARAM_ImpinjRFPhaseAngle)
phaseAngle = ((PARAM_ImpinjRFPhaseAngle)param).PhaseAngle;
else if (param is PARAM_ImpinjPeakRSSI)
peakRSSI = ((PARAM_ImpinjPeakRSSI)param).RSSI;
}
Console.WriteLine("epc, rf phase angle, peak rssi : " 
+ epc + ", " + phaseAngle + ", " + peakRSSI);
}
}
}