Skip to main content

Developing a device adapter and agent for the WebSphere RFID solution, Part 3: Building the device component

Allen Smith (allens@us.ibm.com ), Senior Software Engineer, IBM
Allen Smith photo
Allen Smith is a Senior Software Engineer with the Pervasive Computing Group in Research Triangle Park, North Carolina. He works with business partners to design solutions that use IBM's pervasive middleware. You can contact Allen at allens@us.ibm.com.
Karl Freburger (karlf@us.ibm.com), IT Architect, IBM
Karl Freburg photo
Karl Freburger is an IT Architect with IBM Global Business Services. He works with IBM's Software Group to enable business partners to design solutions that use IBM's RFID components.

Summary:  In Part 3 of this series, we'll take a look at the device component of the adapter, and create a new device and model the commands necessary to read RFID tags using a Sirit™ INfinity 510 RFID reader.

View more content in this series

Date:  07 Feb 2007
Level:  Intermediate
Activity:  234 views

Introduction

This article continues our series on how to build adapters and agents to integrate RFID readers into the IBM® Websphere® RFID solution. Part 1 described the overall solution and the WebSphere RFID Device Infrastructure. Part 2 showed you how to implement the transport layer. In this article, you'll learn how to implement the device layer. Once again, we'll use the Sirit INfinity 510 reader as an example.


Devices

If you'll recall from Part 1, we use the Device Kit component of WebSphere RFID Device Infrastructure to implement an adapter for a reader. Device Kit consists of several layers, as shown in Figure 1. In Part 2 we built a transport. In this article, we'll continue implementing the adapter by constructing a device.


Figure 1. Device Kit adapter
Device Kit adapter

A device provides a container for a set of objects called controls that model a hardware device's commands and messages. There are three types of controls: commands, signals and measurements. Commands model a hardware device's commands. Signals are used to model the messages received from the hardware device. Messages are typically received as the result of executing commands, but may also be asynchronous. Commands and signals together model the messages that can be sent to and received from a device. Measurements are used to model a property or attribute of the hardware device.

Devices are concerned only with modeling the controls of a hardware device. All communication with the hardware device is handled by the underlying transport.

Devices are implemented in Java™ code generated by the Device Kit tools. This code is generated from the device's Control Markup Language (CML) file. Every device has a CML file, which contains definitions that describe the device and the controls that model the hardware device's commands and messages. Agents in the WebSphere RFID solution use the generated Java code to send commands to and receive responses from the hardware device. For example, an agent would use a device's controls to instruct the associated RFID reader to start and stop reading and to receive read reports for singulated RFID tags.

Device CML

When building a device, all of the development work is done in CML. You don't have to develop any Java code. All of the Java code is generated by the Device Kit tools from the CML.

The Device Kit Device Creation wizard creates the initial CML file and necessary device projects. The generated CML file includes the CML device definition and, if specified at creation time, a definition for the transport. Listing 1 shows the generated CML file for a newly created device called SimpleDevice.


Listing 1. Generated CML file

<?xml version="1.0"?>
<!--Licensed Materials - Property of My Company-->
<!--(C) Copyright My Company Corp. 2006 All Rights Reserved-->
<!--US Government Users Restricted Rights - Use, duplication or disclosure-->
<!--restricted by GSA ADP Schedule Contract with My Company Corp.-->
<cml packagebase="com.mycompany" format="hex">
  <version>3.3.0</version>
  <vendor>My Company</vendor>
  <device id="SimpleDevice"
       bundle="SimpleDevice"
       implementation="SimpleDevice">
    <description>Simple Device</description>
    <transportservice service=
      "com.mycompany.simple.transport.service.SimpleTransportService"
       implementation="com.mycompany.simple.transport.SimpleTransport"/>
    <bundle/>
  </device>
</cml>

The <device> element defines a device. Commonly used <device> element attributes are:

  • id - specifies the unique identifier for the <device> element.
  • bundle - specifies the Open Services Gateway Initiative (OSGi) bundle name. This value is used to set the value of the Bundle-Name header in the bundle Manifest file.
  • implementation - specifies the name of the generated device implementation class.

The <device> element can include other elements. Commonly included elements are:

  • <description> - specifies a description of the device.
  • <command> - specifies a command definition.
  • <signal> - specifies a signal definition.
  • <measurement> - specifies a measurement definition.
  • <transportservice> - specifies the transport service used by the device.

For a complete list of the CML elements and attributes that can be used in a device definition, refer to the WebSphere Studio Device Developer Device Kit help.

Device classes

Every device has a core class that contains the device's controls, a message class that contains the messages used by the controls, and a service interface that contains a set of keys for accessing the controls.

DeviceService

Device objects implement the com.ibm.esc.device.service.DeviceService interface. Each control (command, measurement, and signal) defined in the device CML file is accessible by a key, defined in the service interface class (see below). The DeviceService interface defines the following methods for accessing a device's controls:

  • getCommand(String key) - returns the CommandService object identified by the key.
  • getSignal(String key) - returns the SignalService object identified by the key.
  • getMeasurement(String key) - returns the MeasurementService object identified by the key.

