DirectIO

Overview

Through the DirectIO feature a POS application communicates directly with the underlying CoreScanner Service.

This method provides a means for a UnifiedPOS Service to provide functionality to the application that is not otherwise supported by UnifiedPOS control for its device category.

Information in this chapter is applicable to both scanner and scale devices.


DirectIO Java Package

The necessary classes to perform DirectIO are contained in the JposService.jar file under the two namespaces:

  • com.zebra.jpos.service
  • com.zebra.jpos.service.directio

The package com.zebra.jpos.service contains the DirectIO method, while the package com.zebra.jpos.service.directio contains the supporting classes to leverage the DirectIO method.

Zebra JPOS Direct IO implementation is similar to the Scanner SDK.

com.zebra.jpos.service.directio

The directio package contains the following supporting class:

  • DirectIOCommand

DirectIO Command


public class DirectIOCommand {
    public static final int GET_SCANNERS= 1;                    // get scanners list 
    public static final int RSM_ATTR_GETALL= 0x1388;            // Opcode 5000 
    public static final int RSM_ATTR_GET= 0x1389;               // Opcode 5001 
    public static final int RSM_ATTR_SET= 0x138C;               // Opcode 5004 
    public static final int RSM_ATTR_STORE= 0x138D;             // Opcode 5005
    public static final int DIO_NCR_SCAN_TONE = 0x01F5;         // 501
    public static final int DIO_NCR_SCANNER_NOF = 0x01FC;       // 508
    public static final int NCRDIO_SCAN_RESET = 0x1F6;          // 502
    public static final int NCRDIO_SCAN_STATUS = 0x1F7;         // 503
    public static final int NCRDIO_SCAN_DIRECT = 0x1FB;         // 507
    public static final int NCR_DIO_SCAL_LIVE_WEIGHT = 0x25C;   // 604
    public static final int NCRDIO_SCAL_STATUS = 0x259;         // 601
    public static final int NCRDIO_SCAL_DIRECT = 0x25D;         // 605
}        

Viewing Bar Code Data

GET_SCANNERS: This command must be used first when setting up DirectIO. It updates the OutXml parameter with information for available scanners, and returns ScannerIDs used in all other DirectIO calls. See the sample code in Using DirectIO on page 5-8.

InOutXml: This contains the raw XML string of all of the connected scanners in the format:


<scanners>
    <scanner type="mode">
        <scannerID>id1</scannerID>
        <serialnumber>serial_number</serialnumber>
        <GUID>S_N:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</GUID>
        <VID>vendor_id</VID>
        <PID>product_id</PID>
        <modelnumber>model_number</modelnumber>
        <DoM>date_of_manufacture</DoM>
        <firmware>firmare_revision</firmware>
    </scanner>
    <scanner type="mode">
        <scannerID>id2</scannerID>
        <serialnumber>serial_number</serialnumber>
        <GUID>S_N:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</GUID>
        <VID>vendor_id</VID>
        <PID>product_id</PID>
        <modelnumber>model_number</modelnumber>
        <DoM>date_of_manufacture</DoM>
        <firmware>firmare_revision</firmware>
    </scanner>
    ....
    ....
    <scanner type="mode">
        <scannerID>idN</scannerID>
        <serialnumber>serial_number</serialnumber>
        <GUID>S_N:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</GUID>
        <VID>vendor_id</VID>
        <PID>product_id</PID>
        <modelnumber>model_number</modelnumber>
        <DoM>date_of_manufacture</DoM>
        <firmware>firmware_revision</firmware>
    </scanner>
</scanners>

RSM_ATTR_GETALL: This command returns a list in XML format via the object argument, defined above, of all possible attributes that can be set. This list and what it contains is dependent on the scanning device. The scanner specific Product Reference Guide contains the definitions of all of these attributes. The XML string returned in the obj argument has the following format:

InOutXml: This contains the raw XML string of all the supported RSM attributes:


