previous chapter table of contents next chapter


In Getting It Running" section, of a client supplying a user interface to a MINDSTORMS service. This client not only knew that the service was a MINDSTORMS robot, but that it was a particular robot for which it could use a customized UI. In this section, we'll give two user interfaces for the MINDSTORMS "RoverBot," one of which is fairly general and could be used for any robot, and another that is customized to the RoverBot. The service is responsible for creating and exporting both of these user interfaces to a client.


A MINDSTORMS robot is primarily defined by the RCXPort interface. The Jini version is defined by the RCXPortImplementation interface:

 /**  * RCXPortInterface.java  */ package rcx.jini; import net.jini.core.event.RemoteEventListener; public interface RCXPortInterface extends java.io.Serializable {     /**      * constants to distinguish message types      */     public final long ERROR_EVENT = 1;     public final long MESSAGE_EVENT = 2;     /**      * Write an array of bytes that are RCX commands      * to the remote RCX.      */     public boolean write(byte[] byteCommand) throws java.rmi.RemoteException;     /**      * Parse a string into a set of RCX command bytes      */     public byte[] parseString(String command) throws java.rmi.RemoteException;     /**      * Add a RemoteEvent listener to the RCX for messages and errors      */     public void addListener(RemoteEventListener listener)         throws java.rmi.RemoteException;     /**      * The last message from the RCX      */     public byte[] getMessage(long seqNo)         throws java.rmi.RemoteException;     /**      * The error message from the RCX      */     public String getError(long seqNo)         throws java.rmi.RemoteException; } // RCXPortInterface 

This type interface allows programs to be downloaded and run and instructions to be sent for direct execution. As it stands, the client needs to call these interface methods directly. To make it more useable for the human trying to drive a robot, some sort of user interface would be useful.

There can be several general purpose user interfaces for the RCX robot, including these:

  • Enter machine code (somehow) and download that.
  • Enter RCX assembler code in the form of strings, and then assemble and download them.
  • Enter NQC (Not Quite C) code, and then compile and download it.

