Example Sensor Tag Reading Application
This article walks you through the example code that has been included in the Sensor Tag SDK that you can download from the SensThys.com website. This article does not describe a handful of helper functions, such as DecodeCommandLine() and Snooze(), that have been defined to make this code more readable. You should find these reasonbaly self-explanatory.
The following are prerequisites for running this example program:
- You must have a SensThys Extreme, Enterprise, or Core reader powered and communicating on your local network
- You should verify that you can communicate with that reader, preferably by accessing it through the ProSens Windows application
- You must know the IP address of this reader
- You should have appropriate sensor tags sitting on or near the reader's antenna (preferrably Magnus3 tags)
This example program was developed using Microsoft's Visual Studio. To compile and run this application, you will need to do the following:
- Create a new Visual Studio console application project
- Import senstags_example.cs from the SDK example code /src subdirectory into this project; note that this is the only source code file required for this project
- Set up references to the libraries RFIDEngineeringReader.dll, RFID.dll, and SensorTag.dll that you can find in the SDK /lib folder
- Build this application
- Run from the command line or, if you are going to run directly from Visual Studio, set up the startup parameters to specify the antenna and IP address of your reader
The following code shows the Main program for a simple command line Windows console application. The reader's IP address and the antenna number for the reader to be used are provided through command line arguments. When you run this, you should see some overview information, then a data stream of timestamped lines starting with TEMP: and SCDE: showing the temperature values and sensor code values associated with specific EPCs:
Reader name: SensArray Enterprise
Reading from antenna #0
Pass 1. Reading Sensor data (sensor codes and temperature)
SCDE: 2022-04-11 12:40:29.45, E2-82-40-3D-00-02-08-DB-04-76-2A-31, 287
SCDE: 2022-04-11 12:40:29.48, E2-82-40-3D-00-02-08-DB-04-76-2A-31, 287
TEMP: 2022-04-11 12:40:29.66, E2-82-40-3D-00-02-08-DB-04-76-2A-3D, 28.7
TEMP: 2022-04-11 12:40:29.66, E2-82-40-3D-00-02-08-DB-04-76-2A-31, 28.3
...
static void Main(string[] args)
{
First, decode the command line parameters to determine which antenna to read from and the IP address of the reader. Then use that information to create an instance of the main class to be used for collecting sensor data.
if (!DecodeCommandLine(args))
return;
// The following parameters represent a reasonably optimal set for reading both
// sensor codes and temperatures quickly and reliably
sensorDataReader = new SensorDataReader(_ipAddress, TagModel.Magnus3,
dMinScanPower, dMaxScanPower,
new int[1] { iAntennaId }, 1000, 5, 25, 28);
The following lines show an example of how you would interact directly with the reader to access settings. Note that the sensor tag reading API controls most of the RFID settings, so any changes you make to those settings are likely to be overridden. Also, a precautionary note is needed here: Your application should never communicate with the reader while the sensor tag reading process is active. This will corrupt the communications channel and will result in errors being thrown and likely no valid data will be read when that happens.
reader = sensorDataReader.Reader;
String readerName = "";
reader.GetReaderName(out readerName);
Console.WriteLine($"Reader name: {readerName}");
Console.WriteLine($"Reading from antenna #{iAntennaId}");
Start this tag read loop. This will loop continuously until the program is stopped, either by closing the console window or by typing ctrl-C in that window.
int iIterationCount = 0;
while (true)
{
iIterationCount++;
Start reading. Note that both the temperature reading callback as well as the sensor reading callback have been specified. Consequently, both will be reported. Note that in this example program, the SensorDataReader was set up to read Magnus3 tags, so if you have Magnus3 tags on your reader, you should see values reported for both sensor values.
Console.WriteLine($"Pass {iIterationCount}. " +
$"Reading Sensor data (sensor codes and temperature) ");
sensorDataReader.start(OnTemperatureRead, OnSensorDataRead);
// If only want to read temperature data, the sensor code callback can
// be set to null. Similarly for the temperature callback if only the
// sensor code data is of interest. At least one needs to be set, however.
//Console.WriteLine($"Pass {iIterationCount}. Reading Sensor data (temperature) ");
//sensorDataReader.start(OnTemperatureRead, null);
//Console.WriteLine($"Pass {iIterationCount}. Reading Sensor data (sensor codes) ");
//sensorDataReader.start(null, OnSensorDataRead);
// Pause the current thread for the desired scan time. The data reads for
// both temperature and sensor code are a bit noisy. Consequently, we
// recommend that you collect and average the data over an interval that
// is sufficiently long to reduce the noise level to something that works
// for your environment and application. You will need to experiment with
// this to determine what works best.
This Snooze interval defines the basic read period.
Snooze(iTempScanInterval * 1000);
Stop the tag read operation now that the desired time interval is complete.
sensorDataReader.stop();
We need to wait for the tag read operation to complete. It can take a bit of time before the read is complete and all tags have been delivered. The ReadComplete flag is set once the read process has completed. However, in case of a network glitch or other communication problem, we limit this time to 1500 ms so we don't loop forever.
for (idx = 0; idx < 50 && !sensorDataReader.ReadComplete; idx++)
Snooze(50);
Console.WriteLine();
If the read process fails to complete due to communication issues or other problems, the following code closes the connection created by the underlying RFIDEngineeringReader, recreates the underlying reader, then waits for the underlying TCP socket to fully close so that the next reader operation can connect on a clear communication channel.
if (!sensorDataReader.ReadComplete)
{
Console.WriteLine("Sensor data read process timed out. " +
"Attempting to continue processing.");
reader.Shutdown();
reader = new RFIDEngineeringReader(_ipAddress, 5000);
sensorDataReader.Reader = reader;
// Sleep for 5 seconds to let old connection to shutdown and clean up
// before trying to connect again.
Snooze(5000);
}
} // End of while loop
} // End of Main()
The following two methods define the callbacks that are passed into the start() method so that the Sensor Tag API can send temperature and sensor code data back to your application for processing. Note that there is a bit of defensive coding in both callbacks to filter out incorrectly read data. You may run into read environments where a temperature or sensor code value is misread. This usually takes the form of the value being returned as zero. The sensor code API provides a reasonable level of filtering for these cases, but if you suspect that you are getting odd reads, you might do range checks.
Data management for both sensor tag reads and temperature reads include:
- Filtering as discussed above
- Averaging to reduce statistical measurement noise
- Display on a graphical user interface application
- Save to file or database
Refer to the TemperatureReading and SensorCodeReading classes for the data fields that are available for your application to process.
private static void OnTemperatureRead(TemperatureReading temperatureArg,
RFIDEngineeringReader reader)
{
double dTemperature = temperatureArg.Temperature;
// Filter out bogus readings
if (dTemperature < 1.0 || dTemperature > 100.0)
return;
// Manage data here. Can consider adding to database, performing running averages, etc.
Console.WriteLine($"TEMP: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ff")}, " +
$"{temperatureArg.EPC}, {temperatureArg.Temperature:F1}");
}
private static void OnSensorDataRead(SensorCodeReading scdeArg, RFIDEngineeringReader reader)
{
// Filter out bad sensor code reads
if (scdeArg.SensorCodeValue <= 0.0)
return;
// Manage data here. Can consider adding to database, performing running averages, etc.
Console.WriteLine($"SCDE: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ff")}, " +
$"{scdeArg.EPC}, {scdeArg.SensorCodeValue}");
}
Note that any processing, such as filtering and averaging, that you do to reduce the noise in your data should be advised by laboratory and field experiments you do to collect information specific to your application. Different environments and different requirments for data throughput can require different techniques to achieve the results you need. SensThys can provide advice on how to optimize your sensor tag reading process, but only after you have acquired data relevant to your environment for us to consider.