The DeviceService interface defines two additional methods that allow objects implementing the com.ibm.esc.device.service.DeviceListener interface to add and remove themselves as device listeners. The methods for adding and removing a device listener are: addDeviceListener(DeviceListener)and removeDeviceListener(DeviceListener). Device listeners are notified whenever one of the following device events occur:

  • State change. A DeviceService object can be in one of the following states: DEAD, CREATED, ALIVE, CONNECTED, STARTED. A DeviceService object must be in the STARTED state before it can be used to execute commands on the hardware device.
  • When a control is added to or removed from a DeviceService object or when an existing control is modified.

Message class

The message class contains field definitions for the messages, parameters and filters defined in the device CML file along with getter methods for the fields. For example, suppose the device CML file contains a definition that models a hardware device command. The command definition would include a message definition that specifies the message (string, bytes, and so on) that would be sent to the hardware device to execute the command. The message might also include a parameter definition indicating the command requires a parameter. In this case, the message class would include field definitions and getter methods for both the message and parameter.

See Part 1 for a discussion of messages.

Service interface

The service interface extends the DeviceService interface and contains a set of static field definitions. There is one field definition for each control defined in the CML file. Each field is of type String. The value of the control's CML id attribute is used as the field name and value. The control ID serves as the key for getting and putting controls in a DeviceService object.

DeviceListener

Objects that add themselves as device listeners must implement the DeviceListener interface. This interface defines the methods that are called when a device event occurs. The methods defined by the DeviceListener interface are:

  • controlChanged(DeviceService device, Object timestamp, ControlService control, int code) - The control parameter contains the control that was changed. The code parameter specifies whether the control was added, removed, or modified.
  • deviceChanged(DeviceService source, Object timestamp, int newState, int oldState) - The newState parameter contains the new state of the device (DEAD, CREATED, and so on). The oldState parameter contains the old state of the device.

Connecting the pieces

Let's look at a simple example to illustrate how the various device pieces fit together. In this example, we'll add a command definition to the SimpleDevice.cml file shown earlier. The command definition will model the Sirit INfinity 510 version.sw command. To execute this command, we need to send the string version.sw\r\n to the hardware device. The CML required to model this command is shown in Listing 2.


Listing 2. CML to model the version.sw command

<command id="VersionSwGetRequest">
    <message id="VersionSwGetRequestMessage">
        <ascii>version.sw\r\n</ascii>
    </message>
</command>

After adding the above command definition to the SimpleDevice.cml file and re-generating the device code, the field definition is added to the SimpleDevice class:

private final MessageCommand VersionSwGetRequest =
      new MessageCommand(
            SimpleDeviceService.VersionSwGetRequest,
            SimpleDeviceMessages.getVersionSwGetRequestMessage());

The MessageCommand(String key, MessageService message) constructor requires two parameters. The first one is the command's key and the second is the command's message. The key is obtained from the static field SimpleDeviceService.VersionSwGetRequest. This field is initialized with the string "VersionSwGetRequest". The field's value comes from the id attribute specified on the <command> CML element. The message is obtained from the SimpleDeviceMessage class. This class contains a field definition initialized with an object implementing the MessageService interface and a getter method for the object. The message is an AsciiMessage object whose value is a byte array constructed from the value of the <ascii> CML element specified in the command message definition:

private static final MessageService VersionSwGetRequestMessage =
      new AsciiMessage(
      new byte[] {'v','e','r','s','i','o','n','.','s','w','\r','\n' });

The application code required to obtain the VersionSwGetRequest command is shown in Listing 3.


Listing 3. Application code to obtain a control

// define the variable to hold the controls
CommandService versionSwGetRequestCommand;

// create the device
DeviceService device = new SampleDevice();

// get the control
versionSwGetRequestCommand =
    device.getCommand(SimpleDeviceService.VersionSwGetRequest);

As you can see, the code to get a control is very simple. All you need is the DeviceService object and the control's key.


Commands

A command represents a request that can be sent to a hardware device to perform a specific operation or function. Commands are defined in CML. The Device Kit tools generate the Java code implementing the command from the CML definitions.

Each command definition includes a message definition that specifies the bytes that get sent to the hardware device to execute the command. The message definition must include all required parameters, command terminators, and so on. The format and content of the message is determined by the hardware device specification. For example, the hardware specification specifies whether the protocol is ASCII- or binary-based, any character sequence used to terminate commands and parameter separators. While the format of a message differs from hardware device to hardware device, the approach used to model them in CML is consistent.

Command CML

A <command> element defines a command. The id attribute specifies the unique identifier for the <command> element.

The <command> element can include other elements. Commonly included elements are:

  • <specreference> - specifies a reference to the hardware specification documentation.
  • <description> - specifies a description of the command.
  • <message> - specifies the message (string, bytes, and so on) sent to the hardware device to execute the command.

For a complete list of the CML elements and attributes that can be used in a command definition, refer to the WebSphere Studio Device Developer Device Kit help.

CommandService

Command control objects are instances of classes that implement the com.ibm.esc.command.service.CommandService interface. This interface defines methods for executing a command. It also defines methods that allow objects implementing the com.ibm.esc.command.service.CommandListener interface to add and remove themselves as command listeners. The methods defined by the CommandService interface are:

  • addCommandListener(CommandListener) - adds a listener to receive command listener notifications.
  • removeCommandListener(CommandListener) - removes the listener.
  • execute() - executes the command.
  • execute(Object) - executes the command with a parameter.

CommandListener

Objects that add themselves as command listeners must implement the CommandListener interface. This interface defines a single method that is called when the command is executed. It's important to note that the method is called when the command is executed, not when the response from executing the command is received. The method defined by the CommandListener interface is:

commandExecuted(CommandService source, Object timestamp, Object data)

Command example

Let's look at an example to see how commands work. In this example, we'll add a new command definition that requires a parameter to the SimpleDevice.cml file. We'll add a command definition that models the Sirit INfinity 510 setup.operating_mode command. This command sets the operational mode of the reader to one of the following: autonomous, polled, or standby. The format of the command is: setup.operating_mode = mode\r\n. The value mode is the command parameter and \r\n is the command terminator. The CML required to model this command is shown in Listing 4.


Listing 4. CML to model a command

<command id="SetupOperatingModeSetRequest">
  <message id="SetupOperatingModeSetRequestMessage">
    <ascii>setup.operating_mode = \r\n</ascii>
    <parameter type="string">
      <insert/>
      <index>23</index>
    </parameter>
  </message>
</command>

The command message is defined as a template message (see Part 1 for a discussion of template and concrete messages), allowing a parameter to be specified when the command is executed. By specifying a template message, we can use the same command to set the operational mode of the reader to any one of the supported modes.

After adding the command definition to the SimpleDevice.cml file and re-generating the device code, the field definition shown in Listing 5 is added to the SimpleDevice class. A new static field called SetupOperatingModeSetRequest is also added to the SimpleDeviceService interface. This field contains the control ID.


Listing 5. Code generated from a CML command definition
private final DataCommand SetupOperatingModeSetRequest =
      new DataCommand(
      SimpleDeviceService.SetupOperatingModeSetRequest,
      SimpleDeviceMessages.getSetupOperatingModeSetRequestMessage());

The application code required to execute the SetupOperatingModeSetRequest command and set the reader's operational mode to autonomous is shown in Listing 6.


Listing 6. Application code to execute a command
// define the variable to hold the control
CommandService setupOperatingModeSetRequestCommand;

// get the control
setupOperatingModeSetRequestCommand  =
    device.getCommand(SimpleDeviceService.SetupOperatingModeSetRequest);

// execute the command
setupOperatingModeSetRequestCommand.execute("autonomous");


Signals

A signal is an asynchronous notification that data has been received from a hardware device. This data typically results from executing a command, but may also be an event notification. Signals are defined using CML. The Device Kit tools generate the Java code to implement the signal from the CML definitions.

Each signal definition includes a message definition that specifies the bytes sent from the hardware device. The message definition must include all required parameters, filter definitions, response terminators, and so on. The format and content of the message is determined by the hardware device specification. For example, the hardware specification specifies whether the protocol is ASCII- or binary-based, any character sequence used to terminate responses, and parameter separators.

Signal CML

A <signal> element defines a signal. The id attribute specifies the unique identifier for the <signal> element.

The <signal> element can include other elements. Commonly included elements are:

  • <specreference> - specifies a reference to the hardware specification documentation.
  • <description> - specifies a description of the signal.
  • <message> - specifies the message (string, bytes, and so on) sent from the hardware device.

For a complete list of the CML elements and attributes that can be used in a signal definition, refer to the WebSphere Studio Device Developer Device Kit help.

SignalService

Signal control objects are instances of classes that implement the com.ibm.esc.signal.service.SignalService interface. This interface defines two methods. These methods allow objects implementing the com.ibm.esc.signal.service.SignalListener interface to add and remove themselves as signal listeners. The methods defined by the SignalService interface are:

  • addSignalListener(SignalListener)- adds a listener to receive signal listener notifications.
  • removeSignalListener(SignalListener)- removes the listener.

SignalListener

Objects that add themselves as signal listeners must implement the SignalListener interface. This interface defines a single method that is called when a message is received from the hardware that matches the message defined in the signal. The method defined by the SignalListener interface is:

signalOccurred(SignalService source, Object timestamp, Object data)

The source parameter identifies the signal the notification is for and the data parameter contains any parameters contained in the messages sent by the hardware device. If for example, you modeled a response for a command that gets a hardware device property value, the data parameter would include the property value returned by the hardware device.

Signal example

Let's look at an example to see how signals work. In this example, we'll add a new signal definition to the SimpleDevice.cml file that models the response to the Sirit INfinity 510 version.sw command. The response from the reader to this command is ok 0.2.171\r\n\r\n. ok is the command response , 0.2.171 is the software version and \r\n\r\n is the response terminator. The CML required to model this signal is shown in Listing 7.


Listing 7. CML to model a signal

<signal id="VersionSwReport">
    <message id="VersionSwReportMessage">
        <ascii>ok \r\n\r\n</ascii>
        <parameter type="string">
            <insert/>
            <index>3</index>
        </parameter>
        <filter>
            <bytes format="hex">ff,ff,ff</bytes>
        </filter>
        <sentmessage idref="VersionSwGetRequestMessage"/>
    </message>
</signal>

The message is defined as a template message. The <parameter> element ensures the software version is extracted from the incoming message and made available to the signal listeners. The <filter> element ensures the signal is triggered and the listeners notified any time a response is received from executing the version.sw command, not just when a certain response includes a certain version. The <sentmessage> element ensures that signal is triggered only when the incoming message is a response to a version.sw command.

After adding the signal definition to the SimpleDevice.cml file and regenerating the device code, the field definition shown in Listing 8 is added to the SimpleDevice class. A new static field called VersionSwReport is also added to the SimpleDeviceService interface. This field contains the control ID.


