// Glove Project // Karan Khanna & Amit Penmetcha import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.TooManyListenersException; import java.util.Vector; import java.util.concurrent.LinkedBlockingQueue; import javax.swing.JOptionPane; import java.util.concurrent.TimeUnit; /** * The class reponsible for the local serial port, such as listening to it and * sending data to it. * */ public class GloveCommunicator implements SerialPortEventListener { // Global Variables protected MedusaLite medusa = null; //GLOVE DATA protected int hallActive = 0; //are we using hall effect sensors protected int x_axis, y_axis, hallSensor = 0; //reading on accelerometer or active hall effect sensor protected int[] flex_sensor = new int[5]; //array of flex sensors active // Serial Port Config along with all the possible options possible private SerialPort serialPort = null; // Linux/Mac/Unix - /dev/tty* // Win - COM* private String comPort = null; // SerialPort.PARITY_NONE // SerialPort.PARITY_ODD // SerialPort.PARITY_EVEN // SerialPort.PARITY_MARK // SerialPort.PARITY_SPACE private int parity = SerialPort.PARITY_NONE; // SerialPort.STOPBITS_1 // SerialPort.STOPBITS_2 private int stopBits = SerialPort.STOPBITS_1; // 2400 // 9600 // 19200 // 38400 // 57600 // 115200 private int baudRate = 9600; // SerialPort.DATABITS_8 // SerialPort.DATABITS_7 // SerialPort.DATABITS_6 // SerialPort.DATABITS_5 private int dataBits = SerialPort.DATABITS_8; // Stream variables private InputStream inputStream = null; private OutputStream outputStream = null; private LinkedBlockingQueue buffer = null; private Parse parse = null; /** * Main constructor responsible for selecting the local com port, taking * over it, and starting the queue. */ public GloveCommunicator(MedusaLite medusa) { this.medusa = medusa; buffer = new LinkedBlockingQueue(); System.out.println("Starting Serial Module..."); comPort = selectSerialPort("Select Serial Port"); updateSerialPort(); parse = new Parse(this); System.out.println("...Serial Module Ready\n"); } /** * Serial event listener responsible for decrypting serial port events. Only * really care about when data becomes available. * * @param event - the event that was just detected */ public void serialEvent(SerialPortEvent event) { switch (event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.RI: System.out.println("Bad data received. Ignoring the most recent received data packet"); break; case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: try { while (inputStream.available() > 0) { int i = inputStream.read(); //System.out.println("RX: " + Data.intToHex(i)); try { buffer.put(i); } catch (InterruptedException e) { System.err.println(e); } } } catch (IOException e) { System.err.println("IO Exception occurred while trying to read the data from inputStream."); System.err.println(e); } break; } } /** * Send a string to the serial port * * @param str - a text String */ public void sendString(String str) { if(medusa == null || medusa.getMedusaGUI() == null) return; medusa.getMedusaGUI().printToCOM("TX: " + str); try { outputStream.write(str.getBytes()); } catch (IOException e) { System.err.println(e); } } /** * Send a byte to the serial port * * @param b - a byte */ public void sendByte(byte b) { try { outputStream.write(b); } catch (IOException e) { System.err.println(e); } } /** * Send a byte array to the serial port using a new instance everything * * @param b - a byte array */ public void sendByteArray(byte[] b) { //new SendRequest(b); try { outputStream.write(b); //outputStream.flush(); // At 60ms request wait, works on win without flush } catch (IOException e) { System.out.println("Error writing to outputStream"); System.err.println(e); } } /** * Send and receive a byte array to the serial port using a new instance * * @param tx_data - byte array to be transmitted * @param rx_length - receive length * @return byte array received */ public byte[] sendAndReceiveByteArray(byte[] tx_data, int rx_length) { //if(tx_data[0] == 0) { // sendByteArray(tx_data); //} int counter = 0; byte[] rx_data = new byte[rx_length]; int temp = 0; while (counter < rx_length) { try { while(counter == 0) { // temp = (int) request.poll(1,TimeUnit.NANOSECONDS); //do we need this? temp = buffer.poll(1,TimeUnit.MILLISECONDS).intValue(); if(temp == 192) //value of buffer byte break; //stall until you get buffer byte } if(counter > 0) { temp = buffer.poll(1,TimeUnit.MILLISECONDS).intValue(); } rx_data[counter++] = (byte) temp; } catch (InterruptedException e) { System.err.println(e); } } return rx_data; } /** * Sets the current com port and then updates the program to reflect that change. * * @param newCPort - a string of the name of the new com port */ public void setComPort(String newCPort) { comPort = newCPort; updateSerialPort(); } /** * Returns the current com port * * @return the name of current com port as a String */ public String getComPort() { return comPort; } /** * Sets the current parity and then updates the program to reflect that change. * * @param newParity - the new parity */ public void setParity(int newParity) { parity = newParity; updateSerialPort(); } /** * Returns the current parity of the com port * * @return the parity of com port */ public int getParity() { return parity; } /** * Sets the current stopbits and then updates the program to reflect that change. * * @param newStopBits - the new stopbits */ public void setStopBits(int newStopBits) { stopBits = newStopBits; updateSerialPort(); } /** * Returns the current stopbits of the com port * * @return the stopbits of com port */ public int getStopBits() { return stopBits; } /** * Sets the current baudrate and then updates the program to reflect that change. * * @param newBRate - the new baudrate */ public void setBaudRate(int newBRate) { baudRate = newBRate; updateSerialPort(); } /** * Returns the current baudrate of the com port * * @return the baudrate of com port */ public int getBaudRate() { return baudRate; } /** * Sets the current databits and then updates the program to reflect that change. * * @param newDBits - the new databits */ public void setDataBits(int newDBits) { dataBits = newDBits; updateSerialPort(); } /** * Returns the current databits of the com port * * @return the databits of com port */ public int getDataBits() { return dataBits; } /** * Updates the serial port with these specific settings and then calls to * updateSerialPort() * * @param cPort - string representation of com port * @param parity - parity * @param sBits - stopbits * @param bRate - baudrate * @param dBits - databits */ public void updateSerialPort(String cPort, int parity, int sBits, int bRate, int dBits) { this.comPort = cPort; this.parity = parity; this.stopBits = sBits; this.baudRate = bRate; this.dataBits = dBits; updateSerialPort(); } /** * Updates the serial port with the current settings and retrieves * appropriate information about the port * */ public void updateSerialPort() { CommPortIdentifier portId = null; Enumeration portList = null; boolean portFound = false; if (serialPort != null) { serialPort.close(); } // Retrieve a list of the ports and loop through them until the com port // we want is found // TODO: This might be simplified since we already know the name of the // one we want and we know it is already available portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements() && !portFound) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { // Tests whether this is the com port we want if (portId.getName().equals(comPort)) { portFound = true; /* now put a thread to listen to the Serial port's events */ try { if (serialPort != null) { serialPort.close(); } serialPort = (SerialPort) portId.open("medusalite", 10000); // wait up to 10 sec for the port to open // set the Serial Port parameters serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parity); // set teh flow control to hardware - none serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); // get the streams associated with the serial port inputStream = serialPort.getInputStream(); outputStream = serialPort.getOutputStream(); // start listening for events serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); } catch (PortInUseException e) { System.out.println("Serial Port already in use."); System.err.println(e); } catch (IOException e) { System.out.println("An IO Exception occurred."); System.err.println(e); } catch (TooManyListenersException e) { System.out.println("too many listeners."); System.err.println(e); } catch (UnsupportedCommOperationException e) { System.out.println("Some Unknown Comm Exception Occurred."); System.err.println(e); } } } } if (!portFound) { System.out.println("Port " + comPort + " was not found!"); } } /** * Returns an array of String (though it is uncasted as an Object[]) that * contains a list of comports that are serial. * TODO: Filter through tty.cu, bluetooth, etc * * @param available - * a boolean that determines whether we only return a list * containing available ports or not. * @return a list of ports */ public Object[] listPorts(boolean available) { Vector result = new Vector(); Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); while (portEnum.hasMoreElements()) { CommPortIdentifier com = (CommPortIdentifier) portEnum .nextElement(); if (available) { switch (com.getPortType()) { case CommPortIdentifier.PORT_SERIAL: try { // Test open the port to see if it's available for 50ms CommPort thePort = com.open("commtest", 50); thePort.close(); result.add(com.getName() + " - " + getPortTypeName(com.getPortType())); } catch (PortInUseException e) { System.err.println(e); } catch (Exception e) { System.err.println(e); } } } else { result.add(new String(com.getName() + " - " + getPortTypeName(com.getPortType()))); } } return result.toArray(); } /** * Returns the port type of the com port * TODO: Can be removed. * * @param portType - an int representation of the port type * @return - a String representation of the port type (serial, i2c, etc) */ public String getPortTypeName(int portType) { switch (portType) { case CommPortIdentifier.PORT_I2C: return "I2C"; case CommPortIdentifier.PORT_PARALLEL: return "Parallel"; case CommPortIdentifier.PORT_RAW: return "Raw"; case CommPortIdentifier.PORT_RS485: return "RS485"; case CommPortIdentifier.PORT_SERIAL: return "Serial"; default: return "unknown type"; } } /** * Allows the user to select a serial com port from a list of available ones * * @param msg - message to be displayed to the user when asking them to select * @return the String name of the serial com port */ private String selectSerialPort(String msg) { Object[] list = listPorts(true); String port = null; port = (String) JOptionPane.showInputDialog(null, msg, "Input", JOptionPane.INFORMATION_MESSAGE, null, list, list[0]); if (port == null) { System.out.println("Exiting"); System.exit(0); } port = port.substring(0, port.indexOf(" - ")); System.out.println(port); return port; } private LinkedBlockingQueue getQueue() { return buffer; } /** public void println(String str) { if (medusa == null) { System.out.println(str); } else { medusa.getMedusaGUI().println(str); } }**/ public int get_xaxis(){ return x_axis; } public int get_yaxis(){ return y_axis; } public int get_hallSensor(){ return hallSensor; } public boolean isHallActive(){ return hallActive == 1; } //****************************************************** public void startParse() { parse.start(); } public void stopParse() { parse.stop(); } class Parse extends Thread { GloveCommunicator serial = null; Integer rxData = null; public Parse(GloveCommunicator serial) { this.serial = serial; } /** * Calls to the Thread's start() method so that JVM can call run() * */ public void start() { super.start(); } /** * Called by JVM to begin texting a queue for data. If a data is detected, * it is first parsed, then converted to a byte array, and finally sent out the * serial port. * */ public void run() { System.out.println("in run()"); int var = 1; //temp val int rx_data = 0; int count = 0; while(var == 1) { //run forever try { while(serial.getQueue().isEmpty()); rx_data = ((Integer) (serial.getQueue().poll(1,TimeUnit.MILLISECONDS))).intValue(); if (rx_data == 192) count = 0; if (count == 1){ hallActive = 0x0001 & rx_data; //first bit of 1st byte of data for(int i = 0; i < flex_sensor.length; i++) flex_sensor[i] = (0x0001) & (rx_data >> (i + 1)); //5 bits of data after LSB } else if (count == 2) { x_axis = 0x0007 & (rx_data >> 4); //unsigned upper nibble of second byte of data y_axis = 0x0007 & (rx_data); //unsigned lower nibble of second byte of data if ((rx_data >> 7) == 1) //checks sign x_axis = 0 - x_axis; if ((rx_data << 4)>>7 == 1) //checks sign y_axis = 0 - y_axis; if(hallActive == 1) { hallSensor = rx_data; //hall sensor that is activated x_axis = 0; y_axis = 0; } else hallSensor = 0; } count++; medusa.getMedusaGUI().getPanelControl().moveGlove(); }catch (InterruptedException e) { System.err.println(e); } //System.out.println("" + rx_data); } } } //*******************************************8 public static void main(String[] args) { GloveCommunicator serial = new GloveCommunicator(null); serial.startParse(); } }