Using event handlers in the Octane SDK to address time consuming code

Symptom:

Several users have reported issues with the Octane SDK dropping or not reporting tags.

Possible Cause:

The lack of tag reporting is due to Octane SDK depending on the thread that calls the Event Handlers (E.g. OnTagsReported, OnTagOpComplete, etc..) in your code.  If the user defines code in the event handler that is time consuming or calls out to an external resource such as a database, the Octane SDK will not be able to process the tags being reported by the reader. 

Remedy:

For the lack of tag reporting, move the time consuming code to a separate thread.  

Let's go through an example that is loosely based on the examples provided by the .NET Octane SDK.  It will read tags from the field of view and process them one by one on a separate thread.

Note: The Octane SDK comes in both .NET (currently version 2.30.1 from Nuget) and Java (currently 1.30.1 from here).  The code featured in this article was written for .NET and may be convertible to Java. 

*** Note: This example was run against Octane SDK .NET version 2.30.1 against a reader with Octane Firmware 5.12.2.240.  We do not guarantee this will work against any other versions. Nor do we guarantee this will be supported in future versions of Octane SDK .NET.  ***

The example below uses the following Usings:

Using Clauses

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Impinj.OctaneSdk;

 

The Main code snippet shows a High level overview of what we plan to do.

Main

static void Main(string[] args)
{
    // Connect to the reader.
    // Pass in a reader hostname or IP address as a
    // command line argument when running the example
    if (args.Length != 1)
    {
        Console.WriteLine("Error: No hostname specified.  Pass in the reader hostname as a command line argument when running the Sdk Example.");
        return;
    }
    string hostname = args[0];
    ImpinjReader reader = new ImpinjReader();
 
    try
    {
        reader.Connect(hostname);
 
        // The following specifies which methods to call when tags are reported or operations are complete.
        // The TagsReported handler method will handle all new incoming tags
        reader.TagsReported += OnTagsReported;
 
        // Apply reader settings! (E.g. Reader Mode, Search Mode, Session and Antenna Config)
        setupReaderSettings(reader);
 
        reader.Start();
 
        // Perform the Complex Operations on a separate thread
        Task.Run(() => performComplexOperationsOnSeenTags(reader));
 
        Console.WriteLine("Please put a tag in front of the antenna and Press Enter to Exit!");
        Console.ReadKey();
    }
    catch (OctaneSdkException e)
    {
        // Handle Octane SDK errors.
        Console.WriteLine("Octane SDK exception: {0}", e.Message);
    }
    finally
    {
        // Exit the other thread by marking the tagsSeen Collection as Complete
        reader.TagsReported -= OnTagsReported;
        tagsSeen.CompleteAdding();
 
        // Close the connection with the reader.
        try
        {
            reader.Stop();
            reader.Disconnect();
        }
        catch (OctaneSdkException) { }
    }
}

 The program initializes the system by connecting to your reader/gateway, registering the Event Handlers, and applying the settings to the reader. Should the program throw an unexpected exception or be changed to exit, the finalize method will make sure to stop and disconnect from the reader. 

The reader gets setup to use Dual Target and Auto Set Dense Reader with antenna 1 at 20 dBM and -70 Receive Sensitivity:

Setup Reader Settings

static void setupReaderSettings(ImpinjReader reader)
{
    // Apply initial settings to reader
    Settings settings = new Settings();
    settings = reader.QueryDefaultSettings();
    settings.Report.IncludeAntennaPortNumber = true;
 
    // The reader can be set into various modes in which reader
    // dynamics are optimized for specific regions and environments.
    // The following mode, AutoSetDenseReader, monitors RF noise and interference and then automatically
    // and continuously optimizes the reader’s configuration
    settings.ReaderMode = ReaderMode.AutoSetDenseReader;
    settings.SearchMode = SearchMode.SingleTarget;
    settings.Session = 1;
 
    // Enable antenna #1. Disable all others. You may want to use more antennas, for my test case I
    // only was using one.
    settings.Antennas.DisableAll();
    settings.Antennas.GetAntenna(1).IsEnabled = true;
 
    // Set the Transmit Power and
    // Receive Sensitivity on the antennas.
    settings.Antennas.GetAntenna(1).TxPowerInDbm = 20;
    settings.Antennas.GetAntenna(1).RxSensitivityInDbm = -70;
    reader.ApplySettings(settings);
}

To perform the operations in this program successfully, there is a Blocking Collection Data Structure that will communicate which tags were read and help with communicating among multiple threads.

The OnTagsReported Event Handler is very simple. It just gets tag reports, trims each EPC value, and adds them to the tagsSeen Collection:

Tag Report Event Handler

// Keep Track of the Tags Seen in the Field of View of the Antenna.
static BlockingCollection tagsSeen = new BlockingCollection(3000);
 
static void OnTagsReported(ImpinjReader reader, TagReport report)
{
    // This event handler is called asynchronously when tag reports are available.
    // Loop through each tag in the report
    foreach (Tag tag in report)
    {
        // The Tag report contains an EPC with Spaces so we need to remove those spaces.
        string trimmedEPC = tag.Epc.ToString().Replace(" ", string.Empty);
        Console.WriteLine("Tag EPC Read: {0}", trimmedEPC);
 
        tagsSeen.Add(trimmedEPC);
    }
}

The Complex Operations are performed in a separate thread in function performComplexOperationsOnSeenTags().  While the tagsSeen collection isn't completed, one EPC will be removed from the collection at a time.   Each tag will be operated on.

Complex Operations

static void performComplexOperationsOnSeenTags(ImpinjReader reader)
{
    // Get one Tag from the Collection
    // Blocks if tagsSeen.Count == 0
    foreach (var trimmedEPC in tagsSeen.GetConsumingEnumerable())
    {
        if (!string.IsNullOrEmpty (trimmedEPC))
        {
            Console.WriteLine("Performing operations on EPC: {0}", trimmedEPC);
 
            // Perform Complex Operations on the tags that were seen.
        }
    }
    Console.WriteLine("Exiting Complex Thread!");
}

 

You can now update the code in the performComplexOperationsOnSeenTags method to perform time consuming operations. 

-----

Copyright ©2020 Impinj, Inc. All rights reserved.

You may use and modify this code under the terms of the Impinj Software Tools License & Disclaimer.

Visit this link for full license details, or contact Impinj, Inc. for a copy of the Impinj Software Tools License & Disclaimer.

Was this article helpful?
2 out of 2 found this helpful

Comments

0 comments

Article is closed for comments.