The set of RCX classes by Laverde at http://www.escape.com/~dario/java/rcx includes a standalone application called RCXLoader , which does the second of these options. We can steal code from RCXLoader and some of his other classes to define an RCXLoaderFrame class:

 package rcx.jini; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import net.jini.core.event.RemoteEventListener; import net.jini.core.event.RemoteEvent; import net.jini.core.event.UnknownEventException; import java.rmi.server.UnicastRemoteObject; import java.rmi.RemoteException; import rcx.*; /*  * RCXLoaderFrame  * @author Dario Laverde  * @author Jan Newmarch  * @version 1.1  * Copyright 1999 Dario Laverde, under terms of GNU LGPL  */ public class RCXLoaderFrame extends Frame     implements ActionListener, WindowListener, RemoteEventListener {     private String      portName;     private RCXPortInterface     rcxPort;     private Panel       textPanel;     private Panel       topPanel;     private TextArea    textArea;     private TextField   textField;     private Button      tableButton;     private Properties  parameters;     private int inByte;     private int charPerLine = 48;     private int lenCount;     private StringBuffer sbuffer;     private byte[] byteArray;     private Frame opcodeFrame;     private TextArea opcodeTextArea;     public static Hashtable Opcodes=new Hashtable(55);     static {         Opcodes.put(new Byte((byte)0x10),"PING            ,void, void,P");         Opcodes.put(new Byte((byte)0x12),"GETVAL          ,         byte src byte arg, short val,P");         Opcodes.put(new Byte((byte)0x13),"SETMOTORPOWER   ,         byte motors byte src byte arg, void,CP");         Opcodes.put(new Byte((byte)0x14),"SETVAL          ,         byte index byte src byte arg, void,CP");         // Opcodes truncated to save space in listing     }     // added port interface parameter to Dario's code     public RCXLoaderFrame(RCXPortInterface port) {             super("RCX Loader");         // changed from Dario's code         rcxPort = port;         addWindowListener(this);         topPanel = new Panel();         topPanel.setLayout(new BorderLayout());         tableButton = new Button("table");         tableButton.addActionListener(this);         textField = new TextField();         // textField.setEditable(false);         // textField.setEnabled(false);         // tableButton.setEnabled(false);         textField.addActionListener(this);         textPanel = new Panel();         textPanel.setLayout(new BorderLayout(5,5));         topPanel.add(textField,"Center");         topPanel.add(tableButton,"East");         textPanel.add(topPanel,"North");         textArea = new TextArea();         // textArea.setEditable(false);         textArea.setFont(new Font("Courier",Font.PLAIN,12));         textPanel.add(textArea,"Center");         add(textPanel, "Center");         textArea.setText("initializing...\n");         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();         setBounds(screen.width/2370/2,screen.height/2370/2,370,370);         // setVisible(true);         // changed listener type from Dario's code         try {             // We are remote to the object we are listening to             // (the RCXPort), so the RCXPort must get a stub object             // for us. We have subclassed from Frame, not from             // UnicastRemoteObject. So we must export ourselves             // for the remote references to work             UnicastRemoteObject.exportObject(this);             rcxPort.addListener(this);         } catch(Exception e) {             textArea.append(e.toString());         }         tableButton.setEnabled(true);     }     public void actionPerformed(ActionEvent evt) {         Object obj = evt.getSource();         if(obj==textField) {             String strInput = textField.getText();             textField.setText("");             textArea.append("> "+strInput+"\n");             try {                 byteArray = rcxPort.parseString(strInput);             } catch(RemoteException e) {                 textArea.append(e.toString());             }             // byteArray = RCXOpcode.parseString(strInput);             if(byteArray==null) {                 textArea.append("Error: illegal hex character or length\n");                 return;             }             if(rcxPort!=null) {                 try {                     if(!rcxPort.write(byteArray)) {                         textArea.append("Error: writing data to port                         "+portName+"\n");                     }                 } catch(Exceptione) {                     textArea.append(e.toString());                 }             }         }         else if(obj==tableButton) {             // make this all in the ui side             showTable();             setLocation(0,getLocation().y);         }     }     public void windowActivated(WindowEvent e) { }     public void windowClosed(WindowEvent e) { }     public void windowDeactivated(WindowEvent e) { }     public void windowDeiconified(WindowEvent e) { }     public void windowIconified(WindowEvent e) { }     public void windowOpened(WindowEvent e) { }     public void windowClosing(WindowEvent e) {         /*         if(rcxPort!=null)                 rcxPort.close();         */         System.exit(0);     }     public void notify(RemoteEvent evt) throws UnknownEventException,                                                  java.rmi.RemoteException {         long id = evt.getID();         long seqNo = evt.getSequenceNumber();         if (id == RCXPortInterface.MESSAGE_EVENT) {             byte[] message = rcxPort.getMessage(seqNo);             StringBuffer sbuffer = new StringBuffer();             for(int n = 0; n < message.length; n++) {                 int newbyte = (int) message[n];                 if (newbyte < 0) {                     newbyte += 256;                 }                 sbuffer.append(Integer.toHexString(newbyte) + " ");             }             textArea.append(sbuffer.toString());             System.out.println("MESSAGE: " + sbuffer.toString());         } else if (id == RCXPortInterface.ERROR_EVENT) {             textArea.append(rcxPort.getError(seqNo));         } else {             throw new UnknownEventException("Unknown message " + evt.getID());         }     }     public void showTable()     {         if(opcodeFrame!=null)         {             opcodeFrame.dispose();             opcodeFrame=null;             return;         }         opcodeFrame = new Frame("RCX Opcodes Table");         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();         opcodeFrame.setBounds(screen.width/270,0,                               screen.width/2+70,screen.height25);         opcodeTextArea = new TextArea("   Opcode          ,parameters, response,                                      C=program command P=remote command\n",60,100);         opcodeTextArea.setFont(new Font("Courier",Font.PLAIN,10));         opcodeFrame.add(opcodeTextArea);         Enumeration k = Opcodes.keys();         for (Enumeration e = Opcodes.elements(); e.hasMoreElements();) {             String tmp = Integer.toHexString(((Byte)k.nextElement()).intValue());             tmp = tmp.substring(tmp.length()2)+" "+(String)e.nextElement()+"\n";             opcodeTextArea.append(tmp);         }         opcodeTextArea.setEditable(false);         opcodeFrame.setVisible(true);     } } 

A Programmer[ap]s Guide to Jini Technology
A Programmer[ap]s Guide to Jini Technology
ISBN: 1893115801
Year: 2000
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net