Listing 8. Code generated by a CML signal definition

private final DataSignal VersionSwReport =
      new DataSignal(
            SimpleDeviceService.VersionSwReport,
            SimpleDeviceMessages.getVersionSwReportMessage());

The application code required to receive notifications when the VersionSwReport signal is triggered is shown in Listing 9.


Listing 9. Application code to use a signal

public class SimpleDeviceTestExample implements SignalListener {

  // define the variable to hold the control
  SignalService versionSwReportSignal;

  public void aMethod() {
    // get the control
    versionSwReportSignal =
        device.getSignal(SimpleDeviceService.VersionSwReport);

    // add the listener
    versionSwReportSignal.addSignalListener(this);
  }

  // process the signal
  public void signalOccurred(
      SignalService source,
      Object timestamp,
      Object data) {
        // Code to process signal data goes here
  }
}


Measurements

Measurements are implemented using commands and signals. They combine the functions of these two controls into a single control to provide applications with a convenient mechanism for getting and setting property values on a hardware device. Measurements maintain a local cached copy of the property value. This feature provides convenient access to hardware device properties whose values are unlikely to change. Measurements are defined using CML. The Device Kit tools generate the Java code implementing the measurement from the CML definitions.

Measurement definitions typically define or reference a read command, a write command and a signal. The read command allows the measurement to be used to send a command to the hardware device to get the property value. The write command allows the measurement to be used to update the property on the hardware device. The signal is used to trigger updates to the local cached copy of the property value. It's important to note that the local copy of the property will only be updated when a message is received that causes the signal to be triggered. Omitting a definition or reference to any of these controls will limit the functionality of the measurement. If for example, you omit a definition or reference to a write command, you won't be able to use the measurement to update the property on the hardware device. If you omit the definition or reference to a signal, the measurement's local cached copy of the property won't be updated.

Measurement CML

A <meaurement> element defines a measurement. The id attribute specifies the unique identifier for the <measurement> element.

The <measurement> element can include other elements. Commonly included elements are:

  • <specreference> - specifies a reference to the hardware specification documentation.
  • <description> - specifies a description of the measurement.
  • <readcommand> - defines or references the command used to read the property value on the hardware device.
  • <writecommand> - defines or references the command used to update the property value on the hardware device.
  • <signal> - defines of references the signal response from the hardware device that contains the measurement value.

For a complete list of the CML elements and attributes that can be used in a measurement definition, refer to the WebSphere Studio Device Developer Device Kit help.

MeasurementService

Measurement control objects are instances of classes that implement the com.ibm.esc.measurement.service.MeasurementService interface. This interface defines methods for getting and setting a measurement. It also defines methods that allow objects implementing the com.ibm.esc.measurement.service.MeasurementListener interface to add and remove themselves as measurement listeners. The methods defined by the MeasurementService interface are:

  • addCommandListener(MeasurementListener) - adds a listener to receive measurement listener notifications.
  • removeCommandListener(MeasurementListener) - removes the listener.
  • executeRead()- executes the read command to perform an asynchronous read of the property on the hardware device. To get the value of the property, an application would also have to execute the getValue() method or add itself as a listener of the signal defined or referenced by the <readcommand>.
  • executeWrite(Object) - executes the write command with a parameter to update the property on the hardware device.
  • getValue()- gets the measurement's local cached copy of the property.
  • read(long)- executes a synchronous read of the property on the hardware device.

MeasurementListener

Objects that add themselves as measurement listeners must implement the MeasurementListener interface. This interface defines a single method that will be called whenever the value of the local cached copy of the property changes. The method defined by the MeasurementListener interface is:

measurementChanged(MeasurementService source, Object timestamp,
                   Object newValue, Object oldValue)

The source parameter identifies the measurement the notification is for. The newValue parameter contains the updated property value and the oldValue parameter contains the old property value.

Measurement example

Let's look at example to get a better understanding of how measurements work. In this example, we'll add a new measurement definition to the SimpleDevice.cml file that models the Sirit INfinity 510 setup.operating_mode variable. We've already gone over a command definition to update this property. Now we'll use that command definition and create a new one to read the property value on the reader. We'll also create a signal definition that will allow the measurement's local cached copy of the property to be updated. The CML required to model the measurement is shown in Listing 10.


Listing 10. CML for a measurement

<!--  Define the read command -->
<command id="SetupOperatingModeGetRequest">
      <message id="SetupOperatingModeGetRequestMessage">
            <ascii>setup.operating_mode\r\n</ascii>
      </message>
</command>

<!--  Define the write command -->
<command id="SetupOperatingModeSetRequest">
      <message id="SetupOperatingModeSetRequestMessage">
          <ascii>setup.operating_mode = \r\n</ascii>
          <parameter type="string">
              <insert/>
              <index>23</index>
          </parameter>
      </message>
</command>

<!--  Define the signal  -->
<signal id="SetupOperatingModeReport">
      <message id="SetupOperatingModeReportMessage">
            <ascii>ok \r\n\r\n</ascii>
            <parameter type="string">
                  <insert/>
                  <index>3</index>
            </parameter>
            <filter>
                  <bytes format="hex">ff,ff,ff</bytes>
            </filter>
            <sentmessage idref="SetupOperatingModeGetRequestMessage"/>
      </message>
</signal>

