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;                    
    public static final int RSM_ATTR_GETALL= 0x1388;                            // 5000 
    public static final int RSM_ATTR_GET= 0x1389;                               // 5001 
    public static final int RSM_ATTR_SET= 0x138C;                               // 5004 
    public static final int RSM_ATTR_STORE= 0x138D;                             // 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
    
    public static final int CMD_RTA_SUPPORTED_GET = 0x157C;                     // 5500
    public static final int CMD_RTA_REGISTER = 0x157D;                          // 5501
    public static final int CMD_RTA_UNREGISTER = 0x157E;                        // 5502
    public static final int CMD_RTA_ALERT_STATUS_GET = 0x157F;                  // 5503
    public static final int CMD_RTA_ALERT_STATUS_SET = 0x1580;                  // 5504
    public static final int CMD_RTA_SUSPEND = 0x1581;                           // 5505
    public static final int CMD_RTA_STATE = 0x1582;                             // 5506

    public static final int CMD_LOAD_CONFIGURATION = 0x139C;                    // 5020 
    public static final int CMD_DEVICE_UPDATE_FIRMWARE_FROM_PLUGIN = 0x1399;    // 5017
    public static final int CMD_DEVICE_UPDATE_FIRMWARE_DAT = 0x1398;            // 5016     
}        

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.

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 / 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>

CMD_LOAD_CONFIGURATION

This command can be used to update the scanner configuration by specifying the relevant scannerID and the absolute file path, including the filename, created using 123Scan (.scncfg).

InXML:


<inArgs> 
    <scannerID>1</scannerID> 
    <cmdArgs> 
        <arg-string>C:\DS8108 Config.scncfg</arg-string> 
    </cmdArgs> 
</inArgs>

OutXml: None. Instead of OutXml, DirectIO events with the following event types will be received.

  • CONFIG_LOAD_START = 17
  • CONFIG_LOAD_PROGRESS = 18
  • CONFIG_LOAD_END = 19

Possible error scenarios are outlined below.

Failure Error Code
File does not exist ERROR_INLVAID_CONFIG_FILE (601)
Incorrect extension ERROR_INLVAID_CONFIG_FILE (601)
Self-hash failure ERROR_INLVAID_CONFIG_FILE (601)
Incompatible device ERROR_INCOMPATIBLE_CONFIG_FILE (602)
XML syntax validation failure ERROR_CONFIG_FILE_SYNTAX_VALIDATION_FAILED (603)

CMD_DEVICE_UPDATE_FIRMWARE_FROM_PLUGIN / CMD_DEVICE_UPDATE_FIRMWARE_DAT

This command can be used to update the scanner firmware by specifying the relevant scannerID and the absolute path of the firmware file (PLUGIN or DAT), including the filename.

InXML:


<inArgs> 
    <scannerID>1</scannerID> 
    <cmdArgs> 
        <arg-string>C:\DS3678-STANDARD.SCNPLG</arg-string> 
    <arg-int>2</arg-int> 
    </cmdArgs> 
</inArgs>

OutXml: None. Instead of OutXml, DirectIO events with the following event types will be received.

  • SCANNER_UF_SESS_START = 11
  • SCANNER_UF_DL_START = 12
  • SCANNER_UF_DL_PROGRESS= 13
  • SCANNER_UF_DL_END= 14
  • SCANNER_UF_SESS_END= 15
  • SCANNER_UF_STATUS= 16

Possible error scenarios are outlined below.

Failure Error Code
ERROR_FW_INVALID_DATFILE Invalid firmware file (500)
ERROR_FW_UPDATE_FAILED_IN_SCN FW Update failed in scanner (501)
ERROR_FW_READ_FAILED_DATFILE Failed to read DAT file (502)
ERROR_FW_UPDATE_INPROGRESS Firmware Update is in progress (cannot proceed another FW Update or another command) (503)
ERROR_FW_UPDATE_ALREADY_ABORTED Firmware update is already aborted (504)
ERROR_FW_UPDATE_ABORTE FW Update aborted (505)
ERROR_FW_SCN_DETTACHED Scanner is disconnected while updating firmware (506)
ERROR_FW_UPDATE_NOT_SUPPORTED Device doesn't support firmware update (507)
STATUS_FW_SWCOMP_RESIDENT The software component is already resident in the scanner (600)

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>

Real Time Alerts (RTA)

Real Time Alerts (RTA) are preselected events that are monitored by a scanner device. When a selected statistic has reached a specified value or when a selected event occurs, it is then reported by the scanner device to the host as an alert.

For more information, see Real Time Alerts (RTA) Developer Guide

The JPOS driver uses Direct IO commands to configure the Real Time Alerts feature in the scanner or cradle device, and it uses Direct IO events to receive notifications when an RTA event is sent by the scanner.

For more information on InXmls and OutXmls, refer to RTA opcodes in Using the Methods (Examples).


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());
        }
    }
}