Package com.rim.samples.device.usbdemo

Source Code of com.rim.samples.device.usbdemo.USBDemo$GCFUsbThread

/*
* USBDemo.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings.  However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies.  For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/

package com.rim.samples.device.usbdemo;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;

import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.system.SystemListener2;
import net.rim.device.api.system.USBPort;
import net.rim.device.api.system.USBPortListener;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.DataBuffer;
import net.rim.device.api.util.StringProvider;

/**
* A sample application to demonstrate opening of the USB port for communication
* with a desktop USB client (one that uses the COM interfaces exposed by
* BBDevMgr.exe).
*/
public final class USBDemo extends UiApplication {
    private static final String CHANNEL = "JDE_USBClient";
    private final RichTextField _output;
    private UsbThread _usbThread;

    /**
     * Entry point for application.
     *
     * @param args
     *            Command line arguments (not used)
     */
    public static final void main(final String[] args) {
        // Create a new instance of the application and make the currently
        // running thread the application's event dispatch thread.
        new USBDemo().enterEventDispatcher();
    }

    /**
     * Creates a new USBDemo object
     */
    public USBDemo() {

        final USBScreen screen = new USBScreen();
        screen.setTitle("USB Demo");

        _output = new RichTextField("<output>");

        screen.add(_output);

        pushScreen(screen);
    }

    /**
     * This is the main screen that allows the user to connect to a desktop
     * client.
     */
    private class USBScreen extends MainScreen {
        /**
         * Creates a new USBScreen object
         */
        private USBScreen() {
            // Connects through a GCF USB connection
            final MenuItem connectGCF =
                    new MenuItem(new StringProvider("Connect (GCF)"), 0x230010,
                            0);
            connectGCF.setCommand(new Command(new CommandHandler() {
                /**
                 * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
                 *      Object)
                 */
                public void execute(final ReadOnlyCommandMetadata metadata,
                        final Object context) {
                    // Cleanup the old thread if present
                    onExit();

                    _usbThread = new GCFUsbThread();
                    connect();
                }
            }));
            /*
             * Connects through a low level USB connection.
             */
            final MenuItem connectLowLevel =
                    new MenuItem(new StringProvider("Connect (low level)"),
                            0x230020, 1);
            connectLowLevel.setCommand(new Command(new CommandHandler() {
                /**
                 * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata,
                 *      Object)
                 */
                public void execute(final ReadOnlyCommandMetadata metadata,
                        final Object context) {
                    // Cleanup old thread if present.
                    onExit();

                    _usbThread = new LowLevelUsbThread();
                    connect();
                }
            }));
            addMenuItem(connectGCF);
            addMenuItem(connectLowLevel);
        }

        /**
         * @see net.rim.device.api.ui.container.MainScreen#onSavePrompt()
         */
        public boolean onSavePrompt() {
            // Prevent the save dialog from being displayed
            return true;
        }

        /**
         * @see net.rim.device.api.ui.Screen#close()
         */
        public void close() {
            onExit();

            super.close();
        }
    }

    /**
     * Provides an abstract base for the GCFUsbThread and LowLevelUsbThread to
     * use to connect to a desktop through its USB port.
     */
    private abstract class UsbThread extends Thread {
        /**
         * Provides the action of connecting to a desktop client by calling the
         * abstract methods to be implemented by subclasses.
         */
        public void run() {
            try {
                init();

                String s = read("Hello from PC");
                message("received: " + s);

                // Write back a hello string
                s = "Hello from Device";
                write(s);
                message("wrote: " + s);

                message("Sleeping to demonstrate queueing");
                try {
                    Thread.sleep(1000);
                } catch (final InterruptedException e) {
                }
                for (int i = 0; i < 5; i++) {
                    s = read("Q packet " + (i + 1));
                    message("received: " + s);
                }

                // Wait for goodbye
                s = read("Goodbye from PC");
                message("received: " + s);

                s = "Goodbye from Device";
                write(s);
                message("wrote: " + s);

                close();
            } catch (final IOException e) {
                message(e.toString());
            }
        }

        /**
         * Initializes the connection to the USB port
         *
         * @throws IOException
         *             Thrown if an error occurs while opening the USB port
         *             connection
         */
        abstract protected void init() throws IOException;

        /**
         * Writes to the desktop client
         *
         * @param s
         *            The string to write out
         * @throws IOException
         *             Thrown if a write error occurs
         */
        abstract protected void write(String s) throws IOException;

        /**
         * Reads from the desktop client and returns the read string only if it
         * matches the given string.
         *
         * @param match
         *            The specified string to match with the data read in
         * @return The data read in if it matches the specified string, null
         *         otherwise
         * @throws IOException
         *             Thrown if a read error occurs
         */
        abstract protected String read(String match) throws IOException;