<?xml version="1.0" encoding="UTF-8"?>
<outArgs>
    <scannerID>1</scannerID>
    <arg-xml>
        <modelnumber>DS4801-XXXXXXXXXXX</modelnumber>
        <serialnumber>S/N:B1353E3FBA73C94DB3449420F6F3B3FD</serialnumber>
        <GUID>B1353E3FBA73C94DB3449420F6F3B3FD</GUID>
        <response>
            <opcode>5000</opcode>
            <attrib_list>
                <attribute name="">0</attribute>
                <attribute name="">1</attribute>
                <attribute name="">2</attribute>
                <attribute name="">3</attribute>
                <attribute name="">4</attribute>
                ....
                ....
                <attribute name="">25011</attribute>
                <attribute name="">25012</attribute>
            </attrib_list>
        </response>
    </arg-xml>
</outArgs>

The value of each attribute in the returned XML list can be accessed using the RSM_ATTR_GET command.

NOTE: Calling this is not necessary if the attributes you wish to SET, or GET are known ahead of time.

RSM_ATTR_GET: This command can be used to retrieve scanner attribute information including value, data type, and permission. For more information, refer to the Zebra Scanner SDK for Windows Developer’s Guide.

InOutXml: For this command InOutXml argument is used to provide input and retrieve the output of the command.

Input:


<inArgs>
    <scannerID>scannerID</scannerID>
    <!-- ScannerID one of the scanner which could be retrived executing GET_SCANNRS op-code -->
    <cmdArgs>
        <arg-xml>
            <attrib_list> attribute1[,attribute2…attributeN]</attrib_list>
            <!-- A comma separated list of scanner attribute numbers -->
        </arg-xml>
    </cmdArgs>
</inArgs>

Output:


<outArgs>
    <scannerID>1</scannerID>
    <arg-xml>
        <modelnumber>DS4801-XXXXXXXXXXX</modelnumber>
        <serialnumber>S/N:B1353E3FBA73C94DB3449420F6F3B3FD</serialnumber>
        <GUID>B1353E3FBA73C94DB3449420F6F3B3FD</GUID>
        <response>
            <opcode>5001</opcode>
            <attrib_list>
                <attribute>
                    <id> attribute1</id>
                    <name></name>
                    <datatype>F</datatype>
                    <permission>RWP</permission>
                    <value>True</value>
                </attribute>
                ....
                ....
                <attribute>
                    <id> attributeN</id>
                    <name></name>
                    <datatype>F</datatype>
                    <permission>RWP</permission>
                    <value>True</value>
                </attribute>
            </attrib_list>
        </response>
    </arg-xml>
</outArgs>

RSM_ATTR_SET or RSM_ATTR_STORE: Sets (volatile, cleared after device reboot) or stores (non-volatile, retained after device reboot) attributes respectively, specified in the XML string given in the obj argument. The XML string takes the following format.

InOutXml: For this command using InOutXml argument we could provide the information for the attribute to set in XML format

NOTE: The tabbed formatting is for brevity only, and the actual XML string has no end-line or carriage-return characters required.


<inArgs>
    <scannerID>1</scannerID>
    <cmdArgs>
        <arg-xml>
            <attrib_list>
                <attribute>
                    <id>rsm_attribute_number</id>
                    <!-- 7 -->
                    <datatype>valid_datatype</datatype>
                    <!-- F -->
                    <value>value_matching_datatype</value>
                    <!-- True -->
                </attribute>
            </attrib_list>
        </arg-xml>
    </cmdArgs>
</inArgs>

The following are the valid values:

  • rsm_attribute_number: One of the scanners accepted, writeable attributes numbers.
  • valid_datatype: A valid datatype character: F, B, W, D, A, S
  • value_matching_datatype: A value that is consistent with the datatype and the datatypes range. For example, 'F' is a 'Boolean' value that may be either 'false' or 'true'. A 'B' datatype is 'Byte' which ranges from 0-255.

For example, to disable UPC Code 128, the actual XML string passed into the obj argument would look this:


<inArgs>
    <scannerID>1</scannerID>
    <cmdArgs>
        <arg-xml>
            <attrib_list>
                <attribute>
                    <id>7</id>
                    <datatype>F</datatype>
                    <value>False</value>
                </attribute>
            </attrib_list>
        </arg-xml>
    </cmdArgs>
</inArgs>

InOutXml: This contains the raw XML string of all of the connected scanners in the format:

DIO_NCR_SCAN_TONE: This command is used to execute the NCR tone pattern configured in the JPOS.xml. Tone pattern can be set for any logical device by setting the following configuration.


<prop name="NcrScanTonePattern" type="String" value="<TonePatternID>"/>

InOutXml: No need of providing an InOutXml argument.

DIO_NCR_SCANER_NOF: This command is used to execute the NCR “Not on File” tone pattern configured in the JPOS.xml. Tone pattern can be set for any logical device by setting the following configuration.


<prop name="NcrScanNOFPattern" type="String" value="<TonePatternID>"/>

InOutXml: No need of providing an InOutXml argument.

NCRDIO_SCAN_RESET: This command is used to reset the device. Executing this command is not doing any change to the device now. Once executed it always returns success.

InOutXml: No need of providing an InOutXml argument.

NCRDIO_SCAN_STATUS: This command is used to get the IBM USB status bytes of the scanner. Status bytes are given as a string.

InOutXml: No need of providing an InOutXml argument.

NCRDIO_SCAN_DIRECT: This command is used to execute direct IO commands GetAll, Get, GetNext, Set and Store attributes directly without the corresponding direct IO commands for these operations. Direct IO OpCode for these operations are passed as an attribute in the InXml.

InOutXml: This contains the raw XML string of direct access in xml with the opcode tag.


<inArgs>
    <scannerID>1</scannerID>
    <opcode>5000</opcode>
    <cmdArgs>
        <arg-xml>
            <attrib_list>
                <attribute>
                    <id>6000</id>
                    <datatype>X</datatype>
                    <value>2</value>
                </attribute>
            </attrib_list>
        </arg-xml>
    </cmdArgs>
</inArgs>

NCR_DIO_SCAL_LIVE_WEIGHT: This command is used to get the live weight value of the scale.

InOutXml: No need of providing an InOutXml argument.

NCRDIO_SCALE_STATUS: This command is used to get the IBM USB status bytes of the scale. Status bytes are given as a string.

InOutXml: No need of providing an InOutXml argument.

NCRDIO_SCALE_DIRECT: This command is used to execute direct IO commands GetAll, Get, GetNext, Set and Store attributes directly without the corresponding direct IO commands for these operations. Direct IO OpCode for these operations are passed as an attribute in the InXml.

InOutXml: This contains the raw XML string of direct access in xml with the opcode tag.


<inArgs>
    <scannerID>1</scannerID>
    <opcode>5000</opcode>
    <cmdArgs>
        <arg-xml>
            <attrib_list>
                <attribute>
                    <id>6000</id>
                    <datatype>X</datatype>
                    <value>2</value>
                </attribute>
            </attrib_list>
        </arg-xml>
    </cmdArgs>
</inArgs>


DirectIO Status


public class DirectIOStatus {
    public static final int STATUS_SUCCESS = 0;
}

Currently only STATUS_SUCCESS is defined. Any other value should be indicated as an error. The DirectIO method itself is an exception based method (see The DirectIO Method for more information). As a result, use a try-catch statement when calling it. The JposException class contains most of the error information.


The DirectIO Methods

The Zebra JPOS driver allows direct RSM attribute GET/SET access in order to leverage features not otherwise able to be exposed through the JPOS API Specification.

The JPOS DirectIO method has the following prototype (as of Zebra JPOS driver 1.0):


directIO ( command: int32, inout data: int32, inout obj: object ): void { raises-exception }

DirectIO Method Arguments

For the purposes of the Zebra scanner device class, the DirectIO method arguments are defined as:

command: int32: The command is passed to the CoreScanner service which is responsible for communicating with the scanner. This command is defined in the JposService.jar.

inout data: int32: For Zebra devices, this is used to return the status of the executed op-code.

inout obj: object: This is an object type. In Zebra JPOS Direct IO implementation, Java StringBuffer type is used to provide input and get output of the argument in XML format. See DirectIO Command.

Using the JPOS Sample Application to Send Direct I/O Commands

DirectIO operations can be done using the panel highlighted in red, as shown in the screenshot given below. The required DirectIO command can be selected from the drop-down list named as the Command. Upon selecting, the InXML relevant to the chosen command will be displayed on the left side of the panel.