<!--  Define the measurement  -->
<measurement id="SetupOperatingMode">
      <readcommand idref="SetupOperatingModeGetRequest"/>
      <writecommand idref="SetupOperatingModeSetRequest"/>
      <signal idref="SetupOperatingModeReport"/>
</measurement>

After adding the measurement definition to the SimpleDevice.cml file and regenerating the device code, the field definition shown in Listing 11 is added to the SimpleDevice class. A new static field called SetupOperatingMode is also added to the SimpleDeviceService interface. This field contains the control ID.


Listing 11. Code generated a measurement

private final CommandMeasurement SetupOperatingMode =
      new CommandMeasurement(
            SimpleDeviceService.SetupOperatingMode, null, null, null,
            SetupOperatingModeReport,SetupOperatingModeGetRequest,
            SetupOperatingModeSetRequest);

The application code required to use the SetupOperatingMode measurement to get and set the setup.operating_mode variable on the INfinity 510 is shown in Listing 12.


Listing 12. Application code to use a measurement

// define the variable to hold the control
MeasurementService setupOperatingModeMeasurement;

// get the control
setupOperatingModeMeasurement =
   device.getCommand(SimpleDeviceService.SetupOperatingMode);

String mode = null;
// perform a synchronous read
mode = (String) setupOperatingModeMeasurement.read(1000);

// set the operating mode to autonomous
setupOperatingModeMeasurement.executeWrite("autonomous");

// perform an asynchronous read
setupOperatingModeMeasurement.executeRead();

// get the measurement value
mode = (String) setupOperatingModeMeasurement.getValue()


Building a device for the Sirit INfinity 510 reader

In this example we'll guide you through the steps necessary to create and test a device for a Sirit INfinity 510 RFID reader. You'll learn how to model the commands necessary to tell the reader to start and stop reading and to send tag read reports. Once you've modeled the commands in CML and regenerated the device code, you'll write the application code necessary to use the generated controls to read tags.

Required materials

You'll need the following items to complete this exercise:

  1. WebSphere Studio Device Developer Version 5.1.7, installed with the WebSphere RFID Tracking Kit 1.1.1
  2. Sirit INfinity 510 reader
  3. INfinity 510 Protocol Reference Guide
  4. The SiritTransport you created in Part 2.

The completed example code is in the Downloads section.

Add the transport classes to the wizard

You'll need the SiritTransport project created in the Part 2 to test your device code. You can specify the transport classes in the device CML file or when you create the device using the Device Kit Creation wizard. The Device Kit Creation wizard has two drop-down boxes that allow you to select the transport service and implementation class. The wizard does not automatically populate the drop-down boxes with the transport service and implementation classes loaded in the workspace. To add these classes to the wizard you'll need to update the Device Kit preferences, as follows:

  1. Select Window => Preferences.
  2. Expand Device Kit and select Devices.
  3. Add the transport service and implementation classes:
    • devworks.example.transport.service.SiritTransportService
    • devworks.example.transport.SiritTransport

Create the device

In this part of the example, you'll use the Device Kit Device Creation wizard to generate a skeleton device for the Sirit INfinity 510 reader. This device will use the SiritTransport created in a previous exercise. To generate the device:

  1. Select File => New => Other.
  2. Select Device Kit, then select Device.
  3. Click Next.
  4. Fill in the following fields, as shown in Figure 2:
    • Name: Sirit
    • Package Base: devworks.example
    • Transport Service: devworks.example.transport.service.SiritTransportService
    • Transport Implementation: devworks.example.transport.SiritTransport
  5. Select all of the generation options.
  6. Click Finish to generate the device.

    Figure 2. Device Creation wizard
    Device Creation wizard

The Device Kit Device Creation wizard generates two Java projects. The SiritDevice project contains the device code and the SiritDeviceTest project contains a device test application. The generated device CML file, SiritDevice.cml, is located in the SiritDeviceDevelopment folder in the SiritDevice project. All the work you'll do in this exercise you'll do by modifying the SiritDevice.cml file and regenerating the device code using the Device Kit tools.

Interface Protocol

The INfinity 510 uses two channels for communication: a command/response channel and a channel for receiving asynchronous events. All communication with these channels is handled by the transport we built in Part 2.

The INfinity 510 reader's native protocol is ASCII text based. Every command is terminated using the character sequence\r\n. The corresponding reader response will end with the character sequence \r\n\r\n. An example command is setup.region\r\n and a corresponding response is fcc\r\n\r\n.

Events are also terminated with the character sequence with \r\n\r\n. An example event is event.tag.report tag_id=0xAABBCCDDEEFFGG\r\n\r\n.

Model the commands and events

There are several different commands that can be used to read tags on the INfinity 510. We want to take advantage of the reader's asynchronous event reporting capability to have it send a notification whenever a tag is read. To do this, we'll need a command to tell the reader to start reading, a command to tell the reader to stop reading, a command to register for the tag report event and a command to unregister for the tag report event. The setup.operating_mode variable discussed earlier (see Measurement example) sets the operational mode of the reader to one of the following: autonomous, polled, or standby. When the mode is set to autonomous or polled, the reader continuously tries to singulate tags. If the mode is set to autonomous, the reader automatically reports any singulated tag via an asynchronous event notification on the event channel. When the mode is set to standby, the reader doesn't try to singulate tags unless instructed to do so with another tag read command. Setting the operational mode to autonomous instructs the reader to start reading and setting it to standby tells it to stop. The additional commands and events we'll need to model are:

  • tag.reporting.report_fields
  • reader.register_event
  • reader.unregister_event
  • event.tag.report