        /**
         * Closes the USB connection
         */
        abstract public void close();
    }

    /**
     * The GCF prepends the length of the data written to the outputstream on
     * each transaction. Your server code should expect two bytes length data
     * prior to the actual data when the client is using the GCF.
     */
    private final class GCFUsbThread extends UsbThread {
        private DataInputStream _dis;
        private DataOutputStream _dos;
        private StreamConnection _sc;

        /**
         * @see UsbThread#init()
         */
        protected void init() throws IOException {
            // Using the connector interface
            // - no support for maxRxSize and maxTxSize changes
            // - size is set to 1024 bytes
            synchronized (this) {
                _sc =
                        (StreamConnection) Connector.open("comm:USB;channel="
                                + CHANNEL);

                _dis = _sc.openDataInputStream();
                _dos = _sc.openDataOutputStream();
            }
            message("Channel Open: " + CHANNEL);
        }

        /**
         * @see UsbThread#write(String)
         */
        protected void write(final String s) throws IOException {
            synchronized (this) {
                _dos.writeUTF(s);
                _dos.flush();
            }
        }

        /**
         * @see UsbThread#read(String)
         */
        protected String read(final String match) throws IOException {
            boolean loop;
            final int len = match.length();
            final byte[] data = new byte[len];
            do {
                loop = false;
                try {
                    synchronized (this) {
                        _dis.read(data, 0, len);
                    }
                } catch (final IOException e) {
                    message(e.toString());
                    loop = true;
                    close();
                    init();
                }
            } while (loop);

            final String s = new String(data);

            return s.equals(match) ? s : null;
        }

        /**
         * @see UsbThread#close()
         */
        public void close() {
            message("closing connections...");

            try {
                if (_dis != null) {
                    _dis.close();
                }
            } catch (final IOException e) {
            }
            try {
                if (_dos != null) {
                    _dos.close();
                }
            } catch (final IOException e) {
            }
            try {
                if (_sc != null) {
                    _sc.close();
                }
            } catch (final IOException e) {
            }

            message("connections closed");
        }

        // Default constructor
        public GCFUsbThread() {
        }
    }