Figure 1: JPOS Sample Application - Direct IO Commands

The OutXML corresponding to the selected DirectIO command can be retrieved by clicking on the Execute button.

Figure 2: JPOS Sample Application - Direct IO Commands Output

To send Direct I/O commands using the JPOS sample application:

  1. Connect a Zebra scanner and switch to a management enabled host mode such as IBM OPOS, IBM Hand-held, IBM Table-top, or SNAPI.
  2. Open the JPOS sample application and select the Scanner tab.
  3. Enter ZebraAllScanners as the logical name and click Open.
  4. Click Claim.

To retrieve a list of all the scanners connected to the PC:

  • Select GET_SCANNERS as DIO Op-Code from the Direct I/O section.
  • Click Execute. The Direct I/O OutXml text box populates with XML with all the attached scanners.

To retrieve all attributes available in the scanner:

  1. Select RSM_ATTR_GETALL as DIO Op-Code from Direct I/O section.
  2. In the Direct I/O InXml text box, change the value of the ScannerID XML element to the scannerID from which you want to retrieve attributes. Use the GET_SCANNER command to find available ScannerIDs.
  3. Click Execute. The Direct I/O OutXml text box populates with XML with attribute numbers of all supported attributes.

To retrieve more information for an attribute:

  1. Select RSM_ATTR_GET as DIO Op-Code from the Direct I/O section.
  2. In the Direct I/O InXml text box, change the value of the ScannerID XML element to the required scanner ID, and enter a comma-separated list of attribute numbers as the value of attrib_list.
  3. Click Execute. The Direct I/O OutXml text box populates with XML containing a list of attributes with values and other attribute related details.

To temporarily set or permanently store the value of an attribute:

  1. Select RSM_ATTR_SET or RSM_ATTR_STORE as DIO Op-Code from the Direct I/O section.
  2. In the Direct I/O InXml text box, change the value of the ScannerID XML element to the required scanner ID and change the values of data_type and the value XML elements accordingly as obtained by executing the command RSM_ATTR_GET.
  3. Click Execute. For these Direct I/O op-codes, an OutXml does not populate.

Upon executing each Op-Code, the CoreScanner Status field populates with the status of the underlying CoreScanner driver. Any value other than 0 indicates an error.


Using DirectIO

Following is an example of how to use DirectIO when attached to a single device, assuming a returned scanner/scale ID of '1'.

NOTE: The following code demonstrates how to use DirectIO with scanner JPOS control. The same pattern is applicable to scale JPOS control by declaring and instantiating JPOS scale class, and scale object instead of scanner class in the code.


package dio;

import jpos.*;
import com.zebra.jpos.service.directio.DirectIOCommand; 
import com.zebra.jpos.service.directio.DirectIOStatus; 
import java.io.ByteArrayInputStream;
import java.io.IOException; 
import java.util.logging.Level; 
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException; 
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
*
* @author Zebra Technologies
*/
public class DirectIODemo {
    // As defined in JPOS v1.13

    public static Scanner scannerObj = new Scanner();
    // Interfacing with a single scanner connection 
    static int scannerID;