Model the setup.operating_mode measurement

We modeled the setup.operating_mode variable as a measurement earlier in this article. All we need to do now is add the CML definitions in Listing 10 to the SiritDevice.cml file and regenerate the device code. Add the definitions after the <description> element. To regenerate the device code:

  1. Close the Java editor for the SiritDevice class.
  2. Right-click SiritDevice.cml, and select Device Kit => Generate.

Test the setup.operating_mode measurement

Now that we've defined a measurement for the setup.operating_mode variable, let's test it to see if it works. In this test, we'll write the application code necessary to:

  • Set the setup.operating_mode variable to autonomous.
  • Get and print out the setup.operating_mode variable value.
  • Set the setup.operating_mode variable to standby.
  • Get and print out the setup.operating_mode variable value.

As previously mentioned, the Device Kit Device Creation wizard generates a device test project when it creates the device. Each device test project includes a class that extends com.ibm.esc.device.test.DeviceTest, and that can be used to test the device. The test class iterates over the device's controls and calls the methods appropriate for that control to test it. For example, if the control is an instance of CommandService, the test class will call the command's execute() method.

The default test behavior is limited in its ability to test a device. The test class does not, for example, call a command's execute(Object) method, because it doesn't know what value should be used to test the command. In this example, we'll override the default test behavior by making the following changes to the SiritDeviceTest class.

  1. Add a field definition to hold the DeviceService object:
                private DeviceService device = null;
    

  2. Override the run() method in SiritDeviceTest. Call the superclass run() method.
  3. The setDevice(DeviceService device) method in DeviceTest loops through the list of controls adding the appropriate listener for each control. We want to test that our application code can successfully add and remove listeners. To do this, override the method as shown:
                public void setDevice(final DeviceService device) {
                      this.device = device;
                      if (isActive()) {
                            test();
                      }
                }
    

  4. Override the getDevice() method:
                public DeviceService getDevice() {
                      return this.device;
                }
    

  5. Add the following properties and values to the end of the esc.properties file:
                siritdevicetest.testcount=0
                sirittransport.host=ip_address_of_your_reader
    

Now that we've overridden the default test behavior, we need to add the application logic to test the SiritDevice. We need to add a field to the SiritDeviceTest class to hold the setup.operating_mode measurement, and then add logic to the run() method that uses the control to get and set the setup.operating_mode variable on the reader. The code we need to add to the SiritDeviceTest class is shown in Listing 13.


Listing 13. Code to test the setup.operating_mode measurement


// control field definition
MeasurementService setupOperatingModeMeasurement;

// run() method updates
// get the control
setupOperatingModeMeasurement =
    getDevice().getMeasurement(SiritDeviceService.SetupOperatingMode);

// set the property setup.operating_mode variable to autonomous
setupOperatingModeMeasurement.executeWrite("autonomous");

// get and print out the operating mode
setupOperatingModeMeasurement.executeRead();
sleep(1000);
log(LOG_INFO, "operating mode = " +
        setupOperatingModeMeasurement.getValue());

// set the property setup.operating_mode variable to standby
setupOperatingModeMeasurement.executeWrite("standby");

// get and print out the operating mode
setupOperatingModeMeasurement.executeRead();
sleep(1000);
log(LOG_INFO, "operating mode = " +
        setupOperatingModeMeasurement.getValue());

Now we're ready to find out if we've modeled the measurement correctly and if the SiritDevice works. To test the device using the modified SiritDeviceTest class:

  1. Select the SiritDeviceTest project in a Package Explorer view.
  2. Select Run => Run As => Java Application.

When the SiritDeviceTest application runs, you should see the following output written to the console:

[INFO] 2006-12-19 01:32:36.741 - operating mode = autonomous
[INFO] 2006-12-19 01:32:37.192 - operating mode = standby

Model the tag.reporting.report_fields measurement

The tag.reporting.report_fields variable is used to tell the INfinity 510 what tag fields should be reported on the event.tag.report event. The possible values are:

  • tag_id (tag ID or EPC)
  • tid
  • user_data
  • type (protocol type)
  • time
  • antenna
  • freq
  • rssi
  • tx_power

The format of the tag.reporting.report_fields command is tag.reporting.report_fields=fields\r\n, where fields is set to one or more of the valid tag field values. Add the CML definitions in Listing 14 to the SiritDevice.cml file and regenerate the device code.


Listing 14. CML to model the tag report fields measurement
<!--  Define the command to get the TagReportingReportFields value  -->
<command id="TagReportingReportFieldsGetRequest">
      <message id="TagReportingReportFieldsGetRequestMessage">
            <ascii>tag.reporting.report_fields\r\n</ascii>
      </message>
</command>

<!--  Define the command to set the TagReportingReportFields value  -->
<command id="TagReportingReportFieldsSetRequest">
      <message id="TagReportingReportFieldsSetRequestMessage">
            <ascii>tag.reporting.report_fields = \r\n</ascii>
            <parameter type="string">
                  <insert/>
                  <index>30</index>
            </parameter>
      </message>
</command>