    /**
     * This thread implements a low level USB connector through the USBPort
     * class.
     *
     * Note: This method is not portable. See the USBPort javadocs for details.
     *
     * @see net.rim.device.api.system.USBPort
     */
    private final class LowLevelUsbThread extends UsbThread implements
            USBPortListener, SystemListener2 {
        private boolean _dataAvailable;
        private Vector _readQueue;
        private int _channel;
        private USBPort _port;
        private boolean _waiting;
        private boolean _connected;
        private boolean _abort;

        /**
         * @see UsbThread#init()
         */
        protected void init() throws IOException {
            _readQueue = new Vector();

            // Register the app for callbacks.
            // NOTE: These are here for demonstration, but
            // they can be used in GCF thread if needed.

            USBDemo.this.addIOPortListener(this);
            USBDemo.this.addSystemListener(this);

            message("using low level usb interface");

            // Register the channel
            _channel = USBPort.registerChannel(CHANNEL, 16380, 16380);

            message("Registering channel: " + CHANNEL);

            synchronized (this) {
                // Wait for a channel
                if (_port == null) {
                    _waiting = true;
                    try {
                        this.wait();
                    } catch (final InterruptedException e) {
                    }
                    _waiting = false;
                }
            }
        }

        /**
         * @see UsbThread#write(String)
         */
        protected void write(final String s) throws IOException {
            _port.write(s.getBytes());
        }

        /**
         * @see UsbThread#read(String)
         */
        protected String read(final String match) throws IOException {
            do {
                if (_abort) {
                    // Disconnect happened, so reopen the channel
                    close();
                    init();
                    _abort = false;
                }
                synchronized (this) {
                    if (!_dataAvailable) {
                        // wait for data
                        _waiting = true;
                        try {
                            this.wait();
                        } catch (final InterruptedException e) {
                        }
                        _waiting = false;
                    }

                    _dataAvailable = false;
                }
            } while (_abort); // Check for disconnect

            // Loop through the queue of data and extract each item
            for (;;) {
                byte[] data = null;

                synchronized (this) {
                    if (_readQueue.isEmpty()) {
                        // The read queue is empty, we didn't find our match
                        message("did not recieve match for " + match);
                        break;
                    } else {
                        data = (byte[]) _readQueue.firstElement();

                        // Ensure we always remove the correct object
                        _readQueue.removeElementAt(0);

                        if (!_readQueue.isEmpty()) {
                            _dataAvailable = true;
                        }
                    }
                }

                final String s = new String(data);

                if (s.equals(match)) {
                    return s;
                }
            }
            return null;
        }

        // Wakeup the thread so it can reconnect the channel
        public void abort() {
            _abort = true;
            if (_waiting) {
                synchronized (this) {
                    this.notify();
                }
            }
        }

        /**
         * @see UsbThread#close()
         */
        public void close() {
            _connected = false;
            try {
                message("closing connections...");

                // Close port if not already closed
                if (_port != null) {
                    _port.close();
                }
                _port = null;

                // Deregister the channel
                USBPort.deregisterChannel(_channel);
                message("connections closed");

            } catch (final IOException e) {
                message(e.toString());
            }
        }

        // USBPortListener methods
        // --------------------------------------------------
        /**
         * @see net.rim.device.api.system.USBPortListener#getChannel()
         */
        public int getChannel() {
            return _channel;
        }

        /**
         * @see net.rim.device.api.system.USBPortListener#connectionRequested()
         */
        public void connectionRequested() {
            message("lowlevelusb: Connection requested!");

            try {
                synchronized (this) {
                    _port = new USBPort(_channel);
                    _connected = true;
                    this.notify();
                }
            } catch (final IOException e) {
                message(e.toString());
            }
        }

        /**
         * @see net.rim.device.api.system.USBPortListener#dataNotSent()
         */
        public void dataNotSent() {
            message("lowlevelusb: Data not sent");
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#connected()
         */
        public void connected() {
            message("lowlevelusb: connected");
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#disconnected()
         */
        public void disconnected() {
            message("lowlevelusb: disconnected");
            if (_connected) {
                abort();
            }
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#receiveError(int)
         */
        public void receiveError(final int error) {
            message("lowlevelusb: Got rxError: " + error);
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#dataReceived(int)
         */
        public void dataReceived(int length) {
            final DataBuffer db = new DataBuffer();
            int len;

            try {
                final byte[] receiveBuffer = new byte[16380];

                if (length == -1) // Length not available
                {
                    length = receiveBuffer.length;
                }

                // If something was read then add it to the data buffer to
                // send back later.
                synchronized (this) {
                    len = _port.read(receiveBuffer, 0, length);
                }
                if (len != 0) {
                    db.write(receiveBuffer, 0, len);
                    final String data = new String(receiveBuffer, 0, len);
                    message("lowlevelusb: " + data);
                }

                // Wakeup read()
                synchronized (this) {
                    _readQueue.addElement(db.toArray());
                    _dataAvailable = true;
                    this.notify();
                }
            } catch (final IOException ex) {
                throw new RuntimeException(ex.getMessage());
            }
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#dataSent()
         */
        public void dataSent() {
            // Not implemented
        }

        /**
         * @see net.rim.device.api.system.IOPortListener#patternReceived(byte[])
         */
        public void patternReceived(final byte[] pattern) {
            message("lowlevelusb: Got pattern " + new String(pattern)); // +
                                                                        // pattern[0]
                                                                        // + " "
                                                                        // +
                                                                        // pattern[1]
                                                                        // + " "
                                                                        // +
                                                                        // pattern[2]
                                                                        // + " "
                                                                        // +
                                                                        // pattern[3]
                                                                        // );
        }

        // SystemListener2 methods
        // --------------------------------------------------

        // Used to detect a connection change
        public void usbConnectionStateChange(final int state) {
            switch (state) {
            // USB cable is connected
            case USB_STATE_CABLE_CONNECTED:
                message("Cable connected");
                break;
            // USB cable is disconnected
            case USB_STATE_CABLE_DISCONNECTED:
                message("Cable disconnected");
                if (_connected) {
                    abort();
                }
                break;
            }
        }

        // Not implemented in this demo but need to be defined
        public void backlightStateChange(final boolean on) {
        }

        public void cradleMismatch(final boolean mismatch) {
        }

        public void fastReset() {
        }

        public void powerOffRequested(final int reason) {
        }

        // SystemListener methods
        // --------------------------------------------------

        // Not implemented in this demo but need to be defined
        public void batteryGood() {
        }

        public void batteryLow() {
        }

        public void batteryStatusChange(final int status) {
        }

        public void powerOff() {
        }

        public void powerUp() {
        }

        // Default constructor
        public LowLevelUsbThread() {
        }
    }

    /**
     * Connects the USB to the desktop
     */
    private void connect() {
        _usbThread.start();
    }

    /**
     * Displays a message by appending it to the screen
     *
     * @param msg
     *            The message to display
     */
    private void message(final String msg) {
        invokeLater(new Runnable() {
            public void run() {
                _output.setText(_output.getText() + "\n" + msg);
            }
        });
    }

    /**
     * Closes the USB thread
     */
    public void onExit() {
        if (_usbThread != null) {
            _usbThread.close();
        }
    }
}
TOP

Related Classes of com.rim.samples.device.usbdemo.USBDemo$GCFUsbThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.