    // main function
    public static void main(String[] args) {
        // Open scanner API, claim, enable and perform get scanners 
        try {
            // open with 'ZebraAllScanners' as logical device name 
            scannerObj.open("ZebraAllScanners");
            
            // standard claim with 5000ms timeout 
            scannerObj.claim(5000); 
            
            // enable device
            scannerObj.setDeviceEnabled(true);

            // object to store DirectIO data
            StringBuffer deviceParams = new StringBuffer();

            // get scanners - this acquires the scanner ID needed to perform directIO on a specific device
            int opCode = DirectIOCommand.GET_SCANNERS; int[] csStatus = new int[1];

            scannerObj.directIO(opCode, csStatus, (Object) deviceParams); 
            if (csStatus[0] != DirectIOStatus.STATUS_SUCCESS) {
                    System.out.println("Error connecting to device"); return;
            }

            // retrieve ID number of scanner for this example, we assume at least 1 scanner is found
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
            DocumentBuilder dBuilder;
            try {
                dBuilder = dbFactory.newDocumentBuilder();
                Document doc;
                ByteArrayInputStream inIs = new ByteArrayInputStream(deviceParams.toString().getBytes());
                doc = dBuilder.parse(inIs);

                int scannerCount = doc.getElementsByTagName("scannerID").getLength();
                if (scannerCount <= 0) {
                    System.out.println("No scanner found attatched"); return;
                }

                for (int n = 0; n < scannerCount; n++) {
                    System.out.println("Scanner ID : " + doc.getElementsByTagName("scannerID").item(n).getTextContent());
                }

                System.out.println("Selected scanner ID : " + doc.getElementsByTagName("scannerID").item(0).getTextContent()); 
                scannerID = Integer.parseInt(doc.getElementsByTagName("scannerID").item(0). getTextContent());
            } 
            catch (SAXException ex) { 
                Logger.getLogger(DirectIODemo.class.getName()).log(Level.SEVERE, null, ex);
            } 
            catch (IOException ex) { 
                Logger.getLogger(DirectIODemo.class.getName()).log(Level.SEVERE, null, ex);
            } 
            catch (ParserConfigurationException ex) { 
                Logger.getLogger(DirectIODemo.class.getName()).log(Level.SEVERE, null, ex);
            }

            // retrieve model number of device

            // Setup DirectIO to do a GET Attribute setup DirectIO XML string
            String sGetAttribInXML = "<inArgs>\n"
                                    + " <scannerID>" + scannerID + "</scannerID>\n"
                                    + " <cmdArgs>\n"
                                    + " <arg-xml>\n"
                                    + " <attrib_list>535</attrib_list>\n"
                                    + " </arg-xml>\n"
                                    + " </cmdArgs>\n"
                                    + "</inArgs>";

            // create new DirectIO data structure see DirectIO data definition for more information 
            StringBuffer oGETparams = new StringBuffer();

            // copy XML string into DirectIO inXML member 
            oGETparams.append(sGetAttribInXML);

            // set opcode for Atrribute GET
            opCode = DirectIOCommand.RSM_ATTR_GET;

            // set scanner ID
            int[] csSataus = new int[1];

            // make directIO call to JPOS driver 
            scannerObj.directIO(opCode, csSataus, (Object) oGETparams);

            // check status from DirectIO status member
            if (csSataus[0] != DirectIOStatus.STATUS_SUCCESS) { 
                System.out.println("Error performing DirectIO"); return;
            }

            // output XML string returned. Not that the actual model number will be contained within the <value> XML tag.
            System.out.println("XML string returned: " + oGETparams.toString());

            // disable UPC-A barcode on scanner

            // Setup DirectIO to do a SET Attribute 
            String sSetAttribInXML = "<inArgs>\n"
                                    + " <scannerID>" + scannerID + "</scannerID>\n"
                                    + " <cmdArgs>\n"
                                    + " <arg-xml>\n"
                                    + " <attrib_list>\n"
                                    + " <attribute>\n"
                                    + " <id>6000</id>\n"
                                    + " <datatype>X</datatype>\n"
                                    + " <value>2</value>\n"
                                    + " </attribute>\n"
                                    + " </attrib_list>\n"
                                    + " </arg-xml>\n"
                                    + " </cmdArgs>\n"
                                    + "</inArgs>";

            // create new DirectIO data structure
            // see DirectIO data definition for more information 
            StringBuffer oSETparams = new StringBuffer();

            // copy XML string into DirectIO inXML member 
            oSETparams.append(sSetAttribInXML);

            // set opcode for Atrribute SET
            opCode = DirectIOCommand.RSM_ATTR_SET;

            // set scanner ID
            csSataus[0] = scannerID;

            // make directIO call to JPOS driver 
            scannerObj.directIO(opCode, csSataus, (Object) oSETparams);

            // check status from DirectIO status member
            if (csSataus[0] != DirectIOStatus.STATUS_SUCCESS) { 
                System.out.println("Error performing DirectIO");
            }
        } 
        catch (JposException ex) { 
            System.out.println("Exception: " + ex.getMessage());
        }
    }
}