<!--  Define the TagReportingReportFieldsReport signal  -->
<signal id="TagReportingReportFieldsReport">
      <message id="TagReportingReportFieldsReportMessage">
            <ascii>ok \r\n\r\n</ascii>
            <parameter type="string">
                  <insert/>
                  <index>3</index>
            </parameter>
            <filter>
                  <bytes format="hex">ff,ff,ff</bytes>
            </filter>
            <sentmessage idref="TagReportingReportFieldsGetRequestMessage"/>
      </message>
</signal>

<!--  Define the TagReportingReportFields measurement.  -->
<measurement id="TagReportingReportFields">
      <readcommand idref="TagReportingReportFieldsGetRequest"/>
      <writecommand idref="TagReportingReportFieldsSetRequest"/>
      <signal idref="TagReportingReportFieldsReport"/>
</measurement>

Test the tag.reporting.report_fields measurement

Now that we've defined a measurement for the tag.reporting.report_fields variable, let's test it to see if it works. In this test, we'll write the application code necessary to:

  • Set the tag.reporting.report_fields variable to tag_id and antenna.
  • Get and print out the tag.reporting.report_fields variable.

We need to add a field to the SiritDeviceTest class to hold the tag.reporting.report measurement, and then add logic to the run() method that uses the control to get and set the tag.reporting.report variable on the reader. The code we need to add to the SiritDeviceTest class is shown in Listing 15.


Listing 15. Code to test the tag report fields measurement

// control field definition
MeasurementService tagReportingReportFieldsMeasurement;

// get the control
tagReportingReportFieldsMeasurement =
        getDevice().getMeasurement(SiritDeviceService.TagReportingReportFields);

// set the tag reporting fields
tagReportingReportFieldsMeasurement.executeWrite("tag_id antenna");

// get and print out the tag reporting fields
tagReportingReportFieldsMeasurement.executeRead();
sleep(1000);
log(LOG_INFO, "tag reporting fields = " +
      tagReportingReportFieldsMeasurement.getValue());

To test your changes, run the SiritDeviceTest application. You should see the following output written to the console:

[INFO] 2006-12-19 02:43:04.571 - tag reporting fields = tag_id antenna

Model the reader.register_event and reader.unregister_event commands

The commands to register and unregister for events are reader.register_event and reader.unregister_event . The formats of these commands are:

  • reader.register_event (name = event)\r\n, where event is the event you want to register an interest in.
  • reader.register_event (name = event)\r\n, where event is the event you are no longer interested in.

The event we want to register and unregister an interest in is event.tag.report. When you model this command in CML, you have a choice of either creating a concrete or template message. Since event.tag.report is the only event we're interested in, we'll model the commands using concrete messages (if we were modeling more events, we would use a template message here). Add the CML definitions in Listing 16 to the SiritDevice.cml file and re-generate the device code.


Listing 16. CML to model the event registration commands

<!--  Define the EventTagReportRegisterRequest command -->
<command id="EventTagReportRegisterRequest">
      <message id="EventTagReportRegisterRequestMessage">
            <ascii>reader.register_event(name = event.tag.report)\r\n</ascii>
      </message>
</command>


<!--  Define the EventTagReportUnregisterRequest command -->
<command id="EventTagReportUnregisterRequest">
      <message id="EventTagReportUnregisterRequestMessage">
            <ascii>reader.unregister_event(name = event.tag.report)\r\n</ascii>
      </message>
</command>

Model the event.tag.report event signal

The last thing we need to model is the event.tag.report event. The INfinity 510 automatically sends out the event.tag.report event for singualted tags when the reader is operating in autonomous mode. Since events are notifications sent by the reader, we'll need to model the event using a signal.

The format of the event.tag.report event is event.tag.report tag_field=value tag_field=value\r\n, where tag_field is one of the fields specified in the tag.reporting.report_fields variable. For example, if the tag.reporting.report_fields variable is set to tag_id antenna, the event.tag.report event would resemble event.tag.report tag_id=0xAABBCCDDEEFFGG antenna=1\r\n.

The CML to model the event.tag.report event as a signal is shown in Listing 17. Add the CML definitions to the SiritDevice.cml file and regenerate the device code.


Listing 17. CML to model the tag read event as a signal

<!--  Define the EventTagReportReport signal -->
<signal id="EventTagReportReport">
      <message id="EventTagReportReportMessage">
            <ascii>event.tag.report \r\n\r\n</ascii>
            <parameters type="Map">
                  <parameter>
                        <key>tag_id</key>
                        <field>tag_id</field>
                  </parameter>
                  <parameter>
                        <key>type</key>
                        <field>type</field>
                  </parameter>
                  <parameter>
                        <key>antenna</key>
                        <field>antenna</field>
                  </parameter>
                  <parameter>
                        <key>tid</key>
                        <field>tid</field>
                  </parameter>
                  <parameter>
                        <key>time</key>
                        <field>time</field>
                  </parameter>
                  <parameter>
                        <key>freq</key>
                        <field>freq</field>
                  </parameter>
                  <parameter>
                        <key>rssi</key>
                        <field>rssi</field>
                  </parameter>
                  <parameter>
                        <key>tx_power</key>
                        <field>tx_power</field>
                  </parameter>
                  <parameter>
                        <key>user_data</key>
                        <field>user_data</field>
                  </parameter>
            </parameters>
            <filter>
                  <bytes format="hex">ff, ff, ff, ff, ff, ff, ff, ff,
                                      ff, ff, ff, ff, ff, ff, ff, ff, ff</bytes>
            </filter>
      </message>
</signal>

Read a tag

Now that we've modeled all the necessary commands and events, we're ready to read a tag. To read a tag, we'll update the SiritDeviceTest class to do the following:

  1. Set the tag.reporting.report_fields variable to tag_id antenna.
  2. Add a listener to the event.tag.report signal.
  3. Register an interest in the event.tag.report event.
  4. Set the setup.operating_mode variable to autonomous.
  5. Read tags for 1 second.
  6. Set the setup.operating_mode variable to standby.
  7. Unregister an interest in the event.tag.report event.
  8. Remove the listener for the event.tag.report signal.
  9. Add a signalOccurred(SignalService, Object, Object) method to process the event.tag.report events.

The field definitions and code for the run() and signalOccurred(...) methods are shown in Listing 18. Add this code to SiritDeviceTest.


Listing 18. Code to test tag reading


MeasurementService setupOperatingModeMeasurement;
MeasurementService tagReportingReportFieldsMeasurement;
CommandService eventTagReportRegisterRequestCommand;
CommandService eventTagReportUnregisterRequestCommand;
SignalService eventTagReportReportSignal;

public void run() {
      super.run();

      // get the controls
      tagReportingReportFieldsMeasurement = getDevice().getMeasurement(
          SiritDeviceService.TagReportingReportFields);

      setupOperatingModeMeasurement = getDevice().getMeasurement(
          SiritDeviceService.SetupOperatingMode);

      eventTagReportRegisterRequestCommand = getDevice().getCommand(
          SiritDeviceService.EventTagReportRegisterRequest);

      eventTagReportUnregisterRequestCommand = getDevice().getCommand(
          SiritDeviceService.EventTagReportUnregisterRequest);

      eventTagReportReportSignal = getDevice().getSignal(
          SiritDeviceService.EventTagReportReport);

      // set the tag reporting fields
      tagReportingReportFieldsMeasurement.executeWrite("tag_id antenna");

      // add a listener for the event.tag.report signal
      eventTagReportReportSignal.addSignalListener(this);

      // register for the event.tag.report event
      eventTagReportRegisterRequestCommand.execute();

      // set the operating mode of the reader to autonomous
      setupOperatingModeMeasurement.executeWrite("autonomous");

      // read for 1 second
      sleep(1000);

      // set the operating mode of the reader to standby
      setupOperatingModeMeasurement.executeWrite("standby");

      // unregister for the event.tag.report event
      eventTagReportUnregisterRequestCommand.execute();

      // remove the listener for the event.tag.report signal
      eventTagReportReportSignal.removeSignalListener(this);
}

public void signalOccurred(SignalService source,
          Object timestamp, Object data) {
      log(LOG_INFO, " >>>> Signal occurred..." + " signal: " +
          source.getKey() + " data: " + data);
}

Now let's see if you can read a tag. Place one or more tags near the reader antenna and run the SiritDeviceTest application. If your code is working correctly, you should see output similar to that shown below written to the console:

[INFO] 2007-01-29 13:21:54.156 - >>>> Signal occurred... signal:
EventTagReportReport data: {antenna=1, tag_id=0x30144B5A1CC3758000000008, type=ISOC}
[INFO] 2007-01-29 13:21:54.359 - >>>> Signal occurred... signal:
EventTagReportReport data: {antenna=1, tag_id=0x30144B5A1CC3758000000009, type=ISOC}
[INFO] 2007-01-29 13:21:54.359 - >>>> Signal occurred... signal:
EventTagReportReport data: {antenna=1, tag_id=0x30144B5A1CC375800000000D, type=ISOC}
[INFO] 2007-01-29 13:21:54.359 - >>>> Signal occurred... signal:
EventTagReportReport data: {antenna=1, tag_id=0x30144B5A1CC3758000000008, type=ISOC}
[INFO] 2007-01-29 13:21:54.359 - >>>> Signal occurred... signal:
EventTagReportReport data: {antenna=1, tag_id=0x30144B5A1CC375800000000E, type=ISOC}


Summary

In this article, you learned about the device component of a Device Kit adapter, including the CML definitions required to model a hardware device's command set and the resulting control classes that get created from the definitions. You followed the steps to create a device for a Sirit INfinity 510 RFID reader, including modeling the commands and events necessary to tell the reader to start and stop reading, and to report tag read events. In the final article in this series, you'll build on this knowledge to create a new reader agent for the INfinity 510 that you can plug into the WebSphere RFID solution.



Download

DescriptionNameSizeDownload method
Completed sample devicedevice_projects.zip42KBHTTP

Information about download methods


Resources

Learn

Get products and technologies

About the authors

Allen Smith photo

Allen Smith is a Senior Software Engineer with the Pervasive Computing Group in Research Triangle Park, North Carolina. He works with business partners to design solutions that use IBM's pervasive middleware. You can contact Allen at allens@us.ibm.com.

Karl Freburg photo

Karl Freburger is an IT Architect with IBM Global Business Services. He works with IBM's Software Group to enable business partners to design solutions that use IBM's RFID components.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=193665
ArticleTitle=Developing a device adapter and agent for the WebSphere RFID solution, Part 3: Building the device component
publish-date=02072007
author1-email=allens@us.ibm.com
author1-email-cc=crothemi@us.ibm.com
author2-email=karlf@us.ibm.com
author2-email-cc=crothemi@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers